[pypy-svn] r9095 - in pypy/branch/dist-interpapp/pypy/interpreter: . test

hpk at codespeak.net hpk at codespeak.net
Fri Feb 11 00:24:07 CET 2005


Author: hpk
Date: Fri Feb 11 00:24:07 2005
New Revision: 9095

Modified:
   pypy/branch/dist-interpapp/pypy/interpreter/gateway.py
   pypy/branch/dist-interpapp/pypy/interpreter/test/test_appinterp.py
Log:

handle default arguments for applevel functions
defined via appdef().  This involves some (very localized) 
hacking at definition time but basically doesn't change 
the semantics of the still existing "space.appexec()". 
I.e. if you provide: 

    app = appdef("app(x, y=1)", """
        return x + y
    """) 

the 'app' hook will be compiled from generated sourcode
(more or less with pure string-juggling with some help of 
py.code.Source() :-) 

The resulting interplevel hook for the app-level definition 
(as seen by the translator) looks like this: 

    def app(space, w_x, w_y=None):
        if w_y is None:
            w_y = space.wrap(1)
        pypyco = PyCode(space)._from_code(newco)
        w_glob = space.newdict([])
        frame = pypyco.create_frame(space, w_glob)
        frame.setfastscope([w_x, w_y])
        return frame.run()

which looks pretty reasonable compared to gateway.app2interp 
and friends, doesn't it? 



Modified: pypy/branch/dist-interpapp/pypy/interpreter/gateway.py
==============================================================================
--- pypy/branch/dist-interpapp/pypy/interpreter/gateway.py	(original)
+++ pypy/branch/dist-interpapp/pypy/interpreter/gateway.py	Fri Feb 11 00:24:07 2005
@@ -645,18 +645,6 @@
 
 # and now for something completly different ... 
 #
-# the following function might just go away 
-#def preparesource(source): 
-#    from pypy.tool.pytestsupport import py  # aehem
-#    argdecl, source = source.split(':', 1)
-#    argdecl = argdecl.strip()
-#    if not argdecl.startswith('(') or not argdecl.endswith(')'): 
-#        raise SyntaxError("incorrect exec_with header\n%s" % source)
-#
-#    newco = peparesource_funcdecl(source, argdecl+'(') 
-#    argnames = argdecl[1:-1].strip().split(',')
-#    return newco, argnames 
-
 
 def preparesource(source, funcdecl): 
     from pypy.tool.pytestsupport import py 
@@ -669,24 +657,56 @@
     return d[funcdecl[:i]].func_code 
 
 def appdef(funcdecl, source): 
-    from pypy.tool.pytestsupport import py 
     from pypy.interpreter.pycode import PyCode
+    from pypy.tool.pytestsupport import py   
     newco = preparesource(source, funcdecl) 
     funcname, decl = funcdecl.split('(', 1)
     decl = decl.strip()[:-1] 
-    wargnames = ["w_%s" % x.strip() for x in decl[:-1].split(',')]
-    wdecl = ", ".join(wargnames) 
-    source = py.code.Source("""
+    wfuncdecl, wfastscope, defaulthandlingsource = specialargparse(decl) 
+    source = py.code.Source("""\
         def %s(space, %s):
+            # HERE we inject the defhandlingsource below 
             pypyco = PyCode(space)._from_code(newco) 
             w_glob = space.newdict([])
             frame = pypyco.create_frame(space, w_glob) 
             frame.setfastscope([%s])
             return frame.run() 
-    """ % (funcname, wdecl, wdecl))
+    """ % (funcname, wfuncdecl, wfastscope))
+    source.lines[1:2] = defaulthandlingsource.indent().lines 
+    print str(source)
     glob = {
         'newco' : newco, 
         'PyCode': PyCode, 
     }
     exec source.compile() in glob 
     return glob[funcname]
+
+def specialargparse(decl): 
+    from pypy.tool.pytestsupport import py  # for code generation 
+    wfuncargs = []
+    wfastnames = []
+    defaultargs = []
+    for name in decl.split(','): 
+        name = "w_%s" % name.strip()
+        if '=' in name: 
+            name, value = name.split('=')
+            wfastnames.append(name) 
+            defaultargs.append((name, value))
+            name += "=None" 
+        else: 
+            assert not defaultargs, "posarg follows defaultarg"
+            wfastnames.append(name) 
+        wfuncargs.append(name) 
+   
+    # now we generate some nice code for default arg checking
+    # (which does not imply that the code doing it is nice :-) 
+    defaulthandlingsource = py.code.Source()
+    while defaultargs: 
+        name, value = defaultargs.pop() 
+        defaulthandlingsource = defaulthandlingsource.putaround("""\
+            if %s is None: 
+                %s = space.wrap(%s)
+        """ % (name, name, value), "")
+    wfuncdecl = ", ".join(wfuncargs) 
+    wfastdecl = ", ".join(wfastnames)
+    return wfuncdecl, wfastdecl, defaulthandlingsource 

Modified: pypy/branch/dist-interpapp/pypy/interpreter/test/test_appinterp.py
==============================================================================
--- pypy/branch/dist-interpapp/pypy/interpreter/test/test_appinterp.py	(original)
+++ pypy/branch/dist-interpapp/pypy/interpreter/test/test_appinterp.py	Fri Feb 11 00:24:07 2005
@@ -31,3 +31,12 @@
     assert app.func_name == 'app'
     w_result = app(space, space.wrap(41), space.wrap(1))
     assert space.eq_w(w_result, space.wrap(42))
+
+def test_applevel_withdefault(space):
+    app = appdef("app(x,y=1)", """
+        return x + y
+    """)
+    assert app.func_name == 'app'
+    w_result = app(space, space.wrap(41)) 
+    assert space.eq_w(w_result, space.wrap(42))
+



More information about the Pypy-commit mailing list