summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-01-05 09:16:29 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-01-05 09:16:29 +0000
commitaea45d997631d931d0b34dce129707027cb5040a (patch)
tree4b710bc328f0b3644e0a429787cc524fe37501f3
parentbedb446cefc80f6d0ae5ba93f7adae8f408e3710 (diff)
Integrated python 2.6 interpreter in modules/python. The integration is much simpler than before as it now uses kernel dynamic values and lambda functions to call from/to python.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@895953 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--sca-cpp/trunk/configure.ac21
-rw-r--r--sca-cpp/trunk/modules/python/Makefile.am31
-rw-r--r--sca-cpp/trunk/modules/python/driver.hpp85
-rw-r--r--sca-cpp/trunk/modules/python/eval.hpp286
-rw-r--r--sca-cpp/trunk/modules/python/io.hpp167
-rw-r--r--sca-cpp/trunk/modules/python/python-shell.cpp40
-rw-r--r--sca-cpp/trunk/modules/python/python-test.cpp135
-rw-r--r--sca-cpp/trunk/modules/python/tuscany-sca-1.1-implementation-python.xsd43
8 files changed, 806 insertions, 2 deletions
diff --git a/sca-cpp/trunk/configure.ac b/sca-cpp/trunk/configure.ac
index 99650734c3..95d984396c 100644
--- a/sca-cpp/trunk/configure.ac
+++ b/sca-cpp/trunk/configure.ac
@@ -124,6 +124,20 @@ AC_ARG_WITH([httpd], [AC_HELP_STRING([--with-httpd=PATH], [path to installed htt
])
AC_SUBST(HTTPD_INCLUDE)
+# Configure PYTHON_INCLUDE and PYTHON_LIB
+AC_MSG_CHECKING([for python])
+AC_ARG_WITH([curl], [AC_HELP_STRING([--with-python=PATH], [path to installed python 2.6 [default=/usr]])], [
+ PYTHON_INCLUDE="${withval}/include"
+ PYTHON_LIB="${withval}/lib"
+ AC_MSG_RESULT("${withval}")
+], [
+ PYTHON_INCLUDE="/usr/include"
+ PYTHON_LIB="/usr/lib"
+ AC_MSG_RESULT(/usr)
+])
+AC_SUBST(PYTHON_INCLUDE)
+AC_SUBST(PYTHON_LIB)
+
# Checks for libraries.
original_LIBS="${LIBS}"
AC_MSG_NOTICE([checking for libraries])
@@ -138,6 +152,8 @@ AC_CHECK_LIB([xml2], [xmlInitParser], [], [AC_MSG_ERROR([couldn't find a suitabl
LIBS="-L${APR_LIB} ${original_LIBS}"
AC_CHECK_LIB([apr-1], [apr_pool_initialize], [], [AC_MSG_ERROR([couldn't find a suitable libapr-1, use --with-apr=PATH])])
AC_CHECK_LIB([aprutil-1], [apr_memcache_replace], [], [AC_MSG_ERROR([couldn't find a suitable libaprutil-1, use --with-apr=PATH])])
+LIBS="-L${PYTHON_LIB} ${original_LIBS}"
+AC_CHECK_LIB([python2.6], [Py_Initialize], [], [AC_MSG_ERROR([couldn't find a suitable libpython2.6, use --with-python=PATH])])
LIBS="${original_LIBS}"
# Checks for header files.
@@ -175,7 +191,7 @@ AC_ARG_ENABLE(maintainer-mode, [AS_HELP_STRING([--enable-maintainer-mode], [comp
esac ],
[ AC_MSG_RESULT(no)])
if test "${want_maintainer_mode}" = "true"; then
- cxxflags="${cxxflags} -D_DEBUG -O0 -g3 -Werror -Wall -Wextra -Wno-ignored-qualifiers -Winit-self -Wmissing-include-dirs -Wcast-qual -Wcast-align -Wwrite-strings -Wpointer-arith -Wconversion -Waddress -Wlogical-op -Wredundant-decls -std=c++0x -fmessage-length=0"
+ cxxflags="${cxxflags} -D_DEBUG -O0 -ggdb -g3 -Werror -Wall -Wextra -Wno-ignored-qualifiers -Winit-self -Wmissing-include-dirs -Wcast-qual -Wcast-align -Wwrite-strings -Wpointer-arith -Wconversion -Waddress -Wlogical-op -Wredundant-decls -std=c++0x -fmessage-length=0"
ldflags="${ldflags} -pg"
else
cxxflags="${cxxflags} -O3 -std=c++0x -fmessage-length=0"
@@ -256,9 +272,10 @@ AC_CONFIG_FILES([Makefile
kernel/Makefile
modules/Makefile
modules/atom/Makefile
- modules/eval/Makefile
+ modules/scheme/Makefile
modules/http/Makefile
modules/json/Makefile
+ modules/python/Makefile
modules/scdl/Makefile
modules/server/Makefile
components/Makefile
diff --git a/sca-cpp/trunk/modules/python/Makefile.am b/sca-cpp/trunk/modules/python/Makefile.am
new file mode 100644
index 0000000000..d61ca5bed3
--- /dev/null
+++ b/sca-cpp/trunk/modules/python/Makefile.am
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+noinst_PROGRAMS = python-test python-shell
+
+datadir=$(prefix)/modules/python
+nobase_data_DATA = *.xsd
+
+INCLUDES = -I. -I$(top_builddir)/kernel -I${LIBXML2_INCLUDE} -I${APR_INCLUDE} -I${PYTHON_INCLUDE}
+
+python_test_SOURCES = python-test.cpp
+python_test_LDADD = -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -L${PYTHON_LIB} -lpython2.6
+
+python_shell_SOURCES = python-shell.cpp
+python_shell_LDADD = -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -L${PYTHON_LIB} -lpython2.6
+
+TESTS = python-test
diff --git a/sca-cpp/trunk/modules/python/driver.hpp b/sca-cpp/trunk/modules/python/driver.hpp
new file mode 100644
index 0000000000..a7139889b9
--- /dev/null
+++ b/sca-cpp/trunk/modules/python/driver.hpp
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_python_pydriver_hpp
+#define tuscany_python_pydriver_hpp
+
+/**
+ * Python evaluator main driver loop.
+ */
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "monad.hpp"
+#include "eval.hpp"
+
+namespace tuscany {
+namespace python {
+
+const string evalOutputPrompt("; ");
+const string evalInputPrompt("=> ");
+
+const bool promptForInput(const string& str, ostream& out) {
+ out << endl << endl << str;
+ return true;
+}
+
+const bool announceOutput(const string str, ostream& out) {
+ out << endl << str;
+ return true;
+}
+
+const bool userPrint(const value val, ostream& out) {
+ writeValue(val, out);
+ return true;
+}
+
+const value evalDriverLoop(PyObject* script, istream& in, ostream& out, const gc_pool& pool) {
+ promptForInput(evalInputPrompt, out);
+ value input = readValue(in);
+ if (isNil(input))
+ return input;
+ const value output = evalScript(input, script, pool);
+ announceOutput(evalOutputPrompt, out);
+ userPrint(output, out);
+ return evalDriverLoop(script, in, out, pool);
+}
+
+const bool evalDriverRun(istream& in, ostream& out, const gc_pool& pool) {
+ setupDisplay(out);
+ evalDriverLoop(builtin(pythonRuntime), in, out, pool);
+ return true;
+}
+
+const bool evalDriverRun(const char* path, istream& in, ostream& out, const gc_pool& pool) {
+ setupDisplay(out);
+ ifstream is(path);
+ failable<PyObject*> script = readScript(path, is);
+ if (!hasContent(script))
+ return true;
+ evalDriverLoop(content(script), in, out, pool);
+ Py_DECREF(content(script));
+ return true;
+}
+
+}
+}
+#endif /* tuscany_scheme_pydriver_hpp */
diff --git a/sca-cpp/trunk/modules/python/eval.hpp b/sca-cpp/trunk/modules/python/eval.hpp
new file mode 100644
index 0000000000..8d709731a6
--- /dev/null
+++ b/sca-cpp/trunk/modules/python/eval.hpp
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_python_pyeval_hpp
+#define tuscany_python_pyeval_hpp
+
+/**
+ * Python script evaluation logic.
+ */
+#include <python2.6/Python.h>
+
+#include "list.hpp"
+#include "value.hpp"
+#include "io.hpp"
+
+namespace tuscany {
+namespace python {
+
+/**
+ * Initialize the Python runtime.
+ */
+class PythonRuntime {
+public:
+ PythonRuntime() {
+ Py_Initialize();
+
+ // Import the builtin module
+ PyObject* p = PyString_FromString("__builtin__");
+ builtin = PyImport_Import(p);
+ Py_DECREF(p);
+
+ setupIO();
+ }
+
+ ~PythonRuntime() {
+ Py_DECREF(builtin);
+ }
+
+private:
+ friend PyObject* builtin(const PythonRuntime& r);
+
+ PyObject* builtin;
+
+} pythonRuntime;
+
+PyObject* builtin(const PythonRuntime& r) {
+ return r.builtin;
+}
+
+/**
+ * Declare conversion functions.
+ */
+PyObject* valueToPyObject(const value& v);
+const value pyObjectToValue(PyObject *o);
+PyObject* valuesToPyTuple(const list<value>& v);
+const list<value> pyTupleToValues(PyObject* o);
+
+/**
+ * Callable python type used to represent a lambda expression.
+ */
+typedef struct {
+ PyObject_HEAD
+ lambda<value(const list<value>&)> func;
+} pyLambda;
+
+void pyLambda_dealloc(PyObject* self) {
+ PyMem_DEL(self);
+}
+
+PyObject* pyLambda_call(PyObject* self, PyObject* args, unused PyObject* kwds) {
+ const pyLambda* pyl = (pyLambda*)self;
+ const value result = pyl->func(pyTupleToValues(args));
+ Py_DECREF(args);
+ PyObject *pyr = valueToPyObject(result);
+ return pyr;
+}
+
+PyTypeObject pyLambda_type = {
+ PyObject_HEAD_INIT(0)
+ 0,
+ "lambda",
+ sizeof(pyLambda),
+ 0,
+ (destructor)pyLambda_dealloc,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ (ternaryfunc)pyLambda_call,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
+
+/**
+ * Create a new python object representing a lambda expression.
+ */
+PyObject *mkPyLambda(const lambda<value(const list<value>&)> l) {
+ pyLambda* pyl = NULL;
+ pyl = PyObject_NEW(pyLambda, &pyLambda_type);
+ if (pyl != NULL)
+ pyl->func = l;
+ return (PyObject *)pyl;
+}
+
+/**
+ * Convert a list of values to a python list.
+ */
+
+PyObject* valuesToPyListHelper(PyObject* l, const list<value>& v) {
+ if (isNil(v))
+ return l;
+ PyList_Append(l, valueToPyObject(car(v)));
+ return valuesToPyListHelper(l, cdr(v));
+}
+
+PyObject* valuesToPyTuple(const list<value>& v) {
+ return PyList_AsTuple(valuesToPyListHelper(PyList_New(0), v));
+}
+
+/**
+ * Convert a value to a python object.
+ */
+PyObject* valueToPyObject(const value& v) {
+ switch (type(v)) {
+ case value::List:
+ return valuesToPyTuple(v);
+ case value::Lambda:
+ return mkPyLambda(v);
+ case value::Symbol:
+ case value::String:
+ return PyString_FromString(c_str(v));
+ case value::Number:
+ return PyFloat_FromDouble((double)v);
+ case value::Bool:
+ return (bool)v? Py_True : Py_False;
+ case value::Char:
+ return PyInt_FromLong((long)((char)v));
+ case value::Ptr:
+ return NULL;
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * Convert a python tuple to a list of values.
+ */
+
+const list<value> pyTupleToValuesHelper(PyObject* o, int i, int size) {
+ if (i == size)
+ return list<value>();
+ return cons(pyObjectToValue(PyTuple_GetItem(o, i)), pyTupleToValuesHelper(o, i + 1, size));
+}
+
+const list<value> pyTupleToValues(PyObject* o) {
+ return pyTupleToValuesHelper(o, 0, PyTuple_Size(o));
+}
+
+/**
+ * Lambda function used to represent a python callable object.
+ */
+struct pyCallable {
+ PyObject* func;
+
+ pyCallable(PyObject* func) : func(func) {
+ Py_INCREF(func);
+ }
+
+ ~pyCallable() {
+ Py_DECREF(func);
+ }
+
+ const value operator()(const list<value>& args) const {
+ PyObject* pyargs = valuesToPyTuple(args);
+ PyObject* result = PyObject_CallObject(func, pyargs);
+ Py_DECREF(pyargs);
+ const value v = pyObjectToValue(result);
+ Py_DECREF(result);
+ return v;
+ }
+};
+
+/**
+ * Convert a python object to a value.
+ */
+const value pyObjectToValue(PyObject *o) {
+ if (PyString_Check(o))
+ return value(string(PyString_AsString(o)));
+ if (PyBool_Check(o))
+ return value(o == Py_True);
+ if (PyInt_Check(o))
+ return value((double)PyInt_AsLong(o));
+ if (PyLong_Check(o))
+ return value((double)PyLong_AsLong(o));
+ if (PyFloat_Check(o))
+ return value((double)PyFloat_AsDouble(o));
+ if (PyTuple_Check(o))
+ return pyTupleToValues(o);
+ if (PyCallable_Check(o))
+ return lambda<value(const list<value>&)>(pyCallable(o));
+ return value();
+}
+
+/**
+ * Read a python script from an input stream.
+ */
+const failable<PyObject*> readScript(const string& path, istream& is) {
+ const list<string> ls = streamList(is);
+ ostringstream os;
+ write(ls, os);
+ PyObject* code = Py_CompileStringFlags(c_str(str(os)), c_str(path), Py_file_input, NULL);
+ if (code == NULL)
+ return mkfailure<PyObject*>(string("Couldn't compile script: ") + path + " : " + lastError());
+ PyObject* mod = PyImport_ExecCodeModule(const_cast<char*>(c_str(path)), code);
+ if (mod == NULL)
+ return mkfailure<PyObject*>(string("Couldn't import module: ") + path + " : " + lastError());
+ return mod;
+}
+
+/**
+ * Evaluate an expression against a script provided as a python object.
+ */
+const failable<value> evalScript(const value& expr, PyObject* script, unused const gc_pool& pool) {
+
+ // Get the requested function
+ PyObject* func = PyObject_GetAttrString(script, c_str(car<value>(expr)));
+ if (func == NULL)
+ return mkfailure<value>(string("Couldn't find function: ") + car<value>(expr) + " : " + lastError());
+ if (!PyCallable_Check(func)) {
+ Py_DECREF(func);
+ return mkfailure<value>(string("Couldn't find callable function: ") + car<value>(expr));
+ }
+
+ // Convert args to python objects
+ PyObject* args = valuesToPyTuple(cdr<value>(expr));
+
+ // Call the function
+ PyObject* result = PyObject_CallObject(func, args);
+ Py_DECREF(args);
+ Py_DECREF(func);
+ if (result == NULL)
+ return mkfailure<value>(string("Function call failed: ") + car<value>(expr) + " : " + lastError());
+
+ // Convert python result to a value
+ const value v = pyObjectToValue(result);
+ Py_DECREF(result);
+ return v;
+}
+
+/**
+ * Evaluate an expression against a script provided as an input stream.
+ */
+const failable<value> evalScript(const value& expr, istream& is, unused const gc_pool& pool) {
+ failable<PyObject*> script = readScript("script", is);
+ if (!hasContent(script))
+ return mkfailure<value>(reason(script));
+ return evalScript(expr, content(script), pool);
+}
+
+/**
+ * Evaluate an expression against the python builtin module, no script is provided.
+ */
+const failable<value> evalExpr(const value& expr, const gc_pool& pool) {
+ return evalScript(expr, builtin(pythonRuntime), pool);
+}
+
+}
+}
+#endif /* tuscany_python_pyeval_hpp */
diff --git a/sca-cpp/trunk/modules/python/io.hpp b/sca-cpp/trunk/modules/python/io.hpp
new file mode 100644
index 0000000000..4292c32c34
--- /dev/null
+++ b/sca-cpp/trunk/modules/python/io.hpp
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_python_pyio_hpp
+#define tuscany_python_pyio_hpp
+
+/**
+ * Hooks used to capture python stdout and stderr.
+ */
+#include <python2.6/Python.h>
+
+#include "stream.hpp"
+#include "../scheme/io.hpp"
+
+namespace tuscany {
+namespace python {
+
+#ifdef _REENTRANT
+__thread
+#endif
+ostream* displayOutStream = NULL;
+
+#ifdef _REENTRANT
+__thread
+#endif
+ostream* logOutStream = NULL;
+
+/**
+ * Setup the display stream.
+ */
+const bool setupDisplay(ostream& out) {
+ scheme::setupDisplay(out);
+ displayOutStream = &out;
+ return true;
+}
+
+ostream& displayStream() {
+ if (displayOutStream == NULL)
+ return cout;
+ return *displayOutStream;
+}
+
+/**
+ * Setup the log stream.
+ */
+const bool setupLog(ostream& out) {
+ scheme::setupLog(out);
+ logOutStream = &out;
+ return true;
+}
+
+ostream& logStream() {
+ if (logOutStream == NULL)
+ return cerr;
+ return *logOutStream;
+}
+
+/**
+ * Hook method used to redirect python output to a stream.
+ */
+PyObject* display(unused PyObject* self, PyObject* args) {
+ char* s = NULL;
+ if (!PyArg_ParseTuple(args, "s", &s))
+ return NULL;
+
+ displayStream() << s;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyMethodDef displayHookMethods[] = {
+ {"display", display, METH_VARARGS, "Redirects stdout"},
+ {NULL, NULL, 0, NULL}};
+
+/**
+ * Hook method used to redirect python errors to a stream.
+ */
+PyObject* log(unused PyObject* self, PyObject* args) {
+ char* s = NULL;
+ if (!PyArg_ParseTuple(args, "s", &s))
+ return NULL;
+
+ logStream() << s;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyMethodDef logHookMethods[] = {
+ {"log", log, METH_VARARGS, "Redirects stdout"},
+ {NULL, NULL, 0, NULL}};
+
+/**
+ * Setup the display and log hooks.
+ */
+bool setupIO() {
+ Py_InitModule("displayhook", displayHookMethods);
+ PyRun_SimpleString(
+ "import sys\n"
+ "import displayhook\n"
+ "\n"
+ "class DisplayHook:\n"
+ " def write(self, text):\n"
+ " displayhook.display(text)\n"
+ "\n"
+ "sys.stdout = DisplayHook()\n");
+
+ Py_InitModule("loghook", logHookMethods);
+ PyRun_SimpleString(
+ "import sys\n"
+ "import loghook\n"
+ "\n"
+ "class LogHook:\n"
+ " def write(self, text):\n"
+ " loghook.log(text)\n"
+ "\n"
+ "sys.stderr = LogHook()\n");
+ return true;
+}
+
+/**
+ * Return the last python error.
+ */
+const string lastError() {
+ ostream* pos = logOutStream;
+ ostringstream eos;
+ logOutStream = &eos;
+ if (PyErr_Occurred())
+ PyErr_Print();
+ logOutStream = pos;
+ return str(eos);
+}
+
+/**
+ * Read and write values (using the scheme representation as it's the canonical
+ * representation used throughout the runtime.)
+ */
+const value readValue(istream& in) {
+ return scheme::readValue(in);
+}
+
+const bool writeValue(const value& val, ostream& out) {
+ return scheme::writeValue(val, out);
+}
+
+}
+}
+#endif /* tuscany_python_pyio_hpp */
diff --git a/sca-cpp/trunk/modules/python/python-shell.cpp b/sca-cpp/trunk/modules/python/python-shell.cpp
new file mode 100644
index 0000000000..0525ea2f2c
--- /dev/null
+++ b/sca-cpp/trunk/modules/python/python-shell.cpp
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Python script evaluator shell, used for interactive testing of scripts.
+ */
+
+#include <assert.h>
+#include "gc.hpp"
+#include "stream.hpp"
+#include "string.hpp"
+#include "driver.hpp"
+
+int main(const int argc, char** argv) {
+ tuscany::gc_scoped_pool pool;
+ if (argc == 1) {
+ tuscany::python::evalDriverRun(tuscany::cin, tuscany::cout, pool);
+ return 0;
+ }
+ tuscany::python::evalDriverRun(argv[1], tuscany::cin, tuscany::cout, pool);
+ return 0;
+}
diff --git a/sca-cpp/trunk/modules/python/python-test.cpp b/sca-cpp/trunk/modules/python/python-test.cpp
new file mode 100644
index 0000000000..612dc5b79d
--- /dev/null
+++ b/sca-cpp/trunk/modules/python/python-test.cpp
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test Python script evaluator.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "driver.hpp"
+
+namespace tuscany {
+namespace python {
+
+const value evalBuiltin(const string& py, const gc_pool& pool) {
+ istringstream is(py);
+ ostringstream os;
+ evalDriverRun(is, os, pool);
+ return str(os);
+}
+
+const string testPythonPrint(
+ "(print \"testPrint ok\")");
+
+bool testEval() {
+ gc_scoped_pool pool;
+ assert(contains(evalBuiltin(testPythonPrint, pool), "testPrint ok"));
+ return true;
+}
+
+const string testPythonAdd =
+ "def add(x, y):\n"
+ " return x + y\n";
+
+bool testEvalExpr() {
+ gc_scoped_pool pool;
+ {
+ const value exp = mklist<value>("abs", -5);
+ const failable<value> r = evalExpr(exp, pool);
+ assert(hasContent(r));
+ assert(content(r) == value(5));
+ }
+ {
+ istringstream is(testPythonAdd);
+ failable<PyObject*> script = readScript("script", is);
+ assert(hasContent(script));
+ const value exp = mklist<value>("add", 2, 3);
+ const failable<value> r = evalScript(exp, content(script), pool);
+ assert(hasContent(r));
+ assert(content(r) == value(5));
+ }
+ return true;
+}
+
+bool testEvalRun() {
+ gc_scoped_pool pool;
+ evalDriverRun(cin, cout, pool);
+ return true;
+}
+
+const value mult(const list<value>& args) {
+ const double x = car(args);
+ const double y = cadr(args);
+ return x * y;
+}
+
+const string testReturnLambda(
+ "def mul(x, y):\n"
+ " return x * y\n"
+ "\n"
+ "def testReturnLambda():\n"
+ " return mul\n");
+
+const string testCallLambda(
+ "def testCallLambda(l, x, y):\n"
+ " return l(x, y)\n");
+
+bool testEvalLambda() {
+ gc_scoped_pool pool;
+
+ const value trl = mklist<value>("testReturnLambda");
+ istringstream trlis(testReturnLambda);
+ const failable<value> trlv = evalScript(trl, trlis, pool);
+
+ assert(hasContent(trlv));
+ assert(isLambda(content(trlv)));
+ const lambda<value(const list<value>&)> trll(content(trlv));
+ assert(trll(mklist<value>(2, 3)) == value(6));
+
+ istringstream tclis(testCallLambda);
+ const value tcl = mklist<value>("testCallLambda", content(trlv), 2, 3);
+ const failable<value> tclv = evalScript(tcl, tclis, pool);
+ assert(hasContent(tclv));
+ assert(content(tclv) == value(6));
+
+ istringstream tcelis(testCallLambda);
+ const value tcel = mklist<value>("testCallLambda", lambda<value(const list<value>&)>(mult), 3, 4);
+ const failable<value> tcelv = evalScript(tcel, tcelis, pool);
+ assert(hasContent(tcelv));
+ assert(content(tcelv) == value(12));
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::python::testEval();
+ tuscany::python::testEvalExpr();
+ tuscany::python::testEvalLambda();
+
+ tuscany::cout << "OK" << tuscany::endl;
+ return 0;
+}
diff --git a/sca-cpp/trunk/modules/python/tuscany-sca-1.1-implementation-python.xsd b/sca-cpp/trunk/modules/python/tuscany-sca-1.1-implementation-python.xsd
new file mode 100644
index 0000000000..95ffc4f743
--- /dev/null
+++ b/sca-cpp/trunk/modules/python/tuscany-sca-1.1-implementation-python.xsd
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200903"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ elementFormDefault="qualified">
+
+ <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200903" schemaLocation="sca-1.1-cd04.xsd"/>
+
+ <element name="implementation.python" type="t:PythonImplementation" substitutionGroup="sca:implementation"/>
+
+ <complexType name="PythonImplementation">
+ <complexContent>
+ <extension base="sca:Implementation">
+ <sequence>
+ <any namespace="##targetNamespace" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="location" type="anyURI" use="required"/>
+ <anyAttribute namespace="##any" processContents="lax"/>
+ </extension>
+ </complexContent>
+ </complexType>
+
+</schema>