[pypy-commit] pypy default: merge translation-cleanup
rlamy
noreply at buildbot.pypy.org
Sat Sep 29 18:34:56 CEST 2012
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch:
Changeset: r57663:c80ffd88abd2
Date: 2012-09-29 17:34 +0100
http://bitbucket.org/pypy/pypy/changeset/c80ffd88abd2/
Log: merge translation-cleanup
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -208,11 +208,11 @@
def int_w(self, space):
raise OperationError(space.w_TypeError,
typed_unwrap_error_msg(space, "integer", self))
-
+
def uint_w(self, space):
raise OperationError(space.w_TypeError,
typed_unwrap_error_msg(space, "integer", self))
-
+
def bigint_w(self, space):
raise OperationError(space.w_TypeError,
typed_unwrap_error_msg(space, "integer", self))
@@ -292,8 +292,6 @@
"""Base class for the interpreter-level implementations of object spaces.
http://pypy.readthedocs.org/en/latest/objspace.html"""
- full_exceptions = True # full support for exceptions (normalization & more)
-
def __init__(self, config=None):
"NOT_RPYTHON: Basic initialization of objects."
self.fromcache = InternalSpaceCache(self).getorbuild
@@ -1124,13 +1122,9 @@
def exception_is_valid_obj_as_class_w(self, w_obj):
if not self.isinstance_w(w_obj, self.w_type):
return False
- if not self.full_exceptions:
- return True
return self.is_true(self.issubtype(w_obj, self.w_BaseException))
def exception_is_valid_class_w(self, w_cls):
- if not self.full_exceptions:
- return True
return self.is_true(self.issubtype(w_cls, self.w_BaseException))
def exception_getclass(self, w_obj):
@@ -1381,7 +1375,7 @@
if not self.is_true(self.isinstance(w_obj, self.w_str)):
raise OperationError(self.w_TypeError,
self.wrap('argument must be a string'))
- return self.str_w(w_obj)
+ return self.str_w(w_obj)
def unicode_w(self, w_obj):
return w_obj.unicode_w(self)
@@ -1702,7 +1696,7 @@
'ValueError',
'ZeroDivisionError',
]
-
+
if sys.platform.startswith("win"):
ObjSpace.ExceptionTable += ['WindowsError']
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -45,11 +45,6 @@
def async(self, space):
"Check if this is an exception that should better not be caught."
- if not space.full_exceptions:
- # flow objspace does not support such exceptions and more
- # importantly, raises KeyboardInterrupt if you try to access
- # space.w_KeyboardInterrupt
- return False
return (self.match(space, space.w_SystemExit) or
self.match(space, space.w_KeyboardInterrupt))
@@ -166,9 +161,7 @@
# Or 'Class' can also be an old-style class and 'inst' an old-style
# instance of it.
#
- # Note that 'space.full_exceptions' is set to False by the flow
- # object space; in this case we must assume that we are in a
- # non-advanced case, and ignore the advanced cases. Old-style
+ # The flow object space only deals with non-advanced case. Old-style
# classes and instances *are* advanced.
#
# input (w_type, w_value)... becomes... advanced case?
@@ -183,9 +176,8 @@
#
w_type = self.w_type
w_value = self.get_w_value(space)
- if space.full_exceptions:
- while space.is_true(space.isinstance(w_type, space.w_tuple)):
- w_type = space.getitem(w_type, space.wrap(0))
+ while space.is_true(space.isinstance(w_type, space.w_tuple)):
+ w_type = space.getitem(w_type, space.wrap(0))
if space.exception_is_valid_obj_as_class_w(w_type):
# this is for all cases of the form (Class, something)
@@ -199,8 +191,7 @@
# raise Type, Instance: let etype be the exact type of value
w_type = w_valuetype
else:
- if space.full_exceptions and space.is_true(
- space.isinstance(w_value, space.w_tuple)):
+ if space.is_true(space.isinstance(w_value, space.w_tuple)):
# raise Type, tuple: assume the tuple contains the
# constructor args
w_value = space.call(w_type, w_value)
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -944,14 +944,6 @@
def appcaller(space, *args_w):
if not isinstance(space, ObjSpace):
raise TypeError("first argument must be a space instance.")
- # redirect if the space handles this specially
- # XXX can this be factored a bit less flow space dependently?
- if hasattr(space, 'specialcases'):
- sc = space.specialcases
- if ApplevelClass in sc:
- ret_w = sc[ApplevelClass](space, self, name, args_w)
- if ret_w is not None: # it was RPython
- return ret_w
# the last argument can be an Arguments
w_func = self.wget(space, name)
if not args_w:
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -557,7 +557,7 @@
w_type = self.popvalue()
operror = OperationError(w_type, w_value)
operror.normalize_exception(space)
- if not space.full_exceptions or space.is_w(w_traceback, space.w_None):
+ if space.is_w(w_traceback, space.w_None):
# common case
raise operror
else:
@@ -944,21 +944,9 @@
def WITH_CLEANUP(self, oparg, next_instr):
# see comment in END_FINALLY for stack state
- # This opcode changed a lot between CPython versions
- if (self.pycode.magic >= 0xa0df2ef
- # Implementation since 2.7a0: 62191 (introduce SETUP_WITH)
- or self.pycode.magic >= 0xa0df2d1):
- # implementation since 2.6a1: 62161 (WITH_CLEANUP optimization)
- w_unroller = self.popvalue()
- w_exitfunc = self.popvalue()
- self.pushvalue(w_unroller)
- elif self.pycode.magic >= 0xa0df28c:
- # Implementation since 2.5a0: 62092 (changed WITH_CLEANUP opcode)
- w_exitfunc = self.popvalue()
- w_unroller = self.peekvalue(0)
- else:
- raise NotImplementedError("WITH_CLEANUP for CPython <= 2.4")
-
+ w_unroller = self.popvalue()
+ w_exitfunc = self.popvalue()
+ self.pushvalue(w_unroller)
unroller = self.space.interpclass_w(w_unroller)
is_app_exc = (unroller is not None and
isinstance(unroller, SApplicationException))
@@ -1192,10 +1180,6 @@
def nomoreblocks(self):
raise BytecodeCorruption("misplaced bytecode - should not return")
- # NB. for the flow object space, the state_(un)pack_variables methods
- # give a way to "pickle" and "unpickle" the SuspendedUnroller by
- # enumerating the Variables it contains.
-
class SReturnValue(SuspendedUnroller):
"""Signals a 'return' statement.
Argument is the wrapped object to return."""
@@ -1206,12 +1190,6 @@
def nomoreblocks(self):
return self.w_returnvalue
- def state_unpack_variables(self, space):
- return [self.w_returnvalue]
- def state_pack_variables(space, w_returnvalue):
- return SReturnValue(w_returnvalue)
- state_pack_variables = staticmethod(state_pack_variables)
-
class SApplicationException(SuspendedUnroller):
"""Signals an application-level exception
(i.e. an OperationException)."""
@@ -1226,13 +1204,6 @@
"""Signals a 'break' statement."""
_immutable_ = True
kind = 0x04
-
- def state_unpack_variables(self, space):
- return []
- def state_pack_variables(space):
- return SBreakLoop.singleton
- state_pack_variables = staticmethod(state_pack_variables)
-
SBreakLoop.singleton = SBreakLoop()
class SContinueLoop(SuspendedUnroller):
@@ -1243,12 +1214,6 @@
def __init__(self, jump_to):
self.jump_to = jump_to
- def state_unpack_variables(self, space):
- return [space.wrap(self.jump_to)]
- def state_pack_variables(space, w_jump_to):
- return SContinueLoop(space.int_w(w_jump_to))
- state_pack_variables = staticmethod(state_pack_variables)
-
class FrameBlock(object):
"""Abstract base class for frame blocks from the blockstack,
@@ -1323,8 +1288,7 @@
self.cleanupstack(frame)
assert isinstance(unroller, SApplicationException)
operationerr = unroller.operr
- if frame.space.full_exceptions:
- operationerr.normalize_exception(frame.space)
+ operationerr.normalize_exception(frame.space)
# the stack setup is slightly different than in CPython:
# instead of the traceback, we store the unroller object,
# wrapped.
@@ -1356,8 +1320,7 @@
_immutable_ = True
def handle(self, frame, unroller):
- if (frame.space.full_exceptions and
- isinstance(unroller, SApplicationException)):
+ if isinstance(unroller, SApplicationException):
unroller.operr.normalize_exception(frame.space)
return FinallyBlock.handle(self, frame, unroller)
diff --git a/pypy/objspace/flow/bytecode.py b/pypy/objspace/flow/bytecode.py
--- a/pypy/objspace/flow/bytecode.py
+++ b/pypy/objspace/flow/bytecode.py
@@ -1,7 +1,8 @@
"""
Bytecode handling classes and functions for use by the flow space.
"""
-from pypy.interpreter.pycode import PyCode, BytecodeCorruption
+from pypy.interpreter.pycode import (PyCode, BytecodeCorruption, cpython_magic,
+ cpython_code_signature)
from pypy.tool.stdlib_opcode import (host_bytecode_spec, EXTENDED_ARG,
HAVE_ARGUMENT)
from pypy.interpreter.astcompiler.consts import CO_GENERATOR
@@ -12,6 +13,57 @@
"""
opnames = host_bytecode_spec.method_names
+ def __init__(self, space, argcount, nlocals, stacksize, flags,
+ code, consts, names, varnames, filename,
+ name, firstlineno, lnotab, freevars, cellvars,
+ hidden_applevel=False, magic=cpython_magic):
+ """Initialize a new code object"""
+ self.space = space
+ self.co_name = name
+ assert nlocals >= 0
+ self.co_argcount = argcount
+ self.co_nlocals = nlocals
+ self.co_stacksize = stacksize
+ self.co_flags = flags
+ self.co_code = code
+ self.co_consts_w = consts
+ self.co_names_w = [space.wrap(aname) for aname in names]
+ self.co_varnames = varnames
+ self.co_freevars = freevars
+ self.co_cellvars = cellvars
+ self.co_filename = filename
+ self.co_name = name
+ self.co_firstlineno = firstlineno
+ self.co_lnotab = lnotab
+ self.hidden_applevel = hidden_applevel
+ self.magic = magic
+ self._signature = cpython_code_signature(self)
+ self._initialize()
+
+ def _initialize(self):
+ # Precompute what arguments need to be copied into cellvars
+ self._args_as_cellvars = []
+
+ if self.co_cellvars:
+ argcount = self.co_argcount
+ assert argcount >= 0 # annotator hint
+ if self.co_flags & CO_VARARGS:
+ argcount += 1
+ if self.co_flags & CO_VARKEYWORDS:
+ argcount += 1
+ # Cell vars could shadow already-set arguments.
+ # See comment in PyCode._initialize()
+ argvars = self.co_varnames
+ cellvars = self.co_cellvars
+ for i in range(len(cellvars)):
+ cellname = cellvars[i]
+ for j in range(argcount):
+ if cellname == argvars[j]:
+ # argument j has the same name as the cell var i
+ while len(self._args_as_cellvars) <= i:
+ self._args_as_cellvars.append(-1) # pad
+ self._args_as_cellvars[i] = j
+
def read(self, pos):
"""
Decode the instruction starting at position ``next_instr``.
diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py
--- a/pypy/objspace/flow/flowcontext.py
+++ b/pypy/objspace/flow/flowcontext.py
@@ -1,19 +1,17 @@
import collections
-import sys
from pypy.tool.error import source_lines
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.pytraceback import PyTraceback
from pypy.interpreter import pyframe
from pypy.interpreter.nestedscope import Cell
-from pypy.interpreter.pycode import CO_OPTIMIZED, CO_NEWLOCALS
+from pypy.interpreter.pycode import CO_NEWLOCALS
from pypy.interpreter.argument import ArgumentsForTranslation
-from pypy.interpreter.pyopcode import (Return, Yield, SuspendedUnroller,
- SReturnValue, SApplicationException, BytecodeCorruption,
- RaiseWithExplicitTraceback)
-from pypy.objspace.flow.model import *
+from pypy.interpreter.pyopcode import Return, BytecodeCorruption
+from pypy.objspace.flow.model import (Constant, Variable, Block, Link,
+ UnwrapException, SpaceOperation, FunctionGraph, c_last_exception)
from pypy.objspace.flow.framestate import (FrameState, recursively_unflatten,
recursively_flatten)
from pypy.objspace.flow.bytecode import HostCode
+from pypy.objspace.flow.specialcase import (rpython_print_item,
+ rpython_print_newline)
class FlowingError(Exception):
""" Signals invalid RPython in the function being analysed"""
@@ -27,16 +25,14 @@
msg += source_lines(self.frame.graph, None, offset=self.frame.last_instr)
return "\n".join(msg)
-
class StopFlowing(Exception):
pass
-class FSException(OperationError):
- def __init__(self, w_type, w_value, tb=None):
+class FSException(Exception):
+ def __init__(self, w_type, w_value):
assert w_type is not None
self.w_type = w_type
self.w_value = w_value
- self._application_traceback = tb
def get_w_value(self, _):
return self.w_value
@@ -44,45 +40,6 @@
def __str__(self):
return '[%s: %s]' % (self.w_type, self.w_value)
- def normalize_exception(self, space):
- """Normalize the OperationError. In other words, fix w_type and/or
- w_value to make sure that the __class__ of w_value is exactly w_type.
- """
- w_type = self.w_type
- w_value = self.w_value
- if space.exception_is_valid_obj_as_class_w(w_type):
- # this is for all cases of the form (Class, something)
- if space.is_w(w_value, space.w_None):
- # raise Type: we assume we have to instantiate Type
- w_value = space.call_function(w_type)
- w_type = self._exception_getclass(space, w_value)
- else:
- w_valuetype = space.exception_getclass(w_value)
- if space.exception_issubclass_w(w_valuetype, w_type):
- # raise Type, Instance: let etype be the exact type of value
- w_type = w_valuetype
- else:
- # raise Type, X: assume X is the constructor argument
- w_value = space.call_function(w_type, w_value)
- w_type = self._exception_getclass(space, w_value)
-
- else:
- # the only case left here is (inst, None), from a 'raise inst'.
- w_inst = w_type
- w_instclass = self._exception_getclass(space, w_inst)
- if not space.is_w(w_value, space.w_None):
- raise FSException(space.w_TypeError,
- space.wrap("instance exception may not "
- "have a separate value"))
- w_value = w_inst
- w_type = w_instclass
-
- self.w_type = w_type
- self.w_value = w_value
-
-class OperationThatShouldNotBePropagatedError(FSException):
- pass
-
class ImplicitOperationError(FSException):
pass
@@ -262,6 +219,20 @@
# ____________________________________________________________
+compare_method = [
+ "cmp_lt", # "<"
+ "cmp_le", # "<="
+ "cmp_eq", # "=="
+ "cmp_ne", # "!="
+ "cmp_gt", # ">"
+ "cmp_ge", # ">="
+ "cmp_in",
+ "cmp_not_in",
+ "cmp_is",
+ "cmp_is_not",
+ "cmp_exc_match",
+ ]
+
class FlowSpaceFrame(pyframe.CPythonFrame):
def __init__(self, space, func, constargs=None):
@@ -497,38 +468,68 @@
res = getattr(self, methodname)(oparg, next_instr)
if res is not None:
next_instr = res
- except OperationThatShouldNotBePropagatedError, e:
- raise Exception(
- 'found an operation that always raises %s: %s' % (
- self.space.unwrap(e.w_type).__name__,
- self.space.unwrap(e.w_value)))
except FSException, operr:
- self.attach_traceback(operr)
next_instr = self.handle_operation_error(operr)
- except RaiseWithExplicitTraceback, e:
- next_instr = self.handle_operation_error(e.operr)
return next_instr
- def attach_traceback(self, operr):
- if self.pycode.hidden_applevel:
- return
- tb = operr.get_traceback()
- tb = PyTraceback(self.space, self, self.last_instr, tb)
- operr.set_traceback(tb)
-
def handle_operation_error(self, operr):
- block = self.unrollstack(SFlowException.kind)
+ block = self.unrollstack(SApplicationException.kind)
if block is None:
- # no handler found for the exception
- # try to preserve the CPython-level traceback
- import sys
- tb = sys.exc_info()[2]
- raise operr, None, tb
+ raise operr
else:
- unroller = SFlowException(operr)
+ unroller = SApplicationException(operr)
next_instr = block.handle(self, unroller)
return next_instr
+ def BAD_OPCODE(self, _, next_instr):
+ raise FlowingError(self, "This operation is not RPython")
+
+ def BREAK_LOOP(self, oparg, next_instr):
+ return self.unrollstack_and_jump(SBreakLoop.singleton)
+
+ def CONTINUE_LOOP(self, startofloop, next_instr):
+ unroller = SContinueLoop(startofloop)
+ return self.unrollstack_and_jump(unroller)
+
+ def cmp_lt(self, w_1, w_2):
+ return self.space.lt(w_1, w_2)
+
+ def cmp_le(self, w_1, w_2):
+ return self.space.le(w_1, w_2)
+
+ def cmp_eq(self, w_1, w_2):
+ return self.space.eq(w_1, w_2)
+
+ def cmp_ne(self, w_1, w_2):
+ return self.space.ne(w_1, w_2)
+
+ def cmp_gt(self, w_1, w_2):
+ return self.space.gt(w_1, w_2)
+
+ def cmp_ge(self, w_1, w_2):
+ return self.space.ge(w_1, w_2)
+
+ def cmp_in(self, w_1, w_2):
+ return self.space.contains(w_2, w_1)
+
+ def cmp_not_in(self, w_1, w_2):
+ return self.space.not_(self.space.contains(w_2, w_1))
+
+ def cmp_is(self, w_1, w_2):
+ return self.space.is_(w_1, w_2)
+
+ def cmp_is_not(self, w_1, w_2):
+ return self.space.not_(self.space.is_(w_1, w_2))
+
+ def cmp_exc_match(self, w_1, w_2):
+ return self.space.newbool(self.space.exception_match(w_1, w_2))
+
+ def COMPARE_OP(self, testnum, next_instr):
+ w_2 = self.popvalue()
+ w_1 = self.popvalue()
+ w_result = getattr(self, compare_method[testnum])(w_1, w_2)
+ self.pushvalue(w_result)
+
def RAISE_VARARGS(self, nbargs, next_instr):
space = self.space
if nbargs == 0:
@@ -538,7 +539,7 @@
# re-raising an implicit operation makes it an explicit one
operr = FSException(operr.w_type, operr.w_value)
self.last_exception = operr
- raise RaiseWithExplicitTraceback(operr)
+ raise operr
else:
raise FSException(space.w_TypeError,
space.wrap("raise: no active exception to re-raise"))
@@ -550,8 +551,7 @@
w_value = self.popvalue()
if 1:
w_type = self.popvalue()
- operror = FSException(w_type, w_value)
- operror.normalize_exception(space)
+ operror = space.exc_from_raise(w_type, w_value)
raise operror
def IMPORT_NAME(self, nameindex, next_instr):
@@ -580,17 +580,45 @@
return next_instr # now inside a 'finally' block
def END_FINALLY(self, oparg, next_instr):
- unroller = self.end_finally()
- if isinstance(unroller, SuspendedUnroller):
- # go on unrolling the stack
- block = self.unrollstack(unroller.kind)
- if block is None:
- w_result = unroller.nomoreblocks()
- self.pushvalue(w_result)
- raise Return
- else:
- next_instr = block.handle(self, unroller)
- return next_instr
+ # unlike CPython, there are two statically distinct cases: the
+ # END_FINALLY might be closing an 'except' block or a 'finally'
+ # block. In the first case, the stack contains three items:
+ # [exception type we are now handling]
+ # [exception value we are now handling]
+ # [wrapped SApplicationException]
+ # In the case of a finally: block, the stack contains only one
+ # item (unlike CPython which can have 1, 2 or 3 items):
+ # [wrapped subclass of SuspendedUnroller]
+ w_top = self.popvalue()
+ if w_top == self.space.w_None:
+ # finally: block with no unroller active
+ return
+ try:
+ unroller = self.space.unwrap(w_top)
+ except UnwrapException:
+ pass
+ else:
+ if isinstance(unroller, SuspendedUnroller):
+ # case of a finally: block
+ return self.unroll_finally(unroller)
+ # case of an except: block. We popped the exception type
+ self.popvalue() # Now we pop the exception value
+ unroller = self.space.unwrap(self.popvalue())
+ return self.unroll_finally(unroller)
+
+ def unroll_finally(self, unroller):
+ # go on unrolling the stack
+ block = self.unrollstack(unroller.kind)
+ if block is None:
+ w_result = unroller.nomoreblocks()
+ self.pushvalue(w_result)
+ raise Return
+ else:
+ return block.handle(self, unroller)
+
+ def POP_BLOCK(self, oparg, next_instr):
+ block = self.pop_block()
+ block.cleanupstack(self) # the block knows how to clean up the value stack
def JUMP_ABSOLUTE(self, jumpto, next_instr):
return jumpto
@@ -603,11 +631,48 @@
# isn't popped straightaway.
self.pushvalue(None)
+ PRINT_EXPR = BAD_OPCODE
+ PRINT_ITEM_TO = BAD_OPCODE
+ PRINT_NEWLINE_TO = BAD_OPCODE
+
+ def PRINT_ITEM(self, oparg, next_instr):
+ w_item = self.popvalue()
+ w_s = self.space.do_operation('str', w_item)
+ self.space.appcall(rpython_print_item, w_s)
+
+ def PRINT_NEWLINE(self, oparg, next_instr):
+ self.space.appcall(rpython_print_newline)
+
+ def FOR_ITER(self, jumpby, next_instr):
+ w_iterator = self.peekvalue()
+ try:
+ w_nextitem = self.space.next(w_iterator)
+ except FSException, e:
+ if not self.space.exception_match(e.w_type, self.space.w_StopIteration):
+ raise
+ # iterator exhausted
+ self.popvalue()
+ next_instr += jumpby
+ else:
+ self.pushvalue(w_nextitem)
+ return next_instr
+
+ def SETUP_LOOP(self, offsettoend, next_instr):
+ block = LoopBlock(self, next_instr + offsettoend, self.lastblock)
+ self.lastblock = block
+
+ def SETUP_EXCEPT(self, offsettoend, next_instr):
+ block = ExceptBlock(self, next_instr + offsettoend, self.lastblock)
+ self.lastblock = block
+
+ def SETUP_FINALLY(self, offsettoend, next_instr):
+ block = FinallyBlock(self, next_instr + offsettoend, self.lastblock)
+ self.lastblock = block
+
def SETUP_WITH(self, offsettoend, next_instr):
# A simpler version than the 'real' 2.7 one:
# directly call manager.__enter__(), don't use special lookup functions
# which don't make sense on the RPython type system.
- from pypy.interpreter.pyopcode import WithBlock
w_manager = self.peekvalue()
w_exit = self.space.getattr(w_manager, self.space.wrap("__exit__"))
self.settopvalue(w_exit)
@@ -616,10 +681,47 @@
self.lastblock = block
self.pushvalue(w_result)
+ def WITH_CLEANUP(self, oparg, next_instr):
+ # Note: RPython context managers receive None in lieu of tracebacks
+ # and cannot suppress the exception.
+ # This opcode changed a lot between CPython versions
+ if (self.pycode.magic >= 0xa0df2ef
+ # Implementation since 2.7a0: 62191 (introduce SETUP_WITH)
+ or self.pycode.magic >= 0xa0df2d1):
+ # implementation since 2.6a1: 62161 (WITH_CLEANUP optimization)
+ w_unroller = self.popvalue()
+ w_exitfunc = self.popvalue()
+ self.pushvalue(w_unroller)
+ elif self.pycode.magic >= 0xa0df28c:
+ # Implementation since 2.5a0: 62092 (changed WITH_CLEANUP opcode)
+ w_exitfunc = self.popvalue()
+ w_unroller = self.peekvalue(0)
+ else:
+ raise NotImplementedError("WITH_CLEANUP for CPython <= 2.4")
+
+ unroller = self.space.unwrap(w_unroller)
+ w_None = self.space.w_None
+ if isinstance(unroller, SApplicationException):
+ operr = unroller.operr
+ # The annotator won't allow to merge exception types with None.
+ # Replace it with the exception value...
+ self.space.call_function(w_exitfunc,
+ operr.w_value, operr.w_value, w_None)
+ else:
+ self.space.call_function(w_exitfunc, w_None, w_None, w_None)
+
def LOAD_GLOBAL(self, nameindex, next_instr):
w_result = self.space.find_global(self.w_globals, self.getname_u(nameindex))
self.pushvalue(w_result)
+ def LOAD_ATTR(self, nameindex, next_instr):
+ "obj.attributename"
+ w_obj = self.popvalue()
+ w_attributename = self.getname_w(nameindex)
+ w_value = self.space.getattr(w_obj, w_attributename)
+ self.pushvalue(w_value)
+ LOOKUP_METHOD = LOAD_ATTR
+
def BUILD_LIST_FROM_ARG(self, _, next_instr):
# This opcode was added with pypy-1.8. Here is a simpler
# version, enough for annotation.
@@ -647,23 +749,173 @@
def argument_factory(self, *args):
return ArgumentsForTranslation(self.space, *args)
- def call_contextmanager_exit_function(self, w_func, w_typ, w_val, w_tb):
- if w_typ is not self.space.w_None:
- # The annotator won't allow to merge exception types with None.
- # Replace it with the exception value...
- w_typ = w_val
- self.space.call_function(w_func, w_typ, w_val, w_tb)
- # Return None so that the flow space statically knows that we didn't
- # swallow the exception
- return self.space.w_None
-
### Frame blocks ###
-class SFlowException(SApplicationException):
- """Flowspace override for SApplicationException"""
+class SuspendedUnroller(object):
+ """Abstract base class for interpreter-level objects that
+ instruct the interpreter to change the control flow and the
+ block stack.
+
+ The concrete subclasses correspond to the various values WHY_XXX
+ values of the why_code enumeration in ceval.c:
+
+ WHY_NOT, OK, not this one :-)
+ WHY_EXCEPTION, SApplicationException
+ WHY_RERAISE, implemented differently, see Reraise
+ WHY_RETURN, SReturnValue
+ WHY_BREAK, SBreakLoop
+ WHY_CONTINUE, SContinueLoop
+ WHY_YIELD not needed
+ """
+ def nomoreblocks(self):
+ raise BytecodeCorruption("misplaced bytecode - should not return")
+
+ # NB. for the flow object space, the state_(un)pack_variables methods
+ # give a way to "pickle" and "unpickle" the SuspendedUnroller by
+ # enumerating the Variables it contains.
+
+class SReturnValue(SuspendedUnroller):
+ """Signals a 'return' statement.
+ Argument is the wrapped object to return."""
+ kind = 0x01
+ def __init__(self, w_returnvalue):
+ self.w_returnvalue = w_returnvalue
+
+ def nomoreblocks(self):
+ return self.w_returnvalue
+
+ def state_unpack_variables(self, space):
+ return [self.w_returnvalue]
+
+ @staticmethod
+ def state_pack_variables(space, w_returnvalue):
+ return SReturnValue(w_returnvalue)
+
+class SApplicationException(SuspendedUnroller):
+ """Signals an application-level exception
+ (i.e. an OperationException)."""
+ kind = 0x02
+ def __init__(self, operr):
+ self.operr = operr
+
+ def nomoreblocks(self):
+ raise self.operr
+
def state_unpack_variables(self, space):
return [self.operr.w_type, self.operr.w_value]
@staticmethod
def state_pack_variables(space, w_type, w_value):
- return SFlowException(FSException(w_type, w_value))
+ return SApplicationException(FSException(w_type, w_value))
+
+class SBreakLoop(SuspendedUnroller):
+ """Signals a 'break' statement."""
+ kind = 0x04
+
+ def state_unpack_variables(self, space):
+ return []
+
+ @staticmethod
+ def state_pack_variables(space):
+ return SBreakLoop.singleton
+
+SBreakLoop.singleton = SBreakLoop()
+
+class SContinueLoop(SuspendedUnroller):
+ """Signals a 'continue' statement.
+ Argument is the bytecode position of the beginning of the loop."""
+ kind = 0x08
+ def __init__(self, jump_to):
+ self.jump_to = jump_to
+
+ def state_unpack_variables(self, space):
+ return [space.wrap(self.jump_to)]
+
+ @staticmethod
+ def state_pack_variables(space, w_jump_to):
+ return SContinueLoop(space.int_w(w_jump_to))
+
+
+class FrameBlock(object):
+ """Abstract base class for frame blocks from the blockstack,
+ used by the SETUP_XXX and POP_BLOCK opcodes."""
+
+ def __init__(self, frame, handlerposition, previous):
+ self.handlerposition = handlerposition
+ self.valuestackdepth = frame.valuestackdepth
+ self.previous = previous # this makes a linked list of blocks
+
+ def __eq__(self, other):
+ return (self.__class__ is other.__class__ and
+ self.handlerposition == other.handlerposition and
+ self.valuestackdepth == other.valuestackdepth)
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __hash__(self):
+ return hash((self.handlerposition, self.valuestackdepth))
+
+ def cleanupstack(self, frame):
+ frame.dropvaluesuntil(self.valuestackdepth)
+
+ def handle(self, frame, unroller):
+ raise NotImplementedError
+
+class LoopBlock(FrameBlock):
+ """A loop block. Stores the end-of-loop pointer in case of 'break'."""
+
+ _opname = 'SETUP_LOOP'
+ handling_mask = SBreakLoop.kind | SContinueLoop.kind
+
+ def handle(self, frame, unroller):
+ if isinstance(unroller, SContinueLoop):
+ # re-push the loop block without cleaning up the value stack,
+ # and jump to the beginning of the loop, stored in the
+ # exception's argument
+ frame.append_block(self)
+ return unroller.jump_to
+ else:
+ # jump to the end of the loop
+ self.cleanupstack(frame)
+ return self.handlerposition
+
+class ExceptBlock(FrameBlock):
+ """An try:except: block. Stores the position of the exception handler."""
+
+ _opname = 'SETUP_EXCEPT'
+ handling_mask = SApplicationException.kind
+
+ def handle(self, frame, unroller):
+ # push the exception to the value stack for inspection by the
+ # exception handler (the code after the except:)
+ self.cleanupstack(frame)
+ assert isinstance(unroller, SApplicationException)
+ operationerr = unroller.operr
+ # the stack setup is slightly different than in CPython:
+ # instead of the traceback, we store the unroller object,
+ # wrapped.
+ frame.pushvalue(frame.space.wrap(unroller))
+ frame.pushvalue(operationerr.get_w_value(frame.space))
+ frame.pushvalue(operationerr.w_type)
+ frame.last_exception = operationerr
+ return self.handlerposition # jump to the handler
+
+class FinallyBlock(FrameBlock):
+ """A try:finally: block. Stores the position of the exception handler."""
+
+ _opname = 'SETUP_FINALLY'
+ handling_mask = -1 # handles every kind of SuspendedUnroller
+
+ def handle(self, frame, unroller):
+ # any abnormal reason for unrolling a finally: triggers the end of
+ # the block unrolling and the entering the finally: handler.
+ self.cleanupstack(frame)
+ frame.pushvalue(frame.space.wrap(unroller))
+ return self.handlerposition # jump to the handler
+
+
+class WithBlock(FinallyBlock):
+
+ def handle(self, frame, unroller):
+ return FinallyBlock.handle(self, frame, unroller)
diff --git a/pypy/objspace/flow/framestate.py b/pypy/objspace/flow/framestate.py
--- a/pypy/objspace/flow/framestate.py
+++ b/pypy/objspace/flow/framestate.py
@@ -1,4 +1,3 @@
-from pypy.interpreter.pyopcode import SuspendedUnroller
from pypy.rlib.unroll import SpecTag
from pypy.objspace.flow.model import *
@@ -106,6 +105,7 @@
UNPICKLE_TAGS = {}
def recursively_flatten(space, lst):
+ from pypy.objspace.flow.flowcontext import SuspendedUnroller
i = 0
while i < len(lst):
item = lst[i]
diff --git a/pypy/objspace/flow/objspace.py b/pypy/objspace/flow/objspace.py
--- a/pypy/objspace/flow/objspace.py
+++ b/pypy/objspace/flow/objspace.py
@@ -1,14 +1,14 @@
# ______________________________________________________________________
import __builtin__
import sys
-import operator
import types
-from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
-from pypy.interpreter import pyframe, argument
-from pypy.objspace.flow.model import *
+from pypy.interpreter.baseobjspace import ObjSpace
+from pypy.interpreter.argument import ArgumentsForTranslation
+from pypy.objspace.flow.model import (Constant, Variable, WrapException,
+ UnwrapException, checkgraph, SpaceOperation)
from pypy.objspace.flow import operation
from pypy.objspace.flow.flowcontext import (FlowSpaceFrame, fixeggblocks,
- OperationThatShouldNotBePropagatedError, FSException, FlowingError)
+ FSException, FlowingError)
from pypy.objspace.flow.specialcase import SPECIAL_CASES
from pypy.rlib.unroll import unrolling_iterable, _unroller
from pypy.rlib import rstackovf, rarithmetic
@@ -38,47 +38,32 @@
}
# ______________________________________________________________________
-class FlowObjSpace(ObjSpace):
+class FlowObjSpace(object):
"""NOT_RPYTHON.
The flow objspace space is used to produce a flow graph by recording
the space operations that the interpreter generates when it interprets
(the bytecode of) some function.
"""
+ w_None = Constant(None)
+ builtin = Constant(__builtin__)
+ sys = Constant(sys)
+ w_False = Constant(False)
+ w_True = Constant(True)
+ w_type = Constant(type)
+ w_tuple = Constant(tuple)
+ for exc in [KeyError, ValueError, IndexError, StopIteration,
+ AssertionError, TypeError, AttributeError, ImportError]:
+ clsname = exc.__name__
+ locals()['w_' + clsname] = Constant(exc)
- full_exceptions = False
- FrameClass = FlowSpaceFrame
+ # the following exceptions should not show up
+ # during flow graph construction
+ w_NameError = None
+ w_UnboundLocalError = None
- def initialize(self):
- self.w_None = Constant(None)
- self.builtin = Constant(__builtin__)
- self.sys = Constant(sys)
- self.w_False = Constant(False)
- self.w_True = Constant(True)
- self.w_type = Constant(type)
- self.w_tuple = Constant(tuple)
- for exc in [KeyError, ValueError, IndexError, StopIteration,
- AssertionError, TypeError, AttributeError, ImportError]:
- clsname = exc.__name__
- setattr(self, 'w_'+clsname, Constant(exc))
- # the following exceptions are the ones that should not show up
- # during flow graph construction; they are triggered by
- # non-R-Pythonic constructs or real bugs like typos.
- for exc in [NameError, UnboundLocalError]:
- clsname = exc.__name__
- setattr(self, 'w_'+clsname, None)
- self.specialcases = SPECIAL_CASES.copy()
- #self.make_builtins()
- #self.make_sys()
- # w_str is needed because cmp_exc_match of frames checks against it,
- # as string exceptions are deprecated
- self.w_str = Constant(str)
- # objects which should keep their SomeObjectness
- self.not_really_const = NOT_REALLY_CONST
-
- # disable superclass methods
- enter_cache_building_mode = None
- leave_cache_building_mode = None
- createcompiler = None
+ specialcases = SPECIAL_CASES
+ # objects which should keep their SomeObjectness
+ not_really_const = NOT_REALLY_CONST
def is_w(self, w_one, w_two):
return self.is_true(self.is_(w_one, w_two))
@@ -103,6 +88,12 @@
def newslice(self, w_start, w_stop, w_step):
return self.do_operation('newslice', w_start, w_stop, w_step)
+ def newbool(self, b):
+ if b:
+ return self.w_True
+ else:
+ return self.w_False
+
def wrap(self, obj):
if isinstance(obj, (Variable, Constant)):
raise TypeError("already wrapped: " + repr(obj))
@@ -167,53 +158,77 @@
raise UnwrapException
return obj
- def interpclass_w(self, w_obj):
- obj = self.unwrap(w_obj)
- if isinstance(obj, Wrappable):
- return obj
- return None
+ def exception_issubclass_w(self, w_cls1, w_cls2):
+ return self.is_true(self.issubtype(w_cls1, w_cls2))
- def _check_constant_interp_w_or_w_None(self, RequiredClass, w_obj):
+ def _exception_match(self, w_exc_type, w_check_class):
+ """Helper for exception_match
+
+ Handles the base case where w_check_class is a constant exception
+ type.
"""
- WARNING: this implementation is not complete at all. It's just enough
- to be used by end_finally() inside pyopcode.py.
- """
- return w_obj == self.w_None or (isinstance(w_obj, Constant) and
- isinstance(w_obj.value, RequiredClass))
-
- def getexecutioncontext(self):
- return self.frame
+ if self.is_w(w_exc_type, w_check_class):
+ return True # fast path (also here to handle string exceptions)
+ try:
+ return self.exception_issubclass_w(w_exc_type, w_check_class)
+ except FSException, e:
+ if e.match(self, self.w_TypeError): # string exceptions maybe
+ return False
+ raise
def exception_match(self, w_exc_type, w_check_class):
+ """Checks if the given exception type matches 'w_check_class'."""
try:
check_class = self.unwrap(w_check_class)
except UnwrapException:
- raise Exception, "non-constant except guard"
+ raise FlowingError(self.frame, "Non-constant except guard.")
if check_class in (NotImplementedError, AssertionError):
raise FlowingError(self.frame,
"Catching %s is not valid in RPython" % check_class.__name__)
if not isinstance(check_class, tuple):
# the simple case
- return ObjSpace.exception_match(self, w_exc_type, w_check_class)
+ return self._exception_match(w_exc_type, w_check_class)
# special case for StackOverflow (see rlib/rstackovf.py)
if check_class == rstackovf.StackOverflow:
w_real_class = self.wrap(rstackovf._StackOverflow)
- return ObjSpace.exception_match(self, w_exc_type, w_real_class)
+ return self._exception_match(w_exc_type, w_real_class)
# checking a tuple of classes
for w_klass in self.fixedview(w_check_class):
if self.exception_match(w_exc_type, w_klass):
return True
return False
- def getconstclass(space, w_cls):
- try:
- ecls = space.unwrap(w_cls)
- except UnwrapException:
- pass
+ def exc_from_raise(self, w_type, w_value):
+ """
+ Create a wrapped exception from the arguments of a raise statement.
+
+ Returns an FSException object whose w_value is an instance of w_type.
+ """
+ if self.isinstance_w(w_type, self.w_type):
+ # this is for all cases of the form (Class, something)
+ if self.is_w(w_value, self.w_None):
+ # raise Type: we assume we have to instantiate Type
+ w_value = self.call_function(w_type)
+ w_type = self.type(w_value)
+ else:
+ w_valuetype = self.type(w_value)
+ if self.exception_issubclass_w(w_valuetype, w_type):
+ # raise Type, Instance: let etype be the exact type of value
+ w_type = w_valuetype
+ else:
+ # raise Type, X: assume X is the constructor argument
+ w_value = self.call_function(w_type, w_value)
+ w_type = self.type(w_value)
else:
- if isinstance(ecls, (type, types.ClassType)):
- return ecls
- return None
+ # the only case left here is (inst, None), from a 'raise inst'.
+ w_inst = w_type
+ w_instclass = self.type(w_inst)
+ if not self.is_w(w_value, self.w_None):
+ raise FSException(self.w_TypeError, self.wrap(
+ "instance exception may not have a separate value"))
+ w_value = w_inst
+ w_type = w_instclass
+ return FSException(w_type, w_value)
def build_flow(self, func, constargs={}, tweak_for_generator=True):
"""
@@ -232,7 +247,7 @@
def fixedview(self, w_tuple, expected_length=None):
return self.unpackiterable(w_tuple, expected_length)
- listview = fixedview
+ listview = fixedview_unroll = fixedview
def unpackiterable(self, w_iterable, expected_length=None):
if not isinstance(w_iterable, Variable):
@@ -240,19 +255,17 @@
if expected_length is not None and len(l) != expected_length:
raise ValueError
return [self.wrap(x) for x in l]
- if isinstance(w_iterable, Variable) and expected_length is None:
- raise UnwrapException, ("cannot unpack a Variable iterable"
+ elif expected_length is None:
+ raise UnwrapException("cannot unpack a Variable iterable "
"without knowing its length")
- elif expected_length is not None:
+ else:
w_len = self.len(w_iterable)
w_correct = self.eq(w_len, self.wrap(expected_length))
if not self.is_true(w_correct):
- e = FSException(self.w_ValueError, self.w_None)
- e.normalize_exception(self)
+ e = self.exc_from_raise(self.w_ValueError, self.w_None)
raise e
return [self.do_operation('getitem', w_iterable, self.wrap(i))
for i in range(expected_length)]
- return ObjSpace.unpackiterable(self, w_iterable, expected_length)
# ____________________________________________________________
def do_operation(self, name, *args_w):
@@ -267,6 +280,9 @@
operation.implicit_exceptions.get(name))
return w_result
+ def not_(self, w_obj):
+ return self.wrap(not self.is_true(w_obj))
+
def is_true(self, w_obj):
try:
obj = self.unwrap_for_computation(w_obj)
@@ -310,11 +326,14 @@
def setitem(self, w_obj, w_key, w_val):
# protect us from globals write access
if w_obj is self.frame.w_globals:
- raise SyntaxError("attempt to modify global attribute %r in %r"
- % (w_key, ec.graph.func))
+ raise FlowingError(self.frame,
+ "Attempting to modify global variable %r." % (w_key))
return self.do_operation_with_implicit_exceptions('setitem', w_obj,
w_key, w_val)
+ def setitem_str(self, w_obj, key, w_value):
+ return self.setitem(w_obj, self.wrap(key), w_value)
+
def getattr(self, w_obj, w_name):
# handling special things like sys
# unfortunately this will never vanish with a unique import logic :-(
@@ -333,10 +352,9 @@
result = getattr(obj, name)
except Exception, e:
etype = e.__class__
- msg = "generated by a constant operation:\n\t%s%r" % (
- 'getattr', (obj, name))
- raise OperationThatShouldNotBePropagatedError(
- self.wrap(etype), self.wrap(msg))
+ msg = "getattr(%s, %s) always raises %s: %s" % (
+ obj, name, etype, e)
+ raise FlowingError(self.frame, msg)
try:
return self.wrap(result)
except WrapException:
@@ -344,6 +362,9 @@
return self.do_operation_with_implicit_exceptions('getattr',
w_obj, w_name)
+ def isinstance_w(self, w_obj, w_type):
+ return self.is_true(self.isinstance(w_obj, w_type))
+
def import_name(self, name, glob=None, loc=None, frm=None, level=-1):
try:
mod = __import__(name, glob, loc, frm, level)
@@ -352,20 +373,37 @@
return self.wrap(mod)
def import_from(self, w_module, w_name):
+ assert isinstance(w_module, Constant)
+ assert isinstance(w_name, Constant)
+ # handle sys
+ if w_module in self.not_really_const:
+ const_w = self.not_really_const[w_obj]
+ if w_name not in const_w:
+ return self.do_operation_with_implicit_exceptions('getattr',
+ w_obj, w_name)
try:
- return self.getattr(w_module, w_name)
- except FSException, e:
- if e.match(self, self.w_AttributeError):
- raise FSException(self.w_ImportError,
- self.wrap("cannot import name '%s'" % w_name.value))
- else:
- raise
+ return self.wrap(getattr(w_module.value, w_name.value))
+ except AttributeError:
+ raise FSException(self.w_ImportError,
+ self.wrap("cannot import name '%s'" % w_name.value))
+
+ def call_valuestack(self, w_func, nargs, frame):
+ args = frame.make_arguments(nargs)
+ return self.call_args(w_func, args)
+
+ def call_method(self, w_obj, methname, *arg_w):
+ w_meth = self.getattr(w_obj, self.wrap(methname))
+ return self.call_function(w_meth, *arg_w)
def call_function(self, w_func, *args_w):
- nargs = len(args_w)
- args = argument.ArgumentsForTranslation(self, list(args_w))
+ args = ArgumentsForTranslation(self, list(args_w))
return self.call_args(w_func, args)
+ def appcall(self, func, *args_w):
+ """Call an app-level RPython function directly"""
+ w_func = self.wrap(func)
+ return self.do_operation('simple_call', w_func, *args_w)
+
def call_args(self, w_callable, args):
try:
fn = self.unwrap(w_callable)
@@ -424,20 +462,6 @@
raise FlowingError(self.frame, self.wrap(message))
return self.wrap(value)
- def w_KeyboardInterrupt(self):
- # the reason to do this is: if you interrupt the flowing of a function
- # with <Ctrl-C> the bytecode interpreter will raise an applevel
- # KeyboardInterrupt and you will get an AttributeError: space does not
- # have w_KeyboardInterrupt, which is not very helpful
- raise KeyboardInterrupt
- w_KeyboardInterrupt = property(w_KeyboardInterrupt)
-
- def w_RuntimeError(self):
- # XXX same as w_KeyboardInterrupt()
- raise RuntimeError("the interpreter raises RuntimeError during "
- "flow graph construction")
- w_RuntimeError = prebuilt_recursion_error = property(w_RuntimeError)
-
def make_op(name, arity):
"""Add function operation to the flow space."""
if getattr(FlowObjSpace, name, None) is not None:
@@ -486,10 +510,9 @@
result = op(*args)
except Exception, e:
etype = e.__class__
- msg = "generated by a constant operation:\n\t%s%r" % (
- name, tuple(args))
- raise OperationThatShouldNotBePropagatedError(
- self.wrap(etype), self.wrap(msg))
+ msg = "%s%r always raises %s: %s" % (
+ name, tuple(args), etype, e)
+ raise FlowingError(self.frame, msg)
else:
# don't try to constant-fold operations giving a 'long'
# result. The result is probably meant to be sent to
diff --git a/pypy/objspace/flow/operation.py b/pypy/objspace/flow/operation.py
--- a/pypy/objspace/flow/operation.py
+++ b/pypy/objspace/flow/operation.py
@@ -6,13 +6,9 @@
import __builtin__
import __future__
import operator
-import types
-import sys
from pypy.interpreter.baseobjspace import ObjSpace
-from pypy.interpreter.error import OperationError
from pypy.tool.sourcetools import compile2
from pypy.rlib.rarithmetic import ovfcheck
-from pypy.objspace.flow import model
FunctionByName = {} # dict {"operation_name": <built-in function>}
diff --git a/pypy/objspace/flow/specialcase.py b/pypy/objspace/flow/specialcase.py
--- a/pypy/objspace/flow/specialcase.py
+++ b/pypy/objspace/flow/specialcase.py
@@ -1,11 +1,7 @@
-from pypy.objspace.flow.model import Constant, UnwrapException
+from pypy.objspace.flow.model import Constant
from pypy.objspace.flow.operation import OperationName, Arity
-from pypy.interpreter.gateway import ApplevelClass
-from pypy.interpreter.error import OperationError
-from pypy.tool.cache import Cache
from pypy.rlib.rarithmetic import r_uint
from pypy.rlib.objectmodel import we_are_translated
-import py
def sc_import(space, fn, args):
args_w, kwds_w = args.unpack()
@@ -35,11 +31,13 @@
class StdOutBuffer:
linebuf = []
stdoutbuffer = StdOutBuffer()
+
def rpython_print_item(s):
buf = stdoutbuffer.linebuf
for c in s:
buf.append(c)
buf.append(' ')
+
def rpython_print_newline():
buf = stdoutbuffer.linebuf
if buf:
@@ -51,18 +49,6 @@
import os
os.write(1, s)
-def sc_applevel(space, app, name, args_w):
- # special case only for print_item and print_newline
- if 'pyopcode' in app.filename and name == 'print_item':
- w_s = space.do_operation('str', *args_w)
- args_w = (w_s,)
- elif 'pyopcode' in app.filename and name == 'print_newline':
- pass
- else:
- raise Exception("not RPython: calling %r from %r" % (name, app))
- func = globals()['rpython_' + name]
- return space.do_operation('simple_call', Constant(func), *args_w)
-
# _________________________________________________________________________
def sc_r_uint(space, r_uint, args):
@@ -79,8 +65,8 @@
def sc_we_are_translated(space, we_are_translated, args):
return Constant(True)
-SPECIAL_CASES = {__import__: sc_import, ApplevelClass: sc_applevel,
- r_uint: sc_r_uint, we_are_translated: sc_we_are_translated}
+SPECIAL_CASES = {__import__: sc_import, r_uint: sc_r_uint,
+ we_are_translated: sc_we_are_translated}
for fn in OperationName:
SPECIAL_CASES[fn] = sc_operator
diff --git a/pypy/objspace/flow/test/test_framestate.py b/pypy/objspace/flow/test/test_framestate.py
--- a/pypy/objspace/flow/test/test_framestate.py
+++ b/pypy/objspace/flow/test/test_framestate.py
@@ -1,6 +1,4 @@
-from py.test import raises
from pypy.objspace.flow.model import *
-from pypy.interpreter.pycode import PyCode
from pypy.rlib.unroll import SpecTag
from pypy.objspace.flow.objspace import FlowObjSpace
from pypy.objspace.flow.flowcontext import FlowSpaceFrame
diff --git a/pypy/objspace/flow/test/test_objspace.py b/pypy/objspace/flow/test/test_objspace.py
--- a/pypy/objspace/flow/test/test_objspace.py
+++ b/pypy/objspace/flow/test/test_objspace.py
@@ -1,9 +1,8 @@
from __future__ import with_statement
import new
import py, sys
-from pypy.objspace.flow.model import Constant, Block, Link, Variable
+from pypy.objspace.flow.model import Constant
from pypy.objspace.flow.model import mkentrymap, c_last_exception
-from pypy.interpreter.argument import Arguments
from pypy.translator.simplify import simplify_graph
from pypy.objspace.flow.objspace import FlowObjSpace
from pypy.objspace.flow.flowcontext import FlowingError, FlowSpaceFrame
@@ -100,6 +99,11 @@
def test_print(self):
x = self.codetest(self.print_)
+ def test_bad_print(self):
+ def f(x):
+ print >> x, "Hello"
+ with py.test.raises(FlowingError):
+ self.codetest(f)
#__________________________________________________________
def while_(i):
while i > 0:
@@ -460,6 +464,15 @@
def test_globalconstdict(self):
x = self.codetest(self.globalconstdict)
+ def test_dont_write_globals(self):
+ def f():
+ global DATA
+ DATA = 5
+ with py.test.raises(FlowingError) as excinfo:
+ self.codetest(f)
+ assert "modify global" in str(excinfo.value)
+ assert DATA == {'x': 5, 'y': 6}
+
#__________________________________________________________
def dictliteral(name):
x = {'x': 1}
@@ -500,6 +513,12 @@
assert len(op.args) == 2
assert op.args[1].value == 3
+ def test_unary_ops(self):
+ def f(x):
+ return not ~-x
+ graph = self.codetest(f)
+ assert self.all_operations(graph) == {'is_true': 1, 'invert': 1, 'neg': 1}
+
#__________________________________________________________
def wearetranslated(x):
@@ -953,14 +972,32 @@
return s[-3:]
check(f3, 'llo')
- def test_propagate_attribute_error(self):
+ def test_constfold_attribute_error(self):
def f(x):
try:
"".invalid
finally:
if x and 0:
raise TypeError()
- py.test.raises(Exception, self.codetest, f)
+ with py.test.raises(FlowingError) as excinfo:
+ self.codetest(f)
+ assert 'getattr' in str(excinfo.value)
+
+ def test_constfold_exception(self):
+ def f():
+ return (3 + 2) / (4 - 2 * 2)
+ with py.test.raises(FlowingError) as excinfo:
+ self.codetest(f)
+ assert 'div(5, 0)' in str(excinfo.value)
+
+ def test_nonconstant_except(self):
+ def f(exc_cls):
+ try:
+ raise AttributeError
+ except exc_cls:
+ pass
+ with py.test.raises(FlowingError):
+ self.codetest(f)
def test__flowspace_rewrite_directly_as_(self):
def g(x):
diff --git a/pypy/translator/translator.py b/pypy/translator/translator.py
--- a/pypy/translator/translator.py
+++ b/pypy/translator/translator.py
@@ -8,6 +8,7 @@
from pypy.translator import simplify
from pypy.objspace.flow.model import FunctionGraph, checkgraph, Block
+from pypy.objspace.flow.objspace import FlowObjSpace
from pypy.tool.ansi_print import ansi_log
from pypy.tool.sourcetools import nice_repr_for_func
from pypy.config.pypyoption import pypy_optiondescription
@@ -35,7 +36,6 @@
setattr(config.translation, attr, flowing_flags[attr])
self.config = config
self.platform = get_platform(config)
- self.create_flowspace_config()
self.annotator = None
self.rtyper = None
self.exceptiontransformer = None
@@ -43,17 +43,6 @@
self.callgraph = {} # {opaque_tag: (caller-graph, callee-graph)}
self._prebuilt_graphs = {} # only used by the pygame viewer
- def create_flowspace_config(self):
- # XXX this is a hack: we create a new config, which is only used
- # for the flow object space. The problem is that the flow obj space
- # needs an objspace config, but the thing we are translating might not
- # have one (or worse we are translating pypy and the flow space picks
- # up strange options of the pypy we are translating). Therefore we need
- # to construct this new config
- self.flowconfig = get_combined_translation_config(
- pypy_optiondescription, self.config, translating=True)
- self.flowconfig.objspace.name = "flow"
-
def buildflowgraph(self, func, mute_dot=False):
"""Get the flow graph for a function."""
if not isinstance(func, types.FunctionType):
@@ -64,8 +53,7 @@
else:
if self.config.translation.verbose:
log.start(nice_repr_for_func(func))
- from pypy.objspace.flow.objspace import FlowObjSpace
- space = FlowObjSpace(self.flowconfig)
+ space = FlowObjSpace()
graph = space.build_flow(func)
if self.config.translation.simplifying:
simplify.simplify_graph(graph)
More information about the pypy-commit
mailing list