Commits

Armin Rigo committed 406c10d

more ground work. interactive.py worked quite fine at some point but is now
broken again for a reason not immediately obvious to me.

Comments (0)

Files changed (18)

pypy/interpreter/baseobjspace.py

+from executioncontext import ExecutionContext, OperationError, NoValue
+import pyframe
 
 __all__ = ['ObjSpace', 'OperationError', 'NoValue']
 
-class OperationError(Exception):
-    """Interpreter-level exception that signals an exception that should be
-    sent to the application level.
-
-    OperationError instances have three public attributes (and no .args),
-    w_type, w_value and w_traceback, which contain the wrapped type, value
-    and traceback describing the exception."""
-
-    def __init__(self, w_type, w_value, w_traceback=None):
-        self.w_type = w_type
-        self.w_value = w_value
-        self.w_traceback = w_traceback
-        ### DEBUG DUMP ###
-        #self.nicetraceback(None)
-    
-    def __str__(self):
-        "Convenience for tracebacks."
-        return '[%s: %s]' % (self.w_type, self.w_value)
-    def nicetraceback(self, space):
-        "Dump a nice custom traceback to sys.stderr."
-        import sys, traceback
-        tb = sys.exc_info()[2]
-        if space is not None:
-            exc = space.unwrap(self.w_type)
-            value = space.unwrap(self.w_value)
-            msg = traceback.format_exception_only(exc, value)
-        else:
-            msg = '%r: %r' % (self.w_type, self.w_value)
-        print >> sys.stderr, "*"*10, " OperationError ", "*"*10
-        traceback.print_tb(tb)
-##         if self.w_traceback:
-##             traceback.print_tb(space.unwrap(self.w_traceback))
-        print >> sys.stderr, "[Application-level]", ''.join(msg).strip()
-        print >> sys.stderr, "*"*10
-
-class NoValue(Exception):
-    """Raised to signal absence of value, e.g. in the iterator accessing
-    method 'iternext()' of object spaces."""
-
-
-##################################################################
-
-import executioncontext, pyframe
-
 
 class ObjSpace:
     """Base class for the interpreter-level implementations of object spaces.
     XXX describe here in more details what the object spaces are."""
 
     def __init__(self):
-        "Basic initialization of objects.  Override me."
+        "Basic initialization of objects."
         self.w_builtins = self.newdict([])
         self.w_modules  = self.newdict([])
         self.appfile_helpers = {}
                 if result.space is self:
                     return result
             f = f.f_back
-        return executioncontext.ExecutionContext(self)
+        return ExecutionContext(self)
 
     def gethelper(self, applicationfile):
         try:
         return helper
 
     # Following is a friendly interface to common object space operations
-    # that can be defined in term of more primitive ones
+    # that can be defined in term of more primitive ones.  Subclasses
+    # may also override specific functions for performance.
+
+    def is_(self, w_x, w_y):
+        "'x is y'."
+        w_id_x = self.id(w_x)
+        w_id_y = self.id(w_y)
+        return self.eq(w_id_x, w_id_y)
+
+    def newbool(self, b):
+        if b:
+            return self.w_True
+        else:
+            return self.w_False
 
     def unpackiterable(self, w_iterable, expected_length=None):
         """Unpack an iterable object into a real (interpreter-level) list.
         Raise a real ValueError if the length is wrong."""
-        w_iterator = self.getiter(w_iterable)
+        w_iterator = self.iter(w_iterable)
         items = []
         while True:
             try:
-                w_item = self.iternext(w_iterator)
+                w_item = self.next(w_iterator)
             except NoValue:
                 break  # done
             if expected_length is not None and len(items) == expected_length:
             raise ValueError, "need more than %d value%s to unpack" % (i, plural)
         return items
 
+    def unpacktuple(self, w_tuple, expected_length=None):
+        """Same as unpackiterable(), but only for tuples.
+        Only use for bootstrapping or performance reasons."""
+        tuple_length = self.unwrap(self.len(w_tuple))
+        if expected_length is not None and tuple_length != expected_length:
+            raise ValueError, "got a tuple of length %d instead of %d" % (
+                tuple_length, expected_length)
+        items = []
+        for i in range(tuple_length):
+            w_i = self.wrap(i)
+            w_item = self.getitem(w_tuple, w_i)
+            items.append(w_item)
+        return items
+
+    def exception_match(self, w_exc_type, w_check_class):
+        """Checks if the given exception type matches 'w_check_class'."""
+        # XXX very limited version!
+        return self.is_(w_exc_type, w_check_class)
+
 
 ## Table describing the regular part of the interface of object spaces,
-## namely all methods which only take w_ arguments and return a w_ result.
+## namely all methods which only take w_ arguments and return a w_ result
+## (if any).  XXX Maybe we should say that these methods must be accessed
+## as 'space.op.xxx()' instead of directly 'space.xxx()'.
 
 ObjSpace.MethodTable = [
 # method name # symbol # number of arguments
-    ('type',            'type',     1),
-    ('checktype',       'type?',    2),
-    ('repr',            'repr',     1),
-    ('str',             'str',      1),
-    ('getattr',         'getattr',  2),
-    ('setattr',         'setattr',  3),
-    ('delattr',         'delattr',  2),
-    ('getitem',         'getitem',  2),
-    ('setitem',         'setitem',  3),
-    ('delitem',         'delitem',  2),
-    ('pos',             'unary+',   1),
-    ('neg',             'unary-',   1),
-    ('not_',            'not',      1),
-    ('abs' ,            'abs',      1),
-    ('invert',          '~',        1),
-    ('add',             '+',        2),
-    ('sub',             '-',        2),
-    ('mul',             '*',        2),
-    ('truediv',         '/',        2),
-    ('floordiv',        '//',       2),
-    ('div',             'div',      2),
-    ('mod',             '%',        2),
-    ('divmod',          'divmod',   2),
-    ('pow',             '**',       3),
-    ('lshift',          '<<',       2),
-    ('rshift',          '>>',       2),
-    ('and_',            '&',        2),
-    ('or_',             '|',        2),
-    ('xor',             '^',        2),
-    ('inplace_add',     '+=',       2),
-    ('inplace_sub',     '-=',       2),
-    ('inplace_mul',     '*=',       2),
-    ('inplace_truediv', '/=',       2),
-    ('inplace_floordiv','//=',      2),
-    ('inplace_div',     'div=',     2),
-    ('inplace_mod',     '%=',       2),
-    ('inplace_pow',     '**=',      2),
-    ('inplace_lshift',  '<<=',      2),
-    ('inplace_rshift',  '>>=',      2),
-    ('inplace_and',     '&=',       2),
-    ('inplace_or',      '|=',       2),
-    ('inplace_xor',     '^=',       2),
-    ('getiter',         'iter',     1),
-    ('iternext',        'next',     1),
-    ('call',            'call',     3),
+    ('id',              'id',        1),
+    ('type',            'type',      1),
+    ('issubtype',       'issubtype', 2),  # not for old-style classes
+    ('repr',            'repr',      1),
+    ('str',             'str',       1),
+    ('len',             'len',       1),
+    ('hash',            'hash',      1),
+    ('getattr',         'getattr',   2),
+    ('setattr',         'setattr',   3),
+    ('delattr',         'delattr',   2),
+    ('getitem',         'getitem',   2),
+    ('setitem',         'setitem',   3),
+    ('delitem',         'delitem',   2),
+    ('pos',             'pos',       1),
+    ('neg',             'neg',       1),
+    ('not_',            'not',       1),
+    ('abs' ,            'abs',       1),
+    ('invert',          '~',         1),
+    ('add',             '+',         2),
+    ('sub',             '-',         2),
+    ('mul',             '*',         2),
+    ('truediv',         '/',         2),
+    ('floordiv',        '//',        2),
+    ('div',             'div',       2),
+    ('mod',             '%',         2),
+    ('divmod',          'divmod',    2),
+    ('pow',             '**',        3),
+    ('lshift',          '<<',        2),
+    ('rshift',          '>>',        2),
+    ('and_',            '&',         2),
+    ('or_',             '|',         2),
+    ('xor',             '^',         2),
+    ('inplace_add',     '+=',        2),
+    ('inplace_sub',     '-=',        2),
+    ('inplace_mul',     '*=',        2),
+    ('inplace_truediv', '/=',        2),
+    ('inplace_floordiv','//=',       2),
+    ('inplace_div',     'div=',      2),
+    ('inplace_mod',     '%=',        2),
+    ('inplace_pow',     '**=',       2),
+    ('inplace_lshift',  '<<=',       2),
+    ('inplace_rshift',  '>>=',       2),
+    ('inplace_and',     '&=',        2),
+    ('inplace_or',      '|=',        2),
+    ('inplace_xor',     '^=',        2),
+    ('lt',              '<',         2),
+    ('le',              '<=',        2),
+    ('eq',              '==',        2),
+    ('ne',              '!=',        2),
+    ('gt',              '>',         2),
+    ('ge',              '>=',        2),
+    ('contains',        'contains',  2),
+    ('iter',            'iter',      1),
+    ('next',            'next',      1),  # iterator interface
+    ('call',            'call',      3),
     ]
 
 ## Irregular part of the interface:
 #                        wrap(x) -> w_x
 #                    unwrap(w_x) -> x
 #                   is_true(w_x) -> True or False
-#                      hash(w_x) -> int
-#          compare(w_x, w_y, op) -> w_result
 #       newtuple([w_1, w_2,...]) -> w_tuple
 #        newlist([w_1, w_2,...]) -> w_list
+#      newstring([w_1, w_2,...]) -> w_string from ascii numbers (bytes)
 # newdict([(w_key,w_value),...]) -> w_dict
 # newslice(w_start,w_stop,w_end) -> w_slice     (w_end may be a real None)
 #               newfunction(...) -> w_function

pypy/interpreter/executioncontext.py

 
     def exception_trace(self, operationerr):
         "Trace function called upon OperationError."
-        operationerr.nicetraceback(self.space)
+        operationerr.record_interpreter_traceback()
+        #operationerr.print_detailed_traceback(self.space)
+
+
+class OperationError(Exception):
+    """Interpreter-level exception that signals an exception that should be
+    sent to the application level.
+
+    OperationError instances have three public attributes (and no .args),
+    w_type, w_value and w_traceback, which contain the wrapped type, value
+    and traceback describing the exception."""
+
+    def __init__(self, w_type, w_value, w_traceback=None):
+        self.w_type = w_type
+        self.w_value = w_value
+        self.w_traceback = w_traceback
+        self.debug_tb = None
+
+    def match(self, space, w_check_class):
+        "Check if this application-level exception matches 'w_check_class'."
+        return space.is_true(space.exception_match(self.w_type, w_check_class))
+
+    def __str__(self):
+        "Convenience for tracebacks."
+        return '[%s: %s]' % (self.w_type, self.w_value)
+
+    def errorstr(self, space):
+        "The exception class and value, as a string."
+        exc_type  = space.unwrap(self.w_type)
+        exc_value = space.unwrap(self.w_value)
+        return '%s: %s' % (exc_type.__name__, exc_value)
+
+    def record_interpreter_traceback(self):
+        """Records the current traceback inside the interpreter.
+        This traceback is only useful to debug the interpreter, not the
+        application."""
+        if self.debug_tb is None:
+            self.debug_tb = sys.exc_info()[2]
+
+    def print_application_traceback(self, space, file=None):
+        "Dump a standard application-level traceback."
+        if file is None: file = sys.stderr
+        self.print_app_tb_only(file)
+        print >> file, self.errorstr(space)
+
+    def print_app_tb_only(self, file):
+        tb = self.w_traceback
+        if tb:
+            import linecache
+            tb = self.w_traceback[:]
+            tb.reverse()
+            print >> file, "Traceback (application-level):"
+            for f, i in tb:
+                co = f.bytecode
+                lineno = offset2lineno(co, i)
+                fname = co.co_filename
+                if fname.startswith('<inline>\n'):
+                    lines = fname.split('\n')
+                    fname = lines[0].strip()
+                    try:
+                        l = lines[lineno]
+                    except IndexError:
+                        l = ''
+                else:
+                    l = linecache.getline(fname, lineno)
+                print >> file, "  File", `fname`+',',
+                print >> file, "line", lineno, "in", co.co_name
+                if l:
+                    if l.endswith('\n'):
+                        l = l[:-1]
+                    print >> file, l
+
+    def print_detailed_traceback(self, space, file=None):
+        """Dump a nice detailed interpreter- and application-level traceback,
+        useful to debug the interpreter."""
+        if file is None: file = sys.stderr
+        self.print_app_tb_only(file)
+        if self.debug_tb:
+            import traceback
+            interpr_file = LinePrefixer(file, '||')
+            print >> interpr_file, "Traceback (interpreter-level):"
+            traceback.print_tb(self.debug_tb, file=interpr_file)
+        exc_type  = space.unwrap(self.w_type)
+        exc_value = space.unwrap(self.w_value)
+        print >> file, '(application-level)', exc_type.__name__+':', exc_value
+
+
+class NoValue(Exception):
+    """Raised to signal absence of value, e.g. in the iterator accessing
+    method 'op.next()' of object spaces."""
+
+
+# Utilities
+
+def inlinecompile(source, symbol='exec'):
+    """Compile the given 'source' string.
+    This function differs from the built-in compile() because it abuses
+    co_filename to store a copy of the complete source code.
+    This lets OperationError.print_application_traceback() print the
+    actual source line in the traceback."""
+    return compile(source, '<inline>\n' + source, symbol)
+
+def offset2lineno(c, stopat):
+    tab = c.co_lnotab
+    line = c.co_firstlineno
+    addr = 0
+    for i in range(0, len(tab), 2):
+        addr = addr + ord(tab[i])
+        if addr > stopat:
+            break
+        line = line + ord(tab[i+1])
+    return line
+
+class LinePrefixer:
+    """File-like class that inserts a prefix string
+    at the beginning of each line it prints."""
+    def __init__(self, file, prefix):
+        self.file = file
+        self.prefix = prefix
+        self.linestart = True
+    def write(self, data):
+        if self.linestart:
+            self.file.write(self.prefix)
+        if data.endswith('\n'):
+            data = data[:-1]
+            self.linestart = True
+        else:
+            self.linestart = False
+        self.file.write(data.replace('\n', '\n'+self.prefix))
+        if self.linestart:
+            self.file.write('\n')

pypy/interpreter/interactive.py

 from pypy.interpreter import executioncontext
 from pypy.interpreter import pyframe
 from pypy.interpreter import baseobjspace
-from pypy.objspace import trivial
+import sys
 import code
 import linecache
 
+
 def offset2lineno(c, stopat):
     tab = c.co_lnotab
     line = c.co_firstlineno
     return line
 
 class PyPyConsole(code.InteractiveConsole):
-    def __init__(self):
+    def __init__(self, objspace):
         code.InteractiveConsole.__init__(self)
-        self.space = trivial.TrivialObjSpace()
+        self.space = objspace()
         self.ec = executioncontext.ExecutionContext(self.space)
-        self.locals['__builtins__'] = self.space.w_builtins
+        self.w_globals = self.ec.make_standard_w_globals()
+
+    def interact(self):
+        banner = "Python %s in pypy\n%s / %s" % (
+            sys.version, self.__class__.__name__, self.space.__class__.__name__)
+        code.InteractiveConsole.interact(self, banner)
 
     def runcode(self, code):
         # ah ha!
         frame = pyframe.PyFrame(self.space, code,
-                        self.locals, self.locals)
+                                self.w_globals, self.w_globals)
         try:
             self.ec.eval_frame(frame)
-        except baseobjspace.OperationError, e:
-            print "Traceback"
-            tb = e.w_traceback[:]
-            tb.reverse()
-            for f, i in tb:
-                co = f.bytecode
-                fname = co.co_filename
-                lineno = offset2lineno(co, i)
-                print "  File", `fname`+',',
-                print "line", lineno, "in", co.co_name
-                l = linecache.getline(fname, lineno)
-                if l:
-                    print l[:-1]
-            print e.w_type.__name__+':', e.w_value
-            import traceback
-            traceback.print_exc()
-        
+        except baseobjspace.OperationError, operationerr:
+            # XXX insert exception info into the application-level sys.last_xxx
+            operationerr.print_detailed_traceback(self.space)
+        else:
+            if sys.stdout.softspace:
+                print
+
+    def runsource(self, source, ignored_filename="<input>", symbol="single"):
+        hacked_filename = '<inline>\n'+source
+        try:
+            code = self.compile(source, hacked_filename, symbol)
+        except (OverflowError, SyntaxError, ValueError):
+            self.showsyntaxerror(self.filename)
+            return 0
+        if code is None:
+            return 1
+        self.runcode(code)
+        return 0
+
 if __name__ == '__main__':
-    con = PyPyConsole()
+    # object space selection
+    if len(sys.argv) < 2:
+        choice = 'trivial'   # default
+    else:
+        choice = sys.argv[1]
+    classname = choice.capitalize() + 'ObjSpace'
+    module = __import__('pypy.objspace.%s' % choice,
+                        globals(), locals(), [classname])
+    ObjSpace = getattr(module, classname)
+    con = PyPyConsole(ObjSpace)
     con.interact()
-

pypy/interpreter/opcode.py

 def LOAD_FAST(f, varindex):
     varname = f.getlocalvarname(varindex)
     w_varname = f.space.wrap(varname)
-    w_value = f.space.getitem(f.w_locals, w_varname)
-    # XXX catch KeyError and make it a NameError
+    try:
+        w_value = f.space.getitem(f.w_locals, w_varname)
+    except OperationError, e:
+        # catch KeyErrors and turn them into UnboundLocalErrors
+        if not e.match(f.space, f.space.w_KeyError):
+            raise
+        message = "local variable '%s' referenced before assignment" % varname
+        raise OperationError(f.space.w_UnboundLocalError, f.space.wrap(message))
     f.valuestack.push(w_value)
 
 def LOAD_CONST(f, constindex):
     elif nbargs == 1:
         w_type = f.valuestack.pop()
         w_resulttuple = f.space.gethelper(appfile).call(
-            "prepare_raise", [w_type, None, None])
+            "prepare_raise", [w_type, f.space.w_None, f.space.w_None])
     elif nbargs == 2:
         w_value = f.valuestack.pop()
         w_type  = f.valuestack.pop()
         w_resulttuple = f.space.gethelper(appfile).call(
-            "prepare_raise", [w_type, w_value, None])
+            "prepare_raise", [w_type, w_value, f.space.w_None])
     elif nbargs == 3:
         w_traceback = f.valuestack.pop()
         w_value     = f.valuestack.pop()
             "prepare_raise", [w_type, w_value, w_traceback])
     else:
         raise pyframe.BytecodeCorruption, "bad RAISE_VARARGS oparg"
-    w_type, w_value, w_traceback = f.space.unpackiterable(w_resulttuple)
+    w_type, w_value, w_traceback = f.space.unpacktuple(w_resulttuple)
     raise OperationError(w_type, w_value, w_traceback)
 
 def LOAD_LOCALS(f):
 def DELETE_NAME(f, varindex):
     varname = f.getname(varindex)
     w_varname = f.space.wrap(varname)
-    f.space.delitem(f.w_locals, w_varname)
-    # XXX catch KeyError and make it a NameError
+    try:
+        f.space.delitem(f.w_locals, w_varname)
+    except OperationError, e:
+        # catch KeyErrors and turn them into NameErrors
+        if not e.match(f.space, f.space.w_KeyError):
+            raise
+        message = "name '%s' is not defined" % varname
+        raise OperationError(f.space.w_NameError, f.space.wrap(message))
 
 def UNPACK_SEQUENCE(f, itemcount):
     w_iterable = f.valuestack.pop()
         w_value = f.space.getitem(f.w_globals, w_varname)
     except OperationError, e:
         # catch KeyErrors
-        w_KeyError = f.space.w_KeyError
-        w_match = f.space.compare(e.w_type, w_KeyError, "exc match")
-        if not f.space.is_true(w_match):
+        if not e.match(f.space, f.space.w_KeyError):
             raise
         # we got a KeyError, now look in the built-ins
         try:
             w_value = f.space.getitem(f.w_builtins, w_varname)
         except OperationError, e:
             # catch KeyErrors again
-            w_match = f.space.compare(e.w_type, w_KeyError, "exc match")
-            if not f.space.is_true(w_match):
+            if not e.match(f.space, f.space.w_KeyError):
                 raise
             message = "global name '%s' is not defined" % varname
             w_exc_type = f.space.w_NameError
 def DELETE_FAST(f, varindex):
     varname = f.getlocalvarname(varindex)
     w_varname = f.space.wrap(varname)
-    f.space.delitem(f.w_locals, w_varname)
-    # XXX catch KeyError and make it a NameError
+    try:
+        f.space.delitem(f.w_locals, w_varname)
+    except OperationError, e:
+        # catch KeyErrors and turn them into UnboundLocalErrors
+        if not e.match(f.space, f.space.w_KeyError):
+            raise
+        message = "local variable '%s' referenced before assignment" % varname
+        raise OperationError(f.space.w_UnboundLocalError, f.space.wrap(message))
 
 def LOAD_CLOSURE(f, varindex):
     # nested scopes: access the cell object
     # nested scopes: access a variable through its cell object
     varname = f.getfreevarname(varindex)
     w_varname = f.space.wrap(varname)
-    w_value = f.space.getitem(f.w_locals, w_varname)
-    # XXX catch KeyError and make it a NameError
+    try:
+        w_value = f.space.getitem(f.w_locals, w_varname)
+    except OperationError, e:
+        # catch KeyErrors
+        if not e.match(f.space, f.space.w_KeyError):
+            raise
+        if f.iscellvar(varindex):
+            message = "local variable '%s' referenced before assignment"
+            w_exc_type = f.space.w_UnboundLocalError
+        else:
+            message = ("free variable '%s' referenced before assignment"
+                       " in enclosing scope")
+            w_exc_type = f.space.w_NameError
+        raise OperationError(w_exc_type, f.space.wrap(message % varname))
     f.valuestack.push(w_value)
 
 def STORE_DEREF(f, varindex):
     w_value = f.space.getattr(w_obj, w_attributename)
     f.valuestack.push(w_value)
 
-def COMPARE_OP(f, test):
-    testnames = ["<", "<=", "==", "!=", ">", ">=",
-                 "in", "not in", "is", "is not", "exc match"]
-    testname = testnames[test]
+def cmp_lt(f, w_1, w_2):  return f.space.lt(w_1, w_2)
+def cmp_le(f, w_1, w_2):  return f.space.le(w_1, w_2)
+def cmp_eq(f, w_1, w_2):  return f.space.eq(w_1, w_2)
+def cmp_ne(f, w_1, w_2):  return f.space.ne(w_1, w_2)
+def cmp_gt(f, w_1, w_2):  return f.space.gt(w_1, w_2)
+def cmp_ge(f, w_1, w_2):  return f.space.ge(w_1, w_2)
+
+def cmp_in(f, w_1, w_2):
+    return f.space.contains(w_2, w_1)
+def cmp_not_in(f, w_1, w_2):
+    return f.space.not_(f.space.contains(w_2, w_1))
+def cmp_is(f, w_1, w_2):
+    return f.space.is_(w_1, w_2)
+def cmp_is_not(f, w_1, w_2):
+    return f.space.not_(f.space.is_(w_1, w_2))
+def cmp_exc_match(f, w_1, w_2):
+    return f.space.exception_match(w_1, w_2)
+
+compare_dispatch_table = {
+    0: cmp_lt,   # "<"
+    1: cmp_le,   # "<="
+    2: cmp_eq,   # "=="
+    3: cmp_ne,   # "!="
+    4: cmp_gt,   # ">"
+    5: cmp_ge,   # ">="
+    6: cmp_in,
+    7: cmp_not_in,
+    8: cmp_is,
+    9: cmp_is_not,
+    10: cmp_exc_match,
+    }
+def COMPARE_OP(f, testnum):
     w_2 = f.valuestack.pop()
     w_1 = f.valuestack.pop()
-    w_result = f.space.compare(w_1, w_2, testname)
+    try:
+        testfn = compare_dispatch_table[testnum]
+    except KeyError:
+        raise pyframe.BytecodeCorruption, "bad COMPARE_OP oparg"
+    w_result = testfn(f, w_1, w_2)
     f.valuestack.push(w_result)
 
 def IMPORT_NAME(f, nameindex):
 
 def GET_ITER(f):
     w_iterable = f.valuestack.pop()
-    w_iterator = f.space.getiter(w_iterable)
+    w_iterator = f.space.op.iter(w_iterable)
     f.valuestack.push(w_iterator)
 
 def FOR_ITER(f, jumpby):
     w_iterator = f.valuestack.top()
     try:
-        w_nextitem = f.space.iternext(w_iterator)
+        w_nextitem = f.space.op.next(w_iterator)
     except NoValue:
         # iterator exhausted
         f.valuestack.pop()

pypy/interpreter/opcode_app.py

 def print_item_to(x, stream):
     if file_softspace(stream, False):
         stream.write(" ")
+    stream.write(str(x))
+    # add a softspace unless we just printed a string which ends in a '\t'
+    # or '\n' -- or more generally any whitespace character but ' '
+    if isinstance(x, str) and x[-1].isspace() and x[-1]!=' ':
+        return
     # XXX add unicode handling
-    stream.write(str(x))
-    # XXX add softspaces
+    file_softspace(stream, True)
 
 def print_item(x):
     import sys
 
 def import_name(builtins, modulename, globals, locals, fromlist):
     try:
+        XXXXXXXXXXXXXXX
         import_ = builtins["__import__"]
     except KeyError:
         raise ImportError, "__import__ not found"

pypy/interpreter/pyframe.py

                             opcode.dispatch_noarg(self, op)
 
                     except baseobjspace.OperationError, e:
-                        #executioncontext.exception_trace(e)
+                        executioncontext.exception_trace(e)
                         # convert an OperationError into a reason to unroll
                         # the stack
                         if e.w_traceback is None:
-                            w_traceback = []
-                        else:
-                            w_traceback = e.w_traceback
+                            e.w_traceback = []
 
-                        w_traceback.append((self, self.lasti))
-                        raise SApplicationException(
-                            e.w_type, e.w_value, w_traceback)
+                        e.w_traceback.append((self, self.lasti))
+                        raise SApplicationException(e)
                     # XXX some other exceptions could be caught here too,
                     #     like KeyboardInterrupt
 
         freevarnames = self.bytecode.co_cellvars + self.bytecode.co_freevars
         return freevarnames[index]
 
+    def iscellvar(self, index):
+        # is the variable given by index a cell or a free var?
+        return index < len(self.bytecode.co_cellvars)
+
     ### frame initialization ###
 
     def setargs(self, w_arguments, w_kwargs=None,
             # looks like a simple case, see if we got exactly the correct
             # number of arguments
             try:
-                args = self.space.unpackiterable(w_arguments, co.co_argcount)
+                args = self.space.unpacktuple(w_arguments, co.co_argcount)
             except ValueError:
                 pass  # no
             else:
                                        w_closure, w_bytecode])
         # we assume that decode_frame_arguments() gives us a tuple
         # of the correct length.
-        return self.space.unpackiterable(w_arguments)
+        return self.space.unpacktuple(w_arguments)
 
     def load_builtins(self):
         # initialize self.w_builtins.  This cannot be done in the '.app.py'
         if isinstance(block, ExceptBlock):
             # push the exception to the value stack for inspection by the
             # exception handler (the code after the except:)
-            w_exc_type, w_exc_value, w_exc_traceback = self.args
-            frame.valuestack.push(w_exc_traceback)
-            frame.valuestack.push(w_exc_value)
-            frame.valuestack.push(w_exc_type)
+            operationerr = self.args[0]
+            frame.valuestack.push(operationerr.w_traceback)
+            frame.valuestack.push(operationerr.w_value)
+            frame.valuestack.push(operationerr.w_type)
             frame.next_instr = block.handlerposition   # jump to the handler
             
             # XXX
 
     def emptystack(self, frame):
         # propagate the exception to the caller
-        raise baseobjspace.OperationError(*self.args)
+        operationerr = self.args[0]
+        raise operationerr
 
 class SBreakLoop(StackUnroller):
     """Signals a 'break' statement."""

pypy/interpreter/pyframe_app.py

-from exceptions import TypeError
 
-"""
-Assumptions:
-args = sequence of the normal actual parameters
-kws = dictionary of keyword actual parameters
-defs = sequence of defaults
-"""
 def decode_frame_arguments(args, kws, defs, closure, codeobject):
+    """
+    Assumptions:
+    args = sequence of the normal actual parameters
+    kws = dictionary of keyword actual parameters
+    defs = sequence of defaults
+    """
     CO_VARARGS = 0x4
     CO_VARKEYWORDS = 0x8
     varargs = (codeobject.co_flags & CO_VARARGS) and 1

pypy/interpreter/test/test_interpreter.py

         named by 'functionname' with arguments 'args'."""
         from pypy.interpreter import baseobjspace, executioncontext, appfile
 
-        bytecode = compile(code, '<test>', 'exec')
+        bytecode = executioncontext.inlinecompile(code)
         apphelper = appfile.AppHelper(self.space, bytecode)
 
         wrappedargs = [self.space.wrap(arg) for arg in args]
         try:
             w_output = apphelper.call(functionname, wrappedargs)
         except baseobjspace.OperationError, e:
-            print e.w_traceback
+            e.print_detailed_traceback(self.space)
+            return '<<<%s>>>' % e.errorstr(self.space)
         else:
             return self.space.unwrap(w_output)
 
 def f():
     raise 1
 ''', 'f', [])
-            
+        self.assertEquals(x, '<<<TypeError: exceptions must be classes, instances, or strings (deprecated), not int>>>')
+
 
 if __name__ == '__main__':
     unittest.main()

pypy/objspace/std/__init__.py

-# empty
+from objspace import StdObjSpace

pypy/objspace/std/cpythonobject.py

     return w_obj.cpyobj
 
 StdObjSpace.unwrap.register(cpython_unwrap, W_CPythonObject)
+
+def cpython_id(space, w_obj):
+    return space.wrap(id(w_obj.cpyobj))
+
+StdObjSpace.id.register(cpython_id, W_CPythonObject)

pypy/objspace/std/dictobject.py

 def getitem_dict_any(space, w_dict, w_lookup):
     data = w_dict.data
     for w_key, w_value in data:
-        if space.is_true(space.compare(w_lookup, w_key, '==')):
+        if space.is_true(space.eq(w_lookup, w_key)):
             return w_value
     raise OperationError(space.w_KeyError, w_lookup)
 
     data = w_dict.data
     for i in range(len(data)):
         w_key, w_value = data[i]
-        if space.is_true(space.compare(w_newkey, w_key, '==')):
+        if space.is_true(space.eq(w_newkey, w_key)):
             # replace existing value
             data[i] = w_key, w_newvalue
+            #print 'dict replace %s:' % w_newkey, data
             return
     # add new (key,value) pair
     data.append((w_newkey, w_newvalue))
+    #print 'dict append %s:' % w_newkey, data
 
 StdObjSpace.setitem.register(setitem_dict_any_any, W_DictObject, W_ANY, W_ANY)

pypy/objspace/std/funcobject.py

     w_locals = space.newdict([])
     frame = pypy.interpreter.pyframe.PyFrame(space, bytecode,
                                              w_function.w_globals, w_locals)
-    import sys; print >> sys.stderr, '((((((((((((((((('
     frame.setargs(w_arguments, w_keywords,
                   w_defaults = w_function.w_defaultarguments,
                   w_closure = w_function.w_closure)
-    import sys; print >> sys.stderr, ')))))))))))))))))'
     w_result = ec.eval_frame(frame)
     return w_result
 

pypy/objspace/std/intobject.py

 ##
 ##StdObjSpace.cmp.register(int_int_cmp, W_IntObject, W_IntObject)
 
-def int_int_compare(space, w_int1, w_int2, op):
+def int_int_lt(space, w_int1, w_int2):
     i = w_int1.intval
     j = w_int2.intval
-    if   op == '<':  return space.newbool( i < j  )
-    elif op == '<=': return space.newbool( i <= j )
-    elif op == '==': return space.newbool( i == j )
-    elif op == '!=': return space.newbool( i != j )
-    elif op == '>':  return space.newbool( i > j  )
-    elif op == '>=': return space.newbool( i >= j )
-    #elif op == 'in':           # n.a.
-    #elif op == 'not in':       # n.a.
-    #elip op == 'is': is_,      # elsewhere
-    #elif op == 'is not':       # elsewhere
-    #elif op == 'exc match':    # exceptions
-    else:
-        msg = 'integer comparison "%s" not implemented' % op
-        raise FailedToImplement(space.w_TypeError,
-                                space.wrap(msg))
+    return space.newbool( i < j )
+StdObjSpace.lt.register(int_int_lt, W_IntObject, W_IntObject)
 
-StdObjSpace.compare.register(int_int_compare, W_IntObject, W_IntObject)
+def int_int_le(space, w_int1, w_int2):
+    i = w_int1.intval
+    j = w_int2.intval
+    return space.newbool( i <= j )
+StdObjSpace.le.register(int_int_le, W_IntObject, W_IntObject)
+
+def int_int_eq(space, w_int1, w_int2):
+    i = w_int1.intval
+    j = w_int2.intval
+    return space.newbool( i == j )
+StdObjSpace.eq.register(int_int_eq, W_IntObject, W_IntObject)
+
+def int_int_ne(space, w_int1, w_int2):
+    i = w_int1.intval
+    j = w_int2.intval
+    return space.newbool( i != j )
+StdObjSpace.ne.register(int_int_ne, W_IntObject, W_IntObject)
+
+def int_int_gt(space, w_int1, w_int2):
+    i = w_int1.intval
+    j = w_int2.intval
+    return space.newbool( i > j )
+StdObjSpace.gt.register(int_int_gt, W_IntObject, W_IntObject)
+
+def int_int_ge(space, w_int1, w_int2):
+    i = w_int1.intval
+    j = w_int2.intval
+    return space.newbool( i >= j )
+StdObjSpace.ge.register(int_int_ge, W_IntObject, W_IntObject)
 
 def int_hash(space, w_int1):
     #/* XXX If this is changed, you also need to change the way
     #   Python's long, float and complex types are hashed. */
-    x = w_int1.intval
-    if x == -1:
-        x = -2
-    return W_IntObject(x)
+##    x = w_int1.intval
+##    if x == -1:
+##        x = -2
+##    return W_IntObject(x)
+    # XXX unlike CPython we have no need to special-case the value -1
+    return w_int1
 
 StdObjSpace.hash.register(int_hash, W_IntObject)
 

pypy/objspace/std/objspace.py

             if isinstance(c, types.ClassType) and issubclass(c, Exception):
                 w_c = W_CPythonObject(c)
                 setattr(self, 'w_' + c.__name__, w_c)
+                self.setitem(self.w_builtins, self.wrap(c.__name__), w_c)
 
     def wrap(self, x):
         "Wraps the Python value 'x' into one of the wrapper classes."
         return funcobject.W_FuncObject(w_code, w_globals,
                                        w_defaultarguments, w_closure)
 
-    def newbool(self, b):
-        if b:
-            return self.w_True
-        else:
-            return self.w_False
-
     # special multimethods
     unwrap  = MultiMethod('unwrap', 1)   # returns an unwrapped object
-    hash    = MultiMethod('hash', 1)     # returns an unwrapped int
-    is_true = MultiMethod('true?', 1)    # returns an unwrapped bool
-    compare = MultiMethod('compare', 2)  # extra 3rd arg is a Python string
+    is_true = MultiMethod('nonzero', 1)  # returns an unwrapped bool
 
-    # handling of the common fall-back cases
-    def compare_any_any(self, w_1, w_2, operation):
-        if operation == "is":
-            return self.newbool(w_1 == w_2)
-        elif operation == "is not":
-            return self.newbool(w_1 != w_2)
-        else:
-            raise FailedToImplement(self.w_TypeError,
-                                    "unknown comparison operator %r" % operation)
+##    # handling of the common fall-back cases
+##    def compare_any_any(self, w_1, w_2, operation):
+##        if operation == "is":
+##            return self.newbool(w_1 == w_2)
+##        elif operation == "is not":
+##            return self.newbool(w_1 != w_2)
+##        else:
+##            raise FailedToImplement(self.w_TypeError,
+##                                    "unknown comparison operator %r" % operation)
         
-    compare.register(compare_any_any, W_ANY, W_ANY)
+##    compare.register(compare_any_any, W_ANY, W_ANY)
 
 
 # add all regular multimethods to StdObjSpace

pypy/objspace/std/stringobject.py

 
 StdObjSpace.unwrap.register(str_unwrap, W_StringObject)
 
-def str_str_compare(space, w_str1, w_str2, op):
+def str_str_lt(space, w_str1, w_str2):
     i = w_str1.value
     j = w_str2.value
-    if   op == '<':  return space.newbool( i < j  )
-    elif op == '<=': return space.newbool( i <= j )
-    elif op == '==': return space.newbool( i == j )
-    elif op == '!=': return space.newbool( i != j )
-    elif op == '>':  return space.newbool( i > j  )
-    elif op == '>=': return space.newbool( i >= j )
-    #elif op == 'in':           # n.a.
-    #elif op == 'not in':       # n.a.
-    #elip op == 'is': is_,      # elsewhere
-    #elif op == 'is not':       # elsewhere
-    #elif op == 'exc match':    # exceptions
-    else:
-        msg = 'string comparison "%s" not implemented' % op
-        raise FailedToImplement(space.w_TypeError,
-                                space.wrap(msg))
+    return space.newbool( i < j )
+StdObjSpace.lt.register(str_str_lt, W_StringObject, W_StringObject)
 
-StdObjSpace.compare.register(str_str_compare, W_StringObject, W_StringObject)
+def str_str_le(space, w_str1, w_str2):
+    i = w_str1.value
+    j = w_str2.value
+    return space.newbool( i <= j )
+StdObjSpace.le.register(str_str_le, W_StringObject, W_StringObject)
+
+def str_str_eq(space, w_str1, w_str2):
+    i = w_str1.value
+    j = w_str2.value
+    return space.newbool( i == j )
+StdObjSpace.eq.register(str_str_eq, W_StringObject, W_StringObject)
+
+def str_str_ne(space, w_str1, w_str2):
+    i = w_str1.value
+    j = w_str2.value
+    return space.newbool( i != j )
+StdObjSpace.ne.register(str_str_ne, W_StringObject, W_StringObject)
+
+def str_str_gt(space, w_str1, w_str2):
+    i = w_str1.value
+    j = w_str2.value
+    return space.newbool( i > j )
+StdObjSpace.gt.register(str_str_gt, W_StringObject, W_StringObject)
+
+def str_str_ge(space, w_str1, w_str2):
+    i = w_str1.value
+    j = w_str2.value
+    return space.newbool( i >= j )
+StdObjSpace.ge.register(str_str_ge, W_StringObject, W_StringObject)
+
 
 def getitem_str_int(space, w_str, w_int):
     return W_StringObject(w_str.value[w_int.intval])

pypy/objspace/std/test/test_intobject.py

 
     def test_compare(self):
         import operator
-        optab = {
-            '<':  operator.lt,
-            '<=': operator.le,
-            '==': operator.eq,
-            '!=': operator.ne,
-            '>':  operator.gt,
-            '>=': operator.ge,
-        }
+        optab = ['lt', 'le', 'eq', 'ne', 'gt', 'ge']
         for x in (-10, -1, 0, 1, 2, 1000, sys.maxint):
             for y in (-sys.maxint-1, -11, -9, -2, 0, 1, 3, 1111, sys.maxint):
                 for op in optab:
                     wx = iobj.W_IntObject(x)
                     wy = iobj.W_IntObject(y)
-                    res = optab[op](x, y)
-                    myres = iobj.int_int_compare(self.space, wx, wy, op)
+                    res = getattr(operator, op)(x, y)
+                    method = getattr(iobj, 'int_int_%s' % op)
+                    myres = method(self.space, wx, wy)
                     self.assertEquals(self.space.unwrap(myres), res)
                     
     def test_add(self):
         result = iobj.int_int(self.space, f1)
         self.assertEquals(result, f1)
 
-    def test_long(self):
-        x = 1
-        f1 = iobj.W_IntObject(x)
-        result = iobj.int_long(self.space, f1)
-        self.assertEquals(self.space.unwrap(result), long(x))
+##    def test_long(self):
+##        x = 1
+##        f1 = iobj.W_IntObject(x)
+##        result = iobj.int_long(self.space, f1)
+##        self.assertEquals(self.space.unwrap(result), long(x))
 
-    def test_float(self):
-        x = 1
-        f1 = iobj.W_IntObject(x)
-        result = iobj.int_float(self.space, f1)
-        self.assertEquals(self.space.unwrap(result), float(x))
+##    def test_float(self):
+##        x = 1
+##        f1 = iobj.W_IntObject(x)
+##        result = iobj.int_float(self.space, f1)
+##        self.assertEquals(self.space.unwrap(result), float(x))
 
     def test_oct(self):
         x = 012345

pypy/objspace/std/tupleobject.py

 from pypy.objspace.std.objspace import *
+from intobject import W_IntObject
 
 
 class W_TupleObject(object):
     return not not w_tuple.wrappeditems
 
 StdObjSpace.is_true.register(tuple_is_true, W_TupleObject)
+
+def tuple_len(space, w_tuple):
+    result = len(w_tuple.wrappeditems)
+    return W_IntObject(result)
+
+StdObjSpace.len.register(tuple_len, W_TupleObject)
+
+def tuple_getitem(space, w_tuple, w_index):
+    items = w_tuple.wrappeditems
+    w_item = items[w_index.intval]
+    return w_item
+
+StdObjSpace.getitem.register(tuple_getitem, W_TupleObject, W_IntObject)

pypy/objspace/trivial.py

         return w
 
     # from the built-ins
+    id        = id
     type      = type
-    #no used yet: checktype = isinstance  # no tuple of types is allowed in 'checktype'
+    issubtype = issubclass
     newtuple  = tuple
     newlist   = list
     newdict   = dict
     newslice  = slice  # maybe moved away to application-space at some time
     newmodule = new.module
-    getiter   = iter
+    iter      = iter
     repr      = repr
+    str       = str
+    len       = len
     pow       = pow
     hash      = hash
     setattr   = setattr
     for _name in ('pos', 'neg', 'not_', 'pos', 'neg', 'not_', 'invert',
                  'mul', 'truediv', 'floordiv', 'div', 'mod',
                  'add', 'sub', 'lshift', 'rshift', 'and_', 'xor', 'or_',
-                 'getitem', 'setitem', 'delitem'):
+                 'getitem', 'setitem', 'delitem', 'contains',
+                  'lt', 'le', 'eq', 'ne', 'gt', 'ge'):
         exec """
 def %(_name)s(self, *args):
     try:
             return ec.eval_frame(frame)
         else:
             return apply(callable, args, kwds)
-
-    # comparisons
-    def in_(w1, w2):
-        return w1 in w2
-
-    def not_in(w1, w2):
-        return w1 not in w2
-
-    def is_(w1, w2):
-        return w1 is w2
-
-    def is_not(w1, w2):
-        return w1 is not w2
-
-    def exc_match(w1, w2):
-        try:
-            try:
-                raise w1
-            except w2:
-                return True
-        except:
-            return False
-
-    operation_by_name = {
-        '<':  operator.lt,
-        '<=': operator.le,
-        '==': operator.eq,
-        '!=': operator.ne,
-        '>':  operator.gt,
-        '>=': operator.ge,
-        'in': in_,
-        'not in': not_in,
-        'is': is_,
-        'is not': is_not,
-        'exc match': exc_match,
-        }
-
-    def compare(self, w1, w2, operation):
-        fn = self.operation_by_name[operation]
-        return fn(w1, w2)