[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