[pypy-svn] r69002 - in pypy/branch/avm/pypy: . interpreter interpreter/test module objspace/std objspace/std/test
magcius at codespeak.net
magcius at codespeak.net
Thu Nov 5 20:27:33 CET 2009
Author: magcius
Date: Thu Nov 5 20:27:32 2009
New Revision: 69002
Added:
pypy/branch/avm/pypy/TODO
- copied unchanged from r4823, pypy/trunk/src/pypy/TODO
pypy/branch/avm/pypy/interpreter/autopath.py
- copied unchanged from r4823, pypy/trunk/src/pypy/interpreter/autopath.py
pypy/branch/avm/pypy/interpreter/extmodule.py
- copied unchanged from r4823, pypy/trunk/src/pypy/interpreter/extmodule.py
pypy/branch/avm/pypy/interpreter/py.py
- copied unchanged from r4823, pypy/trunk/src/pypy/interpreter/py.py
pypy/branch/avm/pypy/interpreter/test/autopath.py
- copied unchanged from r4823, pypy/trunk/src/pypy/interpreter/test/autopath.py
pypy/branch/avm/pypy/interpreter/test/foomodule.py
- copied unchanged from r4823, pypy/trunk/src/pypy/interpreter/test/foomodule.py
pypy/branch/avm/pypy/interpreter/test/test_extmodule.py
- copied unchanged from r4823, pypy/trunk/src/pypy/interpreter/test/test_extmodule.py
pypy/branch/avm/pypy/interpreter/unittest_w.py
- copied unchanged from r4823, pypy/trunk/src/pypy/interpreter/unittest_w.py
pypy/branch/avm/pypy/module/__builtin__interp.py
- copied unchanged from r4823, pypy/trunk/src/pypy/module/__builtin__interp.py
pypy/branch/avm/pypy/module/__builtin__module.py
- copied unchanged from r4823, pypy/trunk/src/pypy/module/__builtin__module.py
pypy/branch/avm/pypy/module/sysinterp.py
- copied unchanged from r4823, pypy/trunk/src/pypy/module/sysinterp.py
pypy/branch/avm/pypy/module/sysmodule.py
- copied unchanged from r4823, pypy/trunk/src/pypy/module/sysmodule.py
pypy/branch/avm/pypy/objspace/std/test/broken_test_floatobject.py
- copied unchanged from r4823, pypy/trunk/src/pypy/objspace/std/test/broken_test_floatobject.py
pypy/branch/avm/pypy/objspace/std/userobject.py
- copied unchanged from r4823, pypy/trunk/src/pypy/objspace/std/userobject.py
Modified:
pypy/branch/avm/pypy/ (props changed)
pypy/branch/avm/pypy/interpreter/ (props changed)
pypy/branch/avm/pypy/interpreter/baseobjspace.py
pypy/branch/avm/pypy/interpreter/executioncontext.py
pypy/branch/avm/pypy/interpreter/interactive.py
pypy/branch/avm/pypy/interpreter/pyframe.py
pypy/branch/avm/pypy/interpreter/test/test_interpreter.py
pypy/branch/avm/pypy/objspace/std/intobject.py
pypy/branch/avm/pypy/objspace/std/listobject.py
pypy/branch/avm/pypy/objspace/std/noneobject.py
pypy/branch/avm/pypy/objspace/std/sliceobject.py
pypy/branch/avm/pypy/objspace/std/stringobject.py
pypy/branch/avm/pypy/objspace/std/test/test_multimethod.py
Log:
Finally. More work on AVM2.
Modified: pypy/branch/avm/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/avm/pypy/interpreter/baseobjspace.py (original)
+++ pypy/branch/avm/pypy/interpreter/baseobjspace.py Thu Nov 5 20:27:32 2009
@@ -1,594 +1,130 @@
-from pypy.interpreter.executioncontext import ExecutionContext, ActionFlag
-from pypy.interpreter.executioncontext import UserDelAction, FrameTraceAction
+from pypy.interpreter.executioncontext import ExecutionContext
from pypy.interpreter.error import OperationError
-from pypy.interpreter.argument import Arguments, ArgumentsFromValuestack
-from pypy.interpreter.pycompiler import CPythonCompiler, PythonAstCompiler
-from pypy.interpreter.miscutils import ThreadLocals
-from pypy.tool.cache import Cache
-from pypy.tool.uid import HUGEVAL_BYTES
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.debug import make_sure_not_resized
-from pypy.rlib.timer import DummyTimer, Timer
-import os, sys
-
-__all__ = ['ObjSpace', 'OperationError', 'Wrappable', 'W_Root']
-
-
-class W_Root(object):
- """This is the abstract root class of all wrapped objects that live
- in a 'normal' object space like StdObjSpace."""
- __slots__ = ()
- _settled_ = True
-
- def getdict(self):
- return None
-
- def getdictvalue_w(self, space, attr):
- return self.getdictvalue(space, space.wrap(attr))
-
- def getdictvalue(self, space, w_attr):
- w_dict = self.getdict()
- if w_dict is not None:
- return space.finditem(w_dict, w_attr)
- return None
-
- def getdictvalue_attr_is_in_class(self, space, w_attr):
- return self.getdictvalue(space, w_attr)
-
- def setdictvalue(self, space, w_attr, w_value, shadows_type=True):
- w_dict = self.getdict()
- if w_dict is not None:
- space.set_str_keyed_item(w_dict, w_attr, w_value, shadows_type)
- return True
- return False
+from pypy.interpreter.miscutils import Stack, getthreadlocals
+import pypy.module
- def deldictvalue(self, space, w_name):
- w_dict = self.getdict()
- if w_dict is not None:
- try:
- space.delitem(w_dict, w_name)
- return True
- except OperationError, ex:
- if not ex.match(space, space.w_KeyError):
- raise
- return False
+__all__ = ['ObjSpace', 'OperationError', 'NoValue']
- def setdict(self, space, w_dict):
- typename = space.type(self).getname(space, '?')
- raise OperationError(space.w_TypeError,
- space.wrap("attribute '__dict__' of %s objects "
- "is not writable" % typename))
-
- # to be used directly only by space.type implementations
- def getclass(self, space):
- return space.gettypeobject(self.typedef)
-
- def setclass(self, space, w_subtype):
- raise OperationError(space.w_TypeError,
- space.wrap("__class__ assignment: only for heap types"))
- def user_setup(self, space, w_subtype):
- assert False, "only for interp-level user subclasses from typedef.py"
+class Wrappable(object):
+ """A subclass of Wrappable is an internal, interpreter-level class
+ that can nevertheless be exposed at application-level by space.wrap()."""
- def getname(self, space, default):
+ def get_wdict(self):
+ space = self.space
try:
- return space.str_w(space.getattr(self, space.wrap('__name__')))
- except OperationError, e:
- if e.match(space, space.w_TypeError) or e.match(space, space.w_AttributeError):
- return default
- raise
-
- def getaddrstring(self, space):
- # XXX slowish
- w_id = space.id(self)
- w_4 = space.wrap(4)
- w_0x0F = space.wrap(0x0F)
- i = 2 * HUGEVAL_BYTES
- addrstring = [' '] * i
- while True:
- n = space.int_w(space.and_(w_id, w_0x0F))
- n += ord('0')
- if n > ord('9'):
- n += (ord('a') - ord('9') - 1)
- i -= 1
- addrstring[i] = chr(n)
- if i == 0:
- break
- w_id = space.rshift(w_id, w_4)
- return ''.join(addrstring)
-
- def getrepr(self, space, info, moreinfo=''):
- addrstring = self.getaddrstring(space)
- return space.wrap("<%s at 0x%s%s>" % (info, addrstring,
- moreinfo))
-
- def getslotvalue(self, index):
- raise NotImplementedError
+ return self.w_dict
+ except AttributeError:
+ w_dict = self.w_dict = space.newdict([])
+ for name,w_value in self.app_visible():
+ space.setitem(w_dict,space.wrap(name),w_value)
+ return w_dict
- def setslotvalue(self, index, w_val):
+ def app_visible(self):
+ """ returns [(name,w_value)...] for application-level visible attributes """
raise NotImplementedError
- def descr_call_mismatch(self, space, opname, RequiredClass, args):
- if RequiredClass is None:
- classname = '?'
- else:
- classname = wrappable_class_name(RequiredClass)
- msg = "'%s' object expected, got '%s' instead" % (
- classname, self.getclass(space).getname(space, '?'))
- raise OperationError(space.w_TypeError, space.wrap(msg))
-
- # used by _weakref implemenation
-
- def getweakref(self):
- return None
-
- def setweakref(self, space, weakreflifeline):
- typename = space.type(self).getname(space, '?')
- raise OperationError(space.w_TypeError, space.wrap(
- "cannot create weak reference to '%s' object" % typename))
-
- def clear_all_weakrefs(self):
- """Call this at the beginning of interp-level __del__() methods
- in subclasses. It ensures that weakrefs (if any) are cleared
- before the object is further destroyed.
- """
- lifeline = self.getweakref()
- if lifeline is not None:
- # Clear all weakrefs to this object before we proceed with
- # the destruction of the object. We detach the lifeline
- # first: if the code following before_del() calls the
- # app-level, e.g. a user-defined __del__(), and this code
- # tries to use weakrefs again, it won't reuse the broken
- # (already-cleared) weakrefs from this lifeline.
- self.setweakref(lifeline.space, None)
- lifeline.clear_all_weakrefs()
-
- __already_enqueued_for_destruction = False
-
- def _enqueue_for_destruction(self, space):
- """Put the object in the destructor queue of the space.
- At a later, safe point in time, UserDelAction will use
- space.userdel() to call the object's app-level __del__ method.
- """
- # this function always resurect the object, so when
- # running on top of CPython we must manually ensure that
- # we enqueue it only once
- if not we_are_translated():
- if self.__already_enqueued_for_destruction:
- return
- self.__already_enqueued_for_destruction = True
- self.clear_all_weakrefs()
- space.user_del_action.register_dying_object(self)
-
- def _call_builtin_destructor(self):
- pass # method overridden in typedef.py
-
+ def pypy_getattr(self, w_name):
+ space = self.space
+ w_dict = self.get_wdict()
+ try:
+ return space.getitem(w_dict,w_name)
+ except OperationError,e:
+ if not e.match(space,space.w_KeyError):
+ raise
+ raise OperationError(space.w_AttributeError,w_name)
-class Wrappable(W_Root):
- """A subclass of Wrappable is an internal, interpreter-level class
- that can nevertheless be exposed at application-level by space.wrap()."""
- __slots__ = ()
- _settled_ = True
- def __spacebind__(self, space):
- return self
+class NoValue(Exception):
+ """Raised to signal absence of value, e.g. in the iterator accessing
+ method 'op.next()' of object spaces."""
-class InternalSpaceCache(Cache):
- """A generic cache for an object space. Arbitrary information can
- be attached to the space by defining a function or class 'f' which
- can be called as 'f(space)'. Its result is stored in this
- ObjSpaceCache.
- """
- def __init__(self, space):
- Cache.__init__(self)
- self.space = space
- def _build(self, callable):
- return callable(self.space)
-
-class SpaceCache(Cache):
- """A base class for all our concrete caches."""
- def __init__(self, space):
- Cache.__init__(self)
- self.space = space
- def _build(self, key):
- val = self.space.enter_cache_building_mode()
- try:
- return self.build(key)
- finally:
- self.space.leave_cache_building_mode(val)
- def _ready(self, result):
- val = self.space.enter_cache_building_mode()
- try:
- return self.ready(result)
- finally:
- self.space.leave_cache_building_mode(val)
- def ready(self, result):
- pass
-
-class UnpackValueError(ValueError):
- def __init__(self, msg):
- self.msg = msg
- def __str__(self):
- return self.msg
-
-class DescrMismatch(Exception):
- pass
-
-def wrappable_class_name(Class):
- try:
- return Class.typedef.name
- except AttributeError:
- return 'internal subclass of %s' % (Class.__name__,)
-wrappable_class_name._annspecialcase_ = 'specialize:memo'
-# ____________________________________________________________
-
-class ObjSpace(object):
+class ObjSpace:
"""Base class for the interpreter-level implementations of object spaces.
- http://codespeak.net/pypy/dist/pypy/doc/objspace.html"""
-
+ http://codespeak.net/moin/pypy/moin.cgi/ObjectSpace"""
+
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
- self.threadlocals = ThreadLocals()
- # set recursion limit
- # sets all the internal descriptors
- if config is None:
- from pypy.config.pypyoption import get_pypy_config
- config = get_pypy_config(translating=False)
- self.config = config
-
- # import extra modules for side-effects
- import pypy.interpreter.nestedscope # register *_DEREF bytecodes
-
- self.interned_strings = {}
- self.actionflag = ActionFlag() # changed by the signal module
- self.user_del_action = UserDelAction(self)
- self.frame_trace_action = FrameTraceAction(self)
- self.actionflag.register_action(self.user_del_action)
- self.actionflag.register_action(self.frame_trace_action)
-
- from pypy.interpreter.pyframe import PyFrame
- self.FrameClass = PyFrame # can be overridden to a subclass
-
- if self.config.objspace.logbytecodes:
- self.bytecodecounts = [0] * 256
- self.bytecodetransitioncount = {}
-
- if self.config.objspace.timing:
- self.timer = Timer()
- else:
- self.timer = DummyTimer()
-
+ def __init__(self):
+ "Basic initialization of objects."
self.initialize()
- def startup(self):
- # To be called before using the space
-
- # Initialize all builtin modules
- from pypy.interpreter.module import Module
- for w_modname in self.unpackiterable(
- self.sys.get('builtin_module_names')):
- modname = self.str_w(w_modname)
- mod = self.interpclass_w(self.getbuiltinmodule(modname))
- if isinstance(mod, Module):
- import time
- self.timer.start("startup " + modname)
- mod.startup(self)
- self.timer.stop("startup " + modname)
-
- def finish(self):
- w_exitfunc = self.sys.getdictvalue_w(self, 'exitfunc')
- if w_exitfunc is not None:
- self.call_function(w_exitfunc)
- from pypy.interpreter.module import Module
- for w_modname in self.unpackiterable(
- self.sys.get('builtin_module_names')):
- modname = self.str_w(w_modname)
- mod = self.interpclass_w(self.getbuiltinmodule(modname))
- if isinstance(mod, Module):
- mod.shutdown(self)
- if self.config.objspace.std.withdictmeasurement:
- from pypy.objspace.std.dictmultiobject import report
- report()
- if self.config.objspace.logbytecodes:
- self.reportbytecodecounts()
- if self.config.objspace.std.logspaceoptypes:
- for s in self.FrameClass._space_op_types:
- print s
-
- def reportbytecodecounts(self):
- os.write(2, "Starting bytecode report.\n")
- fd = os.open('bytecode.txt', os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644)
- os.write(fd, "bytecodecounts = {\n")
- for opcode in range(len(self.bytecodecounts)):
- count = self.bytecodecounts[opcode]
- if not count:
- continue
- os.write(fd, " %s: %s,\n" % (opcode, count))
- os.write(fd, "}\n")
- os.write(fd, "bytecodetransitioncount = {\n")
- for opcode, probs in self.bytecodetransitioncount.iteritems():
- os.write(fd, " %s: {\n" % (opcode, ))
- for nextcode, count in probs.iteritems():
- os.write(fd, " %s: %s,\n" % (nextcode, count))
- os.write(fd, " },\n")
- os.write(fd, "}\n")
- os.close(fd)
- os.write(2, "Reporting done.\n")
-
- def __repr__(self):
- try:
- return self._this_space_repr_
- except AttributeError:
- return self.__class__.__name__
-
- def setbuiltinmodule(self, importname):
- """NOT_RPYTHON. load a lazy pypy/module and put it into sys.modules"""
- import sys
-
- fullname = "pypy.module.%s" % importname
-
- Module = __import__(fullname,
- None, None, ["Module"]).Module
- if Module.applevel_name is not None:
- name = Module.applevel_name
- else:
- name = importname
-
- w_name = self.wrap(name)
- w_mod = self.wrap(Module(self, w_name))
- w_modules = self.sys.get('modules')
- self.setitem(w_modules, w_name, w_mod)
- return name
-
- def getbuiltinmodule(self, name):
- w_name = self.wrap(name)
- w_modules = self.sys.get('modules')
- return self.getitem(w_modules, w_name)
-
- def get_builtinmodule_to_install(self):
- """NOT_RPYTHON"""
- try:
- return self._builtinmodule_list
- except AttributeError:
- pass
-
- modules = []
-
- # You can enable more modules by specifying --usemodules=xxx,yyy
- for name, value in self.config.objspace.usemodules:
- if value and name not in modules:
- modules.append(name)
-
- # a bit of custom logic: time2 or rctime take precedence over time
- # XXX this could probably be done as a "requires" in the config
- if ('time2' in modules or 'rctime' in modules) and 'time' in modules:
- modules.remove('time')
-
- import pypy
- if not self.config.objspace.nofaking:
- for modname in self.ALL_BUILTIN_MODULES:
- if not (os.path.exists(
- os.path.join(os.path.dirname(pypy.__file__),
- 'lib', modname+'.py'))):
- modules.append('faked+'+modname)
-
- self._builtinmodule_list = modules
- return self._builtinmodule_list
-
- ALL_BUILTIN_MODULES = [
- 'posix', 'nt', 'os2', 'mac', 'ce', 'riscos',
- 'math', 'array', 'select',
- '_random', '_sre', 'time', '_socket', 'errno',
- 'unicodedata',
- 'parser', 'fcntl', '_codecs', 'binascii'
- ]
-
def make_builtins(self):
- "NOT_RPYTHON: only for initializing the space."
-
- from pypy.module.sys import Module
- w_name = self.wrap('sys')
- self.sys = Module(self, w_name)
- w_modules = self.sys.get('modules')
- self.setitem(w_modules, w_name, self.wrap(self.sys))
-
- from pypy.module.__builtin__ import Module
- w_name = self.wrap('__builtin__')
- self.builtin = Module(self, w_name)
- w_builtin = self.wrap(self.builtin)
- self.setitem(w_modules, w_name, w_builtin)
- self.setitem(self.builtin.w_dict, self.wrap('__builtins__'), w_builtin)
-
- bootstrap_modules = ['sys', '__builtin__', 'exceptions']
- installed_builtin_modules = bootstrap_modules[:]
+ # initializing builtins may require creating a frame which in
+ # turn already accesses space.w_builtins, provide a dummy one ...
+ self.w_builtins = self.newdict([])
+
+ assert not hasattr(self, 'builtin')
+ if not hasattr(self, 'sys'):
+ self.make_sys()
+
+ from pypy.interpreter.extmodule import BuiltinModule
+
+ # the builtins are iteratively initialized
+ self.builtin = BuiltinModule(self, '__builtin__', self.w_builtins)
+ self.w_builtin = self.wrap(self.builtin)
# initialize with "bootstrap types" from objspace (e.g. w_None)
for name, value in self.__dict__.items():
- if name.startswith('w_') and not name.endswith('Type'):
+ if name.startswith('w_'):
name = name[2:]
+ if name.startswith('builtin') or name.startswith('sys'):
+ continue
#print "setitem: space instance %-20s into builtins" % name
- self.setitem(self.builtin.w_dict, self.wrap(name), value)
+ self.setitem(self.w_builtins, self.wrap(name), value)
- # install mixed and faked modules and set builtin_module_names on sys
- for mixedname in self.get_builtinmodule_to_install():
- if (mixedname not in bootstrap_modules
- and not mixedname.startswith('faked+')):
- self.install_mixedmodule(mixedname, installed_builtin_modules)
- for mixedname in self.get_builtinmodule_to_install():
- if mixedname.startswith('faked+'):
- modname = mixedname[6:]
- self.install_faked_module(modname, installed_builtin_modules)
-
- installed_builtin_modules.sort()
- w_builtin_module_names = self.newtuple(
- [self.wrap(fn) for fn in installed_builtin_modules])
-
- # force this value into the dict without unlazyfying everything
- self.setitem(self.sys.w_dict, self.wrap('builtin_module_names'),
- w_builtin_module_names)
-
- def install_mixedmodule(self, mixedname, installed_builtin_modules):
- """NOT_RPYTHON"""
- modname = self.setbuiltinmodule(mixedname)
- if modname:
- assert modname not in installed_builtin_modules, (
- "duplicate interp-level module enabled for the "
- "app-level module %r" % (modname,))
- installed_builtin_modules.append(modname)
-
- def load_cpython_module(self, modname):
- "NOT_RPYTHON. Steal a module from CPython."
- cpy_module = __import__(modname, {}, {}, ['*'])
- return cpy_module
-
- def install_faked_module(self, modname, installed_builtin_modules):
- """NOT_RPYTHON"""
- if modname in installed_builtin_modules:
- return
- try:
- module = self.load_cpython_module(modname)
- except ImportError:
- return
- else:
- w_modules = self.sys.get('modules')
- self.setitem(w_modules, self.wrap(modname), self.wrap(module))
- installed_builtin_modules.append(modname)
-
- def setup_builtin_modules(self):
- "NOT_RPYTHON: only for initializing the space."
- from pypy.interpreter.module import Module
- for w_modname in self.unpackiterable(self.sys.get('builtin_module_names')):
- modname = self.unwrap(w_modname)
- mod = self.getbuiltinmodule(modname)
- if isinstance(mod, Module):
- mod.setup_after_space_initialization()
+ self.sys.setbuiltinmodule(self.w_builtin, '__builtin__')
- def initialize(self):
- """NOT_RPYTHON: Abstract method that should put some minimal
- content into the w_builtins."""
+ def make_sys(self):
+ from pypy.interpreter.extmodule import BuiltinModule
+ assert not hasattr(self, 'sys')
+ self.sys = BuiltinModule(self, 'sys')
+ self.w_sys = self.wrap(self.sys)
+ self.sys.setbuiltinmodule(self.w_sys, 'sys')
+
+ def get_builtin_module(self, name):
+ if name not in self.sys.builtin_modules:
+ return None
+ module = self.sys.builtin_modules[name]
+ if module is None:
+ from pypy.interpreter.extmodule import BuiltinModule
+ module = BuiltinModule(self, name)
+ self.sys.builtin_modules[name] = module
+ w_module = self.wrap(module)
+ self.sys.setbuiltinmodule(w_module, name)
+ return w_module
- def enter_cache_building_mode(self):
- "hook for the flow object space"
- def leave_cache_building_mode(self, val):
- "hook for the flow object space"
+ def initialize(self):
+ """Abstract method that should put some minimal content into the
+ w_builtins."""
def getexecutioncontext(self):
"Return what we consider to be the active execution context."
- # Important: the annotator must not see a prebuilt ExecutionContext
- # for reasons related to the specialization of the framestack attribute
- # so we make sure that the threadlocals never *have* an
- # ExecutionContext during translation.
- if self.config.translating and not we_are_translated():
- assert self.threadlocals.getvalue() is None, (
- "threadlocals got an ExecutionContext during translation!")
- try:
- return self._ec_during_translation
- except AttributeError:
- ec = self.createexecutioncontext()
- self._ec_during_translation = ec
- return ec
- # normal case follows. The 'thread' module installs a real
- # thread-local object in self.threadlocals, so this builds
- # and caches a new ec in each thread.
- ec = self.threadlocals.getvalue()
+ ec = getthreadlocals().executioncontext #it's allways None (dec. 2003)
if ec is None:
ec = self.createexecutioncontext()
- self.threadlocals.setvalue(ec)
return ec
- def _freeze_(self):
- return True
-
def createexecutioncontext(self):
"Factory function for execution contexts."
return ExecutionContext(self)
- def createcompiler(self):
- "Factory function creating a compiler object."
- # XXX simple selection logic for now
- try:
- return self.default_compiler
- except AttributeError:
- if self.config.objspace.compiler == 'cpython':
- compiler = CPythonCompiler(self)
- elif self.config.objspace.compiler == 'ast':
- compiler = PythonAstCompiler(self)
- else:
- raise ValueError('unknown --compiler option value: %r' % (
- self.config.objspace.compiler,))
- self.default_compiler = compiler
- return compiler
-
- def createframe(self, code, w_globals, closure=None):
- "Create an empty PyFrame suitable for this code object."
- return self.FrameClass(self, code, w_globals, closure)
-
- def allocate_lock(self):
- """Return an interp-level Lock object if threads are enabled,
- and a dummy object if they are not."""
- if self.config.objspace.usemodules.thread:
- # we use a sub-function to avoid putting the 'import' statement
- # here, where the flow space would see it even if thread=False
- return self.__allocate_lock()
- else:
- return dummy_lock
-
- def __allocate_lock(self):
- from pypy.module.thread.ll_thread import allocate_lock, error
- try:
- return allocate_lock()
- except error:
- raise OperationError(self.w_RuntimeError,
- self.wrap("out of resources"))
-
# Following is a friendly interface to common object space operations
# 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): -- not really useful. Must be subclassed
- # "'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 not_(self, w_obj):
- return self.wrap(not self.is_true(w_obj))
-
- def eq_w(self, w_obj1, w_obj2):
- """shortcut for space.is_true(space.eq(w_obj1, w_obj2))"""
- return self.is_w(w_obj1, w_obj2) or self.is_true(self.eq(w_obj1, w_obj2))
-
- def is_w(self, w_obj1, w_obj2):
- """shortcut for space.is_true(space.is_(w_obj1, w_obj2))"""
- return self.is_true(self.is_(w_obj1, w_obj2))
-
- def hash_w(self, w_obj):
- """shortcut for space.int_w(space.hash(w_obj))"""
- return self.int_w(self.hash(w_obj))
-
- def set_str_keyed_item(self, w_obj, w_key, w_value, shadows_type=True):
- return self.setitem(w_obj, w_key, w_value)
-
- def finditem(self, w_obj, w_key):
- try:
- return self.getitem(w_obj, w_key)
- except OperationError, e:
- if e.match(self, self.w_KeyError):
- return None
- raise
-
- def findattr(self, w_object, w_name):
- try:
- return self.getattr(w_object, w_name)
- except OperationError, e:
- # a PyPy extension: let SystemExit and KeyboardInterrupt go through
- if e.async(self):
- raise
- return None
+ 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 unwrapdefault(self, w_value, default):
+ if w_value is None or w_value == self.w_None:
+ return default
+ else:
+ return self.unwrap(w_value)
def newbool(self, b):
if b:
@@ -596,462 +132,78 @@
else:
return self.w_False
- def new_interned_w_str(self, w_s):
- s = self.str_w(w_s)
- try:
- return self.interned_strings[s]
- except KeyError:
- pass
- self.interned_strings[s] = w_s
- return w_s
-
- def new_interned_str(self, s):
- try:
- return self.interned_strings[s]
- except KeyError:
- pass
- w_s = self.interned_strings[s] = self.wrap(s)
- return w_s
-
- def interpclass_w(space, w_obj):
- """
- If w_obj is a wrapped internal interpreter class instance unwrap to it,
- otherwise return None. (Can be overridden in specific spaces; you
- should generally use the helper space.interp_w() instead.)
- """
- if isinstance(w_obj, Wrappable):
- return w_obj
- return None
-
- def descr_self_interp_w(self, RequiredClass, w_obj):
- obj = self.interpclass_w(w_obj)
- if not isinstance(obj, RequiredClass):
- raise DescrMismatch()
- return obj
- descr_self_interp_w._annspecialcase_ = 'specialize:arg(1)'
-
- def interp_w(self, RequiredClass, w_obj, can_be_None=False):
- """
- Unwrap w_obj, checking that it is an instance of the required internal
- interpreter class (a subclass of Wrappable).
- """
- assert RequiredClass is not None
- if can_be_None and self.is_w(w_obj, self.w_None):
- return None
- obj = self.interpclass_w(w_obj)
- if not isinstance(obj, RequiredClass): # or obj is None
- msg = "'%s' object expected, got '%s' instead" % (
- wrappable_class_name(RequiredClass),
- w_obj.getclass(self).getname(self, '?'))
- raise OperationError(self.w_TypeError, self.wrap(msg))
- return obj
- interp_w._annspecialcase_ = 'specialize:arg(1)'
-
- def unpackiterable(self, w_iterable, expected_length=-1):
+ def unpackiterable(self, w_iterable, expected_length=None):
"""Unpack an iterable object into a real (interpreter-level) list.
- Raise a real (subclass of) ValueError if the length is wrong."""
+ Raise a real ValueError if the length is wrong."""
w_iterator = self.iter(w_iterable)
items = []
while True:
try:
w_item = self.next(w_iterator)
- except OperationError, e:
- if not e.match(self, self.w_StopIteration):
- raise
+ except NoValue:
break # done
- if expected_length != -1 and len(items) == expected_length:
- raise UnpackValueError("too many values to unpack")
+ if expected_length is not None and len(items) == expected_length:
+ raise ValueError, "too many values to unpack"
items.append(w_item)
- if expected_length != -1 and len(items) < expected_length:
+ if expected_length is not None and len(items) < expected_length:
i = len(items)
if i == 1:
plural = ""
else:
plural = "s"
- raise UnpackValueError("need more than %d value%s to unpack" %
- (i, plural))
+ raise ValueError, "need more than %d value%s to unpack" % (i, plural)
return items
- def viewiterable(self, w_iterable, expected_length=-1):
- """ More or less the same as unpackiterable, but does not return
- a copy. Please don't modify the result
- """
- return make_sure_not_resized(self.unpackiterable(w_iterable,
- expected_length)[:])
+ 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 = [
+ self.getitem(w_tuple, self.wrap(i)) for i in range(tuple_length)]
+ return items
def exception_match(self, w_exc_type, w_check_class):
"""Checks if the given exception type matches 'w_check_class'."""
- if self.is_w(w_exc_type, w_check_class):
- return True # fast path (also here to handle string exceptions)
- try:
- return self.abstract_issubclass_w(w_exc_type, w_check_class)
- except OperationError, e:
- if e.match(self, self.w_TypeError): # string exceptions maybe
- return False
- raise
-
- def call_obj_args(self, w_callable, w_obj, args):
- if not self.config.objspace.disable_call_speedhacks:
- # XXX start of hack for performance
- from pypy.interpreter.function import Function
- if isinstance(w_callable, Function):
- return w_callable.call_obj_args(w_obj, args)
- # XXX end of hack for performance
- return self.call_args(w_callable, args.prepend(w_obj))
-
- def call(self, w_callable, w_args, w_kwds=None):
- args = Arguments.frompacked(self, w_args, w_kwds)
- return self.call_args(w_callable, args)
-
- def call_function(self, w_func, *args_w):
- nargs = len(args_w) # used for pruning funccall versions
- if not self.config.objspace.disable_call_speedhacks and nargs < 5:
- # XXX start of hack for performance
- from pypy.interpreter.function import Function, Method
- if isinstance(w_func, Method):
- w_inst = w_func.w_instance
- if w_inst is not None:
- if nargs < 4:
- func = w_func.w_function
- if isinstance(func, Function):
- return func.funccall(w_inst, *args_w)
- elif args_w and (
- self.abstract_isinstance_w(args_w[0], w_func.w_class)):
- w_func = w_func.w_function
-
- if isinstance(w_func, Function):
- return w_func.funccall(*args_w)
- # XXX end of hack for performance
-
- args = Arguments(self, list(args_w))
- return self.call_args(w_func, args)
-
- def call_valuestack(self, w_func, nargs, frame):
- from pypy.interpreter.function import Function, Method, is_builtin_code
- if frame.is_being_profiled and is_builtin_code(w_func):
- # XXX: this code is copied&pasted :-( from the slow path below
- # call_valuestack().
- args = frame.make_arguments(nargs)
+ check_list = [w_check_class]
+ while check_list:
+ w_item = check_list.pop()
+ # Match identical items.
+ if self.is_true(self.is_(w_exc_type, w_item)):
+ return True
try:
- return self.call_args_and_c_profile(frame, w_func, args)
- finally:
- if isinstance(args, ArgumentsFromValuestack):
- args.frame = None
-
- if not self.config.objspace.disable_call_speedhacks:
- # XXX start of hack for performance
- if isinstance(w_func, Method):
- w_inst = w_func.w_instance
- if w_inst is not None:
- w_func = w_func.w_function
- # reuse callable stack place for w_inst
- frame.settopvalue(w_inst, nargs)
- nargs += 1
- elif nargs > 0 and (
- self.abstract_isinstance_w(frame.peekvalue(nargs-1), # :-(
- w_func.w_class)):
- w_func = w_func.w_function
-
- if isinstance(w_func, Function):
- return w_func.funccall_valuestack(nargs, frame)
- # XXX end of hack for performance
+ # Match subclasses.
+ if self.is_true(self.issubtype(w_exc_type, w_item)):
+ return True
+ except OperationError:
+ # Assume that this is a TypeError: w_item not a type,
+ # and assume that w_item is then actually a tuple.
+ exclst = self.unpackiterable(w_item)
+ check_list.extend(exclst)
+ return False
- args = frame.make_arguments(nargs)
- try:
- return self.call_args(w_func, args)
- finally:
- if isinstance(args, ArgumentsFromValuestack):
- args.frame = None
-
- def call_args_and_c_profile(self, frame, w_func, args):
- ec = self.getexecutioncontext()
- ec.c_call_trace(frame, w_func)
- try:
- w_res = self.call_args(w_func, args)
- except OperationError, e:
- ec.c_exception_trace(frame, e.w_value)
- raise
- ec.c_return_trace(frame, w_func)
- return w_res
+ def call_function(self, w_func, *args_w, **kw_w):
+ w_kw = self.newdict([(self.wrap(k), w_v) for k, w_v in kw_w.iteritems()])
+ return self.call(w_func, self.newtuple(list(args_w)), w_kw)
- def call_method(self, w_obj, methname, *arg_w):
+ def call_method(self, w_obj, methname, *arg_w, **kw_w):
w_meth = self.getattr(w_obj, self.wrap(methname))
- return self.call_function(w_meth, *arg_w)
-
- def lookup(self, w_obj, name):
- w_type = self.type(w_obj)
- w_mro = self.getattr(w_type, self.wrap("__mro__"))
- for w_supertype in self.unpackiterable(w_mro):
- w_value = w_supertype.getdictvalue_w(self, name)
- if w_value is not None:
- return w_value
- return None
-
- def is_oldstyle_instance(self, w_obj):
- # xxx hack hack hack
- from pypy.module.__builtin__.interp_classobj import W_InstanceObject
- obj = self.interpclass_w(w_obj)
- return obj is not None and isinstance(obj, W_InstanceObject)
-
- def callable(self, w_obj):
- if self.lookup(w_obj, "__call__") is not None:
- if self.is_oldstyle_instance(w_obj):
- # ugly old style class special treatment, but well ...
- try:
- self.getattr(w_obj, self.wrap("__call__"))
- return self.w_True
- except OperationError, e:
- if not e.match(self, self.w_AttributeError):
- raise
- return self.w_False
- else:
- return self.w_True
- return self.w_False
+ return self.call_function(w_meth, *arg_w, **kw_w)
def isinstance(self, w_obj, w_type):
w_objtype = self.type(w_obj)
return self.issubtype(w_objtype, w_type)
- def abstract_issubclass_w(self, w_cls1, w_cls2):
- # Equivalent to 'issubclass(cls1, cls2)'. The code below only works
- # for the simple case (new-style class, new-style class).
- # This method is patched with the full logic by the __builtin__
- # module when it is loaded.
- return self.is_true(self.issubtype(w_cls1, w_cls2))
-
- def abstract_isinstance_w(self, w_obj, w_cls):
- # Equivalent to 'isinstance(obj, cls)'. The code below only works
- # for the simple case (new-style instance, new-style class).
- # This method is patched with the full logic by the __builtin__
- # module when it is loaded.
- return self.is_true(self.isinstance(w_obj, w_cls))
-
- def abstract_isclass_w(self, w_obj):
- # Equivalent to 'isinstance(obj, type)'. The code below only works
- # for the simple case (new-style instance without special stuff).
- # This method is patched with the full logic by the __builtin__
- # module when it is loaded.
- return self.is_true(self.isinstance(w_obj, self.w_type))
-
- def abstract_getclass(self, w_obj):
- # Equivalent to 'obj.__class__'. The code below only works
- # for the simple case (new-style instance without special stuff).
- # This method is patched with the full logic by the __builtin__
- # module when it is loaded.
- return self.type(w_obj)
-
- def eval(self, expression, w_globals, w_locals, hidden_applevel=False):
- "NOT_RPYTHON: For internal debugging."
- import types
- from pypy.interpreter.pycode import PyCode
- if isinstance(expression, str):
- expression = compile(expression, '?', 'eval')
- if isinstance(expression, types.CodeType):
- expression = PyCode._from_code(self, expression,
- hidden_applevel=hidden_applevel)
- if not isinstance(expression, PyCode):
- raise TypeError, 'space.eval(): expected a string, code or PyCode object'
- return expression.exec_code(self, w_globals, w_locals)
-
- def exec_(self, statement, w_globals, w_locals, hidden_applevel=False):
- "NOT_RPYTHON: For internal debugging."
- import types
- from pypy.interpreter.pycode import PyCode
- if isinstance(statement, str):
- statement = compile(statement, '?', 'exec')
- if isinstance(statement, types.CodeType):
- statement = PyCode._from_code(self, statement,
- hidden_applevel=hidden_applevel)
- if not isinstance(statement, PyCode):
- raise TypeError, 'space.exec_(): expected a string, code or PyCode object'
- w_key = self.wrap('__builtins__')
- if not self.is_true(self.contains(w_globals, w_key)):
- self.setitem(w_globals, w_key, self.wrap(self.builtin))
- return statement.exec_code(self, w_globals, w_locals)
-
- def appexec(self, posargs_w, source):
- """ return value from executing given source at applevel.
- EXPERIMENTAL. The source must look like
- '''(x, y):
- do_stuff...
- return result
- '''
- """
- w_func = self.fromcache(AppExecCache).getorbuild(source)
- args = Arguments(self, list(posargs_w))
- return self.call_args(w_func, args)
- appexec._annspecialcase_ = 'specialize:arg(2)'
-
- def decode_index(self, w_index_or_slice, seqlength):
- """Helper for custom sequence implementations
- -> (index, 0, 0) or
- (start, stop, step)
- """
- if self.is_true(self.isinstance(w_index_or_slice, self.w_slice)):
- w_indices = self.call_method(w_index_or_slice, "indices",
- self.wrap(seqlength))
- w_start, w_stop, w_step = self.unpackiterable(w_indices, 3)
- start = self.int_w(w_start)
- stop = self.int_w(w_stop)
- step = self.int_w(w_step)
- if step == 0:
- raise OperationError(self.w_ValueError,
- self.wrap("slice step cannot be zero"))
- if start < 0:
- start = 0
- if stop < start:
- stop = start
- assert stop <= seqlength
- else:
- start = self.int_w(w_index_or_slice)
- if start < 0:
- start += seqlength
- if not (0 <= start < seqlength):
- raise OperationError(self.w_IndexError,
- self.wrap("index out of range"))
- stop = 0
- step = 0
- return start, stop, step
-
- def getindex_w(self, w_obj, w_exception, objdescr=None):
- """Return w_obj.__index__() as an RPython int.
- If w_exception is None, silently clamp in case of overflow;
- else raise w_exception.
- """
- try:
- w_index = self.index(w_obj)
- except OperationError, err:
- if objdescr is None or not err.match(self, self.w_TypeError):
- raise
- msg = "%s must be an integer, not %s" % (
- objdescr, self.type(w_obj).getname(self, '?'))
- raise OperationError(self.w_TypeError, self.wrap(msg))
- try:
- index = self.int_w(w_index)
- except OperationError, err:
- if not err.match(self, self.w_OverflowError):
- raise
- if not w_exception:
- # w_index should be a long object, but can't be sure of that
- if self.is_true(self.lt(w_index, self.wrap(0))):
- return -sys.maxint-1
- else:
- return sys.maxint
- else:
- raise OperationError(
- w_exception, self.wrap(
- "cannot fit '%s' into an index-sized "
- "integer" % self.type(w_obj).getname(self, '?')))
- else:
- return index
-
- def r_longlong_w(self, w_obj):
- bigint = self.bigint_w(w_obj)
- try:
- return bigint.tolonglong()
- except OverflowError:
- raise OperationError(self.w_OverflowError,
- self.wrap('integer too large'))
-
- def r_ulonglong_w(self, w_obj):
- bigint = self.bigint_w(w_obj)
- try:
- return bigint.toulonglong()
- except OverflowError:
- raise OperationError(self.w_OverflowError,
- self.wrap('integer too large'))
- except ValueError:
- raise OperationError(self.w_ValueError,
- self.wrap('cannot convert negative integer '
- 'to unsigned int'))
-
- def buffer_w(self, w_obj):
- # returns a Buffer instance
- from pypy.interpreter.buffer import Buffer
- w_buffer = self.buffer(w_obj)
- return self.interp_w(Buffer, w_buffer)
-
- def rwbuffer_w(self, w_obj):
- # returns a RWBuffer instance
- from pypy.interpreter.buffer import RWBuffer
- buffer = self.buffer_w(w_obj)
- if not isinstance(buffer, RWBuffer):
- raise OperationError(self.w_TypeError,
- self.wrap('read-write buffer expected'))
- return buffer
-
- def bufferstr_w(self, w_obj):
- # Directly returns an interp-level str. Note that if w_obj is a
- # unicode string, this is different from str_w(buffer(w_obj)):
- # indeed, the latter returns a string with the raw bytes from
- # the underlying unicode buffer, but bufferstr_w() just converts
- # the unicode to an ascii string. This inconsistency is kind of
- # needed because CPython has the same issue. (Well, it's
- # unclear if there is any use at all for getting the bytes in
- # the unicode buffer.)
- try:
- return self.str_w(w_obj)
- except OperationError, e:
- if not e.match(self, self.w_TypeError):
- raise
- buffer = self.buffer_w(w_obj)
- return buffer.as_str()
-
- def bool_w(self, w_obj):
- # Unwraps a bool, also accepting an int for compatibility.
- # This is here mostly just for gateway.int_unwrapping_space_method().
- return bool(self.int_w(w_obj))
-
- def nonnegint_w(self, w_obj):
- # Like space.int_w(), but raises an app-level ValueError if
- # the integer is negative. Mostly here for gateway.py.
- value = self.int_w(w_obj)
- if value < 0:
- raise OperationError(self.w_ValueError,
- self.wrap("expected a non-negative integer"))
- return value
-
- def warn(self, msg, w_warningcls):
- self.appexec([self.wrap(msg), w_warningcls], """(msg, warningcls):
- import warnings
- warnings.warn(msg, warningcls, stacklevel=2)
- """)
-
- def resolve_target(self, w_obj):
- """ A space method that can be used by special object spaces (like
- thunk) to replace an object by another. """
- return w_obj
-
-
-class AppExecCache(SpaceCache):
- def build(cache, source):
- """ NOT_RPYTHON """
- space = cache.space
- # XXX will change once we have our own compiler
- import py
- source = source.lstrip()
- assert source.startswith('('), "incorrect header in:\n%s" % (source,)
- source = py.code.Source("def anonymous%s\n" % source)
- w_glob = space.newdict()
- space.exec_(source.compile(), w_glob, w_glob)
- return space.getitem(w_glob, space.wrap('anonymous'))
-
-class DummyLock(object):
- def acquire(self, flag):
- return True
- def release(self):
- pass
- def _freeze_(self):
- return True
-dummy_lock = DummyLock()
## Table describing the regular part of the interface of object spaces,
## namely all methods which only take w_ arguments and return a w_ result
-## (if any). Note: keep in sync with pypy.objspace.flow.operation.Table.
+## (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 # special method name(s)
- ('is_', 'is', 2, []),
('id', 'id', 1, []),
('type', 'type', 1, []),
('issubtype', 'issubtype', 2, []), # not for old-style classes
@@ -1065,15 +217,13 @@
('getitem', 'getitem', 2, ['__getitem__']),
('setitem', 'setitem', 3, ['__setitem__']),
('delitem', 'delitem', 2, ['__delitem__']),
- ('getslice', 'getslice', 3, ['__getslice__']),
- ('setslice', 'setslice', 4, ['__setslice__']),
- ('delslice', 'delslice', 3, ['__delslice__']),
('pos', 'pos', 1, ['__pos__']),
('neg', 'neg', 1, ['__neg__']),
- ('nonzero', 'truth', 1, ['__nonzero__']),
+ ('not_', 'not', 1, []),
('abs' , 'abs', 1, ['__abs__']),
('hex', 'hex', 1, ['__hex__']),
('oct', 'oct', 1, ['__oct__']),
+ ('round', 'round', 2, []),
('ord', 'ord', 1, []),
('invert', '~', 1, ['__invert__']),
('add', '+', 2, ['__add__', '__radd__']),
@@ -1091,9 +241,7 @@
('or_', '|', 2, ['__or__', '__ror__']),
('xor', '^', 2, ['__xor__', '__rxor__']),
('int', 'int', 1, ['__int__']),
- ('index', 'index', 1, ['__index__']),
('float', 'float', 1, ['__float__']),
- ('long', 'long', 1, ['__long__']),
('inplace_add', '+=', 2, ['__iadd__']),
('inplace_sub', '-=', 2, ['__isub__']),
('inplace_mul', '*=', 2, ['__imul__']),
@@ -1113,17 +261,12 @@
('ne', '!=', 2, ['__ne__', '__ne__']),
('gt', '>', 2, ['__gt__', '__lt__']),
('ge', '>=', 2, ['__ge__', '__le__']),
- ('cmp', 'cmp', 2, ['__cmp__']), # rich cmps preferred
- ('coerce', 'coerce', 2, ['__coerce__', '__coerce__']),
('contains', 'contains', 2, ['__contains__']),
('iter', 'iter', 1, ['__iter__']),
- ('next', 'next', 1, ['next']),
-# ('call', 'call', 3, ['__call__']),
+ ('call', 'call', 3, ['__call__']),
('get', 'get', 3, ['__get__']),
('set', 'set', 3, ['__set__']),
('delete', 'delete', 2, ['__delete__']),
- ('userdel', 'del', 1, ['__del__']),
- ('buffer', 'buffer', 1, ['__buffer__']), # see buffer.py
]
ObjSpace.BuiltinModuleTable = [
@@ -1176,38 +319,13 @@
## Irregular part of the interface:
#
-# wrap(x) -> w_x
-# str_w(w_str) -> str
-# int_w(w_ival or w_long_ival) -> ival
-# float_w(w_floatval) -> floatval
-# uint_w(w_ival or w_long_ival) -> r_uint_val (unsigned int value)
-# bigint_w(w_ival or w_long_ival) -> rbigint
-#interpclass_w(w_interpclass_inst or w_obj) -> interpclass_inst|w_obj
-# unwrap(w_x) -> x
-# is_true(w_x) -> True or False
-# newtuple([w_1, w_2,...]) -> w_tuple
-# newlist([w_1, w_2,...]) -> w_list
-# newdict() -> empty w_dict
-# newslice(w_start,w_stop,w_step) -> w_slice
-# call_args(w_obj,Arguments()) -> w_result
-
-ObjSpace.IrregularOpTable = [
- 'wrap',
- 'str_w',
- 'int_w',
- 'float_w',
- 'uint_w',
- 'bigint_w',
- 'unicode_w',
- 'interpclass_w',
- 'unwrap',
- 'is_true',
- 'is_w',
- 'newtuple',
- 'newlist',
- 'newdict',
- 'newslice',
- 'call_args',
- 'marshal_w',
- ]
-
+# wrap(x) -> w_x
+# unwrap(w_x) -> x
+# is_true(w_x) -> True or False
+# 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_step) -> w_slice (any argument may be a real None)
+# next(w_iter) -> w_value or raise NoValue
+#
Modified: pypy/branch/avm/pypy/interpreter/executioncontext.py
==============================================================================
--- pypy/branch/avm/pypy/interpreter/executioncontext.py (original)
+++ pypy/branch/avm/pypy/interpreter/executioncontext.py Thu Nov 5 20:27:32 2009
@@ -1,173 +1,48 @@
-import sys
-from pypy.interpreter.miscutils import Stack
-from pypy.interpreter.error import OperationError
-from pypy.rlib.rarithmetic import LONG_BIT
-from pypy.rlib.unroll import unrolling_iterable
-
-def new_framestack():
- return Stack()
-
-def app_profile_call(space, w_callable, frame, event, w_arg):
- space.call_function(w_callable,
- space.wrap(frame),
- space.wrap(event), w_arg)
+from pypy.interpreter.miscutils import getthreadlocals, Stack
class ExecutionContext:
"""An ExecutionContext holds the state of an execution thread
in the Python interpreter."""
-
+
def __init__(self, space):
+ # Note that self.framestack only contains PyFrames
self.space = space
- self.framestack = new_framestack()
- # tracing: space.frame_trace_action.fire() must be called to ensure
- # that tracing occurs whenever self.w_tracefunc or self.is_tracing
- # is modified.
- self.w_tracefunc = None
- self.is_tracing = 0
- self.compiler = space.createcompiler()
- self.profilefunc = None
- self.w_profilefuncarg = None
+ self.framestack = Stack()
def enter(self, frame):
- if self.framestack.depth() > self.space.sys.recursionlimit:
- raise OperationError(self.space.w_RuntimeError,
- self.space.wrap("maximum recursion depth exceeded"))
- try:
- frame.f_back = self.framestack.top()
- except IndexError:
- frame.f_back = None
-
- if not frame.hide():
- self.framestack.push(frame)
-
- def leave(self, frame):
- if self.profilefunc:
- self._trace(frame, 'leaveframe', self.space.w_None)
-
- if not frame.hide():
- self.framestack.pop()
- if self.w_tracefunc is not None:
- self.space.frame_trace_action.fire()
-
-
- class Subcontext(object):
- # coroutine: subcontext support
-
- def __init__(self):
- self.framestack = new_framestack()
- self.w_tracefunc = None
- self.profilefunc = None
- self.w_profilefuncarg = None
- self.is_tracing = 0
-
- def enter(self, ec):
- ec.framestack = self.framestack
- ec.w_tracefunc = self.w_tracefunc
- ec.profilefunc = self.profilefunc
- ec.w_profilefuncarg = self.w_profilefuncarg
- ec.is_tracing = self.is_tracing
- ec.space.frame_trace_action.fire()
-
- def leave(self, ec):
- self.framestack = ec.framestack
- self.w_tracefunc = ec.w_tracefunc
- self.profilefunc = ec.profilefunc
- self.w_profilefuncarg = ec.w_profilefuncarg
- self.is_tracing = ec.is_tracing
-
- # the following interface is for pickling and unpickling
- def getstate(self, space):
- # we just save the framestack
- items = [space.wrap(item) for item in self.framestack.items]
- return space.newtuple(items)
-
- def setstate(self, space, w_state):
- from pypy.interpreter.pyframe import PyFrame
- items = [space.interp_w(PyFrame, w_item)
- for w_item in space.unpackiterable(w_state)]
- self.framestack.items = items
- # coroutine: I think this is all, folks!
-
-
- def get_builtin(self):
- try:
- return self.framestack.top().builtin
- except IndexError:
- return self.space.builtin
+ locals = getthreadlocals()
+ self.framestack.push(frame)
+ previous_ec = locals.executioncontext
+ locals.executioncontext = self
+ return previous_ec
+
+ def leave(self, previous_ec):
+ locals = getthreadlocals()
+ locals.executioncontext = previous_ec
+ self.framestack.pop()
+
+ def get_w_builtins(self):
+ if self.framestack.empty():
+ return self.space.w_builtins
+ else:
+ return self.framestack.top().w_builtins
- # XXX this one should probably be dropped in favor of a module
def make_standard_w_globals(self):
"Create a new empty 'globals' dictionary."
w_key = self.space.wrap("__builtins__")
- w_value = self.space.wrap(self.get_builtin())
- w_globals = self.space.newdict()
- space.setitem(w_globals, w_key, w_value)
+ w_value = self.get_w_builtins()
+ w_globals = self.space.newdict([(w_key, w_value)])
return w_globals
- def c_call_trace(self, frame, w_func):
- "Profile the call of a builtin function"
- if self.profilefunc is None:
- frame.is_being_profiled = False
- else:
- self._trace(frame, 'c_call', w_func)
-
- def c_return_trace(self, frame, w_retval):
- "Profile the return from a builtin function"
- if self.profilefunc is None:
- frame.is_being_profiled = False
- else:
- self._trace(frame, 'c_return', w_retval)
-
- def c_exception_trace(self, frame, w_exc):
- "Profile function called upon OperationError."
- if self.profilefunc is None:
- frame.is_being_profiled = False
- else:
- self._trace(frame, 'c_exception', w_exc)
-
- def _llprofile(self, event, w_arg):
- fr = self.framestack.items
- space = self.space
- w_callback = self.profilefunc
- if w_callback is not None:
- frame = None
- if fr:
- frame = fr[0]
- self.profilefunc(space, self.w_profilefuncarg, frame, event, w_arg)
-
- def call_trace(self, frame):
- "Trace the call of a function"
- if self.w_tracefunc is not None or self.profilefunc is not None:
- self._trace(frame, 'call', self.space.w_None)
- if self.profilefunc:
- frame.is_being_profiled = True
-
- def return_trace(self, frame, w_retval):
- "Trace the return from a function"
- if self.w_tracefunc is not None:
- self._trace(frame, 'return', w_retval)
-
def bytecode_trace(self, frame):
"Trace function called before each bytecode."
- # this is split into a fast path and a slower path that is
- # not invoked every time bytecode_trace() is.
- actionflag = self.space.actionflag
- ticker = actionflag.get()
- if actionflag.has_bytecode_counter: # this "if" is constant-folded
- ticker += 1
- actionflag.set(ticker)
- if ticker & actionflag.interesting_bits: # fast check
- actionflag.action_dispatcher(self, frame) # slow path
- bytecode_trace._always_inline_ = True
- def exception_trace(self, frame, operationerr):
+ def exception_trace(self, operationerr):
"Trace function called upon OperationError."
operationerr.record_interpreter_traceback()
- if self.w_tracefunc is not None:
- self._trace(frame, 'exception', None, operationerr)
#operationerr.print_detailed_traceback(self.space)
- def sys_exc_info(self): # attn: the result is not the wrapped sys.exc_info() !!!
+ def sys_exc_info(self):
"""Implements sys.exc_info().
Return an OperationError instance or None."""
for i in range(self.framestack.depth()):
@@ -175,339 +50,3 @@
if frame.last_exception is not None:
return frame.last_exception
return None
-
- def settrace(self, w_func):
- """Set the global trace function."""
- if self.space.is_w(w_func, self.space.w_None):
- self.w_tracefunc = None
- else:
- self.w_tracefunc = w_func
- self.space.frame_trace_action.fire()
-
- def setprofile(self, w_func):
- """Set the global trace function."""
- if self.space.is_w(w_func, self.space.w_None):
- self.profilefunc = None
- self.w_profilefuncarg = None
- else:
- self.setllprofile(app_profile_call, w_func)
-
- def setllprofile(self, func, w_arg):
- self.profilefunc = func
- if func is not None:
- if w_arg is None:
- raise ValueError("Cannot call setllprofile with real None")
- for frame in self.framestack.items:
- frame.is_being_profiled = True
- self.w_profilefuncarg = w_arg
-
- def call_tracing(self, w_func, w_args):
- is_tracing = self.is_tracing
- self.is_tracing = 0
- try:
- self.space.frame_trace_action.fire()
- return self.space.call(w_func, w_args)
- finally:
- self.is_tracing = is_tracing
-
- def _trace(self, frame, event, w_arg, operr=None):
- if self.is_tracing or frame.hide():
- return
-
- space = self.space
-
- # Tracing cases
- if event == 'call':
- w_callback = self.w_tracefunc
- else:
- w_callback = frame.w_f_trace
-
- if w_callback is not None and event != "leaveframe":
- if operr is not None:
- w_arg = space.newtuple([operr.w_type, operr.w_value,
- space.wrap(operr.application_traceback)])
-
- frame.fast2locals()
- self.is_tracing += 1
- try:
- try:
- w_result = space.call_function(w_callback, space.wrap(frame), space.wrap(event), w_arg)
- if space.is_w(w_result, space.w_None):
- frame.w_f_trace = None
- else:
- frame.w_f_trace = w_result
- except:
- self.settrace(space.w_None)
- frame.w_f_trace = None
- raise
- finally:
- self.is_tracing -= 1
- frame.locals2fast()
- space.frame_trace_action.fire()
-
- # Profile cases
- if self.profilefunc is not None:
- if event not in ['leaveframe', 'call', 'c_call',
- 'c_return', 'c_exception']:
- return
-
- last_exception = None
- if event == 'leaveframe':
- last_exception = frame.last_exception
- event = 'return'
-
- assert self.is_tracing == 0
- self.is_tracing += 1
- try:
- try:
- self.profilefunc(space, self.w_profilefuncarg,
- frame, event, w_arg)
- except:
- self.profilefunc = None
- self.w_profilefuncarg = None
- raise
-
- finally:
- frame.last_exception = last_exception
- self.is_tracing -= 1
-
- def _freeze_(self):
- raise Exception("ExecutionContext instances should not be seen during"
- " translation. Now is a good time to inspect the"
- " traceback and see where this one comes from :-)")
-
-
-class AbstractActionFlag:
- """This holds the global 'action flag'. It is a single bitfield
- integer, with bits corresponding to AsyncAction objects that need to
- be immediately triggered. The correspondance from bits to
- AsyncAction instances is built at translation time. We can quickly
- check if there is anything at all to do by checking if any of the
- relevant bits is set. If threads are enabled, they consume the 20
- lower bits to hold a counter incremented at each bytecode, to know
- when to release the GIL.
- """
- def __init__(self):
- self._periodic_actions = []
- self._nonperiodic_actions = []
- self.unused_bits = self.FREE_BITS[:]
- self.has_bytecode_counter = False
- self.interesting_bits = 0
- self._rebuild_action_dispatcher()
-
- def fire(self, action):
- """Request for the action to be run before the next opcode.
- The action must have been registered at space initalization time."""
- ticker = self.get()
- self.set(ticker | action.bitmask)
-
- def register_action(self, action):
- "NOT_RPYTHON"
- assert isinstance(action, AsyncAction)
- if action.bitmask == 0:
- while True:
- action.bitmask = self.unused_bits.pop(0)
- if not (action.bitmask & self.interesting_bits):
- break
- self.interesting_bits |= action.bitmask
- if action.bitmask & self.BYTECODE_COUNTER_OVERFLOW_BIT:
- assert action.bitmask == self.BYTECODE_COUNTER_OVERFLOW_BIT
- self._periodic_actions.append(action)
- self.has_bytecode_counter = True
- self.force_tick_counter()
- else:
- self._nonperiodic_actions.append((action, action.bitmask))
- self._rebuild_action_dispatcher()
-
- def setcheckinterval(self, space, interval):
- if interval < self.CHECK_INTERVAL_MIN:
- interval = self.CHECK_INTERVAL_MIN
- elif interval > self.CHECK_INTERVAL_MAX:
- interval = self.CHECK_INTERVAL_MAX
- space.sys.checkinterval = interval
- self.force_tick_counter()
-
- def force_tick_counter(self):
- # force the tick counter to a valid value -- this actually forces
- # it to reach BYTECODE_COUNTER_OVERFLOW_BIT at the next opcode.
- ticker = self.get()
- ticker &= ~ self.BYTECODE_COUNTER_OVERFLOW_BIT
- ticker |= self.BYTECODE_COUNTER_MASK
- self.set(ticker)
-
- def _rebuild_action_dispatcher(self):
- periodic_actions = unrolling_iterable(self._periodic_actions)
- nonperiodic_actions = unrolling_iterable(self._nonperiodic_actions)
- has_bytecode_counter = self.has_bytecode_counter
-
- def action_dispatcher(ec, frame):
- # periodic actions
- if has_bytecode_counter:
- ticker = self.get()
- if ticker & self.BYTECODE_COUNTER_OVERFLOW_BIT:
- # We must run the periodic actions now, but first
- # reset the bytecode counter (the following line
- # works by assuming that we just overflowed the
- # counter, i.e. BYTECODE_COUNTER_OVERFLOW_BIT is
- # set but none of the BYTECODE_COUNTER_MASK bits
- # are).
- ticker -= ec.space.sys.checkinterval
- self.set(ticker)
- for action in periodic_actions:
- action.perform(ec, frame)
-
- # nonperiodic actions
- for action, bitmask in nonperiodic_actions:
- ticker = self.get()
- if ticker & bitmask:
- self.set(ticker & ~ bitmask)
- action.perform(ec, frame)
-
- action_dispatcher._dont_inline_ = True
- self.action_dispatcher = action_dispatcher
-
- # Bits reserved for the bytecode counter, if used
- BYTECODE_COUNTER_MASK = (1 << 20) - 1
- BYTECODE_COUNTER_OVERFLOW_BIT = (1 << 20)
-
- # Free bits
- FREE_BITS = [1 << _b for _b in range(21, LONG_BIT-1)]
-
- # The acceptable range of values for sys.checkinterval, so that
- # the bytecode_counter fits in 20 bits
- CHECK_INTERVAL_MIN = 1
- CHECK_INTERVAL_MAX = BYTECODE_COUNTER_OVERFLOW_BIT
-
-
-class ActionFlag(AbstractActionFlag):
- """The normal class for space.actionflag. The signal module provides
- a different one."""
- _flags = 0
-
- def get(self):
- return self._flags
-
- def set(self, value):
- self._flags = value
-
-
-class AsyncAction(object):
- """Abstract base class for actions that must be performed
- asynchronously with regular bytecode execution, but that still need
- to occur between two opcodes, not at a completely random time.
- """
- bitmask = 0 # means 'please choose one bit automatically'
-
- def __init__(self, space):
- self.space = space
-
- def fire(self):
- """Request for the action to be run before the next opcode.
- The action must have been registered at space initalization time."""
- self.space.actionflag.fire(self)
-
- def fire_after_thread_switch(self):
- """Bit of a hack: fire() the action but only the next time the GIL
- is released and re-acquired (i.e. after a portential thread switch).
- Don't call this if threads are not enabled.
- """
- from pypy.module.thread.gil import spacestate
- spacestate.set_actionflag_bit_after_thread_switch |= self.bitmask
-
- def perform(self, executioncontext, frame):
- """To be overridden."""
-
-
-class PeriodicAsyncAction(AsyncAction):
- """Abstract base class for actions that occur automatically
- every sys.checkinterval bytecodes.
- """
- bitmask = ActionFlag.BYTECODE_COUNTER_OVERFLOW_BIT
-
-
-class UserDelAction(AsyncAction):
- """An action that invokes all pending app-level __del__() method.
- This is done as an action instead of immediately when the
- interp-level __del__() is invoked, because the latter can occur more
- or less anywhere in the middle of code that might not be happy with
- random app-level code mutating data structures under its feet.
- """
-
- def __init__(self, space):
- AsyncAction.__init__(self, space)
- self.dying_objects_w = []
- self.finalizers_lock_count = 0
-
- def register_dying_object(self, w_obj):
- self.dying_objects_w.append(w_obj)
- self.fire()
-
- def perform(self, executioncontext, frame):
- if self.finalizers_lock_count > 0:
- return
- # Each call to perform() first grabs the self.dying_objects_w
- # and replaces it with an empty list. We do this to try to
- # avoid too deep recursions of the kind of __del__ being called
- # while in the middle of another __del__ call.
- pending_w = self.dying_objects_w
- self.dying_objects_w = []
- space = self.space
- for w_obj in pending_w:
- try:
- space.userdel(w_obj)
- except OperationError, e:
- e.write_unraisable(space, 'method __del__ of ', w_obj)
- e.clear(space) # break up reference cycles
- # finally, this calls the interp-level destructor for the
- # cases where there is both an app-level and a built-in __del__.
- w_obj._call_builtin_destructor()
-
-
-class FrameTraceAction(AsyncAction):
- """An action that calls the local trace functions (w_f_trace)."""
-
- def perform(self, executioncontext, frame):
- if frame.w_f_trace is None or executioncontext.is_tracing:
- return
- code = frame.pycode
- if frame.instr_lb <= frame.last_instr < frame.instr_ub:
- if frame.last_instr <= frame.instr_prev:
- # We jumped backwards in the same line.
- executioncontext._trace(frame, 'line', self.space.w_None)
- else:
- size = len(code.co_lnotab) / 2
- addr = 0
- line = code.co_firstlineno
- p = 0
- lineno = code.co_lnotab
- while size > 0:
- c = ord(lineno[p])
- if (addr + c) > frame.last_instr:
- break
- addr += c
- if c:
- frame.instr_lb = addr
-
- line += ord(lineno[p + 1])
- p += 2
- size -= 1
-
- if size > 0:
- while True:
- size -= 1
- if size < 0:
- break
- addr += ord(lineno[p])
- if ord(lineno[p + 1]):
- break
- p += 2
- frame.instr_ub = addr
- else:
- frame.instr_ub = sys.maxint
-
- if frame.instr_lb == frame.last_instr: # At start of line!
- frame.f_lineno = line
- executioncontext._trace(frame, 'line', self.space.w_None)
-
- frame.instr_prev = frame.last_instr
- self.space.frame_trace_action.fire() # continue tracing
Modified: pypy/branch/avm/pypy/interpreter/interactive.py
==============================================================================
--- pypy/branch/avm/pypy/interpreter/interactive.py (original)
+++ pypy/branch/avm/pypy/interpreter/interactive.py Thu Nov 5 20:27:32 2009
@@ -1,229 +1,72 @@
-from pypy.interpreter import error
-from pypy.interpreter import baseobjspace, module, main
+import autopath
+
+from pypy.interpreter import executioncontext, pyframe, baseobjspace
import sys
import code
-import time
-
-
-class Completer:
- """ Stolen mostly from CPython's rlcompleter.py """
- def __init__(self, space, w_globals):
- self.space = space
- self.w_globals = w_globals
-
- def complete(self, text, state):
- if state == 0:
- if "." in text:
- self.matches = self.attr_matches(text)
- else:
- self.matches = self.global_matches(text)
- try:
- return self.matches[state]
-
- except IndexError:
- return None
-
- def global_matches(self, text):
- import keyword
- w_res = self.space.call_method(self.w_globals, "keys")
- namespace_keys = self.space.unwrap(w_res)
- w_res = self.space.call_method(self.space.builtin.getdict(), "keys")
- builtin_keys = self.space.unwrap(w_res)
-
- matches = []
- n = len(text)
-
- for l in [namespace_keys, builtin_keys, keyword.kwlist]:
- for word in l:
- if word[:n] == text and word != "__builtins__":
- matches.append(word)
-
- return matches
-
- def attr_matches(self, text):
- import re
- m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
- if not m:
- return
-
- expr, attr = m.group(1, 3)
- s = self.space
- w_obj = s.eval(expr, self.w_globals, self.w_globals)
- words = self.get_words(w_obj)
-
- w_clz = s.getattr(w_obj, s.wrap("__class__"))
- words += self.get_class_members(w_clz)
-
- matches = []
- n = len(attr)
- for word in words:
- if word[:n] == attr and word != "__builtins__":
- matches.append("%s.%s" % (expr, word))
-
- return matches
-
- def get_words(self, w_clz):
- s = self.space
- w_dir_func = s.builtin.get("dir")
- w_res = s.call_function(w_dir_func, w_clz)
- return s.unwrap(w_res)
-
- def get_class_members(self, w_clz):
- s = self.space
- words = self.get_words(w_clz)
- try:
- w_bases = s.getattr(w_clz, s.wrap("__bases__"))
- bases_w = s.viewiterable(w_bases)
-
- except error.OperationError:
- return words
+import linecache
- for w_clz in bases_w:
- words += self.get_class_members(w_clz)
-
- return words
class PyPyConsole(code.InteractiveConsole):
- def __init__(self, objspace, verbose=0, completer=False):
+ def __init__(self, objspace):
code.InteractiveConsole.__init__(self)
self.space = objspace
- self.verbose = verbose
- space = self.space
- self.console_compiler_flags = 0
-
- mainmodule = main.ensure__main__(space)
- self.w_globals = mainmodule.w_dict
- space.setitem(self.w_globals, space.wrap('__builtins__'), space.builtin)
- if completer:
- self.enable_command_line_completer()
-
- # forbidden:
- #space.exec_("__pytrace__ = 0", self.w_globals, self.w_globals)
- space.setitem(self.w_globals, space.wrap('__pytrace__'),space.wrap(0))
- self.tracelevel = 0
- self.console_locals = {}
-
- def enable_command_line_completer(self):
- try:
- import readline
- # Keep here to save windoze tears
- readline.set_completer(Completer(self.space, self.w_globals).complete)
- readline.parse_and_bind("tab: complete")
- readline.set_history_length(25000)
-
- try:
- readline.read_history_file()
- except IOError:
- pass # guess it doesn't exit
-
- import atexit
- atexit.register(readline.write_history_file)
- except:
- pass
+ self.ec = executioncontext.ExecutionContext(self.space)
+ self.w_globals = self.ec.make_standard_w_globals()
+ self.space.setitem(self.w_globals,
+ self.space.wrap("__name__"),
+ self.space.wrap("__main__"))
def interact(self, banner=None):
- #banner = "Python %s in pypy\n%s / %s" % (
- # sys.version, self.__class__.__name__,
- # self.space.__class__.__name__)
- w_sys = self.space.sys
- major, minor, micro, _, _ = self.space.unwrap(self.space.sys.get('pypy_version_info'))
- elapsed = time.time() - self.space._starttime
- banner = "PyPy %d.%d.%d in %r on top of Python %s (startuptime: %.2f secs)" % (
- major, minor, micro, self.space, sys.version.split()[0], elapsed)
+ if banner is None:
+ banner = "Python %s in pypy\n%s / %s" % (
+ sys.version, self.__class__.__name__,
+ self.space.__class__.__name__)
code.InteractiveConsole.interact(self, banner)
def raw_input(self, prompt=""):
# add a character to the PyPy prompt so that you know where you
# are when you debug it with "python -i py.py"
- try:
- return code.InteractiveConsole.raw_input(self, prompt[0] + prompt)
- except KeyboardInterrupt:
- # fires into an interpreter-level console
- print
- banner = ("Python %s on %s\n" % (sys.version, sys.platform) +
- "*** Entering interpreter-level console ***")
- local = self.console_locals
- # don't copy attributes that look like names that came
- # from self.w_globals (itself the main offender) as they
- # would then get copied back into the applevel namespace.
- local.update(dict([(k,v) for (k, v) in self.__dict__.iteritems()
- if not k.startswith('w_')]))
- del local['locals']
- for w_name in self.space.unpackiterable(self.w_globals):
- local['w_' + self.space.str_w(w_name)] = (
- self.space.getitem(self.w_globals, w_name))
- code.interact(banner=banner, local=local)
- # copy back 'w_' names
- for name in local:
- if name.startswith('w_'):
- self.space.setitem(self.w_globals,
- self.space.wrap(name[2:]),
- local[name])
- print '*** Leaving interpreter-level console ***'
- raise
+ return code.InteractiveConsole.raw_input(self, prompt[0] + prompt)
def runcode(self, code):
- raise NotImplementedError
-
- def runsource(self, source, ignored_filename="<input>", symbol="single"):
- # the following hacked file name is recognized specially by error.py
- hacked_filename = '<inline>\n' + source
- compiler = self.space.getexecutioncontext().compiler
-
- # CPython 2.6 turns console input into unicode
- if isinstance(source, unicode):
- source = source.encode(sys.stdin.encoding)
-
- def doit():
- # compile the provided input
- code = compiler.compile_command(source, hacked_filename, symbol,
- self.console_compiler_flags)
- if code is None:
- raise IncompleteInput
- self.console_compiler_flags |= compiler.getcodeflags(code)
-
- # execute it
- self.settrace()
+ # 'code' is a CPython code object
+ from pypy.interpreter.pycode import PyCode
+ pycode = PyCode()._from_code(code)
+ try:
+ pycode.exec_code(self.space, self.w_globals, self.w_globals)
+ except baseobjspace.OperationError, operationerr:
+ # XXX insert exception info into the application-level sys.last_xxx
+ operationerr.print_detailed_traceback(self.space)
+ else:
try:
- code.exec_code(self.space, self.w_globals, self.w_globals)
- finally:
- if self.tracelevel:
- self.space.unsettrace()
- self.checktrace()
+ if sys.stdout.softspace:
+ print
+ except AttributeError:
+ # Don't crash if user defined stdout doesn't have softspace
+ pass
- # run doit() in an exception-catching box
+ def runsource(self, source, ignored_filename="<input>", symbol="single"):
+ hacked_filename = '<inline>\n'+source
try:
- main.run_toplevel(self.space, doit, verbose=self.verbose)
- except IncompleteInput:
- return 1
- else:
+ 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
- def settrace(self):
- if self.tracelevel:
- self.space.settrace()
-
- def checktrace(self):
- from pypy.objspace import trace
-
- s = self.space
-
- # Did we modify __pytrace__
- tracelevel = s.int_w(s.getitem(self.w_globals,
- s.wrap("__pytrace__")))
-
- if self.tracelevel > 0 and tracelevel == 0:
- s.reset_trace()
- print "Tracing disabled"
-
- if self.tracelevel == 0 and tracelevel > 0:
- trace.create_trace_space(s)
- self.space.unsettrace()
- print "Tracing enabled"
-
- self.tracelevel = tracelevel
-
-
-class IncompleteInput(Exception):
- pass
-
+if __name__ == '__main__':
+ try:
+ import readline
+ except ImportError:
+ pass
+
+ from pypy.tool import option
+ from pypy.tool import testit
+ args = option.process_options(option.get_standard_options(),
+ option.Options)
+ objspace = option.objspace()
+ con = PyPyConsole(objspace)
+ con.interact()
Modified: pypy/branch/avm/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/branch/avm/pypy/interpreter/pyframe.py (original)
+++ pypy/branch/avm/pypy/interpreter/pyframe.py Thu Nov 5 20:27:32 2009
@@ -1,604 +1,299 @@
""" PyFrame class implementation with the interpreter main loop.
"""
-from pypy.tool.pairtype import extendabletype
-from pypy.interpreter import eval, baseobjspace, pycode
-from pypy.interpreter.argument import Arguments, ArgumentsFromValuestack
+from pypy.interpreter import eval, baseobjspace, gateway
+from pypy.interpreter.miscutils import Stack
from pypy.interpreter.error import OperationError
from pypy.interpreter import pytraceback
-import opcode
-from pypy.rlib.objectmodel import we_are_translated, instantiate
-from pypy.rlib.jit import we_are_jitted, hint
-from pypy.rlib.debug import make_sure_not_resized
-
-# Define some opcodes used
-g = globals()
-for op in '''DUP_TOP POP_TOP SETUP_LOOP SETUP_EXCEPT SETUP_FINALLY
-POP_BLOCK END_FINALLY'''.split():
- g[op] = opcode.opmap[op]
-HAVE_ARGUMENT = opcode.HAVE_ARGUMENT
-class PyFrame(eval.Frame):
+
+class PyFrame(eval.Frame, baseobjspace.Wrappable):
"""Represents a frame for a regular Python function
that needs to be interpreted.
- See also pyopcode.PyStandardFrame and nestedscope.PyNestedScopeFrame.
+ See also pyopcode.PyStandardFrame and pynestedscope.PyNestedScopeFrame.
Public fields:
* 'space' is the object space this frame is running in
* 'code' is the PyCode object this frame runs
* 'w_locals' is the locals dictionary to use
* 'w_globals' is the attached globals dictionary
- * 'builtin' is the attached built-in module
- * 'valuestack_w', 'blockstack', control the interpretation
+ * 'w_builtins' is the attached built-ins dictionary
+ * 'valuestack', 'blockstack', 'next_instr' control the interpretation
"""
- __metaclass__ = extendabletype
-
- frame_finished_execution = False
- last_instr = -1
- last_exception = None
- f_back = None
- w_f_trace = None
- # For tracing
- instr_lb = 0
- instr_ub = -1
- instr_prev = -1
- is_being_profiled = False
-
def __init__(self, space, code, w_globals, closure):
- #self = hint(self, access_directly=True)
- assert isinstance(code, pycode.PyCode)
- self.pycode = code
- eval.Frame.__init__(self, space, w_globals, code.co_nlocals)
- self.valuestack_w = [None] * code.co_stacksize
- self.valuestackdepth = 0
- self.blockstack = []
- if space.config.objspace.honor__builtins__:
- self.builtin = space.builtin.pick_builtin(w_globals)
+ eval.Frame.__init__(self, space, code, w_globals, code.co_nlocals)
+ self.valuestack = Stack()
+ self.blockstack = Stack()
+ self.last_exception = None
+ self.next_instr = 0
+ self.w_builtins = self.space.w_builtins
# regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
# class bodies only have CO_NEWLOCALS.
- self.initialize_frame_scopes(closure)
- self.fastlocals_w = [None]*self.numlocals
- make_sure_not_resized(self.fastlocals_w)
- self.f_lineno = self.pycode.co_firstlineno
-
- def get_builtin(self):
- if self.space.config.objspace.honor__builtins__:
- return self.builtin
- else:
- return self.space.builtin
-
- def initialize_frame_scopes(self, closure):
- # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
- # class bodies only have CO_NEWLOCALS.
- # CO_NEWLOCALS: make a locals dict unless optimized is also set
- # CO_OPTIMIZED: no locals dict needed at all
- # NB: this method is overridden in nestedscope.py
- flags = self.pycode.co_flags
- if flags & pycode.CO_OPTIMIZED:
- return
- if flags & pycode.CO_NEWLOCALS:
- self.w_locals = self.space.newdict()
- else:
- assert self.w_globals is not None
- self.w_locals = self.w_globals
-
- def run(self):
- """Start this frame's execution."""
- if self.pycode.co_flags & pycode.CO_GENERATOR:
- from pypy.interpreter.generator import GeneratorIterator
- return self.space.wrap(GeneratorIterator(self))
- else:
- return self.execute_frame()
-
- def execute_generator_frame(self, w_inputvalue, ex=False):
- # opcode semantic change in CPython 2.5: we must pass an input value
- # when resuming a generator, which goes into the value stack.
- # It's not working because the value of magic must be changed in PyCode
- if self.pycode.magic >= 0xa0df294 and self.last_instr != -1 and not ex:
- self.pushvalue(w_inputvalue)
- return self.execute_frame()
-
- def execute_frame(self):
- """Execute this frame. Main entry point to the interpreter."""
- from pypy.rlib import rstack
- # the following 'assert' is an annotation hint: it hides from
- # the annotator all methods that are defined in PyFrame but
- # overridden in the FrameClass subclass of PyFrame.
- assert isinstance(self, self.space.FrameClass)
- executioncontext = self.space.getexecutioncontext()
- executioncontext.enter(self)
- try:
- executioncontext.call_trace(self)
- # Execution starts just after the last_instr. Initially,
- # last_instr is -1. After a generator suspends it points to
- # the YIELD_VALUE instruction.
- next_instr = self.last_instr + 1
- try:
- w_exitvalue = self.dispatch(self.pycode, next_instr,
- executioncontext)
- rstack.resume_point("execute_frame", self, executioncontext,
- returns=w_exitvalue)
- except Exception:
- executioncontext.return_trace(self, self.space.w_None)
- raise
- executioncontext.return_trace(self, w_exitvalue)
- # on exit, we try to release self.last_exception -- breaks an
- # obvious reference cycle, so it helps refcounting implementations
- self.last_exception = None
- finally:
- executioncontext.leave(self)
- return w_exitvalue
- execute_frame.insert_stack_check_here = True
-
- # stack manipulation helpers
- def pushvalue(self, w_object):
- depth = self.valuestackdepth
- self.valuestack_w[depth] = w_object
- self.valuestackdepth = depth + 1
-
- def popvalue(self):
- depth = self.valuestackdepth - 1
- assert depth >= 0, "pop from empty value stack"
- w_object = self.valuestack_w[depth]
- self.valuestack_w[depth] = None
- self.valuestackdepth = depth
- return w_object
-
- def popstrdictvalues(self, n):
- dic_w = {}
- while True:
- n -= 1
- if n < 0:
- break
- w_value = self.popvalue()
- w_key = self.popvalue()
- key = self.space.str_w(w_key)
- dic_w[key] = w_value
- return dic_w
-
- # we need two popvalues that return different data types:
- # one in case we want list another in case of tuple
- def _new_popvalues():
- def popvalues(self, n):
- values_w = [None] * n
- while True:
- n -= 1
- if n < 0:
- break
- values_w[n] = self.popvalue()
- return values_w
- return popvalues
- popvalues = _new_popvalues()
- popvalues_mutable = _new_popvalues()
- del _new_popvalues
-
- def peekvalues(self, n):
- values_w = [None] * n
- base = self.valuestackdepth - n
- assert base >= 0
- while True:
- n -= 1
- if n < 0:
- break
- values_w[n] = self.valuestack_w[base+n]
- return values_w
-
- def dropvalues(self, n):
- finaldepth = self.valuestackdepth - n
- assert finaldepth >= 0, "stack underflow in dropvalues()"
- while True:
- n -= 1
- if n < 0:
- break
- self.valuestack_w[finaldepth+n] = None
- self.valuestackdepth = finaldepth
-
- def pushrevvalues(self, n, values_w): # n should be len(values_w)
- while True:
- n -= 1
- if n < 0:
- break
- self.pushvalue(values_w[n])
-
- def dupvalues(self, n):
- delta = n-1
- while True:
- n -= 1
- if n < 0:
- break
- w_value = self.peekvalue(delta)
- self.pushvalue(w_value)
-
- def peekvalue(self, index_from_top=0):
- index = self.valuestackdepth + ~index_from_top
- assert index >= 0, "peek past the bottom of the stack"
- return self.valuestack_w[index]
-
- def settopvalue(self, w_object, index_from_top=0):
- index = self.valuestackdepth + ~index_from_top
- assert index >= 0, "settop past the bottom of the stack"
- self.valuestack_w[index] = w_object
-
- def dropvaluesuntil(self, finaldepth):
- depth = self.valuestackdepth - 1
- while depth >= finaldepth:
- self.valuestack_w[depth] = None
- depth -= 1
- self.valuestackdepth = finaldepth
-
- def savevaluestack(self):
- return self.valuestack_w[:self.valuestackdepth]
-
- def restorevaluestack(self, items_w):
- assert None not in items_w
- self.valuestack_w[:len(items_w)] = items_w
- self.dropvaluesuntil(len(items_w))
-
- def make_arguments(self, nargs):
- if we_are_jitted():
- return Arguments(self.space, self.peekvalues(nargs))
- else:
- return ArgumentsFromValuestack(self.space, self, nargs)
-
- def descr__reduce__(self, space):
- from pypy.interpreter.mixedmodule import MixedModule
- from pypy.module._pickle_support import maker # helper fns
- w_mod = space.getbuiltinmodule('_pickle_support')
- mod = space.interp_w(MixedModule, w_mod)
- new_inst = mod.get('frame_new')
- w = space.wrap
- nt = space.newtuple
-
- cells = self._getcells()
- if cells is None:
- w_cells = space.w_None
- else:
- w_cells = space.newlist([space.wrap(cell) for cell in cells])
-
- if self.w_f_trace is None:
- f_lineno = self.get_last_lineno()
- else:
- f_lineno = self.f_lineno
-
- values_w = self.valuestack_w[0:self.valuestackdepth]
- w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w)
-
- w_blockstack = nt([block._get_state_(space) for block in self.blockstack])
- w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w)
- if self.last_exception is None:
- w_exc_value = space.w_None
- w_tb = space.w_None
- else:
- w_exc_value = self.last_exception.w_value
- w_tb = w(self.last_exception.application_traceback)
-
- tup_state = [
- w(self.f_back),
- w(self.get_builtin()),
- w(self.pycode),
- w_valuestack,
- w_blockstack,
- w_exc_value, # last_exception
- w_tb, #
- self.w_globals,
- w(self.last_instr),
- w(self.frame_finished_execution),
- w(f_lineno),
- w_fastlocals,
- space.w_None, #XXX placeholder for f_locals
-
- #f_restricted requires no additional data!
- space.w_None, ## self.w_f_trace, ignore for now
+ if code.dictscope_needed():
+ self.w_locals = space.newdict([]) # set to None by Frame.__init__
- w(self.instr_lb), #do we need these three (that are for tracing)
- w(self.instr_ub),
- w(self.instr_prev),
- w_cells,
- ]
-
- return nt([new_inst, nt([]), nt(tup_state)])
-
- def descr__setstate__(self, space, w_args):
- from pypy.module._pickle_support import maker # helper fns
- from pypy.interpreter.pycode import PyCode
- from pypy.interpreter.module import Module
- args_w = space.unpackiterable(w_args)
- w_f_back, w_builtin, w_pycode, w_valuestack, w_blockstack, w_exc_value, w_tb,\
- w_globals, w_last_instr, w_finished, w_f_lineno, w_fastlocals, w_f_locals, \
- w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev, w_cells = args_w
-
- new_frame = self
- pycode = space.interp_w(PyCode, w_pycode)
-
- if space.is_w(w_cells, space.w_None):
- closure = None
- cellvars = []
- else:
- from pypy.interpreter.nestedscope import Cell
- cells_w = space.unpackiterable(w_cells)
- cells = [space.interp_w(Cell, w_cell) for w_cell in cells_w]
- ncellvars = len(pycode.co_cellvars)
- cellvars = cells[:ncellvars]
- closure = cells[ncellvars:]
-
- # do not use the instance's __init__ but the base's, because we set
- # everything like cells from here
- PyFrame.__init__(self, space, pycode, w_globals, closure)
- new_frame.f_back = space.interp_w(PyFrame, w_f_back, can_be_None=True)
- new_frame.builtin = space.interp_w(Module, w_builtin)
- new_frame.blockstack = [unpickle_block(space, w_blk)
- for w_blk in space.unpackiterable(w_blockstack)]
- values_w = maker.slp_from_tuple_with_nulls(space, w_valuestack)
- for w_value in values_w:
- new_frame.pushvalue(w_value)
- if space.is_w(w_exc_value, space.w_None):
- new_frame.last_exception = None
- else:
- from pypy.interpreter.pytraceback import PyTraceback
- tb = space.interp_w(PyTraceback, w_tb)
- new_frame.last_exception = OperationError(space.type(w_exc_value),
- w_exc_value, tb
- )
- new_frame.last_instr = space.int_w(w_last_instr)
- new_frame.frame_finished_execution = space.is_true(w_finished)
- new_frame.f_lineno = space.int_w(w_f_lineno)
- new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals)
-
- if space.is_w(w_f_trace, space.w_None):
- new_frame.w_f_trace = None
- else:
- new_frame.w_f_trace = w_f_trace
-
- new_frame.instr_lb = space.int_w(w_instr_lb) #the three for tracing
- new_frame.instr_ub = space.int_w(w_instr_ub)
- new_frame.instr_prev = space.int_w(w_instr_prev)
-
- self._setcellvars(cellvars)
- space.frame_trace_action.fire()
-
- def hide(self):
- return self.pycode.hidden_applevel
-
- def getcode(self):
- return hint(self.pycode, promote=True)
-
- def getfastscope(self):
- "Get the fast locals as a list."
- return self.fastlocals_w
-
- def setfastscope(self, scope_w):
- """Initialize the fast locals from a list of values,
- where the order is according to self.pycode.signature()."""
- scope_len = len(scope_w)
- if scope_len > len(self.fastlocals_w):
- raise ValueError, "new fastscope is longer than the allocated area"
- self.fastlocals_w[:scope_len] = scope_w
- self.init_cells()
-
- def init_cells(self):
- """Initialize cellvars from self.fastlocals_w
- This is overridden in nestedscope.py"""
- pass
-
def getclosure(self):
return None
- def _getcells(self):
- return None
-
- def _setcellvars(self, cellvars):
- pass
-
- ### line numbers ###
-
- # for f*_f_* unwrapping through unwrap_spec in typedef.py
-
- def fget_f_lineno(space, self):
- "Returns the line number of the instruction currently being executed."
- if self.w_f_trace is None:
- return space.wrap(self.get_last_lineno())
- else:
- return space.wrap(self.f_lineno)
-
- def fset_f_lineno(space, self, w_new_lineno):
- "Returns the line number of the instruction currently being executed."
+ def eval(self, executioncontext):
+ "Interpreter main loop!"
try:
- new_lineno = space.int_w(w_new_lineno)
- except OperationError, e:
- raise OperationError(space.w_ValueError,
- space.wrap("lineno must be an integer"))
+ while True:
+ try:
+ executioncontext.bytecode_trace(self)
+ last_instr = self.next_instr
+ try:
+ # fetch and dispatch the next opcode
+ # dispatch() is abstract, see pyopcode.
+ self.dispatch()
+ except OperationError, e:
+ pytraceback.record_application_traceback(
+ self.space, e, self, last_instr)
+ # convert an OperationError into a control flow
+ # exception
+ import sys
+ tb = sys.exc_info()[2]
+ raise SApplicationException(e, tb)
+ # XXX some other exceptions could be caught here too,
+ # like KeyboardInterrupt
+
+ except ControlFlowException, ctlflowexc:
+ # we have a reason to change the control flow
+ # (typically unroll the stack)
+ ctlflowexc.action(self, last_instr, executioncontext)
- if self.w_f_trace is None:
- raise OperationError(space.w_ValueError,
- space.wrap("f_lineo can only be set by a trace function."))
-
- if new_lineno < self.pycode.co_firstlineno:
- raise OperationError(space.w_ValueError,
- space.wrap("line %d comes before the current code." % new_lineno))
- code = self.pycode.co_code
- addr = 0
- line = self.pycode.co_firstlineno
- new_lasti = -1
- offset = 0
- lnotab = self.pycode.co_lnotab
- for offset in xrange(0, len(lnotab), 2):
- addr += ord(lnotab[offset])
- line += ord(lnotab[offset + 1])
- if line >= new_lineno:
- new_lasti = addr
- new_lineno = line
+ except ExitFrame, e:
+ # leave that frame
+ w_exitvalue = e.args[0]
+ return w_exitvalue
+
+ ### exception stack ###
+
+ def clean_exceptionstack(self):
+ # remove all exceptions that can no longer be re-raised
+ # because the current valuestack is no longer deep enough
+ # to hold the corresponding information
+ while self.exceptionstack:
+ ctlflowexc, valuestackdepth = self.exceptionstack.top()
+ if valuestackdepth <= self.valuestack.depth():
break
+ self.exceptionstack.pop()
+
+ ### application level visible attributes ###
+ def app_visible(self):
+ def makedict(**kw): return kw
+ space = self.space
+ d = makedict(
+ f_code = space.wrap(self.code),
+ f_locals = self.getdictscope(),
+ f_globals = self.w_globals,
+ f_builtins = self.w_builtins,
+ # XXX f_lasti, f_back, f_exc*, f_restricted need to do pypy_getattr directly
+ )
+ return d.items()
+
+### Frame Blocks ###
+
+class FrameBlock:
+
+ """Abstract base class for frame blocks from the blockstack,
+ used by the SETUP_XXX and POP_BLOCK opcodes."""
+
+ def __init__(self, frame, handlerposition):
+ self.handlerposition = handlerposition
+ self.valuestackdepth = frame.valuestack.depth()
+
+ 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):
+ for i in range(self.valuestackdepth, frame.valuestack.depth()):
+ frame.valuestack.pop()
+
+ def cleanup(self, frame):
+ "Clean up a frame when we normally exit the block."
+ self.cleanupstack(frame)
+
+ def unroll(self, frame, unroller):
+ "Clean up a frame when we abnormally exit the block."
+ self.cleanupstack(frame)
+ return False # continue to unroll
+
+
+class LoopBlock(FrameBlock):
+ """A loop block. Stores the end-of-loop pointer in case of 'break'."""
+
+ def unroll(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.blockstack.push(self)
+ jump_to = unroller.args[0]
+ frame.next_instr = jump_to
+ return True # stop unrolling
+ self.cleanupstack(frame)
+ if isinstance(unroller, SBreakLoop):
+ # jump to the end of the loop
+ frame.next_instr = self.handlerposition
+ return True # stop unrolling
+ return False
+
+
+class ExceptBlock(FrameBlock):
+ """An try:except: block. Stores the position of the exception handler."""
+
+ def unroll(self, frame, unroller):
+ self.cleanupstack(frame)
+ if isinstance(unroller, SApplicationException):
+ # push the exception to the value stack for inspection by the
+ # exception handler (the code after the except:)
+ operationerr = unroller.args[0]
+ w_type = operationerr.w_type
+ w_value = operationerr.w_value
+ if frame.space.full_exceptions:
+ w_normalized = normalize_exception(frame.space, w_type, w_value)
+ w_type, w_value = frame.space.unpacktuple(w_normalized, 2)
+ # the stack setup is slightly different than in CPython:
+ # instead of the traceback, we store the unroller object,
+ # wrapped.
+ frame.valuestack.push(frame.space.wrap(unroller))
+ frame.valuestack.push(w_value)
+ frame.valuestack.push(w_type)
+ frame.next_instr = self.handlerposition # jump to the handler
+ return True # stop unrolling
+ return False
+
+def app_normalize_exception(etype, evalue):
+ # XXX should really be defined as a method on OperationError,
+ # but this is not so easy because OperationError cannot be
+ # at the same time an old-style subclass of Exception and a
+ # new-style subclass of Wrappable :-(
+ # moreover, try importing gateway from errors.py and you'll see :-(
+
+ # mistakes here usually show up as infinite recursion, which is fun.
+ if isinstance(evalue, etype):
+ return etype, evalue
+ if isinstance(etype, type) and issubclass(etype, Exception):
+ if evalue is None:
+ evalue = ()
+ elif not isinstance(evalue, tuple):
+ evalue = (evalue,)
+ evalue = etype(*evalue)
+ else:
+ raise Exception, "?!" # XXX
+ return etype, evalue
+normalize_exception = gateway.app2interp(app_normalize_exception)
+
+
+class FinallyBlock(FrameBlock):
+ """A try:finally: block. Stores the position of the exception handler."""
+
+ def cleanup(self, frame):
+ # upon normal entry into the finally: part, the standard Python
+ # bytecode pushes a single None for END_FINALLY. In our case we
+ # always push three values into the stack: the wrapped ctlflowexc,
+ # the exception value and the exception type (which are all None
+ # here).
+ self.cleanupstack(frame)
+ # one None already pushed by the bytecode
+ frame.valuestack.push(frame.space.w_None)
+ frame.valuestack.push(frame.space.w_None)
+
+ def unroll(self, frame, unroller):
+ # any abnormal reason for unrolling a finally: triggers the end of
+ # the block unrolling and the entering the finally: handler.
+ # see comments in cleanup().
+ self.cleanupstack(frame)
+ frame.valuestack.push(frame.space.wrap(unroller))
+ frame.valuestack.push(frame.space.w_None)
+ frame.valuestack.push(frame.space.w_None)
+ frame.next_instr = self.handlerposition # jump to the handler
+ return True # stop unrolling
+
+
+### Internal exceptions that change the control flow ###
+### and (typically) unroll the block stack ###
+
+class ControlFlowException(Exception):
+ """Abstract base class for interpreter-level exceptions 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, we don't think this is needed
+ WHY_RETURN, SReturnValue
+ WHY_BREAK, SBreakLoop
+ WHY_CONTINUE, SContinueLoop
+ WHY_YIELD SYieldValue
- if new_lasti == -1:
- raise OperationError(space.w_ValueError,
- space.wrap("line %d comes after the current code." % new_lineno))
-
- # Don't jump to a line with an except in it.
- if ord(code[new_lasti]) in (DUP_TOP, POP_TOP):
- raise OperationError(space.w_ValueError,
- space.wrap("can't jump to 'except' line as there's no exception"))
-
- # Don't jump into or out of a finally block.
- f_lasti_setup_addr = -1
- new_lasti_setup_addr = -1
- blockstack = []
- addr = 0
- while addr < len(code):
- op = ord(code[addr])
- if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY):
- blockstack.append([addr, False])
- elif op == POP_BLOCK:
- setup_op = ord(code[blockstack[-1][0]])
- if setup_op == SETUP_FINALLY:
- blockstack[-1][1] = True
- else:
- blockstack.pop()
- elif op == END_FINALLY:
- if len(blockstack) > 0:
- setup_op = ord(code[blockstack[-1][0]])
- if setup_op == SETUP_FINALLY:
- blockstack.pop()
-
- if addr == new_lasti or addr == self.last_instr:
- for ii in range(len(blockstack)):
- setup_addr, in_finally = blockstack[~ii]
- if in_finally:
- if addr == new_lasti:
- new_lasti_setup_addr = setup_addr
- if addr == self.last_instr:
- f_lasti_setup_addr = setup_addr
- break
-
- if op >= HAVE_ARGUMENT:
- addr += 3
- else:
- addr += 1
-
- assert len(blockstack) == 0
-
- if new_lasti_setup_addr != f_lasti_setup_addr:
- raise OperationError(space.w_ValueError,
- space.wrap("can't jump into or out of a 'finally' block %d -> %d" %
- (f_lasti_setup_addr, new_lasti_setup_addr)))
-
- if new_lasti < self.last_instr:
- min_addr = new_lasti
- max_addr = self.last_instr
- else:
- min_addr = self.last_instr
- max_addr = new_lasti
-
- delta_iblock = min_delta_iblock = 0
- addr = min_addr
- while addr < max_addr:
- op = ord(code[addr])
-
- if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY):
- delta_iblock += 1
- elif op == POP_BLOCK:
- delta_iblock -= 1
- if delta_iblock < min_delta_iblock:
- min_delta_iblock = delta_iblock
-
- if op >= opcode.HAVE_ARGUMENT:
- addr += 3
- else:
- addr += 1
-
- f_iblock = len(self.blockstack)
- min_iblock = f_iblock + min_delta_iblock
- if new_lasti > self.last_instr:
- new_iblock = f_iblock + delta_iblock
+ """
+ def action(self, frame, last_instr, executioncontext):
+ "Default unroller implementation."
+ while not frame.blockstack.empty():
+ block = frame.blockstack.pop()
+ if block.unroll(frame, self):
+ break
else:
- new_iblock = f_iblock - delta_iblock
+ self.emptystack(frame)
- if new_iblock > min_iblock:
- raise OperationError(space.w_ValueError,
- space.wrap("can't jump into the middle of a block"))
-
- while f_iblock > new_iblock:
- block = self.blockstack.pop()
- block.cleanup(self)
- f_iblock -= 1
-
- self.f_lineno = new_lineno
- self.last_instr = new_lasti
-
- def get_last_lineno(self):
- "Returns the line number of the instruction currently being executed."
- return pytraceback.offset2lineno(self.pycode, self.last_instr)
-
- def fget_f_builtins(space, self):
- return self.get_builtin().getdict()
-
- def fget_f_back(space, self):
- return self.space.wrap(self.f_back)
+ def emptystack(self, frame):
+ "Default behavior when the block stack is exhausted."
+ # could occur e.g. when a BREAK_LOOP is not actually within a loop
+ raise BytecodeCorruption, "block stack exhausted"
+
+class SApplicationException(ControlFlowException):
+ """Unroll the stack because of an application-level exception
+ (i.e. an OperationException)."""
+
+ def action(self, frame, last_instr, executioncontext):
+ e = self.args[0]
+ frame.last_exception = e
+ executioncontext.exception_trace(e)
+
+ ControlFlowException.action(self, frame,
+ last_instr, executioncontext)
+
+ def emptystack(self, frame):
+ # propagate the exception to the caller
+ if len(self.args) == 2:
+ operationerr, tb = self.args
+ raise operationerr.__class__, operationerr, tb
+ else:
+ operationerr = self.args[0]
+ raise operationerr
+
+class SBreakLoop(ControlFlowException):
+ """Signals a 'break' statement."""
+
+class SContinueLoop(ControlFlowException):
+ """Signals a 'continue' statement.
+ Argument is the bytecode position of the beginning of the loop."""
+
+class SReturnValue(ControlFlowException):
+ """Signals a 'return' statement.
+ Argument is the wrapped object to return."""
+ def emptystack(self, frame):
+ w_returnvalue = self.args[0]
+ raise ExitFrame(w_returnvalue)
+
+class ExitFrame(Exception):
+ """Signals the end of the frame execution.
+ The argument is the returned or yielded value, already wrapped."""
- def fget_f_lasti(space, self):
- return self.space.wrap(self.last_instr)
-
- def fget_f_trace(space, self):
- return self.w_f_trace
-
- def fset_f_trace(space, self, w_trace):
- if space.is_w(w_trace, space.w_None):
- self.w_f_trace = None
- else:
- self.w_f_trace = w_trace
- self.f_lineno = self.get_last_lineno()
- space.frame_trace_action.fire()
-
- def fdel_f_trace(space, self):
- self.w_f_trace = None
-
- def fget_f_exc_type(space, self):
- if self.last_exception is not None:
- f = self.f_back
- while f is not None and f.last_exception is None:
- f = f.f_back
- if f is not None:
- return f.last_exception.w_type
- return space.w_None
-
- def fget_f_exc_value(space, self):
- if self.last_exception is not None:
- f = self.f_back
- while f is not None and f.last_exception is None:
- f = f.f_back
- if f is not None:
- return f.last_exception.w_value
- return space.w_None
-
- def fget_f_exc_traceback(space, self):
- if self.last_exception is not None:
- f = self.f_back
- while f is not None and f.last_exception is None:
- f = f.f_back
- if f is not None:
- return space.wrap(f.last_exception.application_traceback)
- return space.w_None
-
- def fget_f_restricted(space, self):
- if space.config.objspace.honor__builtins__:
- return space.wrap(self.builtin is not space.builtin)
- return space.w_False
-
-# ____________________________________________________________
-
-def get_block_class(opname):
- # select the appropriate kind of block
- from pypy.interpreter.pyopcode import block_classes
- return block_classes[opname]
-
-def unpickle_block(space, w_tup):
- w_opname, w_handlerposition, w_valuestackdepth = space.unpackiterable(w_tup)
- opname = space.str_w(w_opname)
- handlerposition = space.int_w(w_handlerposition)
- valuestackdepth = space.int_w(w_valuestackdepth)
- assert valuestackdepth >= 0
- blk = instantiate(get_block_class(opname))
- blk.handlerposition = handlerposition
- blk.valuestackdepth = valuestackdepth
- return blk
+class BytecodeCorruption(ValueError):
+ """Detected bytecode corruption. Never caught; it's an error."""
Modified: pypy/branch/avm/pypy/interpreter/test/test_interpreter.py
==============================================================================
--- pypy/branch/avm/pypy/interpreter/test/test_interpreter.py (original)
+++ pypy/branch/avm/pypy/interpreter/test/test_interpreter.py Thu Nov 5 20:27:32 2009
@@ -1,81 +1,75 @@
-import py
-import sys
+import autopath
+from pypy.tool import testit
-class TestInterpreter:
- from pypy.interpreter.pycompiler import CPythonCompiler as CompilerClass
+class TestInterpreter(testit.TestCase):
def codetest(self, source, functionname, args):
"""Compile and run the given code string, and then call its function
named by 'functionname' with arguments 'args'."""
- from pypy.interpreter import baseobjspace
+ from pypy.interpreter import baseobjspace, executioncontext
from pypy.interpreter import pyframe, gateway, module
space = self.space
- source = str(py.code.Source(source).strip()) + '\n'
-
+ compile = space.builtin.compile
w = space.wrap
- w_code = space.builtin.call('compile',
- w(source), w('<string>'), w('exec'), w(0), w(0))
+ w_code = compile(w(source), w('<string>'), w('exec'), w(0), w(0))
+
+ ec = executioncontext.ExecutionContext(space)
tempmodule = module.Module(space, w("__temp__"))
w_glob = tempmodule.w_dict
- space.setitem(w_glob, w("__builtins__"), space.builtin)
+ space.setitem(w_glob, w("__builtins__"), space.w_builtins)
code = space.unwrap(w_code)
code.exec_code(space, w_glob, w_glob)
- wrappedargs = [w(a) for a in args]
+ wrappedargs = w(args)
wrappedfunc = space.getitem(w_glob, w(functionname))
+ wrappedkwds = space.newdict([])
try:
- w_output = space.call_function(wrappedfunc, *wrappedargs)
+ w_output = space.call(wrappedfunc, wrappedargs, wrappedkwds)
except baseobjspace.OperationError, e:
#e.print_detailed_traceback(space)
return '<<<%s>>>' % e.errorstr(space)
else:
return space.unwrap(w_output)
- def setup_method(self, arg):
- ec = self.space.getexecutioncontext()
- self.saved_compiler = ec.compiler
- ec.compiler = self.CompilerClass(self.space)
-
- def teardown_method(self, arg):
- ec = self.space.getexecutioncontext()
- ec.compiler = self.saved_compiler
+ def setUp(self):
+ self.space = testit.objspace()
def test_exception_trivial(self):
- x = self.codetest('''\
- def f():
- try:
- raise Exception()
- except Exception, e:
- return 1
- return 2
- ''', 'f', [])
- assert x == 1
+ x = self.codetest('''
+def f():
+ try:
+ raise Exception()
+ except Exception, e:
+ return 1
+ return 2
+''', 'f', [])
+ self.assertEquals(x, 1)
def test_exception(self):
x = self.codetest('''
- def f():
- try:
- raise Exception, 1
- except Exception, e:
- return e.args[0]
- ''', 'f', [])
- assert x == 1
+def f():
+ try:
+ raise Exception, 1
+ except Exception, e:
+ return e.args[0]
+''', 'f', [])
+ self.assertEquals(x, 1)
def test_finally(self):
code = '''
- def f(a):
- try:
- if a:
- raise Exception
- a = -12
- finally:
- return a
- '''
- assert self.codetest(code, 'f', [0]) == -12
- assert self.codetest(code, 'f', [1]) == 1
+def f(a):
+ try:
+ if a:
+ raise Exception
+ a = -12
+ finally:
+ return a
+'''
+ self.assertEquals(self.codetest(code, 'f', [0]), -12)
+ self.assertEquals(self.codetest(code, 'f', [1]), 1)
## def test_raise(self):
## x = self.codetest('''
@@ -86,206 +80,137 @@
def test_except2(self):
x = self.codetest('''
- def f():
- try:
- z = 0
- try:
- "x"+1
- except TypeError, e:
- z = 5
- raise e
- except TypeError:
- return z
- ''', 'f', [])
- assert x == 5
+def f():
+ try:
+ z = 0
+ try:
+ "x"+1
+ except TypeError, e:
+ z = 5
+ raise e
+ except TypeError:
+ return z
+''', 'f', [])
+ self.assertEquals(x, 5)
def test_except3(self):
code = '''
- def f(v):
- z = 0
- try:
- z = 1//v
- except ZeroDivisionError, e:
- z = "infinite result"
- return z
- '''
- assert self.codetest(code, 'f', [2]) == 0
- assert self.codetest(code, 'f', [0]) == "infinite result"
+def f(v):
+ z = 0
+ try:
+ z = 1//v
+ except ZeroDivisionError, e:
+ z = "infinite result"
+ return z
+'''
+ self.assertEquals(self.codetest(code, 'f', [2]), 0)
+ self.assertEquals(self.codetest(code, 'f', [0]), "infinite result")
ess = "TypeError: unsupported operand type"
res = self.codetest(code, 'f', ['x'])
- assert res.find(ess) >= 0
+ self.failUnless(res.find(ess) >= 0)
# the following (original) test was a bit too strict...:
# self.assertEquals(self.codetest(code, 'f', ['x']), "<<<TypeError: unsupported operand type(s) for //: 'int' and 'str'>>>")
def test_break(self):
code = '''
- def f(n):
- total = 0
- for i in range(n):
- try:
- if i == 4:
- break
- finally:
- total += i
- return total
- '''
- assert self.codetest(code, 'f', [4]) == 1+2+3
- assert self.codetest(code, 'f', [9]) == 1+2+3+4
+def f(n):
+ total = 0
+ for i in range(n):
+ try:
+ if i == 4:
+ break
+ finally:
+ total += i
+ return total
+'''
+ self.assertEquals(self.codetest(code, 'f', [4]), 1+2+3)
+ self.assertEquals(self.codetest(code, 'f', [9]), 1+2+3+4)
def test_continue(self):
code = '''
- def f(n):
- total = 0
- for i in range(n):
- try:
- if i == 4:
- continue
- finally:
- total += 100
- total += i
- return total
- '''
- assert self.codetest(code, 'f', [4]) == 1+2+3+400
- assert self.codetest(code, 'f', [9]) == (
+def f(n):
+ total = 0
+ for i in range(n):
+ try:
+ if i == 4:
+ continue
+ finally:
+ total += 100
+ total += i
+ return total
+'''
+ self.assertEquals(self.codetest(code, 'f', [4]), 1+2+3+400)
+ self.assertEquals(self.codetest(code, 'f', [9]),
1+2+3 + 5+6+7+8+900)
- def test_import(self):
- # Regression test for a bug in PyFrame.IMPORT_NAME: when an
- # import statement was executed in a function without a locals dict, a
- # plain unwrapped None could be passed into space.call_function causing
- # assertion errors later on.
- real_call_function = self.space.call_function
- def safe_call_function(w_obj, *arg_w):
- for arg in arg_w:
- assert arg is not None
- return real_call_function(w_obj, *arg_w)
- self.space.call_function = safe_call_function
- code = '''
- def f():
- import sys
- '''
- self.codetest(code, 'f', [])
-
- def test_extended_arg(self):
- longexpr = 'x = x or ' + '-x' * 2500
- code = '''
- def f(x):
- %s
- %s
- %s
- %s
- %s
- %s
- %s
- %s
- %s
- %s
- while x:
- x -= 1 # EXTENDED_ARG is for the JUMP_ABSOLUTE at the end of the loop
- return x
- ''' % ((longexpr,)*10)
- assert self.codetest(code, 'f', [3]) == 0
-
- def test_call_star_starstar(self):
- code = '''\
- def f1(n):
- return n*2
- def f38(n):
- f = f1
- r = [
- f(n, *[]),
- f(n),
- apply(f, (n,)),
- apply(f, [n]),
- f(*(n,)),
- f(*[n]),
- f(n=n),
- f(**{'n': n}),
- apply(f, (n,), {}),
- apply(f, [n], {}),
- f(*(n,), **{}),
- f(*[n], **{}),
- f(n, **{}),
- f(n, *[], **{}),
- f(n=n, **{}),
- f(n=n, *[], **{}),
- f(*(n,), **{}),
- f(*[n], **{}),
- f(*[], **{'n':n}),
- ]
- return r
- '''
- assert self.codetest(code, 'f38', [117]) == [234]*19
-
- def test_star_arg(self):
- code = '''
- def f(x, *y):
- return y
- def g(u, v):
- return f(u, *v)
- '''
- assert self.codetest(code, 'g', [12, ()]) == ()
- assert self.codetest(code, 'g', [12, (3,4)]) == (3,4)
- assert self.codetest(code, 'g', [12, []]) == ()
- assert self.codetest(code, 'g', [12, [3,4]]) == (3,4)
- assert self.codetest(code, 'g', [12, {}]) == ()
- assert self.codetest(code, 'g', [12, {3:1}]) == (3,)
-
- def test_closure(self):
- code = '''
- def f(x, y):
- def g(u, v):
- return u - v + 7*x
- return g
- def callme(x, u, v):
- return f(x, 123)(u, v)
- '''
- assert self.codetest(code, 'callme', [1, 2, 3]) == 6
+class AppTestInterpreter(testit.AppTestCase):
+ def test_exception(self):
+ try:
+ raise Exception, 1
+ except Exception, e:
+ self.assertEquals(e.args[0], 1)
- def test_list_comprehension(self):
- code = '''
- def f():
- return [dir() for i in [1]][0]
- '''
- assert self.codetest(code, 'f', [])[0] == '_[1]'
-
- def test_import_statement(self):
- for x in range(10):
- import os
- code = '''
- def f():
- for x in range(10):
- import os
- return os.name
- '''
- assert self.codetest(code, 'f', []) == os.name
+ def test_trivial(self):
+ x = 42
+ self.assertEquals(x, 42)
+ def test_raise(self):
+ def f():
+ raise Exception
+ self.assertRaises(Exception, f)
-class TestPyPyInterpreter(TestInterpreter):
- """Runs the previous test with the pypy parser"""
- from pypy.interpreter.pycompiler import PythonAstCompiler as CompilerClass
+ def test_exception(self):
+ try:
+ raise Exception
+ self.fail("exception failed to raise")
+ except:
+ pass
+ else:
+ self.fail("exception executing else clause!")
- def test_extended_arg(self):
- py.test.skip("expression too large for the recursive parser")
+ def test_raise2(self):
+ def f(r):
+ try:
+ raise r
+ except LookupError:
+ return 1
+ self.assertRaises(Exception, f, Exception)
+ self.assertEquals(f(IndexError), 1)
+ def test_raise3(self):
+ try:
+ raise 1
+ except TypeError:
+ pass
+ else:
+ self.fail("shouldn't be able to raise 1")
-class AppTestInterpreter:
- def test_trivial(self):
- x = 42
- assert x == 42
+ def test_raise_three_args(self):
+ import sys
+ try:
+ raise ValueError
+ except:
+ exc_type,exc_val,exc_tb = sys.exc_info()
+ try:
+ raise exc_type,exc_val,exc_tb
+ except:
+ exc_type2,exc_val2,exc_tb2 = sys.exc_info()
+ self.assertEquals(exc_type,exc_type2)
+ self.assertEquals(exc_val,exc_val2)
+ self.assertEquals(exc_tb,exc_tb2)
def test_trivial_call(self):
def f(): return 42
- assert f() == 42
+ self.assertEquals(f(), 42)
def test_trivial_call2(self):
def f(): return 1 + 1
- assert f() == 2
+ self.assertEquals(f(), 2)
def test_print(self):
import sys
save = sys.stdout
- class Out(object):
+ class Out:
def __init__(self):
self.args = []
def write(self, *args):
@@ -294,10 +219,14 @@
try:
sys.stdout = out
print 10
- assert out.args == ['10','\n']
+ self.assertEquals(out.args, ['10','\n'])
finally:
sys.stdout = save
def test_identity(self):
def f(x): return x
- assert f(666) == 666
+ self.assertEquals(f(666), 666)
+
+
+if __name__ == '__main__':
+ testit.main()
Modified: pypy/branch/avm/pypy/objspace/std/intobject.py
==============================================================================
--- pypy/branch/avm/pypy/objspace/std/intobject.py (original)
+++ pypy/branch/avm/pypy/objspace/std/intobject.py Thu Nov 5 20:27:32 2009
@@ -1,153 +1,194 @@
from pypy.objspace.std.objspace import *
-from pypy.objspace.std.noneobject import W_NoneObject
-from pypy.rlib.rarithmetic import ovfcheck, ovfcheck_lshift, LONG_BIT, r_uint
-from pypy.rlib.rbigint import rbigint
-from pypy.objspace.std.inttype import wrapint
+from inttype import W_IntType
+from noneobject import W_NoneObject
+from restricted_int import r_int, LONG_BIT
"""
-In order to have the same behavior running
-on CPython, and after RPython translation we use ovfcheck
-from rarithmetic to explicitly check for overflows,
-something CPython does not do anymore.
+The implementation of integers is a bit difficult,
+since integers are currently undergoing the change to turn
+themselves into longs under overflow circumstances.
+The restricted Python does not overflow or throws
+exceptions.
+The definitions in this file are fine, given that
+restricted Python integers behave that way.
+But for testing, the resticted stuff must be run
+by CPython which has different behavior.
+For that reason, I defined an r_int extension class
+for native integers, which tries to behave as in
+RPython, just for test purposes.
"""
class W_IntObject(W_Object):
- __slots__ = 'intval'
-
- _immutable_ = True
-
- from pypy.objspace.std.inttype import int_typedef as typedef
+ statictype = W_IntType
- def __init__(w_self, intval):
- w_self.intval = intval
+ def __init__(w_self, space, intval):
+ W_Object.__init__(w_self, space)
+ w_self.intval = r_int(intval)
def __repr__(w_self):
""" representation for debugging purposes """
return "%s(%d)" % (w_self.__class__.__name__, w_self.intval)
- def unwrap(w_self, space):
- return int(w_self.intval)
-
registerimplementation(W_IntObject)
-def int_w__Int(space, w_int1):
- return int(w_int1.intval)
-
-def uint_w__Int(space, w_int1):
- intval = w_int1.intval
- if intval < 0:
- raise OperationError(space.w_ValueError,
- space.wrap("cannot convert negative integer to unsigned"))
- else:
- return r_uint(intval)
+"""
+XXX not implemented:
+free list
+FromString
+FromUnicode
+print
+"""
-def bigint_w__Int(space, w_int1):
- return rbigint.fromint(w_int1.intval)
+def unwrap__Int(space, w_int1):
+ return int(w_int1.intval)
def repr__Int(space, w_int1):
a = w_int1.intval
- res = str(a)
+ res = "%ld" % a
return space.wrap(res)
str__Int = repr__Int
-def declare_new_int_comparison(opname):
- import operator
- from pypy.tool.sourcetools import func_with_new_name
- op = getattr(operator, opname)
- def f(space, w_int1, w_int2):
- i = w_int1.intval
- j = w_int2.intval
- return space.newbool(op(i, j))
- name = opname + "__Int_Int"
- return func_with_new_name(f, name), name
-
-for op in ['lt', 'le', 'eq', 'ne', 'gt', 'ge']:
- func, name = declare_new_int_comparison(op)
- globals()[name] = func
+## deprecated
+## we are going to support rich compare, only
-def hash__Int(space, w_int1):
- # unlike CPython, we don't special-case the value -1 in most of our
- # hash functions, so there is not much sense special-casing it here either.
- # Make sure this is consistent with the hash of floats and longs.
- return int__Int(space, w_int1)
-
-# coerce
-def coerce__Int_Int(space, w_int1, w_int2):
- return space.newtuple([w_int1, w_int2])
+##def int_int_cmp(space, w_int1, w_int2):
+## i = w_int1.intval
+## j = w_int2.intval
+## if i < j:
+## ret = -1
+## elif i > j:
+## ret = 1
+## else:
+## ret = 0
+## return W_IntObject(space, ret)
+##
+##StdObjSpace.cmp.register(int_int_cmp, W_IntObject, W_IntObject)
+
+def lt__Int_Int(space, w_int1, w_int2):
+ i = w_int1.intval
+ j = w_int2.intval
+ return space.newbool( i < j )
+
+def le__Int_Int(space, w_int1, w_int2):
+ i = w_int1.intval
+ j = w_int2.intval
+ return space.newbool( i <= j )
+
+def eq__Int_Int(space, w_int1, w_int2):
+ i = w_int1.intval
+ j = w_int2.intval
+ return space.newbool( i == j )
+
+def ne__Int_Int(space, w_int1, w_int2):
+ i = w_int1.intval
+ j = w_int2.intval
+ return space.newbool( i != j )
+
+def gt__Int_Int(space, w_int1, w_int2):
+ i = w_int1.intval
+ j = w_int2.intval
+ return space.newbool( i > j )
+
+def ge__Int_Int(space, w_int1, w_int2):
+ i = w_int1.intval
+ j = w_int2.intval
+ return space.newbool( i >= j )
+
+STRICT_HASH = True # temporary, to be put elsewhere or removed
+
+def _hash_strict(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(space, x)
+
+def _hash_liberal(space, w_int1):
+ # Armin: unlike CPython we have no need to special-case the value -1
+ return w_int1
+
+# Chris: I'm not yet convinced that we want to make hash()
+# return different values that CPython does.
+# So for the moment, both versions are here,
+# and we might think of some config options
+# or decide to drop compatibility (using pypy-dev).
+def hash__Int(space, w_int1):
+ if STRICT_HASH:
+ return _hash_strict(space, w_int1)
+ else:
+ return _hash_liberal(space, w_int1)
def add__Int_Int(space, w_int1, w_int2):
x = w_int1.intval
y = w_int2.intval
try:
- z = ovfcheck(x + y)
+ z = x + y
except OverflowError:
raise FailedToImplement(space.w_OverflowError,
space.wrap("integer addition"))
- return wrapint(space, z)
+ return W_IntObject(space, z)
def sub__Int_Int(space, w_int1, w_int2):
x = w_int1.intval
y = w_int2.intval
try:
- z = ovfcheck(x - y)
+ z = x - y
except OverflowError:
raise FailedToImplement(space.w_OverflowError,
space.wrap("integer substraction"))
- return wrapint(space, z)
+ return W_IntObject(space, z)
def mul__Int_Int(space, w_int1, w_int2):
x = w_int1.intval
y = w_int2.intval
try:
- z = ovfcheck(x * y)
+ z = x * y
except OverflowError:
raise FailedToImplement(space.w_OverflowError,
space.wrap("integer multiplication"))
- return wrapint(space, z)
+ return W_IntObject(space, z)
-def floordiv__Int_Int(space, w_int1, w_int2):
+def _floordiv(space, w_int1, w_int2):
x = w_int1.intval
y = w_int2.intval
try:
- z = ovfcheck(x // y)
+ z = x // y
except ZeroDivisionError:
raise OperationError(space.w_ZeroDivisionError,
space.wrap("integer division by zero"))
except OverflowError:
raise FailedToImplement(space.w_OverflowError,
space.wrap("integer division"))
- return wrapint(space, z)
-div__Int_Int = floordiv__Int_Int
+ return W_IntObject(space, z)
-def truediv__Int_Int(space, w_int1, w_int2):
- x = float(w_int1.intval)
- y = float(w_int2.intval)
- if y == 0.0:
- raise FailedToImplement(space.w_ZeroDivisionError, space.wrap("float division"))
- return space.wrap(x / y)
+def _truediv(space, w_int1, w_int2):
+ # cannot implement, since it gives floats
+ raise FailedToImplement(space.w_OverflowError,
+ space.wrap("integer division"))
def mod__Int_Int(space, w_int1, w_int2):
x = w_int1.intval
y = w_int2.intval
try:
- z = ovfcheck(x % y)
+ z = x % y
except ZeroDivisionError:
raise OperationError(space.w_ZeroDivisionError,
space.wrap("integer modulo by zero"))
except OverflowError:
raise FailedToImplement(space.w_OverflowError,
space.wrap("integer modulo"))
- return wrapint(space, z)
+ return W_IntObject(space, z)
def divmod__Int_Int(space, w_int1, w_int2):
x = w_int1.intval
y = w_int2.intval
try:
- z = ovfcheck(x // y)
+ z = x // y
except ZeroDivisionError:
raise OperationError(space.w_ZeroDivisionError,
space.wrap("integer divmod by zero"))
@@ -156,30 +197,41 @@
space.wrap("integer modulo"))
# no overflow possible
m = x % y
- w = space.wrap
- return space.newtuple([w(z), w(m)])
+ return space.wrap((z,m))
+
+def div__Int_Int(space, w_int1, w_int2):
+ # Select the proper div
+ if 1 / 2 == 1 // 2:
+ return _floordiv(space, w_int1, w_int2)
+ else:
+ return _truediv(space, w_int1, w_int2)
+floordiv__Int_Int = _floordiv
# helper for pow()
-def _impl_int_int_pow(space, iv, iw, iz=0):
+def _impl_int_int_pow(space, iv, iw, iz=None):
if iw < 0:
- if iz != 0:
+ if iz is not None:
raise OperationError(space.w_TypeError,
space.wrap("pow() 2nd argument "
"cannot be negative when 3rd argument specified"))
## bounce it, since it always returns float
raise FailedToImplement(space.w_ValueError,
space.wrap("integer exponentiation"))
+ if iz is not None:
+ if iz == 0:
+ raise OperationError(space.w_ValueError,
+ space.wrap("pow() 3rd argument cannot be 0"))
temp = iv
ix = 1
try:
while iw > 0:
if iw & 1:
- ix = ovfcheck(ix*temp)
+ ix = ix*temp
iw >>= 1 #/* Shift exponent down by 1 bit */
if iw==0:
break
- temp = ovfcheck(temp*temp) #/* Square the value of temp */
+ temp *= temp #/* Square the value of temp */
if iz:
#/* If we did a multiplication, perform a modulo */
ix = ix % iz;
@@ -189,31 +241,48 @@
except OverflowError:
raise FailedToImplement(space.w_OverflowError,
space.wrap("integer exponentiation"))
- return wrapint(space, ix)
+ return ix
+"""
def pow__Int_Int_Int(space, w_int1, w_int2, w_int3):
x = w_int1.intval
y = w_int2.intval
z = w_int3.intval
- if z == 0:
- raise OperationError(space.w_ValueError,
- space.wrap("pow() 3rd argument cannot be 0"))
- return _impl_int_int_pow(space, x, y, z)
+ ret = _impl_int_int_pow(space, x, y, z)
+ return W_IntObject(space, ret)
+"""
+
+def pow__Int_Int_Int(space, w_int1, w_int2, w_int3):
+ x = w_int1.intval
+ y = w_int2.intval
+ z = w_int3.intval
+ ret = _impl_int_int_pow(space, x, y, z)
+ return W_IntObject(space, ret)
def pow__Int_Int_None(space, w_int1, w_int2, w_int3):
x = w_int1.intval
y = w_int2.intval
- return _impl_int_int_pow(space, x, y)
+ ret = _impl_int_int_pow(space, x, y)
+ return W_IntObject(space, ret)
def neg__Int(space, w_int1):
a = w_int1.intval
try:
- x = ovfcheck(-a)
+ x = -a
except OverflowError:
raise FailedToImplement(space.w_OverflowError,
space.wrap("integer negation"))
- return wrapint(space, x)
+ return W_IntObject(space, x)
+# pos__Int is supposed to do nothing, unless it has
+# a derived integer object, where it should return
+# an exact one.
+def pos__Int(space, w_int1):
+ #not sure if this should be done this way:
+ if w_int1.__class__ is W_IntObject:
+ return w_int1
+ a = w_int1.intval
+ return W_IntObject(space, a)
def abs__Int(space, w_int1):
if w_int1.intval >= 0:
@@ -221,13 +290,14 @@
else:
return neg__Int(space, w_int1)
-def nonzero__Int(space, w_int1):
- return space.newbool(w_int1.intval != 0)
+def is_true__Int(space, w_int1):
+ ''' note: this must return an UNWRAPPED bool!!! '''
+ return w_int1.intval != 0
def invert__Int(space, w_int1):
x = w_int1.intval
a = ~x
- return wrapint(space, a)
+ return W_IntObject(space, a)
def lshift__Int_Int(space, w_int1, w_int2):
a = w_int1.intval
@@ -236,16 +306,25 @@
raise OperationError(space.w_ValueError,
space.wrap("negative shift count"))
if a == 0 or b == 0:
- return int__Int(space, w_int1)
+ return Int_pos(w_int1)
if b >= LONG_BIT:
raise FailedToImplement(space.w_OverflowError,
space.wrap("integer left shift"))
+ ##
+ ## XXX please! have a look into pyport.h and see how to implement
+ ## the overflow checking, using macro Py_ARITHMETIC_RIGHT_SHIFT
+ ## we *assume* that the overflow checking is done correctly
+ ## in the code generator, which is not trivial!
try:
- c = ovfcheck_lshift(a, b)
+ c = a << b
+ ## the test in C code is
+ ## if (a != Py_ARITHMETIC_RIGHT_SHIFT(long, c, b)) {
+ ## if (PyErr_Warn(PyExc_FutureWarning,
+ # and so on
except OverflowError:
raise FailedToImplement(space.w_OverflowError,
space.wrap("integer left shift"))
- return wrapint(space, c)
+ return W_IntObject(space, c)
def rshift__Int_Int(space, w_int1, w_int2):
a = w_int1.intval
@@ -254,46 +333,59 @@
raise OperationError(space.w_ValueError,
space.wrap("negative shift count"))
if a == 0 or b == 0:
- return int__Int(space, w_int1)
+ return Int_pos(w_int1)
if b >= LONG_BIT:
if a < 0:
a = -1
else:
a = 0
else:
+ ## please look into pyport.h, how >> should be implemented!
+ ## a = Py_ARITHMETIC_RIGHT_SHIFT(long, a, b);
a = a >> b
- return wrapint(space, a)
+ return W_IntObject(space, a)
def and__Int_Int(space, w_int1, w_int2):
a = w_int1.intval
b = w_int2.intval
res = a & b
- return wrapint(space, res)
+ return W_IntObject(space, res)
def xor__Int_Int(space, w_int1, w_int2):
a = w_int1.intval
b = w_int2.intval
res = a ^ b
- return wrapint(space, res)
+ return W_IntObject(space, res)
def or__Int_Int(space, w_int1, w_int2):
a = w_int1.intval
b = w_int2.intval
res = a | b
- return wrapint(space, res)
+ return W_IntObject(space, res)
+
+# coerce is not wanted
+##
+##static int
+##coerce__Int(PyObject **pv, PyObject **pw)
+##{
+## if (PyInt_Check(*pw)) {
+## Py_INCREF(*pv);
+## Py_INCREF(*pw);
+## return 0;
+## }
+## return 1; /* Can't do it */
+##}
-# int__Int is supposed to do nothing, unless it has
-# a derived integer object, where it should return
-# an exact one.
def int__Int(space, w_int1):
- if space.is_w(space.type(w_int1), space.w_int):
- return w_int1
- a = w_int1.intval
- return wrapint(space, a)
-pos__Int = int__Int
+ return w_int1
-def index__Int(space, w_int1):
- return int__Int(space, w_int1)
+"""
+# Not registered
+def long__Int(space, w_int1):
+ a = w_int1.intval
+ x = long(a) ## XXX should this really be done so?
+ return space.newlong(x)
+"""
def float__Int(space, w_int1):
a = w_int1.intval
@@ -301,13 +393,33 @@
return space.newfloat(x)
def oct__Int(space, w_int1):
- return space.wrap(oct(w_int1.intval))
+ x = w_int1.intval
+ if x < 0:
+ ## XXX what about this warning?
+ #if (PyErr_Warn(PyExc_FutureWarning,
+ # "hex()/oct() of negative int will return "
+ # "a signed string in Python 2.4 and up") < 0)
+ # return NULL;
+ pass
+ if x == 0:
+ ret = "0"
+ else:
+ ret = "0%lo" % x
+ return space.wrap(ret)
def hex__Int(space, w_int1):
- return space.wrap(hex(w_int1.intval))
-
-def getnewargs__Int(space, w_int1):
- return space.newtuple([wrapint(space, w_int1.intval)])
-
+ x = w_int1.intval
+ if x < 0:
+ ## XXX what about this warning?
+ #if (PyErr_Warn(PyExc_FutureWarning,
+ # "hex()/oct() of negative int will return "
+ # "a signed string in Python 2.4 and up") < 0)
+ # return NULL;
+ pass
+ if x == 0:
+ ret = "0"
+ else:
+ ret = "0x%lx" % x
+ return space.wrap(ret)
register_all(vars())
Modified: pypy/branch/avm/pypy/objspace/std/listobject.py
==============================================================================
--- pypy/branch/avm/pypy/objspace/std/listobject.py (original)
+++ pypy/branch/avm/pypy/objspace/std/listobject.py Thu Nov 5 20:27:32 2009
@@ -1,531 +1,536 @@
from pypy.objspace.std.objspace import *
-from pypy.objspace.std.inttype import wrapint
-from pypy.objspace.std.listtype import get_list_index
-from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
-
-from pypy.objspace.std import slicetype
-from pypy.interpreter import gateway, baseobjspace
-from pypy.rlib.listsort import TimSort
+from listtype import W_ListType
+from intobject import W_IntObject
+from sliceobject import W_SliceObject
+from tupleobject import W_TupleObject
+
+import slicetype
+from pypy.interpreter import gateway
+from restricted_int import r_int, r_uint
+
class W_ListObject(W_Object):
- from pypy.objspace.std.listtype import list_typedef as typedef
-
- def __init__(w_self, wrappeditems):
- w_self.wrappeditems = wrappeditems
+ statictype = W_ListType
+
+ def __init__(w_self, space, wrappeditems):
+ W_Object.__init__(w_self, space)
+ w_self.ob_item = []
+ w_self.ob_size = 0
+ newlen = len(wrappeditems)
+ _list_resize(w_self, newlen)
+ w_self.ob_size = newlen
+ items = w_self.ob_item
+ p = newlen
+ while p:
+ p -= 1
+ items[p] = wrappeditems[p]
def __repr__(w_self):
""" representation for debugging purposes """
- return "%s(%s)" % (w_self.__class__.__name__, w_self.wrappeditems)
+ reprlist = [repr(w_item) for w_item in w_self.ob_item[:w_self.ob_size]]
+ return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist))
- def unwrap(w_list, space):
- items = [space.unwrap(w_item) for w_item in w_list.wrappeditems]# XXX generic mixed types unwrap
- return list(items)
-
- def append(w_list, w_item):
- w_list.wrappeditems.append(w_item)
registerimplementation(W_ListObject)
-EMPTY_LIST = W_ListObject([])
-
-def init__List(space, w_list, __args__):
- w_iterable, = __args__.parse('list',
- (['sequence'], None, None), # signature
- [EMPTY_LIST]) # default argument
- #
- # this is the old version of the loop at the end of this function:
- #
- # w_list.wrappeditems = space.unpackiterable(w_iterable)
- #
- # This is commented out to avoid assigning a new RPython list to
- # 'wrappeditems', which defeats the W_FastSeqIterObject optimization.
- #
- items_w = w_list.wrappeditems
- del items_w[:]
- if w_iterable is not EMPTY_LIST:
+def unwrap__List(space, w_list):
+ items = [space.unwrap(w_item) for w_item in w_list.ob_item[:w_list.ob_size]]
+ return list(items)
+
+def object_init__List(space, w_list, w_args, w_kwds):
+ if space.is_true(w_kwds):
+ raise OperationError(space.w_TypeError,
+ space.wrap("no keyword arguments expected"))
+ w_list.ob_size = 0 # XXX think about it later
+ args = space.unpackiterable(w_args)
+ if len(args) == 0:
+ pass # empty list
+ elif len(args) == 1:
+ w_iterable = args[0]
w_iterator = space.iter(w_iterable)
while True:
try:
w_item = space.next(w_iterator)
- except OperationError, e:
- if not e.match(space, space.w_StopIteration):
- raise
+ except NoValue:
break # done
- items_w.append(w_item)
+ _ins1(w_list, w_list.ob_size, w_item)
+ else:
+ raise OperationError(space.w_TypeError,
+ space.wrap("list() takes at most 1 argument"))
def len__List(space, w_list):
- result = len(w_list.wrappeditems)
- return wrapint(space, result)
+ result = w_list.ob_size
+ return W_IntObject(space, result)
-def getitem__List_ANY(space, w_list, w_index):
- try:
- return w_list.wrappeditems[get_list_index(space, w_index)]
- except IndexError:
+def getitem__List_Int(space, w_list, w_index):
+ items = w_list.ob_item
+ idx = w_index.intval
+ if idx < 0:
+ idx += w_list.ob_size
+ if idx < 0 or idx >= w_list.ob_size:
raise OperationError(space.w_IndexError,
space.wrap("list index out of range"))
+ w_item = items[idx]
+ return w_item
def getitem__List_Slice(space, w_list, w_slice):
- # XXX consider to extend rlist's functionality?
- length = len(w_list.wrappeditems)
- start, stop, step, slicelength = w_slice.indices4(space, length)
+ items = w_list.ob_item
+ length = w_list.ob_size
+ start, stop, step, slicelength = slicetype.indices4(space, w_slice, length)
assert slicelength >= 0
- if step == 1 and 0 <= start <= stop:
- return W_ListObject(w_list.wrappeditems[start:stop])
- w_res = W_ListObject([None] * slicelength)
- items_w = w_list.wrappeditems
- subitems_w = w_res.wrappeditems
+ w_res = W_ListObject(space, [])
+ _list_resize(w_res, slicelength)
+ subitems = w_res.ob_item
for i in range(slicelength):
- subitems_w[i] = items_w[start]
+ subitems[i] = items[start]
start += step
+ w_res.ob_size = slicelength
return w_res
-def getslice__List_ANY_ANY(space, w_list, w_start, w_stop):
- length = len(w_list.wrappeditems)
- start, stop = normalize_simple_slice(space, length, w_start, w_stop)
- return W_ListObject(w_list.wrappeditems[start:stop])
-
-def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_sequence):
- length = len(w_list.wrappeditems)
- start, stop = normalize_simple_slice(space, length, w_start, w_stop)
- _setitem_slice_helper(space, w_list, start, 1, stop-start, w_sequence)
-
-def delslice__List_ANY_ANY(space, w_list, w_start, w_stop):
- length = len(w_list.wrappeditems)
- start, stop = normalize_simple_slice(space, length, w_start, w_stop)
- _delitem_slice_helper(space, w_list, start, 1, stop-start)
-
-def contains__List_ANY(space, w_list, w_obj):
- # needs to be safe against eq_w() mutating the w_list behind our back
- i = 0
- items_w = w_list.wrappeditems
- while i < len(items_w): # intentionally always calling len!
- if space.eq_w(items_w[i], w_obj):
- return space.w_True
- i += 1
- return space.w_False
-
def iter__List(space, w_list):
- from pypy.objspace.std import iterobject
- return iterobject.W_FastListIterObject(w_list, w_list.wrappeditems)
+ import iterobject
+ return iterobject.W_SeqIterObject(space, w_list)
def add__List_List(space, w_list1, w_list2):
- return W_ListObject(w_list1.wrappeditems + w_list2.wrappeditems)
+ w_res = W_ListObject(space, [])
+ newlen = w_list1.ob_size + w_list2.ob_size
+ _list_resize(w_res, newlen)
+ p = 0
+ items = w_res.ob_item
+ src = w_list1.ob_item
+ for i in range(w_list1.ob_size):
+ items[p] = src[i]
+ p += 1
+ src = w_list2.ob_item
+ for i in range(w_list2.ob_size):
+ items[p] = src[i]
+ p += 1
+ w_res.ob_size = p
+ return w_res
+def mul__List_Int(space, w_list, w_int):
+ w_res = W_ListObject(space, [])
+ times = w_int.intval
+ src = w_list.ob_item
+ size = w_list.ob_size
+ newlen = size * times # XXX check overflow
+ _list_resize(w_res, newlen)
+ items = w_res.ob_item
+ p = 0
+ for _ in range(times):
+ for i in range(size):
+ items[p] = src[i]
+ p += 1
+ w_res.ob_size = p
+ return w_res
-def inplace_add__List_ANY(space, w_list1, w_iterable2):
- list_extend__List_ANY(space, w_list1, w_iterable2)
- return w_list1
-
-def inplace_add__List_List(space, w_list1, w_list2):
- list_extend__List_List(space, w_list1, w_list2)
- return w_list1
-
-def mul_list_times(space, w_list, w_times):
- try:
- times = space.getindex_w(w_times, space.w_OverflowError)
- except OperationError, e:
- if e.match(space, space.w_TypeError):
- raise FailedToImplement
- raise
- return W_ListObject(w_list.wrappeditems * times)
-
-def mul__List_ANY(space, w_list, w_times):
- return mul_list_times(space, w_list, w_times)
-
-def mul__ANY_List(space, w_times, w_list):
- return mul_list_times(space, w_list, w_times)
-
-def inplace_mul__List_ANY(space, w_list, w_times):
- try:
- times = space.getindex_w(w_times, space.w_OverflowError)
- except OperationError, e:
- if e.match(space, space.w_TypeError):
- raise FailedToImplement
- raise
- w_list.wrappeditems *= times
- return w_list
+def mul__Int_List(space, w_int, w_list):
+ return mul__List_Int(space, w_list, w_int)
def eq__List_List(space, w_list1, w_list2):
- # needs to be safe against eq_w() mutating the w_lists behind our back
- items1_w = w_list1.wrappeditems
- items2_w = w_list2.wrappeditems
- return equal_wrappeditems(space, items1_w, items2_w)
-
-def equal_wrappeditems(space, items1_w, items2_w):
- if len(items1_w) != len(items2_w):
+ items1 = w_list1.ob_item
+ items2 = w_list2.ob_item
+ if w_list1.ob_size != w_list2.ob_size:
return space.w_False
- i = 0
- while i < len(items1_w) and i < len(items2_w):
- if not space.eq_w(items1_w[i], items2_w[i]):
+ for i in range(w_list1.ob_size):
+ if not space.is_true(space.eq(items1[i], items2[i])):
return space.w_False
- i += 1
return space.w_True
-def lessthan_unwrappeditems(space, items1_w, items2_w):
- # needs to be safe against eq_w() mutating the w_lists behind our back
+def _min(a, b):
+ if a < b:
+ return a
+ return b
+
+def lt__List_List(space, w_list1, w_list2):
+ items1 = w_list1.ob_item
+ items2 = w_list2.ob_item
+ ncmp = _min(w_list1.ob_size, w_list2.ob_size)
# Search for the first index where items are different
- i = 0
- while i < len(items1_w) and i < len(items2_w):
- w_item1 = items1_w[i]
- w_item2 = items2_w[i]
- if not space.eq_w(w_item1, w_item2):
- return space.lt(w_item1, w_item2)
- i += 1
+ for p in range(ncmp):
+ if not space.is_true(space.eq(items1[p], items2[p])):
+ return space.lt(items1[p], items2[p])
# No more items to compare -- compare sizes
- return space.newbool(len(items1_w) < len(items2_w))
+ return space.newbool(w_list1.ob_size < w_list2.ob_size)
-def greaterthan_unwrappeditems(space, items1_w, items2_w):
- # needs to be safe against eq_w() mutating the w_lists behind our back
+def gt__List_List(space, w_list1, w_list2):
+ items1 = w_list1.ob_item
+ items2 = w_list2.ob_item
+ ncmp = _min(w_list1.ob_size, w_list2.ob_size)
# Search for the first index where items are different
- i = 0
- while i < len(items1_w) and i < len(items2_w):
- w_item1 = items1_w[i]
- w_item2 = items2_w[i]
- if not space.eq_w(w_item1, w_item2):
- return space.gt(w_item1, w_item2)
- i += 1
+ for p in range(ncmp):
+ if not space.is_true(space.eq(items1[p], items2[p])):
+ return space.gt(items1[p], items2[p])
# No more items to compare -- compare sizes
- return space.newbool(len(items1_w) > len(items2_w))
-
-def lt__List_List(space, w_list1, w_list2):
- return lessthan_unwrappeditems(space, w_list1.wrappeditems,
- w_list2.wrappeditems)
+ return space.newbool(w_list1.ob_size > w_list2.ob_size)
-def gt__List_List(space, w_list1, w_list2):
- return greaterthan_unwrappeditems(space, w_list1.wrappeditems,
- w_list2.wrappeditems)
+# upto here, lists are nearly identical to tuples, despite the
+# fact that we now support over-allocation!
-def delitem__List_ANY(space, w_list, w_idx):
- idx = get_list_index(space, w_idx)
- try:
- del w_list.wrappeditems[idx]
- except IndexError:
+def delitem__List_Int(space, w_list, w_idx):
+ i = w_idx.intval
+ if i < 0:
+ i += w_list.ob_size
+ if i < 0 or i >= w_list.ob_size:
raise OperationError(space.w_IndexError,
space.wrap("list deletion index out of range"))
+ _del_slice(w_list, i, i+1)
return space.w_None
-
def delitem__List_Slice(space, w_list, w_slice):
- start, stop, step, slicelength = w_slice.indices4(space,
- len(w_list.wrappeditems))
- _delitem_slice_helper(space, w_list, start, step, slicelength)
-
-def _delitem_slice_helper(space, w_list, start, step, slicelength):
- if slicelength==0:
- return
-
- if step < 0:
- start = start + step * (slicelength-1)
- step = -step
-
+ start, stop, step, slicelength = slicetype.indices4(space, w_slice, w_list.ob_size)
if step == 1:
- assert start >= 0
- assert slicelength >= 0
- del w_list.wrappeditems[start:start+slicelength]
- else:
- items = w_list.wrappeditems
- n = len(items)
- i = start
-
- for discard in range(1, slicelength):
- j = i+1
- i += step
- while j < i:
- items[j-discard] = items[j]
- j += 1
-
- j = i+1
- while j < n:
- items[j-slicelength] = items[j]
- j += 1
- start = n - slicelength
- assert start >= 0 # annotator hint
- del items[start:]
-
-def setitem__List_ANY_ANY(space, w_list, w_index, w_any):
- idx = get_list_index(space, w_index)
- try:
- w_list.wrappeditems[idx] = w_any
- except IndexError:
+ return _setitem_slice_helper(space, w_list, w_slice, [], 0)
+
+ # The current code starts from the top, to simplify
+ # coding. A later optimization could be to start from
+ # the bottom, which would reduce the list motion.
+ # A further later optimization would be to special-case
+ # a step of -1, because this version will perform a LOT
+ # of extra motion for this case. Anybody with a real-life
+ # use-case for this is welcome to write the special case.
+ r = range(start, stop, step)
+ if step > 0:
+ r.reverse()
+ for i in r:
+ _del_slice(w_list, i, i+1)
+ return space.w_None
+
+def setitem__List_Int_ANY(space, w_list, w_index, w_any):
+ items = w_list.ob_item
+ idx = w_index.intval
+ if idx < 0:
+ idx += w_list.ob_size
+ if idx < 0 or idx >= w_list.ob_size:
raise OperationError(space.w_IndexError,
space.wrap("list index out of range"))
+ items[idx] = w_any
return space.w_None
-def setitem__List_Slice_ANY(space, w_list, w_slice, w_iterable):
- oldsize = len(w_list.wrappeditems)
- start, stop, step, slicelength = w_slice.indices4(space, oldsize)
- _setitem_slice_helper(space, w_list, start, step, slicelength, w_iterable)
-
-def _setitem_slice_helper(space, w_list, start, step, slicelength, w_iterable):
- if isinstance(w_iterable, W_ListObject):
- sequence2 = w_iterable.wrappeditems
- else:
- sequence2 = space.unpackiterable(w_iterable)
+def setitem__List_Slice_List(space, w_list, w_slice, w_list2):
+ return _setitem_slice_helper(space, w_list, w_slice, w_list2.ob_item, w_list2.ob_size)
+
+def setitem__List_Slice_Tuple(space, w_list, w_slice, w_tuple):
+ t = w_tuple.wrappeditems
+ return _setitem_slice_helper(space, w_list, w_slice, t, len(t))
+def _setitem_slice_helper(space, w_list, w_slice, sequence2, len2):
+ start, stop, step, slicelength = slicetype.indices4(space, w_slice, w_list.ob_size)
assert slicelength >= 0
- items = w_list.wrappeditems
- oldsize = len(items)
- len2 = len(sequence2)
+
if step == 1: # Support list resizing for non-extended slices
- delta = slicelength - len2
- if delta < 0:
- delta = -delta
- newsize = oldsize + delta
- # XXX support this in rlist!
- items += [None] * delta
- lim = start+len2
- i = newsize - 1
- while i >= lim:
- items[i] = items[i-delta]
- i -= 1
- elif start >= 0:
- del items[start:start+delta]
- else:
- assert delta==0
+ oldsize = w_list.ob_size
+ delta = len2 - slicelength
+ newsize = oldsize + delta
+ _list_resize(w_list, newsize)
+ w_list.ob_size = newsize
+ r = range(stop+delta, newsize)
+ if delta > 0:
+ r.reverse()
+ items = w_list.ob_item
+ for i in r:
+ items[i] = items[i-delta]
elif len2 != slicelength: # No resize for extended slices
raise OperationError(space.w_ValueError, space.wrap("attempt to "
"assign sequence of size %d to extended slice of size %d" %
(len2,slicelength)))
+ r = range(len2)
+ items = w_list.ob_item
if sequence2 is items:
if step > 0:
# Always copy starting from the right to avoid
# having to make a shallow copy in the case where
# the source and destination lists are the same list.
- i = len2 - 1
- start += i*step
- while i >= 0:
- items[start] = sequence2[i]
- start -= step
- i -= 1
- return
+ r.reverse()
else:
# Make a shallow copy to more easily handle the reversal case
sequence2 = list(sequence2)
- for i in range(len2):
- items[start] = sequence2[i]
- start += step
-
-app = gateway.applevel("""
- def listrepr(currently_in_repr, l):
- 'The app-level part of repr().'
- list_id = id(l)
- if list_id in currently_in_repr:
- return '[...]'
- currently_in_repr[list_id] = 1
- try:
- return "[" + ", ".join([repr(x) for x in l]) + ']'
- finally:
- try:
- del currently_in_repr[list_id]
- except:
- pass
-""", filename=__file__)
-
-listrepr = app.interphook("listrepr")
+ for i in r:
+ items[start+i*step] = sequence2[i]
+ return space.w_None
def repr__List(space, w_list):
- if len(w_list.wrappeditems) == 0:
- return space.wrap('[]')
- ec = space.getexecutioncontext()
- w_currently_in_repr = ec._py_repr
- if w_currently_in_repr is None:
- w_currently_in_repr = ec._py_repr = space.newdict()
- return listrepr(space, w_currently_in_repr, w_list)
-
-def list_insert__List_ANY_ANY(space, w_list, w_where, w_any):
- where = space.int_w(w_where)
- length = len(w_list.wrappeditems)
+ w = space.wrap
+ a = space.add
+ reprs_w = map(space.repr, space.unpackiterable(w_list))
+ from pypy.objspace.std.stringtype import W_StringType
+ w_bm = space.getattr(space.wrap(', '), space.wrap('join'))
+ return a(a(w('['), space.call_function(w_bm, space.newlist(reprs_w))), w(']'))
+ return space.newstring([])
+
+def hash__List(space,w_list):
+ raise OperationError(space.w_TypeError,space.wrap("list objects are unhashable"))
+
+# adapted C code
+def _roundupsize(n):
+ nbits = r_uint(0)
+ n2 = n >> 5
+
+## /* Round up:
+## * If n < 256, to a multiple of 8.
+## * If n < 2048, to a multiple of 64.
+## * If n < 16384, to a multiple of 512.
+## * If n < 131072, to a multiple of 4096.
+## * If n < 1048576, to a multiple of 32768.
+## * If n < 8388608, to a multiple of 262144.
+## * If n < 67108864, to a multiple of 2097152.
+## * If n < 536870912, to a multiple of 16777216.
+## * ...
+## * If n < 2**(5+3*i), to a multiple of 2**(3*i).
+## *
+## * This over-allocates proportional to the list size, making room
+## * for additional growth. The over-allocation is mild, but is
+## * enough to give linear-time amortized behavior over a long
+## * sequence of appends() in the presence of a poorly-performing
+## * system realloc() (which is a reality, e.g., across all flavors
+## * of Windows, with Win9x behavior being particularly bad -- and
+## * we've still got address space fragmentation problems on Win9x
+## * even with this scheme, although it requires much longer lists to
+## * provoke them than it used to).
+## */
+ while 1:
+ n2 >>= 3
+ nbits += 3
+ if not n2 :
+ break
+ return ((n >> nbits) + 1) << nbits
+
+# before we have real arrays,
+# we use lists, allocated to fixed size.
+# XXX memory overflow is ignored here.
+# See listobject.c for reference.
+
+for_later = """
+#define NRESIZE(var, type, nitems) \
+do { \
+ size_t _new_size = _roundupsize(nitems); \
+ if (_new_size <= ((~(size_t)0) / sizeof(type))) \
+ PyMem_RESIZE(var, type, _new_size); \
+ else \
+ var = NULL; \
+} while (0)
+"""
+
+def _list_resize(w_list, newlen):
+ if newlen > len(w_list.ob_item):
+ true_size = _roundupsize(newlen)
+ old_items = w_list.ob_item
+ w_list.ob_item = items = [None] * true_size
+ for p in range(len(old_items)):
+ items[p] = old_items[p]
+
+def _ins1(w_list, where, w_any):
+ _list_resize(w_list, w_list.ob_size+1)
+ size = w_list.ob_size
+ items = w_list.ob_item
if where < 0:
- where += length
- if where < 0:
- where = 0
- elif where > length:
- where = length
- w_list.wrappeditems.insert(where, w_any)
- return space.w_None
+ where += size
+ if where < 0:
+ where = 0
+ if (where > size):
+ where = size
+ for i in range(size, where, -1):
+ items[i] = items[i-1]
+ items[where] = w_any
+ w_list.ob_size += 1
-def list_append__List_ANY(space, w_list, w_any):
- w_list.wrappeditems.append(w_any)
+def list_insert__List_Int_ANY(space, w_list, w_where, w_any):
+ _ins1(w_list, w_where.intval, w_any)
return space.w_None
-def list_extend__List_List(space, w_list, w_other):
- w_list.wrappeditems += w_other.wrappeditems
+def list_append__List_ANY(space, w_list, w_any):
+ _ins1(w_list, w_list.ob_size, w_any)
return space.w_None
def list_extend__List_ANY(space, w_list, w_any):
- w_list.wrappeditems += space.unpackiterable(w_any)
+ lis = space.unpackiterable(w_any)
+ newlen = w_list.ob_size + len(lis)
+ _list_resize(w_list, newlen)
+ d = w_list.ob_size
+ items = w_list.ob_item
+ for i in range(len(lis)):
+ items[d+i] = lis[i]
+ w_list.ob_size = newlen
return space.w_None
+def _del_slice(w_list, ilow, ihigh):
+ """ similar to the deletion part of list_ass_slice in CPython """
+ if ilow < 0:
+ ilow = 0
+ elif ilow > w_list.ob_size:
+ ilow = w_list.ob_size
+ if ihigh < ilow:
+ ihigh = ilow
+ elif ihigh > w_list.ob_size:
+ ihigh = w_list.ob_size
+ items = w_list.ob_item
+ d = ihigh-ilow
+ # XXX this is done by CPython to hold the elements
+ # to be deleted. I have no idea how to express
+ # this here, but we need to be aware when we write
+ # a compiler.
+ # recycle = [items[i] for i in range(ilow, ihigh)]
+ for i in range(ilow, w_list.ob_size - d):
+ items[i] = items[i+d]
+ items[i+d] = None
+ w_list.ob_size -= d
+
# note that the default value will come back wrapped!!!
-def list_pop__List_ANY(space, w_list, w_idx=-1):
- items = w_list.wrappeditems
- if len(items)== 0:
+def list_pop__List_Int(space, w_list, w_idx=-1):
+ if w_list.ob_size == 0:
raise OperationError(space.w_IndexError,
space.wrap("pop from empty list"))
- idx = space.int_w(w_idx)
- try:
- return items.pop(idx)
- except IndexError:
+ i = w_idx.intval
+ if i < 0:
+ i += w_list.ob_size
+ if i < 0 or i >= w_list.ob_size:
raise OperationError(space.w_IndexError,
space.wrap("pop index out of range"))
+ w_res = w_list.ob_item[i]
+ _del_slice(w_list, i, i+1)
+ return w_res
def list_remove__List_ANY(space, w_list, w_any):
- # needs to be safe against eq_w() mutating the w_list behind our back
- items = w_list.wrappeditems
- i = 0
- while i < len(items):
- if space.eq_w(items[i], w_any):
- if i < len(items): # if this is wrong the list was changed
- del items[i]
+ eq = space.eq
+ items = w_list.ob_item
+ for i in range(w_list.ob_size):
+ cmp = eq(items[i], w_any)
+ if space.is_true(cmp):
+ _del_slice(w_list, i, i+1)
return space.w_None
- i += 1
- raise OperationError(space.w_ValueError,
+ raise OperationError(space.w_IndexError,
space.wrap("list.remove(x): x not in list"))
-def list_index__List_ANY_ANY_ANY(space, w_list, w_any, w_start, w_stop):
- # needs to be safe against eq_w() mutating the w_list behind our back
- items = w_list.wrappeditems
- size = len(items)
- i = slicetype.adapt_bound(space, size, w_start)
- stop = slicetype.adapt_bound(space, size, w_stop)
- while i < stop and i < len(items):
- if space.eq_w(items[i], w_any):
+def list_index__List_ANY_Int_Int(space, w_list, w_any, w_start, w_stop):
+ eq = space.eq
+ items = w_list.ob_item
+ size = w_list.ob_size
+ start = space.unwrap(w_start)
+ if start < 0:
+ start += size
+ start = min(max(0,start),size)
+ stop = space.unwrap(w_stop)
+ if stop < 0:
+ stop += size
+ stop = min(max(start,stop),size)
+
+ for i in range(start,stop):
+ cmp = eq(items[i], w_any)
+ if space.is_true(cmp):
return space.wrap(i)
- i += 1
raise OperationError(space.w_ValueError,
space.wrap("list.index(x): x not in list"))
def list_count__List_ANY(space, w_list, w_any):
- # needs to be safe against eq_w() mutating the w_list behind our back
- count = 0
- i = 0
- items = w_list.wrappeditems
- while i < len(items):
- if space.eq_w(items[i], w_any):
+ eq = space.eq
+ items = w_list.ob_item
+ count = r_int(0)
+ for i in range(w_list.ob_size):
+ cmp = eq(items[i], w_any)
+ if space.is_true(cmp):
count += 1
- i += 1
return space.wrap(count)
+# Reverse a slice of a list in place, from lo up to (exclusive) hi.
+# (also used in sort, later)
+
+def _reverse_slice(lis, lo, hi):
+ hi -= 1
+ while lo < hi:
+ t = lis[lo]
+ lis[lo] = lis[hi]
+ lis[hi] = t
+ lo += 1
+ hi -= 1
+
def list_reverse__List(space, w_list):
- w_list.wrappeditems.reverse()
+ if w_list.ob_size > 1:
+ _reverse_slice(w_list.ob_item, 0, w_list.ob_size)
return space.w_None
-# ____________________________________________________________
-# Sorting
+
-# Reverse a slice of a list in place, from lo up to (exclusive) hi.
-# (used in sort)
+# Python Quicksort Written by Magnus Lie Hetland
+# http://www.hetland.org/python/quicksort.html
-class KeyContainer(baseobjspace.W_Root):
- def __init__(self, w_key, w_item):
- self.w_key = w_key
- self.w_item = w_item
-
-# NOTE: all the subclasses of TimSort should inherit from a common subclass,
-# so make sure that only SimpleSort inherits directly from TimSort.
-# This is necessary to hide the parent method TimSort.lt() from the
-# annotator.
-class SimpleSort(TimSort):
- def lt(self, a, b):
- space = self.space
- return space.is_true(space.lt(a, b))
-
-class CustomCompareSort(SimpleSort):
- def lt(self, a, b):
- space = self.space
- w_cmp = self.w_cmp
- w_result = space.call_function(w_cmp, a, b)
- try:
- result = space.int_w(w_result)
- except OperationError, e:
- if e.match(space, space.w_TypeError):
+# NOTE: we cannot yet detect that a user comparision
+# function modifies the list in-place. The
+# CPython sort() should be studied to learn how
+# to implement this functionality.
+
+def _partition(list, start, end, lt):
+ pivot = list[end] # Partition around the last value
+ bottom = start-1 # Start outside the area to be partitioned
+ top = end # Ditto
+
+ done = 0
+ while not done: # Until all elements are partitioned...
+
+ while not done: # Until we find an out of place element...
+ bottom = bottom+1 # ... move the bottom up.
+
+ if bottom == top: # If we hit the top...
+ done = 1 # ... we are done.
+ break
+
+ if lt(pivot, list[bottom]): # Is the bottom out of place?
+ list[top] = list[bottom] # Then put it at the top...
+ break # ... and start searching from the top.
+
+ while not done: # Until we find an out of place element...
+ top = top-1 # ... move the top down.
+
+ if top == bottom: # If we hit the bottom...
+ done = 1 # ... we are done.
+ break
+
+ if lt(list[top], pivot): # Is the top out of place?
+ list[bottom] = list[top] # Then put it at the bottom...
+ break # ...and start searching from the bottom.
+
+ list[top] = pivot # Put the pivot in its place.
+ return top # Return the split point
+
+
+def _quicksort(list, start, end, lt):
+ if start < end: # If there are two or more elements...
+ split = _partition(list, start, end, lt) # ... partition the sublist...
+ _quicksort(list, start, split-1, lt) # ... and sort both halves.
+ _quicksort(list, split+1, end, lt)
+
+def list_sort__List_ANY(space, w_list, w_cmp):
+ if w_cmp is space.w_None:
+ def lt(a,b):
+ return space.is_true(space.lt(a,b))
+ else:
+ def lt(a,b):
+ result = space.unwrap(space.call_function(w_cmp, a, b))
+ if not isinstance(result,int):
raise OperationError(space.w_TypeError,
- space.wrap("comparison function must return int"))
- raise
- return result < 0
-
-class CustomKeySort(SimpleSort):
- def lt(self, a, b):
- assert isinstance(a, KeyContainer)
- assert isinstance(b, KeyContainer)
- space = self.space
- return space.is_true(space.lt(a.w_key, b.w_key))
-
-class CustomKeyCompareSort(CustomCompareSort):
- def lt(self, a, b):
- assert isinstance(a, KeyContainer)
- assert isinstance(b, KeyContainer)
- return CustomCompareSort.lt(self, a.w_key, b.w_key)
-
-def list_sort__List_ANY_ANY_ANY(space, w_list, w_cmp, w_keyfunc, w_reverse):
- has_cmp = not space.is_w(w_cmp, space.w_None)
- has_key = not space.is_w(w_keyfunc, space.w_None)
- has_reverse = space.is_true(w_reverse)
-
- # create and setup a TimSort instance
- if has_cmp:
- if has_key:
- sorterclass = CustomKeyCompareSort
- else:
- sorterclass = CustomCompareSort
- else:
- if has_key:
- sorterclass = CustomKeySort
- else:
- sorterclass = SimpleSort
- items = w_list.wrappeditems
- sorter = sorterclass(items, len(items))
- sorter.space = space
- sorter.w_cmp = w_cmp
-
- try:
- # The list is temporarily made empty, so that mutations performed
- # by comparison functions can't affect the slice of memory we're
- # sorting (allowing mutations during sorting is an IndexError or
- # core-dump factory, since wrappeditems may change).
- w_list.wrappeditems = []
-
- # wrap each item in a KeyContainer if needed
- if has_key:
- for i in range(sorter.listlength):
- w_item = sorter.list[i]
- w_key = space.call_function(w_keyfunc, w_item)
- sorter.list[i] = KeyContainer(w_key, w_item)
-
- # Reverse sort stability achieved by initially reversing the list,
- # applying a stable forward sort, then reversing the final result.
- if has_reverse:
- sorter.list.reverse()
-
- # perform the sort
- sorter.sort()
-
- # reverse again
- if has_reverse:
- sorter.list.reverse()
-
- finally:
- # unwrap each item if needed
- if has_key:
- for i in range(sorter.listlength):
- w_obj = sorter.list[i]
- if isinstance(w_obj, KeyContainer):
- sorter.list[i] = w_obj.w_item
-
- # check if the user mucked with the list during the sort
- mucked = len(w_list.wrappeditems) > 0
-
- # put the items back into the list
- w_list.wrappeditems = sorter.list
-
- if mucked:
- raise OperationError(space.w_ValueError,
- space.wrap("list modified during sort"))
+ space.wrap("comparison function must return int"))
+ return result < 0
+ # XXX Basic quicksort implementation
+ # XXX this is not stable !!
+ _quicksort(w_list.ob_item, 0, w_list.ob_size-1, lt)
return space.w_None
-from pypy.objspace.std import listtype
-register_all(vars(), listtype)
+"""
+static PyMethodDef list_methods[] = {
+ {"append", (PyCFunction)listappend, METH_O, append_doc},
+ {"insert", (PyCFunction)listinsert, METH_VARARGS, insert_doc},
+ {"extend", (PyCFunction)listextend, METH_O, extend_doc},
+ {"pop", (PyCFunction)listpop, METH_VARARGS, pop_doc},
+ {"remove", (PyCFunction)listremove, METH_O, remove_doc},
+ {"index", (PyCFunction)listindex, METH_O, index_doc},
+ {"count", (PyCFunction)listcount, METH_O, count_doc},
+ {"reverse", (PyCFunction)listreverse, METH_NOARGS, reverse_doc},
+ {"sort", (PyCFunction)listsort, METH_VARARGS, sort_doc},
+ {NULL, NULL} /* sentinel */
+};
+"""
+
+register_all(vars(), W_ListType)
Modified: pypy/branch/avm/pypy/objspace/std/noneobject.py
==============================================================================
--- pypy/branch/avm/pypy/objspace/std/noneobject.py (original)
+++ pypy/branch/avm/pypy/objspace/std/noneobject.py Thu Nov 5 20:27:32 2009
@@ -5,19 +5,17 @@
"""
from pypy.objspace.std.objspace import *
+from nonetype import W_NoneType
class W_NoneObject(W_Object):
- from pypy.objspace.std.nonetype import none_typedef as typedef
-
- def unwrap(w_self, space):
- return None
-
+ statictype = W_NoneType
registerimplementation(W_NoneObject)
-W_NoneObject.w_None = W_NoneObject()
+def unwrap__None(space, w_none):
+ return None
-def nonzero__None(space, w_none):
- return space.w_False
+def is_true__None(space, w_none):
+ return False
def repr__None(space, w_none):
return space.wrap('None')
Modified: pypy/branch/avm/pypy/objspace/std/sliceobject.py
==============================================================================
--- pypy/branch/avm/pypy/objspace/std/sliceobject.py (original)
+++ pypy/branch/avm/pypy/objspace/std/sliceobject.py Thu Nov 5 20:27:32 2009
@@ -6,135 +6,37 @@
"""
from pypy.objspace.std.objspace import *
-from pypy.interpreter import gateway
-from pypy.objspace.std.slicetype import _Eval_SliceIndex
+from slicetype import W_SliceType
class W_SliceObject(W_Object):
- from pypy.objspace.std.slicetype import slice_typedef as typedef
+ statictype = W_SliceType
- def __init__(w_self, w_start, w_stop, w_step):
- assert w_start is not None
- assert w_stop is not None
- assert w_step is not None
+ def __init__(w_self, space, w_start, w_stop, w_step):
+ W_Object.__init__(w_self, space)
w_self.w_start = w_start
w_self.w_stop = w_stop
w_self.w_step = w_step
- def unwrap(w_slice, space):
- return slice(space.unwrap(w_slice.w_start), space.unwrap(w_slice.w_stop), space.unwrap(w_slice.w_step))
+registerimplementation(W_SliceObject)
- def indices3(w_slice, space, length):
- if space.is_w(w_slice.w_step, space.w_None):
- step = 1
- else:
- step = _Eval_SliceIndex(space, w_slice.w_step)
- if step == 0:
- raise OperationError(space.w_ValueError,
- space.wrap("slice step cannot be zero"))
- if space.is_w(w_slice.w_start, space.w_None):
- if step < 0:
- start = length - 1
- else:
- start = 0
+
+def getattribute__Slice_ANY(space, w_slice, w_attr):
+ if space.is_true(space.eq(w_attr, space.wrap('start'))):
+ if w_slice.w_start is None:
+ return space.w_None
else:
- start = _Eval_SliceIndex(space, w_slice.w_start)
- if start < 0:
- start += length
- if start < 0:
- if step < 0:
- start = -1
- else:
- start = 0
- elif start >= length:
- if step < 0:
- start = length - 1
- else:
- start = length
- if space.is_w(w_slice.w_stop, space.w_None):
- if step < 0:
- stop = -1
- else:
- stop = length
+ return w_slice.w_start
+ if space.is_true(space.eq(w_attr, space.wrap('stop'))):
+ if w_slice.w_stop is None:
+ return space.w_None
else:
- stop = _Eval_SliceIndex(space, w_slice.w_stop)
- if stop < 0:
- stop += length
- if stop < 0:
- stop =-1
- elif stop > length:
- stop = length
- return start, stop, step
-
- def indices4(w_slice, space, length):
- start, stop, step = w_slice.indices3(space, length)
- if (step < 0 and stop >= start) or (step > 0 and start >= stop):
- slicelength = 0
- elif step < 0:
- slicelength = (stop - start + 1) / step + 1
+ return w_slice.w_stop
+ if space.is_true(space.eq(w_attr, space.wrap('step'))):
+ if w_slice.w_step is None:
+ return space.w_None
else:
- slicelength = (stop - start - 1) / step + 1
- return start, stop, step, slicelength
+ return w_slice.w_step
+ raise FailedToImplement(space.w_AttributeError)
-registerimplementation(W_SliceObject)
-
-
-def normalize_simple_slice(space, length, w_start, w_stop):
- """Helper for the {get,set,del}slice multimethod implementations."""
- # this returns a pair (start, stop) which is usable for slicing
- # a sequence of the given length in the most friendly way, i.e.
- # guaranteeing that 0 <= start <= stop <= length.
- start = space.int_w(w_start)
- stop = space.int_w(w_stop)
- assert length >= 0
- if start < 0:
- start = 0
- if stop < start:
- stop = start
- if stop > length:
- stop = length
- if start > length:
- start = length
- return start, stop
-
-
-repr__Slice = gateway.applevel("""
- def repr__Slice(aslice):
- return 'slice(%r, %r, %r)' % (aslice.start, aslice.stop, aslice.step)
-""", filename=__file__).interphook("repr__Slice")
-
-def eq__Slice_Slice(space, w_slice1, w_slice2):
- # We need this because CPython considers that slice1 == slice1
- # is *always* True (e.g. even if slice1 was built with non-comparable
- # parameters
- if space.is_w(w_slice1, w_slice2):
- return space.w_True
- if space.eq_w(w_slice1.w_start, w_slice2.w_start) and \
- space.eq_w(w_slice1.w_stop, w_slice2.w_stop) and \
- space.eq_w(w_slice1.w_step, w_slice2.w_step):
- return space.w_True
- else:
- return space.w_False
-
-def lt__Slice_Slice(space, w_slice1, w_slice2):
- if space.is_w(w_slice1, w_slice2):
- return space.w_False # see comments in eq__Slice_Slice()
- if space.eq_w(w_slice1.w_start, w_slice2.w_start):
- if space.eq_w(w_slice1.w_stop, w_slice2.w_stop):
- return space.lt(w_slice1.w_step, w_slice2.w_step)
- else:
- return space.lt(w_slice1.w_stop, w_slice2.w_stop)
- else:
- return space.lt(w_slice1.w_start, w_slice2.w_start)
-
-# indices impl
-
-def slice_indices__Slice_ANY(space, w_slice, w_length):
- length = space.getindex_w(w_length, space.w_OverflowError)
- start, stop, step = w_slice.indices3(space, length)
- return space.newtuple([space.wrap(start), space.wrap(stop),
- space.wrap(step)])
-
-# register all methods
-from pypy.objspace.std import slicetype
-register_all(vars(), slicetype)
+register_all(vars())
Modified: pypy/branch/avm/pypy/objspace/std/stringobject.py
==============================================================================
--- pypy/branch/avm/pypy/objspace/std/stringobject.py (original)
+++ pypy/branch/avm/pypy/objspace/std/stringobject.py Thu Nov 5 20:27:32 2009
@@ -1,190 +1,211 @@
-# -*- coding: latin-1 -*-
+# -*- Coding: Latin-1 -*-
+"""
+stringobject.py
+
+Synopsis of implemented methods (* marks work in progress)
+
+Py PyPy
+
+ def _is_generic(w_self, fun):
+ def mod__String_ANY(space, w_str, w_item):def mod__String_Tuple(space, w_str, w_tuple):def mod_str_tuple(space, w_format, w_args):
+ def ord__String(space, w_str):
+ def string_richcompare(space, w_str1, w_str2, op):
+ def unwrap__String(space, w_str):
+__add__ def add__String_String(space, w_left, w_right):
+__class__
+__contains__
+__delattr__
+__doc__
+__eq__ def eq__String_String(space, w_str1, w_str2):
+__ge__ def ge__String_String(space, w_str1, w_str2):
+__getattribute__
+__getitem__ def getitem__String_Int(space, w_str, w_int): def getitem__String_Slice(space, w_str, w_slice):
+__getslice__
+__gt__ def gt__String_String(space, w_str1, w_str2):
+__hash__ def hash__String(space, w_str):
+__init__
+__le__ def le__String_String(space, w_str1, w_str2):
+__len__ def len__String(space, w_str):
+__lt__ def lt__String_String(space, w_str1, w_str2):
+__mul__
+__ne__ def ne__String_String(space, w_str1, w_str2):
+__new__
+__reduce__
+__repr__ def repr__String(space, w_str):
+__rmul__
+__setattr__
+__str__ def str__String(space, w_str):
+capitalize def str_capitalize__String(space, w_self):
+center def str_center__String_Int(space, w_self):
+count def str_count__String_String_Int_Int(space, w_self): [optional arguments not supported now]
+decode !Unicode not supported now
+encode !Unicode not supported now
+endswith str_endswith__String_String [optional arguments not supported now]
+expandtabs str_expandtabs__String_Int
+find OK
+index OK
+isalnum def str_isalnum__String(space, w_self): def _isalnum(ch):
+isalpha def str_isalpha__String(space, w_self): def _isalpha(ch):
+isdigit def str_isdigit__String(space, w_self): def _isdigit(ch):
+islower def str_islower__String(space, w_self): def _islower(ch):
+isspace def str_isspace__String(space, w_self): def _isspace(ch):
+istitle def str_istitle(space, w_self):
+isupper def str_isupper__String(space, w_self): def _isupper(ch):
+join def str_join__String_ANY(space, w_self, w_list):
+ljust def str_ljust__String_ANY(space, w_self, w_arg):
+lower OK
+lstrip def str_lstrip__String_String(space, w_self, w_chars):
+replace OK
+rfind OK
+rindex OK
+rjust def str_rjust__String_ANY(space, w_self, w_arg):
+rstrip def str_rstrip__String_String(space, w_self, w_chars):
+split def str_split__String_None_Int(space, w_self, w_none, w_maxsplit=-1):def str_split__String_String_Int(space, w_self, w_by, w_maxsplit=-1):
+splitlines def str_splitlines__String_String(space, w_self, w_keepends):
+startswith str_startswith__String_String [optional arguments not supported now]
+strip def str_strip__String_String(space, w_self, w_chars):
+swapcase OK
+title def str_title__String(space, w_self):
+translate OK
+upper def str_upper__String(space, w_self):
+zfill OK
+"""
from pypy.objspace.std.objspace import *
from pypy.interpreter import gateway
-from pypy.rlib.rarithmetic import ovfcheck, _hash_string
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.objspace.std.inttype import wrapint
-from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
-from pypy.objspace.std import slicetype
-from pypy.objspace.std.listobject import W_ListObject
-from pypy.objspace.std.noneobject import W_NoneObject
-from pypy.objspace.std.tupleobject import W_TupleObject
-from pypy.rlib.rstring import StringBuilder
-from pypy.interpreter.buffer import StringBuffer
+from stringtype import W_StringType
+from intobject import W_IntObject
+from sliceobject import W_SliceObject
+import slicetype
+from listobject import W_ListObject
+from noneobject import W_NoneObject
+from tupleobject import W_TupleObject
-from pypy.objspace.std.stringtype import sliced, joined, wrapstr, wrapchar, \
- stringendswith, stringstartswith, joined2
+# XXX consider reimplementing _value to be a list of characters
+# instead of a plain string
-from pypy.objspace.std.formatting import mod_format
class W_StringObject(W_Object):
- from pypy.objspace.std.stringtype import str_typedef as typedef
+ statictype = W_StringType
- _immutable_ = True
- def __init__(w_self, str):
+ def __init__(w_self, space, str):
+ W_Object.__init__(w_self, space)
w_self._value = str
def __repr__(w_self):
""" representation for debugging purposes """
return "%s(%r)" % (w_self.__class__.__name__, w_self._value)
- def unwrap(w_self, space):
- return w_self._value
registerimplementation(W_StringObject)
-W_StringObject.EMPTY = W_StringObject('')
-W_StringObject.PREBUILT = [W_StringObject(chr(i)) for i in range(256)]
-del i
+def _isspace(ch):
+ return ord(ch) in (9, 10, 11, 12, 13, 32)
-def _decode_ascii(space, s):
- try:
- return s.decode("ascii")
- except UnicodeDecodeError:
- for i in range(len(s)):
- if ord(s[i]) > 127:
- raise OperationError(
- space.w_UnicodeDecodeError,
- space.newtuple([
- space.wrap('ascii'),
- space.wrap(s),
- space.wrap(i),
- space.wrap(i+1),
- space.wrap("ordinal not in range(128)")]))
- assert False, "unreachable"
-
-def unicode_w__String(space, w_self):
- # XXX should this use the default encoding?
- return _decode_ascii(space, w_self._value)
-
-def _is_generic(space, w_self, fun):
- v = w_self._value
+def _isdigit(ch):
+ o = ord(ch)
+ return o >= 48 and o <= 57
+
+def _isalpha(ch):
+ o = ord(ch)
+ return (o>=97 and o<=122) or (o>=65 and o<=90)
+
+def _isalnum(ch):
+ o = ord(ch)
+ return (o>=97 and o<=122) \
+ or (o>=65 and o<=90) \
+ or (o>=48 and o<=57)
+
+def _isupper(ch):
+ o = ord(ch)
+ return (o>=65 and o<=90)
+
+def _islower(ch):
+ o = ord(ch)
+ return (o>=97 and o<=122)
+
+def _is_generic(w_self, fun):
+ space = w_self.space
+ v = space.unwrap(w_self)
if len(v) == 0:
return space.w_False
if len(v) == 1:
c = v[0]
return space.newbool(fun(c))
else:
+ res = 1
for idx in range(len(v)):
if not fun(v[idx]):
return space.w_False
return space.w_True
-_is_generic._annspecialcase_ = "specialize:arg(2)"
-
-def _upper(ch):
- if ch.islower():
- o = ord(ch) - 32
- return chr(o)
- else:
- return ch
-
-def _lower(ch):
- if ch.isupper():
- o = ord(ch) + 32
- return chr(o)
- else:
- return ch
-
-_isspace = lambda c: c.isspace()
-_isdigit = lambda c: c.isdigit()
-_isalpha = lambda c: c.isalpha()
-_isalnum = lambda c: c.isalnum()
def str_isspace__String(space, w_self):
- return _is_generic(space, w_self, _isspace)
+ return _is_generic(w_self, _isspace)
def str_isdigit__String(space, w_self):
- return _is_generic(space, w_self, _isdigit)
+ return _is_generic(w_self, _isdigit)
def str_isalpha__String(space, w_self):
- return _is_generic(space, w_self, _isalpha)
+ return _is_generic(w_self, _isalpha)
def str_isalnum__String(space, w_self):
- return _is_generic(space, w_self, _isalnum)
+ return _is_generic(w_self, _isalnum)
def str_isupper__String(space, w_self):
- """Return True if all cased characters in S are uppercase and there is
-at least one cased character in S, False otherwise."""
- v = w_self._value
- if len(v) == 1:
- c = v[0]
- return space.newbool(c.isupper())
- cased = False
- for idx in range(len(v)):
- if v[idx].islower():
- return space.w_False
- elif not cased and v[idx].isupper():
- cased = True
- return space.newbool(cased)
+ return _is_generic(w_self, _isupper)
def str_islower__String(space, w_self):
- """Return True if all cased characters in S are lowercase and there is
-at least one cased character in S, False otherwise."""
- v = w_self._value
- if len(v) == 1:
- c = v[0]
- return space.newbool(c.islower())
- cased = False
- for idx in range(len(v)):
- if v[idx].isupper():
- return space.w_False
- elif not cased and v[idx].islower():
- cased = True
- return space.newbool(cased)
+ return _is_generic(w_self, _islower)
def str_istitle__String(space, w_self):
- """Return True if S is a titlecased string and there is at least one
-character in S, i.e. uppercase characters may only follow uncased
-characters and lowercase characters only cased ones. Return False
-otherwise."""
- input = w_self._value
- cased = False
- previous_is_cased = False
+ input = space.unwrap(w_self)
+ prev_letter='!'
for pos in range(0, len(input)):
ch = input[pos]
- if ch.isupper():
- if previous_is_cased:
- return space.w_False
- previous_is_cased = True
- cased = True
- elif ch.islower():
- if not previous_is_cased:
- return space.w_False
- cased = True
- else:
- previous_is_cased = False
+ if ch.isalpha():
+ if (prev_letter.isalpha() and ch.isupper()) or \
+ (not prev_letter.isalpha() and ch.islower()):
+ return space.w_False
+ prev_letter = ch
- return space.newbool(cased)
+ return space.w_True
def str_upper__String(space, w_self):
- self = w_self._value
+ self = space.unwrap(w_self)
res = [' '] * len(self)
for i in range(len(self)):
ch = self[i]
- res[i] = _upper(ch)
+ if _islower(ch):
+ o = ord(ch) - 32
+ res[i] = chr(o)
+ else:
+ res[i] = ch
return space.wrap("".join(res))
def str_lower__String(space, w_self):
- self = w_self._value
+ self = space.unwrap(w_self)
res = [' '] * len(self)
for i in range(len(self)):
ch = self[i]
- res[i] = _lower(ch)
+ if _isupper(ch):
+ o = ord(ch) + 32
+ res[i] = chr(o)
+ else:
+ res[i] = ch
return space.wrap("".join(res))
def str_swapcase__String(space, w_self):
- self = w_self._value
+ self = space.unwrap(w_self)
res = [' '] * len(self)
for i in range(len(self)):
ch = self[i]
- if ch.isupper():
+ if _isupper(ch):
o = ord(ch) + 32
res[i] = chr(o)
- elif ch.islower():
+ elif _islower(ch):
o = ord(ch) - 32
res[i] = chr(o)
else:
@@ -194,11 +215,11 @@
def str_capitalize__String(space, w_self):
- input = w_self._value
+ input = space.unwrap(w_self)
buffer = [' '] * len(input)
if len(input) > 0:
ch = input[0]
- if ch.islower():
+ if _islower(ch):
o = ord(ch) - 32
buffer[0] = chr(o)
else:
@@ -206,7 +227,7 @@
for i in range(1, len(input)):
ch = input[i]
- if ch.isupper():
+ if _isupper(ch):
o = ord(ch) + 32
buffer[i] = chr(o)
else:
@@ -215,330 +236,305 @@
return space.wrap("".join(buffer))
def str_title__String(space, w_self):
- input = w_self._value
+ input = space.unwrap(w_self)
buffer = [' '] * len(input)
prev_letter=' '
for pos in range(0, len(input)):
ch = input[pos]
if not prev_letter.isalpha():
- buffer[pos] = _upper(ch)
+ buffer[pos] = ch.upper()
else:
- buffer[pos] = _lower(ch)
+ buffer[pos] = ch.lower()
prev_letter = buffer[pos]
return space.wrap("".join(buffer))
-def str_split__String_None_ANY(space, w_self, w_none, w_maxsplit=-1):
- maxsplit = space.int_w(w_maxsplit)
- res_w = []
- value = w_self._value
- length = len(value)
- i = 0
- while True:
- # find the beginning of the next word
- while i < length:
- if not value[i].isspace():
- break # found
- i += 1
- else:
- break # end of string, finished
-
- # find the end of the word
- if maxsplit == 0:
- j = length # take all the rest of the string
- else:
- j = i + 1
- while j < length and not value[j].isspace():
- j += 1
- maxsplit -= 1 # NB. if it's already < 0, it stays < 0
-
- # the word is value[i:j]
- res_w.append(sliced(space, value, i, j, w_self))
-
- # continue to look from the character following the space after the word
- i = j + 1
-
- return space.newlist(res_w)
-
-def str_split__String_String_ANY(space, w_self, w_by, w_maxsplit=-1):
- maxsplit = space.int_w(w_maxsplit)
- value = w_self._value
- by = w_by._value
+def str_split__String_None_Int(space, w_self, w_none, w_maxsplit=-1):
+ res = []
+ inword = 0
+ u = space.unwrap
+ value = u(w_self)
+ maxsplit = u(w_maxsplit)
+ pos = 0
+
+ for ch in value:
+ if ch.isspace():
+ if inword:
+ inword = 0
+ else:
+ if inword:
+ res[-1] += ch
+ else:
+ if maxsplit > -1:
+ if maxsplit == 0:
+ res.append(value[pos:])
+ break
+ maxsplit = maxsplit - 1
+ res.append(ch)
+ inword = 1
+ pos = pos + 1
+
+ for i in range(len(res)):
+ res[i] = W_StringObject(space, res[i])
+ return W_ListObject(space, res)
+
+def str_split__String_String_Int(space, w_self, w_by, w_maxsplit=-1):
+ u = space.unwrap
+ res = []
+ start = 0
+ value = u(w_self)
+ by = u(w_by)
bylen = len(by)
- if bylen == 0:
- raise OperationError(space.w_ValueError, space.wrap("empty separator"))
+ maxsplit = u(w_maxsplit)
- res_w = []
- start = 0
- while maxsplit != 0:
- next = value.find(by, start)
+ #if maxsplit is default, then you have no limit
+ #of the length of the resulting array
+ if maxsplit == -1:
+ splitcount = 1
+ else:
+ splitcount = maxsplit
+
+ while splitcount:
+ next = _find(value, by, start, len(value), 1)
+ #next = value.find(by, start) #of course we cannot use
+ #the find method,
if next < 0:
+ res.append(value[start:])
+ start = len(value) + 1
break
- res_w.append(sliced(space, value, start, next, w_self))
+ res.append(value[start:next])
start = next + bylen
- maxsplit -= 1 # NB. if it's already < 0, it stays < 0
-
- res_w.append(sliced(space, value, start, len(value), w_self))
- return space.newlist(res_w)
-
-def str_rsplit__String_None_ANY(space, w_self, w_none, w_maxsplit=-1):
- maxsplit = space.int_w(w_maxsplit)
- res_w = []
- value = w_self._value
- i = len(value)-1
- while True:
- # starting from the end, find the end of the next word
- while i >= 0:
- if not value[i].isspace():
- break # found
- i -= 1
- else:
- break # end of string, finished
-
- # find the start of the word
- # (more precisely, 'j' will be the space character before the word)
- if maxsplit == 0:
- j = -1 # take all the rest of the string
- else:
- j = i - 1
- while j >= 0 and not value[j].isspace():
- j -= 1
- maxsplit -= 1 # NB. if it's already < 0, it stays < 0
-
- # the word is value[j+1:i+1]
- j1 = j + 1
- assert j1 >= 0
- res_w.append(sliced(space, value, j1, i+1, w_self))
-
- # continue to look from the character before the space before the word
- i = j - 1
-
- res_w.reverse()
- return space.newlist(res_w)
-
-def make_rsplit_with_delim(funcname, sliced):
- from pypy.tool.sourcetools import func_with_new_name
-
- def fn(space, w_self, w_by, w_maxsplit=-1):
- maxsplit = space.int_w(w_maxsplit)
- res_w = []
- value = w_self._value
- end = len(value)
- by = w_by._value
- bylen = len(by)
- if bylen == 0:
- raise OperationError(space.w_ValueError, space.wrap("empty separator"))
-
- while maxsplit != 0:
- next = value.rfind(by, 0, end)
- if next < 0:
- break
- res_w.append(sliced(space, value, next+bylen, end, w_self))
- end = next
- maxsplit -= 1 # NB. if it's already < 0, it stays < 0
-
- res_w.append(sliced(space, value, 0, end, w_self))
- res_w.reverse()
- return space.newlist(res_w)
-
- return func_with_new_name(fn, funcname)
-
-str_rsplit__String_String_ANY = make_rsplit_with_delim('str_rsplit__String_String_ANY',
- sliced)
+ #decrese the counter only then, when
+ #we don't have default maxsplit
+ if maxsplit > -1:
+ splitcount = splitcount - 1
+
+ if start < len(value):
+ res.append(value[start:])
+
+ for i in range(len(res)):
+ res[i] = W_StringObject(w_self.space, res[i])
+ return W_ListObject(w_self.space, res)
def str_join__String_ANY(space, w_self, w_list):
- list_w = space.unpackiterable(w_list)
- str_w = space.str_w
- if list_w:
- self = w_self._value
+ u = space.unwrap
+ list = space.unpackiterable(w_list)
+ if list:
+ self = u(w_self)
+ firstelem = 1
listlen = 0
- reslen = 0
- l = []
- for i in range(len(list_w)):
- w_s = list_w[i]
- if not space.is_true(space.isinstance(w_s, space.w_str)):
- if space.is_true(space.isinstance(w_s, space.w_unicode)):
- w_u = space.call_function(space.w_unicode, w_self)
- return space.call_method(w_u, "join", space.newlist(list_w))
- raise OperationError(
- space.w_TypeError,
- space.wrap("sequence item %d: expected string, %s "
- "found" % (i,
- space.type(w_s).getname(space, '?'))))
- l.append(space.str_w(w_s))
- return space.wrap(self.join(l))
+ reslen = 0
+ #compute the length of the resulting string
+ for w_item in list:
+ reslen = reslen + len(u(w_item))
+ listlen = listlen + 1
+
+ reslen = reslen + (listlen - 1) * len(self)
+
+ #allocate the string buffer
+ res = [' '] * reslen
+
+ pos = 0
+ #fill in the string buffer
+ for w_item in list:
+ item = u(w_item)
+ if firstelem:
+ for i in range(len(item)):
+ res[i+pos] = item[i]
+ firstelem = 0
+ pos = pos + len(item)
+ else:
+ for i in range(len(self)):
+ res[i+pos] = self[i]
+ pos = pos + len(self)
+
+ for i in range(len(item)):
+ res[i+pos] = item[i]
+ pos = pos + len(item)
+
+ return space.wrap("".join(res))
else:
- return W_StringObject.EMPTY
+ return space.wrap("")
+
+
+def str_rjust__String_ANY(space, w_self, w_arg):
+ u = space.unwrap
-def str_rjust__String_ANY_ANY(space, w_self, w_arg, w_fillchar):
- u_arg = space.int_w(w_arg)
- u_self = w_self._value
- fillchar = space.str_w(w_fillchar)
- if len(fillchar) != 1:
- raise OperationError(space.w_TypeError,
- space.wrap("rjust() argument 2 must be a single character"))
+ u_arg = u(w_arg)
+ u_self = u(w_self)
d = u_arg - len(u_self)
if d>0:
- fillchar = fillchar[0] # annotator hint: it's a single character
- u_self = d * fillchar + u_self
+ u_self = d * ' ' + u_self
return space.wrap(u_self)
-def str_ljust__String_ANY_ANY(space, w_self, w_arg, w_fillchar):
- u_self = w_self._value
- u_arg = space.int_w(w_arg)
- fillchar = space.str_w(w_fillchar)
- if len(fillchar) != 1:
- raise OperationError(space.w_TypeError,
- space.wrap("ljust() argument 2 must be a single character"))
+def str_ljust__String_ANY(space, w_self, w_arg):
+ u = space.unwrap
+
+ u_self = u(w_self)
+ u_arg = u(w_arg)
d = u_arg - len(u_self)
if d>0:
- fillchar = fillchar[0] # annotator hint: it's a single character
- u_self += d * fillchar
+ u_self += d * ' '
return space.wrap(u_self)
-def _convert_idx_params(space, w_self, w_sub, w_start, w_end, upper_bound=False):
- self = w_self._value
- sub = w_sub._value
- if upper_bound:
- start = slicetype.adapt_bound(space, len(self), w_start)
- end = slicetype.adapt_bound(space, len(self), w_end)
- else:
- start = slicetype.adapt_lower_bound(space, len(self), w_start)
- end = slicetype.adapt_lower_bound(space, len(self), w_end)
+def _convert_idx_params(space, w_self, w_sub, w_start, w_end):
+ u = space.unwrap
+ start = u(w_start)
+ end = u(w_end)
+ self = u(w_self)
+ sub = u(w_sub)
+ if start is None:
+ start = 0
+ if end is None:
+ end = len(self)
+
return (self, sub, start, end)
-_convert_idx_params._annspecialcase_ = 'specialize:arg(5)'
-def contains__String_String(space, w_self, w_sub):
- self = w_self._value
- sub = w_sub._value
- return space.newbool(self.find(sub) >= 0)
-def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
+def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start=None, w_end=None):
+
(self, sub, start, end) = _convert_idx_params(space, w_self, w_sub, w_start, w_end)
- res = self.find(sub, start, end)
+ res = _find(self, sub, start, end, 1)
return space.wrap(res)
-def str_rfind__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
+def str_rfind__String_String_ANY_ANY(space, w_self, w_sub, w_start=None, w_end=None):
+
(self, sub, start, end) = _convert_idx_params(space, w_self, w_sub, w_start, w_end)
- res = self.rfind(sub, start, end)
+ res = _find(self, sub, start, end, -1)
return space.wrap(res)
-def str_partition__String_String(space, w_self, w_sub):
- self = w_self._value
- sub = w_sub._value
- if not sub:
- raise OperationError(space.w_ValueError,
- space.wrap("empty separator"))
- pos = self.find(sub)
- if pos == -1:
- return space.newtuple([w_self, space.wrap(''), space.wrap('')])
- else:
- return space.newtuple([sliced(space, self, 0, pos, w_self),
- w_sub,
- sliced(space, self, pos+len(sub), len(self),
- w_self)])
-
-def str_rpartition__String_String(space, w_self, w_sub):
- self = w_self._value
- sub = w_sub._value
- if not sub:
- raise OperationError(space.w_ValueError,
- space.wrap("empty separator"))
- pos = self.rfind(sub)
- if pos == -1:
- return space.newtuple([space.wrap(''), space.wrap(''), w_self])
- else:
- return space.newtuple([sliced(space, self, 0, pos, w_self),
- w_sub,
- sliced(space, self, pos+len(sub), len(self), w_self)])
-
+def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start=None, w_end=None):
-def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
(self, sub, start, end) = _convert_idx_params(space, w_self, w_sub, w_start, w_end)
- res = self.find(sub, start, end)
- if res < 0:
+ res = _find(self, sub, start, end, 1)
+
+ if res == -1:
raise OperationError(space.w_ValueError,
space.wrap("substring not found in string.index"))
return space.wrap(res)
-def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
+def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start=None, w_end=None):
+
(self, sub, start, end) = _convert_idx_params(space, w_self, w_sub, w_start, w_end)
- res = self.rfind(sub, start, end)
- if res < 0:
+ res = _find(self, sub, start, end, -1)
+ if res == -1:
raise OperationError(space.w_ValueError,
space.wrap("substring not found in string.rindex"))
return space.wrap(res)
-def _string_replace(space, input, sub, by, maxsplit):
- if maxsplit == 0:
- return space.wrap(input)
+
+def str_replace__String_String_String_Int(space, w_self, w_sub, w_by, w_maxsplit=-1):
+ u = space.unwrap
+
+ input = u(w_self)
+ sub = u(w_sub)
+ by = u(w_by)
+ maxsplit = u(w_maxsplit) #I don't use it now
#print "from replace, input: %s, sub: %s, by: %s" % (input, sub, by)
- if not sub:
- upper = len(input)
- if maxsplit > 0 and maxsplit < upper + 2:
- upper = maxsplit - 1
- assert upper >= 0
- substrings_w = [""]
- for i in range(upper):
- c = input[i]
- substrings_w.append(c)
- substrings_w.append(input[upper:])
- else:
+ #what do we have to replace?
+ startidx = 0
+ endidx = len(input)
+ indices = []
+ foundidx = _find(input, sub, startidx, endidx, 1)
+ while foundidx > -1 and (maxsplit == -1 or maxsplit > 0):
+ indices.append(foundidx)
+ if len(sub) == 0:
+ #so that we go forward, even if sub is empty
+ startidx = foundidx + 1
+ else:
+ startidx = foundidx + len(sub)
+ foundidx = _find(input, sub, startidx, endidx, 1)
+ if maxsplit != -1:
+ maxsplit = maxsplit - 1
+ indiceslen = len(indices)
+ buf = [' '] * (len(input) - indiceslen * len(sub) + indiceslen * len(by))
+ startidx = 0
+
+ #ok, so do it
+ bufpos = 0
+ for i in range(indiceslen):
+ for j in range(startidx, indices[i]):
+ buf[bufpos] = input[j]
+ bufpos = bufpos + 1
+
+ for j in range(len(by)):
+ buf[bufpos] = by[j]
+ bufpos = bufpos + 1
+
+ startidx = indices[i] + len(sub)
+
+ for j in range(startidx, len(input)):
+ buf[bufpos] = input[j]
+ bufpos = bufpos + 1
+ return space.wrap("".join(buf))
+
+def _find(self, sub, start, end, dir):
+
+ length = len(self)
+
+ #adjust_indicies
+ if (end > length):
+ end = length
+ elif (end < 0):
+ end += length
+ if (end < 0):
+ end = 0
+ if (start < 0):
+ start += length
+ if (start < 0):
start = 0
- sublen = len(sub)
- substrings_w = []
- while maxsplit != 0:
- next = input.find(sub, start)
- if next < 0:
- break
- substrings_w.append(input[start:next])
- start = next + sublen
- maxsplit -= 1 # NB. if it's already < 0, it stays < 0
-
- substrings_w.append(input[start:])
+ if dir > 0:
+ if len(sub) == 0 and start < end:
+ return start
+
+ end = end - len(sub) + 1
+
+ for i in range(start, end):
+ match = 1
+ for idx in range(len(sub)):
+ if sub[idx] != self[idx+i]:
+ match = 0
+ break
+ if match:
+ return i
+ return -1
+ else:
+ if len(sub) == 0 and start < end:
+ return end
+
+ end = end - len(sub)
+
+ for j in range(end, start-1, -1):
+ match = 1
+ for idx in range(len(sub)):
+ if sub[idx] != self[idx+j]:
+ match = 0
+ break
+ if match:
+ return j
+ return -1
- try:
- # XXX conservative estimate. If your strings are that close
- # to overflowing, bad luck.
- one = ovfcheck(len(substrings_w) * len(by))
- ovfcheck(one + len(input))
- except OverflowError:
- raise OperationError(
- space.w_OverflowError,
- space.wrap("replace string is too long"))
-
- return space.wrap(by.join(substrings_w))
-
-
-def str_replace__String_ANY_ANY_ANY(space, w_self, w_sub, w_by, w_maxsplit):
- return _string_replace(space, w_self._value, space.buffer_w(w_sub).as_str(),
- space.buffer_w(w_by).as_str(),
- space.int_w(w_maxsplit))
-
-def str_replace__String_String_String_ANY(space, w_self, w_sub, w_by, w_maxsplit=-1):
- input = w_self._value
- sub = w_sub._value
- by = w_by._value
- maxsplit = space.int_w(w_maxsplit)
- return _string_replace(space, input, sub, by, maxsplit)
def _strip(space, w_self, w_chars, left, right):
"internal function called by str_xstrip methods"
- u_self = w_self._value
- u_chars = w_chars._value
+ u_self = space.unwrap(w_self)
+ u_chars = space.unwrap(w_chars)
+
+ if u_self == None or u_chars == None:
+ return w_self
lpos = 0
rpos = len(u_self)
@@ -549,113 +545,98 @@
lpos += 1
if right:
- while rpos > lpos and u_self[rpos - 1] in u_chars:
+ while rpos > 0 and u_self[rpos - 1] in u_chars:
rpos -= 1
- assert rpos >= lpos # annotator hint, don't remove
- return sliced(space, u_self, lpos, rpos, w_self)
+ return space.wrap(u_self[lpos:rpos])
-def _strip_none(space, w_self, left, right):
- "internal function called by str_xstrip methods"
- u_self = w_self._value
-
- lpos = 0
- rpos = len(u_self)
-
- if left:
- #print "while %d < %d and -%s- in -%s-:"%(lpos, rpos, u_self[lpos],w_chars)
- while lpos < rpos and u_self[lpos].isspace():
- lpos += 1
-
- if right:
- while rpos > lpos and u_self[rpos - 1].isspace():
- rpos -= 1
-
- assert rpos >= lpos # annotator hint, don't remove
- return sliced(space, u_self, lpos, rpos, w_self)
def str_strip__String_String(space, w_self, w_chars):
return _strip(space, w_self, w_chars, left=1, right=1)
-def str_strip__String_None(space, w_self, w_chars):
- return _strip_none(space, w_self, left=1, right=1)
def str_rstrip__String_String(space, w_self, w_chars):
return _strip(space, w_self, w_chars, left=0, right=1)
-def str_rstrip__String_None(space, w_self, w_chars):
- return _strip_none(space, w_self, left=0, right=1)
-
def str_lstrip__String_String(space, w_self, w_chars):
return _strip(space, w_self, w_chars, left=1, right=0)
+
-def str_lstrip__String_None(space, w_self, w_chars):
- return _strip_none(space, w_self, left=1, right=0)
-
-
-
-def str_center__String_ANY_ANY(space, w_self, w_arg, w_fillchar):
- u_self = w_self._value
- u_arg = space.int_w(w_arg)
- fillchar = space.str_w(w_fillchar)
- if len(fillchar) != 1:
- raise OperationError(space.w_TypeError,
- space.wrap("center() argument 2 must be a single character"))
+def str_center__String_Int(space, w_self, w_arg):
+ u_self = space.unwrap(w_self)
+ u_arg = space.unwrap(w_arg)
d = u_arg - len(u_self)
if d>0:
- offset = d//2 + (d & u_arg & 1)
- fillchar = fillchar[0] # annotator hint: it's a single character
- u_centered = offset * fillchar + u_self + (d - offset) * fillchar
+ offset = d//2
+ u_centered = offset * ' ' + u_self + (d - offset) * ' '
else:
u_centered = u_self
- return wrapstr(space, u_centered)
-
+ return W_StringObject(space, u_centered)
+
+
def str_count__String_String_ANY_ANY(space, w_self, w_arg, w_start, w_end):
- u_self, u_arg, u_start, u_end = _convert_idx_params(space, w_self, w_arg,
- w_start, w_end)
- return wrapint(space, u_self.count(u_arg, u_start, u_end))
-
-def str_endswith__String_String_ANY_ANY(space, w_self, w_suffix, w_start, w_end):
- (u_self, suffix, start, end) = _convert_idx_params(space, w_self,
- w_suffix, w_start,
- w_end, True)
- return space.newbool(stringendswith(u_self, suffix, start, end))
-
-def str_endswith__String_Tuple_ANY_ANY(space, w_self, w_suffixes, w_start, w_end):
- (u_self, _, start, end) = _convert_idx_params(space, w_self,
- space.wrap(''), w_start,
- w_end, True)
- for w_suffix in space.viewiterable(w_suffixes):
- if space.is_true(space.isinstance(w_suffix, space.w_unicode)):
- w_u = space.call_function(space.w_unicode, w_self)
- return space.call_method(w_u, "endswith", w_suffixes, w_start,
- w_end)
- suffix = space.str_w(w_suffix)
- if stringendswith(u_self, suffix, start, end):
- return space.w_True
- return space.w_False
+ u_self = space.unwrap(w_self)
+ u_arg = space.unwrap(w_arg)
+ u_start = space.unwrap(w_start)
+ u_end = space.unwrap(w_end)
+
+
+ if u_end == None:
+ u_end = len(u_self)
+ elif u_end < 0:
+ u_end += len(u_self)
+
+ if u_start == None: u_start = 0
+
+ area = u_self [u_start:u_end]
+
+ count = 0
+
+ pos = -1
+ while 1:
+ pos = _find(area, u_arg, pos+1, u_end, 1)
+ #pos = area.find(u_arg, pos+1, u_end)
+ if pos == -1:
+ break
+ count += 1
+
+ return W_IntObject(space, count)
-def str_startswith__String_String_ANY_ANY(space, w_self, w_prefix, w_start, w_end):
- (u_self, prefix, start, end) = _convert_idx_params(space, w_self,
- w_prefix, w_start,
- w_end, True)
- return space.newbool(stringstartswith(u_self, prefix, start, end))
-
-def str_startswith__String_Tuple_ANY_ANY(space, w_self, w_prefixes, w_start, w_end):
- (u_self, _, start, end) = _convert_idx_params(space, w_self, space.wrap(''),
- w_start, w_end, True)
- for w_prefix in space.viewiterable(w_prefixes):
- if space.is_true(space.isinstance(w_prefix, space.w_unicode)):
- w_u = space.call_function(space.w_unicode, w_self)
- return space.call_method(w_u, "startswith", w_prefixes, w_start,
- w_end)
- prefix = space.str_w(w_prefix)
- if stringstartswith(u_self, prefix, start, end):
- return space.w_True
- return space.w_False
+
+#[optional arguments not supported now]
+def str_endswith__String_String(space, w_self, w_end):
+ u_self = space.unwrap(w_self)
+ u_end = space.unwrap(w_end)
+
+ found = 0
+ if u_end:
+ endlen = len(u_end)
+ if endlen <= len(u_self):
+ found = (u_end == u_self[-endlen:])
+ else:
+ found = 1
+
+ return W_IntObject(space, found)
+
+
+#[optional arguments not supported now]
+def str_startswith__String_String(space, w_self, w_start):
+ u_self = space.unwrap(w_self)
+ u_start = space.unwrap(w_start)
+
+ found = 0
+ if u_start:
+ startlen = len(u_start)
+ if startlen <= len(u_self):
+ found = (u_start == u_self[:startlen])
+ else:
+ found = 1
+
+ return W_IntObject(space, found)
+
def _tabindent(u_token, u_tabsize):
"calculates distance behind the token to the next tabstop"
@@ -683,13 +664,13 @@
return distance
-def str_expandtabs__String_ANY(space, w_self, w_tabsize):
- u_self = w_self._value
- u_tabsize = space.int_w(w_tabsize)
+def str_expandtabs__String_Int(space, w_self, w_tabsize):
+ u_self = space.unwrap(w_self)
+ u_tabsize = space.unwrap(w_tabsize)
u_expanded = ""
if u_self:
- split = u_self.split("\t")
+ split = u_self.split("\t") #XXX use pypy split
u_expanded =oldtoken = split.pop(0)
for token in split:
@@ -697,40 +678,37 @@
u_expanded += " " * _tabindent(oldtoken,u_tabsize) + token
oldtoken = token
- return wrapstr(space, u_expanded)
+ return W_StringObject(space, u_expanded)
-def str_splitlines__String_ANY(space, w_self, w_keepends):
- u_keepends = space.int_w(w_keepends) # truth value, but type checked
- data = w_self._value
- selflen = len(data)
- strs_w = []
- i = j = 0
- while i < selflen:
- # Find a line and append it
- while i < selflen and data[i] != '\n' and data[i] != '\r':
- i += 1
- # Skip the line break reading CRLF as one line break
- eol = i
- i += 1
- if i < selflen and data[i-1] == '\r' and data[i] == '\n':
- i += 1
- if u_keepends:
- eol = i
- strs_w.append(sliced(space, data, j, eol, w_self))
- j = i
-
- if j < selflen:
- strs_w.append(sliced(space, data, j, len(data), w_self))
- return space.newlist(strs_w)
-
-def str_zfill__String_ANY(space, w_self, w_width):
- input = w_self._value
- width = space.int_w(w_width)
+def str_splitlines__String_Int(space, w_self, w_keepends):
+ u_self = space.unwrap(w_self)
+ u_keepends = space.unwrap(w_keepends)
+ selflen = len(u_self)
+
+ L = []
+ pos = 0
+ while 1:
+ oldpos = pos
+ pos = _find(u_self, '\n', pos, selflen, 1) + 1
+ if pos > oldpos:
+ w_item = space.wrap(u_self[oldpos:pos])
+ if not u_keepends:
+ w_item = _strip(space, w_item, W_StringObject(space,'\n'), left=0, right=1)
+ L.append(w_item)
+ else:
+ break
+ return W_ListObject(space, L)
+
+def str_zfill__String_Int(space, w_self, w_width):
+ u = space.unwrap
+ input = u(w_self)
+ width = u(w_width)
if len(input) >= width:
- # cannot return w_self, in case it is a subclass of str
- return space.wrap(input)
+ return w_self
+
+ b = width - len(input)
buf = [' '] * width
if len(input) > 0 and (input[0] == '+' or input[0] == '-'):
@@ -749,256 +727,285 @@
start = start + 1
return space.wrap("".join(buf))
+
+
+def app_str_translate__String_String_String(s, table, deletechars=''):
+ """charfilter - unicode handling is not implemented
+
+ Return a copy of the string where all characters occurring
+ in the optional argument deletechars are removed, and the
+ remaining characters have been mapped through the given translation table,
+ which must be a string of length 256"""
+
+ if len(table) < 256:
+ raise ValueError("translation table must be 256 characters long")
-def str_w__String(space, w_str):
+ L = [ table[ord(s[i])] for i in range(len(s)) if s[i] not in deletechars ]
+ return ''.join(L)
+
+str_translate__String_String_String = gateway.app2interp(app_str_translate__String_String_String)
+
+
+def unwrap__String(space, w_str):
return w_str._value
def hash__String(space, w_str):
- s = w_str._value
- if we_are_translated():
- x = hash(s) # to use the hash cache in rpython strings
+ return W_IntObject(space, hash(space.unwrap(w_str)))
+
+
+EQ = 1
+LE = 2
+GE = 3
+GT = 4
+LT = 5
+NE = 6
+
+
+def string_richcompare(space, w_str1, w_str2, op):
+ u = space.unwrap
+ str1 = u(w_str1)
+ str2 = u(w_str2)
+
+ if space.is_true(space.is_(w_str1, w_str2)):
+ if op == EQ or op == LE or op == GE:
+ return space.w_True
+ elif op == GT or op == LT or op == NE:
+ return space.w_False
+ if 0:
+ pass
else:
- x = _hash_string(s) # to make sure we get the same hash as rpython
- # (otherwise translation will freeze W_DictObjects where we can't find
- # the keys any more!)
- return wrapint(space, x)
+ if op == EQ:
+ if len(str1) == len(str2):
+ for i in range(len(str1)):
+ if ord(str1[i]) != ord(str2[i]):
+ return space.w_False
+ return space.w_True
+ else:
+ return space.w_False
+ else:
+ if len(str1) > len(str2):
+ min_len = len(str2)
+ else:
+ min_len = len(str1)
+
+ c = 0
+ idx = 0
+ if (min_len > 0):
+ while (c == 0) and (idx < min_len):
+ c = ord(str1[idx]) - ord(str2[idx])
+ idx = idx + 1
+ else:
+ c = 0
+
+ if (c == 0):
+ if len(str1) < len(str2):
+ c = -1
+ elif len(str1) > len(str2):
+ c = 1
+ else:
+ c = 0
+
+ if op == LT:
+ return space.newbool(c < 0)
+ elif op == LE:
+ return space.newbool(c <= 0)
+ elif op == NE:
+ return space.newbool(c != 0)
+ elif op == GT:
+ return space.newbool(c > 0)
+ elif op == GE:
+ return space.newbool(c >= 0)
+ else:
+ return NotImplemented
def lt__String_String(space, w_str1, w_str2):
- s1 = w_str1._value
- s2 = w_str2._value
- if s1 < s2:
- return space.w_True
- else:
- return space.w_False
+ return string_richcompare(space, w_str1, w_str2, LT)
def le__String_String(space, w_str1, w_str2):
- s1 = w_str1._value
- s2 = w_str2._value
- if s1 <= s2:
- return space.w_True
- else:
- return space.w_False
+ return string_richcompare(space, w_str1, w_str2, LE)
def eq__String_String(space, w_str1, w_str2):
- s1 = w_str1._value
- s2 = w_str2._value
- if s1 == s2:
- return space.w_True
- else:
- return space.w_False
+ return string_richcompare(space, w_str1, w_str2, EQ)
def ne__String_String(space, w_str1, w_str2):
- s1 = w_str1._value
- s2 = w_str2._value
- if s1 != s2:
- return space.w_True
- else:
- return space.w_False
+ return string_richcompare(space, w_str1, w_str2, NE)
def gt__String_String(space, w_str1, w_str2):
- s1 = w_str1._value
- s2 = w_str2._value
- if s1 > s2:
- return space.w_True
- else:
- return space.w_False
+ return string_richcompare(space, w_str1, w_str2, GT)
def ge__String_String(space, w_str1, w_str2):
- s1 = w_str1._value
- s2 = w_str2._value
- if s1 >= s2:
- return space.w_True
- else:
- return space.w_False
+ return string_richcompare(space, w_str1, w_str2, GE)
-def getitem__String_ANY(space, w_str, w_index):
- ival = space.getindex_w(w_index, space.w_IndexError, "string index")
- str = w_str._value
- slen = len(str)
+def getitem__String_Int(space, w_str, w_int):
+ u = space.unwrap
+ ival = w_int.intval
+ str = u(w_str)
+ slen = len(u(w_str))
if ival < 0:
ival += slen
if ival < 0 or ival >= slen:
exc = space.call_function(space.w_IndexError,
space.wrap("string index out of range"))
raise OperationError(space.w_IndexError, exc)
- return wrapchar(space, str[ival])
+ return W_StringObject(space, str[ival])
def getitem__String_Slice(space, w_str, w_slice):
+ # XXX this is really too slow for slices with no step argument
w = space.wrap
- s = w_str._value
- length = len(s)
- start, stop, step, sl = w_slice.indices4(space, length)
- if sl == 0:
- return W_StringObject.EMPTY
- elif step == 1:
- assert start >= 0 and stop >= 0
- return sliced(space, s, start, stop, w_str)
- else:
- str = "".join([s[start + i*step] for i in range(sl)])
- return wrapstr(space, str)
+ length = len(w_str._value)
+ start, stop, step, sl = slicetype.indices4(space, w_slice, length)
+ r = [space.getitem(w_str, w(start + i*step)) for i in range(sl)]
+ w_r = space.newlist(r)
+ w_empty = space.newstring([])
+ return str_join__String_ANY(space, w_empty, w_r)
+
+def mul__String_Int(space, w_str, w_mul):
+ u = space.unwrap
+ input = u(w_str)
+ mul = u(w_mul)
+
+ buffer = [' '] * (mul*len(input))
+
+ pos = 0
+ for i in range(mul):
+ for j in range(len(input)):
+ buffer[pos] = input[j]
+ pos = pos + 1
-def getslice__String_ANY_ANY(space, w_str, w_start, w_stop):
- s = w_str._value
- start, stop = normalize_simple_slice(space, len(s), w_start, w_stop)
- if start == stop:
- return W_StringObject.EMPTY
- else:
- return sliced(space, s, start, stop, w_str)
-
-def mul_string_times(space, w_str, w_times):
- try:
- mul = space.getindex_w(w_times, space.w_OverflowError)
- except OperationError, e:
- if e.match(space, space.w_TypeError):
- raise FailedToImplement
- raise
- if mul <= 0:
- return W_StringObject.EMPTY
- input = w_str._value
- input_len = len(input)
- try:
- buflen = ovfcheck(mul * input_len)
- except OverflowError:
- raise OperationError(
- space.w_OverflowError,
- space.wrap("repeated string is too long: %d %d" % (input_len, mul)))
- # XXX maybe only do this when input has a big length
- return joined(space, [input] * mul)
-
-def mul__String_ANY(space, w_str, w_times):
- return mul_string_times(space, w_str, w_times)
-
-def mul__ANY_String(space, w_times, w_str):
- return mul_string_times(space, w_str, w_times)
+ return space.wrap("".join(buffer))
def add__String_String(space, w_left, w_right):
- right = w_right._value
- left = w_left._value
- return joined2(space, left, right)
+ u = space.unwrap
+ right = u(w_right)
+ left = u(w_left)
+ buf = [' '] * (len(left) + len(right))
+ for i in range(len(left)):
+ buf[i] = left[i]
+ for i in range(len(right)):
+ buf[i+len(left)] = right[i]
+ return space.wrap("".join(buf))
+
+def mod_str_tuple(space, w_format, w_args):
+ # XXX implement me
+ format = space.unwrap(w_format)
+ args = space.unwrap(w_args)
+ try:
+ s = format % args
+ except TypeError, e:
+ raise OperationError(space.w_TypeError, space.wrap(str(e)))
+ except ValueError, e:
+ raise OperationError(space.w_ValueError, space.wrap(str(e)))
+ return space.wrap(s)
def len__String(space, w_str):
- return space.wrap(len(w_str._value))
+ return space.wrap(len(space.unwrap(w_str)))
def str__String(space, w_str):
- if type(w_str) is W_StringObject:
- return w_str
- return wrapstr(space, w_str._value)
-
-def iter__String(space, w_list):
- from pypy.objspace.std import iterobject
- return iterobject.W_SeqIterObject(w_list)
-
-def ord__String(space, w_str):
- u_str = w_str._value
- if len(u_str) != 1:
- raise OperationError(
- space.w_TypeError,
- space.wrap("ord() expected a character, but string "
- "of length %d found"%(len(w_str._value),)))
- return space.wrap(ord(u_str))
+ return w_str
-def getnewargs__String(space, w_str):
- return space.newtuple([wrapstr(space, w_str._value)])
-def repr__String(space, w_str):
- s = w_str._value
+def iter__String(space, w_list):
+ import iterobject
+ return iterobject.W_SeqIterObject(space, w_list)
- buf = StringBuilder(50)
+def app_repr__String(s):
quote = "'"
if quote in s and '"' not in s:
quote = '"'
- buf.append(quote)
- startslice = 0
+ repr = quote
- for i in range(len(s)):
- c = s[i]
- use_bs_char = False # character quoted by backspace
-
- if c == '\\' or c == quote:
- bs_char = c
- use_bs_char = True
- elif c == '\t':
- bs_char = 't'
- use_bs_char = True
- elif c == '\r':
- bs_char = 'r'
- use_bs_char = True
- elif c == '\n':
- bs_char = 'n'
- use_bs_char = True
+ for c in s:
+ if c == '\\' or c == quote: repr += '\\'+c
+ elif c == '\t': repr += '\\t'
+ elif c == '\r': repr += '\\r'
+ elif c == '\n': repr += '\\n'
elif not '\x20' <= c < '\x7f':
n = ord(c)
- if i != startslice:
- buf.append_slice(s, startslice, i)
- startslice = i + 1
- buf.append('\\x')
- buf.append("0123456789abcdef"[n>>4])
- buf.append("0123456789abcdef"[n&0xF])
-
- if use_bs_char:
- if i != startslice:
- buf.append_slice(s, startslice, i)
- startslice = i + 1
- buf.append('\\')
- buf.append(bs_char)
+ repr += '\\x'+"0123456789abcdef"[n>>4]+"0123456789abcdef"[n&0xF]
+ else:
+ repr += c
- if len(s) != startslice:
- buf.append_slice(s, startslice, len(s))
+ repr += quote
- buf.append(quote)
+ return repr
- return space.wrap(buf.build())
+repr__String = gateway.app2interp(app_repr__String)
-
-def str_translate__String_ANY_ANY(space, w_string, w_table, w_deletechars=''):
- """charfilter - unicode handling is not implemented
- Return a copy of the string where all characters occurring
- in the optional argument deletechars are removed, and the
- remaining characters have been mapped through the given translation table,
- which must be a string of length 256"""
+def ord__String(space, w_str):
+ return space.wrap(ord(space.unwrap(w_str)))
+
+def mod__String_ANY(space, w_str, w_item):
+ return mod__String_Tuple(space, w_str, space.newtuple([w_item]))
+
+def app_mod__String_ANY(format, values):
+ pieces = []
+ start = 0
+ state = 0
+ i = 0
+ index = -1
+ len_format = len(format)
+ while i < len_format:
+ c = format[i]
+ if state == 0:
+ # just copy constant-pieces of the format
+ if c=='%':
+ pieces.append(format[start:i])
+ state = 1
+ else:
+ if c=='%':
+ pieces.append('%')
+ else:
+ if c == '(':
+ # read name
+ j = format.find(')', i+1)
+ if j == -1:
+ raise ValueError, "incomplete format string"
+ if index >= 0:
+ raise TypeError, "format string mismatch"
+ name = format[i+1:j]
+ value = values[name]
+ index = -2
+ i = j+1
+ c = format[i]
+ else:
+ index += 1
+ if index < 0:
+ raise TypeError, "format string mismatch"
+ elif index == 0 and not isinstance(values, tuple):
+ values = tuple([values])
+ try:
+ value = values[index]
+ except IndexError:
+ raise TypeError, "not enough arguments for format string"
+
+ if c=='s':
+ pieces.append(str(value))
+ elif c=='d':
+ pieces.append(str(int(value)))
+ elif c=='x':
+ pieces.append(hex(int(value)))
+ elif c=='r':
+ pieces.append(repr(value))
+ else:
+ raise ValueError, "unsupported format character '%s' (%x) at index %d" % (
+ c, ord(c), i)
+ state = 0
+ start = i+1
+ i += 1
+
+ if state == 1:
+ raise ValueError, "incomplete format"
+ if index >= 0 and index < len(values) - 1:
+ raise TypeError, 'not all arguments converted during string formatting'
+ pieces.append(format[start:])
+ return ''.join(pieces)
+
+mod__String_ANY = gateway.app2interp(app_mod__String_ANY)
+
+# register all methods
+register_all(vars(), W_StringType)
+
- # XXX CPython accepts buffers, too, not sure what we should do
- table = space.str_w(w_table)
- if len(table) != 256:
- raise OperationError(
- space.w_ValueError,
- space.wrap("translation table must be 256 characters long"))
-
- string = w_string._value
- chars = []
- for char in string:
- w_char = W_StringObject.PREBUILT[ord(char)]
- if not space.is_true(space.contains(w_deletechars, w_char)):
- chars.append(table[ord(char)])
- return W_StringObject(''.join(chars))
-
-def str_decode__String_ANY_ANY(space, w_string, w_encoding=None, w_errors=None):
- from pypy.objspace.std.unicodetype import _get_encoding_and_errors, \
- unicode_from_string, decode_object
- encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors)
- if encoding is None and errors is None:
- return unicode_from_string(space, w_string)
- return decode_object(space, w_string, encoding, errors)
-
-def str_encode__String_ANY_ANY(space, w_string, w_encoding=None, w_errors=None):
- from pypy.objspace.std.unicodetype import _get_encoding_and_errors, \
- encode_object
- encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors)
- return encode_object(space, w_string, encoding, errors)
-
-# CPython's logic for deciding if ""%values is
-# an error (1 value, 0 %-formatters) or not
-# (values is of a mapping type)
-def mod__String_ANY(space, w_format, w_values):
- return mod_format(space, w_format, w_values, do_unicode=False)
-
-def buffer__String(space, w_string):
- from pypy.interpreter.buffer import StringBuffer
- return space.wrap(StringBuffer(w_string._value))
-
-# register all methods
-from pypy.objspace.std import stringtype
-register_all(vars(), stringtype)
Modified: pypy/branch/avm/pypy/objspace/std/test/test_multimethod.py
==============================================================================
--- pypy/branch/avm/pypy/objspace/std/test/test_multimethod.py (original)
+++ pypy/branch/avm/pypy/objspace/std/test/test_multimethod.py Thu Nov 5 20:27:32 2009
@@ -1,250 +1,149 @@
-from py.test import raises
+import autopath
-from pypy.objspace.std import multimethod
-from pypy.objspace.std.multimethod import FailedToImplement
+from pypy.objspace.std.multimethod import *
+from pypy.tool import testit
+BoundMultiMethod.ASSERT_BASE_TYPE = object
-class W_Root(object):
- pass
-class W_IntObject(W_Root):
- pass
-
-class W_BoolObject(W_Root):
- pass
-
-class W_StringObject(W_Root):
- pass
-
-def delegate_b2i(space, w_x):
- assert isinstance(w_x, W_BoolObject)
- return W_IntObject()
-
-def add__Int_Int(space, w_x, w_y):
- assert space == 'space'
- assert isinstance(w_x, W_IntObject)
- assert isinstance(w_y, W_IntObject)
- return 'fine'
-
-
-class TestMultiMethod1:
- Installer = multimethod.InstallerVersion1
-
- def setup_class(cls):
- cls.prev_installer = multimethod.Installer
- multimethod.Installer = cls.Installer
- add = multimethod.MultiMethodTable(2, root_class=W_Root,
- argnames_before=['space'])
- add.register(add__Int_Int, W_IntObject, W_IntObject)
- typeorder = {
- W_IntObject: [(W_IntObject, None), (W_Root, None)],
- W_BoolObject: [(W_BoolObject, None), (W_IntObject, delegate_b2i),
- (W_Root, None)],
- W_StringObject: [(W_StringObject, None), (W_Root, None)],
- }
- cls.typeorder = typeorder
- cls.add = add
- cls.add1 = staticmethod(add.install('__add', [typeorder, typeorder]))
-
- def teardown_class(cls):
- multimethod.Installer = cls.prev_installer
-
- def test_simple(self):
- space = 'space'
- w_x = W_IntObject()
- w_y = W_IntObject()
- assert self.add1(space, w_x, w_y) == 'fine'
-
- def test_failtoimplement(self):
- space = 'space'
- w_x = W_IntObject()
- w_s = W_StringObject()
- raises(FailedToImplement, "self.add1(space, w_x, w_s)")
- raises(FailedToImplement, "self.add1(space, w_s, w_x)")
-
- def test_delegate(self):
- space = 'space'
- w_x = W_IntObject()
- w_s = W_StringObject()
- w_b = W_BoolObject()
- assert self.add1(space, w_x, w_b) == 'fine'
- assert self.add1(space, w_b, w_x) == 'fine'
- assert self.add1(space, w_b, w_b) == 'fine'
- raises(FailedToImplement, "self.add1(space, w_b, w_s)")
- raises(FailedToImplement, "self.add1(space, w_s, w_b)")
-
- def test_not_baked(self):
- typeorder = self.typeorder
- add2 = self.add.install('__add2', [typeorder, typeorder],
- baked_perform_call=False)
- assert add2[0] == ['space', 'arg0', 'arg1']
- if multimethod.Installer is multimethod.InstallerVersion1:
- assert add2[1] == 'arg0.__add2(space, arg1)'
- assert isinstance(add2[2], dict)
- assert not add2[3]
-
- def test_empty(self):
- add3_installer = multimethod.Installer(self.add, '__add3', [{},{}])
- assert add3_installer.is_empty()
- if multimethod.Installer is multimethod.InstallerVersion1:
- assert len(add3_installer.to_install) == 1
- assert add3_installer.to_install[0][0] is None
-
- def test_empty_direct(self):
- assert not self.add.install_if_not_empty('__add4', [{},{}])
-
- def test_empty_not_baked(self):
- add5_installer = multimethod.Installer(self.add, '__add5', [{},{}],
- baked_perform_call=False)
- assert add5_installer.is_empty()
- if multimethod.Installer is multimethod.InstallerVersion1:
- assert len(add5_installer.to_install) == 0
- add5 = add5_installer.install()
- assert add5[0] == ['space', 'arg0', 'arg1']
- assert add5[1] == 'raiseFailedToImplement()'
- assert isinstance(add5[2], dict)
- assert add5[3]
-
- def test_mmdispatcher(self):
- typeorder = self.typeorder
- add2 = multimethod.MMDispatcher(self.add, [typeorder, typeorder])
- space = 'space'
- w_x = W_IntObject()
- w_s = W_StringObject()
- w_b1 = W_BoolObject()
- w_b2 = W_BoolObject()
- assert add2(space, w_x, w_b1) == 'fine'
- assert add2(space, w_b2, w_x) == 'fine'
- assert add2(space, w_b1, w_b2) == 'fine'
- raises(FailedToImplement, "add2(space, w_b2, w_s)")
- raises(FailedToImplement, "add2(space, w_s, w_b1)")
-
- def test_forbidden_subclasses(self):
- mul = multimethod.MultiMethodTable(2, root_class=W_Root,
- argnames_before=['space'])
- class UserW_StringObject(W_StringObject):
- pass
- def mul__Int_String(space, w_x, w_y):
- assert space == 'space'
- assert isinstance(w_x, W_IntObject)
- assert isinstance(w_y, W_StringObject)
- return 'fine'
- mul.register(mul__Int_String, W_IntObject, W_StringObject)
-
- mul1 = mul.install('__mul1', [self.typeorder, self.typeorder])
- assert mul1('space', W_IntObject(), W_StringObject()) == 'fine'
- assert mul1('space', W_IntObject(), UserW_StringObject()) == 'fine'
-
- ext_typeorder = self.typeorder.copy()
- ext_typeorder[UserW_StringObject] = []
- mul2 = mul.install('__mul2', [ext_typeorder, ext_typeorder])
- assert mul2('space', W_IntObject(), W_StringObject()) == 'fine'
- raises(FailedToImplement,
- mul2, 'baz', W_IntObject(), UserW_StringObject())
-
- def test_more_forbidden_subclasses(self):
- mul = multimethod.MultiMethodTable(2, root_class=W_Root,
- argnames_before=['space'])
- class UserW_StringObject(W_StringObject):
- pass
- def mul__String_String(space, w_x, w_y):
- assert space == 'space'
- assert isinstance(w_x, W_StringObject)
- assert isinstance(w_y, W_StringObject)
- return 'fine'
- mul.register(mul__String_String, W_StringObject, W_StringObject)
-
- ext_typeorder = {W_StringObject: [(W_StringObject, None)],
- UserW_StringObject: []}
- mul2 = mul.install('__mul2', [ext_typeorder, ext_typeorder])
- assert mul2('space', W_StringObject(), W_StringObject()) == 'fine'
- raises(FailedToImplement,
- mul2, 'baz', W_StringObject(), UserW_StringObject())
- raises(FailedToImplement,
- mul2, 'baz', UserW_StringObject(), W_StringObject())
- raises(FailedToImplement,
- mul2, 'baz', UserW_StringObject(), UserW_StringObject())
-
- def test_ANY(self):
- setattr = multimethod.MultiMethodTable(3, root_class=W_Root,
- argnames_before=['space'])
- def setattr__Int_ANY_ANY(space, w_x, w_y, w_z):
- assert space == 'space'
- assert isinstance(w_x, W_IntObject)
- assert isinstance(w_y, W_Root)
- assert isinstance(w_z, W_Root)
- return w_y.__class__.__name__ + w_z.__class__.__name__
- setattr.register(setattr__Int_ANY_ANY, W_IntObject, W_Root, W_Root)
- setattr1 = setattr.install('__setattr1', [self.typeorder]*3)
- for cls1 in self.typeorder:
- for cls2 in self.typeorder:
- assert setattr1('space', W_IntObject(), cls1(), cls2()) == (
- cls1.__name__ + cls2.__name__)
-
- def test_all_cases(self):
- import random
- space = 'space'
- w_x = W_IntObject()
- w_x.expected = [W_IntObject, W_Root]
- w_s = W_StringObject()
- w_s.expected = [W_StringObject, W_Root]
- w_b = W_BoolObject()
- w_b.expected = [W_BoolObject, W_IntObject, W_Root]
-
- def test(indices):
- sub = multimethod.MultiMethodTable(2, root_class=W_Root,
- argnames_before=['space'])
- def addimpl(cls1, cls2):
- token = random.random()
- def sub__cls1_cls2(space, w_x, w_y):
- assert space == 'space'
- assert isinstance(w_x, cls1)
- assert isinstance(w_y, cls2)
- return token
- sub.register(sub__cls1_cls2, cls1, cls2)
- return token
-
- def check(w1, w2):
- try:
- res = sub1(space, w1, w2)
- except FailedToImplement:
- res = FailedToImplement
- for cls1 in w1.expected:
- for cls2 in w2.expected:
- if (cls1, cls2) in expected:
- assert res == expected[cls1, cls2]
- return
- else:
- assert res is FailedToImplement
-
- random.shuffle(indices)
- expected = {}
- for index in indices:
- cls1, cls2 = choices[index]
- token = addimpl(cls1, cls2)
- expected[cls1, cls2] = token
-
- typeorder = self.typeorder
- sub1 = sub.install('__sub', [typeorder, typeorder])
- for w1 in [w_x, w_s, w_b]:
- for w2 in [w_x, w_s, w_b]:
- check(w1, w2)
-
- classes = [W_Root, W_StringObject, W_IntObject, W_BoolObject]
- choices = [(cls1, cls2) for cls1 in classes
- for cls2 in classes]
- # each choice is a pair of classes which can be implemented or
- # not by the multimethod 'sub'. Test all combinations that
- # involve at most three implemented choices.
- for i in range(len(choices)):
- test([i])
- for j in range(i+1, len(choices)):
- test([i, j])
- for k in range(j+1, len(choices)):
- test([i, j, k])
- #for l in range(k+1, len(choices)): -- for a 4th choice
- # test([i, j, k, l]) -- (takes a while)
+class X:
+ def __init__(self, value):
+ self.value = value
+ def __repr__(self):
+ return '<X %r>' % self.value
+
+def from_y_to_x(space, yinstance):
+ return X(yinstance)
+
+from_y_to_x.result_class = X
+from_y_to_x.priority = 2
+
+def from_x_to_str(space, xinstance):
+ #if xinstance.value:
+ return w('!' + repr(xinstance.value))
+ #else:
+ # return []
+
+from_x_to_str.result_class = str
+from_x_to_str.priority = 2
+
+
+class Y:
+ def __init__(self, value):
+ self.value = value
+ def __repr__(self):
+ return '<Y %r>' % self.value
+ def __nonzero__(self):
+ return self.value != 666
+
+
+def add_x_x(space, x1, x2):
+ return "add_x_x", x1, x2
+
+def add_x_y(space, x1, y2):
+ if x1.value < 0:
+ raise FailedToImplement(ValueError, 'not good')
+ return "add_x_y", x1, y2
+
+def add_y_y(space, y1, y2):
+ return "add_y_y", y1, y2
+
+def add_string_string(space, x, y):
+ return "add_string_string", x, y
+
+def add_int_string(space, x, y):
+ return "add_int_string", x, y
+
+def add_int_any(space, y1, o2):
+ return "add_int_any", y1, o2
+
+class FakeObjSpace:
+ add = MultiMethod('+', 2, [])
+ add.register(add_x_x, X, X)
+ add.register(add_x_y, X, Y)
+ add.register(add_y_y, Y, Y)
+ add.register(add_string_string, str, str)
+ add.register(add_int_string, int, str)
+ add.register(add_int_any, int, object)
+
+ delegate = DelegateMultiMethod()
+ delegate.register(from_y_to_x, Y)
+ delegate.register(from_x_to_str, X)
+
+ def wrap(self, x):
+ return '<wrapped %r>' % (x,)
+ w_TypeError = 'w_TypeError'
+
+##def w(x, cache={}):
+## if type(x) in cache:
+## Stub = cache[type(x)]
+## else:
+## Stub = type(type(x))('%s_stub' % type(x).__name__, (type(x),), {})
+## Stub.dispatchclass = Stub
+## cache[type(x)] = Stub
+## return Stub(x)
+
+##X.dispatchclass = X
+##Y.dispatchclass = Y
+
+def w(x):
+ return x
+
+
+class TestMultiMethod(testit.TestCase):
+ def setUp(self):
+ # only run when testing stdobjectspace
+ #XXX removed: testit.objspace('std')
+ self.space = FakeObjSpace()
+
+ def test_non_delegate(self):
+ space = self.space
+
+ r = space.add(X(2), X(5))
+ self.assertEquals(repr(r), "('add_x_x', <X 2>, <X 5>)")
+
+ r = space.add(X(3), Y(4))
+ self.assertEquals(repr(r), "('add_x_y', <X 3>, <Y 4>)")
+
+ r = space.add(Y(0), Y(20))
+ self.assertEquals(repr(r), "('add_y_y', <Y 0>, <Y 20>)")
+
+ r = space.add(w(-3), w([7,6,5]))
+ self.assertEquals(repr(r), "('add_int_any', -3, [7, 6, 5])")
+
+ r = space.add(w(5), w("test"))
+ self.assertEquals(repr(r), "('add_int_string', 5, 'test')")
+
+ r = space.add(w("x"), w("y"))
+ self.assertEquals(repr(r), "('add_string_string', 'x', 'y')")
+
+ def test_delegate_y_to_x(self):
+ space = self.space
+ r = space.add(Y(-1), X(7))
+ self.assertEquals(repr(r), "('add_x_x', <X <Y -1>>, <X 7>)")
+
+ r = space.add(Y(1), X(7))
+ self.assertEquals(repr(r), "('add_x_x', <X <Y 1>>, <X 7>)")
+
+ r = space.add(X(-3), Y(20))
+ self.assertEquals(repr(r), "('add_x_x', <X -3>, <X <Y 20>>)")
+
+ def test_no_operation_defined(self):
+ space = self.space
+ self.assertRaises(OperationError, space.add, w([3]), w(4))
+ self.assertRaises(OperationError, space.add, w(3.0), w('bla'))
+ #self.assertRaises(OperationError, space.add, X(0), w("spam"))
+ #self.assertRaises(OperationError, space.add, Y(666), w("egg"))
+
+ def test_delegate_x_to_str(self):
+ space = self.space
+ r = space.add(X(42), w("spam"))
+ self.assertEquals(repr(r), "('add_string_string', '!42', 'spam')")
+ r = space.add(Y(20), w("egg"))
+ self.assertEquals(repr(r), "('add_string_string', '!<Y 20>', 'egg')")
-class TestMultiMethod2(TestMultiMethod1):
- Installer = multimethod.InstallerVersion2
+
+
+if __name__ == '__main__':
+ testit.main()
More information about the Pypy-commit
mailing list