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