From: Timo Korvola Date: Fri, 27 Jan 2017 14:04:24 +0000 (+0200) Subject: Add some PyEval_{Restore,Save}Thread calls. X-Git-Tag: v1.31.0~6^2~3 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F97%2F297%2F1;p=simantics%2Fpython.git Add some PyEval_{Restore,Save}Thread calls. More are needed, but it is a mess of copy-paste programming. Change-Id: Ie4dcc7627349cab84c37cb0b6c7275876373e25d --- diff --git a/org.simantics.pythonlink.win32.x86_64/jnipython.dll b/org.simantics.pythonlink.win32.x86_64/jnipython.dll index 7fff774..37e4577 100644 Binary files a/org.simantics.pythonlink.win32.x86_64/jnipython.dll and b/org.simantics.pythonlink.win32.x86_64/jnipython.dll differ diff --git a/org.simantics.pythonlink.win32.x86_64/src/sclpy.c b/org.simantics.pythonlink.win32.x86_64/src/sclpy.c index b10b36f..1cc36d8 100644 --- a/org.simantics.pythonlink.win32.x86_64/src/sclpy.c +++ b/org.simantics.pythonlink.win32.x86_64/src/sclpy.c @@ -1,1288 +1,1293 @@ -/////////////////////////////////////////////////////// -// // -// VTT Technical Research Centre of Finland LTD // -// For internal use only. Do not redistribute. // -// // -// Authors: // -// Antton Tapani ext-antton.tapani@vtt.fi // -// // -// Last modified by Antton Tapani 9.2016 // -// // -/////////////////////////////////////////////////////// - -#include "sclpy.h" - -#include - -jint throwException( JNIEnv *env, char *className, char *message ) -{ - jclass exClass = (*env)->FindClass( env, className); - if (exClass == NULL) { - return 0; - } - - return (*env)->ThrowNew( env, exClass, message ); -} - -jint throwPythonException( JNIEnv *env, char *message ) { - return throwException( env, PYTHON_EXCEPTION, message ); -} - -jint throwIllegalArgumentException( JNIEnv *env, char *message ) { - return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message ); -} - -int moduleCount = 0; -int initCalled = 0; -int hasNumpy = 0; - -JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) { - char name[16]; - - if (!initCalled) { - Py_Initialize(); - initCalled = 1; - - hasNumpy = _import_array(); - hasNumpy = hasNumpy != -1; - } - - sprintf(name, "SCL_%d", ++moduleCount); - - { - PyObject *module = PyModule_New(name); - PyObject *main = PyImport_AddModule("__main__"); - - PyDict_Merge(PyModule_GetDict(module), PyModule_GetDict(main), 0); - - return (jlong)module; - } -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) { - PyObject *module = (PyObject*)contextID; - Py_XDECREF(module); -} - -PyObject *getPythonBool(jboolean value) { - if (value) { - Py_RETURN_TRUE; - } - else { - Py_RETURN_FALSE; - } -} - -PyObject *getPythonString(JNIEnv *env, jstring string) { - jsize len = (*env)->GetStringLength(env, string); - const jchar *chars = (*env)->GetStringChars(env, string, NULL); - - PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL); - - (*env)->ReleaseStringChars(env, string, chars); - return value; -} - -PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) { - jsize nitems = (*env)->GetArrayLength(env, value); - jint *values = (*env)->GetIntArrayElements(env, value, NULL); - jclass stringClass = (*env)->FindClass(env, STRING_CLASS); - jint i; - - PyObject *result = PyList_New(nitems); - for (i = 0; i < nitems; i++) { - jobject item = (*env)->GetObjectArrayElement(env, value, i); - if (item != NULL && (*env)->IsInstanceOf(env, item, stringClass)) { - PyList_SetItem(result, i, getPythonString(env, (jstring)item)); - } - else { - PyList_SetItem(result, i, Py_None); - } - } - - (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT); - return result; -} - -PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) { - jsize nitems = (*env)->GetArrayLength(env, value); - jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL); - jint i; - - PyObject *result = PyList_New(nitems); - for (i = 0; i < nitems; i++) { - PyList_SetItem(result, i, getPythonBool(values[i])); - } - - (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT); - return result; -} - -PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) { - jint len = (*env)->GetArrayLength(env, value); - jbyte *values = (*env)->GetByteArrayElements(env, value, NULL); - - PyObject *result = PyByteArray_FromStringAndSize(values, len); - - (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT); - return result; -} - -PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) { - jsize nitems = (*env)->GetArrayLength(env, value); - jint *values = (*env)->GetIntArrayElements(env, value, NULL); - jint i; - - PyObject *result = PyList_New(nitems); - for (i = 0; i < nitems; i++) { - PyList_SetItem(result, i, PyLong_FromLong(values[i])); - } - - (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT); - return result; -} - -PyObject *getPythonLongList(JNIEnv *env, jlongArray value) { - jsize nitems = (*env)->GetArrayLength(env, value); - jlong *values = (*env)->GetLongArrayElements(env, value, NULL); - jint i; - - PyObject *result = PyList_New(nitems); - for (i = 0; i < nitems; i++) { - PyList_SetItem(result, i, PyLong_FromLongLong(values[i])); - } - - (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT); - return result; -} - -PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) { - jsize nitems = (*env)->GetArrayLength(env, value); - float *values = (*env)->GetFloatArrayElements(env, value, NULL); - jint i; - - PyObject *result = PyList_New(nitems); - for (i = 0; i < nitems; i++) { - PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i])); - } - - (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT); - return result; -} - -PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) { - jsize nitems = (*env)->GetArrayLength(env, value); - double *values = (*env)->GetDoubleArrayElements(env, value, NULL); - jint i; - - PyObject *result = PyList_New(nitems); - for (i = 0; i < nitems; i++) { - PyList_SetItem(result, i, PyFloat_FromDouble(values[i])); - } - - (*env)->ReleaseDoubleArrayElements(env, value, values, JNI_ABORT); - return result; -} - -PyObject *getPythonNDArray(JNIEnv *env, jobject value) { - jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS); - jmethodID dimsMethod = (*env)->GetMethodID(env, ndarrayClass, "dims", "()[I"); - jmethodID getValuesMethod = (*env)->GetMethodID(env, ndarrayClass, "getValues", "()[D"); - - jintArray jdims = (*env)->CallObjectMethod(env, value, dimsMethod); - jsize ndims = (*env)->GetArrayLength(env, jdims); - jint *dims = (*env)->GetIntArrayElements(env, jdims, NULL); - - jdoubleArray jvalues = (*env)->CallObjectMethod(env, value, getValuesMethod); - jsize len = (*env)->GetArrayLength(env, jvalues); - jdouble *values = (*env)->GetDoubleArrayElements(env, jvalues, NULL); - - npy_intp *pyDims = (npy_intp*)malloc(ndims * sizeof(npy_intp)); - - jint i, nelem = ndims > 0 ? 1 : 0; - for (i = 0; i < ndims; i++) { - nelem *= dims[i]; - pyDims[i] = dims[i]; - } - - len = min(len, nelem); - - { - PyObject *array = PyArray_EMPTY(ndims, pyDims, NPY_DOUBLE, 0); - double *data = (double *)PyArray_DATA((PyArrayObject*)array); - - memcpy(data, values, len * sizeof(double)); - - free(pyDims); - - (*env)->ReleaseDoubleArrayElements(env, jvalues, values, JNI_ABORT); - (*env)->ReleaseIntArrayElements(env, jdims, dims, JNI_ABORT); - - return array; - } -} - -PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS); - jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z"); - - jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object); - return getPythonBool(bvalue); -} - -PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS); - jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B"); - - jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object); - return PyLong_FromLong(v); -} - -PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS); - jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I"); - - jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object); - return PyLong_FromLong(v); -} - -PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS); - jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J"); - - jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object); - return PyLong_FromLongLong(v); -} - -PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS); - jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F"); - - jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object); - return PyFloat_FromDouble(v); -} - -PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS); - jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D"); - - jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object); - return PyFloat_FromDouble(v); -} - -PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS); - jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";"); - - jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object); - jsize len = (*env)->GetStringLength(env, string); - const jchar *chars = (*env)->GetStringChars(env, string, NULL); - - PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL); - - (*env)->ReleaseStringChars(env, string, chars); - return value; -} - -PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS); - jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";"); - jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";"); - jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";"); - - jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS); - jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";"); - jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I"); - - jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS); - jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";"); - - jobject type = (*env)->CallObjectMethod(env, binding, typeMethod); - jint n = (*env)->CallIntMethod(env, type, getComponentCount); - jint i; - - PyObject *result = PyDict_New(); - for (i = 0; i < n; i++) { - jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i); - jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField); - jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i); - jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i); - - PyObject *item = getPythonObject(env, componentObject, componentBinding); - PyDict_SetItem(result, getPythonString(env, fieldName), item); - } - - return result; -} - -PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS); - jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";"); - jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I"); - jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";"); - - jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod); - - jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object); - - PyObject *result = PyList_New(size); - - jint i; - for (i = 0; i < size; i++) { - jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i); - if (item != NULL) - PyList_SetItem(result, i, getPythonObject(env, item, componentBinding)); - else - PyList_SetItem(result, i, Py_None); - } - - return result; -} - -PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) { - jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS); - jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS); - jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";"); - jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";"); - jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I"); - jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V"); - - jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod); - jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod); - - jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object); - jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL); - jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL); - - PyObject *result = PyDict_New(); - jint i; - - (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values); - - for (i = 0; i < size; i++) { - jobject key = (*env)->GetObjectArrayElement(env, keys, i); - jobject item = (*env)->GetObjectArrayElement(env, values, i); - PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding)); - } - - (*env)->DeleteLocalRef(env, keys); - (*env)->DeleteLocalRef(env, values); - - return result; -} - -PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS); - jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z"); - - jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object); - - if (hasValue) { - jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";"); - jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); - - jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod); - jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object); - - return getPythonObject(env, value, componentBinding); - } - else { - return Py_None; - } -} - -PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS); - jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";"); - jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I"); - jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); - jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";"); - - jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS); - jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";"); - - jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS); - jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";"); - - jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object); - jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object); - - jobject type = (*env)->CallObjectMethod(env, binding, typeMethod); - jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag); - jstring compName = (*env)->GetObjectField(env, typeComponent, nameField); - - jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag); - - PyObject *result = PyTuple_New(2); - PyTuple_SetItem(result, 0, getPythonString(env, compName)); - PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding)); - - return result; -} - -PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) { - jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS); - jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); - jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";"); - - jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object); - jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object); - - return getPythonObject(env, content, contentBinding); -} - -PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) { - jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS); - jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS); - jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS); - jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS); - jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS); - jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS); - jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS); - jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS); - jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS); - jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS); - jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS); - jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS); - jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS); - - if (value == NULL) - return Py_None; - - if ((*env)->IsInstanceOf(env, binding, booleanBinding)) { - return getPythonBooleanObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, byteBinding)) { - return getPythonByteObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, integerBinding)) { - return getPythonIntegerObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, longBinding)) { - return getPythonLongObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, floatBinding)) { - return getPythonFloatObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) { - return getPythonDoubleObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, stringBinding)) { - return getPythonStringObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, recordBinding)) { - return getPythonRecordObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) { - return getPythonArrayObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, mapBinding)) { - return getPythonMapObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) { - return getPythonOptionalObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, untionBinding)) { - return getPythonUnionObject(env, value, binding); - } - else if ((*env)->IsInstanceOf(env, binding, variantBinding)) { - return getPythonVariantObject(env, value, binding); - } - else { - return Py_None; - } -} - -void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) { - if (name && value) { - PyDict_SetItem(PyModule_GetDict(module), name, value); - } - - Py_XDECREF(name); - Py_XDECREF(value); -} - -static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) { - if (d == nd) { - ncont[d] = 1; - return 1; - } - else { - npy_intp n = nContiguous(d+1, nd, strides, dims, ncont); - ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0; - return ncont[d]; - } -} - -static void copyDoubleArrayValues(JNIEnv *env, jdoubleArray array, double *data, npy_intp *offset, int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) { - if (ncont[d] > 0) { - (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data); - *offset += ncont[d]; - } - else { - int i; - for (i = 0; i < dims[d]; i++) { - copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont); - } - } -} - -jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) { - jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean"); - jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;"); - - return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True)); -} - -jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) { - jclass longClass = (*env)->FindClass(env, "java/lang/Long"); - jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;"); - - return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value)); -} - -jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) { - jclass doubleClass = (*env)->FindClass(env, "java/lang/Double"); - jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;"); - - return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value)); -} - -jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) { - Py_ssize_t size = PyByteArray_Size(value); - jbyteArray result = (*env)->NewByteArray(env, (jsize)size); - char *bytes = PyByteArray_AsString(value); - - (*env)->SetByteArrayRegion(env, result, 0, size, bytes); - - return result; -} - -jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) { - PyObject *utf16Value = PyUnicode_AsUTF16String(string); - Py_ssize_t len = PyBytes_Size(utf16Value) / 2; - char *bytes = PyBytes_AsString(utf16Value); - - // Create Java string, skipping the byte order mark in the beginning - jstring result = (*env)->NewString(env, (jchar *)bytes + 1, (jsize)min(len, JAVA_MAXINT) - 1); - - Py_XDECREF(utf16Value); - - return result; -} - -jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) { - Py_ssize_t len = PySequence_Size(seq); - jsize jlen = (jsize)min(len, JAVA_MAXINT); - jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL); - - jint i; - - for (i = 0; i < jlen; i++) { - PyObject *item = PySequence_GetItem(seq, i); - if (PyUnicode_Check(item)) { - jstring value = pythonStringAsJavaString(env, item); - (*env)->SetObjectArrayElement(env, array, i, value); - } - else { - throwPythonException(env, "List item not a string"); - return NULL; - } - } - - return array; -} - -jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) { - Py_ssize_t len = PySequence_Size(seq); - jsize jlen = (jsize)min(len, JAVA_MAXINT); - jdoubleArray array = (*env)->NewDoubleArray(env, jlen); - - jint i; - - for (i = 0; i < jlen; i++) { - PyObject *item = PySequence_GetItem(seq, i); - if (PyFloat_Check(item)) { - double value = PyFloat_AsDouble(item); - (*env)->SetDoubleArrayRegion(env, array, i, 1, &value); - } - else { - throwPythonException(env, "List item not a floating point value"); - return NULL; - } - } - - return array; -} - -jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) { - if (PyBool_Check(value)) - return pythonBoolAsBooleanObject(env, value); - else if (PyLong_Check(value)) - return pythonLongAsLongObject(env, value); - else if (PyFloat_Check(value)) - return pythonFloatAsDoubleObject(env, value); - else if (PyUnicode_Check(value)) - return pythonStringAsJavaString(env, value); - else if (PyByteArray_Check(value)) - return pythonByteArrayAsByteArray(env, value); - else if (PyDict_Check(value)) - return pythonDictionaryAsMap(env, value); - else if (hasNumpy && PyArray_Check(value)) - return pythonArrayAsNDArray(env, (PyArrayObject *)value); - else if (PySequence_Check(value)) - return pythonSequenceAsObjectArray(env, value); - else - return NULL; -} - -jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) { - Py_ssize_t len = PySequence_Size(seq); - jsize jlen = (jsize)min(len, JAVA_MAXINT); - jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL); - - jint i; - - for (i = 0; i < jlen; i++) { - PyObject *item = PySequence_GetItem(seq, i); - jobject object = pythonObjectAsObject(env, item); - (*env)->SetObjectArrayElement(env, array, i, object); - } - - return array; -} - -jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) { - Py_ssize_t len = PySequence_Size(seq); - jsize jlen = (jsize)min(len, JAVA_MAXINT); - jbooleanArray array = (*env)->NewBooleanArray(env, jlen); - - jint i; - - for (i = 0; i < jlen; i++) { - PyObject *item = PySequence_GetItem(seq, i); - if (PyBool_Check(item)) { - jboolean value = item == Py_True; - (*env)->SetBooleanArrayRegion(env, array, i, 1, &value); - } - else { - throwPythonException(env, "List item not a boolean"); - return NULL; - } - } - - return array; -} - -jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) { - Py_ssize_t len = PySequence_Size(seq); - jsize jlen = (jsize)min(len, JAVA_MAXINT); - jintArray array = (*env)->NewIntArray(env, jlen); - - jint i; - - for (i = 0; i < jlen; i++) { - PyObject *item = PySequence_GetItem(seq, i); - if (PyLong_Check(item)) { - jint value = PyLong_AsLong(item); - (*env)->SetIntArrayRegion(env, array, i, 1, &value); - } - else { - throwPythonException(env, "List item not an integer"); - return NULL; - } - } - - return array; -} - -jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) { - Py_ssize_t len = PySequence_Size(seq); - jsize jlen = (jsize)min(len, JAVA_MAXINT); - jlongArray array = (*env)->NewLongArray(env, jlen); - - jint i; - - for (i = 0; i < jlen; i++) { - PyObject *item = PySequence_GetItem(seq, i); - if (PyLong_Check(item)) { - jlong value = PyLong_AsLongLong(item); - (*env)->SetLongArrayRegion(env, array, i, 1, &value); - } - else { - throwPythonException(env, "List item not an integer"); - return NULL; - } - } - - return array; -} - -jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) { - jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS); - jmethodID constructor = (*env)->GetMethodID(env, ndarrayClass, "", "([I[D)V"); - - int ndims = PyArray_NDIM(array); - npy_intp *dims = PyArray_DIMS(array); - - npy_intp len = PyArray_Size((PyObject*)array); - double *values = (double*)PyArray_DATA(array); - - jboolean isFortran = PyArray_ISFORTRAN(array) != 0; - - int i; - - if (len > JAVA_MAXINT) { - throwPythonException(env, "Array too large"); - return NULL; - } - - { - jintArray jdims = (*env)->NewIntArray(env, ndims); - jdoubleArray jvalues = (*env)->NewDoubleArray(env, (jsize)len); - - for (i = 0; i < ndims; i++) { - jint dim = (jint)dims[i]; - (*env)->SetIntArrayRegion(env, jdims, i, 1, &dim); - } - - if (PyArray_IS_C_CONTIGUOUS(array)) { - (*env)->SetDoubleArrayRegion(env, jvalues, 0, (jsize)len, values); - } - else { - npy_intp offset = 0; - npy_intp *strides = PyArray_STRIDES(array); - npy_intp *ncont = (npy_intp*)malloc((ndims + 1) * sizeof(npy_intp)); - nContiguous(0, ndims, strides, dims, ncont); - copyDoubleArrayValues(env, jvalues, values, &offset, 0, ndims, strides, dims, ncont); - free(ncont); - } - - return (*env)->NewObject(env, ndarrayClass, constructor, jdims, jvalues, isFortran); - } -} - -jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) { - jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap"); - jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "", "(I)V"); - jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); - - Py_ssize_t size = PyDict_Size(dict); - jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size); - - PyObject *key, *value; - Py_ssize_t pos = 0; - - while (PyDict_Next(dict, &pos, &key, &value)) { - jobject keyObject = pythonObjectAsObject(env, key); - jobject valueObject = pythonObjectAsObject(env, value); - (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject); - } - - return map; -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jboolean value) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonBool(value); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jbooleanArray value) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonBooleanList(env, value); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlong value) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = PyLong_FromLongLong(value); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jintArray value) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonIntegerList(env, value); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlongArray value) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonLongList(env, value); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdouble value) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = PyFloat_FromDouble(value); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonFloatArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jfloatArray value) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonFloatList(env, value); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdoubleArray value) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonDoubleList(env, value); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jstring value) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonString(env, value); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobjectArray value) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonStringList(env, value); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value) { - PyObject *module = (PyObject*)contextID; - - if (!hasNumpy) { - throwPythonException(env, "Importing numpy failed"); - return; - } - - { - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonNDArray(env, value); - - setPythonVariable(module, pythonName, val); - } -} - -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value, jobject binding) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = getPythonObject(env, value, binding); - - setPythonVariable(module, pythonName, val); -} - -JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) { - PyObject *module = (PyObject*)contextID; - - const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL); - - PyErr_Clear(); - { - PyObject *globals; - - globals = PyModule_GetDict(module); - - { - PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals); - - PyObject *exceptionType = PyErr_Occurred(); - if (exceptionType != NULL) { - PyObject *exception, *traceback; - PyErr_Fetch(&exceptionType, &exception, &traceback); - - { - PyObject *tracebackModule = PyImport_ImportModule("traceback"); - if (tracebackModule != NULL) { - PyObject *formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception"); - if (formatExc != NULL) { - PyObject *args = PyTuple_Pack(3, exceptionType, exception, traceback); - PyObject *message = PyObject_CallObject(formatExc, args); - if (message != NULL) { - PyObject *emptyStr = PyUnicode_FromString(""); - PyObject *joined = PyUnicode_Join(emptyStr, message); - char *messageStr = PyUnicode_AsUTF8(joined); - throwPythonException(env, messageStr); - Py_DECREF(joined); - Py_DECREF(emptyStr); - Py_DECREF(message); - } - else { - throwPythonException(env, "Internal error, no message"); - } - Py_DECREF(args); - Py_DECREF(formatExc); - } - else { - throwPythonException(env, "Internal error, no format_exc function"); - } - Py_DECREF(tracebackModule); - } - else { - throwPythonException(env, "Internal error, no traceback module"); - } - } - } - - (*env)->ReleaseStringUTFChars(env, statement, utfchars); - - return result != NULL ? 0 : 1; - } - } -} - -JNIEXPORT jstring JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0; - } - - if (!PyUnicode_Check(value)) { - throwPythonException(env, "Python variable not a string"); - return 0; - } - - { - jstring result = pythonStringAsJavaString(env, value); - return result; - } -} - -JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0; - } - - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return 0; - } - - { - jobjectArray result = pythonSequenceAsStringArray(env, value); - return result; - } -} - -JNIEXPORT jboolean JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0; - } - - if (!PyBool_Check(value)) { - throwPythonException(env, "Python variable not a boolean"); - return 0; - } - - return value == Py_True; -} - -JNIEXPORT jbooleanArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0; - } - - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return 0; - } - - { - jbooleanArray result = pythonSequenceAsBooleanArray(env, value); - return result; - } -} - -JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0; - } - - if (!PyLong_Check(value)) { - throwPythonException(env, "Python variable not an integer"); - return 0; - } - - { - jlong result = PyLong_AsLongLong(value); - return result; - } -} - -JNIEXPORT jintArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return NULL; - } - - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return NULL; - } - - { - jintArray result = pythonSequenceAsIntegerArray(env, value); - return result; - } -} - -JNIEXPORT jlongArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return NULL; - } - - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return NULL; - } - - { - jlongArray result = pythonSequenceAsLongArray(env, value); - return result; - } -} - -JNIEXPORT jdouble JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return 0.0; - } - - if (!PyFloat_Check(value)) { - throwPythonException(env, "Python variable not a float"); - return 0.0; - } - - { - jdouble result = PyFloat_AsDouble(value); - return result; - } -} - -JNIEXPORT jdoubleArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return NULL; - } - - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return NULL; - } - - { - jdoubleArray result = pythonSequenceAsDoubleArray(env, value); - return result; - } -} - -JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - if (!hasNumpy) { - throwPythonException(env, "Importing numpy failed"); - return NULL; - } - - { - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return NULL; - } - - if (!PyArray_Check(value)) { - throwPythonException(env, "Python variable not an ndarray"); - return NULL; - } - - if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) { - throwPythonException(env, "Only ndarrays of type double are supported"); - return NULL; - } - - { - jobject result = pythonArrayAsNDArray(env, (PyArrayObject *)value); - return result; - } - } -} - -JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - - PyObject *pythonName = getPythonString(env, variableName); - - PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - if (value == NULL) { - throwPythonException(env, "Python variable not found"); - return NULL; - } - - hasNumpy = _import_array() != -1; - - { - jobject result = pythonObjectAsObject(env, value); - return result; - } -} - -JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; - PyObject *dict = PyModule_GetDict(module); - - PyObject *pythonName = getPythonString(env, variableName); - - if (!PyDict_Contains(dict, pythonName)) { - return 0; - } - - { - PyObject *value = PyDict_GetItem(dict, pythonName); - - jint result; - - if (PyBool_Check(value)) - result = 1; - else if (PyLong_Check(value)) - result = 2; - else if (PyFloat_Check(value)) - result = 3; - else if (PyUnicode_Check(value)) - result = 4; - else if (PyByteArray_Check(value)) - result = 5; - else if (PyDict_Check(value)) - result = 6; - else if (hasNumpy && PyArray_Check(value)) - result = 7; - else if (PySequence_Check(value)) - result = 8; - else - result = -1; - - return result; - } -} - -JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(JNIEnv *env, jobject thisObj, jlong contextID) { - PyObject *module = (PyObject*)contextID; - PyObject *dict = PyModule_GetDict(module); - - PyObject *keys = PyDict_Keys(dict); - Py_ssize_t size = PyList_Size(keys); - - jobjectArray result = (*env)->NewObjectArray(env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL); - - Py_ssize_t i; - for (i = 0; i < size; i++) { - jstring javaName = pythonStringAsJavaString(env, PyList_GetItem(keys, i)); - (*env)->SetObjectArrayElement(env, result, (jint)i, javaName); - } - - Py_XDECREF(keys); - - return result; -} - -BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -//extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - // attach to process - // return FALSE to fail DLL load - break; - - case DLL_PROCESS_DETACH: - // detach from process - break; - - case DLL_THREAD_ATTACH: - // attach to thread - break; - - case DLL_THREAD_DETACH: - // detach from thread - break; - } - return TRUE; // succesful -} +/////////////////////////////////////////////////////// +// // +// VTT Technical Research Centre of Finland LTD // +// For internal use only. Do not redistribute. // +// // +// Authors: // +// Antton Tapani ext-antton.tapani@vtt.fi // +// // +// Last modified by Antton Tapani 9.2016 // +// // +/////////////////////////////////////////////////////// + +#include "sclpy.h" + +#include + +jint throwException( JNIEnv *env, char *className, char *message ) +{ + jclass exClass = (*env)->FindClass( env, className); + if (exClass == NULL) { + return 0; + } + + return (*env)->ThrowNew( env, exClass, message ); +} + +jint throwPythonException( JNIEnv *env, char *message ) { + return throwException( env, PYTHON_EXCEPTION, message ); +} + +jint throwIllegalArgumentException( JNIEnv *env, char *message ) { + return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message ); +} + +int moduleCount = 0; +int hasNumpy = 0; +PyThreadState *main_ts = 0; + +JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) { + char name[16]; + + if (!main_ts) { + Py_Initialize(); + + hasNumpy = _import_array(); + hasNumpy = hasNumpy != -1; + main_ts = PyEval_SaveThread(); + } + + sprintf(name, "SCL_%d", ++moduleCount); + + PyEval_RestoreThread(main_ts); + { + PyObject *module = PyModule_New(name); + PyObject *main = PyImport_AddModule("__main__"); + + PyDict_Merge(PyModule_GetDict(module), PyModule_GetDict(main), 0); + PyEval_SaveThread(); + return (jlong)module; + } +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) { + PyObject *module = (PyObject*)contextID; + PyEval_RestoreThread(main_ts); + Py_XDECREF(module); + PyEval_SaveThread(); +} + +PyObject *getPythonBool(jboolean value) { + if (value) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +PyObject *getPythonString(JNIEnv *env, jstring string) { + jsize len = (*env)->GetStringLength(env, string); + const jchar *chars = (*env)->GetStringChars(env, string, NULL); + + PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL); + + (*env)->ReleaseStringChars(env, string, chars); + return value; +} + +PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) { + jsize nitems = (*env)->GetArrayLength(env, value); + jint *values = (*env)->GetIntArrayElements(env, value, NULL); + jclass stringClass = (*env)->FindClass(env, STRING_CLASS); + jint i; + + PyObject *result = PyList_New(nitems); + for (i = 0; i < nitems; i++) { + jobject item = (*env)->GetObjectArrayElement(env, value, i); + if (item != NULL && (*env)->IsInstanceOf(env, item, stringClass)) { + PyList_SetItem(result, i, getPythonString(env, (jstring)item)); + } + else { + PyList_SetItem(result, i, Py_None); + } + } + + (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT); + return result; +} + +PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) { + jsize nitems = (*env)->GetArrayLength(env, value); + jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL); + jint i; + + PyObject *result = PyList_New(nitems); + for (i = 0; i < nitems; i++) { + PyList_SetItem(result, i, getPythonBool(values[i])); + } + + (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT); + return result; +} + +PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) { + jint len = (*env)->GetArrayLength(env, value); + jbyte *values = (*env)->GetByteArrayElements(env, value, NULL); + + PyObject *result = PyByteArray_FromStringAndSize(values, len); + + (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT); + return result; +} + +PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) { + jsize nitems = (*env)->GetArrayLength(env, value); + jint *values = (*env)->GetIntArrayElements(env, value, NULL); + jint i; + + PyObject *result = PyList_New(nitems); + for (i = 0; i < nitems; i++) { + PyList_SetItem(result, i, PyLong_FromLong(values[i])); + } + + (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT); + return result; +} + +PyObject *getPythonLongList(JNIEnv *env, jlongArray value) { + jsize nitems = (*env)->GetArrayLength(env, value); + jlong *values = (*env)->GetLongArrayElements(env, value, NULL); + jint i; + + PyObject *result = PyList_New(nitems); + for (i = 0; i < nitems; i++) { + PyList_SetItem(result, i, PyLong_FromLongLong(values[i])); + } + + (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT); + return result; +} + +PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) { + jsize nitems = (*env)->GetArrayLength(env, value); + float *values = (*env)->GetFloatArrayElements(env, value, NULL); + jint i; + + PyObject *result = PyList_New(nitems); + for (i = 0; i < nitems; i++) { + PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i])); + } + + (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT); + return result; +} + +PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) { + jsize nitems = (*env)->GetArrayLength(env, value); + double *values = (*env)->GetDoubleArrayElements(env, value, NULL); + jint i; + + PyObject *result = PyList_New(nitems); + for (i = 0; i < nitems; i++) { + PyList_SetItem(result, i, PyFloat_FromDouble(values[i])); + } + + (*env)->ReleaseDoubleArrayElements(env, value, values, JNI_ABORT); + return result; +} + +PyObject *getPythonNDArray(JNIEnv *env, jobject value) { + jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS); + jmethodID dimsMethod = (*env)->GetMethodID(env, ndarrayClass, "dims", "()[I"); + jmethodID getValuesMethod = (*env)->GetMethodID(env, ndarrayClass, "getValues", "()[D"); + + jintArray jdims = (*env)->CallObjectMethod(env, value, dimsMethod); + jsize ndims = (*env)->GetArrayLength(env, jdims); + jint *dims = (*env)->GetIntArrayElements(env, jdims, NULL); + + jdoubleArray jvalues = (*env)->CallObjectMethod(env, value, getValuesMethod); + jsize len = (*env)->GetArrayLength(env, jvalues); + jdouble *values = (*env)->GetDoubleArrayElements(env, jvalues, NULL); + + npy_intp *pyDims = (npy_intp*)malloc(ndims * sizeof(npy_intp)); + + jint i, nelem = ndims > 0 ? 1 : 0; + for (i = 0; i < ndims; i++) { + nelem *= dims[i]; + pyDims[i] = dims[i]; + } + + len = min(len, nelem); + + { + PyObject *array = PyArray_EMPTY(ndims, pyDims, NPY_DOUBLE, 0); + double *data = (double *)PyArray_DATA((PyArrayObject*)array); + + memcpy(data, values, len * sizeof(double)); + + free(pyDims); + + (*env)->ReleaseDoubleArrayElements(env, jvalues, values, JNI_ABORT); + (*env)->ReleaseIntArrayElements(env, jdims, dims, JNI_ABORT); + + return array; + } +} + +PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z"); + + jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object); + return getPythonBool(bvalue); +} + +PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B"); + + jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object); + return PyLong_FromLong(v); +} + +PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I"); + + jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object); + return PyLong_FromLong(v); +} + +PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J"); + + jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object); + return PyLong_FromLongLong(v); +} + +PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F"); + + jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object); + return PyFloat_FromDouble(v); +} + +PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D"); + + jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object); + return PyFloat_FromDouble(v); +} + +PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";"); + + jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object); + jsize len = (*env)->GetStringLength(env, string); + const jchar *chars = (*env)->GetStringChars(env, string, NULL); + + PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL); + + (*env)->ReleaseStringChars(env, string, chars); + return value; +} + +PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS); + jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";"); + jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";"); + jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";"); + + jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS); + jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";"); + jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I"); + + jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS); + jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";"); + + jobject type = (*env)->CallObjectMethod(env, binding, typeMethod); + jint n = (*env)->CallIntMethod(env, type, getComponentCount); + jint i; + + PyObject *result = PyDict_New(); + for (i = 0; i < n; i++) { + jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i); + jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField); + jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i); + jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i); + + PyObject *item = getPythonObject(env, componentObject, componentBinding); + PyDict_SetItem(result, getPythonString(env, fieldName), item); + } + + return result; +} + +PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS); + jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";"); + jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I"); + jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";"); + + jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod); + + jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object); + + PyObject *result = PyList_New(size); + + jint i; + for (i = 0; i < size; i++) { + jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i); + if (item != NULL) + PyList_SetItem(result, i, getPythonObject(env, item, componentBinding)); + else + PyList_SetItem(result, i, Py_None); + } + + return result; +} + +PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) { + jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS); + jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS); + jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";"); + jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";"); + jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I"); + jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V"); + + jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod); + jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod); + + jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object); + jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL); + jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL); + + PyObject *result = PyDict_New(); + jint i; + + (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values); + + for (i = 0; i < size; i++) { + jobject key = (*env)->GetObjectArrayElement(env, keys, i); + jobject item = (*env)->GetObjectArrayElement(env, values, i); + PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding)); + } + + (*env)->DeleteLocalRef(env, keys); + (*env)->DeleteLocalRef(env, values); + + return result; +} + +PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS); + jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z"); + + jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object); + + if (hasValue) { + jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";"); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); + + jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod); + jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object); + + return getPythonObject(env, value, componentBinding); + } + else { + return Py_None; + } +} + +PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS); + jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";"); + jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I"); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); + jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";"); + + jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS); + jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";"); + + jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS); + jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";"); + + jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object); + jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object); + + jobject type = (*env)->CallObjectMethod(env, binding, typeMethod); + jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag); + jstring compName = (*env)->GetObjectField(env, typeComponent, nameField); + + jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag); + + PyObject *result = PyTuple_New(2); + PyTuple_SetItem(result, 0, getPythonString(env, compName)); + PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding)); + + return result; +} + +PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS); + jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); + jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";"); + + jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object); + jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object); + + return getPythonObject(env, content, contentBinding); +} + +PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) { + jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS); + jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS); + jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS); + jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS); + jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS); + jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS); + jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS); + jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS); + jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS); + jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS); + jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS); + jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS); + jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS); + + if (value == NULL) + return Py_None; + + if ((*env)->IsInstanceOf(env, binding, booleanBinding)) { + return getPythonBooleanObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, byteBinding)) { + return getPythonByteObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, integerBinding)) { + return getPythonIntegerObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, longBinding)) { + return getPythonLongObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, floatBinding)) { + return getPythonFloatObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) { + return getPythonDoubleObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, stringBinding)) { + return getPythonStringObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, recordBinding)) { + return getPythonRecordObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) { + return getPythonArrayObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, mapBinding)) { + return getPythonMapObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) { + return getPythonOptionalObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, untionBinding)) { + return getPythonUnionObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, variantBinding)) { + return getPythonVariantObject(env, value, binding); + } + else { + return Py_None; + } +} + +void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) { + if (name && value) { + PyDict_SetItem(PyModule_GetDict(module), name, value); + } + + Py_XDECREF(name); + Py_XDECREF(value); +} + +static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) { + if (d == nd) { + ncont[d] = 1; + return 1; + } + else { + npy_intp n = nContiguous(d+1, nd, strides, dims, ncont); + ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0; + return ncont[d]; + } +} + +static void copyDoubleArrayValues(JNIEnv *env, jdoubleArray array, double *data, npy_intp *offset, int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) { + if (ncont[d] > 0) { + (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data); + *offset += ncont[d]; + } + else { + int i; + for (i = 0; i < dims[d]; i++) { + copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont); + } + } +} + +jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) { + jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean"); + jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;"); + + return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True)); +} + +jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) { + jclass longClass = (*env)->FindClass(env, "java/lang/Long"); + jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;"); + + return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value)); +} + +jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) { + jclass doubleClass = (*env)->FindClass(env, "java/lang/Double"); + jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;"); + + return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value)); +} + +jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) { + Py_ssize_t size = PyByteArray_Size(value); + jbyteArray result = (*env)->NewByteArray(env, (jsize)size); + char *bytes = PyByteArray_AsString(value); + + (*env)->SetByteArrayRegion(env, result, 0, size, bytes); + + return result; +} + +jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) { + PyObject *utf16Value = PyUnicode_AsUTF16String(string); + Py_ssize_t len = PyBytes_Size(utf16Value) / 2; + char *bytes = PyBytes_AsString(utf16Value); + + // Create Java string, skipping the byte order mark in the beginning + jstring result = (*env)->NewString(env, (jchar *)bytes + 1, (jsize)min(len, JAVA_MAXINT) - 1); + + Py_XDECREF(utf16Value); + + return result; +} + +jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); + jsize jlen = (jsize)min(len, JAVA_MAXINT); + jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL); + + jint i; + + for (i = 0; i < jlen; i++) { + PyObject *item = PySequence_GetItem(seq, i); + if (PyUnicode_Check(item)) { + jstring value = pythonStringAsJavaString(env, item); + (*env)->SetObjectArrayElement(env, array, i, value); + } + else { + throwPythonException(env, "List item not a string"); + return NULL; + } + } + + return array; +} + +jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); + jsize jlen = (jsize)min(len, JAVA_MAXINT); + jdoubleArray array = (*env)->NewDoubleArray(env, jlen); + + jint i; + + for (i = 0; i < jlen; i++) { + PyObject *item = PySequence_GetItem(seq, i); + if (PyFloat_Check(item)) { + double value = PyFloat_AsDouble(item); + (*env)->SetDoubleArrayRegion(env, array, i, 1, &value); + } + else { + throwPythonException(env, "List item not a floating point value"); + return NULL; + } + } + + return array; +} + +jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) { + if (PyBool_Check(value)) + return pythonBoolAsBooleanObject(env, value); + else if (PyLong_Check(value)) + return pythonLongAsLongObject(env, value); + else if (PyFloat_Check(value)) + return pythonFloatAsDoubleObject(env, value); + else if (PyUnicode_Check(value)) + return pythonStringAsJavaString(env, value); + else if (PyByteArray_Check(value)) + return pythonByteArrayAsByteArray(env, value); + else if (PyDict_Check(value)) + return pythonDictionaryAsMap(env, value); + else if (hasNumpy && PyArray_Check(value)) + return pythonArrayAsNDArray(env, (PyArrayObject *)value); + else if (PySequence_Check(value)) + return pythonSequenceAsObjectArray(env, value); + else + return NULL; +} + +jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); + jsize jlen = (jsize)min(len, JAVA_MAXINT); + jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL); + + jint i; + + for (i = 0; i < jlen; i++) { + PyObject *item = PySequence_GetItem(seq, i); + jobject object = pythonObjectAsObject(env, item); + (*env)->SetObjectArrayElement(env, array, i, object); + } + + return array; +} + +jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); + jsize jlen = (jsize)min(len, JAVA_MAXINT); + jbooleanArray array = (*env)->NewBooleanArray(env, jlen); + + jint i; + + for (i = 0; i < jlen; i++) { + PyObject *item = PySequence_GetItem(seq, i); + if (PyBool_Check(item)) { + jboolean value = item == Py_True; + (*env)->SetBooleanArrayRegion(env, array, i, 1, &value); + } + else { + throwPythonException(env, "List item not a boolean"); + return NULL; + } + } + + return array; +} + +jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); + jsize jlen = (jsize)min(len, JAVA_MAXINT); + jintArray array = (*env)->NewIntArray(env, jlen); + + jint i; + + for (i = 0; i < jlen; i++) { + PyObject *item = PySequence_GetItem(seq, i); + if (PyLong_Check(item)) { + jint value = PyLong_AsLong(item); + (*env)->SetIntArrayRegion(env, array, i, 1, &value); + } + else { + throwPythonException(env, "List item not an integer"); + return NULL; + } + } + + return array; +} + +jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); + jsize jlen = (jsize)min(len, JAVA_MAXINT); + jlongArray array = (*env)->NewLongArray(env, jlen); + + jint i; + + for (i = 0; i < jlen; i++) { + PyObject *item = PySequence_GetItem(seq, i); + if (PyLong_Check(item)) { + jlong value = PyLong_AsLongLong(item); + (*env)->SetLongArrayRegion(env, array, i, 1, &value); + } + else { + throwPythonException(env, "List item not an integer"); + return NULL; + } + } + + return array; +} + +jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) { + jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS); + jmethodID constructor = (*env)->GetMethodID(env, ndarrayClass, "", "([I[D)V"); + + int ndims = PyArray_NDIM(array); + npy_intp *dims = PyArray_DIMS(array); + + npy_intp len = PyArray_Size((PyObject*)array); + double *values = (double*)PyArray_DATA(array); + + jboolean isFortran = PyArray_ISFORTRAN(array) != 0; + + int i; + + if (len > JAVA_MAXINT) { + throwPythonException(env, "Array too large"); + return NULL; + } + + { + jintArray jdims = (*env)->NewIntArray(env, ndims); + jdoubleArray jvalues = (*env)->NewDoubleArray(env, (jsize)len); + + for (i = 0; i < ndims; i++) { + jint dim = (jint)dims[i]; + (*env)->SetIntArrayRegion(env, jdims, i, 1, &dim); + } + + if (PyArray_IS_C_CONTIGUOUS(array)) { + (*env)->SetDoubleArrayRegion(env, jvalues, 0, (jsize)len, values); + } + else { + npy_intp offset = 0; + npy_intp *strides = PyArray_STRIDES(array); + npy_intp *ncont = (npy_intp*)malloc((ndims + 1) * sizeof(npy_intp)); + nContiguous(0, ndims, strides, dims, ncont); + copyDoubleArrayValues(env, jvalues, values, &offset, 0, ndims, strides, dims, ncont); + free(ncont); + } + + return (*env)->NewObject(env, ndarrayClass, constructor, jdims, jvalues, isFortran); + } +} + +jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) { + jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap"); + jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "", "(I)V"); + jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); + + Py_ssize_t size = PyDict_Size(dict); + jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size); + + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next(dict, &pos, &key, &value)) { + jobject keyObject = pythonObjectAsObject(env, key); + jobject valueObject = pythonObjectAsObject(env, value); + (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject); + } + + return map; +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jboolean value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonBool(value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jbooleanArray value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonBooleanList(env, value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlong value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = PyLong_FromLongLong(value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jintArray value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonIntegerList(env, value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlongArray value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonLongList(env, value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdouble value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = PyFloat_FromDouble(value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonFloatArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jfloatArray value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonFloatList(env, value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdoubleArray value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonDoubleList(env, value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jstring value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonString(env, value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobjectArray value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonStringList(env, value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value) { + PyObject *module = (PyObject*)contextID; + + if (!hasNumpy) { + throwPythonException(env, "Importing numpy failed"); + return; + } + + { + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonNDArray(env, value); + + setPythonVariable(module, pythonName, val); + } +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value, jobject binding) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonObject(env, value, binding); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) { + PyObject *module = (PyObject*)contextID; + + const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL); + + PyEval_RestoreThread(main_ts); + PyErr_Clear(); + { + PyObject *globals; + + globals = PyModule_GetDict(module); + + { + PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals); + + PyObject *exceptionType = PyErr_Occurred(); + if (exceptionType != NULL) { + PyObject *exception, *traceback; + PyErr_Fetch(&exceptionType, &exception, &traceback); + + { + PyObject *tracebackModule = PyImport_ImportModule("traceback"); + if (tracebackModule != NULL) { + PyObject *formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception"); + if (formatExc != NULL) { + PyObject *args = PyTuple_Pack(3, exceptionType, exception, traceback); + PyObject *message = PyObject_CallObject(formatExc, args); + if (message != NULL) { + PyObject *emptyStr = PyUnicode_FromString(""); + PyObject *joined = PyUnicode_Join(emptyStr, message); + char *messageStr = PyUnicode_AsUTF8(joined); + throwPythonException(env, messageStr); + Py_DECREF(joined); + Py_DECREF(emptyStr); + Py_DECREF(message); + } + else { + throwPythonException(env, "Internal error, no message"); + } + Py_DECREF(args); + Py_DECREF(formatExc); + } + else { + throwPythonException(env, "Internal error, no format_exc function"); + } + Py_DECREF(tracebackModule); + } + else { + throwPythonException(env, "Internal error, no traceback module"); + } + } + } + + PyEval_SaveThread(); + (*env)->ReleaseStringUTFChars(env, statement, utfchars); + + return result != NULL ? 0 : 1; + } + } +} + +JNIEXPORT jstring JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return 0; + } + + if (!PyUnicode_Check(value)) { + throwPythonException(env, "Python variable not a string"); + return 0; + } + + { + jstring result = pythonStringAsJavaString(env, value); + return result; + } +} + +JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return 0; + } + + if (!PySequence_Check(value)) { + throwPythonException(env, "Python variable not a sequence"); + return 0; + } + + { + jobjectArray result = pythonSequenceAsStringArray(env, value); + return result; + } +} + +JNIEXPORT jboolean JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return 0; + } + + if (!PyBool_Check(value)) { + throwPythonException(env, "Python variable not a boolean"); + return 0; + } + + return value == Py_True; +} + +JNIEXPORT jbooleanArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return 0; + } + + if (!PySequence_Check(value)) { + throwPythonException(env, "Python variable not a sequence"); + return 0; + } + + { + jbooleanArray result = pythonSequenceAsBooleanArray(env, value); + return result; + } +} + +JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return 0; + } + + if (!PyLong_Check(value)) { + throwPythonException(env, "Python variable not an integer"); + return 0; + } + + { + jlong result = PyLong_AsLongLong(value); + return result; + } +} + +JNIEXPORT jintArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return NULL; + } + + if (!PySequence_Check(value)) { + throwPythonException(env, "Python variable not a sequence"); + return NULL; + } + + { + jintArray result = pythonSequenceAsIntegerArray(env, value); + return result; + } +} + +JNIEXPORT jlongArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return NULL; + } + + if (!PySequence_Check(value)) { + throwPythonException(env, "Python variable not a sequence"); + return NULL; + } + + { + jlongArray result = pythonSequenceAsLongArray(env, value); + return result; + } +} + +JNIEXPORT jdouble JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return 0.0; + } + + if (!PyFloat_Check(value)) { + throwPythonException(env, "Python variable not a float"); + return 0.0; + } + + { + jdouble result = PyFloat_AsDouble(value); + return result; + } +} + +JNIEXPORT jdoubleArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return NULL; + } + + if (!PySequence_Check(value)) { + throwPythonException(env, "Python variable not a sequence"); + return NULL; + } + + { + jdoubleArray result = pythonSequenceAsDoubleArray(env, value); + return result; + } +} + +JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + if (!hasNumpy) { + throwPythonException(env, "Importing numpy failed"); + return NULL; + } + + { + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return NULL; + } + + if (!PyArray_Check(value)) { + throwPythonException(env, "Python variable not an ndarray"); + return NULL; + } + + if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) { + throwPythonException(env, "Only ndarrays of type double are supported"); + return NULL; + } + + { + jobject result = pythonArrayAsNDArray(env, (PyArrayObject *)value); + return result; + } + } +} + +JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return NULL; + } + + hasNumpy = _import_array() != -1; + + { + jobject result = pythonObjectAsObject(env, value); + return result; + } +} + +JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + PyObject *dict = PyModule_GetDict(module); + + PyObject *pythonName = getPythonString(env, variableName); + + if (!PyDict_Contains(dict, pythonName)) { + return 0; + } + + { + PyObject *value = PyDict_GetItem(dict, pythonName); + + jint result; + + if (PyBool_Check(value)) + result = 1; + else if (PyLong_Check(value)) + result = 2; + else if (PyFloat_Check(value)) + result = 3; + else if (PyUnicode_Check(value)) + result = 4; + else if (PyByteArray_Check(value)) + result = 5; + else if (PyDict_Check(value)) + result = 6; + else if (hasNumpy && PyArray_Check(value)) + result = 7; + else if (PySequence_Check(value)) + result = 8; + else + result = -1; + + return result; + } +} + +JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(JNIEnv *env, jobject thisObj, jlong contextID) { + PyObject *module = (PyObject*)contextID; + PyObject *dict = PyModule_GetDict(module); + + PyObject *keys = PyDict_Keys(dict); + Py_ssize_t size = PyList_Size(keys); + + jobjectArray result = (*env)->NewObjectArray(env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL); + + Py_ssize_t i; + for (i = 0; i < size; i++) { + jstring javaName = pythonStringAsJavaString(env, PyList_GetItem(keys, i)); + (*env)->SetObjectArrayElement(env, result, (jint)i, javaName); + } + + Py_XDECREF(keys); + + return result; +} + +BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +//extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + // attach to process + // return FALSE to fail DLL load + break; + + case DLL_PROCESS_DETACH: + // detach from process + break; + + case DLL_THREAD_ATTACH: + // attach to thread + break; + + case DLL_THREAD_DETACH: + // detach from thread + break; + } + return TRUE; // succesful +}