diff --git a/.gitignore b/.gitignore index 611da148b..e16a93af7 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,5 @@ C/new_iop.c *.log *.orig + +JIT/HPP/#JIT_In# diff --git a/library/clp/CMakeFiles/progress.marks b/library/clp/CMakeFiles/progress.marks new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/library/clp/CMakeFiles/progress.marks @@ -0,0 +1 @@ +0 diff --git a/packages/python/python.c b/packages/python/python.c index ffb764cce..5e098990d 100644 --- a/packages/python/python.c +++ b/packages/python/python.c @@ -5,53 +5,41 @@ #include #include #ifdef HAVE_STAT -#undef HAVE_STAT +#undef HAVE_STATa #endif #include -static atom_t ATOM_true, - ATOM_colon, - ATOM_false, - ATOM_t; +//@{ -static functor_t FUNCTOR_dollar1, - FUNCTOR_abs1, - FUNCTOR_all1, - FUNCTOR_any1, - FUNCTOR_bin1, - FUNCTOR_dir1, - FUNCTOR_float1, - FUNCTOR_int1, - FUNCTOR_iter1, - FUNCTOR_iter2, - FUNCTOR_long1, - FUNCTOR_len1, - FUNCTOR_curly1, - FUNCTOR_ord1, - FUNCTOR_range1, - FUNCTOR_range2, - FUNCTOR_range3, - FUNCTOR_sum1, - FUNCTOR_pointer1, - FUNCTOR_complex2, - FUNCTOR_plus2, - FUNCTOR_sub2, - FUNCTOR_mul2, - FUNCTOR_div2, - FUNCTOR_hat2, - FUNCTOR_colon2, - FUNCTOR_comma2, - FUNCTOR_equal2; +/** @brief Prolog to Python library +* +* This is a C-library to call Python from Prolog. Although developed +* within YAP, it should work in SWI-Prolog with little work. +* +* Please look at python.pl for more information, and to real.pl and real.c +* for related work. +*/ + +static atom_t ATOM_true, ATOM_false, ATOM_colon, ATOM_dot, ATOM_none, ATOM_t; + +static functor_t FUNCTOR_dollar1, FUNCTOR_abs1, FUNCTOR_all1, FUNCTOR_any1, + FUNCTOR_bin1, FUNCTOR_brackets1, FUNCTOR_comma2, FUNCTOR_dir1, + FUNCTOR_float1, FUNCTOR_int1, FUNCTOR_iter1, FUNCTOR_iter2, FUNCTOR_long1, + FUNCTOR_len1, FUNCTOR_curly1, FUNCTOR_ord1, FUNCTOR_range1, FUNCTOR_range2, + FUNCTOR_range3, FUNCTOR_sum1, FUNCTOR_pointer1, FUNCTOR_complex2, + FUNCTOR_plus2, FUNCTOR_sub2, FUNCTOR_mul2, FUNCTOR_div2, FUNCTOR_hat2, + FUNCTOR_colon2, FUNCTOR_comma2, FUNCTOR_equal2, FUNCTOR_sqbrackets2, + FUNCTOR_dot2; static PyObject *py_Main; static PyObject *term_to_python(term_t t); +static foreign_t python_to_ptr(PyObject *pVal, term_t t); +static PyObject *atom_to_python_string(term_t t); static PyObject *ActiveModules[32]; static int active_modules = 0; -static inline int -proper_ascii_string(char *s) -{ +static inline int proper_ascii_string(char *s) { unsigned char c; while ((c = *s++)) { @@ -61,8 +49,7 @@ proper_ascii_string(char *s) return TRUE; } -static Py_ssize_t -get_p_int(PyObject *o, Py_ssize_t def) { +static Py_ssize_t get_p_int(PyObject *o, Py_ssize_t def) { if (o == NULL) return def; if (PyLong_Check(o)) { @@ -75,17 +62,15 @@ get_p_int(PyObject *o, Py_ssize_t def) { return def; } -static PyObject * -find_obj(PyObject *ob, term_t lhs) -{ +static PyObject *find_obj(PyObject *ob, term_t lhs) { char *s; PyObject *out, *pName; int arity = 0; if (!PL_get_atom_chars(lhs, &s)) { atom_t name; - if (!PL_get_name_arity(lhs, &name, &arity) ) - return NULL; + if (!PL_get_name_arity(lhs, &name, &arity)) + return NULL; s = PL_atom_chars(name); } if (ob) { @@ -93,65 +78,116 @@ find_obj(PyObject *ob, term_t lhs) return out; } if (!ob && !arity) { -#if PY_MAJOR_VERSION<3 - pName = PyString_FromString(s); +#if PY_MAJOR_VERSION < 3 + pName = PyString_FromString(s); #else pName = PyUnicode_FromString(s); #endif if (pName == NULL) { return NULL; } - if (( out = PyImport_Import(pName))) { + if ((out = PyImport_Import(pName))) { return out; } } - if (!ob && py_Main && (out = PyObject_GetAttrString(py_Main, s) ) ) + if (!ob && py_Main && (out = PyObject_GetAttrString(py_Main, s))) return out; return NULL; } -static int -copy_to_dictionary(PyObject *dict, term_t targ, term_t taux) -{ +static int copy_to_dictionary(PyObject *dict, term_t targ, term_t taux) { PyObject *lhs, *rhs; - term_t tleft = taux, tright = tleft; + term_t tleft = PL_new_term_ref(), tright = PL_new_term_ref(); - if (!PL_get_arg(1, targ, tleft)) { - return FALSE; + while (true) { + functor_t fun; + + if (!PL_get_functor(targ, &fun)) + return false; + if (fun == FUNCTOR_comma2) { + if (!PL_get_arg(1, targ, taux)) { + return false; + } + if (!PL_get_arg(1, taux, tleft)) { + return FALSE; + } + lhs = term_to_python(tleft); + if (!PL_get_arg(2, taux, tright)) { + return FALSE; + } + rhs = term_to_python(tright); + if (PyDict_SetItem(dict, lhs, rhs) < 0) { + return FALSE; + } + // PyObject_Print(dict, stderr, 0); fprintf(stderr,"\n"); + Py_DECREF(lhs); + Py_DECREF(rhs); + + if (!PL_get_arg(1, targ, targ)) { + return FALSE; + } + } else { + if (!PL_get_arg(1, targ, tleft)) { + return FALSE; + } + lhs = atom_to_python_string(tleft); + if (!PL_get_arg(2, targ, tright)) { + return FALSE; + } + rhs = term_to_python(tright); + if (PyDict_SetItem(dict, lhs, rhs) < 0) { + return FALSE; + } + // PyObject_Print(dict, stderr, 0); fprintf(stderr,"\n"); + Py_DECREF(lhs); + Py_DECREF(rhs); + break; + } } - lhs = term_to_python(tleft); - if (!PL_get_arg(2, targ, tright)) { - return FALSE; - } - rhs = term_to_python(tright); - if (PyDict_SetItem(dict, lhs, rhs) < 0 ) { - return FALSE; - } - //PyObject_Print(dict, stderr, 0); fprintf(stderr,"\n"); - Py_DECREF(lhs); - Py_DECREF(rhs); return TRUE; } -static PyObject * -bip_abs(term_t t) -{ +/** +* +* @section Python Built-Ins +* +* The Python engine includes a large number of Python built-ins. Some +* of them are interfaced here. +*/ + +//@{ + +/** +* Python abs +* +* @param t Prolog term with a number +* +* @return a Python object with the number's absolute value +*/ + +static PyObject *bip_abs(term_t t) { PyObject *pVal; - if (! PL_get_arg(1, t, t) ) + if (!PL_get_arg(1, t, t)) return NULL; pVal = term_to_python(t); return PyNumber_Absolute(pVal); } -static PyObject * -bip_all(term_t t) -{ +/** +* Python all +* +* @param t Prolog term with a previously constructed Python iterator +* +* @return the Python boolean `True` if all elements of the iterator are `True`, +* `False` otherwise. +*/ +static PyObject *bip_all(term_t t) { PyObject *it, *item, *v; PyObject *(*iternext)(PyObject *); int cmp; - if (! PL_get_arg(1, t, t) ) + if (!PL_get_arg(1, t, t)) return NULL; v = term_to_python(t); it = PyObject_GetIter(v); @@ -185,14 +221,20 @@ bip_all(term_t t) return Py_True; } -static PyObject * -bip_any(term_t t) -{ +/** +* Python any +* +* @param t Prolog term with a previously constructed Python iterator +* +* @return the Python boolean `True` if any element of the iterator is `True`, +* `False` if all of them are false. +*/ +static PyObject *bip_any(term_t t) { PyObject *it, *item, *v; PyObject *(*iternext)(PyObject *); int cmp; - if (! PL_get_arg(1, t, t) ) + if (!PL_get_arg(1, t, t)) return NULL; v = term_to_python(t); it = PyObject_GetIter(v); @@ -225,31 +267,26 @@ bip_any(term_t t) Py_RETURN_FALSE; } -static PyObject * -bip_bin(term_t t) -{ +static PyObject *bip_bin(term_t t) { PyObject *v; - if (! PL_get_arg(1, t, t) ) + if (!PL_get_arg(1, t, t)) return NULL; v = term_to_python(t); return PyNumber_ToBase(v, 2); } - -static PyObject * -bip_float(term_t t) -{ +static PyObject *bip_float(term_t t) { PyObject *pVal, *o; - if (! PL_get_arg(1, t, t) ) + if (!PL_get_arg(1, t, t)) return NULL; pVal = term_to_python(t); if (PyLong_Check(pVal)) { - o = PyFloat_FromDouble( PyLong_AsLong(pVal) ); -#if PY_MAJOR_VERSION<3 + o = PyFloat_FromDouble(PyLong_AsLong(pVal)); +#if PY_MAJOR_VERSION < 3 } else if (PyInt_Check(pVal)) { - o = PyFloat_FromDouble( PyInt_AsLong(pVal) ); + o = PyFloat_FromDouble(PyInt_AsLong(pVal)); #endif } else if (PyFloat_Check(pVal)) { return pVal; @@ -259,17 +296,15 @@ bip_float(term_t t) return o; } -static PyObject * -bip_int(term_t t) -{ +static PyObject *bip_int(term_t t) { PyObject *pVal, *o; - if (! PL_get_arg(1, t, t) ) + if (!PL_get_arg(1, t, t)) return NULL; pVal = term_to_python(t); -#if PY_MAJOR_VERSION<3 +#if PY_MAJOR_VERSION < 3 if (PyLong_Check(pVal)) { - o = PyInt_FromLong( PyLong_AsLong(pVal) ); + o = PyInt_FromLong(PyLong_AsLong(pVal)); } else if (PyInt_Check(pVal)) { return pVal; #else @@ -277,10 +312,10 @@ bip_int(term_t t) return pVal; #endif } else if (PyFloat_Check(pVal)) { -#if PY_MAJOR_VERSION<3 - o = PyInt_FromLong( PyFloat_AsDouble(pVal) ); +#if PY_MAJOR_VERSION < 3 + o = PyInt_FromLong(PyFloat_AsDouble(pVal)); #else - o = PyLong_FromDouble( PyFloat_AsDouble(pVal) ); + o = PyLong_FromDouble(PyFloat_AsDouble(pVal)); #endif } else return NULL; @@ -288,47 +323,40 @@ bip_int(term_t t) return o; } -static PyObject * -bip_long(term_t t) -{ +static PyObject *bip_long(term_t t) { PyObject *pVal, *o; - if (! PL_get_arg(1, t, t) ) + if (!PL_get_arg(1, t, t)) return NULL; pVal = term_to_python(t); if (PyLong_Check(pVal)) { return pVal; -#if PY_MAJOR_VERSION<3 +#if PY_MAJOR_VERSION < 3 } else if (PyInt_Check(pVal)) { - o = PyLong_FromLong( PyInt_AsLong(pVal) ); + o = PyLong_FromLong(PyInt_AsLong(pVal)); #endif } else if (PyFloat_Check(pVal)) { - o = PyLong_FromLong( PyFloat_AsDouble(pVal) ); + o = PyLong_FromLong(PyFloat_AsDouble(pVal)); } else return NULL; Py_DECREF(pVal); return o; } -static PyObject * -bip_iter(term_t t) -{ +static PyObject *bip_iter(term_t t) { PyObject *v; - if (! PL_get_arg(1, t, t) ) + if (!PL_get_arg(1, t, t)) return NULL; v = term_to_python(t); return PyObject_GetIter(v); } - -static PyObject * -bip_ord(term_t t) -{ +static PyObject *bip_ord(term_t t) { PyObject *pVal; Py_ssize_t size; - if (! PL_get_arg(1, t, t) ) + if (!PL_get_arg(1, t, t)) return NULL; pVal = term_to_python(t); if (PyUnicode_Check(pVal)) { @@ -367,14 +395,12 @@ bip_ord(term_t t) return NULL; } -static PyObject* -bip_sum(term_t t) -{ +static PyObject *bip_sum(term_t t) { PyObject *seq; PyObject *result = NULL; PyObject *temp, *item, *iter; - if (! PL_get_arg(1, t, t) ) + if (!PL_get_arg(1, t, t)) return NULL; seq = term_to_python(t); iter = PyObject_GetIter(seq); @@ -396,19 +422,19 @@ bip_sum(term_t t) /* reject string values for 'start' parameter */ if (PyObject_TypeCheck(result, &PyBaseString_Type)) { PyErr_SetString(PyExc_TypeError, - "sum() can't sum strings [use ''.join(seq) instead]"); + "sum() can't sum strings [use ''.join(seq) instead]"); Py_DECREF(iter); return NULL; } Py_INCREF(result); -#endif } +#endif #ifndef SLOW_SUM - /* Fast addition by keeping temporary sums in C instead of new Python objects. - Assumes all inputs are the same type. If the assumption fails, default - to the more general routine. - */ +/* Fast addition by keeping temporary sums in C instead of new Python objects. +Assumes all inputs are the same type. If the assumption fails, default +to the more general routine. +*/ #if PY_MAJOR_VERSION < 3 if (PyInt_CheckExact(result)) { long i_result = PyInt_AS_LONG(result); @@ -418,33 +444,34 @@ bip_sum(term_t t) #endif Py_DECREF(result); result = NULL; - while(result == NULL) { + while (result == NULL) { item = PyIter_Next(iter); if (item == NULL) { - Py_DECREF(iter); - if (PyErr_Occurred()) - return NULL; + Py_DECREF(iter); + if (PyErr_Occurred()) + return NULL; #if PY_MAJOR_VERSION < 3 - return PyInt_FromLong(i_result); + return PyInt_FromLong(i_result); #else - return PyLong_FromLong(i_result); + return PyLong_FromLong(i_result); #endif } #if PY_MAJOR_VERSION < 3 if (PyInt_CheckExact(item)) { - long b = PyInt_AS_LONG(item); + long b = PyInt_AS_LONG(item); #else if (PyLong_CheckExact(item)) { - long b = PyLong_AS_LONG(item); + long b = PyLong_AS_LONG(item); #endif - long x = i_result + b; - if ((x^i_result) >= 0 || (x^b) >= 0) { - i_result = x; - Py_DECREF(item); - continue; - } + long x = i_result + b; + if ((x ^ i_result) >= 0 || (x ^ b) >= 0) { + i_result = x; + Py_DECREF(item); + continue; + } } - /* Either overflowed or is not an int. Restore real objects and process normally */ +/* Either overflowed or is not an int. Restore real objects and process normally + */ #if PY_MAJOR_VERSION < 3 result = PyInt_FromLong(i_result); #else @@ -455,8 +482,8 @@ bip_sum(term_t t) Py_DECREF(item); result = temp; if (result == NULL) { - Py_DECREF(iter); - return NULL; + Py_DECREF(iter); + return NULL; } } } @@ -465,33 +492,31 @@ bip_sum(term_t t) double f_result = PyFloat_AS_DOUBLE(result); Py_DECREF(result); result = NULL; - while(result == NULL) { + while (result == NULL) { item = PyIter_Next(iter); if (item == NULL) { - Py_DECREF(iter); - if (PyErr_Occurred()) - return NULL; - return PyFloat_FromDouble(f_result); + Py_DECREF(iter); + if (PyErr_Occurred()) + return NULL; + return PyFloat_FromDouble(f_result); } if (PyFloat_CheckExact(item)) { - PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0) - f_result += PyFloat_AS_DOUBLE(item); - PyFPE_END_PROTECT(f_result) - Py_DECREF(item); - continue; + PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0) + f_result += PyFloat_AS_DOUBLE(item); + PyFPE_END_PROTECT(f_result) Py_DECREF(item); + continue; } #if PY_MAJOR_VERSION < 3 if (PyInt_CheckExact(item)) { - PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0) - f_result += (double)PyInt_AS_LONG(item); + PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0) + f_result += (double)PyInt_AS_LONG(item); #else if (PyLong_CheckExact(item)) { - PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0) - f_result += PyLong_AsDouble(item); + PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0) + f_result += PyLong_AsDouble(item); #endif - PyFPE_END_PROTECT(f_result) - Py_DECREF(item); - continue; + PyFPE_END_PROTECT(f_result) Py_DECREF(item); + continue; } result = PyFloat_FromDouble(f_result); temp = PyNumber_Add(result, item); @@ -499,32 +524,32 @@ bip_sum(term_t t) Py_DECREF(item); result = temp; if (result == NULL) { - Py_DECREF(iter); - return NULL; + Py_DECREF(iter); + return NULL; } } } #endif - for(;;) { + for (;;) { item = PyIter_Next(iter); if (item == NULL) { /* error, or end-of-sequence */ if (PyErr_Occurred()) { - Py_DECREF(result); - result = NULL; + Py_DECREF(result); + result = NULL; } break; } /* It's tempting to use PyNumber_InPlaceAdd instead of - PyNumber_Add here, to avoid quadratic running time - when doing 'sum(list_of_lists, [])'. However, this - would produce a change in behaviour: a snippet like + PyNumber_Add here, to avoid quadratic running time + when doing 'sum(list_of_lists, [])'. However, this + would produce a change in behaviour: a snippet like - empty = [] - sum([[x] for x in range(10)], empty) + empty = [] + sum([[x] for x in range(10)], empty) - would change the value of empty. */ + would change the value of empty. */ temp = PyNumber_Add(result, item); Py_DECREF(result); Py_DECREF(item); @@ -536,9 +561,9 @@ bip_sum(term_t t) return result; } -static long -get_int(term_t arg) -{ +//@} + +static long get_int(term_t arg) { long ilow; if (!PL_get_long(arg, &ilow)) { @@ -547,7 +572,7 @@ get_int(term_t arg) return PyLong_AsLong(low); #if PY_MAJOR_VERSION < 3 } else if (PyInt_Check(low)) { - return PyInt_AsLong(low); + return PyInt_AsLong(low); #endif } else { return 0; @@ -556,161 +581,178 @@ get_int(term_t arg) return ilow; } - /* Return number of items in range/xrange (lo, hi, step). step > 0 - * required. Return a value < 0 if & only if the true value is too - * large to fit in a signed long. - */ -static long -get_len_of_range(long lo, long hi, long step) -{ - /* ------------------------------------------------------------- - If lo >= hi, the range is empty. - Else if n values are in the range, the last one is - lo + (n-1)*step, which must be <= hi-1. Rearranging, - n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives - the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so - the RHS is non-negative and so truncation is the same as the - floor. Letting M be the largest positive long, the worst case - for the RHS numerator is hi=M, lo=-M-1, and then - hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough - precision to compute the RHS exactly. - ---------------------------------------------------------------*/ - long n = 0; - if (lo < hi) { - unsigned long uhi = (unsigned long)hi; - unsigned long ulo = (unsigned long)lo; - unsigned long diff = uhi - ulo - 1; - n = (long)(diff / (unsigned long)step + 1); - } - return n; +* required. Return a value < 0 if & only if the true value is too +* large to fit in a signed long. +*/ +static long get_len_of_range(long lo, long hi, long step) { + /* ------------------------------------------------------------- + If lo >= hi, the range is empty. + Else if n values are in the range, the last one is + lo + (n-1)*step, which must be <= hi-1. Rearranging, + n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives + the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so + the RHS is non-negative and so truncation is the same as the + floor. Letting M be the largest positive long, the worst case + for the RHS numerator is hi=M, lo=-M-1, and then + hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough + precision to compute the RHS exactly. + ---------------------------------------------------------------*/ + long n = 0; + if (lo < hi) { + unsigned long uhi = (unsigned long)hi; + unsigned long ulo = (unsigned long)lo; + unsigned long diff = uhi - ulo - 1; + n = (long)(diff / (unsigned long)step + 1); + } + return n; } -static PyObject * -bip_range(term_t t) -{ - long ilow = 0, ihigh = 0, istep = 1; - long bign; - Py_ssize_t i, n; - int arity; - atom_t name; - term_t arg = PL_new_term_ref(); +static PyObject *bip_range(term_t t) { + long ilow = 0, ihigh = 0, istep = 1; + long bign; + Py_ssize_t i, n; + int arity; + atom_t name; + term_t arg = PL_new_term_ref(); - PyObject *v; + PyObject *v; - if (!PL_get_name_arity(t, &name, &arity) ) - return NULL; - if (! PL_get_arg(1, t, arg) ) + if (!PL_get_name_arity(t, &name, &arity)) + return NULL; + if (!PL_get_arg(1, t, arg)) + return NULL; + ilow = get_int(arg); + if (arity == 1) { + ihigh = ilow; + ilow = 0; + } else { + if (!PL_get_arg(2, t, arg)) return NULL; - ilow = get_int(arg); - if (arity == 1) { - ihigh = ilow; - ilow = 0; - } else { - if (! PL_get_arg(2, t, arg) ) - return NULL; - ihigh = get_int(arg); - if (arity == 3) { - if (! PL_get_arg(3, t, arg) ) - return NULL; - istep = get_int(arg); - } - } - if (istep == 0) { - PyErr_SetString(PyExc_ValueError, - "range() step argument must not be zero"); + ihigh = get_int(arg); + if (arity == 3) { + if (!PL_get_arg(3, t, arg)) return NULL; + istep = get_int(arg); } - if (istep > 0) - bign = get_len_of_range(ilow, ihigh, istep); - else - bign = get_len_of_range(ihigh, ilow, -istep); - n = (Py_ssize_t)bign; - if (bign < 0 || (long)n != bign) { - PyErr_SetString(PyExc_OverflowError, - "range() result has too many items"); - return NULL; - } - v = PyList_New(n); - if (v == NULL) - return NULL; - for (i = 0; i < n; i++) { + } + if (istep == 0) { + PyErr_SetString(PyExc_ValueError, "range() step argument must not be zero"); + return NULL; + } + if (istep > 0) + bign = get_len_of_range(ilow, ihigh, istep); + else + bign = get_len_of_range(ihigh, ilow, -istep); + n = (Py_ssize_t)bign; + if (bign < 0 || (long)n != bign) { + PyErr_SetString(PyExc_OverflowError, "range() result has too many items"); + return NULL; + } + v = PyList_New(n); + if (v == NULL) + return NULL; + for (i = 0; i < n; i++) { #if PY_MAJOR_VERSION < 3 - PyObject *w = PyInt_FromLong(ilow); + PyObject *w = PyInt_FromLong(ilow); #else - PyObject *w = PyLong_FromLong(ilow); + PyObject *w = PyLong_FromLong(ilow); #endif - if (w == NULL) { - Py_DECREF(v); - return NULL; - } - PyList_SET_ITEM(v, i, w); - ilow += istep; + if (w == NULL) { + Py_DECREF(v); + return NULL; } - return v; + PyList_SET_ITEM(v, i, w); + ilow += istep; + } + return v; } +static PyObject *atom_to_python_string(term_t t) { + // Yap_DebugPlWrite(YAP_GetFromSlot(t)); fprintf(stderr, " here I + // am\n"); + char *s; + if (!PL_get_atom_chars(t, &s)) + return NULL; +/* return __main__,s */ +#if PY_MAJOR_VERSION < 3 + if (proper_ascii_string(s)) { + return PyString_FromStringAndSize(s, strlen(s)); + } else +#endif + { + PyObject *pobj = PyUnicode_DecodeUTF8(s, strlen(s), NULL); + // fprintf(stderr, "%s\n", s); + return pobj; + } +} -static PyObject * -term_to_python(term_t t) -{ - // Yap_DebugPlWrite(YAP_GetFromSlot(t)); fprintf(stderr, " here I am\n"); +/** +* term_to_python translates and evaluates from Prolog to Python +* +* @param t handle to Prolog term +* +* @return a Python object descriptor or NULL if failed +*/ + +static PyObject *term_to_python(term_t t) { + // Yap_DebugPlWrite(YAP_GetFromSlot(t)); fprintf(stderr, " here I + // am\n"); switch (PL_term_type(t)) { case PL_VARIABLE: return NULL; - case PL_ATOM: - { - atom_t at; + case PL_ATOM: { + atom_t at; - if (PL_get_atom(t, &at)) { - if (at == ATOM_true) return Py_True; - if (at == ATOM_false) return Py_False; - } - { - char *s; - if (!PL_get_atom_chars(t, &s)) - return NULL; - /* return __main__,s */ - return PyObject_GetAttrString(py_Main, s); - } + if (PL_get_atom(t, &at)) { + if (at == ATOM_true) + return Py_True; + if (at == ATOM_false) + return Py_False; + if (at == ATOM_none) + return Py_None; } - break; - case PL_STRING: - { - char *s; - if (!PL_get_chars(t, &s, REP_UTF8|CVT_ATOM|CVT_STRING|BUF_DISCARDABLE) ) { - return NULL; - } -#if PY_MAJOR_VERSION < 3 - if (proper_ascii_string(s)) { - return PyString_FromStringAndSize(s, strlen(s) ); - } else -#endif - { - PyObject *pobj = PyUnicode_DecodeUTF8(s, strlen(s), NULL); - //fprintf(stderr, "%s\n", s); - return pobj; - } - } - break; - case PL_INTEGER: { - int64_t j; - if (!PL_get_int64_ex(t, &j)) - return NULL; + char *s; + if (!PL_get_atom_chars(t, &s)) + return NULL; + /* return __main__,s */ + return PyObject_GetAttrString(py_Main, s); + } + } break; + case PL_STRING: { + char *s; + if (!PL_get_chars(t, &s, + REP_UTF8 | CVT_ATOM | CVT_STRING | BUF_DISCARDABLE)) { + return NULL; + } #if PY_MAJOR_VERSION < 3 - return PyInt_FromLong(j); + if (proper_ascii_string(s)) { + return PyString_FromStringAndSize(s, strlen(s)); + } else +#endif + { + PyObject *pobj = PyUnicode_DecodeUTF8(s, strlen(s), NULL); + // fprintf(stderr, "%s\n", s); + return pobj; + } + } break; + case PL_INTEGER: { + int64_t j; + if (!PL_get_int64_ex(t, &j)) + return NULL; +#if PY_MAJOR_VERSION < 3 + return PyInt_FromLong(j); #else return PyLong_FromLong(j); #endif - } - case PL_FLOAT: - { - double fl; - if (!PL_get_float(t, &fl)) - return NULL; - return PyFloat_FromDouble( fl ); - } + } + case PL_FLOAT: { + double fl; + if (!PL_get_float(t, &fl)) + return NULL; + return PyFloat_FromDouble(fl); + } case PL_TERM: if (PL_is_list(t)) { size_t len, i; @@ -719,328 +761,330 @@ term_to_python(term_t t) PL_skip_list(t, tail, &len); if (!PL_get_nil(tail)) - return NULL; + return NULL; arg = tail; out = PyList_New(len); if (!out) - return NULL; + return NULL; - for (i=0; i< len; i++) { - if (!PL_get_list(t, arg, t)) { - return NULL; - } - if (PyList_SetItem(out, i, term_to_python(arg)) < 0) - return NULL; + for (i = 0; i < len; i++) { + if (!PL_get_list(t, arg, t)) { + return NULL; + } + if (PyList_SetItem(out, i, term_to_python(arg)) < 0) + return NULL; } return out; } else { functor_t fun; if (!PL_get_functor(t, &fun)) - return NULL; + return NULL; if (fun == FUNCTOR_dollar1) { - char *s; - term_t targ = PL_new_term_ref(); - if (! PL_get_arg(1, t, targ) ) - return NULL; - if (!PL_get_atom_chars(targ, &s)) - return NULL; - /* return __main__,s */ - return PyObject_GetAttrString(py_Main, s); + char *s; + term_t targ = PL_new_term_ref(); + if (!PL_get_arg(1, t, targ)) + return NULL; + if (!PL_get_atom_chars(targ, &s)) + return NULL; + /* return __main__,s */ + return PyObject_GetAttrString(py_Main, s); } else if (fun == FUNCTOR_pointer1) { - void *ptr; - term_t targ = PL_new_term_ref(); + void *ptr; + term_t targ = PL_new_term_ref(); - if (! PL_get_arg(1, t, targ) ) - return NULL; - if (!PL_get_pointer(targ, &ptr)) - return NULL; - Py_INCREF((PyObject *)ptr); - /* return __main__,s */ - return (PyObject *)ptr; + if (!PL_get_arg(1, t, targ)) + return NULL; + if (!PL_get_pointer(targ, &ptr)) + return NULL; + Py_INCREF((PyObject *)ptr); + /* return __main__,s */ + return (PyObject *)ptr; + } else if (fun == FUNCTOR_brackets1) { + if (!PL_get_arg(1, t, t)) + return NULL; + return term_to_python(t); } else if (fun == FUNCTOR_abs1) { - return bip_abs(t); + return bip_abs(t); } else if (fun == FUNCTOR_all1) { - return bip_all(t); + return bip_all(t); } else if (fun == FUNCTOR_any1) { - return bip_any(t); + return bip_any(t); } else if (fun == FUNCTOR_bin1) { - return bip_bin(t); + return bip_bin(t); } else if (fun == FUNCTOR_ord1) { - return bip_ord(t); + return bip_ord(t); } else if (fun == FUNCTOR_int1) { - return bip_int(t); + return bip_int(t); } else if (fun == FUNCTOR_long1) { - return bip_long(t); + return bip_long(t); } else if (fun == FUNCTOR_float1) { - return bip_float(t); + return bip_float(t); } else if (fun == FUNCTOR_iter1) { - return bip_iter(t); - } else if (fun == FUNCTOR_range1 || - fun == FUNCTOR_range2 || - fun == FUNCTOR_range3) { - return bip_range(t); + return bip_iter(t); + } else if (fun == FUNCTOR_range1 || fun == FUNCTOR_range2 || + fun == FUNCTOR_range3) { + return bip_range(t); } else if (fun == FUNCTOR_sum1) { - return bip_sum(t); + return bip_sum(t); } else if (fun == FUNCTOR_len1) { - term_t targ = PL_new_term_ref(); - PyObject *ptr; + term_t targ = PL_new_term_ref(); + PyObject *ptr; - if (! PL_get_arg(1, t, targ) ) - return NULL; - ptr = term_to_python(targ); - return PyLong_FromLong(PyObject_Length(ptr)); + if (!PL_get_arg(1, t, targ)) + return NULL; + ptr = term_to_python(targ); + return PyLong_FromLong(PyObject_Length(ptr)); } else if (fun == FUNCTOR_dir1) { - term_t targ = PL_new_term_ref(); - PyObject *ptr; + term_t targ = PL_new_term_ref(); + PyObject *ptr; - if (! PL_get_arg(1, t, targ) ) - return NULL; - ptr = term_to_python(targ); - return PyObject_Dir(ptr); + if (!PL_get_arg(1, t, targ)) + return NULL; + ptr = term_to_python(targ); + return PyObject_Dir(ptr); } else if (fun == FUNCTOR_complex2) { - term_t targ = PL_new_term_ref(); - PyObject *lhs, *rhs; - double d1, d2; + term_t targ = PL_new_term_ref(); + PyObject *lhs, *rhs; + double d1, d2; - if (! PL_get_arg(1, t, targ) ) - return NULL; - lhs = term_to_python(targ); - if (!PyNumber_Check(lhs)) - return NULL; - if (PyFloat_Check(lhs)) { - d1 = PyFloat_AsDouble(lhs); - } else if (PyLong_Check(lhs)) { - d1 = PyLong_AsLong(lhs); + if (!PL_get_arg(1, t, targ)) + return NULL; + lhs = term_to_python(targ); + if (!PyNumber_Check(lhs)) + return NULL; + if (PyFloat_Check(lhs)) { + d1 = PyFloat_AsDouble(lhs); + } else if (PyLong_Check(lhs)) { + d1 = PyLong_AsLong(lhs); #if PY_MAJOR_VERSION < 3 - } else if (PyInt_Check(lhs)) { - d1 = PyInt_AsLong(lhs); + } else if (PyInt_Check(lhs)) { + d1 = PyInt_AsLong(lhs); #endif - } else { - return NULL; - } - if (! PL_get_arg(2, t, targ) ) - return NULL; - rhs = term_to_python(targ); - if (!PyNumber_Check(rhs)) - return NULL; - if (PyFloat_Check(rhs)) { - d2 = PyFloat_AsDouble(rhs); - } else if (PyLong_Check(rhs)) { - d2 = PyLong_AsLong(rhs); + } else { + return NULL; + } + if (!PL_get_arg(2, t, targ)) + return NULL; + rhs = term_to_python(targ); + if (!PyNumber_Check(rhs)) + return NULL; + if (PyFloat_Check(rhs)) { + d2 = PyFloat_AsDouble(rhs); + } else if (PyLong_Check(rhs)) { + d2 = PyLong_AsLong(rhs); #if PY_MAJOR_VERSION < 3 - } else if (PyInt_Check(rhs)) { - d2 = PyInt_AsLong(rhs); + } else if (PyInt_Check(rhs)) { + d2 = PyInt_AsLong(rhs); #endif - } else { - return NULL; - } + } else { + return NULL; + } - return PyComplex_FromDoubles(d1, d2); + return PyComplex_FromDoubles(d1, d2); } else if (fun == FUNCTOR_curly1) { - term_t targ = PL_new_term_ref(), taux = PL_new_term_ref(); - PyObject *dict; + term_t targ = PL_new_term_ref(), taux = PL_new_term_ref(); + PyObject *dict; - if (! PL_get_arg(1, t, t) ) - return NULL; - if (! (dict = PyDict_New() ) ) - return NULL; - while (PL_is_functor(t, FUNCTOR_comma2)) { - if (! PL_get_arg(1, t, targ) ) - return NULL; - if (PL_is_functor(targ, FUNCTOR_colon2)) { - if ( !copy_to_dictionary(dict, targ, taux) ) - return NULL; - if (! PL_get_arg(2, t, t) ) - return NULL; - } else { - return NULL; - } - } - if (PL_is_functor(t, FUNCTOR_colon2)) { - if ( !copy_to_dictionary(dict, t, taux) ) - return NULL; - } else { - return NULL; - } - return dict; + if (!PL_get_arg(1, t, t)) + return NULL; + if (!(dict = PyDict_New())) + return NULL; + while (PL_is_functor(t, FUNCTOR_comma2)) { + if (!PL_get_arg(1, t, targ)) + return NULL; + if (PL_is_functor(targ, FUNCTOR_colon2)) { + if (!copy_to_dictionary(dict, targ, taux)) + return NULL; + if (!PL_get_arg(2, t, t)) + return NULL; + } else { + return NULL; + } + } + if (PL_is_functor(t, FUNCTOR_colon2)) { + if (!copy_to_dictionary(dict, t, taux)) + return NULL; + } else { + return NULL; + } + return dict; } else if (fun == FUNCTOR_plus2) { - term_t targ = PL_new_term_ref(); - PyObject *lhs, *rhs; + term_t targ = PL_new_term_ref(); + PyObject *lhs, *rhs; - if (! PL_get_arg(1, t, targ) ) - return NULL; - lhs = term_to_python(targ); - if (! PL_get_arg(2, t, targ) ) - return NULL; - rhs = term_to_python(targ); - if (PySequence_Check(lhs) && PySequence_Check(rhs)) { - return PySequence_Concat(lhs, rhs); - } - if (!PyNumber_Check(lhs)) - return NULL; - if (!PyNumber_Check(rhs)) - return NULL; - return PyNumber_Add(lhs, rhs); + if (!PL_get_arg(1, t, targ)) + return NULL; + lhs = term_to_python(targ); + if (!PL_get_arg(2, t, targ)) + return NULL; + rhs = term_to_python(targ); + if (PySequence_Check(lhs) && PySequence_Check(rhs)) { + return PySequence_Concat(lhs, rhs); + } + if (!PyNumber_Check(lhs)) + return NULL; + if (!PyNumber_Check(rhs)) + return NULL; + return PyNumber_Add(lhs, rhs); } else if (fun == FUNCTOR_sub2) { - term_t targ = PL_new_term_ref(); - PyObject *lhs, *rhs; + term_t targ = PL_new_term_ref(); + PyObject *lhs, *rhs; - if (! PL_get_arg(1, t, targ) ) - return NULL; - lhs = term_to_python(targ); - if (!PyNumber_Check(lhs)) - return NULL; - if (! PL_get_arg(2, t, targ) ) - return NULL; - rhs = term_to_python(targ); - if (!PyNumber_Check(rhs)) - return NULL; - return PyNumber_Subtract(lhs, rhs); + if (!PL_get_arg(1, t, targ)) + return NULL; + lhs = term_to_python(targ); + if (!PyNumber_Check(lhs)) + return NULL; + if (!PL_get_arg(2, t, targ)) + return NULL; + rhs = term_to_python(targ); + if (!PyNumber_Check(rhs)) + return NULL; + return PyNumber_Subtract(lhs, rhs); } else if (fun == FUNCTOR_mul2) { - term_t targ = PL_new_term_ref(); - PyObject *lhs, *rhs; + term_t targ = PL_new_term_ref(); + PyObject *lhs, *rhs; - if (! PL_get_arg(1, t, targ) ) - return NULL; - lhs = term_to_python(targ); - if (! PL_get_arg(2, t, targ) ) - return NULL; - rhs = term_to_python(targ); - if (PySequence_Check(lhs) && ( + if (!PL_get_arg(1, t, targ)) + return NULL; + lhs = term_to_python(targ); + if (!PL_get_arg(2, t, targ)) + return NULL; + rhs = term_to_python(targ); + if (PySequence_Check(lhs) && ( #if PY_MAJOR_VERSION < 3 - PyInt_Check(rhs) || + PyInt_Check(rhs) || #endif - PyLong_Check(rhs)) ){ - return PySequence_Repeat(lhs, get_p_int(rhs, 0)); - } - if (!PyNumber_Check(lhs)+!PyNumber_Check(rhs)) - return NULL; - return PyNumber_Multiply(lhs, rhs); + PyLong_Check(rhs))) { + return PySequence_Repeat(lhs, get_p_int(rhs, 0)); + } + if (!PyNumber_Check(lhs) + !PyNumber_Check(rhs)) + return NULL; + return PyNumber_Multiply(lhs, rhs); } else if (fun == FUNCTOR_div2) { - term_t targ = PL_new_term_ref(); - PyObject *lhs, *rhs; + term_t targ = PL_new_term_ref(); + PyObject *lhs, *rhs; - if (! PL_get_arg(1, t, targ) ) - return NULL; - lhs = term_to_python(targ); - if (!PyNumber_Check(lhs)) - return NULL; - if (! PL_get_arg(2, t, targ) ) - return NULL; - rhs = term_to_python(targ); - if (!PyNumber_Check(rhs)) - return NULL; + if (!PL_get_arg(1, t, targ)) + return NULL; + lhs = term_to_python(targ); + if (!PyNumber_Check(lhs)) + return NULL; + if (!PL_get_arg(2, t, targ)) + return NULL; + rhs = term_to_python(targ); + if (!PyNumber_Check(rhs)) + return NULL; #if PY_MAJOR_VERSION < 3 - return - PyNumber_Divide(lhs, rhs); + return PyNumber_Divide(lhs, rhs); #else - return - PyNumber_TrueDivide(lhs, rhs); + return PyNumber_TrueDivide(lhs, rhs); #endif - } else if (fun == FUNCTOR_hat2) { - term_t targ = PL_new_term_ref(), trhs = PL_new_term_ref(); - PyObject *lhs, *rhs; + } else if (fun == FUNCTOR_sqbrackets2) { + // + term_t targ = PL_new_term_ref(), trhs = PL_new_term_ref(); + PyObject *v; + Py_ssize_t min, max; - if (! PL_get_arg(1, t, targ)) - return NULL; - lhs = term_to_python(targ); - if (! PL_get_arg(2, t, targ) || !PL_is_list(targ) || !PL_get_list(targ, trhs, targ) ) - return NULL; - if (PL_is_functor(trhs, FUNCTOR_colon2) ) { - Py_ssize_t left, right; - if (!PL_get_arg(1, trhs, targ)) - return NULL; - left = get_p_int(term_to_python(targ), 0); - if (!PL_get_arg(2, trhs, targ)) - return NULL; - right = get_p_int(term_to_python(targ), PyObject_Size(lhs) ); - if (!PySequence_Check(lhs)) - return NULL; - return PySequence_GetSlice(lhs, left, right); - } else { - rhs = term_to_python(trhs); - return PyObject_GetItem(lhs, rhs); - } - } else if (fun == FUNCTOR_colon2) { - term_t tleft = PL_new_term_ref(); - PyObject *pArgs, *o; - long i; - int arity; - atom_t name; + if (!PL_get_arg(1, t, targ)) + return NULL; + v = term_to_python(targ); + if (!PL_get_arg(2, t, targ) || !PL_get_list(targ, trhs, targ)) + return NULL; + if (PL_is_functor(targ, FUNCTOR_colon2)) { + if (!PL_get_arg(1, trhs, targ)) + return NULL; + min = get_p_int(term_to_python(targ), 0); + if (!PL_get_arg(2, trhs, targ)) + return NULL; + if (PL_is_functor(targ, FUNCTOR_colon2)) { + return NULL; + } + max = get_p_int(term_to_python(targ), PyObject_Size(v)); + if (!PySequence_Check(v)) + return NULL; + return PySequence_GetSlice(v, min, max); + } + } else if (fun == FUNCTOR_dot2) { + term_t tleft = PL_new_term_ref(); + PyObject *pArgs, *o; + long i; + int arity; + atom_t name; - o = NULL; - while (fun == FUNCTOR_colon2) { - if (! PL_get_arg(1, t, tleft) ) - return FALSE; - o = find_obj(o, tleft); - if (!o) - return FALSE; - if (! PL_get_arg(2, t, t) ) - return FALSE; - if (!PL_get_functor(t, &fun)) - break; - } - if (! PL_get_name_arity( t, &name, &arity) ) { - return NULL; - } - if (!arity) { - char *s; - PyObject *pValue; + o = NULL; + while (fun == FUNCTOR_dot2) { + if (!PL_get_arg(1, t, tleft)) + return FALSE; + o = find_obj(o, tleft); + if (!o) + return FALSE; + if (!PL_get_arg(2, t, t)) + return FALSE; + if (!PL_get_functor(t, &fun)) + break; + } + if (!PL_get_name_arity(t, &name, &arity)) { + return NULL; + } + if (!arity) { + char *s; + PyObject *pValue; - if (!PL_get_atom_chars(t, &s)) - return NULL; - if ((pValue = PyObject_GetAttrString(o, s)) == NULL) { - PyErr_Print(); - return NULL; - } - return pValue; - } - o = PyObject_GetAttrString(o, PL_atom_chars(name)); - if (!o || ! PyCallable_Check(o)) { - return NULL; - } - pArgs = PyTuple_New(arity); - for (i = 0 ; i < arity; i++) { - PyObject *pArg; - if (! PL_get_arg(i+1, t, tleft) ) - return NULL; - /* ignore (_) */ - if (i == 0 && PL_is_variable(tleft)) { - Py_DECREF(pArgs); - pArgs = NULL; - } - pArg = term_to_python(tleft); - if (pArg == NULL) - return NULL; - /* pArg reference stolen here: */ - PyTuple_SetItem(pArgs, i, pArg); - } - return PyObject_CallObject(o, pArgs); + if (!PL_get_atom_chars(t, &s)) + return NULL; + if ((pValue = PyObject_GetAttrString(o, s)) == NULL) { + PyErr_Print(); + return NULL; + } + return pValue; + } + o = PyObject_GetAttrString(o, PL_atom_chars(name)); + if (!o || !PyCallable_Check(o)) { + return NULL; + } + pArgs = PyTuple_New(arity); + for (i = 0; i < arity; i++) { + PyObject *pArg; + if (!PL_get_arg(i + 1, t, tleft)) + return NULL; + /* ignore (_) */ + if (i == 0 && PL_is_variable(tleft)) { + Py_DECREF(pArgs); + pArgs = NULL; + } + pArg = term_to_python(tleft); + if (pArg == NULL) + return NULL; + /* pArg reference stolen here: */ + PyTuple_SetItem(pArgs, i, pArg); + } + return PyObject_CallObject(o, pArgs); } else { - atom_t name; - int len; + atom_t name; + int len; - if (! PL_get_name_arity( t, &name, &len) ) { - return NULL; - } - if (name == ATOM_t) { - term_t targ = PL_new_term_ref(); - PyObject *out; - int i; + if (!PL_get_name_arity(t, &name, &len)) { + return NULL; + } + if (name == ATOM_t) { + term_t targ = PL_new_term_ref(); + PyObject *out; + int i; - out = PyTuple_New(len); - if (!out) - return NULL; - for (i=0; i< len; i++) { - if (!PL_get_arg(i+1, t, targ)) { - return NULL; - } - if (PyTuple_SetItem(out, i, term_to_python(targ)) < 0) - return NULL; - } - return out; - } + out = PyTuple_New(len); + if (!out) + return NULL; + for (i = 0; i < len; i++) { + if (!PL_get_arg(i + 1, t, targ)) { + return NULL; + } + if (PyTuple_SetItem(out, i, term_to_python(targ)) < 0) + return NULL; + } + return out; + } } } return NULL; @@ -1048,66 +1092,78 @@ term_to_python(term_t t) return NULL; } -static int -assign_python(PyObject *root, term_t t, PyObject *e) -{ +/** + * assign_python assigns the Python RHS to a Prolog term LHS, ie LHS = RHS + * + * @param root Python environment + * @param t left hand side, in Prolog, may be + * - a Prolog variable, exports the term to Prolog, A <- RHS + * - Python variable A, A <- RHS + * - Python variable $A, A <- RHS + * - Python string "A", A <- RHS + * - Python array range + * @param e the right-hand side + * + * @return -1 on failure. + * + * Note that this is an auxiliary routine to the Prolog python_assign. + */ static int assign_python(PyObject *root, term_t t, PyObject *e) { switch (PL_term_type(t)) { case PL_VARIABLE: - return -1; - case PL_ATOM: - { - char *s; - if (!PL_get_atom_chars(t, &s)) { - wchar_t *w; - atom_t at; - size_t len; - PyObject *attr; + if (python_to_ptr(e, t)) + return 1; + else + return -1; + case PL_ATOM: { + char *s; + if (!PL_get_atom_chars(t, &s)) { + wchar_t *w; + atom_t at; + size_t len; + PyObject *attr; - if (!PL_get_atom(t, &at)) { - return -1; - } - if (!(w = PL_atom_wchars(at, &len))) - return -1; - attr = PyUnicode_FromWideChar(w, wcslen(w) ); - if (!attr) - return -1; - return PyObject_SetAttr(py_Main, attr, e); - } - if (proper_ascii_string(s)) { - return PyObject_SetAttrString(py_Main, s, e); - } else { - PyObject *attr= PyUnicode_DecodeLatin1(s, strlen(s), NULL); - if (!attr) - return -1; - return PyObject_SetAttr(py_Main, attr, e); - } - } - break; - case PL_STRING: - { - char *s; - - if (!PL_get_atom_chars(t, &s)) { - wchar_t *w; - atom_t at; - size_t len; - PyObject *wo; - - if (!PL_get_atom(t, &at)) - return -1; - if (!(w = PL_atom_wchars(at, &len))) - return -1; - wo = PyUnicode_FromWideChar(w, wcslen(w) ); - return PyObject_SetAttr(root, wo, e); - } - if (proper_ascii_string(s)) { - return PyObject_SetAttrString(root, s, e); - } else { - PyObject *wo= PyUnicode_DecodeLatin1(s, strlen(s), NULL); - return PyObject_SetAttr(root, wo, e); + if (!PL_get_atom(t, &at)) { + return -1; } + if (!(w = PL_atom_wchars(at, &len))) + return -1; + attr = PyUnicode_FromWideChar(w, wcslen(w)); + if (!attr) + return -1; + return PyObject_SetAttr(py_Main, attr, e); } - break; + if (proper_ascii_string(s)) { + return PyObject_SetAttrString(py_Main, s, e); + } else { + PyObject *attr = PyUnicode_DecodeLatin1(s, strlen(s), NULL); + if (!attr) + return -1; + return PyObject_SetAttr(py_Main, attr, e); + } + } break; + case PL_STRING: { + char *s; + + if (!PL_get_atom_chars(t, &s)) { + wchar_t *w; + atom_t at; + size_t len; + PyObject *wo; + + if (!PL_get_atom(t, &at)) + return -1; + if (!(w = PL_atom_wchars(at, &len))) + return -1; + wo = PyUnicode_FromWideChar(w, wcslen(w)); + return PyObject_SetAttr(root, wo, e); + } + if (proper_ascii_string(s)) { + return PyObject_SetAttrString(root, s, e); + } else { + PyObject *wo = PyUnicode_DecodeLatin1(s, strlen(s), NULL); + return PyObject_SetAttr(root, wo, e); + } + } break; case PL_INTEGER: case PL_FLOAT: return -1; @@ -1118,63 +1174,64 @@ assign_python(PyObject *root, term_t t, PyObject *e) functor_t fun; if (!PL_get_functor(t, &fun)) - return -1; + return -1; if (fun == FUNCTOR_dollar1) { - char *s; + char *s; + if (!PL_get_arg(1, t, t)) + return -1; + if (!PL_get_atom_chars(t, &s)) { + wchar_t *w; + atom_t at; + size_t len; + PyObject *attr; - if (! PL_get_arg(1, t, t) ) - return -1; - if (!PL_get_atom_chars(t, &s)) { - wchar_t *w; - atom_t at; - size_t len; - PyObject *attr; - - if (!PL_get_atom(t, &at)) { - return -1; - } - if (!(w = PL_atom_wchars(at, &len))) - return -1; - attr = PyUnicode_FromWideChar(w, wcslen(w) ); - if (!attr) - return -1; - return PyObject_SetAttr(py_Main, attr, e); - } - if (proper_ascii_string(s)) { - return PyObject_SetAttrString(py_Main, s, e); - } else { - PyObject *attr= PyUnicode_DecodeLatin1(s, strlen(s), NULL); - if (!attr) - return -1; - return PyObject_SetAttr(py_Main, attr, e); - } + if (!PL_get_atom(t, &at)) { + return -1; + } + if (!(w = PL_atom_wchars(at, &len))) + return -1; + attr = PyUnicode_FromWideChar(w, wcslen(w)); + if (!attr) + return -1; + return PyObject_SetAttr(py_Main, attr, e); + } + if (proper_ascii_string(s)) { + return PyObject_SetAttrString(py_Main, s, e); + } else { + PyObject *attr = PyUnicode_DecodeLatin1(s, strlen(s), NULL); + if (!attr) + return -1; + return PyObject_SetAttr(py_Main, attr, e); + } } else if (fun == FUNCTOR_pointer1) { - return -1; - } else if (fun == FUNCTOR_hat2) { - term_t targ = PL_new_term_ref(), trhs = PL_new_term_ref(); - PyObject *lhs, *rhs; + return -1; + } else if (fun == FUNCTOR_colon2) { + term_t targ = PL_new_term_ref(), trhs = PL_new_term_ref(); + PyObject *lhs, *rhs; - if (! PL_get_arg(1, t, targ) ) - return -1; - lhs = term_to_python(targ); - if (! PL_get_arg(2, t, targ) || !PL_is_list(targ) || !PL_get_list(targ, trhs, targ ) ) - return -1; - if (PL_is_functor(trhs, FUNCTOR_colon2) ) { - Py_ssize_t left, right; - if (!PL_get_arg(1, trhs, targ)) - return -1; - left = get_p_int(term_to_python(targ), 0); - if (!PL_get_arg(2, trhs, targ)) - return -1; - right = get_p_int(term_to_python(targ), PyObject_Size(lhs) ); - if (!PySequence_Check(lhs)) - return -1; - return PySequence_SetSlice(lhs, left, right, e); - } else { - rhs = term_to_python(trhs); - return PyObject_SetItem(lhs, rhs, e); - } + if (!PL_get_arg(1, t, targ)) + return -1; + lhs = term_to_python(targ); + if (!PL_get_arg(2, t, targ) || !PL_is_list(targ) || + !PL_get_list(targ, trhs, targ)) + return -1; + if (PL_is_functor(trhs, FUNCTOR_colon2)) { + Py_ssize_t left, right; + if (!PL_get_arg(1, trhs, targ)) + return -1; + left = get_p_int(term_to_python(targ), 0); + if (!PL_get_arg(2, trhs, targ)) + return -1; + right = get_p_int(term_to_python(targ), PyObject_Size(lhs)); + if (!PySequence_Check(lhs)) + return -1; + return PySequence_SetSlice(lhs, left, right, e); + } else { + rhs = term_to_python(trhs); + return PyObject_SetItem(lhs, rhs, e); + } + PL_reset_term_refs(targ); } } return -1; @@ -1182,19 +1239,33 @@ assign_python(PyObject *root, term_t t, PyObject *e) return -1; } -static foreign_t -address_to_term(PyObject *pVal, term_t t) -{ - term_t to = PL_new_term_ref(), t1 = PL_new_term_ref(); - PL_put_pointer(t1, (void *)pVal); - PL_cons_functor(to, FUNCTOR_pointer1, t1); - Py_INCREF(pVal); - return PL_unify(t, to); +static foreign_t address_to_term(PyObject *pVal, term_t t) { + term_t to = PL_new_term_ref(), t1 = PL_new_term_ref(); + PL_put_pointer(t1, (void *)pVal); + PL_cons_functor(to, FUNCTOR_pointer1, t1); + Py_INCREF(pVal); + PL_reset_term_refs(to); + return PL_unify(t, to); } -static foreign_t -python_to_term(PyObject *pVal, term_t t) -{ +static foreign_t repr_term(const char *pVal, size_t sz, term_t t) { + term_t to = PL_new_term_ref(), t1 = PL_new_term_ref(); + PL_put_string_nchars(t1, pVal, sz); + free(pVal); + PL_cons_functor(to, FUNCTOR_pointer1, t1); + Py_INCREF(pVal); + PL_reset_term_refs(to); + return PL_unify(t, to); +} + +static foreign_t python_to_ptr(PyObject *pVal, term_t t) { + return address_to_term(pVal, t); +} + +static foreign_t python_to_term(PyObject *pVal, term_t t) { + if (pVal == Py_None) { + return PL_unify_atom(t, ATOM_none); + } if (PyBool_Check(pVal)) { if (PyObject_IsTrue(pVal)) { return PL_unify_atom(t, ATOM_true); @@ -1210,23 +1281,29 @@ python_to_term(PyObject *pVal, term_t t) } else if (PyFloat_Check(pVal)) { return PL_unify_float(t, PyFloat_AsDouble(pVal)); } else if (PyComplex_Check(pVal)) { - term_t to = PL_new_term_ref(), t1= PL_new_term_ref(), t2 = PL_new_term_ref(); - if (!PL_put_float(t1, PyComplex_RealAsDouble(pVal) ) || - !PL_put_float(t2, PyComplex_ImagAsDouble(pVal) ) || - !PL_cons_functor(to, FUNCTOR_complex2, t1, t2) ) - return FALSE; - return PL_unify(t, to); + bool rc; + term_t to = PL_new_term_ref(), t1 = PL_new_term_ref(), + t2 = PL_new_term_ref(); + if (!PL_put_float(t1, PyComplex_RealAsDouble(pVal)) || + !PL_put_float(t2, PyComplex_ImagAsDouble(pVal)) || + !PL_cons_functor(to, FUNCTOR_complex2, t1, t2)) { + rc = FALSE; + } else { + rc = PL_unify(t, to); + } + PL_reset_term_refs(to); + return rc; } else if (PyUnicode_Check(pVal)) { atom_t tmp_atom; #if PY_MAJOR_VERSION < 3 - Py_ssize_t sz = PyUnicode_GetSize(pVal)+1; - wchar_t *ptr = malloc(sizeof(wchar_t)*sz); - sz = PyUnicode_AsWideChar((PyUnicodeObject *)pVal, ptr, sz-1); + Py_ssize_t sz = PyUnicode_GetSize(pVal) + 1; + wchar_t *ptr = malloc(sizeof(wchar_t) * sz); + sz = PyUnicode_AsWideChar((PyUnicodeObject *)pVal, ptr, sz - 1); #else - Py_ssize_t sz = PyUnicode_GetLength(pVal)+1; - wchar_t *ptr = malloc(sizeof(wchar_t)*sz); - sz = PyUnicode_AsWideChar(pVal, ptr, sz); + Py_ssize_t sz = PyUnicode_GetLength(pVal) + 1; + wchar_t *ptr = malloc(sizeof(wchar_t) * sz); + sz = PyUnicode_AsWideChar(pVal, ptr, sz); #endif tmp_atom = PL_new_atom_wchars(sz, ptr); free(ptr); @@ -1246,10 +1323,10 @@ python_to_term(PyObject *pVal, term_t t) return FALSE; for (i = 0; i < sz; i++) { term_t to = PL_new_term_ref(); - if (!PL_unify_arg(i+1, t, to)) - return FALSE; - if ( !python_to_term(PyTuple_GetItem(pVal, i), to) ) - return FALSE; + if (!PL_unify_arg(i + 1, t, to)) + return FALSE; + if (!python_to_ptr(PyTuple_GetItem(pVal, i), to)) + return FALSE; } return TRUE; } else if (PyList_Check(pVal)) { @@ -1258,8 +1335,8 @@ python_to_term(PyObject *pVal, term_t t) for (i = 0; i < sz; i++) { if (!PL_unify_list(t, to, t) || - !python_to_term(PyList_GetItem(pVal, i), to)) - return FALSE; + !python_to_term(PyList_GetItem(pVal, i), to)) + return FALSE; } return PL_unify_nil(t); } else if (PyDict_Check(pVal)) { @@ -1269,48 +1346,88 @@ python_to_term(PyObject *pVal, term_t t) PyObject *key, *value; while (PyDict_Next(pVal, &pos, &key, &value)) { - term_t tkey = PL_new_term_ref(), tval = PL_new_term_ref(), tint, tnew = PL_new_term_ref(); + term_t tkey = PL_new_term_ref(), tval = PL_new_term_ref(), tint, + tnew = PL_new_term_ref(); /* do something interesting with the values... */ if (!python_to_term(key, tkey)) { - return FALSE; + return FALSE; } if (!python_to_term(value, tval)) { - return FALSE; + return FALSE; } /* reuse */ tint = tkey; if (!PL_cons_functor(tint, FUNCTOR_colon2, tkey, tval)) { - return FALSE; + return FALSE; } if (--left) { - if (!PL_cons_functor(tint, FUNCTOR_comma2, tint, tnew)) - return FALSE; + if (!PL_cons_functor(tint, FUNCTOR_comma2, tint, tnew)) + return FALSE; } if (!PL_unify(ti, tint)) - return FALSE; + return FALSE; ti = tnew; } PL_cons_functor(to, FUNCTOR_curly1, to); return PL_unify(t, to); } else { - return address_to_term(pVal, t); + char *s; + PyObject *pValR = PyObject_Repr(pVal); + if (pValR == NULL) + return address_to_term(pVal, t); +#if PY_MAJOR_VERSION < 3 + Py_ssize_t sz = PyUnicode_GetSize(pValR) + 1; + PyObject *us = PyUnicode_EncodeUTF8((PyUnicodeObject *)pValR, s, NULL); +#else + Py_ssize_t sz = PyUnicode_GetLength(pVal) + 1; + s = malloc(sizeof(char) * sz); + PyObject *obj = PyUnicode_AsUTF8Char(pVal, ptr, sz); + PyString_AsStringAndSize(obj, &s & sz) +#endif + + return repr_term(s, sz, t); } } -static int -python_import(term_t mname, term_t mod) -{ +static foreign_t python_export(term_t t, term_t pl) { + if (PL_is_functor(t, FUNCTOR_pointer1)) { + void *ptr; + term_t targ = PL_new_term_ref(); + + if (!PL_get_arg(1, t, targ)) + return false; + if (!PL_get_pointer(targ, &ptr)) + return false; + Py_INCREF((PyObject *)ptr); + /* return __main__,s */ + return python_to_term((PyObject *)ptr, pl); + } + return false; +} +static int python_import(term_t mname, term_t mod) { char *s; size_t len; PyObject *pName, *pModule; - if ( !PL_get_nchars(mname, &len, &s, CVT_ALL|CVT_EXCEPTION) ) { + if (PL_is_list(mname)) { + char *s2; + char str[256]; + term_t arg = PL_new_term_ref(); + if (!PL_get_arg(1, mname, arg) || !PL_get_atom_chars(arg, &s) || + !PL_get_arg(2, mname, mname) || !PL_get_arg(1, mname, arg) || + !PL_get_atom_chars(arg, &s2)) + return FALSE; + strcpy(str, s); + strcat(str, "."); + strcat(str, s2); + s = str; + } else if (!PL_get_nchars(mname, &len, &s, CVT_ALL | CVT_EXCEPTION)) { return FALSE; } #if PY_MAJOR_VERSION < 3 pName = PyString_FromString(s); #else - pName = PyUnicode_FromString(s); + pName = PyUnicode_FromString(s); #endif if (pName == NULL) { return FALSE; @@ -1318,33 +1435,31 @@ python_import(term_t mname, term_t mod) pModule = PyImport_Import(pName); Py_DECREF(pName); if (pModule == NULL) { - if (PyErr_Occurred()) - PyErr_Print(); + // if (PyErr_Occurred()) + // PyErr_Print(); PyErr_Clear(); return FALSE; } ActiveModules[active_modules++] = pModule; - return python_to_term(pModule, mod); + return python_to_ptr(pModule, mod); } -static foreign_t -python_f(term_t tmod, term_t fname, term_t tf) -{ +static foreign_t python_f(term_t tmod, term_t fname, term_t tf) { char *s; size_t len; PyObject *pF, *pModule; /* if an atom, fetch again */ - if ( PL_is_atom(tmod) ) { + if (PL_is_atom(tmod)) { PyObject *pName; - if ( !PL_get_nchars(fname, &len, &s, CVT_ALL|CVT_EXCEPTION) ) { + if (!PL_get_nchars(fname, &len, &s, CVT_ALL | CVT_EXCEPTION)) { return FALSE; } #if PY_MAJOR_VERSION < 3 pName = PyString_FromString(s); #else - pName = PyUnicode_FromString(s); + pName = PyUnicode_FromString(s); #endif if (pName == NULL) { return FALSE; @@ -1352,39 +1467,35 @@ python_f(term_t tmod, term_t fname, term_t tf) pModule = PyImport_Import(pName); } else if (!(pModule = term_to_python(tmod))) return FALSE; - if ( !PL_get_nchars(fname, &len, &s, CVT_ALL|CVT_EXCEPTION) ) { + if (!PL_get_nchars(fname, &len, &s, CVT_ALL | CVT_EXCEPTION)) { return FALSE; } pF = PyObject_GetAttrString(pModule, s); PyErr_Print(); Py_DECREF(pModule); - if (pF == NULL || ! PyCallable_Check(pF)) { + if (pF == NULL || !PyCallable_Check(pF)) { return FALSE; } - return python_to_term(pF, tf); + return python_to_ptr(pF, tf); } -static foreign_t -python_o(term_t tmod, term_t fname, term_t tf) -{ +static foreign_t python_o(term_t tmod, term_t fname, term_t tf) { char *s; size_t len; PyObject *pO, *pModule; pModule = term_to_python(tmod); - if ( !PL_get_nchars(fname, &len, &s, CVT_ALL|CVT_EXCEPTION) ) { + if (!PL_get_nchars(fname, &len, &s, CVT_ALL | CVT_EXCEPTION)) { return FALSE; } pO = PyObject_GetAttrString(pModule, s); if (pO == NULL) { return FALSE; } - return python_to_term(pO, tf); + return python_to_ptr(pO, tf); } -static foreign_t -python_len(term_t tobj, term_t tf) -{ +static foreign_t python_len(term_t tobj, term_t tf) { Py_ssize_t len; PyObject *o; @@ -1395,9 +1506,7 @@ python_len(term_t tobj, term_t tf) return PL_unify_int64(tf, len); } -static foreign_t -python_dir(term_t tobj, term_t tf) -{ +static foreign_t python_dir(term_t tobj, term_t tf) { PyObject *dir; PyObject *o; @@ -1405,23 +1514,36 @@ python_dir(term_t tobj, term_t tf) if (o == NULL) return FALSE; dir = PyObject_Dir(o); - return python_to_term(dir, tf); + return python_to_ptr(dir, tf); } -static foreign_t -python_is(term_t tobj, term_t tf) -{ +static foreign_t python_index(term_t tobj, term_t tindex, term_t val) { + PyObject *i; + PyObject *o; + PyObject *f; + o = term_to_python(tobj); + if (o == NULL) + return false; + if (!PySequence_Check(o)) + return false; + i = term_to_python(tindex); + if (i == NULL) + return false; + f = PyObject_CallMethodObjArgs(o, PyString_FromString("getitem"), i); + return python_to_ptr(f, val); +} + +static foreign_t python_is(term_t tobj, term_t tf) { PyObject *o; o = term_to_python(tobj); if (!o) return FALSE; - return python_to_term(o, tf); + return python_to_ptr(o, tf); } -static foreign_t -python_apply(term_t tin, term_t targs, term_t keywds, term_t tf) -{ +static foreign_t python_apply(term_t tin, term_t targs, term_t keywds, + term_t tf) { PyObject *pF, *pValue; PyObject *pArgs, *pKeywords; int i, arity; @@ -1429,74 +1551,55 @@ python_apply(term_t tin, term_t targs, term_t keywds, term_t tf) foreign_t out; term_t targ = PL_new_term_ref(); - pF = term_t - - - - - - - - - - - - - - - - - - - 'o_python(tin); - if ( pF == NULL ) { - PYError() - return FALSE; + pF = term_to_python(tin); + if (pF == NULL) { + return false; } - if (PL_is_atom(keywds) ) - pKeywords = NULL; - else - pKeywords = term_to_python(keywds); - if (! PL_get_name_arity( targs, &aname, &arity) ) { - return FALSE; - } - if (aname == ATOM_t) { - if (arity == 0) - pArgs = NULL; - else - pArgs = term_to_python( targs ); + if (PL_is_atom(targs)) { + pArgs = NULL; } else { - pArgs = PyTuple_New(arity); - if (!pArgs) + + if (PL_is_atom(keywds)) { + pKeywords = NULL; + } else { + pKeywords = term_to_python(keywds); + } + if (!PL_get_name_arity(targs, &aname, &arity)) { return FALSE; - for (i = 0 ; i < arity; i++) { - PyObject *pArg; - if (! PL_get_arg(i+1, targs, targ) ) - return FALSE; - /* ignore (_) */ - if (i == 0 && PL_is_variable(targ)) { - Py_DECREF(pArgs); - pArgs = NULL; - break; + } + if (aname == ATOM_t) { + pArgs = term_to_python(targs); + } else { + pArgs = PyTuple_New(arity); + if (!pArgs) + return FALSE; + for (i = 0; i < arity; i++) { + PyObject *pArg; + if (!PL_get_arg(i + 1, targs, targ)) + return FALSE; + /* ignore (_) */ + if (i == 0 && PL_is_variable(targ)) { + Py_DECREF(pArgs); + pArgs = NULL; + break; + } + pArg = term_to_python(targ); + if (pArg == NULL) + return FALSE; + /* pArg reference stolen here: */ + PyTuple_SetItem(pArgs, i, pArg); } - pArg = term_to_python(targ); - if (pArg == NULL) - return FALSE; - /* pArg reference stolen here: */ - PyTuple_SetItem(pArgs, i, pArg); } } if (PyCallable_Check(pF)) { - if (!pKeywords) - pValue = PyObject_CallObject(pF, pArgs); - else { - pValue = PyObject_Call(pF, pArgs, pKeywords); - // PyObject_Print(pF,stderr,0);fprintf(stderr, "\n"); - //PyObject_Print(pArgs,stderr,0);fprintf(stderr, " "); - //PyObject_Print(pKeywords,stderr,0);fprintf(stderr, "\n"); - } + pValue = PyEval_CallObjectWithKeywords(pF, pArgs, pKeywords); + // PyObject_Print(pF,stderr,0);fprintf(stderr, "\n"); + // PyObject_Print(pArgs,stderr,0);fprintf(stderr, " "); + // PyObject_Print(pKeywords,stderr,0);fprintf(stderr, "\n"); if (!pValue) PyErr_Print(); + } else if (pArgs == NULL) { + pValue = pF; } else { PyErr_Print(); return FALSE; @@ -1505,15 +1608,13 @@ python_apply(term_t tin, term_t targs, term_t keywds, term_t tf) Py_DECREF(pArgs); Py_DECREF(pF); if (pValue == NULL) - return FALSE; - out = python_to_term(pValue, tf); + return FALSE; + out = python_to_ptr(pValue, tf); Py_DECREF(pValue); return out; } -static foreign_t -python_assign(term_t name, term_t exp) -{ +static foreign_t python_assign(term_t name, term_t exp) { PyObject *e = term_to_python(exp); if (e == NULL) @@ -1521,9 +1622,7 @@ python_assign(term_t name, term_t exp) return assign_python(py_Main, name, e) >= 0; } -static foreign_t -python_access(term_t obj, term_t f, term_t out) -{ +static foreign_t python_access(term_t obj, term_t f, term_t out) { PyObject *o = term_to_python(obj), *pValue, *pArgs, *pF; atom_t name; char *s; @@ -1531,17 +1630,17 @@ python_access(term_t obj, term_t f, term_t out) term_t targ = PL_new_term_ref(); if (o == NULL) - return FALSE; - if ( PL_is_atom(f) ) { + return false; + if (PL_is_atom(f)) { if (!PL_get_atom_chars(f, &s)) - return FALSE; + return false; if ((pValue = PyObject_GetAttrString(o, s)) == NULL) { PyErr_Print(); - return FALSE; + return false; } - return python_to_term(pValue, out); + return python_to_ptr(pValue, out); } - if (! PL_get_name_arity( f, &name, &arity) ) { + if (!PL_get_name_arity(f, &name, &arity)) { return FALSE; } /* follow chains of the form a.b.c.d.e() */ @@ -1549,16 +1648,16 @@ python_access(term_t obj, term_t f, term_t out) term_t tleft = PL_new_term_ref(); PyObject *lhs; - if (! PL_get_arg(1, f, tleft) ) + if (!PL_get_arg(1, f, tleft)) return FALSE; lhs = term_to_python(tleft); if ((o = PyObject_GetAttr(o, lhs)) == NULL) { PyErr_Print(); return FALSE; } - if (! PL_get_arg(2, f, f) ) + if (!PL_get_arg(2, f, f)) return FALSE; - if (! PL_get_name_arity( f, &name, &arity) ) { + if (!PL_get_name_arity(f, &name, &arity)) { return FALSE; } } @@ -1568,9 +1667,9 @@ python_access(term_t obj, term_t f, term_t out) return FALSE; } pArgs = PyTuple_New(arity); - for (i = 0 ; i < arity; i++) { + for (i = 0; i < arity; i++) { PyObject *pArg; - if (! PL_get_arg(i+1, f, targ) ) + if (!PL_get_arg(i + 1, f, targ)) return FALSE; /* ignore (_) */ if (i == 0 && PL_is_variable(targ)) { @@ -1581,7 +1680,7 @@ python_access(term_t obj, term_t f, term_t out) if (pArg == NULL) return FALSE; /* pArg reference stolen here: */ - PyTuple_SetItem(pArgs, i, pArg); + PyTuple_SetItem(pArgs, i, pArg); } pValue = PyObject_CallObject(pF, pArgs); if (pValue == NULL) { @@ -1591,76 +1690,61 @@ python_access(term_t obj, term_t f, term_t out) } Py_DECREF(pArgs); Py_DECREF(pF); - return python_to_term(pValue, out); + return python_to_ptr(pValue, out); } -static foreign_t -python_field(term_t f, term_t tobj, term_t tname, term_t tout) -{ - PyObject *o = NULL, *pF; +static foreign_t python_field(term_t parent, term_t att, term_t tobj) { + PyObject *pF; atom_t name; char *s; int arity; - if (! PL_get_name_arity( f, &name, &arity) ) { - return FALSE; - } - /* follow chains of the form a.b.c.d.e() */ - while (name == ATOM_colon && arity == 2) { - term_t tleft = PL_new_term_ref(); - PyObject *lhs; + if (!PL_get_name_arity(att, &name, &arity)) { + return false; + } else { + PyObject *p; - if (! PL_get_arg(1, f, tleft) ) - return FALSE; - lhs = term_to_python(tleft); - if (o == NULL) { - o = lhs; - } else if ((o = PyObject_GetAttr(o, lhs)) == NULL) { - // PyErr_Print(); + // got Scope.Exp + // get Scope ... + p = term_to_python(parent); + // Exp + if (!PL_get_name_arity(att, &name, &arity)) { + return false; + } + s = PL_atom_chars(name); + if (arity == 1 && !strcmp(s, "()")) { + if (!PL_get_arg(1, att, att)) + return false; + if (!PL_get_name_arity(att, &name, &arity)) { + return false; + } + s = PL_atom_chars(name); + } + if (!s || !p) { + return false; + } else if ((pF = PyObject_GetAttrString(p, s)) == NULL) { PyErr_Clear(); return FALSE; } - if (! PL_get_arg(2, f, f) ) - return FALSE; - if (! PL_get_name_arity( f, &name, &arity) ) { - return FALSE; - } } - s = PL_atom_chars(name); - if (!s || !o) { - return FALSE; - } else if ((pF = PyObject_GetAttrString(o, s)) == NULL) { - // PyErr_Print(); - PyErr_Clear(); - return FALSE; - } - return - address_to_term(pF, tobj) && - PL_unify_atom(tname, name) && - PL_unify(tout, f); + return address_to_term(pF, tobj); } -static foreign_t -python_main_module(term_t mod) -{ +static foreign_t python_main_module(term_t mod) { return address_to_term(py_Main, mod); } -static foreign_t -python_function(term_t tobj) -{ +static foreign_t python_function(term_t tobj) { PyObject *obj = term_to_python(tobj); return PyFunction_Check(obj); } -static foreign_t -python_run_command(term_t cmd) -{ +static foreign_t python_run_command(term_t cmd) { char *s; size_t len; - if ( PL_get_nchars(cmd, &len, &s, CVT_ALL|CVT_EXCEPTION) ) { + if (PL_get_nchars(cmd, &len, &s, CVT_ALL | CVT_EXCEPTION)) { PyRun_SimpleString(s); return TRUE; @@ -1668,18 +1752,14 @@ python_run_command(term_t cmd) return FALSE; } -static foreign_t -init_python(void) -{ +static foreign_t init_python(void) { Py_Initialize(); - py_Main = PyImport_AddModule("__main__"); + py_Main = PyImport_AddModule("__main__"); return TRUE; } -static foreign_t -end_python(void) -{ +static foreign_t end_python(void) { Py_Finalize(); return TRUE; @@ -1687,14 +1767,15 @@ end_python(void) install_t install_libpython(void); -install_t -install_libpython(void) -{ // FUNCTOR_dot2 = PL_new_functor(PL_new_atom("."), 2); +install_t install_libpython(void) { + FUNCTOR_dot2 = PL_new_functor(PL_new_atom("."), 2); // FUNCTOR_equal2 = PL_new_functor(PL_new_atom("="), 2); // FUNCTOR_boolop1 = PL_new_functor(PL_new_atom("@"), 1); ATOM_colon = PL_new_atom(":"); - ATOM_true = PL_new_atom("true"); + ATOM_true = PL_new_atom("true"); ATOM_false = PL_new_atom("false"); + ATOM_dot = PL_new_atom("."); + ATOM_none = PL_new_atom("none"); ATOM_t = PL_new_atom("t"); FUNCTOR_abs1 = PL_new_functor(PL_new_atom("abs"), 1); FUNCTOR_all1 = PL_new_functor(PL_new_atom("all"), 1); @@ -1724,20 +1805,23 @@ install_libpython(void) FUNCTOR_colon2 = PL_new_functor(PL_new_atom(":"), 2); FUNCTOR_comma2 = PL_new_functor(PL_new_atom(","), 2); FUNCTOR_equal2 = PL_new_functor(PL_new_atom("="), 2); + FUNCTOR_sqbrackets2 = PL_new_functor(PL_new_atom("[]"), 2); - PL_register_foreign("init_python", 0, init_python, 0); - PL_register_foreign("end_python", 0, end_python, 0); - PL_register_foreign("python_import", 2, python_import, 0); - PL_register_foreign("python_f", 3, python_f, 0); - PL_register_foreign("python_o", 3, python_o, 0); - PL_register_foreign("python_len", 2, python_len, 0); - PL_register_foreign("python_is", 2, python_is, 0); - PL_register_foreign("python_dir", 2, python_dir, 0); - PL_register_foreign("python_apply", 4, python_apply, 0); - PL_register_foreign("python_access", 3, python_access, 0); - PL_register_foreign("python_field", 4, python_field, 0); - PL_register_foreign("python_assign", 2, python_assign, 0); - PL_register_foreign("python_function", 1, python_function, 0); - PL_register_foreign("python_run_command", 1, python_run_command, 0); - PL_register_foreign("python_main_module", 1, python_main_module, 0); + PL_register_foreign("init_python", 0, init_python, 0); + PL_register_foreign("end_python", 0, end_python, 0); + PL_register_foreign("python_import", 2, python_import, 0); + PL_register_foreign("python_f", 3, python_f, 0); + PL_register_foreign("python_o", 3, python_o, 0); + PL_register_foreign("python_len", 2, python_len, 0); + PL_register_foreign("python_is", 2, python_is, 0); + PL_register_foreign("python_dir", 2, python_dir, 0); + PL_register_foreign("python_apply", 4, python_apply, 0); + PL_register_foreign("python_index", 3, python_index, 0); + PL_register_foreign("python_access", 3, python_access, 0); + PL_register_foreign("python_field", 3, python_field, 0); + PL_register_foreign("python_assign", 2, python_assign, 0); + PL_register_foreign("python_export", 2, python_export, 0); + PL_register_foreign("python_function", 1, python_function, 0); + PL_register_foreign("python_run_command", 1, python_run_command, 0); + PL_register_foreign("python_main_module", 1, python_main_module, 0); } diff --git a/packages/python/python.pl b/packages/python/python.pl index 06e35a2f6..e4badb5aa 100644 --- a/packages/python/python.pl +++ b/packages/python/python.pl @@ -1,4 +1,4 @@ -%%% -*- Mode: Prolog; -*- +% % % -* - Mode : Prolog; -*- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Author: Vitor Santos Costa % E-mail: vsc@dcc.fc.up.pt @@ -56,10 +56,25 @@ To best define the interface, one has to address two opposite goals: - make all embedded language interfaces (python, R, Java) as similar as possible. - Currently, YAP supports the following translation: + YAP supports the following translation between Prolog and Python: - - numbers -> identical - -> +| *Prolog* | *Pyhon* | *Prolog Examples* | +|:-------------:|:-------------:|---------------------------------------:| +| Numbers | Numbers | 2.3 +| | | 1545 +| | | +| Atom | Symbols | var +| $Atom | | $var [ = var] +| `string` | 'string' | \`hello\` +| "string" | ' | "hello" +| | | +| Atom(...) | Symb(...) | f( a, b, named=v) +| E.F(...) | E.F (...) | mod.f( a) [ = [mod\|f(a)] ] +| Atom() | | f() [ = '()'(f) ] +| Lists | Lists | [1,2,3] +| t(....) | Tuples | t(1,2,3) to (1,2,3) +| (..., ...) | | (1,2,3)[ = (1,(2,3))] +| {.=., .=.} | Dict | {\`one\`: 1, \`two\`: 2, \`three\`: 3} */ @@ -93,13 +108,20 @@ Data types are := F :- python(F,_). V := F :- var(V), !, python(F,V). -A := F :- python(F, F1), python_assign(A, F1). +A := F :- + python(F, F1), + python_lhs(A, A1), + python_assign(A1, F1, _). user:( V <- F ) :- - V := F. + var(V), !, + V0 := F, + python_export(V0,V). +user:( V <- F ) :- + V := F. user:((<- F)) :- - <- F. + python( F, _). python_import(Module) :- python_do_import(Module, _). @@ -107,54 +129,38 @@ python_import(Module) :- python_do_import(Module, MRef) :- python_mref_cache(Module, MRef), !. python_do_import(Module, MRef) :- - python_import(Module, MRef), + python_import(Module, MRef), assert( python_mref_cache(Module, MRef) ). -fetch_module(M:E, M1, E1, MRef) :- +fetch_module(M:E, _M1, E, MRef) :- atom(M), - python_import(M, MRef0), - module_extend(M, E, M1, E1, MRef0, MRef). - -% -% extend the module as much as we can. -% -module_extend(M0, M:E, MF, EF, _MRef0, MRef) :- - atom(M), - atom_concat([M0,'.',M], MM), - python_import(MM, MRef1), !, - module_extend(MM, E, MF, EF, MRef1, MRef). -module_extend(M0, M.E, MF, EF, _MRef0, MRef) :- - MM = M0.M, - python_import(MM, MRef1), !, - module_extend(MM, E, MF, EF, MRef1, MRef). -module_extend(M, E, M, E, MRef, MRef). - -object_prefix('__obj__'(_)). -object_prefix('$'(_)). -object_prefix('__obj__'(_):_). -object_prefix('$'(_):_). -object_prefix('__obj__'(_)._). -object_prefix('$'(_)._). + python_import(M, MRef). % from an exp take an object, and its corresponding Prolog representation -descend_exp(V, _Obj, _F, _S) :- +descend_exp(V, _Obj) :- var(V), !, throw(error(instantiation_error,_)). -descend_exp(Exp, Obj, F, S) :- - object_prefix(Exp), - !, - python_field(Exp, Obj, F, S). -descend_exp(Exp, Obj, F, S) :- - python_mref_cache(_, MObj), - python_field(MObj:Exp, Obj, F, S), !. -descend_exp(Mod:Exp, Obj, F, S) :- +descend_exp(Mod.Exp, Obj) :- atom(Mod), python_import(Mod, MObj), - python_field(MObj:Exp, Obj, F, S), !. -descend_exp(Mod.Exp, Obj, F, S) :- - atom(Mod), - python_import(Mod, MObj), - python_field(MObj:Exp, Obj, F, S), !. + !, + descend_exp(MObj.Exp, Obj). +descend_exp(C1.C2.E, Obj) :- !, + python_eval_term(C1, O1), + python_field(O1, C2, Obj0 ), + descend_exp(Obj0.E, Obj). +descend_exp(Exp, Obj) :- + fail, + python_mref_cache(_, MObj), + python_field(MObj, Exp, Obj), !. +descend_exp(C1.E, Obj) :- + !, + python_eval_term(C1, O1), + python_field(O1, E, Obj0 ), + python_check_args(E, NE, Dict), + python_apply(Obj0, NE, Dict, Obj). +descend_exp(C, O) :- + python_is(C, O). python_class(Obj) :- python_obj_cache(inspect:isclass(_), F), @@ -164,32 +170,81 @@ process_obj(Obj, _, S, Obj, NS, Dict) :- python_callable(Obj), !, python_check_args(S, NS, Dict). process_obj(Obj, _, S, FObj, NS, Dict) :- - python_class(Obj), + descend_object(Obj:'__init__', FObj, _, _), descend_object(Obj:'__init__', FObj, _, _), python_check_args(S, NS, Dict). +%% @pred python_eval_term( + Obj, -Obj) is semi-det +% It implements the Python interprter's evaluation loop. +% python_eval_term(Obj, Obj) :- - var(Obj), !. + var(Obj), !, + throw(error(instantiation_error, Obj) ). + %% atom use basic evaluation of an atom + %% check if a variable. +python_eval_term(Name, Obj) :- + atom(Name), + !, + python_is(Name, Obj). + %% numbers are evaluated +python_eval_term(N, N) :- number(N), !. +python_eval_term(N, N) :- string(N), !. +%% we assume objects are so yoo. python_eval_term('__obj__'(Obj), '__obj__'(Obj)) :- !. +%% constant functions are useful. +python_eval_term('()'(X), NX) :- !, + python_eval_term(X, NX). +%% $ -> compatibilty with older versions python_eval_term($Name, Obj) :- !, - python_is($Name, Obj). + python_is(Name, Obj). + %% lists are collections of individuals + %% that may need futrher processing python_eval_term([H|T], NL) :- is_list(T), !, maplist( python_eval_term, [H|T], NL). -python_eval_term(N, N) :- atomic(N), !. -python_eval_term(N, N) :- string(N), !. -python_eval_term(Exp, O) :- - descend_exp(Exp, Obj, _Old, S), !, - (functor(S, _, 0) -> - O = Obj - ; - python_check_args(S, NS, Dict), - python_apply(Obj, NS, Dict, O) - ). -python_eval_term(S, O) :- - python_check_args(S, NS, {}), - python_is(NS, O). + %% array access, Python understands numeric + % indices and slices. +python_eval_term(Exp[Min:Max:Step], NEl) :- !, + python_eval_term(slice(Min,Max,Step), Slice), python_eval_term(Exp.getitem(Slice), NEl). +python_eval_term(Exp[Min:Max], NEl) :- !, + python_eval_term(slice(Min,Max), Slice), + python_eval_term(Exp.getitem(Slice), NEl). +python_eval_term(Exp[Index], O) :- !, + python_eval_term(Exp.getitem(Index),O ). +python_eval_term(Tuple, O) :- + Tuple =.. [t|TupleL], !, + maplist(python_eval_term, TupleL, OL), + O =.. [t|OL]. +% function or method call of the form +% a.b.f(...) +python_eval_term(Inp.Exp, Obj) :- !, + %flatten_exp(Exp, Exp1, []), + descend_exp(Inp.Exp, Obj). +python_eval_term(Exp, Obj) :- + p_is(Exp, Obj). + +flatten_exp( V , V, V0) :- + V0 == [], + var( V ), + !. +flatten_exp( V1 ) --> + { var( V1 ) }, + !, + [V1]. +flatten_exp( (V1.V2) ) --> + !, + flatten_exp( V1 ), % propagte the RHS first. + flatten_exp( V2 ). +flatten_exp( V1() ) --> + !, + flatten_exp( V1 ). +flatten_exp( V1, V1, V0 ) :- V0 == [], !. +flatten_exp( V1 ) --> + [V1]. + +python_check_args(_Exp(), t, {}) :- + !. python_check_args(Exp, t, {}) :- Exp =.. [_,V], var(V), !. python_check_args(Exp, NExp, Dict) :- @@ -203,6 +258,14 @@ python_check_args(Exp, NExp, {}) :- maplist(python_eval_term, L, LF), NExp =.. [F|LF]. +python_build_tuple(V) --> + {var(V) }, !, + [V]. +python_build_tuple((X,Y)) --> !, + python_build_tuple(X), + python_build_tuple(Y). +python_build_tuple(X) --> [X]. + % in case it is __init__ from __new__ splice_class(Ref, Ref, ArgNames, ArgNames) :- !. splice_class(_FRef, _Ref, [_|ArgNames], ArgNames). @@ -244,6 +307,28 @@ python(Obj, Out) :- python_command(Cmd) :- python_run_command(Cmd). +python_lhs(Obj,Obj) :- + var(Obj), !. +python_lhs(Name,Name) :- + atom(Name), !. +python_lhs(N, N) :- + number(N), !, + throw(error(type(evaluable, N)), "in left-hand-side of s"). +python_lhs(N) :- + string(N), !, + throw(error(type(evaluable, N)), "in left-hand-side of s"). +python_lhs('__obj__'(Obj), '__obj__'(Obj)) :- !. +python_lhs($Name, Name) :- + !. +python_lhs([H|T], NL) :- + is_list(T), !, + maplist( python_lhs, [H|T], NL). +python_lhs((Exp1,Exp2), O) :- !, + python_build_tuple((Exp1,Exp2), TupleL, []), + Tuple =.. [t|TupleL], % <<< + python_lhs( Tuple, O). +python_lhs(F, F). + start_python :- init_python, python_main_module(MRef), @@ -251,9 +336,9 @@ start_python :- python_command('import sys'), python_import('inspect'), python_mref_cache(inspect, InspRef), - python_field(InspRef:isclass(_), IsClass, _, _), + python_field(InspRef, isclass(_), IsClass), assert(python_obj_cache(inspect:isclass(_), IsClass)), - python_field(InspRef:getargspec(_), GetArgSpec, _, _), + python_field(InspRef, getargspec(_), GetArgSpec), assert(python_obj_cache(inspect:getargspec(_), GetArgSpec)), at_halt(end_python). @@ -264,11 +349,13 @@ add_cwd_to_python :- python_command("sys.argv = [\"yap\"]"). % done -python_assign(Name, Exp, '$'(Name)) :- +python_assign(Name, Exp, N) :- + Name =.. [N,A|As], + Exp =.. [N,E|Es], !, + maplist( python_assign,[A|As], [E|Es]). +python_assign(Name, Exp, Name) :- python_assign(Name, Exp). :- initialization( use_foreign_library(foreign(libpython)), now ). -:- initialization(start_python, now). - -:- initialization(add_cwd_to_python). +:- initialization(start_python ).