[pypy-svn] r14655 - in pypy/dist/pypy/rpython: . test

pedronis at codespeak.net pedronis at codespeak.net
Thu Jul 14 03:31:13 CEST 2005


Author: pedronis
Date: Thu Jul 14 03:31:12 2005
New Revision: 14655

Added:
   pypy/dist/pypy/rpython/callparse.py   (contents, props changed)
Modified:
   pypy/dist/pypy/rpython/rpbc.py
   pypy/dist/pypy/rpython/rtuple.py
   pypy/dist/pypy/rpython/test/test_rpbc.py
Log:
refactor to reuse argument.py logic in rtyping of simple_call and call_args.

Support for call_args for non-normalized cases, with tests.



Added: pypy/dist/pypy/rpython/callparse.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/callparse.py	Thu Jul 14 03:31:12 2005
@@ -0,0 +1,151 @@
+from pypy.interpreter.pycode import cpython_code_signature
+from pypy.interpreter.argument import Arguments, ArgErr
+from pypy.annotation import model as annmodel
+from pypy.rpython import rtuple
+
+class CallPatternTooComplex(Exception):
+    pass
+
+
+# for parsing call arguments
+class RPythonCallsSpace:
+    """Pseudo Object Space providing almost no real operation.
+    For the Arguments class: if it really needs other operations, it means
+    that the call pattern is too complex for R-Python.
+    """
+    def newtuple(self, items):
+        return NewTupleHolder(items)
+
+    def newdict(self, stuff):
+        raise CallPatternTooComplex, "'**' argument"
+
+    def unpackiterable(self, it, expected_length=None):
+        if it.is_tuple():
+            items = it.items()
+            if (expected_length is not None and
+                expected_length != len(items)):
+                raise ValueError
+            return items
+        raise CallPatternTooComplex, "'*' argument must be a tuple"
+
+
+def callparse(op, func, rinputs, hop):
+    space = RPythonCallsSpace()
+    def args_h(start):
+        return [VarHolder(i, hop.args_s[i]) for i in range(start, hop.nb_args)]
+    if op == "simple_call":
+        arguments =  Arguments(space, args_h(1))
+    elif op == "call_args":
+        arguments = Arguments.fromshape(space, hop.args_s[1].const, # shape
+                                        args_h(2))
+    # parse the arguments according to the function we are calling
+    signature = cpython_code_signature(func.func_code)
+    defs_h = []
+    if func.func_defaults:
+        for x in func.func_defaults:
+            defs_h.append(ConstHolder(x))
+    try:
+        holders = arguments.match_signature(signature, defs_h)
+    except ArgErr, e:
+        raise TypeError, "signature mismatch: %s" % e.getmsg(arguments, func.__name__)
+
+    assert len(holders) == len(rinputs), "argument parsing mismatch"
+    vlist = []
+    for h,r in zip(holders, rinputs):
+        v = h.emit(r, hop)
+        vlist.append(v)
+    return vlist
+
+
+class Holder(object):
+
+    def is_tuple(self):
+        return False
+
+    def emit(self, repr, hop):
+        try:
+            cache = self._cache
+        except AttributeError:
+            cache = self._cache = {}
+        try:
+            return cache[repr]
+        except KeyError:
+            v = self._emit(repr, hop)
+            cache[repr] = v
+            return v
+    
+
+class VarHolder(Holder):
+
+    def __init__(self, num, s_obj):
+        self.num = num
+        self.s_obj = s_obj
+
+    def is_tuple(self):
+        return isinstance(self.s_obj, annmodel.SomeTuple)
+
+    def items(self):
+        assert self.is_tuple()
+        n = len(self.s_obj.items)
+        return tuple([ItemHolder(self, i) for i in range(n)])
+        
+    def _emit(self, repr, hop):
+        return hop.inputarg(repr, arg=self.num)
+
+    def access(self, hop):
+        repr = hop.args_r[self.num]
+        return repr, self.emit(repr, hop)
+
+class ConstHolder(Holder):
+    def __init__(self, value):
+        self.value = value
+
+    def is_tuple(self):
+        return type(self.value) is tuple
+
+    def items(self):
+        assert self.is_tuple()
+        return self.value
+
+    def _emit(self, repr, hop):
+        return hop.inputconst(repr, self.value)
+
+
+class NewTupleHolder(Holder):
+    def __new__(cls, holders):
+        for h in holders:
+            if not isinstance(h, ItemHolder) or not h.holder == holders[0].holder:
+                break
+        else:
+            if 0 < len(holders) == len(holders[0].holder.items()):
+                return h[0].holder
+        inst = Holder.__new__(cls)
+        inst.holders = tuple(holders)
+        return inst
+
+    def is_tuple(self):
+        return True
+
+    def items(self):
+        return self.holders
+
+    def _emit(self, repr, hop):
+        assert isinstance(repr, rtuple.TupleRepr)
+        tupleitems_v = []
+        for h in self.holders:
+            v = h.emit(repr.items_r[len(tupleitems_v)], hop)
+            tupleitems_v.append(v)
+        vtuple = rtuple.newtuple(hop.llops, repr, tupleitems_v)
+        return vtuple
+
+
+class ItemHolder(Holder):
+    def __init__(self, holder, index):
+        self.holder = holder
+        self.index = index
+
+    def _emit(self, repr, hop):
+        index = self.index
+        r_tup, v_tuple = self.holder.access(hop)
+        v = r_tup.getitem(hop, v_tuple, index)
+        return hop.llops.convertvar(v, r_tup.items_r[index], repr)

Modified: pypy/dist/pypy/rpython/rpbc.py
==============================================================================
--- pypy/dist/pypy/rpython/rpbc.py	(original)
+++ pypy/dist/pypy/rpython/rpbc.py	Thu Jul 14 03:31:12 2005
@@ -12,6 +12,8 @@
 from pypy.rpython import rtuple
 from pypy.tool.sourcetools import has_varargs
 
+from pypy.rpython import callparse
+
 class __extend__(annmodel.SomePBC):
     def rtyper_makerepr(self, rtyper):
         # for now, we require that the PBC fits neatly into one of the Repr
@@ -340,7 +342,7 @@
         f, rinputs, rresult = self.function_signatures()[value]
         return f
 
-    def rtype_simple_call(self, hop):
+    def PREVIOUS_rtype_simple_call(self, hop):
         f, rinputs, rresult = self.function_signatures().itervalues().next()
         extravlist = []
         if getattr(f._obj.graph, 'normalized_for_calls', False):
@@ -386,15 +388,44 @@
         v = hop.genop('direct_call', vlist, resulttype = rresult)
         return hop.llops.convertvar(v, rresult, hop.r_result)
 
+    def rtype_simple_call(self, hop):
+        f, rinputs, rresult = self.function_signatures().itervalues().next()
+
+        if getattr(f._obj.graph, 'normalized_for_calls', False):
+            # should not have an argument count mismatch
+            assert len(rinputs) == hop.nb_args-1, "normalization bug"
+            vlist = hop.inputargs(self, *rinputs)
+        else:
+            # if not normalized, should be a call to a known function
+            assert len(self.function_signatures()) == 1, "normalization bug"
+            func, = self.function_signatures().keys()
+            vlist = [hop.inputarg(self, arg=0)]
+            vlist += callparse.callparse('simple_call', func, rinputs, hop)
+
+        return self.call(hop, f, vlist, rresult)
+
+    def call(self, hop, f, vlist, rresult):
+        if self.lowleveltype == Void:
+            assert len(self.function_signatures()) == 1
+            vlist[0] = hop.inputconst(typeOf(f), f)
+        v = hop.genop('direct_call', vlist, resulttype = rresult)
+        return hop.llops.convertvar(v, rresult, hop.r_result)
+
     def rtype_call_args(self, hop):
         f, rinputs, rresult = self.function_signatures().itervalues().next()
         # the function arguments may have been normalized by normalizecalls()
         # already
-        if not getattr(f._obj.graph, 'normalized_for_calls', False):
-            assert False, "XXX do stuff here"
-        vlist = hop.inputargs(self, Void, *rinputs)
-        return hop.genop('direct_call', vlist[:1] + vlist[2:],
-                         resulttype = rresult)
+        if getattr(f._obj.graph, 'normalized_for_calls', False):
+            vlist = hop.inputargs(self, Void, *rinputs)
+            vlist = vlist[:1] + vlist[2:]
+        else:
+            # if not normalized, should be a call to a known function
+            assert len(self.function_signatures()) == 1, "normalization bug"
+            func, = self.function_signatures().keys()
+            vlist = [hop.inputarg(self, arg=0)] 
+            vlist += callparse.callparse('call_args', func, rinputs, hop)
+
+        return self.call(hop, f, vlist, rresult)
 
 # ____________________________________________________________
 

Modified: pypy/dist/pypy/rpython/rtuple.py
==============================================================================
--- pypy/dist/pypy/rpython/rtuple.py	(original)
+++ pypy/dist/pypy/rpython/rtuple.py	Thu Jul 14 03:31:12 2005
@@ -70,6 +70,13 @@
             return Length1TupleIteratorRepr(self)
         raise TyperError("can only iterate over tuples of length 1 for now")
 
+    def getitem(self, llops, v_tuple, index):
+        name = self.fieldnames[index]
+        llresult = self.lltypes[index]
+        cname = inputconst(Void, name)
+        return llops.genop('getfield', [v_tuple, cname], resulttype = llresult)
+
+
 class __extend__(pairtype(TupleRepr, Repr)): 
     def rtype_contains((r_tup, r_item), hop): 
         v_tup = hop.args_v[0] 
@@ -98,10 +105,7 @@
         if not isinstance(v_index, Constant):
             raise TyperError("non-constant tuple index")
         index = v_index.value
-        name = r_tup.fieldnames[index]
-        llresult = r_tup.lltypes[index]
-        cname = hop.inputconst(Void, name)
-        return hop.genop('getfield', [v_tuple, cname], resulttype = llresult)
+        return r_tup.getitem(hop.llops, v_tuple, index)
 
 class __extend__(pairtype(TupleRepr, TupleRepr)):
     

Modified: pypy/dist/pypy/rpython/test/test_rpbc.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rpbc.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rpbc.py	Thu Jul 14 03:31:12 2005
@@ -484,4 +484,128 @@
     res = interpret(g, [1, 0])
     assert res.super.typeptr.name[0] == 'A'    
     
-        
+def test_call_keywords():
+    def g(a=1, b=2, c=3):
+        return 100*a+10*b+c
+
+    def f(i):
+        if i == 0:
+            return g(a=7)
+        elif i == 1:
+            return g(b=11)
+        elif i == 2:
+            return g(c=13)
+        elif i == 3:
+            return g(a=7, b=11)
+        elif i == 4:
+            return g(b=7, a=11)
+        elif i == 5:
+            return g(a=7, c=13)
+        elif i == 6:
+            return g(c=7, a=13)
+        elif i == 7:
+            return g(a=7,b=11,c=13)
+        elif i == 8:
+            return g(a=7,c=11,b=13)
+        elif i == 9:
+            return g(b=7,a=11,c=13)
+        else:
+            return g(b=7,c=11,a=13)
+
+    for i in range(11):
+        res = interpret(f, [i])
+        assert res == f(i)
+
+def test_call_star_and_keywords():
+    def g(a=1, b=2, c=3):
+        return 100*a+10*b+c
+
+    def f(i, x):
+        if x == 1:
+            j = 11
+        else:
+            j = 22
+        if i == 0:
+            return g(7)
+        elif i == 1:
+            return g(7,*(j,))
+        elif i == 2:
+            return g(7,*(11,j))
+        elif i == 3:
+            return g(a=7)
+        elif i == 4:
+            return g(b=7, *(j,))
+        elif i == 5:
+            return g(b=7, c=13, *(j,))
+        elif i == 6:
+            return g(c=7, b=13, *(j,))
+        elif i == 7:
+            return g(c=7,*(j,))
+        elif i == 8:
+            return g(c=7,*(11,j))
+        else:
+            return 0
+
+    for i in range(9):
+        for x in range(1):
+            res = interpret(f, [i, x])
+            assert res == f(i, x)
+
+def test_call_star_and_keywords_starargs():
+    def g(a=1, b=2, c=3, *rest):
+        return 1000*len(rest)+100*a+10*b+c
+
+    def f(i, x):
+        if x == 1:
+            j = 13
+        else:
+            j = 31
+        if i == 0:
+            return g()
+        elif i == 1:
+            return g(*(j,))
+        elif i == 2:
+            return g(*(13, j))
+        elif i == 3:
+            return g(*(13, j, 19))
+        elif i == 4:
+            return g(*(13, j, 19, 21))
+        elif i == 5:
+            return g(7)
+        elif i == 6:
+            return g(7, *(j,))
+        elif i == 7:
+            return g(7, *(13, j))
+        elif i == 8:
+            return g(7, *(13, 17, j))
+        elif i == 9:
+            return g(7, *(13, 17, j, 21))
+        elif i == 10:
+            return g(7, 9)
+        elif i == 11:
+            return g(7, 9, *(j,))
+        elif i == 12:
+            return g(7, 9, *(j, 17))
+        elif i == 13:
+            return g(7, 9, *(13, j, 19))
+        elif i == 14:
+            return g(7, 9, 11)
+        elif i == 15:
+            return g(7, 9, 11, *(j,))
+        elif i == 16:
+            return g(7, 9, 11, *(13, j))
+        elif i == 17:
+            return g(7, 9, 11, *(13, 17, j))
+        elif i == 18:
+            return g(7, 9, 11, 2)
+        elif i == 19:
+            return g(7, 9, 11, 2, *(j,))
+        elif i == 20:
+            return g(7, 9, 11, 2, *(13, j))
+        else:
+            return 0
+
+    for i in range(21):
+        for x in range(1):
+            res = interpret(f, [i, x])
+            assert res == f(i, x)



More information about the Pypy-commit mailing list