From hpk at codespeak.net Thu Oct 7 11:59:11 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 7 Oct 2004 11:59:11 +0200 (MEST) Subject: [pypy-svn] r6868 - pypy/trunk/doc/sprintinfo Message-ID: <20041007095911.12CF75A096@thoth.codespeak.net> Author: hpk Date: Thu Oct 7 11:59:10 2004 New Revision: 6868 Modified: pypy/trunk/doc/sprintinfo/checklist.txt Log: we are usally only 10 people, not 20 Modified: pypy/trunk/doc/sprintinfo/checklist.txt ============================================================================== --- pypy/trunk/doc/sprintinfo/checklist.txt (original) +++ pypy/trunk/doc/sprintinfo/checklist.txt Thu Oct 7 11:59:10 2004 @@ -13,7 +13,7 @@ - find someone who can organize locally a good place with (at least) these characteristics: - - for 20 people + - for at least 10 people - with an permananent internet connection From arigo at codespeak.net Sat Oct 9 10:44:34 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 9 Oct 2004 10:44:34 +0200 (MEST) Subject: [pypy-svn] r6876 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041009084434.9E9D55C3BF@thoth.codespeak.net> Author: arigo Date: Sat Oct 9 10:44:33 2004 New Revision: 6876 Removed: pypy/trunk/src/pypy/translator/classtyper.py pypy/trunk/src/pypy/translator/genc_op.py pypy/trunk/src/pypy/translator/genc_repr.py pypy/trunk/src/pypy/translator/genc_typeset.py pypy/trunk/src/pypy/translator/typer.py Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: Deleted all the complicated genc_* and *typer sources. There is only a typeless genc.py left. Getting it to work with types again should be done by a preprocessor phase which updates the control flow graph before genc.py translates it. Deleted: /pypy/trunk/src/pypy/translator/classtyper.py ============================================================================== --- /pypy/trunk/src/pypy/translator/classtyper.py Sat Oct 9 10:44:33 2004 +++ (empty file) @@ -1,161 +0,0 @@ -""" -Extension to typer.py to preprocess class definitions and usage into -lower-level field and function definitions. -""" -from __future__ import generators -import re -from pypy.objspace.flow.model import Variable, Constant, SpaceOperation -from pypy.objspace.flow.model import FunctionGraph, Block, Link -from pypy.annotation import model as annmodel -from pypy.translator.typer import LLTyper, LLFunction, LLVar -from pypy.translator.genc_repr import R_OBJECT - -r_ends_in_underscore_digit = re.compile(r'_\d+$') - -# ____________________________________________________________ - -class ClassField: - "An attribute of a class, mapped to some field(s) of a low-level struct." - - def __init__(self, hltype, name, llclass, is_class_attr): - self.hltype = hltype - self.name = name - self.llclass = llclass - self.is_class_attr = is_class_attr - varname = '%s_%s' % (llclass.field_prefix, name) - # to avoid name collisions between the 2nd lltype of a field called xyz - # and another field whose name is exactly xyz_1, forbid field names - # ending in '_\d+' - if r_ends_in_underscore_digit.search(name): - varname += '_' - # self.var is a Variable that can stand for this field - self.var = Variable(varname) - llclass.makevar(self.var, hltype=hltype) - # this (high-level) field is implemented as a list of LLVars - # that are real fields for the C struct - self.llvars = llclass.llreprs[self.var] - - def getllvars(self, pattern='%s'): - """Return a list of fresh LLVars that implement the fields in this - C struct. The name of the variables are %'ed with 'pattern', - which can be a C expression template to generate expressions to - access this field. - """ - return [LLVar(x.type, pattern % x.name) for x in self.llvars] - -# ____________________________________________________________ - -class LLClass(LLTyper): - """Low-level representation of a class as a structure and - global functions that operate on it.""" - - def __init__(self, typeset, name, cdef, llparent): - LLTyper.__init__(self, typeset) - self.typeset = typeset - self.name = name - self.cdef = cdef # instance of pypy.annotator.factory.ClassDef - self.llparent = llparent - self.bindings = typeset.bindings - self.s_instance = annmodel.SomeInstance(self.cdef) - - def setup(self): - # two-phase initialization. The code below might require other - # classes to be already present in GenC.llclasses. - - # collect the fields that the annotator deduced for this class - typeset = self.typeset - cdef = self.cdef - cls = cdef.cls - mainletters = [c.lower() for c in cls.__name__ if 'A' <= c <= 'Z'] - self.field_prefix = ''.join(mainletters[:3] or ['f']) - self.fields_here = [] - for attr, s_value in cdef.attrs.items(): - is_class_attr = cdef.readonly[attr] - hltype = typeset.gethltype(s_value, unbound=is_class_attr) - fld = ClassField(hltype, attr, self, is_class_attr) - self.fields_here.append(fld) - # fields are categorized as instance attributes and class attributes - # according to whether they are ever accessed with SET_ATTR or not - if self.llparent: - self.instance_fields = list(self.llparent.instance_fields) - self.class_fields = list(self.llparent.class_fields) - else: - self.instance_fields = [] - self.class_fields = [] - self.instance_fields += [fld for fld in self.fields_here - if not fld.is_class_attr] - self.class_fields += [fld for fld in self.fields_here - if fld.is_class_attr] - - def get_instance_field(self, name): - """Returns the ClassField corresponding to this attribute name. - Keep in mind that it might be from some parent LLClass.""" - for fld in self.instance_fields: - if fld.name == name: - return fld - return None - - def get_class_field(self, name): - """Returns the ClassField corresponding to this class attribute name. - Keep in mind that it might be from some parent LLClass.""" - for fld in self.class_fields: - if fld.name == name: - return fld - return None - - def get_management_functions(self): - "Generate LLFunctions that operate on this class' structure." - yield self.make_fn_new() - yield self.make_fn_typenew() - - def build_llfunc(self, graph): - return LLFunction(self.typeset, graph.name, graph) - - def put_op(self, b): - def op(opname, *args, **kw): - assert kw.keys() == ['s_result'] - result = Variable() - self.bindings[result] = kw['s_result'] - b.operations.append(SpaceOperation(opname, args, result)) - return result - return op - - def make_fn_new(self): - # generate the flow graph of the new_xxx() function - b = Block([]) - op = self.put_op(b) - cls = self.cdef.cls - v1 = op('alloc_instance', Constant(cls), - s_result = self.s_instance) - # class attributes are used as defaults to initialize instance fields - for fld in self.instance_fields: - if hasattr(cls, fld.name): - value = getattr(cls, fld.name) - op('setattr', v1, Constant(fld.name), Constant(value), - s_result = annmodel.SomeImpossibleValue()) - # finally, return v1 - graph = FunctionGraph('new_%s' % self.name, b) - self.bindings[graph.getreturnvar()] = self.bindings[v1] - b.closeblock(Link([v1], graph.returnblock)) - return self.build_llfunc(graph) - - def make_fn_typenew(self): - # generate the flow graph of the typenew_xxx() function that - # initializes the class attributes of the type object - b = Block([]) - op = self.put_op(b) - cls = self.cdef.cls - v1 = Constant(cls) - # initialize class attributes - for fld in self.class_fields: - # some attributes might be missing from 'cls' if it is an abstract - # base class. We left the field uninitialized in this case. - if hasattr(cls, fld.name): - value = getattr(cls, fld.name) - op('initclassattr', v1, Constant(fld.name), Constant(value), - s_result = annmodel.SomeImpossibleValue()) - # finally, return None - graph = FunctionGraph('typenew_%s' % self.name, b) - self.bindings[graph.getreturnvar()] = annmodel.immutablevalue(None) - b.closeblock(Link([Constant(None)], graph.returnblock)) - return self.build_llfunc(graph) Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Oct 9 10:44:33 2004 @@ -6,157 +6,56 @@ #include -/*** operations on ints ***/ +#define op_richcmp(x,y,r,err,dir) \ + if (!(r=PyObject_RichCompare(x,y,dir))) goto err; +#define OP_LT(x,y,r,err) op_richcmp(x,y,r,err, Py_LT) +#define OP_LE(x,y,r,err) op_richcmp(x,y,r,err, Py_LE) +#define OP_EQ(x,y,r,err) op_richcmp(x,y,r,err, Py_EQ) +#define OP_NE(x,y,r,err) op_richcmp(x,y,r,err, Py_NE) +#define OP_GT(x,y,r,err) op_richcmp(x,y,r,err, Py_GT) +#define OP_GE(x,y,r,err) op_richcmp(x,y,r,err, Py_GE) + +#define OP_IS_TRUE(x,r,err) switch (PyObject_IsTrue(x)) { \ + case 0: r=Py_False; break; \ + case 1: r=Py_True; break; \ + default: goto err; \ + } \ + Py_INCREF(r); + +#define OP_ADD(x,y,r,err) if (!(r=PyNumber_Add(x,y))) goto err; +#define OP_SUB(x,y,r,err) if (!(r=PyNumber_Subtract(x,y))) goto err; +#define OP_MUL(x,y,r,err) if (!(r=PyNumber_Multiply(x,y))) goto err; +#define OP_DIV(x,y,r,err) if (!(r=PyNumber_Divide(x,y))) goto err; +#define OP_MOD(x,y,r,err) if (!(r=PyNumber_Remainder(x,y))) goto err; +#define OP_INPLACE_ADD(x,y,r,err) if(!(r=PyNumber_InPlaceAdd(x,y))) goto err; + +#define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem(x,y))) goto err; +#define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem(x,y,z))<0) goto err; \ + r = NULL; + +#define OP_GETATTR(x,y,r,err) if (!(r=PyObject_GetAttr(x,y))) goto err; +#define OP_SETATTR(x,y,z,r,err) if ((PyObject_SetAttr(x,y,z))<0) goto err; \ + r = NULL; +#define OP_DELATTR(x,y,r,err) if ((PyObject_SetAttr(x,y,NULL))<0)goto err; \ + r = NULL; + +#define OP_NEWSLICE(x,y,z,r,err) if (!(r=PySlice_New(x,y,z))) goto err; -#define OP_LT_iii(x,y,r) r = x < y; -#define OP_LE_iii(x,y,r) r = x <= y; -#define OP_EQ_iii(x,y,r) r = x == y; -#define OP_NE_iii(x,y,r) r = x != y; -#define OP_GT_iii(x,y,r) r = x > y; -#define OP_GE_iii(x,y,r) r = x >= y; - -#define OP_IS_TRUE_ii(x,r) r = !(!x); - -#define OP_ADD_iii(x,y,r) r = x + y; -#define OP_SUB_iii(x,y,r) r = x - y; -#define OP_MUL_iii(x,y,r) r = x * y; -#define OP_DIV_iii(x,y,r) r = x / y; -#define OP_MOD_iii(x,y,r) r = x % y; -#define OP_INPLACE_ADD_iii(x,y,r) r = x + y; - - -/*** generic operations on PyObjects ***/ - -#define op_richcmp_ooi(x,y,r,err,dir) \ - if ((r=PyObject_RichCompareBool(x,y,dir))<0) goto err; -#define OP_LT_ooi(x,y,r,err) op_richcmp_ooi(x,y,r,err, Py_LT) -#define OP_LE_ooi(x,y,r,err) op_richcmp_ooi(x,y,r,err, Py_LE) -#define OP_EQ_ooi(x,y,r,err) op_richcmp_ooi(x,y,r,err, Py_EQ) -#define OP_NE_ooi(x,y,r,err) op_richcmp_ooi(x,y,r,err, Py_NE) -#define OP_GT_ooi(x,y,r,err) op_richcmp_ooi(x,y,r,err, Py_GT) -#define OP_GE_ooi(x,y,r,err) op_richcmp_ooi(x,y,r,err, Py_GE) - -#define OP_IS_TRUE_oi(x,r,err) if ((r=PyObject_IsTrue(x))<0) goto err; -#define OP_ADD_ooo(x,y,r,err) if (!(r=PyNumber_Add(x,y))) goto err; -#define OP_SUB_ooo(x,y,r,err) if (!(r=PyNumber_Subtract(x,y))) goto err; -#define OP_MUL_ooo(x,y,r,err) if (!(r=PyNumber_Multiply(x,y))) goto err; -#define OP_DIV_ooo(x,y,r,err) if (!(r=PyNumber_Divide(x,y))) goto err; -#define OP_MOD_ooo(x,y,r,err) if (!(r=PyNumber_Remainder(x,y))) goto err; -#define OP_INPLACE_ADD_ooo(x,y,r,err) if(!(r=PyNumber_InPlaceAdd(x,y)))goto err; - -#define OP_GETITEM_ooo(x,y,r,err) if (!(r=PyObject_GetItem(x,y))) goto err; -#define OP_SETITEM_ooov(x,y,z,err) if ((PyObject_SetItem(x,y,z))<0) goto err; -#define OP_GETATTR_ooo(x,y,r,err) if (!(r=PyObject_GetAttr(x,y))) goto err; -#define OP_SETATTR_ooov(x,y,z,err) if ((PyObject_SetAttr(x,y,z))<0) goto err; -#define OP_DELATTR_oov(x,y,err) if ((PyObject_SetAttr(x,y,NULL))<0)goto err; -#define OP_NEWSLICE_oooo(x,y,z,r,err) if (!(r=PySlice_New(x,y,z))) goto err; - -/* temporary hack */ -#define OP_GETITEM_ooi(x,y,r,err) { \ - PyObject* o = PyObject_GetItem(x,y); \ - if (!o) goto err; \ - if ((r=PyInt_AsLong(o)) == -1 && PyErr_Occurred()) goto err; \ -} - - -/*** conversions ***/ - -#define CONVERT_io(x,r,err) if (!(r=PyInt_FromLong(x))) goto err; -#define CONVERT_so(c,l,r,err) if (!(r=PyString_FromStringAndSize(c,l)))goto err; -#define CONVERT_vo(r) r = Py_None; Py_INCREF(r); - -/*#define convert_oi(x,r,err) if ((r=PyInt_AsLong(x)) == -1 \ - * && PyErr_Occurred()) goto err; - * -- should be done differently */ /*** tests ***/ -#define CASE_False_i(n, err) if (n) goto err; -#define CASE_True_i(n, err) if (!n) goto err; -#define CASE_0_i(n, err) if (n != 0) goto err; -#define CASE_1_i(n, err) if (n != 1) goto err; - -#define CASE_False_o(o, err) if (!(PyInt_Check(o) && !PyInt_AS_LONG(o))) goto err; -#define CASE_True_o(o, err) if (!(PyInt_Check(o) && PyInt_AS_LONG(o))) goto err; -#define CASE_0_o(o, err) if (!(PyInt_Check(o) && PyInt_AS_LONG(o)==0)) goto err; -#define CASE_1_o(o, err) if (!(PyInt_Check(o) && PyInt_AS_LONG(o)==1)) goto err; +#define EQ_False(o) (o == Py_False) +#define EQ_True(o) (o == Py_True) +#define EQ_0(o) (PyInt_Check(o) && PyInt_AS_LONG(o)==0) +#define EQ_1(o) (PyInt_Check(o) && PyInt_AS_LONG(o)==1) /*** misc ***/ -#define OP_EXCEPTION_ov(x) /* XXX exceptions not implemented */ +#define OP_EXCEPTION(x,r,err) r = NULL; /* XXX exceptions not implemented */ + +#define MOVE(x, y) y = x; -#define OP_ALLOC_AND_SET_ioo(l,o,r,err) { \ - int i; \ - if (!(r = PyList_New(l))) goto err; \ - for (i=l; --i >= 0; ) { \ - PyList_SET_ITEM(r, i, o); \ - Py_INCREF(o); \ - } \ - } - -/* a few built-in functions */ - -#define CALL_len_oi(o,r,err) if ((r=PyObject_Size(o))<0) goto err; -#define CALL_pow_iii(x,y,r) { int i=y; r=1; while (--i>=0) r*=x; } /*slow*/ - - -/*** macros used directly by genc_op.py ***/ - -#define OP_NEWLIST(len, r, err) if (!(r=PyList_New(len))) goto err; -#define OP_NEWLIST_SET(r, i, o) PyList_SET_ITEM(r, i, o); Py_INCREF(o); -#define OP_NEWTUPLE(len, r, err) if (!(r=PyTuple_New(len))) goto err; -#define OP_NEWTUPLE_SET(r, i, o) PyTuple_SET_ITEM(r, i, o); Py_INCREF(o); - -#define OP_CALL_PYOBJ(args, r, err) if (!(r=PyObject_CallFunction args)) \ - goto err; - -#define OP_INSTANTIATE(cls, r, err) if (!(r=new_##cls())) goto err; -#define ALLOC_INSTANCE(cls, r, err) \ - if (!(r=PyType_GenericAlloc(&g_Type_##cls.type, 0))) goto err; -#define SETUP_TYPE(cls) \ - PyType_Ready(&g_Type_##cls.type); \ - typenew_##cls(); - -#define OP_GETINSTATTR(cls,o,f,r) r=((PyObj_##cls*) o)->f; -#define OP_GETINSTATTR_o(cls,o,f,r) r=((PyObj_##cls*) o)->f; Py_INCREF(r); -#define OP_GETCLASSATTR(cls,o,f,r) r=((PyTypeObject_##cls*)(o->ob_type))->f; -#define OP_GETCLASSATTR_o(cls,o,f,r) r=((PyTypeObject_##cls*)(o->ob_type))->f;\ - Py_INCREF(r); -#define OP_SETINSTATTR(cls, o, f, v) ((PyObj_##cls*) o)->f=v; -#define OP_SETINSTATTR_o(cls, o, f, v) { PyObject* tmp; \ - OP_GETINSTATTR(cls, o, f, tmp) \ - OP_SETINSTATTR(cls, o, f, v) \ - Py_INCREF(v); Py_XDECREF(tmp); \ - } -#define OP_INITCLASSATTR(cls, f, v) g_Type_##cls.f=v; -#define OP_INITCLASSATTR_o(cls, f, v) g_Type_##cls.f=v; Py_INCREF(v); - -#define OP_DUMMYREF(r) r = Py_None; Py_INCREF(r); - -#define MOVE(x, y) y = x; - -#define OP_CCALL_v(fn, args, err) if (fn args < 0) goto err; -#define OP_CCALL(fn, args, r, err) if ((r=fn args) == NULL) goto err; -#define OP_CCALL_i(fn, args, r, err) if ((r=fn args) == -1 && \ - PyErr_Occurred()) goto err; - -#define OP_NEWARRAY(name,len,r,err) if (!(r=alloclist_##name(len))) goto err; -#define OP_NEWARRAY_SET(name,a,i,f,v) ((PyList_##name*) a)->ob_item[i].f=v; -#define OP_NEWARRAY_SET_o(name,a,i,f,v) ((PyList_##name*) a)->ob_item[i].f=v; \ - Py_INCREF(v); -#define OP_GETARRAYITEM(name,a,i,f,r) r=((PyList_##name*) a)->ob_item[i].f; -#define OP_GETARRAYITEM_o(name,a,i,f,r) r=((PyList_##name*) a)->ob_item[i].f; \ - Py_INCREF(r); -#define OP_SETARRAYITEM(name,a,i,f,v) ((PyList_##name*) a)->ob_item[i].f=v; -#define OP_SETARRAYITEM_o(name,a,i,f,v) { PyObject* tmp; \ - OP_GETARRAYITEM(name,a,i,f,tmp) \ - OP_SETARRAYITEM(name,a,i,f,v) \ - Py_INCREF(v); Py_DECREF(tmp); \ - } -#define ARRAYLEN(a) (((PyVarObject*) a)->ob_size) -#define OP_ARRAYLEN(a,r) r=ARRAYLEN(a); -#define OP_GROWLIST(name,a,l,err) if (growlist_##name(a,l) < 0) goto err; /************************************************************/ /*** The rest is produced by genc.py ***/ Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Oct 9 10:44:33 2004 @@ -6,11 +6,7 @@ import autopath, os from pypy.objspace.flow.model import Variable, Constant, SpaceOperation from pypy.objspace.flow.model import FunctionGraph, Block, Link -from pypy.translator.typer import LLFunction, LLOp, LLVar, LLConst -from pypy.translator.classtyper import LLClass -from pypy.translator.genc_typeset import CTypeSet -from pypy.translator.genc_op import ERROR_RETVAL -from pypy.translator.genc_repr import R_INT, R_OBJECT, cdecl +from pypy.objspace.flow.model import traverse, uniqueitems # ____________________________________________________________ @@ -33,323 +29,200 @@ self.translator = translator self.modname = (modname or uniquemodulename(translator.functions[0].__name__)) - if translator.annotator: - bindings = translator.annotator.bindings.copy() - else: - bindings = {} - self.typeset = CTypeSet(self, bindings) - self.initializationcode = [] - self.llclasses = {}; self.classeslist = [] - self.llfunctions = {}; self.functionslist = [] - self.llarrays = {} - # must build functions first, otherwise methods are not found - self.build_llfunctions() - self.build_llclasses() - self.build_llentrypoint() + self.cnames = {} + self.seennames = {} + self.initcode = [] + self.globaldecl = [] + self.pendingfunctions = [] self.gen_source() + def nameof(self, obj): + key = type(obj), obj # to avoid confusing e.g. 0 and 0.0 + try: + return self.cnames[key] + except KeyError: + for cls in type(obj).__mro__: + meth = getattr(self, 'nameof_' + cls.__name__, None) + if meth: + break + else: + raise TypeError, "nameof(%r)" % (obj,) + name = meth(obj) + self.cnames[key] = name + return name + + def uniquename(self, basename): + name = basename + i = 0 + while name in self.seennames: + i += 1 + name = '%s_%d' % (basename, i) + self.seennames[name] = True + return name + + def nameof_int(self, value): + if value >= 0: + name = 'gint_%d' % value + else: + name = 'gint_minus%d' % abs(value) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('%s = PyInt_FromLong(%d);' % (name, value)) + return name + + def nameof_function(self, func): + name = self.uniquename('gfunc_' + func.__name__) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('%s = PyCFunction_New(&ml_%s, NULL);' % (name, + name)) + self.pendingfunctions.append(func) + return name + def gen_source(self): f = self.f info = { 'modname': self.modname, - 'exported': self.translator.functions[0].__name__, + 'entrypointname': self.translator.functions[0].__name__, + 'entrypoint': self.nameof(self.translator.functions[0]), } # header print >> f, self.C_HEADER - # forward declarations - print >> f, '/* forward declarations */' - for llfunc in self.functionslist: - print >> f, '%s;' % self.cfunction_header(llfunc) - print >> f - - # declaration of class structures - for llclass in self.classeslist: - self.gen_cclass(llclass) - - # function implementation - print >> f, self.C_SEP - print >> f - for llfunc in self.functionslist: - self.gen_cfunction(llfunc) - print >> f - - # entry point - print >> f, self.C_SEP - print >> f, self.C_ENTRYPOINT_HEADER % info - self.gen_entrypoint() - print >> f, self.C_ENTRYPOINT_FOOTER % info + # function implementations + for func in self.pendingfunctions: + self.gen_cfunction(func) # footer - print >> f, self.C_METHOD_TABLE % info print >> f, self.C_INIT_HEADER % info - for codeline in self.initializationcode: + for codeline in self.initcode: print >> f, '\t' + codeline print >> f, self.C_INIT_FOOTER % info - - def build_llclasses(self): - if not self.translator.annotator: - return - n = 0 - for cdef in self.translator.annotator.getuserclassdefinitions(): - # annotation.factory guarantees that this will enumerate - # the ClassDefs in a parent-first, children-last order. - cls = cdef.cls - assert cls not in self.llclasses, '%r duplicate' % (cls,) - if cdef.basedef is None: - llparent = None - else: - llparent = self.llclasses[cdef.basedef.cls] - llclass = LLClass( - typeset = self.typeset, - name = '%s__%d' % (cls.__name__, n), - cdef = cdef, - llparent = llparent, - ) - self.llclasses[cls] = llclass - self.classeslist.append(llclass) - n += 1 - for llclass in self.classeslist: - llclass.setup() - management_functions = [] - for llclass in self.classeslist: - management_functions += llclass.get_management_functions() - self.functionslist[:0] = management_functions - - def build_llfunctions(self): - n = 0 - for func in self.translator.functions: - assert func not in self.llfunctions, '%r duplicate' % (func,) - llfunc = LLFunction( - typeset = self.typeset, - name = 'f%d_%s' % (n, func.func_name), - graph = self.translator.flowgraphs[func]) - self.llfunctions[func] = llfunc - self.functionslist.append(llfunc) - n += 1 - - def build_llentrypoint(self): - # create a LLFunc that calls the entry point function and returns - # whatever it returns, but converted to PyObject*. - main = self.translator.functions[0] - llmain = self.llfunctions[main] - inputargs = llmain.graph.getargs() - b = Block(inputargs) - v1 = Variable() - b.operations.append(SpaceOperation('simple_call', - [Constant(main)] + inputargs, - v1)) - # finally, return v1 - graph = FunctionGraph('entry_point', b) - b.closeblock(Link([v1], graph.returnblock)) - llfunc = LLFunction(self.typeset, graph.name, graph) - self.functionslist.append(llfunc) - - def get_llfunc_header(self, llfunc): - llargs, llret = llfunc.ll_header() - if len(llret) == 0: - retlltype = None - elif len(llret) == 1: - retlltype = llret[0].type - else: - # if there is more than one return LLVar, only the first one is - # returned and the other ones are returned via ptr output args - retlltype = llret[0].type - llargs += [LLVar(a.type, '*output_'+a.name) for a in llret[1:]] - return llargs, retlltype - - def cfunction_header(self, llfunc): - llargs, rettype = self.get_llfunc_header(llfunc) - l = [cdecl(a.type, a.name) for a in llargs] - l = l or ['void'] - return 'static ' + cdecl(rettype or 'int', - '%s(%s)' % (llfunc.name, ', '.join(l))) - - def gen_entrypoint(self): - f = self.f - llfunc = self.functionslist[-1] - llargs, rettype = self.get_llfunc_header(llfunc) - assert llfunc.name == 'entry_point', llfunc.name - assert rettype == 'PyObject*', rettype - l = [] - l2 = [] - for a in llargs: - print >> f, '\t%s;' % cdecl(a.type, a.name) - l.append('&' + a.name) - l2.append(a.name) - formatstr = [] - for v in llfunc.graph.getargs(): - hltype = self.typeset.gethltype(v) - assert hltype.parse_code, ( - "entry point arg %s has unsupported type %s" % (v, hltype)) - formatstr.append(hltype.parse_code) - l.insert(0, '"' + ''.join(formatstr) + '"') - print >> f, '\tif (!PyArg_ParseTuple(args, %s))' % ', '.join(l) - print >> f, '\t\treturn NULL;' - print >> f, '\treturn entry_point(%s);' % (', '.join(l2)) - - def gen_cfunction(self, llfunc): + def gen_cfunction(self, func): f = self.f - - # generate the body of the function - llargs, rettype = self.get_llfunc_header(llfunc) - error_retval = LLConst(rettype, ERROR_RETVAL.get(rettype, 'NULL')) - body = list(llfunc.ll_body([error_retval])) - - # print the declaration of the new global constants needed by - # the current function - to_declare = [] - for line in body: - if isinstance(line, LLOp): - for a in line.using(): - if isinstance(a, LLConst) and a.to_declare: - to_declare.append(a) - if a.initexpr: - self.initializationcode.append('%s = %s;' % ( - a.name, a.initexpr)) - a.to_declare = False - if to_declare: - print >> f, '/* global constant%s */' % ('s'*(len(to_declare)>1)) - for a in to_declare: - print >> f, 'static %s;' % cdecl(a.type, a.name) + body = list(self.cfunction_body(func)) + g = self.globaldecl + if g: + print >> f, '/* global declaration%s */' % ('s'*(len(g)>1)) + for line in g: + print >> f, line print >> f + del g[:] # print header - print >> f, self.cfunction_header(llfunc) + name = self.nameof(func) + assert name.startswith('gfunc_') + f_name = 'f_' + name[6:] + print >> f, 'static PyObject* %s(PyObject* self, PyObject* args)' % ( + f_name,) print >> f, '{' - # collect and print all the local variables from the body - lllocals = [] - for line in body: - if isinstance(line, LLOp): - lllocals += line.using() - seen = {} - for a in llargs: - seen[a] = True - for a in lllocals: - if a not in seen: - if not isinstance(a, LLConst): - print >> f, '\t%s;' % cdecl(a.type, a.name) - seen[a] = True + # collect and print all the local variables + graph = self.translator.flowgraphs[func] + localslst = [] + def visit(node): + if isinstance(node, Block): + localslst.extend(node.getvariables()) + traverse(visit, graph) + for a in uniqueitems(localslst): + print >> f, '\tPyObject* %s;' % a.name print >> f + # argument unpacking + lst = ['"' + 'O'*len(graph.getargs()) + '"'] + lst += ['&' + a.name for a in graph.getargs()] + print >> f, '\tif (!PyArg_ParseTuple(args, %s))' % ', '.join(lst) + print >> f, '\t\treturn NULL;' + # print the body for line in body: - if isinstance(line, LLOp): - code = line.write() - if code: - for codeline in code.split('\n'): - print >> f, '\t' + codeline - elif line: # label - print >> f, ' %s:' % line - else: # empty line - print >> f + if line.endswith(':'): + line = ' ' + line + else: + line = '\t' + line + print >> f, line print >> f, '}' - def gen_cclass(self, llclass): - f = self.f - cls = llclass.cdef.cls - info = { - 'module': cls.__module__, - 'basename': cls.__name__, - 'name': llclass.name, - 'base': '0', - } - if llclass.llparent is not None: - info['base'] = '&g_Type_%s.type' % llclass.llparent.name + # print the PyMethodDef + print >> f, 'static PyMethodDef ml_%s = { "%s", %s, METH_VARARGS };' % ( + name, func.__name__, f_name) + print >> f - # print the C struct declaration - print >> f, self.C_STRUCT_HEADER % info - for fld in llclass.instance_fields: - for llvar in fld.llvars: - print >> f, '\t%s;' % cdecl(llvar.type, llvar.name) - print >> f, self.C_STRUCT_FOOTER % info - - # print the struct PyTypeObject_Xxx, which is an extension of - # PyTypeObject with the class attributes of this class - print >> f, self.C_TYPESTRUCT_HEADER % info - for fld in llclass.class_fields: - for llvar in fld.llvars: - print >> f, '\t%s;' % cdecl(llvar.type, llvar.name) - print >> f, self.C_TYPESTRUCT_FOOTER % info - - # generate the deallocator function -- must special-case it; - # other functions are generated by LLClass.get_management_functions() - print >> f, self.C_DEALLOC_HEADER % info - llxdecref = self.typeset.rawoperations['xdecref'] - for fld in llclass.instance_fields: - llvars = fld.getllvars('op->%s') - line = llxdecref(llvars) - code = line.write() - if code: - for codeline in code.split('\n'): - print >> f, '\t' + codeline - print >> f, self.C_DEALLOC_FOOTER % info - - # generate the member list for the type object - print >> f, self.C_MEMBERLIST_HEADER % info - # XXX write member definitions for member with well-known types only - # members from the parents are inherited via tp_base - for fld in llclass.fields_here: - if fld.is_class_attr: - continue # XXX should provide a reader - if fld.hltype == R_OBJECT: - t = 'T_OBJECT_EX' - elif fld.hltype == R_INT: - t = 'T_INT' + def cfunction_body(self, func): + graph = self.translator.flowgraphs[func] + blocknum = {} + allblocks = [] + + def expr(v): + if isinstance(v, Variable): + return v.name + elif isinstance(v, Constant): + return self.nameof(v.value) else: - continue # ignored - print >> f, '\t{"%s",\t%s,\toffsetof(PyObj_%s, %s)},' % ( - fld.name, t, llclass.name, fld.llvars[0].name) - print >> f, self.C_MEMBERLIST_FOOTER % info - - # declare and initialize the static PyTypeObject - print >> f, self.C_TYPEOBJECT % info - - self.initializationcode.append('SETUP_TYPE(%s)' % llclass.name) - - def declare_list(self, lltypes): - # called by genc_typer.py to write the type definition of a list - # as an array of "struct { lltypes };" - lltypes = tuple(lltypes) - if lltypes in self.llarrays: - return self.llarrays[lltypes] # already seen - - s = '_'.join(lltypes) - name = ''.join([('a'<=c<='z' or - 'A'<=c<='Z' or - '0'<=c<='9') and c or '_' - for c in s]) - name = name or 'void' - name += '_%d' % len(self.llarrays) - self.llarrays[lltypes] = name - - f = self.f - info = { - 'name': name, - } - print >> f, self.C_LIST_HEADER % info - llvars1 = [] - for i in range(len(lltypes)): - print >> f, '\t%s;' % cdecl(lltypes[i], 'a%d'%i) - llvars1.append(LLVar(lltypes[i], 'item->a%d'%i)) - print >> f, self.C_LIST_FOOTER % info - - print >> f, self.C_LIST_DEALLOC_HEADER % info - lldecref = self.typeset.rawoperations['decref'] - line = lldecref(llvars1) - code = line.write() - if code: - print >> f, self.C_LIST_DEALLOC_LOOP_HEADER % info - for codeline in code.split('\n'): - print >> f, '\t\t' + codeline - print >> f, self.C_LIST_DEALLOC_LOOP_FOOTER % info - print >> f, self.C_LIST_DEALLOC_FOOTER % info - - print >> f, self.C_LIST_TYPEOBJECT % info + raise TypeError, "expr(%r)" % (v,) - return name + def gen_link(link): + "Generate the code to jump across the given Link." + has_ref = {} + for v in to_release: + has_ref[v] = True + for a1, a2 in zip(link.args, link.target.inputargs): + line = 'MOVE(%s, %s)' % (expr(a1), a2.name) + if a1 in has_ref: + del has_ref[a1] + else: + line += '\tPy_INCREF(%s);' % a2.name + yield line + for v in to_release: + if v in has_ref: + yield 'Py_XDECREF(%s);' % v.name + yield 'goto block%d;' % blocknum[link.target] + + # collect all blocks + def visit(block): + if isinstance(block, Block): + allblocks.append(block) + blocknum[block] = len(blocknum) + traverse(visit, graph) + + # generate an incref for each input argument + for v in graph.getargs(): + yield 'Py_INCREF(%s);' % v.name + + # generate the body of each block + for block in allblocks: + yield '' + yield 'block%d:' % blocknum[block] + to_release = list(block.inputargs) + for op in block.operations: + lst = [expr(v) for v in op.args] + lst.append(op.result.name) + lst.append('err%d_%d' % (blocknum[block], len(to_release))) + yield 'OP_%s(%s)' % (op.opname.upper(), ', '.join(lst)) + to_release.append(op.result) + + if len(block.exits) == 0: + yield 'return %s;' % expr(block.inputargs[0]) + continue + if block.exitswitch is not None: + for link in block.exits[:-1]: + yield 'if (EQ_%s(%s)) {' % (link.exitcase, + block.exitswitch.name) + for op in gen_link(link): + yield '\t' + op + yield '}' + link = block.exits[-1] + yield 'assert(EQ_%s(%s));' % (link.exitcase, + block.exitswitch.name) + for op in gen_link(block.exits[-1]): + yield op + + yield '' + to_release.pop() # this label is never reachable + while to_release: + n = len(to_release) + v = to_release.pop() + yield 'err%d_%d: Py_XDECREF(%s);' % (blocknum[block], n, v.name) + yield 'return NULL;' # ____________________________________________________________ @@ -357,205 +230,26 @@ C_SEP = "/************************************************************/" - C_ENTRYPOINT_HEADER = ''' -static PyObject* c_%(exported)s(PyObject* self, PyObject* args) -{''' - - C_ENTRYPOINT_FOOTER = '''}''' - - C_METHOD_TABLE = ''' -static PyMethodDef g_methods_%(modname)s[] = { -\t{"%(exported)s", (PyCFunction)c_%(exported)s, METH_VARARGS}, -\t{NULL, NULL} -};''' + C_INIT_HEADER = C_SEP + ''' - C_INIT_HEADER = ''' void init%(modname)s(void) { -\tPy_InitModule("%(modname)s", g_methods_%(modname)s);''' - - C_INIT_FOOTER = '''}''' - - C_STRUCT_HEADER = C_SEP + ''' -/*** Definition of class %(module)s.%(basename)s ***/ - -typedef struct { - PyObject_HEAD''' - - C_STRUCT_FOOTER = '''} PyObj_%(name)s; -''' - - C_DEALLOC_HEADER = '''static void dealloc_%(name)s(PyObj_%(name)s* op) -{''' - - C_DEALLOC_FOOTER = ''' PyObject_Del((PyObject*) op); -} +\tPyObject* m = Py_InitModule("%(modname)s", NULL); ''' - C_MEMBERLIST_HEADER = '''static PyMemberDef g_memberlist_%(name)s[] = {''' - - C_MEMBERLIST_FOOTER = ''' {NULL} /* Sentinel */ -}; -''' - - # NB: our types don't have Py_TPFLAGS_BASETYPE because we do not want - # the complications of dynamically created subclasses. This doesn't - # prevent the various types from inheriting from each other via - # tp_base. This is ok because we expect all RPython classes to exist - # and be analyzed in advance. This allows class attributes to be stored - # as an extensison of the PyTypeObject structure, which are then - # accessed with ((PyTypeObject_Xxx*)op->ob_type)->classattrname. - # This doesn't work if op->ob_type can point to a heap-allocated - # type object over which we have no control. - - C_TYPESTRUCT_HEADER = '''typedef struct { - PyTypeObject type; - /* class attributes follow */''' - - C_TYPESTRUCT_FOOTER = '''} PyTypeObject_%(name)s; -''' - - C_TYPEOBJECT = '''static PyTypeObject_%(name)s g_Type_%(name)s = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "%(name)s", - sizeof(PyObj_%(name)s), - 0, - (destructor)dealloc_%(name)s, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* XXX need GC */ /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - g_memberlist_%(name)s, /* tp_members */ - 0, /* tp_getset */ - %(base)s, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* XXX call %(name)s_new() */ /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - PyObject_Del, /* tp_free */ -}; -''' - - C_LIST_HEADER = '''/* the type "list of %(name)s" */ -typedef struct {''' - - C_LIST_FOOTER = '''} ListItem_%(name)s; - -typedef struct { - PyObject_VAR_HEAD - ListItem_%(name)s* ob_item; -} PyList_%(name)s; -''' - - C_LIST_DEALLOC_HEADER = ( -'''static void dealloclist_%(name)s(PyList_%(name)s* op) -{''') - - C_LIST_DEALLOC_LOOP_HEADER = ( -''' int i = op->ob_size; - ListItem_%(name)s* item = op->ob_item + i; - while (--i >= 0) { - --item;''') - - C_LIST_DEALLOC_LOOP_FOOTER = ( -''' }''') - - C_LIST_DEALLOC_FOOTER = ( -''' PyMem_Free(op->ob_item); - PyObject_Del((PyObject*) op); -} -''') - - C_LIST_TYPEOBJECT = '''static PyTypeObject g_ListType_%(name)s = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "list of %(name)s", - sizeof(PyList_%(name)s), - 0, - (destructor)dealloclist_%(name)s, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* XXX need GC */ /* tp_traverse */ - 0, /* tp_clear */ -}; - -static PyObject* alloclist_%(name)s(int len) -{ - void* buffer; - PyList_%(name)s* o; - - if (len > 0) { - buffer = PyMem_Malloc(len * sizeof(ListItem_%(name)s)); - if (buffer == NULL) { - PyErr_NoMemory(); - return NULL; - } - } - else - buffer = NULL; - - o = PyObject_New(PyList_%(name)s, &g_ListType_%(name)s); - if (o != NULL) { - o->ob_size = len; - o->ob_item = (ListItem_%(name)s*) buffer; - } - else { - PyMem_Free(buffer); - } - return (PyObject*) o; -} - -static int growlist_%(name)s(PyObject* a, int extralen) -{ - /* NB. this function does not update o->ob_size */ - PyList_%(name)s* o = (PyList_%(name)s*) a; - int newlen = o->ob_size + extralen; - void* buffer = PyMem_Realloc(o->ob_item, - newlen*sizeof(ListItem_%(name)s)); - if (buffer == NULL) { - PyErr_NoMemory(); - return -1; - } - o->ob_item = (ListItem_%(name)s*) buffer; - return 0; -} -''' + C_INIT_FOOTER = ''' +\tPyModule_AddObject(m, "%(entrypointname)s", %(entrypoint)s); +}''' # ____________________________________________________________ + +def cdecl(type, name): + # Utility to generate a typed name declaration in C syntax. + # For local variables, struct fields, function declarations, etc. + # For complex C types, the 'type' can contain a '@' character that + # specifies where the 'name' should be inserted; for example, an + # array of 10 ints has a type of "int @[10]". + if '@' in type: + return type.replace('@', name) + else: + return ('%s %s' % (type, name)).rstrip() Deleted: /pypy/trunk/src/pypy/translator/genc_op.py ============================================================================== --- /pypy/trunk/src/pypy/translator/genc_op.py Sat Oct 9 10:44:33 2004 +++ (empty file) @@ -1,443 +0,0 @@ -""" -Low-level operations for C code generation. -""" - -from pypy.translator.typer import LLOp - -# This file defines one class per possible operation. But there are families -# of very similar operations (e.g. incref/decref/xdecref). To make it easy -# to follow which class is really an operation and which class represents a -# family, we introduce a simple mecanism: class attributes that are set to -# PARAMETER are parameters that can be set by calling the class method With(). -PARAMETER = object() # marker - - -class LoC(LLOp): - # base class for LLOps that produce C code. - cost = 2 - - def write(self): - "Default write method, delegating to writestr()." - args = [a.name for a in self.args] - if self.can_fail: - args.append(self.errtarget) - return self.writestr(*args) - - def using(self): - return self.args # all locals and constants needed by write() - - def With(cls, **params): - class subcls(cls): - pass - items = params.items() - items.sort() - info = [repr(value) for name, value in items] - subcls.__name__ = '%s.With(%s)' % (cls.__name__, ', '.join(info)) - for name, value in items: - assert hasattr(cls, name), 'not a parameter: %r' % (name,) - setattr(subcls, name, value) - # check that all PARAMETERs, at least from this class, - # have been given a value - for name, value in cls.__dict__.items(): - if value is PARAMETER: - assert name in params, 'missing definition for parameter '+name - return subcls - With = classmethod(With) - -class LoOptimized(LoC): - def write(self): - raise NotImplementedError, 'should be optimized away' - def optimize(self, typer, llresult): - # patch the result with the known answer - constantsllrepr = self.optimized_result(typer) - assert len(constantsllrepr) == len(llresult) - llresult[:] = constantsllrepr - return True - -# ____________________________________________________________ -# -# For each operation we describe what argument list it expected. -# These arguments are LLVars expanded from high-level arguments (Variables) -# and the result, also as zero or more LLVars, all put together in a single -# list. The occasionally hackish look of self.args manipulations come from -# the fact that the boundaries between the original high-level arguments -# are lost by design. In the #self.args comments below, a trailing '..' -# means that zero or more items can come here. - -class LoStandardOperation(LoC): - "A standard operation is one defined by a macro in genc.h." - can_fail = PARAMETER - llname = PARAMETER - cost = PARAMETER - # self.args: [macro args expanded from Variables..] - def writestr(self, *args): - return self.llname + '(' + ', '.join(args) + ')' - -class LoKnownAnswer(LoOptimized): - known_answer = PARAMETER - cost = 0 - # self.args: [ignored input args.., - # output args to replace with known_answer..] - def optimized_result(self, typer): - return self.known_answer - -class LoCallFunction(LoC): - can_fail = True - cost = 3 - # self.args: [callable PyObject, argument PyObjects.., result PyObject] - def writestr(self, func, *stuff): - args = stuff[:-2] - result = stuff[-2] - err = stuff[-1] - format = '"' + 'O' * len(args) + '"' - args = (func, format) + args - return ('OP_CALL_PYOBJ((%s), %s, %s)' % (', '.join(args), result, err)) - -class LoInstantiate(LoC): - can_fail = True - llclass = PARAMETER - # self.args: [output PyObject instance] - def writestr(self, res, err): - return 'OP_INSTANTIATE(%s, %s, %s)' % (self.llclass.name, res, err) - -class LoAllocInstance(LoC): - can_fail = True - llclass = PARAMETER - # self.args: [output PyObject instance] - def writestr(self, res, err): - return 'ALLOC_INSTANCE(%s, %s, %s)' % (self.llclass.name, res, err) - -class LoConvertTupleItem(LoOptimized): - source_r = PARAMETER # tuple-of-hltypes, one per item of the input tuple - target_r = PARAMETER # tuple-of-hltypes, one per item of the output tuple - cost = PARAMETER - # self.args: [input unpacked tuple items.., output unpacked tuple items..] - def optimized_result(self, typer): - # replace this complex conversion by the simpler conversion of - # only the items that changed - llinputs = [] - pos = 0 - for r in self.source_r: - L = len(r.impl) - llinputs.append(self.args[pos:pos+L]) - pos += L - lloutputs = [] - for r in self.target_r: - L = len(r.impl) - lloutputs.append(self.args[pos:pos+L]) - pos += L - - llrepr = [] # answer - for i in range(len(self.source_r)): - if self.source_r[i] != self.target_r[i]: - # convert this item - llrepr += typer.convert(self.source_r[i], llinputs[i], - self.target_r[i], lloutputs[i]) - else: - # don't convert, just pass this item unchanged to the result - llrepr += llinputs[i] - return llrepr - -class LoNewTuple(LoC): - can_fail = True - cost = 3 - macro = 'OP_NEWTUPLE' - # self.args: [input PyObjects.., output PyObject] - def writestr(self, *stuff): - args = stuff[:-2] - result = stuff[-2] - err = stuff[-1] - ls = ['%s(%d, %s, %s)' % (self.macro, len(args), result, err)] - for i in range(len(args)): - ls.append('%s_SET(%s, %d, %s)' % (self.macro, result, i, args[i])) - return '\n'.join(ls) - -class LoNewList(LoNewTuple): - macro = 'OP_NEWLIST' - # self.args: [input PyObjects.., output PyObject] - -class LoNewArray(LoC): - can_fail = True - typename = PARAMETER # the name of the PyList_Xxx type in the C source - lltypes = PARAMETER # the C types needed to represent each array item - length = PARAMETER - # self.args: [item0.., item1.., item2.., ..., output PyObject] - def writestr(self, *stuff): - args = stuff[:-2] - result = stuff[-2] - err = stuff[-1] - assert len(args) == self.length * len(self.lltypes) - ls = ['OP_NEWARRAY(%s, %d, %s, %s)' % ( - self.typename, self.length, result, err)] - for i in range(self.length): - for j in range(len(self.lltypes)): - if self.lltypes[j] == 'PyObject*': - typecode = '_o' - else: - typecode = '' - a = args[i*len(self.lltypes) + j] - ls.append('OP_NEWARRAY_SET%s(%s, %s, %d, a%d, %s)' % ( - typecode, self.typename, result, i, j, a)) - return '\n'.join(ls) - -class LoAllocAndSetArray(LoC): - can_fail = True - typename = PARAMETER # the name of the PyList_Xxx type in the C source - lltypes = PARAMETER # the C types needed to represent each array item - # self.args: [length, input_item.., output PyObject] - def writestr(self, length, *stuff): - input = stuff[:-2] - result = stuff[-2] - err = stuff[-1] - assert len(input) == len(self.lltypes) - ls = ['OP_NEWARRAY(%s, %s, %s, %s)' % ( - self.typename, length, result, err)] - if len(self.lltypes) > 0: - ls.append('{ int i; for (i=0; i<%s; i++) {' % length) - for j in range(len(self.lltypes)): - if self.lltypes[j] == 'PyObject*': - typecode = '_o' - else: - typecode = '' - a = input[j] - ls.append('\tOP_NEWARRAY_SET%s(%s, %s, i, a%d, %s)' % ( - typecode, self.typename, result, j, a)) - ls.append('} }') - return '\n'.join(ls) - -class LoGetArrayItem(LoC): - typename = PARAMETER # the name of the PyList_Xxx type in the C source - lltypes = PARAMETER # the C types needed to represent each array item - macro = 'OP_GETARRAYITEM' - # self.args: [PyObject, int_index, output_item..] - def writestr(self, array, index, *output): - assert len(output) == len(self.lltypes) - ls = [] - for j in range(len(self.lltypes)): - if self.lltypes[j] == 'PyObject*': - typecode = '_o' - else: - typecode = '' - ls.append('%s%s(%s, %s, %s, a%d, %s)' % ( - self.macro, typecode, self.typename, - array, index, j, output[j])) - return '\n'.join(ls) - -class LoSetArrayItem(LoGetArrayItem): - macro = 'OP_SETARRAYITEM' - # self.args: [PyObject, int_index, input_item..] - -class LoArrayGrow(LoC): - can_fail = True - cost = 3 - typename = PARAMETER - # self.args: [PyObject, int_extralen] - def writestr(self, array, extralen, err): - return 'OP_GROWLIST(%s, %s, %s, %s)' % (self.typename, array, - extralen, err) - -class LoArrayFastAppend(LoSetArrayItem): - # self.args: [PyObject, new_item..] - def writestr(self, array, *newitem): - index = 'ARRAYLEN(%s)' % array - ls = [LoSetArrayItem.writestr(self, array, index, *newitem), - '%s++;' % index] - return '\n'.join(ls) - -class LoGetAttr(LoC): - cost = 1 - fld = PARAMETER - # self.args: [PyObject instance, result..] - def writestr(self, inst, *result): - ls = [] - if self.fld.is_class_attr: - macro = 'OP_GETCLASSATTR' - else: - macro = 'OP_GETINSTATTR' - llclass = self.fld.llclass - for src, dstname in zip(self.fld.llvars, result): - if src.type == 'PyObject*': - typecode = '_o' - else: - typecode = '' - ls.append('%s%s(%s, %s, %s, %s)' % ( - macro, typecode, llclass.name, inst, src.name, dstname)) - return '\n'.join(ls) - -class LoGetAttrMethod(LoGetAttr): - # self.args: [PyObject instance, result..] - def optimize(self, typer, llresult): - # for a OP_GETATTR that must return a bound method. The 'self' - # part of the result can be statically copied from self.args[0]. - # The rest is done as with LoGetAttr. - inst = self.args[0] - llresult[-1] = inst # patch to do the copy statically - return False # proceed with the normal LoGetAttr.writestr() - -class LoSetAttr(LoC): - cost = 1 - llclass = PARAMETER # the class involved in the operation - fld = PARAMETER # the field, which might come from a parent class - # self.args: [PyObject instance, new value..] - def writestr(self, inst, *value): - assert len(value) == len(self.fld.llvars) - ls = [] - for srcname, dst in zip(value, self.fld.llvars): - if dst.type == 'PyObject*': - typecode = '_o' - else: - typecode = '' - ls.append('OP_SETINSTATTR%s(%s, %s, %s, %s)' % ( - typecode, self.llclass.name, inst, dst.name, srcname)) - return '\n'.join(ls) - -class LoInitClassAttr(LoC): - cost = 1 - llclass = PARAMETER # the class involved in the operation - fld = PARAMETER # the field, which might come from a parent class - # self.args: [constant value to store..] - def writestr(self, *value): - assert len(value) == len(self.fld.llvars) - ls = [] - # setting class attributes is only used for initialization - for srcname, dst in zip(value, self.fld.llvars): - if dst.type == 'PyObject*': - typecode = '_o' - else: - typecode = '' - ls.append('OP_INITCLASSATTR%s(%s, %s, %s)' % ( - typecode, self.llclass.name, dst.name, srcname)) - return '\n'.join(ls) - -class LoConvertBoundMethod(LoOptimized): - r_source = PARAMETER - r_target = PARAMETER - cost = PARAMETER - # self.args: [im_func.., im_self PyObject, output im_func.., im_self PyObj] - def optimized_result(self, typer): - slen = len(self.r_source.impl) - tlen = len(self.r_target.impl) - assert len(self.args) == slen+1+tlen+1 - # convert the 'func' part of the method - answer = typer.convert(self.r_source, self.args[:slen], - self.r_target, self.args[slen+1:-1]) - # pass the 'self' argument unchanged - answer.append(self.args[slen]) - return answer - -class LoConvertChain(LoOptimized): - r_from = PARAMETER - r_middle = PARAMETER - r_to = PARAMETER - cost = PARAMETER - # self.args: [input value.., output value..] - def optimized_result(self, typer): - half = len(self.r_from.impl) - assert half + len(self.r_to.impl) == len(self.args) - input = self.args[:half] - output = self.args[half:] - middle = typer.convert(self.r_from, input, self.r_middle) - return typer.convert(self.r_middle, middle, self.r_to, output) - -class LoDummyResult(LoC): - cost = 1 - # self.args: [output value..] - def write(self): - ls = [] - for a in self.args: - if a.type == 'PyObject*': - ls.append('OP_DUMMYREF(%s)' % a.name) - return '\n'.join(ls) - -# ____________________________________________________________ - -class LoMove(LoC): - cost = 1 - # self.args: [input LLVar, output LLVar] - def writestr(self, x, y): - return 'MOVE(%s, %s)' % (x, y) - -class LoGoto(LoC): - cost = 0 - # self.args: [] - def write(self): - return 'goto %s;' % self.errtarget - -class LoCopy(LoOptimized): - cost = 0 - # self.args: [input LLVars.., output LLVars..] - def optimized_result(self, typer): - # the result's llvars is equal to the input's llvars. - assert len(self.args) % 2 == 0 - half = len(self.args) // 2 - return self.args[:half] - -class LoDoSomethingWithRef(LoC): - do_what = PARAMETER - cost = 1 - # self.args: [value..] - def write(self): - ls = [] - for a in self.args: - if a.type == 'PyObject*': - ls.append('%s(%s);' % (self.do_what, a.name)) - return ' '.join(ls) - -LoIncref = LoDoSomethingWithRef.With(do_what = 'Py_INCREF') -LoDecref = LoDoSomethingWithRef.With(do_what = 'Py_DECREF') -LoXDecref = LoDoSomethingWithRef.With(do_what = 'Py_XDECREF') - -class LoComment(LoC): - cost = 0 - # self.args: [] - def write(self): - s = self.errtarget - s = s.replace('/*', '/+') - s = s.replace('*/', '+/') - return '/* %s */' % s - -# ____________________________________________________________ - -ERROR_RETVAL = { - None: '-1', - 'int': '-1', - } - -class LoCallPyFunction(LoC): - can_fail = True - hlrettype = PARAMETER - # self.args: [C function pointer, arguments.., result..] - def write(self): - funcptr = self.args[0].name - L = len(self.hlrettype.impl) - R = len(self.args) - L - args = [a.name for a in self.args[1:R]] - err = self.errtarget - if L == 0: # no return value - return 'OP_CCALL_v(%s, (%s), %s)' % (funcptr, ', '.join(args), err) - else: - # the return value is the first return LLVar: - retvar = self.args[R] - # if there are several return LLVars, the extra ones are passed - # in by reference as output arguments - args += ['&%s' % a.name for a in self.args[R+1:]] - if retvar.type == 'int': - typecode = '_i' - else: - typecode = '' - return 'OP_CCALL%s(%s, (%s), %s, %s)' % ( - typecode, funcptr, ', '.join(args), retvar.name, err) - -class LoReturn(LoC): - cost = 1 - # self.args: [return value..] - def write(self): - if not self.args: - return 'return 0;' - ls = [] - for extra in self.args[1:]: - ls.append('*output_%s = %s;' % (extra.name, extra.name)) - ls.append('return %s;' % self.args[0].name) - return '\n'.join(ls) - -# ____________________________________________________________ Deleted: /pypy/trunk/src/pypy/translator/genc_repr.py ============================================================================== --- /pypy/trunk/src/pypy/translator/genc_repr.py Sat Oct 9 10:44:33 2004 +++ (empty file) @@ -1,385 +0,0 @@ -""" -High-level types and how variables of that type are represented by a -series of low-level variables. -""" - -import types, __builtin__ -from pypy.translator.typer import CannotConvert, LLConst -from pypy.translator import genc_op - - -class CRepr: - "A possible representation of a flow-graph variable as C-level variables." - parse_code = None # character(s) for PyArg_ParseTuple() - - def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, ' + '.join(self.impl)) - - def convert_to(self, target, typeset): - raise CannotConvert - - -class CAtomicRepr(CRepr): - "A simple C type." - - def __init__(self, impl, parse_code=None): - self.impl = impl - self.parse_code = parse_code - - -class CUndefined(CRepr): - "An undefined value. (singleton class)" - impl = [] - - def convert_to(self, target, typeset): - return genc_op.LoDummyResult - - -class CConstant(CRepr): - "A constant value." - impl = [] - - def __init__(self, value): - self.value = value - - def __repr__(self): - return 'CConstant(%r)' % (self.value,) - - def convert_to_pyobj(self, initexpr, globalname): - # helper for subclasses - return genc_op.LoKnownAnswer.With( - known_answer = [LLConst('PyObject*', globalname, initexpr, - to_declare = bool(initexpr))], - ) - -class CConstantInt(CConstant): - def convert_to(self, target, typeset): - if target == R_INT: - # can convert the constant to a C int - return genc_op.LoKnownAnswer.With( - known_answer = [LLConst('int', '%d' % self.value)], - ) - elif target == R_OBJECT: - # can convert the constant to a PyObject* - if self.value >= 0: - name = 'g_IntObj_%d' % self.value - else: - name = 'g_IntObj_minus%d' % abs(self.value) - return self.convert_to_pyobj( - 'PyInt_FromLong(%d)' % self.value, - name) - else: - raise CannotConvert - -class CConstantStr(CConstant): - def convert_to(self, target, typeset): - if target == R_OBJECT: - # can convert the constant to a PyObject* - return self.convert_to_pyobj( - 'PyString_FromStringAndSize(%s, %d)' % (c_str(self.value), - len(self.value)), - 'g_StrObj_%s' % manglestr(self.value)) - else: - raise CannotConvert - -class CConstantNone(CConstant): - def convert_to(self, target, typeset): - if target == R_OBJECT: - # can convert the constant to a PyObject* - return self.convert_to_pyobj(None, 'Py_None') - else: - raise CannotConvert - -class CConstantBuiltin(CConstant): # a constant from the __builtin__ module - def convert_to(self, target, typeset): - if target == R_OBJECT: - # can load the constant as a PyObject* from the builtins - fn = self.value - if getattr(__builtin__, fn.__name__, None) is not fn: - raise CannotConvert # unless it doesn't appear to be there - return self.convert_to_pyobj( - 'PyMapping_GetItemString(PyEval_GetBuiltins(), %s)' % ( - c_str(fn.__name__)), - 'g_Builtin_%s' % manglestr(fn.__name__)) - else: - raise CannotConvert - -class CConstantFunction(CConstant): - def convert_to(self, target, typeset): - if isinstance(target, CFunction): - fn = self.value - if fn not in typeset.genc.llfunctions: - raise CannotConvert - llfunc = typeset.genc.llfunctions[fn] - my_header_r = typeset.getfunctionsig(llfunc) - if my_header_r != target.header_r: - raise CannotConvert(self, my_header_r, target) - cfunctype, = target.impl - return genc_op.LoKnownAnswer.With( - known_answer = [LLConst(cfunctype, llfunc.name)], - ) - else: - raise CannotConvert - - -class CTuple(CRepr): - "An unpacked tuple. Represents all its items independently." - - def __init__(self, items_r): - self.items_r = tuple(items_r) - self.impl = [] - for r in items_r: - self.impl += r.impl - - def __repr__(self): - return 'CTuple(%s)' % ', '.join([repr(r) for r in self.items_r]) - - def convert_to(self, target, typeset): - if isinstance(target, CTuple): - if len(self.items_r) != len(target.items_r): - raise CannotConvert - # convert each tuple item that needs to be converted - cost = 0 - for r1, r2 in zip(self.items_r, target.items_r): - if r1 != r2: - cost += typeset.getconversion(r1, r2).cost - return genc_op.LoConvertTupleItem.With( - source_r = self.items_r, - target_r = target.items_r, - cost = cost, - ) - elif target == R_OBJECT: - # to convert a tuple to a PyTupleObject* we first need to - # make sure that all items are PyObject*. - intermediate_r = (R_OBJECT,) * len(self.items_r) - if self.items_r == intermediate_r: - return genc_op.LoNewTuple # already the case - else: - r_middle = tuple_representation(intermediate_r) - cost1 = typeset.getconversion(self, r_middle).cost - return genc_op.LoConvertChain.With( - r_from = self, - r_middle = r_middle, - r_to = target, - cost = cost1 + genc_op.LoNewTuple.cost, - ) - else: - raise CannotConvert - - -class CInstance(CRepr): - "An instance of some class (or a subclass of it)." - impl = ['PyObject*'] - - def __init__(self, llclass): - self.llclass = llclass # instance of classtyper.LLClass or None - # R_INSTANCE is CInstance(None): a match-all, any-type instance. - - def __repr__(self): - if self.llclass is None: - return 'CInstance(*)' - else: - cls = self.llclass.cdef.cls - return 'CInstance(%s.%s)' % (cls.__module__, cls.__name__) - - def convert_to(self, target, typeset): - if isinstance(target, CInstance): - if not (self.llclass is None or target.llclass is None): - # can only convert to an instance of a parent class - if target.llclass.cdef not in self.llclass.cdef.getmro(): - raise CannotConvert - return genc_op.LoCopy - elif target == R_OBJECT: - # can convert to a generic PyObject* - return genc_op.LoCopy - else: - raise CannotConvert - - -class CFunction(CRepr): - "A C-level function or a pointer to a function." - - def __init__(self, header_r): - self.header_r = header_r # list of CReprs: [arg1, arg2, ..., retval] - # C syntax is quite strange: a pointer to a function is declared - # with a syntax like "int (*varname)(long, char*)". We build here - # a 'type' string like "int (*@)(long, char*)" that will be combined - # with an actual name by cdecl() below. Oh, and by the way, to - # make a string like "int (*@)(long, char*)" we need to use cdecl() - # as well, because the "int" which is the return type could itself - # contain a "@"... for functions returning pointers to functions. - llargs = [] - for r in header_r[:-1]: - llargs += [cdecl(atype, '') for atype in r.impl] - llret = header_r[-1].impl - # same logic as get_llfunc_header() - if len(llret) == 0: - retlltype = 'int' # no return value needed, returns an error flag - elif len(llret) == 1: - retlltype = llret[0] - else: - # if there is more than one C return type, only the first one is - # returned and the other ones are returned via ptr output args - retlltype = llret[0] - llargs += [cdecl(atype, '*') for atype in llret[1:]] - cfunctype = cdecl(retlltype, '(*@)(%s)' % ', '.join(llargs)) - self.impl = [cfunctype] - - def __repr__(self): - args = [repr(r) for r in self.header_r[:-1]] - return 'CFunction(%s -> %r)' % (', '.join(args), self.header_r[-1]) - - -class CMethod(CRepr): - "A CFunction or CConstantFunction with its first argument bound." - - def __init__(self, r_func): - self.r_func = r_func - self.impl = r_func.impl + ['PyObject*'] - - def __repr__(self): - return 'CMethod(%r)' % (self.r_func,) - - def convert_to(self, target, typeset): - if not isinstance(target, CMethod): - raise CannotConvert - cost = typeset.getconversion(self.r_func, target.r_func).cost - return genc_op.LoConvertBoundMethod.With( - r_source = self.r_func, - r_target = target.r_func, - cost = cost, - ) - -class CList(CRepr): - "A list as an array whose items are represented as r_item." - - def __init__(self, r_item): - self.r_item = r_item - self.impl = ['PyObject*'] - - def __repr__(self): - return 'CList(%r)' % (self.r_item,) - - def convert_to(self, target, typeset): - if target == R_OBJECT: - # can convert to a generic PyObject* - # (but not, or not yet, to a regular PyListObject*!) - return genc_op.LoCopy - else: - raise CannotConvert - -# ____________________________________________________________ -# -# Predefined CReprs and caches for building more - -R_VOID = CAtomicRepr([]) -R_INT = CAtomicRepr(['int'], parse_code='i') -R_OBJECT = CAtomicRepr(['PyObject*'], parse_code='O') -R_UNDEFINED = CUndefined() -R_INSTANCE = CInstance(None) - -R_TUPLE_CACHE = {} -R_CONSTANT_CACHE = {} -R_INSTANCE_CACHE = {} -R_FUNCTION_CACHE = {} -R_METHOD_CACHE = {} -R_LIST_CACHE = {} - -def tuple_representation(items_r): - items_r = tuple(items_r) - try: - return R_TUPLE_CACHE[items_r] - except KeyError: - rt = R_TUPLE_CACHE[items_r] = CTuple(items_r) - return rt - -CONST_TYPES = { - int: CConstantInt, - str: CConstantStr, - types.NoneType: CConstantNone, - types.BuiltinFunctionType: CConstantBuiltin, - types.FunctionType: CConstantFunction, - } - -def constant_representation(value): - key = type(value), value # to avoid mixing for example 0 and 0.0 - try: - return R_CONSTANT_CACHE[key] - except KeyError: - if isinstance(value, tuple): - # tuples have their own representation and - # don't need a fully constant representation - items_r = [constant_representation(x) for x in value] - return tuple_representation(items_r) - for cls in type(value).__mro__: - if cls in CONST_TYPES: - cls = CONST_TYPES[cls] - break - else: - if isinstance(value, types.MethodType) and value.im_self is None: - # replace unbound methods with plain funcs - return constant_representation(value.im_func) - cls = CConstant - r = R_CONSTANT_CACHE[key] = cls(value) - return r - -def instance_representation(llclass): - try: - return R_INSTANCE_CACHE[llclass] - except KeyError: - r = R_INSTANCE_CACHE[llclass] = CInstance(llclass) - return r - -def function_representation(sig): - key = tuple(sig) - try: - return R_FUNCTION_CACHE[key] - except KeyError: - r = R_FUNCTION_CACHE[key] = CFunction(sig) - return r - -def method_representation(r_func): - key = r_func - try: - return R_METHOD_CACHE[key] - except KeyError: - r = R_METHOD_CACHE[key] = CMethod(r_func) - return r - -def list_representation(r_item): - try: - return R_LIST_CACHE[r_item] - except KeyError: - r = R_LIST_CACHE[r_item] = CList(r_item) - return r - - -def c_str(s): - "Return the C expression for the string 's'." - s = repr(s) - if s.startswith("'"): - s = '"' + s[1:-1].replace('"', r'\"') + '"' - return s - -def manglestr(s): - "Return an identifier name unique for the string 's'." - l = [] - for c in s: - if not ('a' <= c <= 'z' or 'A' <= c <= 'Z' or '0' <= c <= '9'): - if c == '_': - c = '__' - else: - c = '_%02x' % ord(c) - l.append(c) - return ''.join(l) - -def cdecl(type, name): - # Utility to generate a typed name declaration in C syntax. - # For local variables, struct fields, function declarations, etc. - # For complex C types, the 'type' can contain a '@' character that - # specifies where the 'name' should be inserted; for example, an - # array of 10 ints has a type of "int @[10]". - if '@' in type: - return type.replace('@', name) - else: - return ('%s %s' % (type, name)).rstrip() Deleted: /pypy/trunk/src/pypy/translator/genc_typeset.py ============================================================================== --- /pypy/trunk/src/pypy/translator/genc_typeset.py Sat Oct 9 10:44:33 2004 +++ (empty file) @@ -1,446 +0,0 @@ -from __future__ import generators -import re -from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant -from pypy.annotation import model as annmodel -from pypy.translator import genc_op -from pypy.translator.typer import CannotConvert, TypingError, LLConst -from pypy.translator.genc_repr import R_VOID, R_INT, R_OBJECT, R_UNDEFINED -from pypy.translator.genc_repr import R_INSTANCE -from pypy.translator.genc_repr import tuple_representation -from pypy.translator.genc_repr import constant_representation, CConstant -from pypy.translator.genc_repr import instance_representation, CInstance -from pypy.translator.genc_repr import function_representation, CFunction -from pypy.translator.genc_repr import CConstantFunction -from pypy.translator.genc_repr import method_representation, CMethod -from pypy.translator.genc_repr import list_representation, CList - - -class CTypeSet: - "A (small) set of C types that typer.LLFunction can manipulate." - - REPR_BY_CODE = { - 'v': R_VOID, - 'i': R_INT, - 'o': R_OBJECT, - } - - rawoperations = { - 'goto' : genc_op.LoGoto, - 'move' : genc_op.LoMove, - 'copy' : genc_op.LoCopy, - 'incref' : genc_op.LoIncref, - 'decref' : genc_op.LoDecref, - 'xdecref': genc_op.LoXDecref, - 'comment': genc_op.LoComment, - 'return' : genc_op.LoReturn, - } - - def __init__(self, genc, bindings): - self.genc = genc - self.bindings = bindings - self.conversion_cache = {} - self.conversion_errors = {} - self.lloperations = {'CONVERT': self.conversion_cache} - self.parse_operation_templates() - - # __________ methods required by LLFunction __________ - # - # Here, we assume that every high-level type has a canonical representation - # so a high-level type is just a CRepr. - - def gethltype(self, var, unbound=False): - if isinstance(var, Variable): - var = self.bindings.get(var) or annmodel.SomeObject() - if isinstance(var, annmodel.SomeObject): - if var.is_constant(): - return constant_representation(var.const) - if issubclass(var.knowntype, int): - return R_INT - if isinstance(var, annmodel.SomeImpossibleValue): - return R_VOID - if isinstance(var, annmodel.SomeTuple): - items_r = [self.gethltype(s_item) for s_item in var.items] - return tuple_representation(items_r) - if isinstance(var, annmodel.SomeInstance): - llclass = self.genc.llclasses[var.knowntype] - return instance_representation(llclass) - if isinstance(var, annmodel.SomeFunction): - func_sig = self.regroup_func_sig(var.funcs) - return function_representation(func_sig) - if isinstance(var, annmodel.SomeMethod): - r_func = self.gethltype(annmodel.SomeFunction(var.meths)) - if unbound: - return r_func - else: - return method_representation(r_func) - if isinstance(var, annmodel.SomeList): - r_item = self.gethltype(var.s_item) - typename = self.genc.declare_list(r_item.impl) - r = list_representation(r_item) - r.typename = typename - return r - # fall-back - return R_OBJECT - if isinstance(var, UndefinedConstant): - return R_UNDEFINED - if isinstance(var, Constant): - return constant_representation(var.value) - raise TypeError, var - - def represent(self, hltype): - return hltype.impl - - def getconversion(self, hltype1, hltype2): - sig = hltype1, hltype2 - if sig in self.conversion_errors: - raise CannotConvert(hltype1, hltype2) # shortcut - try: - return self.conversion_cache[sig] - except KeyError: - try: - llopcls = hltype1.convert_to(hltype2, self) - self.conversion_cache[sig] = llopcls - return llopcls - except CannotConvert, e: - self.conversion_errors[sig] = True - if not e.args: - e.args = hltype1, hltype2 - raise - - def typemismatch(self, opname, hltypes): - # build operations on demand, e.g. if they take a variable number - # of arguments or depend on a constant value (e.g. the class being - # instantiated). - try: - extender = getattr(self, 'extend_' + opname) - except AttributeError: - return - for newsig, newop in extender(hltypes): - # record the new operation only if it has a lower cost than - # an existing operation with the same signature - llops = self.lloperations.setdefault(opname, {}) - if newsig not in llops or newop.cost < llops[newsig].cost: - llops[newsig] = newop - - # ____________________________________________________________ - - def getfunctionsig(self, llfunc): - "Get the high-level header (argument types and result) for a function." - # XXX messy! we allow different CInstances to appear as function - # arguments by replacing them with the generic R_INSTANCE. - # This is not too clean, but it might be unavoidable, because - # the whole implementation relies on this "coincidence" that - # pointers to objects of different classes are interchangeable. - result = [] - for v in llfunc.graph.getargs() + [llfunc.graph.getreturnvar()]: - r = self.gethltype(v) - if isinstance(r, CInstance): - r = R_INSTANCE - result.append(r) - return result - - def regroup_func_sig(self, funcs): - # find a common signature for the given functions - signatures = [] - for func in funcs: - llfunc = self.genc.llfunctions[func] - signatures.append(self.getfunctionsig(llfunc)) - # XXX we expect the functions to have exactly the same signature - # but this is currently not enforced by the annotator. - result = signatures[0] - for test in signatures[1:]: - if test != result: - raise TypingError(test, result) - return result - - # ____________________________________________________________ - # - # Each extend_OPNAME() method below is called when there is no direct - # match for the given hltypes for the operation OPNAME. - # The extend_XXX() methods should produce (yield) as many low-level - # operation signatures as they like, using the hltypes as a guide; - # once all these have been generated, the algorithms in typer.py will - # look for a best approximate match, doing conversions if needed. - # - # For example, extend_OP_GETITEM() is called with - # hltypes == (repr_of_obj, repr_of_index, repr_of_result). - # When it is called with an instance of CList in hltypes[0], it - # generates the operation that reads an item out of this kind of array. - # This operation takes exactly an R_INT index (which may differ from - # hltypes[1]) and produce a result of exactly the CList's r_item type - # (which may differ from hltypes[2]). Then typer.py will try to - # convert the index from hltypes[1] to R_INT and convert the result back - # to hltypes[2]. - - def extend_OP_NEWLIST(self, hltypes): - if not hltypes: - return - # LoNewList can build a list of any length from PyObject* args. - sig = (R_OBJECT,) * len(hltypes) - yield sig, genc_op.LoNewList - - # LoNewArray can build an array from items of the correct type. - r = hltypes[-1] - if isinstance(r, CList): - sig = (r.r_item,) * (len(hltypes)-1) + (r,) - yield sig, genc_op.LoNewArray.With( - typename = r.typename, - lltypes = r.r_item.impl, - length = len(hltypes)-1, - ) - - def extend_OP_ALLOC_AND_SET(self, hltypes): - if len(hltypes) != 3: - return - # we have LoAllocAndSetArray - r_length, r_input, r = hltypes - if isinstance(r, CList): - sig = (R_INT, r.r_item, r) - yield sig, genc_op.LoAllocAndSetArray.With( - typename = r.typename, - lltypes = r.r_item.impl, - ) - - def extend_OP_NEWTUPLE(self, hltypes): - # We can use LoCopy to virtually build a tuple because - # the tuple representation 'rt' is just the collection of all the - # representations for the input args. - rt = tuple_representation(hltypes[:-1]) - sig = tuple(hltypes[:-1]) + (rt,) - yield sig, genc_op.LoCopy - - def extend_OP_SIMPLE_CALL(self, hltypes): - if not hltypes: - return - # We can call the function using PyObject_CallFunction(), if - # it can be converted to PyObject*. - sig = (R_OBJECT,) * len(hltypes) - yield sig, genc_op.LoCallFunction - - r = hltypes[0] - if (isinstance(r, CConstantFunction) and - r.value in self.genc.llfunctions): - # a constant function can be converted to a function pointer, - # so we fall back to the latter case - llfunc = self.genc.llfunctions[r.value] - r = function_representation(self.getfunctionsig(llfunc)) - - if isinstance(r, CFunction): - # a function pointer (the pointer is a C pointer, but points - # to a C function generated from a user-defined Python function). - sig = (r,) + tuple(r.header_r) - yield sig, genc_op.LoCallPyFunction.With( - hlrettype = sig[-1], - ) - - if isinstance(r, CMethod): - # first consider how we could call the underlying function - # with an extra R_INSTANCE first argument - hltypes2 = (r.r_func, R_INSTANCE) + hltypes[1:] - self.typemismatch('OP_SIMPLE_CALL', hltypes2) - # then lift all OP_SIMPLE_CALLs to method calls - opsimplecall = self.lloperations.setdefault('OP_SIMPLE_CALL', {}) - for sig, opcls in opsimplecall.items(): - if sig[1:2] == (R_INSTANCE,): - r_meth = method_representation(sig[0]) - sig2 = (r_meth,) + sig[2:] - yield sig2, opcls - # Note that we are reusing the same opcls. Indeed, both the - # original 'sig' and the modified one expand to the same list - # of LLVars, so opcls cannot tell the difference: - # - # sig = r.r_func R_INSTANCE ... - # /-----\ /------------\ - # LLVars: funcptr, PyObject* self, arguments..., result - # \-----------------------/ - # sig2 = r_meth ... - - if isinstance(r, CConstant): - # maybe it is a well-known constant non-user-defined function - fn = r.value - if not callable(fn): - return - # Instantiating a user-defined class - if fn in self.genc.llclasses: - # XXX do __init__ - llclass = self.genc.llclasses[fn] - r_result = instance_representation(llclass) - sig = (r, r_result) # r_result is the result of the op - yield sig, genc_op.LoInstantiate.With( - llclass = self.genc.llclasses[fn], - ) - # Calling a built-in defined in genc.h, if we have a macro - # CALL_funcname() - opname = 'CALL_' + getattr(fn, '__name__', '?') - self.typemismatch(opname, hltypes[1:]) # invoke extend_CALL_xxx() - if opname in self.lloperations: - for sig, llopcls in self.lloperations[opname].items(): - sig = (r,) + sig - yield sig, llopcls - - def extend_OP_ALLOC_INSTANCE(self, hltypes): - # OP_ALLOC_INSTANCE is used by the constructor functions xxx_new() - if not hltypes: - return - r = hltypes[0] - if isinstance(r, CConstant): - fn = r.value - if not callable(fn): - return - if fn in self.genc.llclasses: - llclass = self.genc.llclasses[fn] - r_result = instance_representation(llclass) - sig = (r, r_result) # r_result is the result of the op - yield sig, genc_op.LoAllocInstance.With( - llclass = llclass, - ) - - def extend_OP_GETATTR(self, hltypes): - if len(hltypes) != 3: - return - r_obj, r_attr, r_result = hltypes - if not isinstance(r_attr, CConstant): - return - if isinstance(r_obj, CInstance): - # record the OP_GETATTR operation for this field - fld = (r_obj.llclass.get_instance_field(r_attr.value) or - r_obj.llclass.get_class_field(r_attr.value)) - if fld is None: - return - sig = (r_obj, r_attr, fld.hltype) - # special case: reading a function out of a class attribute - # produces a bound method - if fld.is_class_attr: - r = sig[-1] - if isinstance(r, (CFunction, CConstantFunction)): - r_method = method_representation(r) - sig = (r_obj, r_attr, r_method) - yield sig, genc_op.LoGetAttrMethod.With( - fld = fld, - ) - return - # common case - yield sig, genc_op.LoGetAttr.With( - fld = fld, - ) - - def extend_OP_SETATTR(self, hltypes): - if len(hltypes) != 4: - return - r_obj, r_attr, r_value, r_voidresult = hltypes - if not isinstance(r_attr, CConstant): - return - if isinstance(r_obj, CInstance): - # record the OP_SETATTR operation for this field - fld = r_obj.llclass.get_instance_field(r_attr.value) - if fld is not None: - sig = (r_obj, r_attr, fld.hltype, R_VOID) - yield sig, genc_op.LoSetAttr.With( - fld = fld, - llclass = r_obj.llclass, - ) - - def extend_OP_INITCLASSATTR(self, hltypes): - # only to initialize class attributes - if len(hltypes) != 4: - return - r_obj, r_attr, r_value, r_voidresult = hltypes - if isinstance(r_attr, CConstant) and isinstance(r_obj, CConstant): - cls = r_obj.value - if cls in self.genc.llclasses: - llclass = self.genc.llclasses[cls] - fld = llclass.get_class_field(r_attr.value) - if fld is not None: - sig = (r_obj, r_attr, fld.hltype, R_VOID) - yield sig, genc_op.LoInitClassAttr.With( - fld = fld, - llclass = llclass, - ) - - def extend_OP_GETITEM(self, hltypes): - if len(hltypes) != 3: - return - r, r_index, r_result = hltypes - # reading from a CList - if isinstance(r, CList): - sig = (r, R_INT, r.r_item) - yield sig, genc_op.LoGetArrayItem.With( - typename = r.typename, - lltypes = r.r_item.impl, - ) - - def extend_OP_SETITEM(self, hltypes): - if len(hltypes) != 4: - return - r, r_index, r_value, r_void = hltypes - # writing into a CList - if isinstance(r, CList): - sig = (r, R_INT, r.r_item, R_VOID) - yield sig, genc_op.LoSetArrayItem.With( - typename = r.typename, - lltypes = r.r_item.impl, - ) - - def extend_OP_LEN(self, hltypes): - if len(hltypes) != 2: - return - r, r_result = hltypes - # the length of a CList - if isinstance(r, CList): - sig = (r, R_INT) - yield sig, genc_op.LoStandardOperation.With( - can_fail = False, - llname = 'OP_ARRAYLEN', - cost = 1, - ) - - extend_CALL_len = extend_OP_LEN - - def extend_OP_GROWLIST(self, hltypes): - if len(hltypes) != 3: - return - r, r_newlen, r_void = hltypes - # grow a CList - if isinstance(r, CList): - sig = (r, R_INT, R_VOID) - yield sig, genc_op.LoArrayGrow.With( - typename = r.typename, - ) - - def extend_OP_FASTAPPEND(self, hltypes): - # like append() but can assume that the list was already - # reallocated with OP_GROWLIST and has enough room - if len(hltypes) != 3: - return - r, r_newitem, r_void = hltypes - # append to a CList - if isinstance(r, CList): - sig = (r, r.r_item, R_VOID) - yield sig, genc_op.LoArrayFastAppend.With( - typename = r.typename, - lltypes = r.r_item.impl, - ) - - # ____________________________________________________________ - - def parse_operation_templates(self): - # parse the genc.h header to figure out which macros are implemented - codes = ''.join(self.REPR_BY_CODE.keys()) - pattern = r"#define ([A-Za-z_][0-9A-Za-z_]*)_([%s]*)[(](.*?)[)]" % codes - rexp = re.compile(pattern) - for line in self.genc.C_HEADER.split('\n'): - match = rexp.match(line) - if match: - self.register_operation_template(*match.groups()) - - def register_operation_template(self, opname, typecodes, formalargs): - llname = '%s_%s' % (opname, typecodes) - sig = tuple([self.REPR_BY_CODE[code] for code in typecodes]) - can_fail = formalargs.replace(' ','').endswith(',err') - ops = self.lloperations.setdefault(opname, {}) - assert sig not in ops, llname - ops.setdefault(sig, genc_op.LoStandardOperation.With( - can_fail = can_fail, - llname = llname, - cost = 1 + typecodes.count('o'), # rough cost estimate - )) Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Sat Oct 9 10:44:33 2004 @@ -84,7 +84,8 @@ self.assertEquals(sand(0, 6), "no") self.assertEquals(sand(0, 0), "no") -class TypedTestCase(testit.IntTestCase): +if 0: + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): t = Translator(func) Deleted: /pypy/trunk/src/pypy/translator/typer.py ============================================================================== --- /pypy/trunk/src/pypy/translator/typer.py Sat Oct 9 10:44:33 2004 +++ (empty file) @@ -1,439 +0,0 @@ -""" -Graph-to-low-level transformer for C/Assembler code generators. -""" - -from __future__ import generators -from pypy.objspace.flow.model import Variable, Block, Link, traverse -from pypy.translator.simplify import remove_direct_loops - - -class LLVar: - "A variable in the low-level language." - def __init__(self, type, name): - self.type = type # low-level type in any format, e.g. a C type name - self.name = name - -class LLConst(LLVar): - "A global, constant, preinitialized variable." - def __init__(self, type, name, initexpr=None, to_declare=False): - LLVar.__init__(self, type, name) - self.initexpr = initexpr - self.to_declare = to_declare - -class LLOp(object): - "A low-level operation. Must be subclassed, one subclass per operation." - can_fail = False # boolean attribute: should an errtarget be generated? - - def __init__(self, args, errtarget=None): - self.args = args # list of LLVars - self.errtarget = errtarget # label to jump to in case of error - - def optimize(self, typer, llresult): - """If the operation can be statically optimized, this method can - patch the llresult list of LLVars and optionally generate - replacement operations by calling typer.operation() or - typer.convert(). Can return True to skip the 'self' operation.""" - return False - -class TypingError(Exception): - pass - -class CannotConvert(Exception): - pass - - -# ____________________________________________________________ -# -# below, a 'typeset' is an object with the following methods/attributes: -# -# def gethltype(self, var_or_const) -# Return the high-level type of a var or const. -# -# def represent(self, hltype) -# Return a list of LLTypes that together implement the high-level type. -# -# lloperations = { -# 'opname': { -# (tuple-of-hltypes): subclass-of-LLOp, -# ... }, -# ...} -# This dict contains the known signatures of each space operation. -# Special opnames: -# 'CASE_XXX' v : fails (i.e. jump to errlabel) if v is not XXX -# -# rawoperations = { -# 'opname': subclass-of-LLOp, -# ...} -# Low-level-only operations on raw LLVars (as opposed to lloperations, -# which are on flow.model.Variables as found in SpaceOperations): -# 'goto' : fails unconditionally (i.e. jump to errlabel) -# 'move' x y : raw copy of the LLVar x to the LLVar y -# 'copy' x1 x2.. y1 y2...: raw copy x1 to y1, x2 to y2, etc. and incref -# 'incref' x y...: raw incref of the LLVars x, y, etc. -# 'decref' x y...: raw decref of the LLVars x, y, etc. -# 'xdecref' x y...: raw xdecref of the LLVars x, y, etc. -# 'comment' : comment (text is in errtarget) -# 'return' x y...: return the value stored in the LLVars -# -# def getconvertion(self, hltype1, hltype2): -# If it is possible to convert from 'hltype1' to 'hltype2', this -# function should return the conversion operation (as a subclass of -# LLOp). Otherwise, it should raise CannotConvert. -# -# def typemismatch(self, opname, hltypes): -# Called when no exact match is found in lloperations. This function -# can extend lloperations[opname] to provide a better match for hltypes. -# Partial matches (i.e. ones requiring conversions) are only considered -# after this function returns. -# ____________________________________________________________ - - -class LLTyper: - "Base class for type-oriented low-level generators." - - def __init__(self, typeset): - self.gethltype = typeset.gethltype - self.represent = typeset.represent - self.lloperations = typeset.lloperations - self.rawoperations= typeset.rawoperations - self.getconversion= typeset.getconversion - self.typemismatch = typeset.typemismatch - self.hltypes = {} - self.llreprs = {} - - def makevar(self, v, hltype=None): - "Record v in self.hltypes and self.llreprs." - if v in self.llreprs: - return - if hltype is None: - hltype = self.gethltype(v) - llrepr = [] - lltypes = self.represent(hltype) - for i, lltype in zip(range(len(lltypes)), lltypes): - if i: - suffix = '_%d' % i - else: - suffix = '' - llrepr.append(LLVar(lltype, v.name + suffix)) - self.hltypes[v] = hltype - self.llreprs[v] = llrepr - -# ____________________________________________________________ - -class LLFunction(LLTyper): - "A low-level version of a function from a control flow graph." - - def __init__(self, typeset, name, graph): - LLTyper.__init__(self, typeset) - remove_direct_loops(graph) - self.name = name - self.graph = graph - - def ll_header(self): - """ - Get the low-level representation of the header. - """ - llrepr = [] - for v in self.graph.getargs(): - self.makevar(v) - llrepr += self.llreprs[v] - v = self.graph.getreturnvar() - self.makevar(v) - llret = self.llreprs[v] - return llrepr, llret - - def ll_body(self, error_retvals): - """ - Get the body by flattening and low-level-izing the flow graph. - Enumerates low-level operations: LLOps with labels inbetween (strings). - """ - self.blockname = {} - llreturn = self.rawoperations['return'] - assert not llreturn.can_fail - self.release_root = ReleaseNode(None, llreturn(error_retvals), None) - allblocks = [] - - # collect all blocks - def visit(block): - if isinstance(block, Block): - allblocks.append(block) - self.blockname[block] = 'block%d' % len(self.blockname) - for v in block.inputargs: - self.makevar(v) - traverse(visit, self.graph) - - # generate an incref for each input argument - for v in self.graph.getargs(): - yield self.rawoperations['incref'](self.llreprs[v]) - - # generate the body of each block - for block in allblocks: - for op in self.generate_block(block): - yield op - yield '' # empty line - - # generate the code to handle errors - for op in self.release_root.error_code(self.rawoperations): - yield op - - def generate_block(self, block): - "Generate the operations for one basic block." - self.to_release = self.release_root - llrepr = [] - for v in block.inputargs: - llrepr += self.llreprs[v] - self.mark_release(llrepr) - # entry point - self.blockops = [self.blockname[block]] # label - # basic block operations - for op in block.operations: - self.operation('OP_' + op.opname.upper(), list(op.args), op.result) - # exits - if block.exits: - for exit in block.exits[:-1]: - # generate | CASE_XXX v elselabel - # | copy output vars to next block's input vars - # | jump to next block - # | elselabel: - elselabel = '%s_not%s' % (self.blockname[block], exit.exitcase) - self.operation('CASE_%s' % exit.exitcase, - [block.exitswitch], - errlabel = elselabel) - self.goto(exit) - self.blockops.append(elselabel) - # for the last exit, generate only the jump to next block - exit = block.exits[-1] - self.goto(exit) - - elif hasattr(block, 'exc_type'): - XXX("to do") - else: - llreturn = self.rawoperations['return'] - assert not llreturn.can_fail - llrepr = self.llreprs[block.inputargs[0]] - self.blockops.append(llreturn(llrepr)) - return self.blockops - - # __________ Type checking and conversion routines __________ - - def mark_release(self, llrepr): - if llrepr: - llop = self.rawoperations['decref'](llrepr) - # make a new node for the release tree - self.to_release = ReleaseNode(llrepr, llop, self.to_release) - - def find_best_match(self, opname, args_t, directions): - # look for an exact match first - llsigs = self.lloperations.setdefault(opname, {}) - sig = tuple(args_t) - if sig in llsigs: - return sig, llsigs[sig] - # no exact match, give the typeset a chance to provide an - # accurate version - self.typemismatch(opname, tuple(args_t)) - if sig in llsigs: - return sig, llsigs[sig] - # enumerate the existing operation signatures and their costs - choices = [] - for sig, llopcls in llsigs.items(): - if len(sig) != len(args_t): - continue # wrong number of arguments - try: - cost = llopcls.cost - for hltype1, hltype2, reverse in zip(args_t, sig, - directions): - if hltype1 != hltype2: - if reverse: - hltype1, hltype2 = hltype2, hltype1 - convop = self.getconversion(hltype1, hltype2) - cost += convop.cost - choices.append((cost, sig, llopcls)) - except CannotConvert: - continue # non-matching signature - if choices: - cost, sig, llopcls = min(choices) - # for performance, cache the approximate match - # back into self.lloperations - llsigs[sig] = llopcls - return sig, llopcls - raise TypingError([opname] + list(args_t)) - - def operation(self, opname, args, result=None, errlabel=None): - "Helper to build the LLOps for a single high-level operation." - # get the hltypes of the input arguments - for v in args: - self.makevar(v) - args_t = [self.hltypes[v] for v in args] - directions = [False] * len(args) - # append the hltype of the result - if result: - self.makevar(result) - args_t.append(self.hltypes[result]) - directions.append(True) - # look for the low-level operation class that implements these types - sig, llopcls = self.find_best_match(opname, args_t, directions) - # convert input args to temporary variables, if needed - llargs = [] - for v, v_t, s_t in zip(args, args_t, sig): - if v_t != s_t: - llargs += self.convert(v_t, self.llreprs[v], s_t) - else: - llargs += self.llreprs[v] - # case-by-case analysis of the result variable - if result: - if args_t[-1] == sig[-1]: - # the result has the correct type - self.writeoperation(llopcls, llargs, - self.llreprs[result], errlabel) - else: - # the result has to be converted - tmp = Variable() - self.makevar(tmp, hltype=sig[-1]) - self.writeoperation(llopcls, llargs, - self.llreprs[tmp], errlabel) - self.convert_variable(tmp, result) - else: - # no result variable - self.writeoperation(llopcls, llargs, [], errlabel) - - def writeoperation(self, llopcls, llargs, llresult, errlabel=None): - # generate an error label if the operation can fail - if llopcls.can_fail and errlabel is None: - errlabel = self.to_release.getlabel() - # create the LLOp instance - llresultcopy = list(llresult) - llop = llopcls(llargs + llresult, errlabel) - if llop.optimize(self, llresult): - return # skip the operation - # common case: emit the LLOp. - self.blockops.append(llop) - # all LLVars that are still in llresult (haven't been optimized away) - # are new and marked as "to be released". - assert len(llresult) == len(llresultcopy) - llrepr = [new for new, prev in zip(llresult, llresultcopy) - if new == prev] - self.mark_release(llrepr) - - def convert(self, inputtype, inputrepr, outputtype, outputrepr=None): - convop = self.getconversion(inputtype, outputtype) - if outputrepr is None: - tmp = Variable() - self.makevar(tmp, hltype=outputtype) - outputrepr = self.llreprs[tmp] - self.writeoperation(convop, inputrepr, outputrepr) - return outputrepr - - def convert_variable(self, v1, v2): - self.makevar(v1) - self.makevar(v2) - convop = self.getconversion(self.hltypes[v1], self.hltypes[v2]) - self.writeoperation(convop, self.llreprs[v1], self.llreprs[v2]) - - def goto(self, exit): - # generate the exit.args -> target.inputargs copying operations - to_release_copy = self.to_release - try: - # convert the exit.args to the type expected by the target.inputargs - exitargs = [] - for v, w in zip(exit.args, exit.target.inputargs): - self.makevar(v) - if self.hltypes[v] != self.hltypes[w]: - tmp = Variable() - self.makevar(tmp, hltype=self.hltypes[w]) - self.convert_variable(v, tmp) - v = tmp - exitargs.append(v) - # move the data from exit.args to target.inputargs - # See also remove_direct_loops() for why we don't worry about - # the order of the move operations - current_refcnt = {} - needed_refcnt = {} - llmove = self.rawoperations['move'] - for v, w in zip(exitargs, exit.target.inputargs): - for x, y in zip(self.llreprs[v], self.llreprs[w]): - self.blockops.append(llmove([x, y])) - needed_refcnt.setdefault(x, 0) - needed_refcnt[x] += 1 - # list all variables that go out of scope: by default - # they need no reference, but have one reference. - for node in self.to_release.getbranch(): - for x in node.llrepr: - current_refcnt[x] = 1 - needed_refcnt.setdefault(x, 0) - # now adjust all reference counters: first increfs, then decrefs - # (in case a variable to decref points to the same objects than - # another variable to incref). - llincref = self.rawoperations['incref'] - for x, needed in needed_refcnt.items(): - current_refcnt.setdefault(x, 0) - while current_refcnt[x] < needed: - self.blockops.append(llincref([x])) - current_refcnt[x] += 1 - lldecref = self.rawoperations['decref'] - for x, needed in needed_refcnt.items(): - while current_refcnt[x] > needed: - self.blockops.append(lldecref([x])) - current_refcnt[x] -= 1 - # finally jump to the target block - llgoto = self.rawoperations['goto'] - self.blockops.append(llgoto([], self.blockname[exit.target])) - finally: - self.to_release = to_release_copy - # after a call to goto() we are back to generating ops for - # other cases, so we restore the previous self.to_release. - -# ____________________________________________________________ - -# In a function, all the variables that have to released can be organized -# in a tree in which each node is a variable: whenever this variable has -# to be released, its parent in the tree has to be release too, and its -# parent's parent and so on up to the root. -class ReleaseNode: - accessible = False - label = None - counter = 0 - - def __init__(self, llrepr, release_operation, parent): - self.llrepr = llrepr - self.release_operation = release_operation - self.parent = parent - self.accessible_children = [] - - def mark_accessible(self): - if not self.accessible: - self.accessible = True - if self.parent: - self.parent.accessible_children.append(self) - self.parent.mark_accessible() - - def nextlabel(self): - while self.parent: - self = self.parent - self.counter += 1 - return 'err%d' % self.counter - - def getlabel(self): - if self.label is None: - self.mark_accessible() - self.label = self.nextlabel() - return self.label - - def getbranch(self): - while self.parent: - yield self - self = self.parent - - def error_code(self, rawoperations): - N = len(self.accessible_children) - for i in range(N): - if i > 0: - llgoto = rawoperations['goto'] - yield llgoto([], self.getlabel()) - node = self.accessible_children[~i] - for op in node.error_code(rawoperations): - yield op - if self.label: - yield self.label - elif not N: - return - yield self.release_operation From arigo at codespeak.net Sat Oct 9 12:49:32 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 9 Oct 2004 12:49:32 +0200 (MEST) Subject: [pypy-svn] r6877 - pypy/trunk/src/pypy/translator Message-ID: <20041009104932.1E8D45C3BF@thoth.codespeak.net> Author: arigo Date: Sat Oct 9 12:49:31 2004 New Revision: 6877 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: Made typeless tests work. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Oct 9 12:49:31 2004 @@ -31,13 +31,13 @@ #define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem(x,y))) goto err; #define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem(x,y,z))<0) goto err; \ - r = NULL; + r=Py_None; Py_INCREF(r); #define OP_GETATTR(x,y,r,err) if (!(r=PyObject_GetAttr(x,y))) goto err; #define OP_SETATTR(x,y,z,r,err) if ((PyObject_SetAttr(x,y,z))<0) goto err; \ - r = NULL; + r=Py_None; Py_INCREF(r); #define OP_DELATTR(x,y,r,err) if ((PyObject_SetAttr(x,y,NULL))<0)goto err; \ - r = NULL; + r=Py_None; Py_INCREF(r); #define OP_NEWSLICE(x,y,z,r,err) if (!(r=PySlice_New(x,y,z))) goto err; @@ -52,10 +52,64 @@ /*** misc ***/ -#define OP_EXCEPTION(x,r,err) r = NULL; /* XXX exceptions not implemented */ + /* XXX exceptions not implemented */ +#define OP_EXCEPTION(x,r,err) r=Py_None; Py_INCREF(r); #define MOVE(x, y) y = x; +/*** operations with a variable number of arguments ***/ + +#define OP_NEWLIST0(r,err) if (!(r=PyList_New(0))) goto err; +#define OP_NEWLIST(args,r,err) if (!(r=PyList_Pack args)) goto err; +#define OP_NEWTUPLE(args,r,err) if (!(r=PyTuple_Pack args)) goto err; +#define OP_SIMPLE_CALL(args,r,err) if (!(r=PyObject_CallFunctionObjArgs args)) \ + goto err; + +static PyObject* PyList_Pack(int n, ...) +{ + int i; + PyObject *o; + PyObject *result; + va_list vargs; + + va_start(vargs, n); + result = PyList_New(n); + if (result == NULL) + return NULL; + for (i = 0; i < n; i++) { + o = va_arg(vargs, PyObject *); + Py_INCREF(o); + PyList_SET_ITEM(result, i, o); + } + va_end(vargs); + return result; +} + +#if PY_VERSION_HEX < 0x02040000 /* 2.4 */ +static PyObject* PyTuple_Pack(int n, ...) +{ + int i; + PyObject *o; + PyObject *result; + PyObject **items; + va_list vargs; + + va_start(vargs, n); + result = PyTuple_New(n); + if (result == NULL) + return NULL; + items = ((PyTupleObject *)result)->ob_item; + for (i = 0; i < n; i++) { + o = va_arg(vargs, PyObject *); + Py_INCREF(o); + items[i] = o; + } + va_end(vargs); + return result; +} +#endif + + /************************************************************/ /*** The rest is produced by genc.py ***/ Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Oct 9 12:49:31 2004 @@ -29,7 +29,10 @@ self.translator = translator self.modname = (modname or uniquemodulename(translator.functions[0].__name__)) - self.cnames = {} + self.cnames = {(type(None), None): 'Py_None', + ( bool, False): 'Py_False', + ( bool, True): 'Py_True', + } self.seennames = {} self.initcode = [] self.globaldecl = [] @@ -69,6 +72,25 @@ self.initcode.append('%s = PyInt_FromLong(%d);' % (name, value)) return name + def nameof_str(self, value): + chrs = [c for c in value if ('a' <= c <='z' or + 'A' <= c <='Z' or + '0' <= c <='9' or + '_' == c )] + name = self.uniquename('gstr_' + ''.join(chrs)) + self.globaldecl.append('static PyObject* %s;' % name) + if [c for c in value if not (' '<=c<='~')]: + # non-printable string + s = 'chr_%s' % name + self.globaldecl.append('static char %s[] = { %s };' % ( + s, ', '.join(['%d' % ord(c) for c in value]))) + else: + # printable string + s = '"%s"' % value + self.initcode.append('%s = PyString_FromStringAndSize(%s, %d);' % ( + name, s, len(value))) + return name + def nameof_function(self, func): name = self.uniquename('gfunc_' + func.__name__) self.globaldecl.append('static PyObject* %s;' % name) @@ -77,6 +99,17 @@ self.pendingfunctions.append(func) return name + def nameof_builtin_function_or_method(self, func): + import __builtin__ + assert func is getattr(__builtin__, func.__name__, None), ( + '%r is not from __builtin__' % (func,)) + name = self.uniquename('gbltin_' + func.__name__) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('%s = PyMapping_GetItemString(' + 'PyEval_GetBuiltins(), "%s");' % ( + name, func.__name__)) + return name + def gen_source(self): f = self.f info = { @@ -117,7 +150,7 @@ print >> f, '{' # collect and print all the local variables - graph = self.translator.flowgraphs[func] + graph = self.translator.getflowgraph(func) localslst = [] def visit(node): if isinstance(node, Block): @@ -128,9 +161,13 @@ print >> f # argument unpacking - lst = ['"' + 'O'*len(graph.getargs()) + '"'] + lst = ['args', + '"%s"' % func.__name__, + '%d' % len(graph.getargs()), + '%d' % len(graph.getargs()), + ] lst += ['&' + a.name for a in graph.getargs()] - print >> f, '\tif (!PyArg_ParseTuple(args, %s))' % ', '.join(lst) + print >> f, '\tif (!PyArg_UnpackTuple(%s))' % ', '.join(lst) print >> f, '\t\treturn NULL;' # print the body @@ -148,7 +185,7 @@ print >> f def cfunction_body(self, func): - graph = self.translator.flowgraphs[func] + graph = self.translator.getflowgraph(func) blocknum = {} allblocks = [] @@ -174,7 +211,7 @@ yield line for v in to_release: if v in has_ref: - yield 'Py_XDECREF(%s);' % v.name + yield 'Py_DECREF(%s);' % v.name yield 'goto block%d;' % blocknum[link.target] # collect all blocks @@ -197,7 +234,12 @@ lst = [expr(v) for v in op.args] lst.append(op.result.name) lst.append('err%d_%d' % (blocknum[block], len(to_release))) - yield 'OP_%s(%s)' % (op.opname.upper(), ', '.join(lst)) + macro = 'OP_%s' % op.opname.upper() + meth = getattr(self, macro, None) + if meth: + yield meth(lst[:-2], lst[-2], lst[-1]) + else: + yield '%s(%s)' % (macro, ', '.join(lst)) to_release.append(op.result) if len(block.exits) == 0: @@ -221,8 +263,8 @@ while to_release: n = len(to_release) v = to_release.pop() - yield 'err%d_%d: Py_XDECREF(%s);' % (blocknum[block], n, v.name) - yield 'return NULL;' + yield 'err%d_%d: Py_DECREF(%s);' % (blocknum[block], n, v.name) + yield 'err%d_0: return NULL;' % blocknum[block] # ____________________________________________________________ @@ -241,6 +283,24 @@ \tPyModule_AddObject(m, "%(entrypointname)s", %(entrypoint)s); }''' + # the C preprocessor cannot handle operations taking a variable number + # of arguments, so here are Python methods that do it + + def OP_NEWLIST(self, args, r, err): + if len(args) == 0: + return 'OP_NEWLIST0(%s, %s)' % (r, err) + else: + args.insert(0, '%d' % len(args)) + return 'OP_NEWLIST((%s), %s, %s)' % (', '.join(args), r, err) + + def OP_NEWTUPLE(self, args, r, err): + args.insert(0, '%d' % len(args)) + return 'OP_NEWTUPLE((%s), %s, %s)' % (', '.join(args), r, err) + + def OP_SIMPLE_CALL(self, args, r, err): + args.append('NULL') + return 'OP_SIMPLE_CALL((%s), %s, %s)' % (', '.join(args), r, err) + # ____________________________________________________________ def cdecl(type, name): From arigo at codespeak.net Sun Oct 10 11:15:45 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 10 Oct 2004 11:15:45 +0200 (MEST) Subject: [pypy-svn] r6880 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041010091545.5CD235A0BB@thoth.codespeak.net> Author: arigo Date: Sun Oct 10 11:15:44 2004 New Revision: 6880 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: Enabled all tests again (without type annotations), and made them pass: * added most numeric operations to genc.h * support for classes, implemented as regular Python heap types, with instances storing attributes as usual in their __dict__ * tuple constants The short genc.{py,h} together with the flow objspace now implement most of the equivalent of the old Python2C: translating Python bytecode to C code calling the abstract.h functions, without any type-based optimizations. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sun Oct 10 11:15:44 2004 @@ -22,12 +22,50 @@ } \ Py_INCREF(r); +#define OP_NEG(x,r,err) if (!(r=PyNumber_Negative(x))) goto err; +#define OP_POS(x,r,err) if (!(r=PyNumber_Positive(x))) goto err; +#define OP_INVERT(x,r,err) if (!(r=PyNumber_Invert(x))) goto err; + #define OP_ADD(x,y,r,err) if (!(r=PyNumber_Add(x,y))) goto err; #define OP_SUB(x,y,r,err) if (!(r=PyNumber_Subtract(x,y))) goto err; #define OP_MUL(x,y,r,err) if (!(r=PyNumber_Multiply(x,y))) goto err; +#define OP_TRUEDIV(x,y,r,err) if (!(r=PyNumber_TrueDivide(x,y))) goto err; +#define OP_FLOORDIV(x,y,r,err) if (!(r=PyNumber_FloorDivide(x,y)))goto err; #define OP_DIV(x,y,r,err) if (!(r=PyNumber_Divide(x,y))) goto err; #define OP_MOD(x,y,r,err) if (!(r=PyNumber_Remainder(x,y))) goto err; -#define OP_INPLACE_ADD(x,y,r,err) if(!(r=PyNumber_InPlaceAdd(x,y))) goto err; +#define OP_POW(x,y,r,err) if (!(r=PyNumber_Power(x,y,Py_None)))goto err; +#define OP_LSHIFT(x,y,r,err) if (!(r=PyNumber_Lshift(x,y))) goto err; +#define OP_RSHIFT(x,y,r,err) if (!(r=PyNumber_Rshift(x,y))) goto err; +#define OP_AND_(x,y,r,err) if (!(r=PyNumber_And(x,y))) goto err; +#define OP_OR_(x,y,r,err) if (!(r=PyNumber_Or(x,y))) goto err; +#define OP_XOR(x,y,r,err) if (!(r=PyNumber_Xor(x,y))) goto err; + +#define OP_INPLACE_ADD(x,y,r,err) if (!(r=PyNumber_InPlaceAdd(x,y))) \ + goto err; +#define OP_INPLACE_SUB(x,y,r,err) if (!(r=PyNumber_InPlaceSubtract(x,y))) \ + goto err; +#define OP_INPLACE_MUL(x,y,r,err) if (!(r=PyNumber_InPlaceMultiply(x,y))) \ + goto err; +#define OP_INPLACE_TRUEDIV(x,y,r,err) if (!(r=PyNumber_InPlaceTrueDivide(x,y)))\ + goto err; +#define OP_INPLACE_FLOORDIV(x,y,r,err)if(!(r=PyNumber_InPlaceFloorDivide(x,y)))\ + goto err; +#define OP_INPLACE_DIV(x,y,r,err) if (!(r=PyNumber_InPlaceDivide(x,y))) \ + goto err; +#define OP_INPLACE_MOD(x,y,r,err) if (!(r=PyNumber_InPlaceRemainder(x,y))) \ + goto err; +#define OP_INPLACE_POW(x,y,r,err) if (!(r=PyNumber_InPlacePower(x,y,Py_None))) \ + goto err; +#define OP_INPLACE_LSHIFT(x,y,r,err) if (!(r=PyNumber_InPlaceLshift(x,y))) \ + goto err; +#define OP_INPLACE_RSHIFT(x,y,r,err) if (!(r=PyNumber_InPlaceRshift(x,y))) \ + goto err; +#define OP_INPLACE_AND(x,y,r,err) if (!(r=PyNumber_InPlaceAnd(x,y))) \ + goto err; +#define OP_INPLACE_OR(x,y,r,err) if (!(r=PyNumber_InPlaceOr(x,y))) \ + goto err; +#define OP_INPLACE_XOR(x,y,r,err) if (!(r=PyNumber_InPlaceXor(x,y))) \ + goto err; #define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem(x,y))) goto err; #define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem(x,y,z))<0) goto err; \ @@ -57,6 +95,69 @@ #define MOVE(x, y) y = x; +#define INITCHK(expr) if (!(expr)) return; + + +/*** classes ***/ + +#define SETUP_CLASS(t, name, base) \ + t = PyObject_CallFunction((PyObject*) &PyType_Type, \ + "s(O){}", name, base) + +#define SETUP_CLASS_ATTR(t, attr, value) \ + (PyObject_SetAttrString(t, attr, value) >= 0) + +/* we need a subclass of 'builtin_function_or_method' which can be used + as methods: builtin function objects that can be bound on instances */ +static PyObject * +gencfunc_descr_get(PyObject *func, PyObject *obj, PyObject *type) +{ + if (obj == Py_None) + obj = NULL; + return PyMethod_New(func, obj, type); +} +static PyTypeObject PyGenCFunction_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "pypy_generated_function", + sizeof(PyCFunctionObject), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + /*&PyCFunction_Type set below*/ 0, /* tp_base */ + 0, /* tp_dict */ + gencfunc_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +#define SETUP_MODULE \ + PyGenCFunction_Type.tp_base = &PyCFunction_Type; \ + PyType_Ready(&PyGenCFunction_Type); + /*** operations with a variable number of arguments ***/ Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sun Oct 10 11:15:44 2004 @@ -69,7 +69,8 @@ else: name = 'gint_minus%d' % abs(value) self.globaldecl.append('static PyObject* %s;' % name) - self.initcode.append('%s = PyInt_FromLong(%d);' % (name, value)) + self.initcode.append('INITCHK(%s = ' + 'PyInt_FromLong(%d))' % (name, value)) return name def nameof_str(self, value): @@ -87,15 +88,16 @@ else: # printable string s = '"%s"' % value - self.initcode.append('%s = PyString_FromStringAndSize(%s, %d);' % ( - name, s, len(value))) + self.initcode.append('INITCHK(%s = PyString_FromStringAndSize(' + '%s, %d))' % (name, s, len(value))) return name def nameof_function(self, func): name = self.uniquename('gfunc_' + func.__name__) self.globaldecl.append('static PyObject* %s;' % name) - self.initcode.append('%s = PyCFunction_New(&ml_%s, NULL);' % (name, - name)) + self.initcode.append('INITCHK(%s = PyCFunction_New(' + '&ml_%s, NULL))' % (name, name)) + self.initcode.append('\t%s->ob_type = &PyGenCFunction_Type;' % name) self.pendingfunctions.append(func) return name @@ -105,11 +107,50 @@ '%r is not from __builtin__' % (func,)) name = self.uniquename('gbltin_' + func.__name__) self.globaldecl.append('static PyObject* %s;' % name) - self.initcode.append('%s = PyMapping_GetItemString(' - 'PyEval_GetBuiltins(), "%s");' % ( + self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' + 'PyEval_GetBuiltins(), "%s"))' % ( name, func.__name__)) return name + def nameof_classobj(self, cls): + name = self.uniquename('gcls_' + cls.__name__) + bases = [base for base in cls.__bases__ if base is not object] + assert len(bases) <= 1, "%r needs multiple inheritance" % (cls,) + if bases: + base = self.nameof(bases[0]) + else: + base = '(PyObject*) &PyBaseObject_Type' + content = cls.__dict__.items() + content.sort() + lines = [] + for key, value in content: + if key.startswith('__'): + continue + lines.append('INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( + name, key, self.nameof(value))) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(SETUP_CLASS(%s, "%s", %s))' % ( + name, cls.__name__, base)) + self.initcode.extend(lines) + return name + + def nameof_type(self, cls): + assert hasattr(cls, '__weakref__'), ( + "%r is not a user-defined class" % (cls,)) + return self.nameof_classobj(cls) + + def nameof_tuple(self, tup): + name = self.uniquename('g%dtuple' % len(tup)) + lines = [] + for i in range(len(tup)): + item = self.nameof(tup[i]) + lines.append('\tPy_INCREF(%s);' % item) + lines.append('\tPyTuple_SET_ITEM(%s, %d, %s);' % (name, i, item)) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(%s = PyTuple_New(%d))' % (name, len(tup))) + self.initcode.extend(lines) + return name + def gen_source(self): f = self.f info = { @@ -245,7 +286,7 @@ if len(block.exits) == 0: yield 'return %s;' % expr(block.inputargs[0]) continue - if block.exitswitch is not None: + if len(block.exits) > 1: for link in block.exits[:-1]: yield 'if (EQ_%s(%s)) {' % (link.exitcase, block.exitswitch.name) @@ -277,6 +318,7 @@ void init%(modname)s(void) { \tPyObject* m = Py_InitModule("%(modname)s", NULL); +\tSETUP_MODULE ''' C_INIT_FOOTER = ''' Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Sun Oct 10 11:15:44 2004 @@ -84,21 +84,20 @@ self.assertEquals(sand(0, 6), "no") self.assertEquals(sand(0, 0), "no") -if 0: - class TypedTestCase(testit.IntTestCase): +class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): t = Translator(func) t.simplify() - # builds starting-types from func_defs - argstypelist = [] - if func.func_defaults: - for spec in func.func_defaults: - if isinstance(spec, tuple): - spec = spec[0] # use the first type only for the tests - argstypelist.append(spec) - a = t.annotate(argstypelist) - a.simplify() +## # builds starting-types from func_defs +## argstypelist = [] +## if func.func_defaults: +## for spec in func.func_defaults: +## if isinstance(spec, tuple): +## spec = spec[0] # use the first type only for the tests +## argstypelist.append(spec) +## a = t.annotate(argstypelist) +## a.simplify() return t.ccompile() def test_set_attr(self): @@ -132,10 +131,10 @@ def test_call_five(self): call_five = self.getcompiled(snippet.call_five) result = call_five() - #self.assertEquals(result, [5]) + self.assertEquals(result, [5]) # -- currently result isn't a real list, but a pseudo-array # that can't be inspected from Python. - self.assertEquals(result.__class__.__name__[:8], "list of ") + #self.assertEquals(result.__class__.__name__[:8], "list of ") def test_call_unpack_56(self): call_unpack_56 = self.getcompiled(snippet.call_unpack_56) From arigo at codespeak.net Sun Oct 10 19:41:48 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 10 Oct 2004 19:41:48 +0200 (MEST) Subject: [pypy-svn] r6893 - in pypy/trunk/src/pypy: objspace objspace/flow objspace/std objspace/std/test translator translator/tool translator/tool/pygame Message-ID: <20041010174148.C055A5A0BB@thoth.codespeak.net> Author: arigo Date: Sun Oct 10 19:41:45 2004 New Revision: 6893 Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py pypy/trunk/src/pypy/objspace/flow/model.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/std/fake.py pypy/trunk/src/pypy/objspace/std/test/test_intobject.py pypy/trunk/src/pypy/objspace/std/test/test_unicodestring.py pypy/trunk/src/pypy/objspace/trace.py pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/simplify.py pypy/trunk/src/pypy/translator/tool/buildcl.py pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py pypy/trunk/src/pypy/translator/transform.py pypy/trunk/src/pypy/translator/translator.py Log: Lots of small changes to lots of files: trying to get Python 2.2 to work again. Some tests still fail. Not sure if it's worth the effort... Also contains a new checkgraph() that checks various invariants of flow graphs, e.g. that variables are used consistently and never in more than one block. Graphs now have a method show() to view them using the pygame code, which is handy to figure out what's really wrong with a graph when an assertion in checkgraph() fails. Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/flowcontext.py (original) +++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py Sun Oct 10 19:41:45 2004 @@ -139,6 +139,7 @@ # directly at the new block which is its generalization block.dead = True block.operations = () + block.exitswitch = None outputargs = block.framestate.getoutputargs(newstate) block.recloseblock(Link(outputargs, newblock)) newblock.patchframe(frame, self) Modified: pypy/trunk/src/pypy/objspace/flow/model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/model.py Sun Oct 10 19:41:45 2004 @@ -32,6 +32,10 @@ block.exits = () return block + def show(self): + from pypy.translator.tool.pygame.flowviewer import SingleGraphLayout + SingleGraphLayout(self).display() + class Link: def __init__(self, args, target, exitcase=None): assert len(args) == len(target.inputargs), "output args mismatch" @@ -225,3 +229,46 @@ lst.append(link) traverse(visit, funcgraph) return result + +def checkgraph(graph): + "Check the consistency of a flow graph." + if __debug__: + exitblocks = [graph.returnblock] + graph.exceptblocks.values() + for block in exitblocks: + assert len(block.inputargs) == 1 + assert not block.operations + assert not block.exits + + vars_previous_blocks = {} + + def visit(node): + if isinstance(node, Block): + assert bool(node.isstartblock) == (node is graph.startblock) + if not node.exits: + assert node in exitblocks + vars = {} + for v in node.inputargs + [op.result for op in node.operations]: + assert isinstance(v, Variable) + assert v not in vars, "duplicate variable %r" % (v,) + assert v not in vars_previous_blocks, ( + "variable %r used in more than one block" % (v,)) + vars[v] = True + for op in node.operations: + for v in op.args: + assert isinstance(v, (Constant, Variable)) + if isinstance(v, Variable): + assert v in vars + if node.exitswitch is not None: + assert isinstance(node.exitswitch, (Constant, Variable)) + if isinstance(node.exitswitch, Variable): + assert node.exitswitch in vars + for link in node.exits: + assert len(link.args) == len(link.target.inputargs) + assert link.prevblock is node + for v in link.args: + assert isinstance(v, (Constant, Variable)) + if isinstance(v, Variable): + assert v in vars + vars_previous_blocks.update(vars) + + traverse(visit, graph) Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Sun Oct 10 19:41:45 2004 @@ -122,6 +122,7 @@ for c in "<>&!": name = name.replace(c, '_') ec.graph.name = name + checkgraph(ec.graph) return ec.graph def unpacktuple(self, w_tuple, expected_length=None): Modified: pypy/trunk/src/pypy/objspace/std/fake.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/fake.py (original) +++ pypy/trunk/src/pypy/objspace/std/fake.py Sun Oct 10 19:41:45 2004 @@ -60,10 +60,13 @@ def __init__(w_self, space, val): W_Object.__init__(w_self, space) w_self.val = val + # cannot write to W_Fake.__name__ in Python 2.2! + W_Fake = type(W_Object)('W_Fake%s'%(cpy_type.__name__.capitalize()), + (W_Object,), + dict(W_Fake.__dict__.items())) def fake_unwrap(space, w_obj): return w_obj.val StdObjSpace.unwrap.register(fake_unwrap, W_Fake) - W_Fake.__name__ = 'W_Fake%s'%(cpy_type.__name__.capitalize()) W_Fake.typedef.fakedcpytype = cpy_type _fake_type_cache[cpy_type] = W_Fake return W_Fake Modified: pypy/trunk/src/pypy/objspace/std/test/test_intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Sun Oct 10 19:41:45 2004 @@ -294,7 +294,7 @@ def test_int_string(self): self.assertEquals(42, int("42")) - self.assertEquals(10000000000, int("10000000000")) + self.assertEquals(10000000000, long("10000000000")) def test_int_float(self): self.assertEquals(4, int(4.2)) Modified: pypy/trunk/src/pypy/objspace/std/test/test_unicodestring.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_unicodestring.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_unicodestring.py Sun Oct 10 19:41:45 2004 @@ -1,7 +1,7 @@ # test the integration of unicode and strings (even though we don't # really implement unicode yet). -import autopath +import autopath, sys from pypy.tool import testit @@ -31,8 +31,13 @@ check(', '.join(['a', u'b']), u'a, b') check(u', '.join(['a', 'b']), u'a, b') + if sys.version_info >= (2,3): + def test_contains_ex(self): + self.failUnless(u'' in 'abc') + self.failUnless(u'bc' in 'abc') + self.failUnless('bc' in 'abc') + def test_contains(self): - self.failUnless(u'' in 'abc') self.failUnless(u'a' in 'abc') self.failUnless('a' in u'abc') Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Sun Oct 10 19:41:45 2004 @@ -4,6 +4,7 @@ """ +from __future__ import generators from pypy.tool import pydis from pypy.interpreter.baseobjspace import ObjSpace Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sun Oct 10 19:41:45 2004 @@ -67,8 +67,8 @@ #define OP_INPLACE_XOR(x,y,r,err) if (!(r=PyNumber_InPlaceXor(x,y))) \ goto err; -#define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem(x,y))) goto err; -#define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem(x,y,z))<0) goto err; \ +#define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem1(x,y))) goto err; +#define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem1(x,y,z))<0) goto err; \ r=Py_None; Py_INCREF(r); #define OP_GETATTR(x,y,r,err) if (!(r=PyObject_GetAttr(x,y))) goto err; @@ -211,6 +211,73 @@ } #endif +#if PY_VERSION_HEX >= 0x02030000 /* 2.3 */ +# define PyObject_GetItem1 PyObject_GetItem +# define PyObject_SetItem1 PyObject_SetItem +#else +/* for Python 2.2 only */ +static PyObject* PyObject_GetItem1(PyObject* obj, PyObject* index) +{ + int start, stop, step; + if (!PySlice_Check(index)) + return PyObject_GetItem(obj, index); + if (((PySliceObject*) index)->start == Py_None) + start = -INT_MAX-1; + else + { + start = PyInt_AsLong(((PySliceObject*) index)->start); + if (start == -1 && PyErr_Occurred()) return NULL; + } + if (((PySliceObject*) index)->stop == Py_None) + stop = INT_MAX; + else + { + stop = PyInt_AsLong(((PySliceObject*) index)->stop); + if (stop == -1 && PyErr_Occurred()) return NULL; + } + if (((PySliceObject*) index)->step != Py_None) + { + step = PyInt_AsLong(((PySliceObject*) index)->step); + if (step == -1 && PyErr_Occurred()) return NULL; + if (step != 1) { + PyErr_SetString(PyExc_ValueError, "obj[slice]: no step allowed"); + return NULL; + } + } + return PySequence_GetSlice(obj, start, stop); +} +static PyObject* PyObject_SetItem1(PyObject* obj, PyObject* index, PyObject* v) +{ + int start, stop, step; + if (!PySlice_Check(index)) + return PyObject_SetItem(obj, index, v); + if (((PySliceObject*) index)->start == Py_None) + start = -INT_MAX-1; + else + { + start = PyInt_AsLong(((PySliceObject*) index)->start); + if (start == -1 && PyErr_Occurred()) return NULL; + } + if (((PySliceObject*) index)->stop == Py_None) + stop = INT_MAX; + else + { + stop = PyInt_AsLong(((PySliceObject*) index)->stop); + if (stop == -1 && PyErr_Occurred()) return NULL; + } + if (((PySliceObject*) index)->step != Py_None) + { + step = PyInt_AsLong(((PySliceObject*) index)->step); + if (step == -1 && PyErr_Occurred()) return NULL; + if (step != 1) { + PyErr_SetString(PyExc_ValueError, "obj[slice]: no step allowed"); + return NULL; + } + } + return PySequence_SetSlice(obj, start, stop, v); +} +#endif + /************************************************************/ /*** The rest is produced by genc.py ***/ Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sun Oct 10 19:41:45 2004 @@ -6,7 +6,8 @@ import autopath, os from pypy.objspace.flow.model import Variable, Constant, SpaceOperation from pypy.objspace.flow.model import FunctionGraph, Block, Link -from pypy.objspace.flow.model import traverse, uniqueitems +from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph +from pypy.translator.simplify import remove_direct_loops # ____________________________________________________________ @@ -134,6 +135,8 @@ self.initcode.extend(lines) return name + nameof_class = nameof_classobj # for Python 2.2 + def nameof_type(self, cls): assert hasattr(cls, '__weakref__'), ( "%r is not a user-defined class" % (cls,)) @@ -227,6 +230,9 @@ def cfunction_body(self, func): graph = self.translator.getflowgraph(func) + remove_direct_loops(graph) + checkgraph(graph) + blocknum = {} allblocks = [] @@ -315,9 +321,10 @@ C_INIT_HEADER = C_SEP + ''' +static PyMethodDef no_methods[] = { NULL, NULL }; void init%(modname)s(void) { -\tPyObject* m = Py_InitModule("%(modname)s", NULL); +\tPyObject* m = Py_InitModule("%(modname)s", no_methods); \tSETUP_MODULE ''' Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Sun Oct 10 19:41:45 2004 @@ -81,9 +81,11 @@ def simplify_graph(graph): """Apply all the existing optimisations to the graph.""" + checkgraph(graph) eliminate_empty_blocks(graph) remove_implicit_exceptions(graph) join_blocks(graph) + checkgraph(graph) return graph 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 Sun Oct 10 19:41:45 2004 @@ -36,12 +36,6 @@ content = "'" + content # quote Lisp list return content -# for test -# ultimately, GenCL's str and conv will move to here -def f(): pass -fun = FlowObjSpace().build_flow(f) -gen = GenCL(fun) - def _make_cl_func(func, cl, path, argtypes=[]): fun = FlowObjSpace().build_flow(func) gen = GenCL(fun, argtypes) @@ -61,6 +55,12 @@ return _ if __name__ == '__main__': + # for test + # ultimately, GenCL's str and conv will move to here + def f(): pass + fun = FlowObjSpace().build_flow(f) + gen = GenCL(fun) + what = [True, "universe", 42, None, ("of", "them", ["eternal", 95])] it = writelisp(gen, what) print what Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Sun Oct 10 19:41:45 2004 @@ -46,6 +46,10 @@ break self.links = {} + def display(self): + from graphdisplay import GraphDisplay + GraphDisplay(self).run() + class Node: def __init__(self, name, x, y, w, h, label, style, shape, color, fillcolor): self.name = name Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Sun Oct 10 19:41:45 2004 @@ -6,6 +6,15 @@ from pypy.annotation import model, factory +class SingleGraphLayout(GraphLayout): + """ A GraphLayout showing a single precomputed FlowGraph.""" + + def __init__(self, graph): + from pypy.translator.tool.make_dot import make_dot + fn = make_dot(graph.name, graph, target='plain') + GraphLayout.__init__(self, fn) + + class FlowGraphLayout(GraphLayout): """ A GraphLayout showing a Flow Graph (or a few flow graphs). """ Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Sun Oct 10 19:41:45 2004 @@ -299,9 +299,13 @@ def transform_graph(ann): """Apply set of transformations available.""" + if ann.translator: + ann.translator.checkgraphs() transform_allocate(ann) transform_slice(ann) transform_listextend(ann) # do this last, after the previous transformations had a # chance to remove dependency on certain variables transform_dead_op_vars(ann) + if ann.translator: + ann.translator.checkgraphs() Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Sun Oct 10 19:41:45 2004 @@ -105,9 +105,8 @@ def view(self, *functions): """Shows the control flow graph with annotations if computed. Requires 'dot' and pygame.""" - from pypy.translator.tool.pygame.graphdisplay import GraphDisplay from pypy.translator.tool.pygame.flowviewer import FlowGraphLayout - GraphDisplay(FlowGraphLayout(self)).run() + FlowGraphLayout(self).display() def simplify(self, func=None): """Simplifies the control flow graph (default: for all functions).""" @@ -130,6 +129,10 @@ self.annotator.build_types(graph, input_args_types, func) return self.annotator + def checkgraphs(self): + for graph in self.flowgraphs.itervalues(): + checkgraph(graph) + def source(self, func=None): """Returns original Python source. From arigo at codespeak.net Thu Oct 14 16:14:15 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 14 Oct 2004 16:14:15 +0200 (MEST) Subject: [pypy-svn] r6928 - in pypy/trunk/src/pypy: objspace/flow translator translator/test Message-ID: <20041014141415.69C205A165@thoth.codespeak.net> Author: arigo Date: Thu Oct 14 16:14:14 2004 New Revision: 6928 Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py pypy/trunk/src/pypy/objspace/flow/model.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/gencl.py pypy/trunk/src/pypy/translator/simplify.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: Support for exceptions in genc.py. * the objspace.flow.model is simplified for exceptions, see documentation of 'last_exception' in that module. * fixed gencl.py to support the new model, too. * new test for genc.py with 'for' loops and iterators. 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 Thu Oct 14 16:14:14 2004 @@ -171,6 +171,10 @@ raise AssertionError, "concrete mode: cannot guessbool(%s)" % ( w_condition,) + def guessexception(self, *classes): + return self.guessbool(Constant(last_exception), + cases = [None] + list(classes)) + def build_flow(self): while self.pendingblocks: block = self.pendingblocks.pop(0) 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 Oct 14 16:14:14 2004 @@ -50,7 +50,8 @@ def __init__(self, inputargs): self.inputargs = list(inputargs) # mixed list of variable/const self.operations = [] # list of SpaceOperation(s) - self.exitswitch = None # variable + self.exitswitch = None # a variable or + # Constant(last_exception), see below self.exits = [] # list of Link(s) def getvariables(self): @@ -148,6 +149,15 @@ def __repr__(self): return "%r = %s(%s)" % (self.result, self.opname, ", ".join(map(repr, self.args))) +class LastExceptionValue: + def __repr__(self): + return 'last_exception' +last_exception = LastExceptionValue() +# if Block().exitswitch == Constant(last_exception), it means that we are +# interested in catching the exception that the *last operation* of the +# block could raise. The exitcases of the links are None for no exception +# or XxxError classes to catch the matching exceptions. + def uniqueitems(lst): "Returns a list with duplicate elements removed." result = [] @@ -241,30 +251,40 @@ vars_previous_blocks = {} - def visit(node): - if isinstance(node, Block): - assert bool(node.isstartblock) == (node is graph.startblock) - if not node.exits: - assert node in exitblocks + def visit(block): + if isinstance(block, Block): + assert bool(block.isstartblock) == (block is graph.startblock) + if not block.exits: + assert block in exitblocks vars = {} - for v in node.inputargs + [op.result for op in node.operations]: + resultvars = [op.result for op in block.operations] + for v in block.inputargs + resultvars: assert isinstance(v, Variable) assert v not in vars, "duplicate variable %r" % (v,) assert v not in vars_previous_blocks, ( "variable %r used in more than one block" % (v,)) vars[v] = True - for op in node.operations: + for op in block.operations: for v in op.args: assert isinstance(v, (Constant, Variable)) if isinstance(v, Variable): assert v in vars - if node.exitswitch is not None: - assert isinstance(node.exitswitch, (Constant, Variable)) - if isinstance(node.exitswitch, Variable): - assert node.exitswitch in vars - for link in node.exits: + if block.exitswitch is None: + assert len(block.exits) <= 1 + if block.exits: + assert block.exits[0].exitcase is None + elif block.exitswitch == Constant(last_exception): + assert len(block.operations) >= 1 + assert len(block.exits) >= 1 + assert block.exits[0].exitcase is None + for link in block.exits[1:]: + assert issubclass(link.exitcase, Exception) + else: + assert isinstance(block.exitswitch, Variable) + assert block.exitswitch in vars + for link in block.exits: assert len(link.args) == len(link.target.inputargs) - assert link.prevblock is node + assert link.prevblock is block for v in link.args: assert isinstance(v, (Constant, Variable)) if isinstance(v, Variable): Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Thu Oct 14 16:14:14 2004 @@ -158,9 +158,8 @@ def next(self, w_iter): w_item = self.do_operation("next", w_iter) - w_curexc = self.do_operation('exception', w_item) context = self.getexecutioncontext() - outcome = context.guessbool(w_curexc, [None, StopIteration]) + outcome = context.guessexception(StopIteration) if outcome is StopIteration: raise OperationError(self.w_StopIteration, self.w_None) else: @@ -185,10 +184,6 @@ implicit_exceptions = { 'getitem': [IndexError], } -class ImplicitExcValue: - def __repr__(self): - return 'implicitexc' -implicitexc = ImplicitExcValue() def extract_cell_content(c): """Get the value contained in a CPython 'cell', as read through @@ -245,17 +240,18 @@ #print >> sys.stderr, 'Variable operation', name, args_w w_result = self.do_operation(name, *args_w) if exceptions: - # the 'exception(w_result)' operation is a bit strange, it is - # meant to check if w_result is a correct result or if its - # computation actually resulted in an exception. For now this - # is an approximation of checking if w_result is NULL, and - # using PyErr_Occurred() to get the current exception if so. - w_curexc = self.do_operation('exception', w_result) + # catch possible exceptions implicitely. If the OperationError + # below is not caught in the same function, it will produce an + # exception-raising return block in the flow graph. The special + # value 'wrap(last_exception)' is used as a marker for this kind + # of implicit exceptions, and simplify.py will remove it as per + # the RPython definition: implicit exceptions not explicitely + # caught in the same function are assumed not to occur. context = self.getexecutioncontext() - outcome = context.guessbool(w_curexc, [None] + exceptions) + outcome = context.guessexception(*exceptions) if outcome is not None: raise OperationError(self.wrap(outcome), - self.wrap(implicitexc)) + self.wrap(last_exception)) return w_result setattr(FlowObjSpace, name, generic_operator) Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Thu Oct 14 16:14:14 2004 @@ -79,6 +79,12 @@ #define OP_NEWSLICE(x,y,z,r,err) if (!(r=PySlice_New(x,y,z))) goto err; +#define OP_ITER(x,r,err) if (!(r=PyObject_GetIter(x))) goto err; +#define OP_NEXT(x,r,err) if (!(r=PyIter_Next(x))) { \ + if (!PyErr_Occurred()) PyErr_SetNone(PyExc_StopIteration); \ + goto err; \ + } + /*** tests ***/ @@ -90,9 +96,6 @@ /*** misc ***/ - /* XXX exceptions not implemented */ -#define OP_EXCEPTION(x,r,err) r=Py_None; Py_INCREF(r); - #define MOVE(x, y) y = x; #define INITCHK(expr) if (!(expr)) return; Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Thu Oct 14 16:14:14 2004 @@ -5,7 +5,7 @@ from __future__ import generators import autopath, os from pypy.objspace.flow.model import Variable, Constant, SpaceOperation -from pypy.objspace.flow.model import FunctionGraph, Block, Link +from pypy.objspace.flow.model import FunctionGraph, Block, Link, last_exception from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph from pypy.translator.simplify import remove_direct_loops @@ -217,10 +217,15 @@ # print the body for line in body: if line.endswith(':'): - line = ' ' + line + if line.startswith('err'): + fmt = '\t%s' + else: + fmt = ' %s\n' + elif line: + fmt = '\t%s\n' else: - line = '\t' + line - print >> f, line + fmt = '%s\n' + f.write(fmt % line) print >> f, '}' # print the PyMethodDef @@ -289,10 +294,48 @@ yield '%s(%s)' % (macro, ', '.join(lst)) to_release.append(op.result) + err_reachable = False if len(block.exits) == 0: - yield 'return %s;' % expr(block.inputargs[0]) + retval = expr(block.inputargs[0]) + if hasattr(block, 'exc_type'): + # exceptional return block + yield 'PyErr_SetObject(PyExc_%s, %s);' % ( + block.exc_type.__name__, retval) + yield 'return NULL;' + else: + # regular return block + yield 'return %s;' % retval continue - if len(block.exits) > 1: + elif block.exitswitch is None: + # single-exit block + assert len(block.exits) == 1 + for op in gen_link(block.exits[0]): + yield op + yield '' + elif block.exitswitch == Constant(last_exception): + # block catching the exceptions raised by its last operation + # we handle the non-exceptional case first + link = block.exits[0] + assert link.exitcase is None + for op in gen_link(link): + yield op + # we must catch the exception raised by the last operation, + # which goes to the last err%d_%d label written above. + yield '' + to_release.pop() # skip default error handling for this label + yield 'err%d_%d:' % (blocknum[block], len(to_release)) + yield '' + for link in block.exits[1:]: + assert issubclass(link.exitcase, Exception) + yield 'if (PyErr_ExceptionMatches(PyExc_%s)) {' % ( + link.exitcase.__name__,) + yield '\tPyErr_Clear();' + for op in gen_link(link): + yield '\t' + op + yield '}' + err_reachable = True + else: + # block ending in a switch on a value for link in block.exits[:-1]: yield 'if (EQ_%s(%s)) {' % (link.exitcase, block.exitswitch.name) @@ -302,16 +345,18 @@ link = block.exits[-1] yield 'assert(EQ_%s(%s));' % (link.exitcase, block.exitswitch.name) - for op in gen_link(block.exits[-1]): - yield op + for op in gen_link(block.exits[-1]): + yield op + yield '' - yield '' - to_release.pop() # this label is never reachable while to_release: - n = len(to_release) v = to_release.pop() - yield 'err%d_%d: Py_DECREF(%s);' % (blocknum[block], n, v.name) - yield 'err%d_0: return NULL;' % blocknum[block] + if err_reachable: + yield 'Py_DECREF(%s);' % v.name + yield 'err%d_%d:' % (blocknum[block], len(to_release)) + err_reachable = True + if err_reachable: + yield 'return NULL;' # ____________________________________________________________ Modified: pypy/trunk/src/pypy/translator/gencl.py ============================================================================== --- pypy/trunk/src/pypy/translator/gencl.py (original) +++ pypy/trunk/src/pypy/translator/gencl.py Thu Oct 14 16:14:14 2004 @@ -1,5 +1,4 @@ from pypy.objspace.flow.model import * -from pypy.objspace.flow.objspace import implicitexc from pypy.translator.annrpython import RPythonAnnotator from pypy.translator.simplify import simplify_graph @@ -124,9 +123,6 @@ print "(let ((result (funcall", s(iterator), ")))" print " (setq", s(result), "(car result))" print " (setq last-exc (cdr result)))" - def op_exception(self): - s = self.str - print "(psetq", s(self.result), "last-exc last-exc nil)" builtin_map = { pow: "expt", range: "python-range", @@ -191,8 +187,8 @@ return val elif isinstance(val, type(Exception)) and issubclass(val, Exception): return "'%s" % val.__name__ - elif val is implicitexc: - return "'implicitexc" + elif val is last_exception: + return "last-exc" else: return "#<%r>" % (val,) def emitcode(self): Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Thu Oct 14 16:14:14 2004 @@ -2,7 +2,6 @@ """ from pypy.objspace.flow.model import * -from pypy.objspace.flow.objspace import implicitexc def eliminate_empty_blocks(graph): """Eliminate basic blocks that do not contain any operations. @@ -62,15 +61,17 @@ 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.""" + """An exception raised implicitely has a particular value of + space.wrap(last_exception) -- see pypy.objspace.flow.objspace.make_op -- + which shows up in the flow graph if the exception is not caught. This + function removes such exceptions entierely. This gets rid for example + of possible IndexErrors by 'getitem', assuming they cannot happen unless + there is an exception handler in the same function.""" def visit(link): if isinstance(link, Link) and link in link.prevblock.exits: if (isinstance(link.exitcase, type(Exception)) and issubclass(link.exitcase, Exception) and - link.args == [Constant(implicitexc)] and + link.args == [Constant(last_exception)] and len(link.target.exits) == 0 and hasattr(link.target, 'exc_type')): # remove direct links to implicit exception return blocks Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Thu Oct 14 16:14:14 2004 @@ -84,6 +84,11 @@ self.assertEquals(sand(0, 6), "no") self.assertEquals(sand(0, 0), "no") + def test_yast(self): + yast = self.build_cfunc(snippet.yast) + self.assertEquals(yast([1000,100,10,1]), 1111) + self.assertEquals(yast(range(100)), (99*100)/2) + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): From hpk at codespeak.net Thu Oct 14 16:51:22 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 14 Oct 2004 16:51:22 +0200 (MEST) Subject: [pypy-svn] r6929 - pypy/trunk/doc/sprintinfo Message-ID: <20041014145122.C1CA55A165@thoth.codespeak.net> Author: hpk Date: Thu Oct 14 16:51:22 2004 New Revision: 6929 Added: pypy/trunk/doc/sprintinfo/VilniusSprintAnnouncement.txt Log: added VilniusSprint Announcement proposal. slightly modified from what i previously wrote, incorporated some caution regarding the EU/sprint travel+accomodation funding as proposed by Samuele. Armin: please simply commit any changes ... everyone: comment now or never, we are close to sending it out. Added: pypy/trunk/doc/sprintinfo/VilniusSprintAnnouncement.txt ============================================================================== --- (empty file) +++ pypy/trunk/doc/sprintinfo/VilniusSprintAnnouncement.txt Thu Oct 14 16:51:22 2004 @@ -0,0 +1,51 @@ +Hi Pythonistas and interested developers, + +PyPy, the python-in-python implementation, is steadily moving +on. The next coding sprint will take place in Vilnius, +Lithunia, from + + 15th to 23rd of November, 2004 + +and is organized by the nice Programmers of Vilnius (POV) +company. See http://codespeak.net/pypy/index.cgi?doc for more +in-depth information about PyPy. + +Again, we will be heading towards a first generated C version +of our already pretty compliant Python interpreter and types +implementation. Last time, before the EuroPython 2004 +conference, we actually had a similar goal (a PyPy/C-version) but +discovered we had to largely refactor the basic model for +attribute accesses. We are now closely mirroring the marvelous +"descriptor"-mechanism of CPython. + +If you are interested to participate in our fun and somewhat +mind-altering python sprint event then please subscribe at + + http://codespeak.net/moin/pypy/moin.cgi/VilniusSprintAttendants + +and look around for more information. You'll find that most of +the core PyPy developers are already determined to come. There +are also many areas that need attention so that we should +have tasks suited for different levels of expertise. + +At http://codespeak.net/moin/pypy/moin.cgi/VilniusSprintTasks +you'll find our sprint planning task list which will probably +grow in the next weeks. + +Note that our EU funding efforts are at the final stage now. +In the next weeks, quite likely before the Vilnius sprint, we +_hope_ to get a "go!" from the european commission. One side +effect would be that coders - probably restricted to european +citizens - may generally apply for getting travel and +accomodation costs refunded for PyPy sprints. This would +reduce the barrier of entry to the question if you like to +spend your time with a pypy sprint. However, we probably need +some time to work out the details after when we get more +information from the EU. + +If you have any questions don't hesitate to contact +pypy-sprint at codespeak.net or one of us personally. + +cheers & a bientot, + + Holger Krekel, Armin Rigo From hpk at codespeak.net Mon Oct 18 13:46:43 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 18 Oct 2004 13:46:43 +0200 (MEST) Subject: [pypy-svn] r7003 - in pypy/trunk/src: . py py/bin py/execnet py/magic py/path py/process py/test pypy/tool Message-ID: <20041018114643.BA3D85A92B@thoth.codespeak.net> Author: hpk Date: Mon Oct 18 13:46:43 2004 New Revision: 7003 Added: pypy/trunk/src/py/ - copied from r6999, py/dist/py/ pypy/trunk/src/py/__init__.py - copied unchanged from r7002, py/dist/py/__init__.py pypy/trunk/src/py/bin/ - copied from r7002, py/dist/py/bin/ pypy/trunk/src/py/env.py - copied unchanged from r7002, py/dist/py/env.py pypy/trunk/src/py/execnet/ - copied from r7002, py/dist/py/execnet/ pypy/trunk/src/py/initpkg.py - copied unchanged from r7002, py/dist/py/initpkg.py pypy/trunk/src/py/magic/ - copied from r7002, py/dist/py/magic/ pypy/trunk/src/py/path/ - copied from r7002, py/dist/py/path/ pypy/trunk/src/py/process/ - copied from r7002, py/dist/py/process/ pypy/trunk/src/py/pytest.py - copied unchanged from r7002, py/dist/py/pytest.py pypy/trunk/src/py/test/ - copied from r7002, py/dist/py/test/ pypy/trunk/src/py/test_api.py - copied unchanged from r7002, py/dist/py/test_api.py pypy/trunk/src/py/test_initpkg.py - copied unchanged from r7002, py/dist/py/test_initpkg.py Modified: pypy/trunk/src/ (props changed) pypy/trunk/src/pypy/tool/pypyutest.py pypy/trunk/src/pypy/tool/testit.py pypy/trunk/src/pypy/tool/udir.py Log: made the move from 'std' to the py lib, see http://codespeak.net/py for documentation. Modified: pypy/trunk/src/pypy/tool/pypyutest.py ============================================================================== --- pypy/trunk/src/pypy/tool/pypyutest.py (original) +++ pypy/trunk/src/pypy/tool/pypyutest.py Mon Oct 18 13:46:43 2004 @@ -1,4 +1,6 @@ -from std.__impl__.magic import exprinfo +from py.__impl__.magic import exprinfo +import py +py.magic.autopath() from pypy.objspace.std import StdObjSpace class AppRunnerFrame: Modified: pypy/trunk/src/pypy/tool/testit.py ============================================================================== --- pypy/trunk/src/pypy/tool/testit.py (original) +++ pypy/trunk/src/pypy/tool/testit.py Mon Oct 18 13:46:43 2004 @@ -242,7 +242,7 @@ Additionally, their fully qualified python module path has to be accepted by filterfunc (if it is not None). """ - from std import path + from py import path root = path.local(root) if Options.verbose > 2: Modified: pypy/trunk/src/pypy/tool/udir.py ============================================================================== --- pypy/trunk/src/pypy/tool/udir.py (original) +++ pypy/trunk/src/pypy/tool/udir.py Mon Oct 18 13:46:43 2004 @@ -1,6 +1,6 @@ import autopath -from std.path import local +from py.path import local udir = local.make_numbered_dir(base='usession-', keep=3) From arigo at codespeak.net Mon Oct 18 14:00:27 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 18 Oct 2004 14:00:27 +0200 (MEST) Subject: [pypy-svn] r7004 - pypy/trunk/src/pypy Message-ID: <20041018120027.123305A92B@thoth.codespeak.net> Author: arigo Date: Mon Oct 18 14:00:26 2004 New Revision: 7004 Modified: pypy/trunk/src/pypy/TODO Log: Listed the main missing pieces for Python compliance in TODO. Modified: pypy/trunk/src/pypy/TODO ============================================================================== --- pypy/trunk/src/pypy/TODO (original) +++ pypy/trunk/src/pypy/TODO Mon Oct 18 14:00:26 2004 @@ -1,6 +1,10 @@ General ======= +* missing pieces currently borrowed from CPython: the bytecode + compiler, a number of C modules, and some types -- as printed + when running py.py: "faking ". + * not all of CPython's exceptions use the same __init__! * refactor the cmdline-entrypoints to PyPy aka py.py main.py From arigo at codespeak.net Mon Oct 18 14:01:38 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 18 Oct 2004 14:01:38 +0200 (MEST) Subject: [pypy-svn] r7005 - in pypy/trunk/src/pypy/translator: . tool tool/pygame Message-ID: <20041018120138.ED6A45A92B@thoth.codespeak.net> Author: arigo Date: Mon Oct 18 14:01:37 2004 New Revision: 7005 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/tool/make_dot.py pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Code reformatting. Added multicolor blocks in flow graphs for the upcoming graph transformation tools. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Mon Oct 18 14:01:37 2004 @@ -221,63 +221,59 @@ /* for Python 2.2 only */ static PyObject* PyObject_GetItem1(PyObject* obj, PyObject* index) { - int start, stop, step; - if (!PySlice_Check(index)) - return PyObject_GetItem(obj, index); - if (((PySliceObject*) index)->start == Py_None) - start = -INT_MAX-1; - else - { - start = PyInt_AsLong(((PySliceObject*) index)->start); - if (start == -1 && PyErr_Occurred()) return NULL; - } - if (((PySliceObject*) index)->stop == Py_None) - stop = INT_MAX; - else - { - stop = PyInt_AsLong(((PySliceObject*) index)->stop); - if (stop == -1 && PyErr_Occurred()) return NULL; - } - if (((PySliceObject*) index)->step != Py_None) - { - step = PyInt_AsLong(((PySliceObject*) index)->step); - if (step == -1 && PyErr_Occurred()) return NULL; - if (step != 1) { - PyErr_SetString(PyExc_ValueError, "obj[slice]: no step allowed"); - return NULL; - } - } - return PySequence_GetSlice(obj, start, stop); + int start, stop, step; + if (!PySlice_Check(index)) + return PyObject_GetItem(obj, index); + if (((PySliceObject*) index)->start == Py_None) + start = -INT_MAX-1; + else { + start = PyInt_AsLong(((PySliceObject*) index)->start); + if (start == -1 && PyErr_Occurred()) return NULL; + } + if (((PySliceObject*) index)->stop == Py_None) + stop = INT_MAX; + else { + stop = PyInt_AsLong(((PySliceObject*) index)->stop); + if (stop == -1 && PyErr_Occurred()) return NULL; + } + if (((PySliceObject*) index)->step != Py_None) { + step = PyInt_AsLong(((PySliceObject*) index)->step); + if (step == -1 && PyErr_Occurred()) return NULL; + if (step != 1) { + PyErr_SetString(PyExc_ValueError, + "obj[slice]: no step allowed"); + return NULL; + } + } + return PySequence_GetSlice(obj, start, stop); } static PyObject* PyObject_SetItem1(PyObject* obj, PyObject* index, PyObject* v) { - int start, stop, step; - if (!PySlice_Check(index)) - return PyObject_SetItem(obj, index, v); - if (((PySliceObject*) index)->start == Py_None) - start = -INT_MAX-1; - else - { - start = PyInt_AsLong(((PySliceObject*) index)->start); - if (start == -1 && PyErr_Occurred()) return NULL; - } - if (((PySliceObject*) index)->stop == Py_None) - stop = INT_MAX; - else - { - stop = PyInt_AsLong(((PySliceObject*) index)->stop); - if (stop == -1 && PyErr_Occurred()) return NULL; - } - if (((PySliceObject*) index)->step != Py_None) - { - step = PyInt_AsLong(((PySliceObject*) index)->step); - if (step == -1 && PyErr_Occurred()) return NULL; - if (step != 1) { - PyErr_SetString(PyExc_ValueError, "obj[slice]: no step allowed"); - return NULL; - } - } - return PySequence_SetSlice(obj, start, stop, v); + int start, stop, step; + if (!PySlice_Check(index)) + return PyObject_SetItem(obj, index, v); + if (((PySliceObject*) index)->start == Py_None) + start = -INT_MAX-1; + else { + start = PyInt_AsLong(((PySliceObject*) index)->start); + if (start == -1 && PyErr_Occurred()) return NULL; + } + if (((PySliceObject*) index)->stop == Py_None) + stop = INT_MAX; + else { + stop = PyInt_AsLong(((PySliceObject*) index)->stop); + if (stop == -1 && PyErr_Occurred()) return NULL; + } + if (((PySliceObject*) index)->step != Py_None) { + step = PyInt_AsLong(((PySliceObject*) index)->step); + if (step == -1 && PyErr_Occurred()) return NULL; + if (step != 1) { + PyErr_SetString(PyExc_ValueError, + "obj[slice]: no step allowed"); + return NULL; + } + } + return PySequence_SetSlice(obj, start, stop, v); } #endif 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 Oct 18 14:01:37 2004 @@ -110,7 +110,7 @@ lines.append("") numblocks = len(block.exits) color = "black" - fillcolor = "white" + fillcolor = getattr(block, "fillcolor", "white") if not numblocks: shape = "box" fillcolor="green" Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Mon Oct 18 14:01:37 2004 @@ -19,6 +19,14 @@ } re_nonword=re.compile(r'(\W+)') +def getcolor(name, default): + if name in COLOR: + return COLOR[name] + elif name.startswith('#') and len(name) == 7: + return (int(name[1:3],16), int(name[3:5],16), int(name[5:7],16)) + else: + return default + class GraphLayout: @@ -233,8 +241,8 @@ xcenter, ycenter = self.map(node.x, node.y) boxwidth = int(node.w * self.scale) boxheight = int(node.h * self.scale) - fgcolor = COLOR.get(node.color, (0,0,0)) - bgcolor = COLOR.get(node.fillcolor, (255,255,255)) + fgcolor = getcolor(node.color, (0,0,0)) + bgcolor = getcolor(node.fillcolor, (255,255,255)) text = node.label lines = text.replace('\l','\l\n').replace('\r','\r\n').split('\n') @@ -307,7 +315,7 @@ edgebodycmd = [] edgeheadcmd = [] for edge in self.graphlayout.edges: - fgcolor = COLOR.get(edge.color, (0,0,0)) + fgcolor = getcolor(edge.color, (0,0,0)) points = [self.map(*xy) for xy in edge.bezierpoints()] def drawedgebody(points=points, fgcolor=fgcolor): Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Mon Oct 18 14:01:37 2004 @@ -114,7 +114,10 @@ else: edge = self.viewer.edge_at_position(pos) if edge: - if not self.look_at_node(edge.head): + if (self.distance_to_node(edge.head) >= + self.distance_to_node(edge.tail)): + self.look_at_node(edge.head) + else: self.look_at_node(edge.tail) def sethighlight(self, word=None): @@ -139,6 +142,11 @@ self.ANIM_STEP = self.ANIM_STEP * 0.9 + frametime * 0.1 yield 1.0 + def distance_to_node(self, node): + cx1, cy1 = self.viewer.getcenter() + cx2, cy2 = node.x, node.y + return (cx2-cx1)*(cx2-cx1) + (cy2-cy1)*(cy2-cy1) + def look_at_node(self, node): """Shift the node in view.""" endscale = min(float(self.width-40) / node.w, From arigo at codespeak.net Mon Oct 18 14:02:41 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 18 Oct 2004 14:02:41 +0200 (MEST) Subject: [pypy-svn] r7006 - pypy/trunk/src/pypy/annotation Message-ID: <20041018120241.ED6695ABD7@thoth.codespeak.net> Author: arigo Date: Mon Oct 18 14:02:41 2004 New Revision: 7006 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: Generalized from 'list+=list' to 'list+=iterable'. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Mon Oct 18 14:02:41 2004 @@ -85,8 +85,12 @@ add = union - def inplace_add((lst1, lst2)): - pair(lst1, SomeInteger()).setitem(lst2.s_item) + +class __extend__(pairtype(SomeList, SomeObject)): + + def inplace_add((lst1, obj2)): + s_iter = obj2.iter() + pair(lst1, SomeInteger()).setitem(s_iter.next()) return lst1 From hpk at codespeak.net Tue Oct 19 14:37:38 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 19 Oct 2004 14:37:38 +0200 (MEST) Subject: [pypy-svn] r7023 - in pypy/trunk/src: . py Message-ID: <20041019123738.1CB315A15E@thoth.codespeak.net> Author: hpk Date: Tue Oct 19 14:37:37 2004 New Revision: 7023 Removed: pypy/trunk/src/py/ Modified: pypy/trunk/src/ (props changed) Log: py becomes and external ... From ale at codespeak.net Tue Oct 19 16:33:01 2004 From: ale at codespeak.net (ale at codespeak.net) Date: Tue, 19 Oct 2004 16:33:01 +0200 (MEST) Subject: [pypy-svn] r7028 - in pypy/trunk/src/pypy: tool/tb_server translator/tool Message-ID: <20041019143301.58A7E5A15E@thoth.codespeak.net> Author: ale Date: Tue Oct 19 16:32:59 2004 New Revision: 7028 Modified: pypy/trunk/src/pypy/tool/tb_server/render.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: I have changed some references from "std" to "py" Modified: pypy/trunk/src/pypy/tool/tb_server/render.py ============================================================================== --- pypy/trunk/src/pypy/tool/tb_server/render.py (original) +++ pypy/trunk/src/pypy/tool/tb_server/render.py Tue Oct 19 16:32:59 2004 @@ -1,7 +1,7 @@ from pypy.tool.tb_server.server import TBRequestHandler from xpy import html, xml -from std.magic import dyncode +from py.magic import dyncode import traceback import cgi 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 Tue Oct 19 16:32:59 2004 @@ -2,7 +2,7 @@ from pypy.objspace.flow import FlowObjSpace from pypy.translator.gencl import GenCL -from std.process import cmdexec +from py.process import cmdexec class Literal: def __init__(self, val): 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 Tue Oct 19 16:32:59 2004 @@ -2,8 +2,8 @@ from pypy.tool import testit from pypy.tool.udir import udir -from std.process import cmdexec -from std import path +from py.process import cmdexec +from py import path from pypy.translator.genpyrex import GenPyrex import os, sys, inspect 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 Oct 19 16:32:59 2004 @@ -7,7 +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 +from py.process import cmdexec class DotGen: From jum at codespeak.net Sun Oct 24 01:36:34 2004 From: jum at codespeak.net (jum at codespeak.net) Date: Sun, 24 Oct 2004 01:36:34 +0200 (MEST) Subject: [pypy-svn] r7112 - pypy/trunk/doc/devel Message-ID: <20041023233634.ED26E5B652@thoth.codespeak.net> Author: jum Date: Sun Oct 24 01:36:34 2004 New Revision: 7112 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 Sun Oct 24 01:36:34 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.5-darwin-ppc.tar.gz +.. _MacOS: http://codespeak.net/~jum/svn-1.1.1-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