[pypy-svn] rev 1121 - in pypy/branch/builtinrefactor/pypy: interpreter module module/test
hpk at codespeak.net
hpk at codespeak.net
Sat Jul 12 11:50:54 CEST 2003
Author: hpk
Date: Sat Jul 12 11:50:52 2003
New Revision: 1121
Removed:
pypy/branch/builtinrefactor/pypy/interpreter/pycode_app.py
pypy/branch/builtinrefactor/pypy/interpreter/pyframe_app.py
Modified:
pypy/branch/builtinrefactor/pypy/interpreter/baseobjspace.py
pypy/branch/builtinrefactor/pypy/interpreter/pycode.py
pypy/branch/builtinrefactor/pypy/interpreter/pyframe.py
pypy/branch/builtinrefactor/pypy/module/builtin.py
pypy/branch/builtinrefactor/pypy/module/test/test_builtin.py
Log:
- got rid of pyframe_app, and pyframe_app by introducing a new
mechanism for *exposing app-level defined methods at interp-level*.
This is not really perfect but i begins to work so i check it in.
the mechanism is invoked like so (it's not perfect, i know)
class someclass:
def app_method(self, fixed, number, of, args):
# do app-level stuff, don't use 'self' for the time beeing
# examples: decode_code_arguments, normalize_exception
method = app2interp(app_method)
def othermethod(self):
# 'self.space' *must* contain an objectspace instance
self.method(fixed, number, of, args)
- there is a new (experimental, of course!) approach to executing
code objects. Actually the "app2interp" method when called
makes up an "AppBuiltinCode" instance which is a simple form
of a code object. Instead of the whole "build_arguments" to-dict-locals-
and-then-get-it-out-of-locals business it constructs arguments
in a straightforward manner. Thus it's currently not possible
to pass anything like the exact number of arguments (no defaults, etc.)
It probably makes sense to extend argument-parsing by using Michael's
extmodule's subclassing technique for handling various argument-passing
cases.
Not that AppBuiltinCode creates a new kind of frame called "AppFrame"
which subclass PyFrame but has an easy initialization (see above)
- moved tests to applevel and added one for execfile
Modified: pypy/branch/builtinrefactor/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/baseobjspace.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/baseobjspace.py Sat Jul 12 11:50:52 2003
@@ -1,6 +1,5 @@
from executioncontext import ExecutionContext, OperationError, NoValue
-import pyframe, threadlocals
-import pypy.module.builtin
+import threadlocals
__all__ = ['ObjSpace', 'OperationError', 'NoValue', 'PyPyError']
@@ -22,6 +21,7 @@
self.initialize()
def make_builtins(self):
+ import pypy.module.builtin
self.builtin = pypy.module.builtin.Builtin(self)
self.w_builtin = self.builtin.wrap_base()
self.w_builtins = self.getattr(self.w_builtin, self.wrap("__dict__"))
Modified: pypy/branch/builtinrefactor/pypy/interpreter/pycode.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/pycode.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/pycode.py Sat Jul 12 11:50:52 2003
@@ -16,15 +16,36 @@
# look at this if it makes sense
# think of a proper base class???
-import baseobjspace, pyframe, executioncontext
-import appfile
-
-appfile = appfile.AppFile(__name__, ["interpreter"])
+import baseobjspace, executioncontext
CO_VARARGS = 0x0004
CO_VARKEYWORDS = 0x0008
+class app2interp(object):
+ """ this class exposes an app-level defined function at interpreter-level
+
+ Assumption: the interp-level function will be called ala
+
+ a.function(arg1, arg2, argn)
+
+ with 'a' having an attribute 'space' which the app-level
+ code should run in. (might change in during the branch)
+ """
+
+ def __init__(self, func):
+ #print "making app2interp for", func
+ self.func = func
+ self._codecache = {}
+ def __get__(self, instance, cls=None):
+ space = instance.space
+ try:
+ return self._codecache[(space, instance, self)]
+ except KeyError:
+ c = AppBuiltinCode(space, self.func, instance)
+ self._codecache[(space, instance, self)] = c
+ return c
+
class PyBaseCode(object):
def __init__(self):
self.co_name = ""
@@ -59,16 +80,104 @@
if w_defaults is None: w_defaults = space.newtuple([])
if w_closure is None: w_closure = space.newtuple([])
w_bytecode = space.wrap(co)
- w_arguments = space.gethelper(appfile).call(
- "decode_code_arguments", [w_arguments, w_kwargs, w_defaults,
- w_bytecode])
- # we assume that decode_code_arguments() gives us a dictionary
- # of the correct length.
+
+ self.space = space
+ w_locals = self.decode_code_arguments(w_arguments, w_kwargs,
+ w_defaults, w_bytecode)
if space.is_true(w_closure):
l = zip(co.co_freevars, space.unpackiterable(w_closure))
for key, w_cell in l:
- space.setitem(w_arguments, space.wrap(key), w_cell)
- return w_arguments
+ space.setitem(w_locals, space.wrap(key), w_cell)
+ return w_locals
+
+ def app_decode_code_arguments(self, args, kws, defs, codeobject):
+ """
+ Assumptions:
+ args sequence of the normal actual parameters
+ kws dictionary of keyword actual parameters
+ defs sequence of defaults
+ codeobject our code object carrying argument info
+ """
+ CO_VARARGS = 0x4
+ CO_VARKEYWORDS = 0x8
+ varargs = (codeobject.co_flags & CO_VARARGS) and 1
+ varkeywords = (codeobject.co_flags & CO_VARKEYWORDS) and 1
+ varargs_tuple = ()
+
+ argdict = {}
+ parameter_names = codeobject.co_varnames[:codeobject.co_argcount]
+
+ # Normal arguments
+ for i in range(0, len(args), 1): # see comment above for ", 1"
+ if 0 <= i < len(parameter_names): # try
+ argdict[parameter_names[i]] = args[i]
+ else: # except IndexError:
+ # If varargs, put in tuple, else throw error
+ if varargs:
+ varargs_tuple = args[i:]
+ else:
+ raise TypeError, 'Too many parameters to callable object'
+ break
+
+ # Put all suitable keywords into arglist
+ if kws:
+ if varkeywords:
+ # Allow all keywords
+ newkw = {}
+ for key in kws.keys():
+ for name in parameter_names:
+ if name == key:
+ if key in argdict:
+ raise TypeError, 'Setting parameter %s twice.' % name
+ else:
+ argdict[key] = kws[key]
+ break # name found in parameter names
+ else:
+ newkw[key] = kws[key]
+
+ else:
+ # Only allow formal parameter keywords
+ count = len(kws)
+ for name in parameter_names:
+ if name in kws:
+ count -= 1
+ if name in argdict:
+ raise TypeError, 'Setting parameter %s twice.' % name
+ else:
+ argdict[name] = kws[name]
+ if count:
+ # XXX This should be improved to show the parameters that
+ # shouldn't be here.
+ raise TypeError('Setting keyword parameter that does '
+ 'not exist in formal parameter list.')
+ else:
+ newkw = {}
+
+ # Fill in with defaults, starting at argcount - defcount
+ if defs:
+ argcount = codeobject.co_argcount
+ defcount = len(defs)
+ for i in range(argcount - defcount, argcount, 1): # ", 1" comment above
+ if parameter_names[i] in argdict:
+ continue
+ argdict[parameter_names[i]] = defs[i - (argcount - defcount)]
+
+ if len(argdict) < codeobject.co_argcount:
+ raise TypeError, 'Too few parameters to callable object'
+
+ namepos = codeobject.co_argcount
+ if varargs:
+ name = codeobject.co_varnames[namepos]
+ argdict[name] = varargs_tuple
+ namepos += 1
+ if varkeywords:
+ name = codeobject.co_varnames[namepos]
+ argdict[name] = newkw
+
+ return argdict
+
+ decode_code_arguments = app2interp(app_decode_code_arguments)
+
class PyByteCode(PyBaseCode):
"""Represents a code object for Python functions.
@@ -115,12 +224,14 @@
self.co_consts = newconsts
def eval_code(self, space, w_globals, w_locals):
+ from pypy.interpreter import pyframe
frame = pyframe.PyFrame(space, self, w_globals, w_locals)
ec = space.getexecutioncontext()
w_ret = ec.eval_frame(frame)
return w_ret
def locals2cells(self, space, w_locals):
+ from pypy.interpreter import pyframe
localcells = []
Cell = pyframe.Cell
for name in self.co_varnames:
@@ -145,3 +256,35 @@
cell = space.unwrap(w_cell)
nestedcells.append(cell)
return localcells, nestedcells
+
+class AppBuiltinCode:
+ """The code object implementing a app-level hook """
+
+ def __init__(self, space, func, instance=None):
+ assert func.func_code.co_flags & (CO_VARARGS|CO_VARKEYWORDS) == 0
+ self.space = space
+
+ #PyBaseCode.__init__(self)
+ co = func.func_code
+
+ self.instance = instance
+ self.func = func
+ self.co_code = co.co_code
+ self.co_name = func.__name__
+ self.co_consts = co.co_consts
+ self.co_flags = co.co_flags
+ self.co_varnames = tuple(co.co_varnames)
+ self.co_nlocals = co.co_nlocals
+ self.co_argcount = co.co_argcount
+ self.co_names = co.co_names
+ self.next_arg = self.co_argcount
+
+ def __call__(self, *args_w):
+ from pypy.interpreter import pyframe
+ w_globals = self.space.newdict([])
+ if self.instance:
+ args_w = (self.space.wrap(self.instance),) + args_w # effects untested
+ frame = pyframe.AppFrame(self.space, self, w_globals, args_w)
+ ec = self.space.getexecutioncontext()
+ w_ret = ec.eval_frame(frame)
+ return w_ret
Deleted: pypy/branch/builtinrefactor/pypy/interpreter/pycode_app.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/pycode_app.py Sat Jul 12 11:50:52 2003
+++ (empty file)
@@ -1,99 +0,0 @@
-# replacement for decode_frame_arguments
-#
-# ===== ATTENTION =====
-#
-# This code is pretty fundamental to pypy and great care must be taken
-# to avoid infinite recursion. In particular:
-#
-# - All calls here must be "easy", i.e. not involve default or keyword
-# arguments. For example, all range() calls need three arguments.
-#
-# - You cannot *catch* any exceptions (raising is fine).
-#
-# (I wonder if the pain of writing this at interpreter level might be
-# worth it...)
-
-def decode_code_arguments(args, kws, defs, codeobject):
- """
- Assumptions:
- args = sequence of the normal actual parameters
- kws = dictionary of keyword actual parameters
- defs = sequence of defaults
- """
- CO_VARARGS = 0x4
- CO_VARKEYWORDS = 0x8
- varargs = (codeobject.co_flags & CO_VARARGS) and 1
- varkeywords = (codeobject.co_flags & CO_VARKEYWORDS) and 1
- varargs_tuple = ()
-
- argdict = {}
- parameter_names = codeobject.co_varnames[:codeobject.co_argcount]
-
- # Normal arguments
- for i in range(0, len(args), 1): # see comment above for ", 1"
- if 0 <= i < len(parameter_names): # try
- argdict[parameter_names[i]] = args[i]
- else: # except IndexError:
- # If varargs, put in tuple, else throw error
- if varargs:
- varargs_tuple = args[i:]
- else:
- raise TypeError, 'Too many parameters to callable object'
- break
-
- # Put all suitable keywords into arglist
- if kws:
- if varkeywords:
- # Allow all keywords
- newkw = {}
- for key in kws.keys():
- for name in parameter_names:
- if name == key:
- if key in argdict:
- raise TypeError, 'Setting parameter %s twice.' % name
- else:
- argdict[key] = kws[key]
- break # name found in parameter names
- else:
- newkw[key] = kws[key]
-
- else:
- # Only allow formal parameter keywords
- count = len(kws)
- for name in parameter_names:
- if name in kws:
- count -= 1
- if name in argdict:
- raise TypeError, 'Setting parameter %s twice.' % name
- else:
- argdict[name] = kws[name]
- if count:
- # XXX This should be improved to show the parameters that
- # shouldn't be here.
- raise TypeError('Setting keyword parameter that does '
- 'not exist in formal parameter list.')
- else:
- newkw = {}
-
- # Fill in with defaults, starting at argcount - defcount
- if defs:
- argcount = codeobject.co_argcount
- defcount = len(defs)
- for i in range(argcount - defcount, argcount, 1): # ", 1" comment above
- if parameter_names[i] in argdict:
- continue
- argdict[parameter_names[i]] = defs[i - (argcount - defcount)]
-
- if len(argdict) < codeobject.co_argcount:
- raise TypeError, 'Too few parameters to callable object'
-
- namepos = codeobject.co_argcount
- if varargs:
- name = codeobject.co_varnames[namepos]
- argdict[name] = varargs_tuple
- namepos += 1
- if varkeywords:
- name = codeobject.co_varnames[namepos]
- argdict[name] = newkw
-
- return argdict
Modified: pypy/branch/builtinrefactor/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/pyframe.py (original)
+++ pypy/branch/builtinrefactor/pypy/interpreter/pyframe.py Sat Jul 12 11:50:52 2003
@@ -2,9 +2,8 @@
"""
from pypy.interpreter.executioncontext import OperationError, Stack, NoValue
-from pypy.interpreter.appfile import AppFile
-appfile = AppFile(__name__, ["interpreter"])
+from pypy.interpreter.pycode import app2interp
class PyFrame:
@@ -229,8 +228,8 @@
## import pdb
## pdb.set_trace()
## print w_type, `w_value`, frame.bytecode.co_name
- w_res = s.gethelper(appfile).call(
- "normalize_exception", [w_type, w_value])
+ self.space = s # needed for the following call
+ w_res = self.normalize_exception(w_type, w_value)
w_value = s.getitem(w_res, s.wrap(1))
frame.valuestack.push(w_value)
@@ -238,6 +237,22 @@
frame.next_instr = self.handlerposition # jump to the handler
raise StopUnrolling
+ def app_normalize_exception(self, etype, evalue):
+ # 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, "?!"
+ return etype, evalue
+ normalize_exception = app2interp(app_normalize_exception)
+
+
class FinallyBlock(FrameBlock):
"""A try:finally: block. Stores the position of the exception handler."""
@@ -370,3 +385,41 @@
else:
return "%s(%s)" % (self.__class__.__name__, self.w_value)
+class AppFrame(PyFrame):
+ """Represents a frame for a regular Python function
+ that needs to be interpreted.
+
+ Public fields:
+ * 'space' is the object space this frame is running in
+ * 'w_locals' is the locals dictionary to use
+ * 'w_globals' is the attached globals dictionary
+ * 'w_builtins' is the attached built-ins dictionary
+ * 'valuestack', 'blockstack', 'next_instr' control the interpretation
+ """
+
+ def __init__(self, space, bytecode, w_globals, argtuple):
+ self.space = space
+ self.bytecode = bytecode # Misnomer; this is really like a code object
+
+ # XXX we may want to have lazy access to interp-level through w_globals later
+ self.w_globals = w_globals
+
+ # XXX construct self.w_locals
+ self.nestedcells = ()
+ self.localcells = [ Cell(x) for x in argtuple ]
+ missing = self.bytecode.co_nlocals - len(self.localcells)
+ self.localcells.extend([ Cell() for x in range(missing)])
+
+ self.w_builtins = self.load_builtins()
+ self.valuestack = Stack()
+ self.blockstack = Stack()
+ self.last_exception = None
+ self.next_instr = 0
+ #self._dump()
+
+ def _dump(self):
+ print "AppFrame_dump"
+ print " space ", self.space
+ print " localcells", self.localcells
+ print " co_varnames ", self.bytecode.co_varnames
+
Deleted: pypy/branch/builtinrefactor/pypy/interpreter/pyframe_app.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/interpreter/pyframe_app.py Sat Jul 12 11:50:52 2003
+++ (empty file)
@@ -1,99 +0,0 @@
-# XXX
-# This is deprecated.
-# We use the same functionality,. but do it in
-# pycode_app.py.
-# the function is just fine, we just don't reduce the
-# dictionary; it is the result.
-
-def decode_frame_arguments(args, kws, defs, closure, codeobject):
- """
- Assumptions:
- args = sequence of the normal actual parameters
- kws = dictionary of keyword actual parameters
- defs = sequence of defaults
- """
- CO_VARARGS = 0x4
- CO_VARKEYWORDS = 0x8
- varargs = (codeobject.co_flags & CO_VARARGS) and 1
- varkeywords = (codeobject.co_flags & CO_VARKEYWORDS) and 1
- varargs_tuple = ()
-
- argdict = {}
- parameter_names = codeobject.co_varnames[:codeobject.co_argcount]
-
- # Normal arguments
- for i in range(len(args)):
- try:
- argdict[parameter_names[i]] = args[i]
- except IndexError:
- # If varargs, put in tuple, else throw error
- if varargs:
- varargs_tuple = args[i:]
- else:
- raise TypeError, 'Too many parameters to callable object'
-
- # Put all suitable keywords into arglist
- if kws:
- if varkeywords:
- # Allow all keywords
- newkw = {}
- for key in kws.keys():
- for name in parameter_names:
- if name == key:
- if argdict.has_key(key):
- raise TypeError, 'Setting parameter %s twice.' % name
- else:
- argdict[key] = kws[key]
- break # name found in parameter names
- else:
- newkw[key] = kws[key]
-
- else:
- # Only allow formal parameter keywords
- count = len(kws)
- for name in parameter_names:
- if kws.has_key(name):
- count -= 1
- if argdict.has_key(name):
- raise TypeError, 'Setting parameter %s twice.' % name
- else:
- argdict[name] = kws[name]
- if count:
- # XXX This should be improved to show the parameters that
- # shouldn't be here.
- raise TypeError, 'Setting keyword parameter that does not exist in formal parameter list.'
-
- # Fill in with defaults, starting at argcount - defcount
- if defs:
- argcount = codeobject.co_argcount
- defcount = len(defs)
- for i in range(argcount - defcount, argcount):
- if argdict.has_key(parameter_names[i]):
- continue
- argdict[parameter_names[i]] = defs[i - (argcount - defcount)]
-
- if len(argdict) < codeobject.co_argcount:
- raise TypeError, 'Too few paramteres to callable object'
-
- a = [argdict[name] for name in parameter_names]
- if varargs:
- a.append(varargs_tuple)
- if varkeywords:
- a.append(newkw)
- return tuple(a)
-
-def normalize_exception(etype, evalue):
- # 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, "?!"
- return etype, evalue
-
Modified: pypy/branch/builtinrefactor/pypy/module/builtin.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/module/builtin.py (original)
+++ pypy/branch/builtinrefactor/pypy/module/builtin.py Sat Jul 12 11:50:52 2003
@@ -9,16 +9,6 @@
class Builtin(BuiltinModule):
__pythonname__ = '__builtin__'
- #__appfile__ = appfile.AppFile(__name__, ["module"])
-
- #__helper_appfile__ = appfile.AppFile('builtin_helper',["module"])
-
- # temporary hack, until we have a real tuple type for calling
- #def tuple(self, w_obj):
- # lis = self.space.unpackiterable(w_obj)
- # w_res = self.space.newtuple(lis)
- # return w_res
- #tuple = appmethod(tuple)
def _actframe(self, index=-1):
return self.space.getexecutioncontext().framestack.items[index]
@@ -93,13 +83,13 @@
return space.wrap(res)
compile = appmethod(compile)
- def execfile(self, w_filename, w_globals, w_locals):
+ def execfile(self, w_filename, w_globals=None, w_locals=None):
space = self.space
#XXX why do i have to check against space.w_None instead of None?
# above the compile commands *does* check against None
- if w_globals is None or w_globals is space.w_None:
+ if w_globals is space.w_None:
w_globals = self._actframe().w_globals
- if w_locals is None or w_globals is space.w_None:
+ if w_locals is space.w_None:
w_locals = w_globals
filename = space.unwrap(w_filename)
@@ -174,17 +164,14 @@
return self.space.ord(w_val)
ord = appmethod(ord)
-
def pow(self, w_val):
return self.space.pow(w_val)
pow = appmethod(pow)
-
def repr(self, w_object):
return self.space.repr(w_object)
repr = appmethod(repr)
-
def setattr(self, w_object, w_name, w_val):
return self.space.setattr(w_object, w_name, w_val)
setattr = appmethod(setattr)
Modified: pypy/branch/builtinrefactor/pypy/module/test/test_builtin.py
==============================================================================
--- pypy/branch/builtinrefactor/pypy/module/test/test_builtin.py (original)
+++ pypy/branch/builtinrefactor/pypy/module/test/test_builtin.py Sat Jul 12 11:50:52 2003
@@ -52,13 +52,42 @@
self.assertEquals(iter_x.next(), 3)
self.assertRaises(StopIteration, iter_x.next)
-class TestCmp(test.TestCase):
-
def test_cmp(self):
- self.failUnless(cmp(9, 9) == 0)
- self.failUnless(cmp(0,9) < 0)
- self.failUnless(cmp(9,0) > 0)
-
+ self.assertEquals(cmp(9,9), 0)
+ self.assert_(cmp(0,9) < 0)
+ self.assert_(cmp(9,0) > 0)
+
+class TestInternal(test.IntTestCase):
+
+ def setUp(self):
+ self.space = space = test.objspace()
+
+ def get_builtin(self, name):
+ w = self.space.wrap
+ w_builtins = self.space.w_builtins
+ w_obj = self.space.getitem(w_builtins, w(name))
+ return w_obj
+
+ def test_execfile(self):
+ # we need cpython's tempfile currently to test
+ from tempfile import mktemp
+ fn = mktemp()
+ f = open(fn, 'w')
+ print >>f, "i=42"
+ f.close()
+
+ try:
+ w_execfile = self.get_builtin('execfile')
+ space = self.space
+ w_dict = space.newdict([])
+ self.space.call(w_execfile, space.newtuple([
+ space.wrap(fn), w_dict, space.w_None]), space.newdict([]))
+ w_value = space.getitem(w_dict, space.wrap('i'))
+ self.assertEqual_w(w_value, space.wrap(42))
+ finally:
+ import os
+ os.remove(fn)
+
if __name__ == '__main__':
test.main()
More information about the Pypy-commit
mailing list