]> gerrit.simantics Code Review - simantics/python.git/blob - org.simantics.pythonlink.win32.x86_64/src/sclpy.c
Plug leaks from PySequence_GetItem.
[simantics/python.git] / org.simantics.pythonlink.win32.x86_64 / src / sclpy.c
1 ///////////////////////////////////////////////////////
2 //                                                   //
3 //   VTT Technical Research Centre of Finland LTD    //
4 //   For internal use only. Do not redistribute.     //
5 //                                                   //
6 //   Authors:                                        //
7 //       Antton Tapani    ext-antton.tapani@vtt.fi   //
8 //                                                   //
9 //   Last modified by Antton Tapani    9.2016        //
10 //                                                   //
11 ///////////////////////////////////////////////////////
12
13 #include "sclpy.h"
14
15 #include <windows.h>
16
17 jint throwException( JNIEnv *env, char *className, const char *message )
18 {
19     jclass exClass = (*env)->FindClass( env, className);
20     if (exClass == NULL) {
21         return 0;
22     }
23
24     return (*env)->ThrowNew( env, exClass, message );
25 }
26
27 jint throwPythonException( JNIEnv *env, const char *message ) {
28         return throwException( env, PYTHON_EXCEPTION, message );
29 }
30
31 jint throwIllegalArgumentException( JNIEnv *env, const char *message ) {
32         return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message );
33 }
34
35 PyObject* getModule(jlong contextID) {
36         return PyState_FindModule((PyModuleDef*) contextID);
37 //      return PyImport_AddModule("__main__");
38 }
39
40 int moduleCount = 0;
41 int hasNumpy = 0;
42 PyThreadState *main_ts = 0;
43
44 static JNIEnv *currentEnv = NULL;
45 jobject sclWriter = NULL;
46
47 static PyObject *
48 writeToSCL(PyObject *self, PyObject *args)
49 {
50     if (currentEnv != NULL && sclWriter != NULL) {
51                 Py_UNICODE *what;
52                 Py_ssize_t length;
53         JNIEnv *env = currentEnv;
54
55                 if (!PyArg_ParseTuple(args, "u#", &what, &length))
56                         Py_RETURN_NONE;
57
58                 {
59                         PyThreadState *my_ts = PyThreadState_Get();
60                         if (my_ts == main_ts) {
61                                 jclass writerClass = (*env)->FindClass(env, WRITER_CLASS);
62                                 jmethodID writeMethod = (*env)->GetMethodID(env, writerClass, "write", "([CII)V");
63                                 jcharArray chars = (*env)->NewCharArray(env, (jsize)length);
64
65                                 (*env)->SetCharArrayRegion(env, chars, 0, length, what);
66                                 Py_BEGIN_ALLOW_THREADS
67                                 (*env)->CallVoidMethod(env, sclWriter, writeMethod, chars, 0, length);
68                                 Py_END_ALLOW_THREADS
69                         } else {
70                                 //TODO
71                         }
72                 }
73     }
74
75         Py_RETURN_NONE;
76 }
77
78 static PyObject *
79 flushSCL(PyObject *self, PyObject *args)
80 {
81     if (currentEnv != NULL && sclWriter != NULL) {
82         JNIEnv *env = currentEnv;
83         PyThreadState *my_ts = PyThreadState_Get();
84         if (my_ts != main_ts) {
85                 // TODO: Process calls from other threads
86                         Py_RETURN_NONE;
87         }
88
89         {
90                         jclass writerClass = (*env)->FindClass(env, WRITER_CLASS);
91                         jmethodID flushMethod = (*env)->GetMethodID(env, writerClass, "flush", "()V");
92
93                 Py_BEGIN_ALLOW_THREADS
94                         (*env)->CallVoidMethod(env, sclWriter, flushMethod);
95                         Py_END_ALLOW_THREADS
96         }
97     }
98
99     Py_RETURN_NONE;
100 }
101
102 static PyMethodDef sclWriterMethods[] = {
103     {"write", writeToSCL, METH_VARARGS, "Write something."},
104         {"flush", flushSCL, METH_VARARGS, "Flush output."},
105     {NULL, NULL, 0, NULL}
106 };
107
108 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_initializePython(JNIEnv *env, jobject thisObj, jobject writer) {
109     Py_Initialize();
110
111     {
112         static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods, };
113                 PyObject *m = PyModule_Create(&moduledef);
114
115         sclWriter = (*env)->NewGlobalRef(env, writer);
116
117         if (m == NULL) throwException(env, PYTHON_EXCEPTION, "Failed to create SCL writer module");
118
119                 PySys_SetObject("stdout", m);
120                 PySys_SetObject("stderr", m);
121     }
122
123         hasNumpy = _import_array();
124         hasNumpy = hasNumpy != -1;
125
126         main_ts = PyEval_SaveThread();
127 }
128
129 JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {
130         char name[16];
131
132         if (!main_ts) {
133                 return 0;
134         }
135
136         sprintf(name, "SCL_%d", ++moduleCount);
137
138         PyEval_RestoreThread(main_ts);
139         {
140                 PyObject *module;
141                 PyModuleDef *modDef = malloc(sizeof(PyModuleDef));
142                 memset(modDef, 0, sizeof(PyModuleDef));
143                 modDef->m_name = strdup(name);
144                 modDef->m_doc = NULL;
145                 modDef->m_size = -1;
146
147                 module = PyModule_Create(modDef);
148                 Py_INCREF(module);
149                 PyState_AddModule(module, modDef);
150
151                 {
152                         PyObject *builtin = PyImport_AddModule("builtins");
153                         PyObject *dict = PyModule_GetDict(module);
154                         PyDict_SetItemString(dict, "__builtin__", builtin);
155                         PyDict_SetItemString(dict, "__builtins__", builtin);
156
157                         PyEval_SaveThread();
158                         return (jlong)modDef;
159                 }
160         }
161 }
162
163 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) {
164         PyModuleDef *modDef = (PyModuleDef*)contextID;
165         PyObject *module;
166         PyEval_RestoreThread(main_ts);
167         module = PyState_FindModule(modDef);
168         Py_XDECREF(module);
169         PyState_RemoveModule(modDef);
170         free((char*)modDef->m_name);
171         free(modDef);
172         PyEval_SaveThread();
173 }
174
175 PyObject *getPythonBool(jboolean value) {
176         if (value) {
177                 Py_RETURN_TRUE;
178         }
179         else {
180                 Py_RETURN_FALSE;
181         }
182 }
183
184 PyObject *getPythonString(JNIEnv *env, jstring string) {
185         jsize len = (*env)->GetStringLength(env, string);
186         const jchar *chars = (*env)->GetStringChars(env, string, NULL);
187
188         PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
189
190         (*env)->ReleaseStringChars(env, string, chars);
191         return value;
192 }
193
194 PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) {
195         jsize nitems = (*env)->GetArrayLength(env, value);
196         jint *values = (*env)->GetIntArrayElements(env, value, NULL);
197         jclass stringClass = (*env)->FindClass(env, STRING_CLASS);
198         jint i;
199
200         PyObject *result = PyList_New(nitems);
201         for (i = 0; i < nitems; i++) {
202                 jobject item = (*env)->GetObjectArrayElement(env, value, i);
203                 if (item != NULL && (*env)->IsInstanceOf(env, item, stringClass)) {
204                         PyList_SetItem(result, i, getPythonString(env, (jstring)item));
205                 }
206                 else {
207                         PyList_SetItem(result, i, Py_None);
208                 }
209         }
210
211         (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
212         return result;
213 }
214
215 PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) {
216         jsize nitems = (*env)->GetArrayLength(env, value);
217         jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL);
218         jint i;
219
220         PyObject *result = PyList_New(nitems);
221         for (i = 0; i < nitems; i++) {
222                 PyList_SetItem(result, i, getPythonBool(values[i]));
223         }
224
225         (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT);
226         return result;
227 }
228
229 PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) {
230         jint len = (*env)->GetArrayLength(env, value);
231         jbyte *values = (*env)->GetByteArrayElements(env, value, NULL);
232
233         PyObject *result = PyByteArray_FromStringAndSize(values, len);
234
235         (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT);
236         return result;
237 }
238
239 PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) {
240         jsize nitems = (*env)->GetArrayLength(env, value);
241         jint *values = (*env)->GetIntArrayElements(env, value, NULL);
242         jint i;
243
244         PyObject *result = PyList_New(nitems);
245         for (i = 0; i < nitems; i++) {
246                 PyList_SetItem(result, i, PyLong_FromLong(values[i]));
247         }
248
249         (*env)->ReleaseIntArrayElements(env, value, values, JNI_ABORT);
250         return result;
251 }
252
253 PyObject *getPythonLongList(JNIEnv *env, jlongArray value) {
254         jsize nitems = (*env)->GetArrayLength(env, value);
255         jlong *values = (*env)->GetLongArrayElements(env, value, NULL);
256         jint i;
257
258         PyObject *result = PyList_New(nitems);
259         for (i = 0; i < nitems; i++) {
260                 PyList_SetItem(result, i, PyLong_FromLongLong(values[i]));
261         }
262
263         (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT);
264         return result;
265 }
266
267 PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) {
268         jsize nitems = (*env)->GetArrayLength(env, value);
269         float *values = (*env)->GetFloatArrayElements(env, value, NULL);
270         jint i;
271
272         PyObject *result = PyList_New(nitems);
273         for (i = 0; i < nitems; i++) {
274                 PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i]));
275         }
276
277         (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT);
278         return result;
279 }
280
281 PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) {
282         jsize nitems = (*env)->GetArrayLength(env, value);
283         double *values = (*env)->GetDoubleArrayElements(env, value, NULL);
284         jint i;
285
286         PyObject *result = PyList_New(nitems);
287         for (i = 0; i < nitems; i++) {
288                 PyList_SetItem(result, i, PyFloat_FromDouble(values[i]));
289         }
290
291         (*env)->ReleaseDoubleArrayElements(env, value, values, JNI_ABORT);
292         return result;
293 }
294
295 PyObject *getPythonNDArray(JNIEnv *env, jobject value) {
296         jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
297         jmethodID dimsMethod = (*env)->GetMethodID(env, ndarrayClass, "dims", "()[I");
298         jmethodID getValuesMethod = (*env)->GetMethodID(env, ndarrayClass, "getValues", "()[D");
299
300         jintArray jdims = (*env)->CallObjectMethod(env, value, dimsMethod);
301         jsize ndims = (*env)->GetArrayLength(env, jdims);
302         jint *dims = (*env)->GetIntArrayElements(env, jdims, NULL);
303
304         jdoubleArray jvalues = (*env)->CallObjectMethod(env, value, getValuesMethod);
305         jsize len = (*env)->GetArrayLength(env, jvalues);
306         jdouble *values = (*env)->GetDoubleArrayElements(env, jvalues, NULL);
307
308         npy_intp *pyDims = (npy_intp*)malloc(ndims * sizeof(npy_intp));
309
310         jint i, nelem = ndims > 0 ? 1 : 0;
311         for (i = 0; i < ndims; i++) {
312                 nelem *= dims[i];
313                 pyDims[i] = dims[i];
314         }
315
316         len = min(len, nelem);
317
318         {
319                 PyObject *array = PyArray_EMPTY(ndims, pyDims, NPY_DOUBLE, 0);
320                 double *data = (double *)PyArray_DATA((PyArrayObject*)array);
321
322                 memcpy(data, values, len * sizeof(double));
323
324                 free(pyDims);
325
326                 (*env)->ReleaseDoubleArrayElements(env, jvalues, values, JNI_ABORT);
327                 (*env)->ReleaseIntArrayElements(env, jdims, dims, JNI_ABORT);
328
329                 return array;
330         }
331 }
332
333 PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) {
334         jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
335         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z");
336
337         jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object);
338         return getPythonBool(bvalue);
339 }
340
341 PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) {
342         jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS);
343         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B");
344
345         jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object);
346         return PyLong_FromLong(v);
347 }
348
349 PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) {
350         jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS);
351         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I");
352
353         jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object);
354         return PyLong_FromLong(v);
355 }
356
357 PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) {
358         jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS);
359         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J");
360
361         jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object);
362         return PyLong_FromLongLong(v);
363 }
364
365 PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) {
366         jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS);
367         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F");
368
369         jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object);
370         return PyFloat_FromDouble(v);
371 }
372
373 PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) {
374         jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
375         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D");
376
377         jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object);
378         return PyFloat_FromDouble(v);
379 }
380
381 PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) {
382         jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS);
383         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";");
384
385         jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
386         jsize len = (*env)->GetStringLength(env, string);
387         const jchar *chars = (*env)->GetStringChars(env, string, NULL);
388
389         PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);
390
391         (*env)->ReleaseStringChars(env, string, chars);
392         return value;
393 }
394
395 PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) {
396         jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS);
397         jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
398         jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
399         jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
400
401         jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS);
402         jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";");
403         jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I");
404
405         jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
406         jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
407
408         jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
409         jint n = (*env)->CallIntMethod(env, type, getComponentCount);
410         jint i;
411
412         PyObject *result = PyDict_New();
413         for (i = 0; i < n; i++) {
414                 jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i);
415                 jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField);
416                 jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i);
417                 jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i);
418
419                 PyObject *item = getPythonObject(env, componentObject, componentBinding);
420                 PyDict_SetItem(result, getPythonString(env, fieldName), item);
421         }
422
423         return result;
424 }
425
426 PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) {
427         jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS);
428         jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
429         jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
430         jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");
431
432         jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
433
434         jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
435
436         PyObject *result = PyList_New(size);
437
438         jint i;
439         for (i = 0; i < size; i++) {
440                 jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i);
441                 if (item != NULL)
442                         PyList_SetItem(result, i, getPythonObject(env, item, componentBinding));
443                 else
444                         PyList_SetItem(result, i, Py_None);
445         }
446
447         return result;
448 }
449
450 PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) {
451         jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS);
452         jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS);
453         jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";");
454         jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";");
455         jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");
456         jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V");
457
458         jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod);
459         jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod);
460
461         jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);
462         jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL);
463         jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL);
464
465         PyObject *result = PyDict_New();
466         jint i;
467
468         (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values);
469
470         for (i = 0; i < size; i++) {
471                 jobject key = (*env)->GetObjectArrayElement(env, keys, i);
472                 jobject item = (*env)->GetObjectArrayElement(env, values, i);
473                 PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding));
474         }
475
476         (*env)->DeleteLocalRef(env, keys);
477         (*env)->DeleteLocalRef(env, values);
478
479         return result;
480 }
481
482 PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) {
483         jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
484         jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z");
485
486         jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object);
487
488         if (hasValue) {
489                 jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");
490                 jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
491
492                 jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);
493                 jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
494
495                 return getPythonObject(env, value, componentBinding);
496         }
497         else {
498                 return Py_None;
499         }
500 }
501
502 PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) {
503         jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS);
504         jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");
505         jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I");
506         jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
507         jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");
508
509         jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS);
510         jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";");
511
512         jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);
513         jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");
514
515         jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object);
516         jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);
517
518         jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);
519         jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag);
520         jstring compName = (*env)->GetObjectField(env, typeComponent, nameField);
521
522         jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag);
523
524         PyObject *result = PyTuple_New(2);
525         PyTuple_SetItem(result, 0, getPythonString(env, compName));
526         PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding));
527
528         return result;
529 }
530
531 PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) {
532         jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS);
533         jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
534         jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";");
535
536         jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object);
537         jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object);
538
539         return getPythonObject(env, content, contentBinding);
540 }
541
542 PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) {
543         jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS);
544         jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS);
545         jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS);
546         jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS);
547         jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS);
548         jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS);
549         jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS);
550         jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS);
551         jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS);
552         jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS);
553         jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS);
554         jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS);
555         jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS);
556
557         if (value == NULL)
558                 return Py_None;
559
560         if ((*env)->IsInstanceOf(env, binding, booleanBinding)) {
561                 return getPythonBooleanObject(env, value, binding);
562         }
563         else if ((*env)->IsInstanceOf(env, binding, byteBinding)) {
564                 return getPythonByteObject(env, value, binding);
565         }
566         else if ((*env)->IsInstanceOf(env, binding, integerBinding)) {
567                 return getPythonIntegerObject(env, value, binding);
568         }
569         else if ((*env)->IsInstanceOf(env, binding, longBinding)) {
570                 return getPythonLongObject(env, value, binding);
571         }
572         else if ((*env)->IsInstanceOf(env, binding, floatBinding)) {
573                 return getPythonFloatObject(env, value, binding);
574         }
575         else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) {
576                 return getPythonDoubleObject(env, value, binding);
577         }
578         else if ((*env)->IsInstanceOf(env, binding, stringBinding)) {
579                 return getPythonStringObject(env, value, binding);
580         }
581         else if ((*env)->IsInstanceOf(env, binding, recordBinding)) {
582                 return getPythonRecordObject(env, value, binding);
583         }
584         else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) {
585                 return getPythonArrayObject(env, value, binding);
586         }
587         else if ((*env)->IsInstanceOf(env, binding, mapBinding)) {
588                 return getPythonMapObject(env, value, binding);
589         }
590         else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) {
591                 return getPythonOptionalObject(env, value, binding);
592         }
593         else if ((*env)->IsInstanceOf(env, binding, untionBinding)) {
594                 return getPythonUnionObject(env, value, binding);
595         }
596         else if ((*env)->IsInstanceOf(env, binding, variantBinding)) {
597                 return getPythonVariantObject(env, value, binding);
598         }
599         else {
600                 return Py_None;
601         }
602 }
603
604 void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {
605         if (name && value) {
606                 PyDict_SetItem(PyModule_GetDict(module), name, value);
607         }
608
609         Py_XDECREF(name);
610         Py_XDECREF(value);
611 }
612
613 static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {
614         if (d == nd) {
615                 ncont[d] = 1;
616                 return 1;
617         }
618         else {
619                 npy_intp n = nContiguous(d+1, nd, strides, dims, ncont);
620                 ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0;
621                 return ncont[d];
622         }
623 }
624
625 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) {
626         if (ncont[d] > 0) {
627                 (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data);
628                 *offset += ncont[d];
629         }
630         else {
631                 int i;
632                 for (i = 0; i < dims[d]; i++) {
633                         copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont);
634                 }
635         }
636 }
637
638 jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) {
639         jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean");
640         jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;");
641
642         return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True));
643 }
644
645 jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) {
646         jclass longClass = (*env)->FindClass(env, "java/lang/Long");
647         jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;");
648
649         return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value));
650 }
651
652 jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) {
653         jclass doubleClass = (*env)->FindClass(env, "java/lang/Double");
654         jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;");
655
656         return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value));
657 }
658
659 jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) {
660         Py_ssize_t size = PyByteArray_Size(value);
661         jbyteArray result = (*env)->NewByteArray(env, (jsize)size);
662         char *bytes = PyByteArray_AsString(value);
663
664         (*env)->SetByteArrayRegion(env, result, 0, size, bytes);
665
666         return result;
667 }
668
669 jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) {
670         PyObject *utf16Value = PyUnicode_AsUTF16String(string);
671         Py_ssize_t len = PyBytes_Size(utf16Value) / 2;
672         char *bytes = PyBytes_AsString(utf16Value);
673
674         // Create Java string, skipping the byte order mark in the beginning
675         jstring result = (*env)->NewString(env, (jchar *)bytes + 1, (jsize)min(len, JAVA_MAXINT) - 1);
676
677         Py_XDECREF(utf16Value);
678
679         return result;
680 }
681
682 jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) {
683         Py_ssize_t len = PySequence_Size(seq);
684         jsize jlen = (jsize)min(len, JAVA_MAXINT);
685         jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL);
686
687         jint i;
688
689         for (i = 0; i < jlen; i++) {
690                 PyObject *item = PySequence_GetItem(seq, i);
691                 if (PyUnicode_Check(item)) {
692                         jstring value = pythonStringAsJavaString(env, item);
693                         Py_DECREF(item);
694                         (*env)->SetObjectArrayElement(env, array, i, value);
695                 }
696                 else {
697                         Py_DECREF(item);
698                         throwPythonException(env, "List item not a string");
699                         return NULL;
700                 }
701         }
702
703         return array;
704 }
705
706 jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) {
707         Py_ssize_t len = PySequence_Size(seq);
708         jsize jlen = (jsize)min(len, JAVA_MAXINT);
709         jdoubleArray array = (*env)->NewDoubleArray(env, jlen);
710
711         jint i;
712
713         for (i = 0; i < jlen; i++) {
714                 PyObject *item = PySequence_GetItem(seq, i);
715                 if (PyFloat_Check(item)) {
716                         jdouble value = PyFloat_AsDouble(item);
717                         Py_DECREF(item);
718                         (*env)->SetDoubleArrayRegion(env, array, i, 1, &value);
719                 }
720                 else {
721                         Py_DECREF(item);
722                         throwPythonException(env, "List item not a floating point value");
723                         return NULL;
724                 }
725         }
726
727         return array;
728 }
729
730 jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) {
731         if (PyBool_Check(value))
732                 return pythonBoolAsBooleanObject(env, value);
733         else if (PyLong_Check(value))
734                 return pythonLongAsLongObject(env, value);
735         else if (PyFloat_Check(value))
736                 return pythonFloatAsDoubleObject(env, value);
737         else if (PyUnicode_Check(value))
738                 return pythonStringAsJavaString(env, value);
739         else if (PyByteArray_Check(value))
740                 return pythonByteArrayAsByteArray(env, value);
741         else if (PyDict_Check(value))
742                 return pythonDictionaryAsMap(env, value);
743         else if (hasNumpy && PyArray_Check(value))
744                 return pythonArrayAsNDArray(env, (PyArrayObject *)value);
745         else if (PySequence_Check(value))
746                 return pythonSequenceAsObjectArray(env, value);
747         else
748                 return NULL;
749 }
750
751 jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) {
752         Py_ssize_t len = PySequence_Size(seq);
753         jsize jlen = (jsize)min(len, JAVA_MAXINT);
754         jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL);
755
756         jint i;
757
758         for (i = 0; i < jlen; i++) {
759                 PyObject *item = PySequence_GetItem(seq, i);
760                 jobject object = pythonObjectAsObject(env, item);
761                 Py_DECREF(item);
762                 (*env)->SetObjectArrayElement(env, array, i, object);
763         }
764
765         return array;
766 }
767
768 jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) {
769         Py_ssize_t len = PySequence_Size(seq);
770         jsize jlen = (jsize)min(len, JAVA_MAXINT);
771         jbooleanArray array = (*env)->NewBooleanArray(env, jlen);
772
773         jint i;
774
775         for (i = 0; i < jlen; i++) {
776                 PyObject *item = PySequence_GetItem(seq, i);
777                 if (PyBool_Check(item)) {
778                         jboolean value = item == Py_True;
779                         Py_DECREF(item);
780                         (*env)->SetBooleanArrayRegion(env, array, i, 1, &value);
781                 }
782                 else {
783                         Py_DECREF(item);
784                         throwPythonException(env, "List item not a boolean");
785                         return NULL;
786                 }
787         }
788
789         return array;
790 }
791
792 jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) {
793         Py_ssize_t len = PySequence_Size(seq);
794         jsize jlen = (jsize)min(len, JAVA_MAXINT);
795         jintArray array = (*env)->NewIntArray(env, jlen);
796
797         jint i;
798
799         for (i = 0; i < jlen; i++) {
800                 PyObject *item = PySequence_GetItem(seq, i);
801                 if (PyLong_Check(item)) {
802                         jint value = PyLong_AsLong(item);
803                         Py_DECREF(item);
804                         (*env)->SetIntArrayRegion(env, array, i, 1, &value);
805                 }
806                 else {
807                         Py_DECREF(item);
808                         throwPythonException(env, "List item not an integer");
809                         return NULL;
810                 }
811         }
812
813         return array;
814 }
815
816 jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) {
817         Py_ssize_t len = PySequence_Size(seq);
818         jsize jlen = (jsize)min(len, JAVA_MAXINT);
819         jlongArray array = (*env)->NewLongArray(env, jlen);
820
821         jint i;
822
823         for (i = 0; i < jlen; i++) {
824                 PyObject *item = PySequence_GetItem(seq, i);
825                 if (PyLong_Check(item)) {
826                         jlong value = PyLong_AsLongLong(item);
827                         Py_DECREF(item);
828                         (*env)->SetLongArrayRegion(env, array, i, 1, &value);
829                 }
830                 else {
831                         Py_DECREF(item);
832                         throwPythonException(env, "List item not an integer");
833                         return NULL;
834                 }
835         }
836
837         return array;
838 }
839
840 jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) {
841         jclass ndarrayClass = (*env)->FindClass(env, NDARRAY_CLASS);
842         jmethodID constructor = (*env)->GetMethodID(env, ndarrayClass, "<init>", "([I[D)V");
843
844         int ndims = PyArray_NDIM(array);
845         npy_intp *dims = PyArray_DIMS(array);
846
847         npy_intp len = PyArray_Size((PyObject*)array);
848         double *values = (double*)PyArray_DATA(array);
849
850         jboolean isFortran = PyArray_ISFORTRAN(array) != 0;
851
852         int i;
853
854         if (len > JAVA_MAXINT) {
855                 throwPythonException(env, "Array too large");
856                 return NULL;
857         }
858
859         {
860                 jintArray jdims = (*env)->NewIntArray(env, ndims);
861                 jdoubleArray jvalues = (*env)->NewDoubleArray(env, (jsize)len);
862
863                 for (i = 0; i < ndims; i++) {
864                         jint dim = (jint)dims[i];
865                         (*env)->SetIntArrayRegion(env, jdims, i, 1, &dim);
866                 }
867
868                 if (PyArray_IS_C_CONTIGUOUS(array)) {
869                         (*env)->SetDoubleArrayRegion(env, jvalues, 0, (jsize)len, values);
870                 }
871                 else {
872                         npy_intp offset = 0;
873                         npy_intp *strides = PyArray_STRIDES(array);
874                         npy_intp *ncont = (npy_intp*)malloc((ndims + 1) * sizeof(npy_intp));
875                         nContiguous(0, ndims, strides, dims, ncont);
876                         copyDoubleArrayValues(env, jvalues, values, &offset, 0, ndims, strides, dims, ncont);
877                         free(ncont);
878                 }
879
880                 return (*env)->NewObject(env, ndarrayClass, constructor, jdims, jvalues, isFortran);
881         }
882 }
883
884 jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) {
885         jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap");
886         jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "<init>", "(I)V");
887         jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");
888
889         Py_ssize_t size = PyDict_Size(dict);
890         jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size);
891
892         PyObject *key, *value;
893         Py_ssize_t pos = 0;
894
895         while (PyDict_Next(dict, &pos, &key, &value)) {
896                 jobject keyObject = pythonObjectAsObject(env, key);
897                 jobject valueObject = pythonObjectAsObject(env, value);
898                 (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject);
899         }
900
901         return map;
902 }
903
904 #define DEF_SETTER(typename, jtype, j2py)                               \
905     JNIEXPORT void JNICALL                                              \
906     Java_org_simantics_pythonlink_PythonContext_setPython##typename     \
907     ##VariableImpl(                                                     \
908         JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, \
909         jtype value) {                                                  \
910             PyObject *module;                                           \
911                                                                         \
912             PyEval_RestoreThread(main_ts);                              \
913             module = getModule(contextID);                              \
914             setPythonVariable(module, getPythonString(env, variableName), \
915                               j2py(env, value));                        \
916             PyEval_SaveThread();                                        \
917     }
918
919 #define getPythonBoolean(env, value) getPythonBool(value)
920 #define getPythonLong(env, value) PyLong_FromLongLong(value)
921 #define getPythonDouble(env, value) PyFloat_FromDouble(value)
922
923 DEF_SETTER(Boolean, jboolean, getPythonBoolean)
924 DEF_SETTER(BooleanArray, jbooleanArray, getPythonBooleanList)
925 DEF_SETTER(Long, jlong, getPythonLong)
926 DEF_SETTER(IntegerArray, jintArray, getPythonIntegerList)
927 DEF_SETTER(LongArray, jlongArray, getPythonLongList)
928 DEF_SETTER(Double, jdouble, getPythonDouble)
929 DEF_SETTER(FloatArray, jfloatArray, getPythonFloatList)
930 DEF_SETTER(DoubleArray, jdoubleArray, getPythonDoubleList)
931 DEF_SETTER(String, jstring, getPythonString)
932 DEF_SETTER(StringArray, jobjectArray, getPythonStringList)
933
934 JNIEXPORT void JNICALL
935 Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(
936                 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
937                 jobject value) {
938         if (!hasNumpy) {
939                 throwPythonException(env, "Importing numpy failed");
940                 return;
941         }
942
943         PyEval_RestoreThread(main_ts);
944         {
945                 PyObject *module = getModule(contextID);
946                 PyObject *pythonName = getPythonString(env, variableName);
947                 PyObject *val = getPythonNDArray(env, value);
948
949                 setPythonVariable(module, pythonName, val);
950         }
951         PyEval_SaveThread();
952 }
953
954 JNIEXPORT void JNICALL
955 Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(
956                 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName,
957                 jobject value, jobject binding) {
958         PyObject *module;
959
960         PyEval_RestoreThread(main_ts);
961         module = getModule(contextID);
962         setPythonVariable(module, getPythonString(env, variableName),
963                                           getPythonObject(env, value, binding));
964         PyEval_SaveThread();
965 }
966
967 static PyObject *getExceptionMessage(PyObject *exceptionType, PyObject *exception, PyObject *traceback) {
968         PyObject *formatExc = NULL, *args = NULL;
969         PyObject *tracebackModule = PyImport_ImportModule("traceback");
970         if (!tracebackModule) {
971                 return NULL;
972         }
973
974         if (exception && traceback) {
975                 formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");
976                 args = PyTuple_Pack(3, exceptionType, exception, traceback);
977         }
978         else if (exception) {
979                 formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception_only");
980                 args = PyTuple_Pack(2, exceptionType, exception);
981         }
982
983         Py_DECREF(tracebackModule);
984
985         if (formatExc != NULL && args != NULL) {
986                 PyObject *result = PyObject_CallObject(formatExc, args);
987                 Py_XDECREF(args);
988                 Py_XDECREF(formatExc);
989                 return result;
990         }
991         else {
992                 Py_XDECREF(args);
993                 Py_XDECREF(formatExc);
994                 return NULL;
995         }
996 }
997
998 JNIEXPORT jint JNICALL
999 Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(
1000                 JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {
1001         const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL);
1002
1003         PyEval_RestoreThread(main_ts);
1004         PyErr_Clear();
1005         {
1006                 PyObject *module = getModule(contextID);
1007
1008                 PyObject *globals;
1009
1010                 globals = PyModule_GetDict(module);
1011
1012                 currentEnv = env;
1013
1014                 {
1015                         PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals);
1016
1017                         PyObject *exceptionType = PyErr_Occurred();
1018                         if (exceptionType != NULL) {
1019                                 PyObject *exception, *traceback, *message;
1020                                 PyErr_Fetch(&exceptionType, &exception, &traceback);
1021
1022                                 message = getExceptionMessage(exceptionType, exception, traceback);
1023                                 if (message != NULL) {
1024                                         PyObject *emptyStr = PyUnicode_FromString("");
1025                                         PyObject *joined = PyUnicode_Join(emptyStr, message);
1026                                         char *messageStr = PyUnicode_AsUTF8(joined);
1027                                         throwPythonException(env, messageStr);
1028                                         Py_DECREF(joined);
1029                                         Py_DECREF(emptyStr);
1030                                         Py_DECREF(message);
1031                                 }
1032                                 else {
1033                                         PyTypeObject
1034                                                 *ty = (PyTypeObject *)exceptionType;
1035                                         throwPythonException(
1036                                                         env, ty ? ty->tp_name
1037                                                                         : "Internal error, null exception type");
1038                                 }
1039
1040                                 Py_XDECREF(exceptionType);
1041                                 Py_XDECREF(exception);
1042                                 Py_XDECREF(traceback);
1043                         }
1044
1045                         PyEval_SaveThread();
1046                         (*env)->ReleaseStringUTFChars(env, statement, utfchars);
1047
1048                         currentEnv = NULL;
1049
1050                         return result != NULL ? 0 : 1;
1051                 }
1052         }
1053 }
1054
1055 // Returns a borrowed reference.
1056 static PyObject *getPythonValue(
1057                 JNIEnv *env, jlong contextID, jstring variableName) {
1058         PyObject *module = getModule(contextID);
1059     PyObject *pythonName = getPythonString(env, variableName);
1060     PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);
1061
1062     Py_DECREF(pythonName);
1063     if (value == NULL) {
1064         throwPythonException(env, "Python variable not found");
1065     }
1066     return value;
1067 }
1068
1069 #define DEF_GETTER(typename, jtype, check, desc, py2j)                  \
1070     JNIEXPORT jtype JNICALL                                             \
1071     Java_org_simantics_pythonlink_PythonContext_getPython##typename     \
1072     ##VariableImpl(                                                     \
1073             JNIEnv *env, jobject thisObj, jlong contextID,              \
1074             jstring variableName) {                                     \
1075         jtype result = 0;                                               \
1076         PyEval_RestoreThread(main_ts);                                  \
1077         do {                                                            \
1078             PyObject *value = getPythonValue(env, contextID, variableName); \
1079             if (value == 0) break;                                      \
1080             if (check(value)) {                                         \
1081                 result = py2j(env, value);                              \
1082             } else {                                                    \
1083                 throwPythonException(env, "Python variable not " desc); \
1084             }                                                           \
1085         } while (0);                                                    \
1086         PyEval_SaveThread();                                            \
1087         return result;                                                  \
1088     }
1089
1090 #define pythonBoolAsJboolean(env, value) ((value) == Py_True)
1091 #define pythonLongAsJlong(env, value) PyLong_AsLongLong(value)
1092 #define pythonFloatAsJdouble(env, value) PyFloat_AsDouble(value)
1093
1094 DEF_GETTER(String, jstring, PyUnicode_Check, "a string",
1095                    pythonStringAsJavaString)
1096 DEF_GETTER(StringArray, jobjectArray, PySequence_Check, "a sequence",
1097                    pythonSequenceAsStringArray)
1098 DEF_GETTER(Boolean, jboolean, PyBool_Check, "a Boolean", pythonBoolAsJboolean)
1099 DEF_GETTER(BooleanArray, jbooleanArray, PySequence_Check, "a sequence",
1100                    pythonSequenceAsBooleanArray)
1101 DEF_GETTER(Long, jlong, PyLong_Check, "an integer", pythonLongAsJlong)
1102 DEF_GETTER(IntegerArray, jintArray, PySequence_Check, "a sequence",
1103                    pythonSequenceAsIntegerArray)
1104 DEF_GETTER(LongArray, jlongArray, PySequence_Check, "a sequence",
1105                    pythonSequenceAsLongArray)
1106 DEF_GETTER(Double, jdouble, PyFloat_Check, "a float", pythonFloatAsJdouble)
1107 DEF_GETTER(DoubleArray, jdoubleArray, PySequence_Check, "a sequence",
1108                    pythonSequenceAsDoubleArray)
1109
1110 JNIEXPORT jobject JNICALL
1111 Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(
1112                 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
1113         jobject result = NULL;
1114
1115         if (!hasNumpy) {
1116                 throwPythonException(env, "Importing numpy failed");
1117                 return NULL;
1118         }
1119
1120         PyEval_RestoreThread(main_ts);
1121         do {
1122                 PyObject *value = getPythonValue(env, contextID, variableName);
1123                 if (value == NULL) break;
1124                 if (!PyArray_Check(value)) {
1125                         throwPythonException(env, "Python variable not an ndarray");
1126                 } else if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) {
1127                         throwPythonException(
1128                                         env, "Only ndarrays of type double are supported");
1129                 } else {
1130                         result = pythonArrayAsNDArray(env, (PyArrayObject *)value);
1131                 }
1132         } while (0);
1133         PyEval_SaveThread();
1134         return result;
1135 }
1136
1137 #define python_anything_goes(value) 1
1138
1139 DEF_GETTER(Variant, jobject, python_anything_goes, "frabjous",
1140                    pythonObjectAsObject)
1141
1142 JNIEXPORT jint JNICALL
1143 Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(
1144                 JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {
1145         jint result = 0;
1146         PyEval_RestoreThread(main_ts);
1147         {
1148                 PyObject *value = getPythonValue(env, contextID, variableName);
1149                 if (PyBool_Check(value))
1150                         result = 1;
1151                 else if (PyLong_Check(value))
1152                         result = 2;
1153                 else if (PyFloat_Check(value))
1154                         result = 3;
1155                 else if (PyUnicode_Check(value))
1156                         result = 4;
1157                 else if (PyByteArray_Check(value))
1158                         result = 5;
1159                 else if (PyDict_Check(value))
1160                         result = 6;
1161                 else if (hasNumpy && PyArray_Check(value))
1162                         result = 7;
1163                 else if (PySequence_Check(value))
1164                         result = 8;
1165                 else
1166                         result = -1;
1167         }
1168         PyEval_SaveThread();
1169         return result;
1170 }
1171
1172 JNIEXPORT jobjectArray JNICALL
1173 Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(
1174                 JNIEnv *env, jobject thisObj, jlong contextID) {
1175         jobjectArray result = NULL;
1176         PyEval_RestoreThread(main_ts);
1177         {
1178                 PyObject *module = getModule(contextID);
1179                 PyObject *dict = PyModule_GetDict(module);
1180
1181                 PyObject *keys = PyDict_Keys(dict);
1182                 Py_ssize_t size = PyList_Size(keys);
1183                 Py_ssize_t i;
1184
1185                 result = (*env)->NewObjectArray(
1186                                 env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL);
1187
1188                 for (i = 0; i < size; i++) {
1189                         jstring javaName = pythonStringAsJavaString(
1190                                         env, PyList_GetItem(keys, i));
1191                         (*env)->SetObjectArrayElement(env, result, (jint)i, javaName);
1192                 }
1193
1194                 Py_XDECREF(keys);
1195         }
1196         PyEval_SaveThread();
1197         return result;
1198 }
1199
1200 BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1201 //extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1202 {
1203     switch (fdwReason)
1204     {
1205         case DLL_PROCESS_ATTACH:
1206             // attach to process
1207             // return FALSE to fail DLL load
1208             break;
1209
1210         case DLL_PROCESS_DETACH:
1211             // detach from process
1212             break;
1213
1214         case DLL_THREAD_ATTACH:
1215             // attach to thread
1216             break;
1217
1218         case DLL_THREAD_DETACH:
1219             // detach from thread
1220             break;
1221     }
1222     return TRUE; // succesful
1223 }