[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