[pypy-svn] r76408 - in pypy/branch/call-method-kwarg/pypy: interpreter/astcompiler interpreter/test objspace/std objspace/std/test

agaynor at codespeak.net agaynor at codespeak.net
Fri Jul 30 20:17:58 CEST 2010


Author: agaynor
Date: Fri Jul 30 20:17:55 2010
New Revision: 76408

Modified:
   pypy/branch/call-method-kwarg/pypy/interpreter/astcompiler/codegen.py
   pypy/branch/call-method-kwarg/pypy/interpreter/test/test_compiler.py
   pypy/branch/call-method-kwarg/pypy/objspace/std/callmethod.py
   pypy/branch/call-method-kwarg/pypy/objspace/std/test/test_callmethod.py
Log:
Started implementing kwarg support for CALL_METHOD, the compiler test needs work.

Modified: pypy/branch/call-method-kwarg/pypy/interpreter/astcompiler/codegen.py
==============================================================================
--- pypy/branch/call-method-kwarg/pypy/interpreter/astcompiler/codegen.py	(original)
+++ pypy/branch/call-method-kwarg/pypy/interpreter/astcompiler/codegen.py	Fri Jul 30 20:17:55 2010
@@ -960,9 +960,12 @@
         elif call_type == 3:
             op = ops.CALL_FUNCTION_VAR_KW
         self.emit_op_arg(op, arg)
+    
+    def _call_has_no_star_args(self, call):
+        return not call.starargs and not call.kwargs
 
     def _call_has_simple_args(self, call):
-        return not call.starargs and not call.kwargs and not call.keywords
+        return self._call_has_no_star_args(call) and not call.keywords
 
     def _optimize_builtin_call(self, call):
         if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \
@@ -988,7 +991,7 @@
 
     def _optimize_method_call(self, call):
         if not self.space.config.objspace.opcodes.CALL_METHOD or \
-                not self._call_has_simple_args(call) or \
+                not self._call_has_no_star_args(call) or \
                 not isinstance(call.func, ast.Attribute):
             return False
         attr_lookup = call.func
@@ -1000,7 +1003,12 @@
             arg_count = len(call.args)
         else:
             arg_count = 0
-        self.emit_op_arg(ops.CALL_METHOD, arg_count)
+        if call.kwargs:
+            call.kwargs.walkabout(self)
+            kwarg_count = len(call.kwargs)
+        else:
+            kwarg_count = 0
+        self.emit_op_arg(ops.CALL_METHOD, (kwarg_count << 8) + arg_count)
         return True
 
     def _listcomp_generator(self, list_name, gens, gen_index, elt):

Modified: pypy/branch/call-method-kwarg/pypy/interpreter/test/test_compiler.py
==============================================================================
--- pypy/branch/call-method-kwarg/pypy/interpreter/test/test_compiler.py	(original)
+++ pypy/branch/call-method-kwarg/pypy/interpreter/test/test_compiler.py	Fri Jul 30 20:17:55 2010
@@ -848,13 +848,38 @@
         
         import StringIO, sys, dis
         s = StringIO.StringIO()
+        out = sys.stdout
         sys.stdout = s
         try:
             dis.dis(code)
         finally:
-            sys.stdout = sys.__stdout__
+            sys.stdout = out
         output = s.getvalue()
         assert "LOAD_GLOBAL" not in output
+    
+    def test_call_method_kwargs(self):
+        source = """def _f(a):
+            return a.f(a=a)
+        """
+        CALL_METHOD = self.space.config.objspace.opcodes.CALL_METHOD
+        self.space.config.objspace.opcodes.CALL_METHOD = True
+        try:
+            exec source
+        finally:
+            self.space.config.objspace.opcodes.CALL_METHOD = CALL_METHOD
+        code = _f.func_code
+        
+        import StringIO, sys, dis
+        s = StringIO.StringIO()
+        out = sys.stdout
+        sys.stdout = s
+        try:
+            dis.dis(code)
+        finally:
+            sys.stdout = out
+        output = s.getvalue()
+        assert "CALL_METHOD" in output
+            
 
 class AppTestExceptions:
     def test_indentation_error(self):

Modified: pypy/branch/call-method-kwarg/pypy/objspace/std/callmethod.py
==============================================================================
--- pypy/branch/call-method-kwarg/pypy/objspace/std/callmethod.py	(original)
+++ pypy/branch/call-method-kwarg/pypy/objspace/std/callmethod.py	Fri Jul 30 20:17:55 2010
@@ -56,16 +56,37 @@
     f.pushvalue(w_value)
     f.pushvalue(None)
 
-def CALL_METHOD(f, nargs, *ignored):
-    # 'nargs' is the argument count excluding the implicit 'self'
-    w_self = f.peekvalue(nargs)
-    w_callable = f.peekvalue(nargs + 1)
-    n = nargs + (w_self is not None)
+def CALL_METHOD(f, oparg, *ignored):
+    # opargs contains the arg, and kwarg count, excluding the implicit 'self'
+    n_args = oparg & 0xff
+    n_kwargs = (oparg >> 8) & 0xff
+    w_self = f.peekvalue(n_args + (2 * n_kwargs))
+    w_callable = f.peekvalue(n_args + (2 * n_kwargs) + 1)
+    
+    if n_kwargs:
+        keywords = [None] * n_kwargs
+        keywords_w = [None] * n_kwargs
+        while True:
+            n_kwargs -= 1
+            if n_kwargs < 0:
+                break
+            w_value = f.popvalue()
+            w_key = f.popvalue()
+            key = f.space.str_w(w_key)
+            keywords[n_keywords] = key
+            keywords_w[n_keywords] = w_value
+    else:
+        keywords = None
+        keywords_w = None
+    
+    arguments = f.popvalues(n_args + (w_self is not None))
+    args = f.argument_factory(arguments, keywords, keywords_w, None, None)
+    
     try:
-        w_result = f.space.call_valuestack(w_callable, n, f)
-        rstack.resume_point("CALL_METHOD", f, nargs, returns=w_result)
+        w_result = f.space.call_args(w_callable, args)
+        rstack.resume_point("CALL_METHOD", f, returns=w_result)
     finally:
-        f.dropvalues(nargs + 2)
+        f.dropvalues(1 + (w_self is None))
     f.pushvalue(w_result)
 
 

Modified: pypy/branch/call-method-kwarg/pypy/objspace/std/test/test_callmethod.py
==============================================================================
--- pypy/branch/call-method-kwarg/pypy/objspace/std/test/test_callmethod.py	(original)
+++ pypy/branch/call-method-kwarg/pypy/objspace/std/test/test_callmethod.py	Fri Jul 30 20:17:55 2010
@@ -106,6 +106,15 @@
             else:
                 raise Exception("did not raise?")
         """
+    
+    def test_kwargs(self):
+        exec """if 1:
+            class C(object):
+                def f(self, a):
+                    return a + 2
+            
+            assert C().f(a=3) == 5
+        """
 
 
 class AppTestCallMethodWithGetattributeShortcut(AppTestCallMethod):



More information about the Pypy-commit mailing list