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