[pypy-svn] r28362 - in pypy/dist/pypy/rpython: . ootypesystem ootypesystem/test test
antocuni at codespeak.net
antocuni at codespeak.net
Tue Jun 6 13:08:42 CEST 2006
Author: antocuni
Date: Tue Jun 6 13:08:40 2006
New Revision: 28362
Modified:
pypy/dist/pypy/rpython/llinterp.py
pypy/dist/pypy/rpython/ootypesystem/ootype.py
pypy/dist/pypy/rpython/ootypesystem/rdict.py
pypy/dist/pypy/rpython/ootypesystem/test/test_oortype.py
pypy/dist/pypy/rpython/test/test_objectmodel.py
Log:
Basic r_dict ootypesystem support.
ootype.py has been refactored a bit: the ability of handling generic
types has been moved from BuiltinADTType to the new SpecializableType;
StaticMethod is now a SpecializableType, too.
Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py (original)
+++ pypy/dist/pypy/rpython/llinterp.py Tue Jun 6 13:08:40 2006
@@ -999,6 +999,33 @@
def op_runtimenew(self, class_):
return ootype.runtimenew(class_)
+ def _get_func_or_boundmethod(self, func, method_name):
+ if method_name is None:
+ # eq_func is a HalfConcreteWrapper wrapping a StaticMethod
+ self_arg = []
+ func_graph = func.concretize().value.graph
+ else:
+ # eq_func is an instance, we want to call 'method_name' on it
+ self_arg = [func]
+ func_graph = func._TYPE._methods[method_name].graph
+
+ def interp_func(*args):
+ graph_args = self_arg + list(args)
+ return self.llinterpreter.eval_graph(func_graph, args=graph_args)
+ return func_graph.name, interp_func
+
+ def op_oonewcustomdict(self, DICT, eq_func, eq_method_name, hash_func, hash_method_name):
+ eq_name, interp_eq = self._get_func_or_boundmethod(eq_func, eq_method_name)
+ EQ_FUNC = ootype.StaticMethod([DICT._KEYTYPE, DICT._KEYTYPE], ootype.Bool)
+ sm_eq = ootype.static_meth(EQ_FUNC, eq_name, _callable=interp_eq)
+
+ hash_name, interp_hash = self._get_func_or_boundmethod(hash_func, hash_method_name)
+ HASH_FUNC = ootype.StaticMethod([DICT._KEYTYPE], ootype.Signed)
+ sm_hash = ootype.static_meth(HASH_FUNC, hash_name, _callable=interp_hash)
+
+ # XXX: is it fine to have StaticMethod type for bound methods, too?
+ return ootype.newcustomdict(DICT, sm_eq, sm_hash)
+
def op_oosetfield(self, inst, name, value):
assert checkinst(inst)
assert isinstance(name, str)
Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/ootype.py (original)
+++ pypy/dist/pypy/rpython/ootypesystem/ootype.py Tue Jun 6 13:08:40 2006
@@ -2,6 +2,7 @@
from pypy.rpython.lltypesystem.lltype import Bool, Void, UniChar, typeOf, \
Primitive, isCompatibleType, enforce, saferecursive
from pypy.rpython.lltypesystem.lltype import frozendict, isCompatibleType
+from pypy.rpython import objectmodel
from pypy.tool.uid import uid
STATICNESS = True
@@ -159,8 +160,19 @@
all.update(self._fields)
return all
+class SpecializableType(OOType):
+ def _specialize_type(self, TYPE, generic_types):
+ if isinstance(TYPE, SpecializableType):
+ res = TYPE._specialize(generic_types)
+ else:
+ res = generic_types.get(TYPE, TYPE)
+ assert res is not None
+ return res
+
+ def _specialize(self, generic_types):
+ raise NotImplementedError
-class StaticMethod(OOType):
+class StaticMethod(SpecializableType):
__slots__ = ['_null']
def __init__(self, args, result):
@@ -174,14 +186,24 @@
def _defl(self):
return null(self)
-
+
+ def __repr__(self):
+ return "<StaticMethod(%s, %s)>" % (list(self.ARGS), self.RESULT)
+
+ def _specialize(self, generic_types):
+ ARGS = tuple([self._specialize_type(ARG, generic_types)
+ for ARG in self.ARGS])
+ RESULT = self._specialize_type(self.RESULT, generic_types)
+ return self.__class__(ARGS, RESULT)
+
+
class Meth(StaticMethod):
def __init__(self, args, result):
StaticMethod.__init__(self, args, result)
-class BuiltinType(OOType):
+class BuiltinType(SpecializableType):
def _example(self):
return new(self)
@@ -241,22 +263,11 @@
def _setup_methods(self, generic_types):
methods = {}
for name, meth in self._GENERIC_METHODS.iteritems():
- #args = [generic_types.get(arg, arg) for arg in meth.ARGS]
- #result = generic_types.get(meth.RESULT, meth.RESULT)
args = [self._specialize_type(arg, generic_types) for arg in meth.ARGS]
result = self._specialize_type(meth.RESULT, generic_types)
methods[name] = Meth(args, result)
self._METHODS = frozendict(methods)
- def _specialize_type(self, type_, generic_types):
- if isinstance(type_, BuiltinADTType):
- return type_._specialize(generic_types)
- else:
- return generic_types.get(type_, type_)
-
- def _specialize(self, generic_types):
- raise NotImplementedError
-
def _lookup(self, meth_name):
METH = self._METHODS.get(meth_name)
meth = None
@@ -434,11 +445,11 @@
return self._KEYTYPE is not None and self._VALUETYPE is not None
def _init_methods(self):
- generic_types = {
+ self._generic_types = frozendict({
self.SELFTYPE_T: self,
self.KEYTYPE_T: self._KEYTYPE,
self.VALUETYPE_T: self._VALUETYPE
- }
+ })
self._GENERIC_METHODS = frozendict({
"ll_length": Meth([], Signed),
@@ -450,7 +461,7 @@
"ll_get_items_iterator": Meth([], DictItemsIterator(self.KEYTYPE_T, self.VALUETYPE_T)),
})
- self._setup_methods(generic_types)
+ self._setup_methods(self._generic_types)
# NB: We are expecting Dicts of the same KEYTYPE, VALUETYPE to
# compare/hash equal. We don't redefine __eq__/__hash__ since the
@@ -487,6 +498,27 @@
self._KEYTYPE = KEYTYPE
self._VALUETYPE = VALUETYPE
self._init_methods()
+
+
+class CustomDict(Dict):
+ def __init__(self, KEYTYPE=None, VALUETYPE=None):
+ Dict.__init__(self, KEYTYPE, VALUETYPE)
+ self._null = _null_custom_dict(self)
+
+ if self._is_initialized():
+ self._init_methods()
+
+ def _init_methods(self):
+ Dict._init_methods(self)
+ EQ_FUNC = StaticMethod([self.KEYTYPE_T, self.KEYTYPE_T], Bool)
+ HASH_FUNC = StaticMethod([self.KEYTYPE_T], Signed)
+ self._GENERIC_METHODS['ll_set_functions'] = Meth([EQ_FUNC, HASH_FUNC], Void)
+ self._GENERIC_METHODS['ll_copy'] = Meth([], self.SELFTYPE_T)
+ self._setup_methods(self._generic_types)
+
+ def _get_interp_class(self):
+ return _custom_dict
+
class DictItemsIterator(BuiltinADTType):
SELFTYPE_T = object()
@@ -1033,6 +1065,26 @@
def __init__(self, DICT):
self.__dict__["_TYPE"] = DICT
+class _custom_dict(_dict):
+ def __init__(self, DICT):
+ self._TYPE = DICT
+ self._dict = 'DICT_NOT_CREATED_YET' # it's created inside ll_set_functions
+
+ def ll_set_functions(self, sm_eq, sm_hash):
+ "NOT_RPYTHON"
+ key_eq = sm_eq._callable
+ key_hash = sm_hash._callable
+ self._dict = objectmodel.r_dict(key_eq, key_hash)
+
+ def ll_copy(self):
+ "NOT_RPYTHON"
+ res = self.__class__(self._TYPE)
+ res._dict = self._dict.copy()
+ return res
+
+class _null_custom_dict(_null_mixin(_custom_dict), _custom_dict):
+ def __init__(self, DICT):
+ self.__dict__["_TYPE"] = DICT
class _dict_items_iterator(_builtin_type):
def __init__(self, ITER):
@@ -1108,6 +1160,11 @@
elif isinstance(TYPE, BuiltinType):
return TYPE._get_interp_class()(TYPE)
+def oonewcustomdict(DICT, ll_eq, ll_hash):
+ d = new(DICT)
+ d.ll_set_functions(ll_eq, ll_hash)
+ return d
+
def runtimenew(class_):
assert isinstance(class_, _class)
assert class_ is not nullruntimeclass
@@ -1207,6 +1264,9 @@
def setDictTypes(DICT, KEYTYPE, VALUETYPE):
return DICT._set_types(KEYTYPE, VALUETYPE)
+def setDictFunctions(DICT, ll_eq, ll_hash):
+ return DICT._set_functions(ll_eq, ll_hash)
+
def hasDictTypes(DICT):
return DICT._is_initialized()
Modified: pypy/dist/pypy/rpython/ootypesystem/rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/rdict.py (original)
+++ pypy/dist/pypy/rpython/ootypesystem/rdict.py Tue Jun 6 13:08:40 2006
@@ -32,10 +32,15 @@
else:
self.external_value_repr, self.value_repr = self.pickrepr(value_repr)
+ if self.custom_eq_hash:
+ Dict = ootype.CustomDict
+ else:
+ Dict = ootype.Dict
+
if already_computed:
- self.DICT = ootype.Dict(key_repr.lowleveltype, value_repr.lowleveltype)
+ self.DICT = Dict(key_repr.lowleveltype, value_repr.lowleveltype)
else:
- self.DICT = ootype.Dict()
+ self.DICT = Dict()
self.lowleveltype = self.DICT
self.dictkey = dictkey
@@ -58,6 +63,9 @@
ootype.setDictTypes(self.DICT, self.key_repr.lowleveltype,
self.value_repr.lowleveltype)
+ if self.custom_eq_hash:
+ self.r_rdict_eqfn, self.r_rdict_hashfn = self._custom_eq_hash_repr()
+
def send_message(self, hop, message, can_raise=False, v_args=None):
if v_args is None:
v_args = hop.inputargs(self, *hop.args_r[1:])
@@ -97,7 +105,11 @@
v_dict, = hop.inputargs(self)
cDICT = hop.inputconst(ootype.Void, self.lowleveltype)
hop.exception_cannot_occur()
- return hop.gendirectcall(ll_dict_copy, cDICT, v_dict)
+ if self.custom_eq_hash:
+ c_copy = hop.inputconst(ootype.Void, 'll_copy')
+ return hop.genop('oosend', [c_copy, v_dict], resulttype=hop.r_result.lowleveltype)
+ else:
+ return hop.gendirectcall(ll_dict_copy, cDICT, v_dict)
def rtype_method_update(self, hop):
v_dict1, v_dict2 = hop.inputargs(self, self)
@@ -193,7 +205,39 @@
def rtype_r_dict(hop):
- pass # TODO
+ r_dict = hop.r_result
+ if not r_dict.custom_eq_hash:
+ raise TyperError("r_dict() call does not return an r_dict instance")
+ v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn,
+ r_dict.r_rdict_hashfn)
+ cDICT = hop.inputconst(ootype.Void, r_dict.DICT)
+ hop.exception_cannot_occur()
+
+ if r_dict.r_rdict_eqfn.lowleveltype == ootype.Void:
+ c_eq_method_name = hop.inputconst(ootype.Void, None)
+ else:
+ # simulate a call to the method to get the exact variant name we need
+ s_pbc_eq = hop.args_s[0] # the instance which we take key_eq from
+ s_key = r_dict.dictkey.s_value
+ methodname = r_dict.r_rdict_eqfn._get_method_name("simple_call", s_pbc_eq, [s_key, s_key])
+ c_eq_method_name = hop.inputconst(ootype.Void, methodname)
+
+ if r_dict.r_rdict_hashfn.lowleveltype == ootype.Void:
+ c_hash_method_name = hop.inputconst(ootype.Void, None)
+ else:
+ # same as above
+ s_pbc_hash = hop.args_s[1] # the instance which we take key_hash from
+ s_key = r_dict.dictkey.s_value
+ methodname = r_dict.r_rdict_hashfn._get_method_name("simple_call", s_pbc_hash, [s_key])
+ c_hash_method_name = hop.inputconst(ootype.Void, methodname)
+
+ # the signature of oonewcustomdict is a bit complicated: v_eqfn
+ # can be either a function (with lowleveltype StaticMethod) or a
+ # bound method (with lowleveltype Instance). In the first case
+ # c_eq_method_name is None, in the latter it's a constant Void
+ # string containing the name of the method we want to call.
+ return hop.genop("oonewcustomdict", [cDICT, v_eqfn, c_eq_method_name, v_hashfn, c_hash_method_name],
+ resulttype=hop.r_result.lowleveltype)
def ll_newdict(DICT):
return ootype.new(DICT)
Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_oortype.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/test/test_oortype.py (original)
+++ pypy/dist/pypy/rpython/ootypesystem/test/test_oortype.py Tue Jun 6 13:08:40 2006
@@ -7,6 +7,7 @@
from pypy.objspace.flow import FlowObjSpace
from pypy.translator.translator import TranslationContext, graphof
from pypy.rpython.test.test_llinterp import interpret
+from pypy.rpython.objectmodel import r_dict
from pypy.rpython.ootypesystem import ooregistry # side effects
def gengraph(f, args=[], viewBefore=False, viewAfter=False):
@@ -245,3 +246,28 @@
assert interpret(oof, [True], type_system='ootype') == 2
assert interpret(oof, [False], type_system='ootype') == 1
+
+def test_r_dict():
+ def strange_key_eq(key1, key2):
+ return key1[0] == key2[0] # only the 1st character is relevant
+ def strange_key_hash(key):
+ return ord(key[0])
+ def oof():
+ d = r_dict(strange_key_eq, strange_key_hash)
+ d['x'] = 42
+ return d['x']
+ assert interpret(oof, [], type_system='ootype') == 42
+
+def test_r_dict_bm():
+ class Strange:
+ def key_eq(strange, key1, key2):
+ return key1[0] == key2[0] # only the 1st character is relevant
+ def key_hash(strange, key):
+ return ord(key[0])
+
+ def oof():
+ strange = Strange()
+ d = r_dict(strange.key_eq, strange.key_hash)
+ d['x'] = 42
+ return d['x']
+ assert interpret(oof, [], type_system='ootype') == 42
Modified: pypy/dist/pypy/rpython/test/test_objectmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_objectmodel.py (original)
+++ pypy/dist/pypy/rpython/test/test_objectmodel.py Tue Jun 6 13:08:40 2006
@@ -2,6 +2,7 @@
from pypy.rpython.objectmodel import *
from pypy.translator.translator import TranslationContext, graphof
from pypy.rpython.test.test_llinterp import interpret
+from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
def test_we_are_translated():
assert we_are_translated() == False
@@ -145,13 +146,15 @@
assert a.binding(graph.getargs()[0]).knowntype == Strange_def
assert a.binding(graph.getargs()[1]).knowntype == str
-def test_rtype_r_dict():
- res = interpret(test_r_dict, [])
- assert res is True
-
-def test_rtype_r_dict_bm():
- res = interpret(test_r_dict_bm, [])
- assert res is True
+class BaseTestObjectModel(BaseRtypingTest):
+
+ def test_rtype_r_dict(self):
+ res = self.interpret(test_r_dict, [])
+ assert res is True
+
+ def test_rtype_r_dict_bm(self):
+ res = self.interpret(test_r_dict_bm, [])
+ assert res is True
def test_rtype_constant_r_dicts():
d1 = r_dict(strange_key_eq, strange_key_hash)
@@ -288,3 +291,10 @@
s2 = Symbolic()
py.test.raises(TypeError, "s1 < s2")
py.test.raises(TypeError, "hash(s1)")
+
+
+class TestLLtype(BaseTestObjectModel, LLRtypeMixin):
+ pass
+
+class TestOOtype(BaseTestObjectModel, OORtypeMixin):
+ pass
More information about the Pypy-commit
mailing list