X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.pythonlink.win32.x86_64%2Fsrc%2Fsclpy.c;h=4881cc7d7c26d4a20979542530230724dc1df5f2;hb=ac16ebed6a3e0932f774ca3ee5963ed776ef6c08;hp=e76719248a28c66322bc4bb56dfc0f772c15412e;hpb=941741c6f7ec4924962c2267b1756ff926559cc4;p=simantics%2Fpython.git diff --git a/org.simantics.pythonlink.win32.x86_64/src/sclpy.c b/org.simantics.pythonlink.win32.x86_64/src/sclpy.c index e767192..4881cc7 100644 --- a/org.simantics.pythonlink.win32.x86_64/src/sclpy.c +++ b/org.simantics.pythonlink.win32.x86_64/src/sclpy.c @@ -14,7 +14,7 @@ #include -jint throwException( JNIEnv *env, char *className, char *message ) +jint throwException( JNIEnv *env, char *className, const char *message ) { jclass exClass = (*env)->FindClass( env, className); if (exClass == NULL) { @@ -24,24 +24,71 @@ jint throwException( JNIEnv *env, char *className, char *message ) return (*env)->ThrowNew( env, exClass, message ); } -jint throwPythonException( JNIEnv *env, char *message ) { +jint throwPythonException( JNIEnv *env, const char *message ) { return throwException( env, PYTHON_EXCEPTION, message ); } -jint throwIllegalArgumentException( JNIEnv *env, char *message ) { +jint throwIllegalArgumentException( JNIEnv *env, const char *message ) { return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message ); } +PyObject* getModule(jlong contextID) { + return PyState_FindModule((PyModuleDef*) contextID); +// return PyImport_AddModule("__main__"); +} + int moduleCount = 0; int hasNumpy = 0; PyThreadState *main_ts = 0; +static JNIEnv *currentEnv = NULL; +jobject sclWriter = NULL; + +static PyObject * +writeToSCL(PyObject *self, PyObject *args) +{ + if (currentEnv != NULL && sclWriter != NULL) { + JNIEnv *env = currentEnv; + + Py_UNICODE *what; + Py_ssize_t length; + if (!PyArg_ParseTuple(args, "u#", &what, &length)) + return Py_BuildValue(""); + + { + jclass writerClass = (*env)->FindClass(env, WRITER_CLASS); + jmethodID writeMethod = (*env)->GetMethodID(env, writerClass, "write", "([CII)V"); + jcharArray chars = (*env)->NewCharArray(env, (jsize)length); + + (*env)->SetCharArrayRegion(env, chars, 0, length, what); + (*env)->CallVoidMethod(env, sclWriter, writeMethod, chars, 0, length); + } + } + + return Py_BuildValue(""); +} + +static PyMethodDef sclWriterMethods[] = { + {"write", writeToSCL, METH_VARARGS, "Write something."}, + {NULL, NULL, 0, NULL} +}; + + JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) { char name[16]; if (!main_ts) { Py_Initialize(); + { + static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods, }; + PyObject *m = PyModule_Create(&moduledef); + + if (m == NULL) throwException(env, PYTHON_EXCEPTION, "Failed to create SCL writer module"); + PySys_SetObject("stdout", m); + PySys_SetObject("stderr", m); + } + hasNumpy = _import_array(); hasNumpy = hasNumpy != -1; main_ts = PyEval_SaveThread(); @@ -51,19 +98,37 @@ JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContex PyEval_RestoreThread(main_ts); { - PyObject *module = PyModule_New(name); - PyObject *main = PyImport_AddModule("__main__"); + PyObject *module; + PyModuleDef *modDef = malloc(sizeof(PyModuleDef)); + memset(modDef, 0, sizeof(PyModuleDef)); + modDef->m_name = strdup(name); + modDef->m_doc = NULL; + modDef->m_size = -1; + + module = PyModule_Create(modDef); + Py_INCREF(module); + PyState_AddModule(module, modDef); - PyDict_Merge(PyModule_GetDict(module), PyModule_GetDict(main), 0); - PyEval_SaveThread(); - return (jlong)module; + { + PyObject *builtin = PyImport_AddModule("builtins"); + PyObject *dict = PyModule_GetDict(module); + PyDict_SetItemString(dict, "__builtin__", builtin); + PyDict_SetItemString(dict, "__builtins__", builtin); + + return (jlong)modDef; + } } } JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) { - PyObject *module = (PyObject*)contextID; + PyModuleDef *modDef = (PyModuleDef*)contextID; + PyObject *module; PyEval_RestoreThread(main_ts); + module = PyState_FindModule(modDef); Py_XDECREF(module); + PyState_RemoveModule(modDef); + free((char*)modDef->m_name); + free(modDef); PyEval_SaveThread(); } @@ -787,11 +852,11 @@ jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) { #define DEF_SETTER(typename, jtype, j2py) \ JNIEXPORT void JNICALL \ - Java_org_simantics_pythonlink_PythonContext_setPython \ - ##typename##VariableImpl( \ + Java_org_simantics_pythonlink_PythonContext_setPython##typename \ + ##VariableImpl( \ JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, \ jtype value) { \ - PyObject *module = (PyObject*)contextID; \ + PyObject *module = getModule(contextID); \ \ PyEval_RestoreThread(main_ts); \ setPythonVariable(module, getPythonString(env, variableName), \ @@ -818,7 +883,7 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl( JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value) { - PyObject *module = (PyObject*)contextID; + PyObject *module = getModule(contextID); if (!hasNumpy) { throwPythonException(env, "Importing numpy failed"); @@ -839,7 +904,7 @@ 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 *module = getModule(contextID); PyEval_RestoreThread(main_ts); setPythonVariable(module, getPythonString(env, variableName), @@ -850,17 +915,27 @@ Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl( JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl( JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) { - PyObject *module = (PyObject*)contextID; + PyObject *module = getModule(contextID); const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL); PyEval_RestoreThread(main_ts); PyErr_Clear(); { + jclass sclReportingWriterClass = (*env)->FindClass(env, SCL_REPORTING_WRITER_CLASS); + jmethodID constructor = (*env)->GetMethodID(env, sclReportingWriterClass, "", "()V"); + jmethodID flushMethod = (*env)->GetMethodID(env, sclReportingWriterClass, "flush", "()V"); + PyObject *globals; globals = PyModule_GetDict(module); + currentEnv = env; + if (sclReportingWriterClass && constructor) + sclWriter = (*env)->NewObject(env, sclReportingWriterClass, constructor); + else + sclWriter = NULL; + { PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals); @@ -886,7 +961,11 @@ Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl( Py_DECREF(message); } else { - throwPythonException(env, "Internal error, no message"); + PyTypeObject + *ty = (PyTypeObject *)exceptionType; + throwPythonException( + env, ty ? ty->tp_name + : "Internal error, null exception type"); } Py_DECREF(args); Py_DECREF(formatExc); @@ -900,279 +979,120 @@ Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl( throwPythonException(env, "Internal error, no traceback module"); } } + Py_XDECREF(exceptionType); + Py_XDECREF(exception); + Py_XDECREF(traceback); } 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 (sclWriter != NULL) { + (*env)->CallVoidMethod(env, sclWriter, flushMethod); + } - if (!PySequence_Check(value)) { - throwPythonException(env, "Python variable not a sequence"); - return NULL; - } + currentEnv = NULL; + sclWriter = NULL; - { - jlongArray result = pythonSequenceAsLongArray(env, value); - return result; + return result != NULL ? 0 : 1; + } } } -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); +// Returns a borrowed reference. +static PyObject *getPythonValue( + JNIEnv *env, jlong contextID, jstring variableName) { + PyObject *module = getModule(contextID); + PyObject *pythonName = getPythonString(env, variableName); + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); - 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; - } + Py_DECREF(pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + } + return value; } -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; - } -} +#define DEF_GETTER(typename, jtype, check, desc, py2j) \ + JNIEXPORT jtype JNICALL \ + Java_org_simantics_pythonlink_PythonContext_getPython##typename \ + ##VariableImpl( \ + JNIEnv *env, jobject thisObj, jlong contextID, \ + jstring variableName) { \ + jtype result = 0; \ + PyEval_RestoreThread(main_ts); \ + do { \ + PyObject *value = getPythonValue(env, contextID, variableName); \ + if (value == 0) break; \ + if (check(value)) { \ + result = py2j(env, value); \ + } else { \ + throwPythonException(env, "Python variable not " desc); \ + } \ + } while (0); \ + PyEval_SaveThread(); \ + return result; \ + } -JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { - PyObject *module = (PyObject*)contextID; +#define pythonBoolAsJboolean(env, value) ((value) == Py_True) +#define pythonLongAsJlong(env, value) PyLong_AsLongLong(value) +#define pythonFloatAsJdouble(env, value) PyFloat_AsDouble(value) + +DEF_GETTER(String, jstring, PyUnicode_Check, "a string", + pythonStringAsJavaString) +DEF_GETTER(StringArray, jobjectArray, PySequence_Check, "a sequence", + pythonSequenceAsStringArray) +DEF_GETTER(Boolean, jboolean, PyBool_Check, "a Boolean", pythonBoolAsJboolean) +DEF_GETTER(BooleanArray, jbooleanArray, PySequence_Check, "a sequence", + pythonSequenceAsBooleanArray) +DEF_GETTER(Long, jlong, PyLong_Check, "an integer", pythonLongAsJlong) +DEF_GETTER(IntegerArray, jintArray, PySequence_Check, "a sequence", + pythonSequenceAsIntegerArray) +DEF_GETTER(LongArray, jlongArray, PySequence_Check, "a sequence", + pythonSequenceAsLongArray) +DEF_GETTER(Double, jdouble, PyFloat_Check, "a float", pythonFloatAsJdouble) +DEF_GETTER(DoubleArray, jdoubleArray, PySequence_Check, "a sequence", + pythonSequenceAsDoubleArray) + +JNIEXPORT jobject JNICALL +Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl( + JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + jobject result = NULL; 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; - } - + PyEval_RestoreThread(main_ts); + do { + PyObject *value = getPythonValue(env, contextID, variableName); + if (value == NULL) break; 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; + } else if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) { + throwPythonException( + env, "Only ndarrays of type double are supported"); + } else { + result = pythonArrayAsNDArray(env, (PyArrayObject *)value); } - } -} - -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; - } + } while (0); + PyEval_SaveThread(); + 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); +#define python_anything_goes(value) 1 - PyObject *pythonName = getPythonString(env, variableName); - - if (!PyDict_Contains(dict, pythonName)) { - return 0; - } +DEF_GETTER(Variant, jobject, python_anything_goes, "frabjous", + pythonObjectAsObject) +JNIEXPORT jint JNICALL +Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl( + JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + jint result = 0; + PyEval_RestoreThread(main_ts); { - PyObject *value = PyDict_GetItem(dict, pythonName); - - jint result; - + PyObject *value = getPythonValue(env, contextID, variableName); if (PyBool_Check(value)) result = 1; else if (PyLong_Check(value)) @@ -1191,28 +1111,36 @@ JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVari result = 8; else result = -1; - - return result; } + PyEval_SaveThread(); + 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); +JNIEXPORT jobjectArray JNICALL +Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl( + JNIEnv *env, jobject thisObj, jlong contextID) { + jobjectArray result = NULL; + PyEval_RestoreThread(main_ts); + { + PyObject *module = getModule(contextID); + PyObject *dict = PyModule_GetDict(module); - jobjectArray result = (*env)->NewObjectArray(env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL); + PyObject *keys = PyDict_Keys(dict); + Py_ssize_t size = PyList_Size(keys); + Py_ssize_t i; - 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); - } + result = (*env)->NewObjectArray( + env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL); - Py_XDECREF(keys); + for (i = 0; i < size; i++) { + jstring javaName = pythonStringAsJavaString( + env, PyList_GetItem(keys, i)); + (*env)->SetObjectArrayElement(env, result, (jint)i, javaName); + } + Py_XDECREF(keys); + } + PyEval_SaveThread(); return result; }