[pypy-svn] r7535 - in pypy/trunk/src/pypy: interpreter interpreter/test objspace/flow objspace/std tool translator translator/test

arigo at codespeak.net arigo at codespeak.net
Sun Nov 21 20:13:09 CET 2004


Author: arigo
Date: Sun Nov 21 20:13:08 2004
New Revision: 7535

Modified:
   pypy/trunk/src/pypy/interpreter/eval.py
   pypy/trunk/src/pypy/interpreter/executioncontext.py
   pypy/trunk/src/pypy/interpreter/generator.py
   pypy/trunk/src/pypy/interpreter/miscutils.py
   pypy/trunk/src/pypy/interpreter/pyframe.py
   pypy/trunk/src/pypy/interpreter/pyopcode.py
   pypy/trunk/src/pypy/interpreter/test/test_interpreter.py
   pypy/trunk/src/pypy/interpreter/typedef.py
   pypy/trunk/src/pypy/objspace/flow/flowcontext.py
   pypy/trunk/src/pypy/objspace/flow/framestate.py
   pypy/trunk/src/pypy/objspace/flow/objspace.py
   pypy/trunk/src/pypy/objspace/flow/specialcase.py
   pypy/trunk/src/pypy/objspace/std/fake.py
   pypy/trunk/src/pypy/objspace/std/typeobject.py
   pypy/trunk/src/pypy/tool/cache.py
   pypy/trunk/src/pypy/translator/genc.h
   pypy/trunk/src/pypy/translator/genc.py
   pypy/trunk/src/pypy/translator/test/snippet.py
   pypy/trunk/src/pypy/translator/test/test_ctrans.py
   pypy/trunk/src/pypy/translator/translator.py
Log:
Progress on translate_pypy -no-a.  Now it's starting to complain on real
bugs on our RPython code, like typos in never-tested branches or locals
that could be undefined in some rare cases.

- a typo in EXTENDED_ARG.  In other words it never worked.
  Added a test (not so easy...).

- a few extra NOT_RPYTHON annotations, an extra Cache() usage.

- bare raise statements (to re-raise exceptions) now supported by the flow
  object space.  Required minor changes in the methods of the
  pypy.interpreter.eval.Frame class.

- in the flow graphs, "raise Class" doesn't try to build a Class()
  instance as the exception value any more; it uses None.  (It doesn't try
  to do any normalization at all.)

- always check the length of the iterable in
  FlowObjSpace.unpackiterable().

- NameErroring typo in untested code in fake.py.

- typeobject.compute_C3_mro() shows an exemple of code that the flow
  object space complains about: 'candidate' might be undefined.  We
  now it cannot be; let's use a return statement to help the flow
  objspace.

- a few memory-saving hacks in genc.py allow it to consume a nearly
  constant amount of heap, instead of growing fast.

- OP_LEN in genc.h.

- (hopefully temporary) got tired of finding where to freeze the caches,
  and did it in Cache.__hash__().


Modified: pypy/trunk/src/pypy/interpreter/eval.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/eval.py	(original)
+++ pypy/trunk/src/pypy/interpreter/eval.py	Sun Nov 21 20:13:08 2004
@@ -70,12 +70,7 @@
     def run(self):
         "Run the frame."
         executioncontext = self.space.getexecutioncontext()
-        previous = executioncontext.enter(self)
-        try:
-            result = self.eval(executioncontext)
-        finally:
-            executioncontext.leave(previous)
-        return result
+        return executioncontext.run_frame(self)
 
     def eval(self, executioncontext):
         "Abstract method to override."

Modified: pypy/trunk/src/pypy/interpreter/executioncontext.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/executioncontext.py	(original)
+++ pypy/trunk/src/pypy/interpreter/executioncontext.py	Sun Nov 21 20:13:08 2004
@@ -9,17 +9,18 @@
         self.space = space
         self.framestack = Stack()
 
-    def enter(self, frame):
+    def run_frame(self, frame):
         locals = getthreadlocals()
-        self.framestack.push(frame)
         previous_ec = locals.executioncontext
         locals.executioncontext = self
-        return previous_ec
-
-    def leave(self, previous_ec):
-        locals = getthreadlocals()
-        locals.executioncontext = previous_ec
-        self.framestack.pop()
+        self.framestack.push(frame)
+        try:
+            w_result = frame.eval(self)
+        finally:
+            self.framestack.pop()
+            locals = getthreadlocals()
+            locals.executioncontext = previous_ec
+        return w_result
 
     def get_w_builtins(self):
         if self.framestack.empty():

Modified: pypy/trunk/src/pypy/interpreter/generator.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/generator.py	(original)
+++ pypy/trunk/src/pypy/interpreter/generator.py	Sun Nov 21 20:13:08 2004
@@ -47,16 +47,17 @@
         return self.space.wrap(self)
 
     def descr_next(self):
-        space = self.frame.space
+        space = self.space
         if self.running:
             raise OperationError(space.w_ValueError,
                                  space.wrap('generator already executing'))
         if self.frame.exhausted:
             raise OperationError(space.w_StopIteration, space.w_None) 
+        executioncontext = space.getexecutioncontext()
         self.running = True
         try:
             try:
-                return Frame.run(self.frame)
+                return executioncontext.run_frame(self.frame)
             except OperationError, e:
                 if e.match(self.space, self.space.w_StopIteration):
                     raise OperationError(space.w_StopIteration, space.w_None) 

Modified: pypy/trunk/src/pypy/interpreter/miscutils.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/miscutils.py	(original)
+++ pypy/trunk/src/pypy/interpreter/miscutils.py	Sun Nov 21 20:13:08 2004
@@ -40,8 +40,8 @@
 
 
 class InitializedClass(type):
-    """A meta-class that allows a class to initialize itself (or its
-    subclasses) by calling __initclass__() as a class method."""
+    """NOT_RPYTHON.  A meta-class that allows a class to initialize itself (or
+    its subclasses) by calling __initclass__() as a class method."""
     def __init__(self, name, bases, dict):
         super(InitializedClass, self).__init__(name, bases, dict)
         for basecls in self.__mro__:
@@ -51,8 +51,9 @@
 
 
 class RwDictProxy(object):
-    """A dict-like class standing for 'cls.__dict__', to work around
-    the fact that the latter is a read-only proxy for new-style classes."""
+    """NOT_RPYTHON.  A dict-like class standing for 'cls.__dict__', to work
+    around the fact that the latter is a read-only proxy for new-style
+    classes."""
     
     def __init__(self, cls):
         self.cls = cls

Modified: pypy/trunk/src/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/pyframe.py	(original)
+++ pypy/trunk/src/pypy/interpreter/pyframe.py	Sun Nov 21 20:13:08 2004
@@ -41,9 +41,9 @@
         "Interpreter main loop!"
         try:
             while True:
+                executioncontext.bytecode_trace(self)
+                last_instr = self.next_instr
                 try:
-                    executioncontext.bytecode_trace(self)
-                    last_instr = self.next_instr
                     try:
                         # fetch and dispatch the next opcode
                         # dispatch() is abstract, see pyopcode.

Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/pyopcode.py	(original)
+++ pypy/trunk/src/pypy/interpreter/pyopcode.py	Sun Nov 21 20:13:08 2004
@@ -754,7 +754,7 @@
     def EXTENDED_ARG(f, oparg):
         opcode = f.nextop()
         oparg = oparg<<16 | f.nextarg()
-        fn = self.dispatch_table[opcode]
+        fn = f.dispatch_table[opcode]
         if not fn.has_arg:
             raise pyframe.BytecodeCorruption
         fn(f, oparg)

Modified: pypy/trunk/src/pypy/interpreter/test/test_interpreter.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/test/test_interpreter.py	(original)
+++ pypy/trunk/src/pypy/interpreter/test/test_interpreter.py	Sun Nov 21 20:13:08 2004
@@ -160,6 +160,26 @@
             ''')
         self.codetest(code, 'f', [])
 
+    def test_extended_arg(self):
+        longexpr = 'x = x or ' + '-x' * 2500
+        code = '''
+def f(x):
+    %s
+    %s
+    %s
+    %s
+    %s
+    %s
+    %s
+    %s
+    %s
+    %s
+    while x:
+        x -= 1   # EXTENDED_ARG is for the JUMP_ABSOLUTE at the end of the loop
+    return x
+''' % ((longexpr,)*10)
+        self.assertEquals(self.codetest(code, 'f', [3]), 0)
+
 
 class AppTestInterpreter(testit.AppTestCase):
     def test_trivial(self):

Modified: pypy/trunk/src/pypy/interpreter/typedef.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/typedef.py	(original)
+++ pypy/trunk/src/pypy/interpreter/typedef.py	Sun Nov 21 20:13:08 2004
@@ -5,60 +5,63 @@
 from pypy.interpreter.gateway import interp2app 
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.error import OperationError
+from pypy.tool.cache import Cache
+import new
 
 class TypeDef:
     def __init__(self, __name, __base=None, **rawdict):
+        "NOT_RPYTHON: initialization-time only"
         self.name = __name
         self.base = __base
         self.hasdict = '__dict__' in rawdict or (__base and __base.hasdict)
         self.rawdict = rawdict
 
 
-unique_interplevel_subclass_cache = {}
+unique_interplevel_subclass_cache = Cache()
 def get_unique_interplevel_subclass(cls):
-    try:
-        return unique_interplevel_subclass_cache[cls]
-    except KeyError:
-        typedef = cls.typedef
-        name = 'User' + cls.__name__
-        body = {}
-
-        class User_InsertNameHere(object):
-            
-            def getclass(self, space):
-                return self.w__class__
-            
-            def setclass(self, w_subtype):
-                # XXX sanity checks here
+    return unique_interplevel_subclass_cache.getorbuild(cls, _buildusercls, None)
+
+def _buildusercls(cls, ignored):
+    "NOT_RPYTHON: initialization-time only"
+    typedef = cls.typedef
+    name = 'User' + cls.__name__
+    body = {}
+
+    class User_InsertNameHere(object):
+
+        def getclass(self, space):
+            return self.w__class__
+
+        def setclass(self, w_subtype):
+            # XXX sanity checks here
+            self.w__class__ = w_subtype
+
+        if typedef.hasdict:
+            def user_setup(self, space, w_subtype):
+                self.space = space
                 self.w__class__ = w_subtype
-            
-            if typedef.hasdict:
-                def user_setup(self, space, w_subtype):
-                    self.space = space
-                    self.w__class__ = w_subtype
-                    
-            else:
-                def getdict(self):
-                    return self.w__dict__
-
-                def setdict(self, w_dict):
-                    space = self.space
-                    if not space.is_true(space.isinstance(w_dict, space.w_dict)):
-                        raise OperationError(space.w_TypeError,
-                                space.wrap("setting dictionary to a non-dict"))
-                    self.w__dict__ = w_dict
-
-                def user_setup(self, space, w_subtype):
-                    self.space = space
-                    self.w__class__ = w_subtype
-                    self.w__dict__ = space.newdict([])
-
-        body = dict([(key, value)
-                     for key, value in User_InsertNameHere.__dict__.items()
-                     if not key.startswith('_')])
-        subcls = type(name, (cls,), body)
-        unique_interplevel_subclass_cache[cls] = subcls
-        return subcls
+
+        else:
+            def getdict(self):
+                return self.w__dict__
+
+            def setdict(self, w_dict):
+                space = self.space
+                if not space.is_true(space.isinstance(w_dict, space.w_dict)):
+                    raise OperationError(space.w_TypeError,
+                            space.wrap("setting dictionary to a non-dict"))
+                self.w__dict__ = w_dict
+
+            def user_setup(self, space, w_subtype):
+                self.space = space
+                self.w__class__ = w_subtype
+                self.w__dict__ = space.newdict([])
+
+    body = dict([(key, value)
+                 for key, value in User_InsertNameHere.__dict__.items()
+                 if not key.startswith('_')])
+    subcls = type(name, (cls,), body)
+    return subcls
 
 def instantiate(cls):
     "Create an empty instance of 'cls'."
@@ -69,6 +72,7 @@
 
 class GetSetProperty(Wrappable):
     def __init__(self, fget, fset=None, fdel=None, doc=None):
+        "NOT_RPYTHON: initialization-time only"
         fget = getattr(fget, 'im_func', fget) 
         fset = getattr(fset, 'im_func', fset) 
         fdel = getattr(fdel, 'im_func', fdel) 
@@ -106,12 +110,14 @@
         )
 
 def attrproperty(name):
+    "NOT_RPYTHON: initialization-time only"
     def fget(space, w_obj):
         obj = space.unwrap_builtin(w_obj)
         return space.wrap(getattr(obj, name))
     return GetSetProperty(fget)
 
 def attrproperty_w(name):
+    "NOT_RPYTHON: initialization-time only"
     def fget(space, w_obj):
         obj = space.unwrap_builtin(w_obj)
         w_value = getattr(obj, name)

Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/flowcontext.py	(original)
+++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py	Sun Nov 21 20:13:08 2004
@@ -205,7 +205,7 @@
             except ExitFrame:
                 continue   # restarting a dead SpamBlock
             try:
-                w_result = frame.eval(self)
+                w_result = self.run_frame(frame)
             except OperationError, e:
                 link = Link([e.w_type, e.w_value], self.graph.exceptblock)
                 self.crnt_block.closeblock(link)

Modified: pypy/trunk/src/pypy/objspace/flow/framestate.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/framestate.py	(original)
+++ pypy/trunk/src/pypy/objspace/flow/framestate.py	Sun Nov 21 20:13:08 2004
@@ -1,4 +1,5 @@
 from pypy.interpreter.pyframe import PyFrame, ControlFlowException
+from pypy.interpreter.error import OperationError
 from pypy.objspace.flow.model import *
 
 class FrameState:
@@ -7,11 +8,16 @@
     def __init__(self, state):
         if isinstance(state, PyFrame):
             data = state.getfastscope() + state.valuestack.items
+            if state.last_exception is None:
+                data.append(Constant(None))
+                data.append(Constant(None))
+            else:
+                data.append(state.last_exception.w_type)
+                data.append(state.last_exception.w_value)
             recursively_flatten(state.space, data)
             self.mergeable = data
             self.nonmergeable = (
                 state.blockstack.items[:],
-                state.last_exception,
                 state.next_instr,
                 state.w_locals,
             )
@@ -30,10 +36,14 @@
             data = self.mergeable[:]
             recursively_unflatten(frame.space, data)
             frame.setfastscope(data[:fastlocals])
-            frame.valuestack.items[:] = data[fastlocals:]
+            frame.valuestack.items[:] = data[fastlocals:-2]
+            if data[-2] == Constant(None):
+                assert data[-1] == Constant(None)
+                frame.last_exception = None
+            else:
+                frame.last_exception = OperationError(data[-2], data[-1])
             (
                 frame.blockstack.items[:],
-                frame.last_exception,
                 frame.next_instr,
                 frame.w_locals,
             ) = self.nonmergeable

Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/objspace.py	(original)
+++ pypy/trunk/src/pypy/objspace/flow/objspace.py	Sun Nov 21 20:13:08 2004
@@ -171,7 +171,11 @@
                 items.append(w_item)
                 i += 1
             return items
-        elif expected_length is not None: 
+        elif expected_length is not None:
+            w_len = self.len(w_iterable)
+            w_correct = self.eq(w_len, self.wrap(expected_length))
+            if not self.is_true(w_correct):
+                raise OperationError(self.w_ValueError, self.w_None)
             return [self.do_operation('getitem', w_iterable, self.wrap(i)) 
                         for i in range(expected_length)]
             # XXX TEMPORARY HACK XXX TEMPORARY HACK XXX TEMPORARY HACK

Modified: pypy/trunk/src/pypy/objspace/flow/specialcase.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/specialcase.py	(original)
+++ pypy/trunk/src/pypy/objspace/flow/specialcase.py	Sun Nov 21 20:13:08 2004
@@ -21,7 +21,7 @@
 
     * raise Class
        - with a constant Class, it is easy to recognize.
-         The associated value is Class().
+         But we don't normalize: the associated value is None.
 
     * raise Class(...)
        - when the class is instantiated in-place, we can figure that out
@@ -42,8 +42,7 @@
     etype = getconstclass(space, w_arg1)
     if etype is not None:
         # raise Class
-        w_arg2 = space.do_operation('simple_call', w_arg1)
-        return (w_arg1, w_arg2)
+        return (w_arg1, space.w_None)
     # raise Class(..)?  We need a hack to figure out of which class it is.
     # Normally, Instance should have been created by the previous operation
     # which should be a simple_call(<Class>, ...).

Modified: pypy/trunk/src/pypy/objspace/std/fake.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/fake.py	(original)
+++ pypy/trunk/src/pypy/objspace/std/fake.py	Sun Nov 21 20:13:08 2004
@@ -16,10 +16,9 @@
 
 # real-to-wrapped exceptions
 def wrap_exception(space):
-    "NOT_RPYTHON"  # XXX this needs to end up in the translated code somehow!
     exc, value, tb = sys.exc_info()
     if exc is OperationError:
-        raise exc, value, tb   # just re-raise it
+        raise exc, value  #, tb   # just re-raise it (tb ignored: not RPython)
     name = exc.__name__
     if hasattr(space, 'w_' + name):
         w_exc = getattr(space, 'w_' + name)
@@ -31,7 +30,7 @@
     else:
         w_exc = space.wrap(exc)
         w_value = space.wrap(value)
-    raise OperationError, OperationError(w_exc, w_value), tb
+    raise OperationError, OperationError(w_exc, w_value)  #, tb not RPython
 
 def fake_type(cpy_type):
     assert type(cpy_type) is type
@@ -96,7 +95,7 @@
             unwrappedargs = self.space.unwrap(w_args)
             unwrappedkwds = self.space.unwrap(w_kwds)
         except UnwrapError, e:
-            raise UnwrapError('calling %s: %s' % (cpy_type, e))
+            raise UnwrapError('calling %s: %s' % (fn, e))
         try:
             result = apply(fn, unwrappedargs, unwrappedkwds)
         except:

Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/typeobject.py	(original)
+++ pypy/trunk/src/pypy/objspace/std/typeobject.py	Sun Nov 21 20:13:08 2004
@@ -174,7 +174,7 @@
             if mro_blockinglist(candidate, orderlists) is None:
                 break    # good candidate
         else:
-            mro_error(orderlists)  # no candidate found
+            return mro_error(orderlists)  # no candidate found
         assert candidate not in order
         order.append(candidate)
         for i in range(len(orderlists)-1, -1, -1):

Modified: pypy/trunk/src/pypy/tool/cache.py
==============================================================================
--- pypy/trunk/src/pypy/tool/cache.py	(original)
+++ pypy/trunk/src/pypy/tool/cache.py	Sun Nov 21 20:13:08 2004
@@ -9,7 +9,8 @@
 
     def __hash__(self):
         if not self.frozen: 
-            raise TypeError, "cannot get hash of un-frozen cache"
+            #raise TypeError, "cannot get hash of un-frozen cache"
+            self.freeze()
         return id(self)
 
     def clear(self):

Modified: pypy/trunk/src/pypy/translator/genc.h
==============================================================================
--- pypy/trunk/src/pypy/translator/genc.h	(original)
+++ pypy/trunk/src/pypy/translator/genc.h	Sun Nov 21 20:13:08 2004
@@ -22,11 +22,11 @@
 #endif
 
 #define op_bool(r,err,what) { \
-		int retval = what; \
-		if (retval < 0) { \
+		int _retval = what; \
+		if (_retval < 0) { \
 			FAIL(err) \
 		} \
-		r = PyBool_FromLong(retval); \
+		r = PyBool_FromLong(_retval); \
 	}
 
 #define op_richcmp(x,y,r,err,dir) \
@@ -42,6 +42,13 @@
 
 #define OP_IS_TRUE(x,r,err) op_bool(r,err,PyObject_IsTrue(x))
 
+#define OP_LEN(x,r,err) { \
+		int _retval = PyObject_Size(x); \
+		if (_retval < 0) { \
+			FAIL(err) \
+		} \
+		r = PyInt_FromLong(_retval); \
+	}
 #define OP_NEG(x,r,err)           if (!(r=PyNumber_Negative(x)))     FAIL(err)
 #define OP_POS(x,r,err)           if (!(r=PyNumber_Positive(x)))     FAIL(err)
 #define OP_INVERT(x,r,err)        if (!(r=PyNumber_Invert(x)))       FAIL(err)

Modified: pypy/trunk/src/pypy/translator/genc.py
==============================================================================
--- pypy/trunk/src/pypy/translator/genc.py	(original)
+++ pypy/trunk/src/pypy/translator/genc.py	Sun Nov 21 20:13:08 2004
@@ -39,8 +39,10 @@
 class GenC:
     MODNAMES = {}
 
-    def __init__(self, f, translator, modname=None):
+    def __init__(self, f, translator, modname=None, f2=None, f2name=None):
         self.f = f
+        self.f2 = f2
+        self.f2name = f2name
         self.translator = translator
         self.modname = (modname or
                         uniquemodulename(translator.functions[0].__name__))
@@ -69,7 +71,8 @@
             else:
                 stackentry = obj
             self.debugstack = (self.debugstack, stackentry)
-            if type(obj).__module__ != '__builtin__':
+            if (type(obj).__module__ != '__builtin__' and
+                not isinstance(obj, type)):   # skip user-defined metaclasses
                 # assume it's a user defined thingy
                 name = self.nameof_instance(obj)
             else:
@@ -151,10 +154,10 @@
         return name
 
     def nameof_str(self, value):
-        chrs = [c for c in value if ('a' <= c <='z' or
-                                     'A' <= c <='Z' or
-                                     '0' <= c <='9' or
-                                     '_' == c )]
+        chrs = [c for c in value[:32] if ('a' <= c <='z' or
+                                          'A' <= c <='Z' or
+                                          '0' <= c <='9' or
+                                          '_' == c )]
         name = self.uniquename('gstr_' + ''.join(chrs))
         if [c for c in value if not (' '<=c<='~')]:
             # non-printable string
@@ -179,7 +182,8 @@
         self.initcode.append('\tPyCFunction_GET_SELF(%s) = %s;' % (name, name))
         return name
 
-    def nameof_function(self, func):
+    def nameof_function(self, func, progress=['-\x08', '\\\x08',
+                                              '|\x08', '/\x08']):
         printable_name = '(%s:%d) %s' % (
             func.func_globals.get('__name__', '?'),
             func.func_code.co_firstlineno,
@@ -193,7 +197,9 @@
                 func.func_doc.lstrip().startswith('NOT_RPYTHON')):
                 print "skipped", printable_name
                 return self.skipped_function(func)
-            #print "nameof", printable_name
+            p = progress.pop(0)
+            sys.stderr.write(p)
+            progress.append(p)
         name = self.uniquename('gfunc_' + func.__name__)
         self.initcode.append('INITCHK(%s = PyCFunction_New('
                              '&ml_%s, NULL))' % (name, name))
@@ -313,7 +319,7 @@
             for key, value in content:
                 if key.startswith('__'):
                     if key in ['__module__', '__doc__', '__dict__',
-                               '__weakref__', '__repr__']:
+                               '__weakref__', '__repr__', '__metaclass__']:
                         continue
                     # XXX some __NAMES__ are important... nicer solution sought
                     #raise Exception, "unexpected name %r in class %s"%(key, cls)
@@ -350,6 +356,7 @@
         dict:   '&PyDict_Type',
         str:    '&PyString_Type',
         float:  '&PyFloat_Type',
+        type(Exception()): '&PyInstance_Type',
         type:   '&PyType_Type',
         complex:'&PyComplex_Type',
         unicode:'&PyUnicode_Type',
@@ -458,7 +465,7 @@
 
         # function implementations
         while self.pendingfunctions:
-            func = self.pendingfunctions.pop(0)
+            func = self.pendingfunctions.pop()
             self.gen_cfunction(func)
             # collect more of the latercode after each function
             while self.latercode:
@@ -471,10 +478,10 @@
 
         # footer
         print >> f, self.C_INIT_HEADER % info
+        if self.f2name is not None:
+            print >> f, '#include "%s"' % self.f2name
         for codeline in self.initcode:
             print >> f, '\t' + codeline
-        for name in self.globalobjects:
-            print >> f, '\t' + 'REGISTER_GLOBAL(%s)' % (name,)
         print >> f, self.C_INIT_FOOTER % info
 
     def gen_global_declarations(self):
@@ -486,6 +493,14 @@
                 print >> f, line
             print >> f
             del g[:]
+        g = self.globalobjects
+        for name in g:
+            self.initcode.append('REGISTER_GLOBAL(%s)' % (name,))
+        del g[:]
+        if self.f2 is not None:
+            for line in self.initcode:
+                print >> self.f2, line
+            del self.initcode[:]
 
     def gen_cfunction(self, func):
 ##         print 'gen_cfunction (%s:%d) %s' % (
@@ -584,6 +599,11 @@
             name, func.__name__, f_name)
         print >> f
 
+        if not self.translator.frozen:
+            # this is only to keep the RAM consumption under control
+            del self.translator.flowgraphs[func]
+            Variable.instances.clear()
+
     def cfunction_body(self, func):
         graph = self.translator.getflowgraph(func)
         remove_direct_loops(graph)
@@ -653,7 +673,7 @@
                     # exceptional return block
                     exc_cls   = expr(block.inputargs[0])
                     exc_value = expr(block.inputargs[1])
-                    yield 'PyErr_SetObject(%s, %s);' % (exc_cls, retval)
+                    yield 'PyErr_Restore(%s, %s, NULL);' % (exc_cls, exc_value)
                     yield 'FUNCTION_RETURN(NULL)'
                 else:
                     # regular return block

Modified: pypy/trunk/src/pypy/translator/test/snippet.py
==============================================================================
--- pypy/trunk/src/pypy/translator/test/snippet.py	(original)
+++ pypy/trunk/src/pypy/translator/test/snippet.py	Sun Nov 21 20:13:08 2004
@@ -234,6 +234,19 @@
         x = 8
     return x
 
+def finally2(o, k):
+    try:
+        o[k] += 1
+    finally:
+        o[-1] = 'done'
+
+def bare_raise(o, ignore):
+    try:
+        return o[5]
+    except:
+        if not ignore:
+            raise
+
 def factorial(n=int):
     if n <= 1:
         return 1

Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py
==============================================================================
--- pypy/trunk/src/pypy/translator/test/test_ctrans.py	(original)
+++ pypy/trunk/src/pypy/translator/test/test_ctrans.py	Sun Nov 21 20:13:08 2004
@@ -140,6 +140,29 @@
         self.assertEquals(call_default_and_star_args(42),
                           (111+42+3+0, -1000-2000-3000+2))
 
+    def test_finallys(self):
+        finallys = self.build_cfunc(snippet.finallys)
+        self.assertEquals(finallys(['hello']), 8)
+        self.assertEquals(finallys('X'), 8)
+        self.assertEquals(finallys([]), 6)
+        self.assertEquals(finallys('XY'), 6)
+
+    def test_finally2(self):
+        finally2 = self.build_cfunc(snippet.finally2)
+        lst = range(10)
+        finally2(lst, 5)
+        self.assertEquals(lst, [0,1,2,3,4, 6, 6,7,8, 'done'])
+        dic = {}
+        self.assertRaises(KeyError, finally2, dic, "won't find this key")
+        self.assertEquals(dic, {-1: 'done'})
+
+    def test_bare_raise(self):
+        bare_raise = self.build_cfunc(snippet.bare_raise)
+        self.assertEquals(bare_raise(range(0, 100, 10), False), 50)
+        self.assertEquals(bare_raise(range(0, 100, 10), True), 50)
+        self.assertRaises(IndexError, bare_raise, range(0, 30, 10), False)
+        self.assertEquals(bare_raise(range(0, 30, 10), True), None)
+
 class TypedTestCase(testit.IntTestCase):
 
     def getcompiled(self, func):

Modified: pypy/trunk/src/pypy/translator/translator.py
==============================================================================
--- pypy/trunk/src/pypy/translator/translator.py	(original)
+++ pypy/trunk/src/pypy/translator/translator.py	Sun Nov 21 20:13:08 2004
@@ -212,9 +212,7 @@
         return g.globaldeclarations()
 
     def compile(self):
-        """Returns compiled function.
-
-        Currently function is only compiled using Pyrex.
+        """Returns compiled function, compiled using Pyrex.
         """
         from pypy.tool.udir import udir
         name = self.entrypoint.func_name
@@ -229,7 +227,9 @@
         name = uniquemodulename(self.entrypoint.func_name)
         cfile = udir.join('%s.c' % name)
         f = cfile.open('w')
-        GenC(f, self, name)
+        f2 = udir.join('%s-init.h' % name).open('w')
+        GenC(f, self, name, f2=f2, f2name='%s-init.h' % name)
+        f2.close()
         f.close()
         if not really_compile:
             return cfile



More information about the Pypy-commit mailing list