[pypy-svn] r42600 - in pypy/dist/pypy/translator: . cli cli/test
antocuni at codespeak.net
antocuni at codespeak.net
Wed May 2 23:47:08 CEST 2007
Author: antocuni
Date: Wed May 2 23:47:07 2007
New Revision: 42600
Added:
pypy/dist/pypy/translator/cli/silverpython.py (contents, props changed)
pypy/dist/pypy/translator/cli/test/test_silverpython.py (contents, props changed)
Modified:
pypy/dist/pypy/translator/cli/cts.py
pypy/dist/pypy/translator/cli/entrypoint.py
pypy/dist/pypy/translator/cli/function.py
pypy/dist/pypy/translator/cli/gencli.py
pypy/dist/pypy/translator/cli/rte.py
pypy/dist/pypy/translator/cli/test/runtest.py
pypy/dist/pypy/translator/driver.py
Log:
- add support to driver for building libraries instead of standalone
executables (i.e., allowing more than one entry-point)
- first steps to write a gencli's frontend which allow to compile a
rpython module to a .NET dll; the draft name is SilveRPython,
suggestions are welcome :-)
Modified: pypy/dist/pypy/translator/cli/cts.py
==============================================================================
--- pypy/dist/pypy/translator/cli/cts.py (original)
+++ pypy/dist/pypy/translator/cli/cts.py Wed May 2 23:47:07 2007
@@ -196,6 +196,9 @@
ret_type, ret_var = self.llvar_to_cts(graph.getreturnvar())
func_name = func_name or graph.name
func_name = self.escape_name(func_name)
+ namespace = getattr(graph.func, '_namespace_', None)
+ if namespace:
+ func_name = '%s::%s' % (namespace, func_name)
args = [arg for arg in graph.getargs() if arg.concretetype is not ootype.Void]
if is_method:
Modified: pypy/dist/pypy/translator/cli/entrypoint.py
==============================================================================
--- pypy/dist/pypy/translator/cli/entrypoint.py (original)
+++ pypy/dist/pypy/translator/cli/entrypoint.py Wed May 2 23:47:07 2007
@@ -19,6 +19,12 @@
self.db = db
self.cts = CTS(db)
+ def ilasm_flags(self):
+ return []
+
+ def output_filename(self, il_filename):
+ return il_filename.replace('.il', '.exe')
+
class StandaloneEntryPoint(BaseEntryPoint):
"""
This class produces a 'main' method that converts the argv in a
@@ -59,3 +65,21 @@
ilasm.opcode('ret')
ilasm.end_function()
self.db.pending_function(self.graph)
+
+class DllEntryPoint(BaseEntryPoint):
+ def __init__(self, name, graphs):
+ self.name = name
+ self.graphs = graphs
+
+ def get_name(self):
+ return self.name
+
+ def ilasm_flags(self):
+ return ['/dll']
+
+ def output_filename(self, il_filename):
+ return il_filename.replace('.il', '.dll')
+
+ def render(self, ilasm):
+ for graph in self.graphs:
+ self.db.pending_function(graph)
Modified: pypy/dist/pypy/translator/cli/function.py
==============================================================================
--- pypy/dist/pypy/translator/cli/function.py (original)
+++ pypy/dist/pypy/translator/cli/function.py Wed May 2 23:47:07 2007
@@ -173,7 +173,18 @@
OOFunction.__init__(self, *args, **kwargs)
self._set_args()
self._set_locals()
-
+ namespace = getattr(self.graph.func, '_namespace_', None)
+ str
+ if namespace:
+ if '.' in namespace:
+ self.namespace, self.classname = namespace.rsplit('.', 1)
+ else:
+ self.namespace = None
+ self.classname = namespace
+ else:
+ self.namespace = None
+ self.classname = None
+
def _create_generator(self, ilasm):
return self # Function implements the Generator interface
@@ -192,11 +203,20 @@
else:
args = self.args
meth_type = 'static'
- self.ilasm.begin_function(self.name, args, returntype, self.is_entrypoint, meth_type)
+
+ if self.namespace:
+ self.ilasm.begin_namespace(self.namespace)
+ if self.classname:
+ self.ilasm.begin_class(self.classname)
+ self.ilasm.begin_function(self.name, args, returntype, self.is_entrypoint, meth_type)
self.ilasm.locals(self.locals)
def end_render(self):
self.ilasm.end_function()
+ if self.classname:
+ self.ilasm.end_class()
+ if self.namespace:
+ self.ilasm.end_namespace()
def set_label(self, label):
self.ilasm.label(label)
Modified: pypy/dist/pypy/translator/cli/gencli.py
==============================================================================
--- pypy/dist/pypy/translator/cli/gencli.py (original)
+++ pypy/dist/pypy/translator/cli/gencli.py Wed May 2 23:47:07 2007
@@ -87,20 +87,20 @@
ilasm = SDK.ilasm()
tmpfile = self.tmpfile.strpath
- self._exec_helper(ilasm, tmpfile,
+ self._exec_helper(ilasm, [tmpfile]+self.entrypoint.ilasm_flags(),
'ilasm failed to assemble (%s):\n%s\n%s',
timeout = 900)
# Mono's ilasm occasionally deadlocks. We set a timer to avoid
# blocking automated test runs forever.
- exefile = tmpfile.replace('.il', '.exe')
+ self.outfile = self.entrypoint.output_filename(tmpfile)
if getoption('verify'):
peverify = SDK.peverify()
- self._exec_helper(peverify, exefile, 'peverify failed to verify (%s):\n%s\n%s')
- return exefile
+ self._exec_helper(peverify, [outfile], 'peverify failed to verify (%s):\n%s\n%s')
+ return self.outfile
- def _exec_helper(self, helper, filename, msg, timeout=None):
- args = [helper, filename]
+ def _exec_helper(self, helper, args, msg, timeout=None):
+ args = [helper] + args
if timeout and not sys.platform.startswith('win'):
import os
from pypy.tool import autopath
@@ -109,5 +109,5 @@
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
retval = proc.wait()
- assert retval == 0, msg % (filename, stdout, stderr)
+ assert retval == 0, msg % (args[0], stdout, stderr)
Modified: pypy/dist/pypy/translator/cli/rte.py
==============================================================================
--- pypy/dist/pypy/translator/cli/rte.py (original)
+++ pypy/dist/pypy/translator/cli/rte.py Wed May 2 23:47:07 2007
@@ -11,14 +11,9 @@
from py.compat import subprocess
from pypy.translator.cli.sdk import SDK
from pypy.tool.ansi_print import ansi_log
-log = py.log.Producer("cli")
-py.log.setconsumer("cli", ansi_log)
+log = py.log.Producer("cli")
+py.log.setconsumer("cli", ansi_log)
-SRC_DIR = os.path.join(os.path.dirname(__file__), 'src/')
-
-def _filename(name, path=None):
- rel_path = os.path.join(SRC_DIR, name)
- return os.path.abspath(rel_path)
class Target:
SOURCES = []
@@ -26,6 +21,12 @@
ALIAS = None
FLAGS = []
DEPENDENCIES = []
+ SRC_DIR = os.path.join(os.path.dirname(__file__), 'src/')
+
+ def _filename(cls, name, path=None):
+ rel_path = os.path.join(cls.SRC_DIR, name)
+ return os.path.abspath(rel_path)
+ _filename = classmethod(_filename)
def get_COMPILER(cls):
return SDK.csc()
@@ -34,9 +35,9 @@
def get(cls):
for dep in cls.DEPENDENCIES:
dep.get()
- sources = [_filename(src) for src in cls.SOURCES]
- out = _filename(cls.OUTPUT)
- alias = _filename(cls.ALIAS or cls.OUTPUT)
+ sources = [cls._filename(src) for src in cls.SOURCES]
+ out = cls._filename(cls.OUTPUT)
+ alias = cls._filename(cls.ALIAS or cls.OUTPUT)
recompile = True
try:
src_mtime = max([os.stat(src).st_mtime for src in sources])
@@ -54,14 +55,14 @@
def compile(cls, sources, out):
log.red("Compiling %s" % (cls.ALIAS or cls.OUTPUT))
oldcwd = os.getcwd()
- os.chdir(SRC_DIR)
+ os.chdir(cls.SRC_DIR)
compiler = subprocess.Popen([cls.get_COMPILER()] + cls.FLAGS + ['/out:%s' % out] + sources,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = compiler.communicate()
retval = compiler.wait()
assert retval == 0, 'Failed to compile %s: the compiler said:\n %s' % (cls.OUTPUT, stderr)
if cls.ALIAS is not None:
- alias = _filename(cls.ALIAS)
+ alias = cls._filename(cls.ALIAS)
shutil.copy(out, alias)
os.chdir(oldcwd)
Added: pypy/dist/pypy/translator/cli/silverpython.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/cli/silverpython.py Wed May 2 23:47:07 2007
@@ -0,0 +1,44 @@
+from pypy.translator.driver import TranslationDriver
+from pypy.translator.cli.entrypoint import DllEntryPoint
+
+class DllDef:
+ def __init__(self, name, namespace, functions=[], classes=[]):
+ self.name = name
+ self.namespace = namespace
+ self.functions = functions # [(function, annotation), ...]
+
+ def add_function(self, func, inputtypes):
+ self.functions.append((func, inputtypes))
+
+ def get_entrypoint(self, bk):
+ graphs = [bk.getdesc(f).cachedgraph(None) for f, _ in self.functions]
+ return DllEntryPoint(self.name, graphs)
+
+ def compile(self):
+ # add all functions to the appropriate namespace
+ for func, _ in self.functions:
+ if not hasattr(func, '_namespace_'):
+ func._namespace_ = self.namespace
+ driver = TranslationDriver()
+ driver.setup_library(self)
+ driver.proceed(['compile_cli'])
+ return driver
+
+
+class MyClass:
+ def __init__(self, x):
+ self.x = x
+
+ def foo(self):
+ return self.x
+
+def main():
+ dll = DllDef('mylibrary', 'foo', [], [
+ (MyClass, [int]),
+ ])
+ driver = dll.compile()
+ driver.copy_cli_dll()
+
+
+if __name__ == '__main__':
+ main()
Modified: pypy/dist/pypy/translator/cli/test/runtest.py
==============================================================================
--- pypy/dist/pypy/translator/cli/test/runtest.py (original)
+++ pypy/dist/pypy/translator/cli/test/runtest.py Wed May 2 23:47:07 2007
@@ -137,15 +137,15 @@
assert False, 'Input type %s not supported' % arg_type
-def compile_function(func, annotation=[], graph=None, backend_opt={}):
+def compile_function(func, annotation=[], graph=None, backendopt=True):
olddefs = patch()
- gen = _build_gen(func, annotation, graph, backend_opt)
+ gen = _build_gen(func, annotation, graph, backendopt)
gen.generate_source()
exe_name = gen.build_exe()
unpatch(*olddefs) # restore original values
return CliFunctionWrapper(exe_name)
-def _build_gen(func, annotation, graph=None, backend_opt={}):
+def _build_gen(func, annotation, graph=None, backendopt=True):
try:
func = func.im_func
except AttributeError:
@@ -165,8 +165,9 @@
t.view()
t.buildrtyper(type_system="ootype").specialize()
- check_virtual_methods(ootype.ROOT)
- backend_optimizations(t)
+ if backendopt:
+ check_virtual_methods(ootype.ROOT)
+ backend_optimizations(t)
main_graph = t.graphs[0]
@@ -242,13 +243,13 @@
self._ann = None
self._cli_func = None
- def _compile(self, fn, args, ann=None):
+ def _compile(self, fn, args, ann=None, backendopt=True):
if ann is None:
ann = [lltype_to_annotation(typeOf(x)) for x in args]
if self._func is fn and self._ann == ann:
return self._cli_func
else:
- self._cli_func = compile_function(fn, ann)
+ self._cli_func = compile_function(fn, ann, backendopt=backendopt)
self._func = fn
self._ann = ann
return self._cli_func
@@ -261,8 +262,8 @@
if platform.processor() == 'powerpc':
py.test.skip('PowerPC --> %s' % reason)
- def interpret(self, fn, args, annotation=None):
- f = self._compile(fn, args, annotation)
+ def interpret(self, fn, args, annotation=None, backendopt=True):
+ f = self._compile(fn, args, annotation, backendopt)
res = f(*args)
if isinstance(res, ExceptionWrapper):
raise res
Added: pypy/dist/pypy/translator/cli/test/test_silverpython.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/cli/test/test_silverpython.py Wed May 2 23:47:07 2007
@@ -0,0 +1,58 @@
+from pypy.tool import udir
+from pypy.translator.cli.rte import Target
+from pypy.translator.cli.silverpython import DllDef
+from pypy.translator.cli.test.runtest import CliFunctionWrapper, CliTest
+
+TEMPLATE = """
+using System;
+class SilveRPytonTest {
+ public static void Main() {
+ %s
+ }
+}
+"""
+
+class TestSilveRPython(CliTest):
+
+ def _csharp(self, reference, source):
+ tmpfile = udir.udir.join('tmp.cs')
+ tmpfile.write(TEMPLATE % source)
+ if reference is None:
+ flags = []
+ else:
+ flags = ['/r:%s' % reference]
+
+ class MyTarget(Target):
+ SOURCES = [str(tmpfile)]
+ FLAGS = flags
+ OUTPUT = 'tmp.exe'
+ SRC_DIR = str(udir.udir)
+
+ func = CliFunctionWrapper(MyTarget.get())
+ return func()
+
+
+ def test_compilation(self):
+ res = self._csharp(None, 'Console.WriteLine(42);')
+ assert res == 42
+
+ def test_func_namespace(self):
+ def foo(x):
+ return x+1
+ def bar(x):
+ return foo(x)
+ foo._namespace_ = 'MyNamespace.MyClass'
+ bar._namespace_ = 'MyClass'
+ res = self.interpret(bar, [41], backendopt=False)
+ assert res == 42
+
+ def test_simple_functions(self):
+ def foo(x):
+ return x+1
+ def bar(x):
+ return x*2
+ dll = DllDef('test', 'Test', [(foo, [int]),
+ (bar, [int])])
+ dll.compile()
+ res = self._csharp('test', 'Console.WriteLine("{0}, {1}", Test.foo(42), Test.bar(42));')
+ assert res == (43, 84)
Modified: pypy/dist/pypy/translator/driver.py
==============================================================================
--- pypy/dist/pypy/translator/driver.py (original)
+++ pypy/dist/pypy/translator/driver.py Wed May 2 23:47:07 2007
@@ -209,9 +209,14 @@
self.entry_point = entry_point
self.translator = translator
+ self.libdef = None
self.translator.driver_instrument_result = self.instrument_result
+ def setup_library(self, libdef, policy=None, extra={}, empty_translator=None):
+ self.setup(None, None, policy, extra, empty_translator)
+ self.libdef = libdef
+
def instrument_result(self, args):
backend, ts = self.get_backend_and_type_system()
if backend != 'c' or sys.platform == 'win32':
@@ -275,16 +280,22 @@
annmodel.DEBUG = self.config.translation.debug
annotator = translator.buildannotator(policy=policy)
-
- s = annotator.build_types(self.entry_point, self.inputtypes)
-
- self.sanity_check_annotation()
- if self.standalone and s.knowntype != int:
- raise Exception("stand-alone program entry point must return an "
- "int (and not, e.g., None or always raise an "
- "exception).")
+
+ if self.entry_point:
+ s = annotator.build_types(self.entry_point, self.inputtypes)
+
+ self.sanity_check_annotation()
+ if self.standalone and s.knowntype != int:
+ raise Exception("stand-alone program entry point must return an "
+ "int (and not, e.g., None or always raise an "
+ "exception).")
+ return s
+ else:
+ assert self.libdef is not None
+ for func, inputtypes in self.libdef.functions:
+ annotator.build_types(func, inputtypes)
+ self.sanity_check_annotation()
annotator.simplify()
- return s
#
task_annotate = taskdef(task_annotate, [], "Annotating&simplifying")
@@ -619,9 +630,16 @@
from pypy.translator.cli.gencli import GenCli
from pypy.translator.cli.entrypoint import get_entrypoint
- entry_point_graph = self.translator.graphs[0]
- self.gen = GenCli(udir, self.translator, get_entrypoint(entry_point_graph),
- config=self.config)
+ if self.entry_point is not None: # executable mode
+ entry_point_graph = self.translator.graphs[0]
+ entry_point = get_entrypoint(entry_point_graph)
+ else:
+ # library mode
+ assert self.libdef is not None
+ bk = self.translator.annotator.bookkeeper
+ entry_point = self.libdef.get_entrypoint(bk)
+
+ self.gen = GenCli(udir, self.translator, entry_point, config=self.config)
filename = self.gen.generate_source()
self.log.info("Wrote %s" % (filename,))
task_source_cli = taskdef(task_source_cli, ["?" + OOBACKENDOPT, OOTYPE],
@@ -667,6 +685,15 @@
f.close()
os.chmod(newexename, 0755)
+ def copy_cli_dll(self):
+ import os.path
+ import shutil
+ dllname = self.gen.outfile
+ usession_path, dll_name = os.path.split(dllname)
+ pypylib_dll = os.path.join(usession_path, 'pypylib.dll')
+ shutil.copy(dllname, '.')
+ shutil.copy(pypylib_dll, '.')
+
def task_run_cli(self):
pass
task_run_cli = taskdef(task_run_cli, ['compile_cli'],
More information about the pypy-svn
mailing list