[pypy-svn] r24108 - in pypy/dist/pypy/translator/squeak: . test

nik at codespeak.net nik at codespeak.net
Wed Mar 8 15:40:17 CET 2006


Author: nik
Date: Wed Mar  8 15:40:16 2006
New Revision: 24108

Modified:
   pypy/dist/pypy/translator/squeak/gensqueak.py
   pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py
Log:
- generalize function/method calls with arguments and make them
  actually work
- factor out function/selector mapping and signature generation into
  class Selector
- make squeak tunneling for tests nicer and support arguments


Modified: pypy/dist/pypy/translator/squeak/gensqueak.py
==============================================================================
--- pypy/dist/pypy/translator/squeak/gensqueak.py	(original)
+++ pypy/dist/pypy/translator/squeak/gensqueak.py	Wed Mar  8 15:40:16 2006
@@ -7,21 +7,9 @@
 from pypy.translator.simplify import simplify_graph
 from pypy import conftest
 
-selectormap = {
-    'setitem:with:': 'at:put:',
-    'getitem:':      'at:',
-    'new':           'new',
-    'runtimenew':    'new',
-    'classof':       'class',
-    'sameAs':        'yourself',
-    'intAdd:':       '+',
-}
-
 def camel_case(str):
     words = str.split('_')
-    for i in range(1, len(words)):
-        words[i] = words[i].capitalize()
-    return ''.join(words)
+    return ''.join([words[0]] + [w.capitalize() for w in words[1:]])
 
 def arg_names(graph):
     #XXX need to handle more args, see 
@@ -31,28 +19,49 @@
     assert kwarg is None
     return names
 
-def selector(name, args):
-    s = name
-    if args:
-        s += '_'
-        for arg in args:
-            s += arg + ':'
-    return camel_case(s)
-
-def signature(sel, args):
-    if (':' in sel):
-        parts = []
-        names = sel.split(':')
-#       assert len(names) == len(args)
-        while args:
-            parts.append(names.pop(0) + ': ' + args.pop(0))
-        return ' '.join(parts)
-    elif not sel[0].isalnum():
-#       assert len(args) == 1
-        return "%s %s" %(sel, args[0])
-    else:
-#       assert len(args) == 0
-        return sel
+
+class Selector:
+
+    def __init__(self, function_name, arg_count):
+        self.parts = [camel_case(function_name)]
+        self.arg_count = arg_count
+        self.infix = False
+        if not self.parts[0].isalnum():
+            # Binary infix selector, e.g. "+"
+            assert arg_count == 1
+            self.infix = True
+        if arg_count > 1:
+            self.parts += ["with"] * (arg_count - 1)
+
+    def __str__(self):
+        if self.arg_count == 0 or self.infix:
+            return self.parts[0]
+        else:
+            return "%s:%s" % (self.parts[0],
+                    "".join([p + ":" for p in self.parts[1:]]))
+
+    def symbol(self):
+        return str(self)
+
+    def signature(self, arg_names):
+        assert len(arg_names) == self.arg_count
+        if self.arg_count == 0:
+            return self.parts[0]
+        elif self.infix:
+            return "%s %s" % (self.parts[0], arg_names[0])
+        else:
+            return " ".join(["%s: %s" % (p, a)
+                    for (p, a) in zip(self.parts, arg_names)])
+
+selectormap = {
+    #'setitem:with:': 'at:put:',
+    #'getitem:':      'at:',
+    'new':           Selector('new', 0),
+    'runtimenew':    Selector('new', 0),
+    'classof':       Selector('class', 0),
+    'sameAs':        Selector('yourself', 0), 
+    'intAdd:':       Selector('+', 1),
+}
 
 
 class LoopFinder:
@@ -148,11 +157,8 @@
         self.methods.append((inst, meth))
         print >> f, "!%s methodsFor: 'methods' stamp: 'pypy 1/1/2000 00:00'!" % (
             self.nameof_Instance(inst))
-        # XXX temporary hack, works only for method without arguments.
-        # Need to revisit selector and signature code.
-        print >> f, camel_case(meth)
         graph = inst._methods[meth].graph
-        self.gen_methodbody(graph, f, do_signature=False)
+        self.gen_methodbody(camel_case(meth), graph, f)
 
     def gen_setter(self, INSTANCE, field_name, f):
         if (INSTANCE, field_name) in self.methods:
@@ -170,17 +176,12 @@
             self.function_container = True
         print >> f, "!PyFunctions class methodsFor: 'functions'" \
                 " stamp: 'pypy 1/1/2000 00:00'!"
-        self.gen_methodbody(graph, f)
+        self.gen_methodbody(graph.name, graph, f)
 
-    def gen_methodbody(self, graph, f, do_signature=True):
-        if do_signature:
-            # XXX only works for functions without arguments
-            name = self.unique_name(graph.name.split('.')[-1])
-            print >> f, name
- 
-        renderer = MethodBodyRenderer(self, graph)
+    def gen_methodbody(self, method_name, graph, f):
+        renderer = MethodBodyRenderer(self, method_name, graph)
         for line in renderer.render():
-            print >> f, '       %s' % line
+            print >> f, line
         print >> f, '! !'
         print >> f
 
@@ -281,15 +282,21 @@
 
 class MethodBodyRenderer:
 
-    def __init__(self, gen, graph):
+    def __init__(self, gen, method_name, graph):
         self.gen = gen
+        # XXX need to handle names with packages somehow, probably in Selector
+        self.name = method_name.split('.')[-1]
         self.start = graph.startblock
         self.loops = LoopFinder(self.start).loops
 
     def render(self):
+        args = self.start.inputargs
+        sel = Selector(self.name, len(args))
+        yield sel.signature([self.expr(v) for v in args])
+ 
         # XXX should declare local variables here
         for line in self.render_block(self.start):
-            yield line
+            yield "    %s" % line
 
     def expr(self, v):
         if isinstance(v, Variable):
@@ -304,7 +311,9 @@
         if op.opname == "oosend":
             name = op.args[0].value
             receiver = args[1]
-            args = args[2:]
+            # For now, send nil as the explicit self. XXX will probably have
+            # to do something more intelligent.
+            args = ["nil"] + args[2:]
             self.gen.note_meth(op.args[1].concretetype, name)
         elif op.opname == "oogetfield":
             receiver = args[0]
@@ -320,14 +329,11 @@
             name = op.opname
             receiver = args[0]
             args = args[1:]
-        argnames = ['with'] * len(args)
-        if argnames:
-            argnames[0] = ''
-        sel = selector(name, argnames)
+        sel = Selector(name, len(args))
         if op.opname != "oosend":
-            sel = selectormap.get(sel, sel)
+            sel = selectormap.get(sel.symbol(), sel)
         return "%s := %s %s." \
-                % (self.expr(op.result), receiver, signature(sel, args))
+                % (self.expr(op.result), receiver, sel.signature(args))
 
     def render_return(self, args):
         if len(args) == 2:

Modified: pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py
==============================================================================
--- pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py	(original)
+++ pypy/dist/pypy/translator/squeak/test/test_squeaktrans.py	Wed Mar  8 15:40:16 2006
@@ -2,7 +2,7 @@
 import py
 from pypy.tool.udir import udir
 from pypy.translator.test import snippet
-from pypy.translator.squeak.gensqueak import GenSqueak
+from pypy.translator.squeak.gensqueak import GenSqueak, Selector
 from pypy.translator.translator import TranslationContext
 from pypy import conftest
 
@@ -42,11 +42,16 @@
 # and only works for posix systems. At some later point we'll
 # probably need a socket based solution for this.
 startup_script = """
-| stdout src function result |
+| stdout src selector result arguments arg i |
 src := Smalltalk getSystemAttribute: 3.
 FileStream fileIn: src.
-function := Smalltalk getSystemAttribute: 4.
-result := Compiler new evaluate: ('PyFunctions ' , function) in: nil to: nil.
+selector := (Smalltalk getSystemAttribute: 4) asSymbol.
+arguments := OrderedCollection new.
+i := 4.
+[(arg := Smalltalk getSystemAttribute: (i := i + 1)) notNil]
+    whileTrue: [arguments add: arg asInteger].
+
+result := (PyFunctions perform: selector withArguments: arguments asArray).
 stdout := StandardFileStream fileNamed: '/dev/stdout'.
 stdout nextPutAll: result asString.
 Smalltalk snapshot: false andQuit: true.
@@ -60,7 +65,8 @@
         f.write(startup_script)
         f.close()
 
-    def run_on_squeak(self, function):
+    def run_on_squeak(self, function, *args):
+        # NB: only integers arguments are supported currently
         try:
             import posix
         except ImportError:
@@ -72,13 +78,13 @@
         if os.getenv("SQUEAK_IMAGE") is None:
             py.test.skip("Squeak tests expect the SQUEAK_IMAGE environment "
                     "variable to point to an image.")
-        gen_squeak = build_sqfunc(function)
-        squeak_process = os.popen("squeak -headless -- %s %s %s"
+        arg_types = [type(arg) for arg in args]
+        gen_squeak = build_sqfunc(function, arg_types)
+        cmd = 'squeak -headless -- %s %s "%s" %s' \
                 % (self.startup_st, udir.join(gen_squeak.filename),
-                   # HACK XXX. Only works for functions without arguments.
-                   # Need to really rethink how selectors are assigned 
-                   # to functions.
-                   function.__name__))
+                   Selector(function.__name__, len(args)).symbol(),
+                   " ".join(['"%s"' % a for a in args]))
+        squeak_process = os.popen(cmd)
         result = squeak_process.read()
         assert squeak_process.close() is None # exit status was 0
         return result
@@ -96,3 +102,31 @@
             return A().m()
         assert self.run_on_squeak(simplemethod) == "42"
 
+    def test_argfunction(self):
+        def function(i, j=2):
+            return i + j
+        assert self.run_on_squeak(function, 1, 3) == "4"
+
+    def test_argmethod(self):
+        class A:
+            def m(self, i, j, h=2):
+                return i + j + h
+        def simplemethod(i):
+            return A().m(i, j=3)
+        assert self.run_on_squeak(simplemethod, 1) == "6"
+
+
+class TestSelector:
+
+    def test_selector(self):
+        assert Selector("bla_bla", 0).symbol() == "blaBla"
+        assert Selector("bla", 1).symbol() == "bla:"
+        assert Selector("bla_bla_bla", 3).symbol() == "blaBlaBla:with:with:"
+        assert Selector("+", 1).symbol() == "+"
+
+    def test_signature(self):
+        assert Selector("bla", 0).signature([]) == "bla"
+        assert Selector("bla", 1).signature(["v"]) == "bla: v"
+        assert Selector("bla", 2).signature(["v0", "v1"]) == "bla: v0 with: v1"
+        assert Selector("+", 1).signature(["v"]) == "+ v"
+



More information about the Pypy-commit mailing list