diff --git a/.gitignore b/.gitignore index 634f7d844..104696a90 100644 --- a/.gitignore +++ b/.gitignore @@ -80,14 +80,10 @@ GitSHA1.c CMakeLists.txt.* FindPackageLog.txt GitSHA1.c - -GitSHA1.c - -os/YapIOConfig.h - -os/YapIOConfig.h - +clang +cmake-build-debug os/YapIOConfig.h +CodeBlocks os/readterm.c.cpp diff --git a/packages/python/Sources.cmake b/packages/python/Sources.cmake deleted file mode 100644 index d61cb405e..000000000 --- a/packages/python/Sources.cmake +++ /dev/null @@ -1,7 +0,0 @@ -set (PYTHON_SOURCES python.c pl2py.c pybips.c py2pl.c pl2pl.c pypreds.c) - - -set (PYTHON_HEADERS - python.h) - - \ No newline at end of file diff --git a/packages/python/images.py b/packages/python/images.py deleted file mode 100644 index f7abfbb12..000000000 --- a/packages/python/images.py +++ /dev/null @@ -1,48 +0,0 @@ -import base64 -import imghdr -import os - -#from IPython. - -_TEXT_SAVED_IMAGE = "yap_kernel: saved image data to:" - -image_setup_cmd = """ -display () { - TMPFILE=$(mktemp ${TMPDIR-/tmp}/yap_kernel.XXXXXXXXXX) - cat > $TMPFILE - echo "%s $TMPFILE" >&2 -} -""" % _TEXT_SAVED_IMAGE - -def display_data_for_image(filename): - with open(filename, 'rb') as f: - image = f.read() - os.unlink(filename) - - image_type = imghdr.what(None, image) - if image_type is None: - raise ValueError("Not a valid image: %s" % image) - - image_data = base64.b64encode(image).decode('ascii') - content = { - 'data': { - 'image/' + image_type: image_data - }, - 'metadata': {} - } - return content - - -def extract_image_filenames(output): - output_lines = [] - image_filenames = [] - - for line in output.split("\n"): - if line.startswith(_TEXT_SAVED_IMAGE): - filename = line.rstrip().split(": ")[-1] - image_filenames.append(filename) - else: - output_lines.append(line) - - output = "\n".join(output_lines) - return image_filenames, output diff --git a/packages/python/kernel b/packages/python/kernel deleted file mode 100644 index 2f909311d..000000000 --- a/packages/python/kernel +++ /dev/null @@ -1,92 +0,0 @@ -from __future__ import print_function - -from metakernel import MetaKernel - -from metakernel import register_ipython_magics -register_ipython_magics() - -class MetaKernelyap(MetaKernel): - implementation = 'MetaKernel YAP' - implementation_version = '1.0' - language = 'text' - language_version = '0.1' - banner = "MetaKernel YAP" - language_info = { - 'mimetype': 'text/plain', - 'name': 'text', - # ------ If different from 'language': - 'codemirror_mode': { - "version": 2, - "name": "prolog" - } - 'pygments_lexer': 'language', - 'version' : "0.0.1", - 'file_extension': '.yap', - 'help_links': MetaKernel.help_links, - } - - def __init__(self, **kwargs): - - MetaKernel.__init__(self, **kwargs) - self._start_yap() - self.qq = None sq - - def _start_yap(self): - # Signal handlers are inherited by forked processes, and we can't easily - # reset it from the subprocess. Since kernelapp ignores SIGINT except in - # message handlers, we need to temporarily reset the SIGINT handler here - # so that yap and its children are interruptible. - sig = signal.signal(signal.SIGINT, signal.SIG_DFL) - try: - engine = yap.YAPEngine() - engine.query("load_files(library(python), [])").command() - banner = "YAP {0} Kernel".format(self.engine.version()) - - finally: - signal.signal(signal.SIGINT, sig) - - # Register Yap function to write image data to temporary file - #self.yapwrapper.run_command(image_setup_cmd) - - def get_usage(self): - return "This is the YAP kernel." - - def do_execute_direct(self, code): - if not code.strip(): - return {'status': 'ok', 'execution_count': self.execution_count, - 'payload': [], 'user_expressions': {}} - - interrupted = False - try: - print self.q - if self.q is None: - self.q = self.engine.query(code.rstrip()) - if self.q.next(): - vs = self.q.namedVars() - if vs.length() > 0: - l = [] - while vs.length() > 0: - eq = vs.car() - l.append(' '.join([getArg(1).text(), '=', eq.getArg(2).text()) - vs = vs.cdr() - l.append(';') - o = '\n'.join(l) - else: - return 'yes' - self.q = None - - else: - return 'no' - self.q = None - - - - def repr(self, data): - return repr(data) - -if __name__ == '__main__': - try: - from ipykernel.kernelapp import IPKernelApp - except ImportError: - from IPython.kernel.zmq.kernelapp import IPKernelApp - IPKernelApp.launch_instance(kernel_class=MetaKernelyap) diff --git a/packages/python/pandas.yap b/packages/python/pandas.yap index 62c68b1b4..04d5b105d 100644 --- a/packages/python/pandas.yap +++ b/packages/python/pandas.yap @@ -1,61 +1,7 @@ -%matplotlib inline -import numpy as np -import seaborn as sns -import matplotlib.pyplot as plt -sns.set(style="white", context="talk") -rs = np.random.RandomState(7) -pos={0:(0,0), - 1:(1,0), - 2:(0,1), - 3:(1,1), - 4:(0.1,0.9), - 5:(0.3,1.1), - 6:(0.9,0.9) - } +:- use_module( library(python) ). -names={4:'MMM', - 5:'XXX', - 6:'ZZZ'} +:- := import(pandas)). -def plot1(y10,y20): - def gen(f,f0): - return [f[0],f[1],-f[2]]/max(f,f0) - ax1 = plt.subplot2grid((1,2), (0,0), colspan=2) - ax2 = plt.subplot2grid((1,2), (0,1), colspan=2) - ax3 = plt.subplot2grid((2,2), (2,0), colspan=2, rowspan=2) - - xs = ["+-","++","--"] - y1 = gen(y10, y20) - sns.barplot(xs, y1, palette="RdBu_r", ax=ax1) - y2 = gen(y20,y10) - sns.barplot(xs, y2, palette="Set3", ax=ax2) - # Finalize the plot - # sns.despine(bottom=True) - - - G=nx.Graph() - i=0 - G.pos={} # location - G.pop={} # size - lpos={0:(0,0),1:(0,0),2:(0,0),3:(0,0)} - last=len(pos)-1 - for i in range(4,len(pos)): - G.pos[i]=pos[i] - G.pop[i]=2000 - (x,y) = pos[i] - lpos[i] = (x,y-0.05) - if i > 4: - G.add_edge(i-1,i) - else: - G.add_edge(2,i) - G.add_edge(3,last) - nx.draw_networkx_nodes(G,pos,nodelist=range(4,len(pos)),ax=ax3) - nx.draw_networkx_nodes(G,pos,nodelist=[0,1,2,3],node_color='b',ax=ax3) - nx.draw_networkx_edges(G,pos,alpha=0.5,ax=ax3) - nx.draw_networkx_labels(G,lpos,names,alpha=0.5,ax=ax3) - plt.axis('off') - plt.tight_layout(h_pad=3) - plt.savefig("house_with_colors.png") # save as png - -plot1([20,30,10],[30,30,5]) +pred2panda(Pred, Obj) :- + \ No newline at end of file diff --git a/packages/python/pl2pl.c b/packages/python/pl2pl.c index 4cd532168..311260cc4 100644 --- a/packages/python/pl2pl.c +++ b/packages/python/pl2pl.c @@ -27,7 +27,7 @@ static foreign_t array_to_python_list(term_t addr, term_t type, term_t szt, } } if (PL_is_variable(py)) { - return python_to_ptr(list, py); + return address_to_term(list, py); } return assign_to_symbol(py, list); } @@ -71,7 +71,7 @@ static foreign_t array_to_python_tuple(term_t addr, term_t type, term_t szt, } } if (PL_is_variable(py)) { - return python_to_ptr(list, py); + return address_to_term(list, py); } return assign_to_symbol(py, list); } @@ -107,13 +107,44 @@ static foreign_t array_to_python_view(term_t addr, term_t type, term_t szt, return false; } if (PL_is_variable(py)) { - return python_to_ptr(o, py); + return address_to_term(o, py); } return assign_to_symbol(py, o); } +static foreign_t prolog_list_to_python_list(term_t plist, term_t pyt, term_t tlen) { + size_t sz, i; + PyErr_Clear(); + PyObject *pyl = term_to_python(pyt, true, NULL); + term_t targ = PL_new_term_ref(); + + if (PL_skip_list(plist, targ, &sz) <0 || ! PL_get_nil(targ)) { + pyErrorAndReturn( false, false); +} + if (!PyList_Check(pyl)) + { + pyErrorAndReturn( false, false); + } + if (sz > PyList_GET_SIZE(pyl)) + pyErrorAndReturn( false, false); + for (i=0; i < sz; i++) { + if (!PL_get_list(plist, targ, plist)) { + pyErrorAndReturn( false, false); + } + PyObject *t = term_to_python(targ, true, NULL); + PyList_SET_ITEM(pyl, i, t); + } + if (PL_is_variable(tlen)) { + PL_unify_int64(tlen, sz); +} else { +python_assign(tlen, PyLong_FromUnsignedLong(sz), NULL); +} + pyErrorAndReturn( true, false); +} + install_t install_pl2pl(void) { PL_register_foreign("array_to_python_list", 4, array_to_python_list, 0); PL_register_foreign("array_to_python_tuple", 4, array_to_python_tuple, 0); PL_register_foreign("array_to_python_view", 5, array_to_python_view, 0); + PL_register_foreign("prolog_list_to_python_list", 3, prolog_list_to_python_list, 0); } diff --git a/packages/python/pl2py.c b/packages/python/pl2py.c index fdae768ff..22cf8c947 100644 --- a/packages/python/pl2py.c +++ b/packages/python/pl2py.c @@ -2,112 +2,104 @@ #include "python.h" -PyObject *yap_to_python(YAP_Term t, bool eval) { - term_t yt = YAP_InitSlot(t); - PyObject *o = term_to_python(yt, eval); - PL_reset_term_refs(yt); - return o; +PyObject *py_Local, *py_Global; + +PyObject *YE(term_t t, int line, const char *file, const char *code) +{ + char buf[1024]; + YAP_WriteBuffer(YAP_GetFromSlot(t), buf, 1023, 0); + fprintf(stderr, "**** Warning,%s@%s:%d: failed on expression %s\n", code, file, line, buf ); + + return NULL; } + +void YEM(const char * exp, int line, const char *file, const char *code) +{ + fprintf(stderr, "**** Warning,%s@%s:%d: failed while executing %s\n", code, file, line, exp ); +} + + + /** -* term_to_python translates and evaluates from Prolog to Python -* -* @param t handle to Prolog term -* @param t whether should try to evaluate evaluables. -* -* @return a Python object descriptor or NULL if failed -*/ -PyObject *term_to_python(term_t t, bool eval) { - // Yap_DebugPlWritep(YAP_GetFromSlot(t)); fprintf(stderr, " here I + * term_to_python translates and evaluates from Prolog to Python + * + * @param t handle to Prolog term + * @param t whether should try to evaluate evaluables. + * + * @return a Python object descriptor or NULL if failed + */ +PyObject *term_to_python(term_t t, bool eval, PyObject *o) { + // o≈ YAP_Term yt = YAP_GetFromSlot(t); + // Yap_DebugPlWriteln(yt); switch (PL_term_type(t)) { case PL_VARIABLE: { YAP_Term i = YAP_MkIntTerm(t); - return term_to_nametuple( - "H", 1, YAP_InitSlot(YAP_MkApplTerm( - YAP_MkFunctor(YAP_LookupAtom("H"), 1), 1, &i))); + PyObject *rc = term_to_nametuple( + "H", 1, YAP_InitSlot(YAP_MkApplTerm( + YAP_MkFunctor(YAP_LookupAtom("H"), 1), 1, &i))); + return CHECKNULL( t, rc ); }; case PL_ATOM: { YAP_Atom at = YAP_AtomOfTerm(yt); const char *s; - PyObject *o; - PyObject *c = NULL; s = YAP_AtomName(at); - if (strcmp(s, "true") == 0) - return Py_True; - if (strcmp(s, "false") == 0) - return Py_False; - if (strcmp(s, "none") == 0) - return Py_None; - if (strcmp(s, "[]") == 0) - o = PyList_New(0); - else if (strcmp(s, "{}") == 0) - o = PyDict_New(); - /* return __main__,s */ - else if ((o = PyRun_String(s, Py_single_input, PyEval_GetGlobals(), - PyEval_GetLocals()))) { - Py_IncRef(o); - return o; - } else if (PyObject_HasAttrString(py_Main, s)) { - o = PyObject_GetAttrString(py_Main, s); - } else { - o = PyUnicode_FromString(s); - if (eval) - return NULL; - if (PyObject_HasAttrString(py_Main, "A")) - c = PyObject_GetAttrString(py_Main, "A"); - if (!c && PyObject_HasAttrString(py_Yapex, "A")) - c = PyObject_GetAttrString(py_Yapex, "A"); - if (!c || !PyCallable_Check(c)) { - return o; - } else { - PyObject *t = PyTuple_New(1); - PyTuple_SET_ITEM(t, 0, PyUnicode_FromString(s)); - o = PyObject_CallObject(c, t); + if (eval) { + o = PythonLookup(s, o); + /* if (!o) + return o; + */ + } else + { + PyObject *o = PythonLookupSpecial(s); } - } - if (o) { - Py_IncRef(o); - } - return o; - } break; + if (o) { + Py_INCREF( o ); + return CHECKNULL(t,o); + } +} case PL_STRING: { - char *s = NULL; - if (!PL_get_chars(t, &s, REP_UTF8 | CVT_ATOM | CVT_STRING | BUF_MALLOC)) { - return NULL; + const char *s = NULL; + if (YAP_IsAtomTerm(yt)) { + s = YAP_AtomName(YAP_AtomOfTerm(yt)); + } else if (YAP_IsStringTerm(yt)) { + s = YAP_StringOfTerm(yt); + } else { + return CHECKNULL(t, NULL); } #if PY_MAJOR_VERSION < 3 if (proper_ascii_string(s)) { - return PyString_FromStringAndSize(s, strlen(s)); + PyObject *o = PyString_FromStringAndSize(s, strlen(s)) ; + return CHECKNULL(t, o); } else #endif - { - PyObject *pobj = PyUnicode_DecodeUTF8(s, strlen(s), NULL); - // fprintf(stderr, "%s\n", s); - free(s); - if (pobj) { - Py_IncRef(pobj); + { + PyObject *pobj = PyUnicode_DecodeUTF8(s, strlen(s), NULL); + return CHECKNULL(t,pobj); } - return pobj; - } } break; case PL_INTEGER: { int64_t j; if (!PL_get_int64_ex(t, &j)) - return NULL; + return CHECKNULL(t,NULL); #if PY_MAJOR_VERSION < 3 - return PyInt_FromLong(j); + PyObject *o = PyInt_FromLong(j); + return CHECKNULL(t,o); #else - return PyLong_FromLong(j); + PyObject *o = PyLong_FromLong(j); + return CHECKNULL(t,o); #endif } case PL_FLOAT: { + PyObject *out; double fl; if (!PL_get_float(t, &fl)) - return NULL; - return PyFloat_FromDouble(fl); + return CHECKNULL(t,NULL); + out = PyFloat_FromDouble(fl); + return CHECKNULL(t, out); } default: { term_t tail = PL_new_term_ref(), arg; @@ -118,29 +110,44 @@ PyObject *term_to_python(term_t t, bool eval) { arg = tail; out = PyList_New(len); if (!out) - return NULL; + return CHECKNULL(t,NULL); for (i = 0; i < len; i++) { if (!PL_get_list(t, arg, t)) { - return NULL; + PL_reset_term_refs(tail); + return CHECKNULL(t,NULL); } - if (PyList_SetItem(out, i, term_to_python(arg, eval)) < 0) { - return NULL; + if (PyList_SetItem(out, i, term_to_python(arg, eval, o)) < 0) { + return CHECKNULL(t,NULL); } } - return out; + PL_reset_term_refs(tail); + return CHECKNULL(t,out); } else { functor_t fun; + PyObject *rc; - if (!PL_get_functor(t, &fun)) - return NULL; + if (!PL_get_functor(t, &fun)) { + PL_reset_term_refs(tail); + return CHECKNULL(t,NULL); + } if (eval) - return compound_to_pyeval(t, fun); - return compound_to_pytree(t, fun); + rc = compound_to_pyeval(t, o); + else + rc = compound_to_pytree(t, o); + PL_reset_term_refs(tail); + return rc; } } } - return NULL; + return CHECKNULL(t,NULL); +} + +PyObject *yap_to_python(YAP_Term t, bool eval, PyObject *o) { + term_t yt = YAP_InitSlot(t); + o = term_to_python(yt, eval, o); + PL_reset_term_refs(yt); + return o; } PyObject *deref_term_to_python(term_t t) { @@ -150,7 +157,8 @@ PyObject *deref_term_to_python(term_t t) { if (YAP_IsVarTerm(yt)) { char s[32]; char *o = YAP_WriteBuffer(yt, s, 31, 0); - return PyUnicode_FromString(o); + PyObject *p = PyUnicode_FromString(o); + return p; } - return term_to_python(t, false); + return term_to_python(t, false, NULL); } diff --git a/packages/python/plot.py b/packages/python/plot.py deleted file mode 100644 index 62c68b1b4..000000000 --- a/packages/python/plot.py +++ /dev/null @@ -1,61 +0,0 @@ -%matplotlib inline -import numpy as np -import seaborn as sns -import matplotlib.pyplot as plt -sns.set(style="white", context="talk") -rs = np.random.RandomState(7) - -pos={0:(0,0), - 1:(1,0), - 2:(0,1), - 3:(1,1), - 4:(0.1,0.9), - 5:(0.3,1.1), - 6:(0.9,0.9) - } - -names={4:'MMM', - 5:'XXX', - 6:'ZZZ'} - -def plot1(y10,y20): - def gen(f,f0): - return [f[0],f[1],-f[2]]/max(f,f0) - ax1 = plt.subplot2grid((1,2), (0,0), colspan=2) - ax2 = plt.subplot2grid((1,2), (0,1), colspan=2) - ax3 = plt.subplot2grid((2,2), (2,0), colspan=2, rowspan=2) - - xs = ["+-","++","--"] - y1 = gen(y10, y20) - sns.barplot(xs, y1, palette="RdBu_r", ax=ax1) - y2 = gen(y20,y10) - sns.barplot(xs, y2, palette="Set3", ax=ax2) - # Finalize the plot - # sns.despine(bottom=True) - - - G=nx.Graph() - i=0 - G.pos={} # location - G.pop={} # size - lpos={0:(0,0),1:(0,0),2:(0,0),3:(0,0)} - last=len(pos)-1 - for i in range(4,len(pos)): - G.pos[i]=pos[i] - G.pop[i]=2000 - (x,y) = pos[i] - lpos[i] = (x,y-0.05) - if i > 4: - G.add_edge(i-1,i) - else: - G.add_edge(2,i) - G.add_edge(3,last) - nx.draw_networkx_nodes(G,pos,nodelist=range(4,len(pos)),ax=ax3) - nx.draw_networkx_nodes(G,pos,nodelist=[0,1,2,3],node_color='b',ax=ax3) - nx.draw_networkx_edges(G,pos,alpha=0.5,ax=ax3) - nx.draw_networkx_labels(G,lpos,names,alpha=0.5,ax=ax3) - plt.axis('off') - plt.tight_layout(h_pad=3) - plt.savefig("house_with_colors.png") # save as png - -plot1([20,30,10],[30,30,5]) diff --git a/packages/python/py2pl.c b/packages/python/py2pl.c index ecfe2e3b7..e25d25fea 100644 --- a/packages/python/py2pl.c +++ b/packages/python/py2pl.c @@ -1,9 +1,9 @@ #include "python.h" -static foreign_t repr_term(const char *pVal, size_t sz, term_t t) { +static foreign_t repr_term(PyObject *pVal, term_t t) { term_t to = PL_new_term_ref(), t1 = PL_new_term_ref(); - PL_put_string_chars(t1, pVal); + PL_put_pointer(t1, pVal); PL_cons_functor(to, FUNCTOR_pointer1, t1); Py_INCREF(pVal); PL_reset_term_refs(to); @@ -12,119 +12,16 @@ static foreign_t repr_term(const char *pVal, size_t sz, term_t t) { foreign_t assign_to_symbol(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. - */ -int assign_python(PyObject *root, term_t t, PyObject *e) { - switch (PL_term_type(t)) { - case PL_VARIABLE: - if (python_to_ptr(e, t)) - return 1; - else - return -1; - case PL_ATOM: - return assign_to_symbol(t, e); - case PL_STRING: - case PL_INTEGER: - case PL_FLOAT: - return -1; - case PL_TERM: - if (PL_is_list(t)) { - return -1; - } else { - functor_t fun; - - if (!PL_get_functor(t, &fun)) - return -1; - if (fun == FUNCTOR_dollar1) { - if (!PL_get_arg(1, t, t)) - return -1; - return assign_to_symbol(t, e); - } - if (fun == FUNCTOR_pointer1) { - return -1; - } - if (fun == FUNCTOR_sqbrackets2) { - 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, true); - 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_dot2)) { - Py_ssize_t left, right; - if (!PL_get_arg(1, trhs, targ)) - return -1; - left = get_p_int(term_to_python(targ, true), 0); - if (!PL_get_arg(2, trhs, targ)) - return -1; - right = get_p_int(term_to_python(targ, true), PyObject_Size(lhs)); - if (!PySequence_Check(lhs)) - return -1; - PL_reset_term_refs(targ); - return PySequence_SetSlice(lhs, left, right, e); - } else { - rhs = term_to_python(trhs, true); - PL_reset_term_refs(targ); - return PyObject_SetItem(lhs, rhs, e); - } - } - } - } - return -1; -} - foreign_t assign_to_symbol(term_t t, PyObject *e) { - char *s; + char *s = NULL; PyErr_Clear(); 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 false; - } - if (!(w = PL_atom_wchars(at, &len))) - return false; - attr = PyUnicode_FromWideChar(w, wcslen(w)); - if (attr) { - return PyObject_SetAttr(py_Main, attr, e) >= 0; - } else { - PyErr_Print(); - return false; - } - } else if (proper_ascii_string(s)) { - return PyObject_SetAttrString(py_Main, s, e) >= 0; - } else { - PyObject *attr = PyUnicode_DecodeLatin1(s, strlen(s), NULL); - if (!attr) - return -1; - return PyObject_SetAttr(py_Main, attr, e) >= 0; + return false; } -} - -foreign_t python_to_ptr(PyObject *pVal, term_t t) { - Py_IncRef(pVal); - return address_to_term(pVal, t); + PyObject *dic; + if (!lookupPySymbol(s, NULL, &dic)) + dic = py_Main; + return PyObject_SetAttrString(dic, s, e) == 0; } foreign_t python_to_term(PyObject *pVal, term_t t) { @@ -162,17 +59,17 @@ foreign_t python_to_term(PyObject *pVal, term_t t) { atom_t tmp_atom; #if PY_MAJOR_VERSION < 3 - Py_ssize_t sz = PyUnicode_GetSize(pVal) + 1; + = 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); -#endif - tmp_atom = PL_new_atom_wchars(sz, ptr); + tmp_atom = PL_new_atom_wchars(sz, ptr); free(ptr); - return PL_unify_atom(t, tmp_atom); + return PL_unify_atom(t, tmp_atom); +#else + const char *s = PyUnicode_AsUTF8(pVal); + tmp_atom = PL_new_atom( s); + return PL_unify_atom(t, tmp_atom); +#endif } else if (PyByteArray_Check(pVal)) { atom_t tmp_atom = PL_new_atom(PyByteArray_AsString(pVal)); return PL_unify_atom(t, tmp_atom); @@ -209,14 +106,14 @@ foreign_t python_to_term(PyObject *pVal, term_t t) { f = PL_new_functor(ATOM_t, sz); if (!PL_unify_functor(t, f)) return FALSE; + term_t to = PL_new_term_ref(); for (i = 0; i < sz; i++) { - term_t to = PL_new_term_ref(); - if (!PL_unify_arg(i + 1, t, to)) + if (!PL_get_arg(i + 1, t, to)) return FALSE; if (!python_to_term(PyTuple_GetItem(pVal, i), to)) return FALSE; } - return TRUE; + return true; } else if (PyList_Check(pVal)) { term_t to = PL_new_term_ref(); Py_ssize_t i, sz = PyList_GET_SIZE(pVal); @@ -238,43 +135,34 @@ foreign_t python_to_term(PyObject *pVal, term_t t) { tnew = PL_new_term_ref(); /* do something interesting with the values... */ if (!python_to_term(key, tkey)) { + PL_reset_term_refs(tkey); return FALSE; } if (!python_to_term(value, tval)) { + PL_reset_term_refs(tkey); return FALSE; } /* reuse */ tint = tkey; if (!PL_cons_functor(tint, FUNCTOR_colon2, tkey, tval)) { + PL_reset_term_refs(tkey); return FALSE; } if (--left) { if (!PL_cons_functor(tint, FUNCTOR_comma2, tint, tnew)) - return FALSE; - } - if (!PL_unify(ti, tint)) + PL_reset_term_refs(tkey); return FALSE; + } + if (!PL_unify(ti, tint)) { + PL_reset_term_refs(tkey); + return FALSE; + } ti = tnew; + PL_reset_term_refs(tkey); } - PL_cons_functor(to, FUNCTOR_curly1, to); return PL_unify(t, to); } else { - PyObject *pValR = PyObject_Repr(pVal); - if (pValR == NULL) - return address_to_term(pVal, t); - Py_ssize_t sz = PyUnicode_GetSize(pValR) + 1; -#if PY_MAJOR_VERSION < 3 - char *s = malloc(sizeof(char) * sz); - PyObject *us = PyUnicode_EncodeUTF8((const Py_UNICODE *)pValR, sz, NULL); - PyString_AsStringAndSize(us, &s, &sz); - foreign_t rc = repr_term(s, sz, t); - free((void *)s); - return rc; -#else - // new interface - char *s = PyUnicode_AsUTF8AndSize(pValR, &sz); - return repr_term(s, sz, t); -#endif + return repr_term(pVal, t); } } @@ -283,6 +171,122 @@ X_API YAP_Term pythonToYAP(PyObject *pVal) { if (!python_to_term(pVal, t)) return 0; YAP_Term tt = YAP_GetFromSlot(t); - YAP_RecoverSlots(1, t); + PL_reset_term_refs(t); + Py_DECREF(pVal); return tt; } + +PyObject *py_Local, *py_Global; + +/** + * 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. + */ +bool python_assign(term_t t, PyObject *exp, PyObject *context) { + context = find_obj(context, t, false); + // Yap_DebugPlWriteln(yt); + switch (PL_term_type(t)) { + case PL_VARIABLE: { + if (context == NULL) // prevent a.V= N*N[N-1] + return python_to_term(exp, t); + } + + case PL_ATOM: { + char *s = NULL; + PL_get_atom_chars(t, &s); + if (!context) + context = py_Main; + return PyObject_SetAttrString(context, s, exp) == 0; + } + case PL_STRING: + case PL_INTEGER: + case PL_FLOAT: + // domain or type erro? + return false; + default: { + term_t tail = PL_new_term_ref(), arg = PL_new_term_ref(); + size_t len, i; + if (PL_skip_list(t, tail, &len) && + PL_get_nil(tail)) { // true list + + if (PySequence_Check(exp) && PySequence_Length(exp) == len) + + for (i = 0; i < len; i++) { + if (!PL_get_list(t, arg, t)) { + PL_reset_term_refs(tail); + return false; + } + if (!python_assign(arg, PySequence_GetItem(exp, i), context)) { + PL_reset_term_refs(tail); + return false; + } + } + PL_reset_term_refs(tail); + return true; + } else { + functor_t fun; + + if (!PL_get_functor(t, &fun)) { + PL_reset_term_refs(tail); + return false; + } + + if (fun == FUNCTOR_sqbrackets2) { + if (!PL_get_arg(2, t, tail)) { + PL_reset_term_refs(tail); + return false; + } + + PyObject *o = term_to_python(tail, true, context); + if (!PL_get_arg(2, t, tail) && !PL_get_nil(tail)) { + PL_reset_term_refs(tail); + return false; + } + if (!PL_get_arg(1, t, t)) { + PL_reset_term_refs(tail); + return false; + } + PL_reset_term_refs(tail); + PyObject *i = term_to_python(t, true, NULL); + if (!i) { + return false; + } + if (PyList_Check(i)) { + i = PyList_GetItem(i, 0); + long int j; + if (PyList_Check(o)) { +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(i)) + j = PyInt_AsLong(i); + else +#endif + if (PyLong_Check(i)) + j = PyLong_AsLong(i); + else + return NULL; + return PyList_SetItem(o, j, exp) == 0; + } + if (PyDict_Check(i)) { + return PyDict_SetItem(o, i, exp) == 0; + } + return PyObject_SetAttr(o, i, exp) == 0; + } + } + } + } + } + return NULL; +} diff --git a/packages/python/pybips.c b/packages/python/pybips.c index 5437a215b..dbec4bcc7 100644 --- a/packages/python/pybips.c +++ b/packages/python/pybips.c @@ -1,100 +1,195 @@ #include "python.h" /** -* -* @section Python Built-Ins -* -* The Python engine includes a large number of Python built-ins. Some -* of them are interfaced here. -*/ + * + * @section Python Built-Ins + * + * The Python engine includes a large number of Python built-ins. Some + * of them are interfaced here. + */ //@{ -static PyObject *find_obj(PyObject *ob, term_t lhs) { - char *s; - PyObject *out, *pName; - int arity = 0; +#include "python.h" - if (!PL_get_atom_chars(lhs, &s)) { - atom_t name; - if (!PL_get_name_arity(lhs, &name, &arity)) - return NULL; - s = PL_atom_chars(name); +static PyObject *finalLookup(PyObject *i, const char *s) { + PyObject *rc; + if (i == NULL) + return NULL; + if (PyDict_Check(i)) { + if ((rc = PyDict_GetItemString(i, s))) + return rc; } - if (ob) { - out = PyObject_GetAttrString(ob, s); - return out; + if (PyModule_Check(i)) { + if ((rc = PyDict_GetItemString(i, s))) + return rc; } - if (!ob && !arity) { -#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))) { - Py_IncRef(out); - // Py_DecRef(pName); ?? - return out; - } + if (PyObject_HasAttrString(i, s)) { + return PyObject_GetAttrString(i, s); } - if (!ob && py_Main && (out = PyObject_GetAttrString(py_Main, s))) - return out; return NULL; } +PyObject *PythonLookupSpecial(const char *s) { + if (strcmp(s, "true") == 0) { + return Py_True; + } + if (strcmp(s, "false") == 0) { + return Py_False; + } + if (strcmp(s, "none") == 0) + return Py_None; + if (strcmp(s, "[]") == 0) { + return PyList_New(0); + } else if (strcmp(s, "{}") == 0) { + return PyDict_New(); + /* return __main__,s */ + } + return NULL; +} + +PyObject *lookupPySymbol(const char *sp, PyObject *pContext, PyObject **duc) { + PyObject *out = NULL; + if (!sp) + return NULL; + if ((out = finalLookup(pContext, sp))) { + return out; + } + if ((out = finalLookup(py_Context, sp))) { + return out; + } + PyObject *py_Builtin = PyEval_GetBuiltins(); + if ((out = finalLookup(py_Builtin, sp))) { + return out; + } + PyObject *py_Local = PyEval_GetLocals(); + if ((out = finalLookup(py_Local, sp))) { + return out; + } + PyObject *py_Global = PyEval_GetGlobals(); + if ((out = finalLookup(py_Global, sp))) { + return out; + } + if ((out = finalLookup(py_ModDict, sp))) { + return out; + } + if ((out = finalLookup(py_Main, sp))) { + return out; + } + return NULL; +} + +int lookupPyModule(Py_mod *q) { + char buf[1024], *S = buf; + int prefix = 0; + int j; + py_ModDict = PyObject_GetAttrString(py_Sys, "modules"); + PyObject *ob; + S[0] = '\0'; + while (YAP_IsAtomTerm(q->names[prefix])) { + + strcat(S, YAP_AtomName(YAP_AtomOfTerm(q->names[prefix]))); + strcat(S, "."); + S += strlen(S); + prefix++; + } + for (j = prefix; j > 0; j--) { + S = strrchr(buf, '.'); + S[0] = '\0'; + if ((ob = PyDict_GetItemString(py_ModDict, buf)) != NULL && + PyModule_Check(ob)) { + Py_INCREF(ob); + q->mod = ob; + return j; + } + } + return 0; +} + +PyObject *PythonLookup(const char *s, PyObject *oo) { + PyObject *o; + if ((o = PythonLookupSpecial(s))) + return o; + return lookupPySymbol(s, oo, NULL); +} + +PyObject *find_obj(PyObject *ob, term_t l, bool eval) { + YAP_Term hd, yt; + bool may_be_package = true; + + + py_Context = NULL; + yt = YAP_GetFromSlot(l); + while (YAP_IsPairTerm(yt)) { + hd = YAP_HeadOfTerm(yt); + ob = yap_to_python(hd, true, ob); + ob = CHECKNULL(yt, ob); + if (!ob){ + return NULL; + } + yt = YAP_TailOfTerm(yt); + + } + YAP_PutInSlot(l, yt); + return ob; +} + /** -* Python abs -* -* @param t Prolog term with a number -* -* @return a Python object with the number's absolute value -*/ + * 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, *nVal; - if (!PL_get_arg(1, t, t)) - return NULL; - pVal = term_to_python(t, true); + AOK( PL_get_arg(1, t, t), NULL); + pVal = term_to_python(t, true, NULL); + pVal = CHECKNULL( t, pVal ); nVal = PyNumber_Absolute(pVal); Py_DecRef(pVal); return nVal; } /** -* 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. -*/ + * 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)) - return NULL; - v = term_to_python(t, true); + AOK( PL_get_arg(1, t, t), NULL ); + (v = term_to_python(t, true, NULL) ); + v = CHECKNULL( t, v); it = PyObject_GetIter(v); - if (it == NULL) + if (CHECKNULL( t, it) == NULL) return NULL; iternext = *Py_TYPE(it)->tp_iternext; + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + else + return NULL; + } // PyObject_Print(v, stderr, 0); for (;;) { item = iternext(it); - if (item == NULL) + if (CHECKNULL(t,item) == NULL) break; cmp = PyObject_IsTrue(item); Py_DECREF(item); if (cmp < 0) { Py_DECREF(it); - return NULL; + return Py_None; } if (cmp == 0) { Py_DECREF(it); @@ -102,45 +197,38 @@ static PyObject *bip_all(term_t t) { } } Py_DECREF(it); - if (PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_StopIteration)) - PyErr_Clear(); - else - return NULL; - } return Py_True; } /** -* 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. -*/ + * 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)) - return NULL; - v = term_to_python(t, true); + AOK( PL_get_arg(1, t, t), NULL ); + v = term_to_python(t, true, NULL); it = PyObject_GetIter(v); - if (it == NULL) + if (CHECKNULL(t,it) == NULL) return NULL; iternext = *Py_TYPE(it)->tp_iternext; for (;;) { item = iternext(it); - if (item == NULL) + if (CHECKNULL(t,item) == NULL) break; cmp = PyObject_IsTrue(item); Py_DECREF(item); if (cmp < 0) { Py_DECREF(it); - return NULL; + return Py_None; } if (cmp == 1) { Py_DECREF(it); @@ -152,7 +240,7 @@ static PyObject *bip_any(term_t t) { if (PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear(); else - return NULL; + return CHECKNULL(t,NULL); } Py_RETURN_FALSE; } @@ -160,18 +248,16 @@ static PyObject *bip_any(term_t t) { static PyObject *bip_bin(term_t t) { PyObject *v; - if (!PL_get_arg(1, t, t)) - return NULL; - v = term_to_python(t, true); + AOK ( PL_get_arg(1, t, t), NULL); + v = term_to_python(t, true, NULL); return PyNumber_ToBase(v, 2); } static PyObject *bip_float(term_t t, bool eval) { PyObject *pVal, *o; - if (!PL_get_arg(1, t, t)) - return NULL; - pVal = term_to_python(t, eval); + AOK( PL_get_arg(1, t, t), NULL ); + pVal = term_to_python(t, eval, NULL); if (PyLong_Check(pVal)) { o = PyFloat_FromDouble(PyLong_AsLong(pVal)); #if PY_MAJOR_VERSION < 3 @@ -189,9 +275,8 @@ static PyObject *bip_float(term_t t, bool eval) { static PyObject *bip_int(term_t t) { PyObject *pVal, *o; - if (!PL_get_arg(1, t, t)) - return NULL; - pVal = term_to_python(t, true); + AOK( PL_get_arg(1, t, t), NULL ); + pVal = term_to_python(t, true, NULL); #if PY_MAJOR_VERSION < 3 if (PyLong_Check(pVal)) { o = PyInt_FromLong(PyLong_AsLong(pVal)); @@ -216,9 +301,8 @@ static PyObject *bip_int(term_t t) { static PyObject *bip_long(term_t t) { PyObject *pVal, *o; - if (!PL_get_arg(1, t, t)) - return NULL; - pVal = term_to_python(t, true); + AOK( PL_get_arg(1, t, t), NULL ); + pVal = term_to_python(t, true, NULL); if (PyLong_Check(pVal)) { return pVal; #if PY_MAJOR_VERSION < 3 @@ -236,9 +320,8 @@ static PyObject *bip_long(term_t t) { static PyObject *bip_iter(term_t t) { PyObject *v; - if (!PL_get_arg(1, t, t)) - return NULL; - v = term_to_python(t, true); + AOK( PL_get_arg(1, t, t), NULL ); + v = term_to_python(t, true, NULL); return PyObject_GetIter(v); } @@ -246,9 +329,8 @@ static PyObject *bip_ord(term_t t) { PyObject *pVal; Py_ssize_t size; - if (!PL_get_arg(1, t, t)) - return NULL; - pVal = term_to_python(t, true); + AOK( PL_get_arg(1, t, t), NULL ); + pVal = term_to_python(t, true, NULL); if (PyUnicode_Check(pVal)) { #if PY_MAJOR_VERSION < 3 size = PyUnicode_GET_SIZE(pVal); @@ -290,9 +372,8 @@ static PyObject *bip_sum(term_t t) { PyObject *result = NULL; PyObject *temp, *item, *iter; - if (!PL_get_arg(1, t, t)) - return NULL; - seq = term_to_python(t, true); + AOK( PL_get_arg(1, t, t), NULL ); + seq = term_to_python(t, true, NULL); iter = PyObject_GetIter(seq); if (iter == NULL) return NULL; @@ -322,8 +403,8 @@ static PyObject *bip_sum(term_t t) { #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. + 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)) { @@ -435,14 +516,14 @@ to the more general routine. 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); @@ -460,7 +541,7 @@ static long get_int(term_t arg, bool eval) { long low; if (!PL_get_long(arg, &low)) { - PyObject *low = term_to_python(arg, eval); + PyObject *low = term_to_python(arg, eval, NULL); if (PyLong_Check(low)) { return PyLong_AsLong(low); #if PY_MAJOR_VERSION < 3 @@ -475,22 +556,22 @@ static long get_int(term_t arg, bool eval) { } /* 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. -*/ + * 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. - ---------------------------------------------------------------*/ + 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; @@ -641,12 +722,13 @@ static PyObject *structseq_repr(PyObject *iobj) { #endif PyObject *term_to_nametuple(const char *s, int arity, term_t t) { -#if PY_MAJOR_VERSION >= 3 - PyTypeObject *typp; PyObject *o; +#if PY_MAJOR_VERSION >= 3 && 0 + PyTypeObject *typp; PyObject *key = PyUnicode_FromString(s); if (py_F2P && PyDict_Contains(py_F2P, key)) { typp = (PyTypeObject *)PyDict_GetItem(py_F2P, key); + Py_INCREF(typp); } else { typp = PyMem_Malloc(sizeof(PyTypeObject)); @@ -662,12 +744,17 @@ PyObject *term_to_nametuple(const char *s, int arity, term_t t) { typp->tp_repr = structseq_repr; // typp = PyStructSequence_NewType(desc); Py_INCREF(typp); - // typp->tp_flags |= Py_TPFLAGS_HEAPTYPE; - PyModule_AddObject(py_Yapex, s, (PyObject *)typp); + typp->tp_flags |= Py_TPFLAGS_HEAPTYPE; + // don't do this: we cannot add a type as an atribute. + //PyModule_AddObject(py_Main, s, (PyObject *)typp); if (py_F2P) PyDict_SetItem(py_F2P, key, (PyObject *)typp); } - o = PyStructSequence_New(typp); +#endif + o = PyTuple_New(arity); + DebugPrintf("Tuple %p\n", o); + if (o == NULL) + return o; term_t tleft = PL_new_term_ref(); int i; @@ -675,18 +762,21 @@ PyObject *term_to_nametuple(const char *s, int arity, term_t t) { PyObject *pArg; if (!PL_get_arg(i + 1, t, tleft)) return NULL; - pArg = term_to_python(tleft, false); - if (pArg == NULL) + pArg = term_to_python(tleft, false, NULL ); + if (CHECKNULL(tleft,pArg)) return NULL; +#if PY_MAJOR_VERSION >= 3 /* pArg reference stolen here: */ + Py_INCREF(pArg); PyStructSequence_SET_ITEM(o, i, pArg); } ((PyStructSequence *)o)->ob_base.ob_size = arity; - return o; #else - if (PyObject_HasAttrString(py_Yapex, "T")) - c = PyObject_GetAttrString(py_Yapex, "T"); + /* pArg reference stolen here: */ + PyTuple_SET_ITEM(o, i, pArg); + } + PyObject *o1; o1 = PyTuple_New(2); PyTuple_SET_ITEM(o1, 0, PyUnicode_FromString(s)); PyTuple_SET_ITEM(o1, 1, o); @@ -706,19 +796,16 @@ static PyObject *bip_range(term_t t) { if (!PL_get_name_arity(t, &name, &arity)) return NULL; - if (!PL_get_arg(1, t, arg)) - return NULL; + AOK( PL_get_arg(1, t, arg), NULL); ilow = get_int(arg, true); if (arity == 1) { ihigh = ilow; ilow = 0; } else { - if (!PL_get_arg(2, t, arg)) - return NULL; + AOK( PL_get_arg(2, t, arg), NULL ); ihigh = get_int(arg, true); if (arity == 3) { - if (!PL_get_arg(3, t, arg)) - return NULL; + AOK( PL_get_arg(3, t, arg), NULL ); istep = get_int(arg, true); } } @@ -731,11 +818,9 @@ static PyObject *bip_range(term_t t) { 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; - } + AOK ( ( (bign >= 0 && (long)n == bign) || "range() result has too many items" ), NULL ); v = PyList_New(n); + if (v == NULL) return NULL; for (i = 0; i < n; i++) { @@ -749,11 +834,13 @@ static PyObject *bip_range(term_t t) { return NULL; } PyList_SET_ITEM(v, i, w); + Py_INCREF(w); ilow += istep; } return v; } -static int copy_to_dictionary(PyObject *dict, term_t targ, term_t taux, + +static bool copy_to_dictionary(PyObject *dict, term_t targ, term_t taux, bool eval) { PyObject *lhs, *rhs; term_t tleft = PL_new_term_ref(), tright = PL_new_term_ref(); @@ -761,20 +848,15 @@ static int copy_to_dictionary(PyObject *dict, term_t targ, term_t taux, while (true) { functor_t fun; - if (!PL_get_functor(targ, &fun)) - return false; + AOK (PL_get_functor(targ, &fun), 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, eval); - if (!PL_get_arg(2, taux, tright)) { - return FALSE; - } - rhs = term_to_python(tright, eval); + AOK( PL_get_arg(1, taux, tleft), false); + lhs = term_to_python(tleft, eval, NULL); + AOK ( PL_get_arg(2, taux, tright), false); + rhs = term_to_python(tright, eval, NULL); if (PyDict_SetItem(dict, lhs, rhs) < 0) { return FALSE; } @@ -782,21 +864,14 @@ static int copy_to_dictionary(PyObject *dict, term_t targ, term_t taux, // 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; - } + AOK(PL_get_arg(1, targ, targ), false); + AOK(PL_get_arg(1, targ, tleft), false); lhs = atom_to_python_string(tleft); if (lhs == NULL) { return FALSE; } - if (!PL_get_arg(2, targ, tright)) { - return FALSE; - } - rhs = term_to_python(tright, eval); + AOK(PL_get_arg(2, targ, tright), false); + rhs = term_to_python(tright, eval, NULL); if (rhs == NULL) { PyErr_Print(); return FALSE; @@ -813,194 +888,237 @@ static int copy_to_dictionary(PyObject *dict, term_t targ, term_t taux, return TRUE; } -PyObject *compound_to_pytree(term_t t, functor_t fun) { - PyObject *o; - o = py_Main; - atom_t name = PL_functor_name(fun); - int arity = PL_functor_arity(fun); +PyObject *compound_to_data(term_t t, PyObject *o, functor_t fun, bool exec) { + atom_t name; + int len; - 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); - } else if (fun == FUNCTOR_pointer1) { + AOK (PL_get_name_arity(t, &name, &len), o); + + if (fun == FUNCTOR_pointer1) { 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; - /* return __main__.s */ + AOK (PL_get_arg(1, t, t), NULL); + AOK (PL_get_pointer(t, &ptr), NULL) + /* return __main__,s */ return (PyObject *)ptr; - } else if (fun == FUNCTOR_brackets1) { - if (!PL_get_arg(1, t, t)) + } + if (name == ATOM_t) { + term_t targ = PL_new_term_ref(); + PyObject *out; + int i; + + out = PyTuple_New(len); + DebugPrintf("Tuple %p\n", out); + + if (!out) return NULL; - return term_to_python(t, false); - } else if (fun == FUNCTOR_complex2) { + for (i = 0; i < len; i++) { + AOK ( PL_get_arg(i + 1, t, targ), NULL); + PyErr_Clear(); + PyObject *oa = term_to_python(targ, true, o); + bool rc = PyTuple_SET_ITEM(out, i, oa) == 0; + if (rc) { + PyErr_Print(); + } + Py_INCREF(oa); + } + return out; + } else if (fun == FUNCTOR_div2) { term_t targ = PL_new_term_ref(); PyObject *lhs, *rhs; - double d1 = 0.0, d2 = 0.0; - if (!PL_get_arg(1, t, targ)) + AOK ( PL_get_arg(1, t, targ), NULL ); + lhs = term_to_python(targ, true, NULL); + if (!PyNumber_Check(lhs)) return NULL; - lhs = term_to_python(targ, false); - if (!PL_get_arg(2, t, targ)) - return NULL; - rhs = term_to_python(targ, false); - if (lhs == NULL || rhs == NULL) + AOK ( PL_get_arg(2, t, targ), NULL ); + rhs = term_to_python(targ, true, NULL); + if (!PyNumber_Check(rhs)) return NULL; +#if PY_MAJOR_VERSION < 3 + return PyNumber_Divide(lhs, rhs); +#else + return PyNumber_TrueDivide(lhs, rhs); +#endif + } + if (fun == FUNCTOR_sqbrackets2) { + term_t targ = PL_new_term_ref(), trhs = PL_new_term_ref(); + PyObject *v; + Py_ssize_t min, max; + AOK (PL_get_arg(2, t, targ), NULL); + v = term_to_python(targ, true, o); + + AOK (PL_get_arg(1, t, targ), NULL ); + AOK (PL_get_list(targ, trhs, targ) , NULL); + if (PL_is_functor(trhs, FUNCTOR_colon2)) { + if (!PySequence_Check(v)) + return NULL; + min = get_p_int(term_to_python(targ, true, NULL), 0); + AOK (PL_get_arg(1, trhs, targ), NULL); + if (PL_is_functor(targ, FUNCTOR_colon2)) { + return NULL; + } + max = get_p_int(term_to_python(targ, true, o), PyObject_Size(v)); + return PySequence_GetSlice(v, min, max); + } else { + PyObject *ip = term_to_python(trhs, true, o); + if (PySequence_Check(v)) { +#if PY_MAJOR_VERSION < 3 + if (PyLong_Check(ip) { + min = PyLong_AsLong(ip); + } else if (PyInt_Check(ip) { + min = PyInt_asInt(ip); + } +#else + if (PyLong_Check(ip)) { + PyObject *o = PySequence_GetItem(v, PyLong_AsLong(ip)); + if (CHECKNULL(t,o) == NULL) + return NULL; + Py_INCREF(o); + return o; + } +#endif + } else { + o = PyObject_GetItem(v, ip); + Py_INCREF(o); + return o; + } + } + } + if (fun == FUNCTOR_dollar1) { + char *s = NULL; + term_t targ = PL_new_term_ref(); + AOK ( PL_get_arg(1, t, targ), NULL ); + AOK ( PL_get_atom_chars(targ, &s), NULL ); + /* return __main__,s */ + PyObject *o = PyObject_GetAttrString(py_Main, s); + return o; + } + if (fun == FUNCTOR_brackets1) { + AOK ( PL_get_arg(1, t, t), NULL ); + return term_to_python(t, true, NULL); + } + if (fun == FUNCTOR_complex2) { + term_t targ = PL_new_term_ref(); + PyObject *lhs, *rhs; + double d1, d2; + + AOK ( PL_get_arg(1, t, targ), NULL ); + lhs = term_to_python(targ, true, NULL); + AOK ( PyNumber_Check(lhs), NULL ); if (PyFloat_Check(lhs)) { d1 = PyFloat_AsDouble(lhs); } else if (PyLong_Check(lhs)) { - d1 = PyLong_AsDouble(lhs); + d1 = PyLong_AsLong(lhs); #if PY_MAJOR_VERSION < 3 } else if (PyInt_Check(lhs)) { d1 = PyInt_AsLong(lhs); #endif } else { - lhs = NULL; + return NULL; } + AOK (PL_get_arg(2, t, targ), NULL ); + rhs = term_to_python(targ, true, NULL); + AOK (PyNumber_Check(rhs), NULL); if (PyFloat_Check(rhs)) { d2 = PyFloat_AsDouble(rhs); } else if (PyLong_Check(rhs)) { - d2 = PyLong_AsDouble(rhs); + d2 = PyLong_AsLong(rhs); #if PY_MAJOR_VERSION < 3 } else if (PyInt_Check(rhs)) { d2 = PyInt_AsLong(rhs); #endif } else { - lhs = NULL; + return NULL; } - if (lhs && rhs) - return PyComplex_FromDoubles(d1, d2); - } else if (fun == FUNCTOR_curly1) { + + return PyComplex_FromDoubles(d1, d2); + } + if (fun == FUNCTOR_curly1) { term_t targ = PL_new_term_ref(), taux = PL_new_term_ref(); PyObject *dict; - if (!PL_get_arg(1, t, t)) - return NULL; + AOK ( PL_get_arg(1, t, t), NULL ); if (!(dict = PyDict_New())) return NULL; + DebugPrintf("Dict %p\n", dict); + 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, false)) - return NULL; - if (!PL_get_arg(2, t, t)) - return NULL; - } else { - return NULL; - } - } + AOK ( PL_get_arg(1, t, targ), NULL ); + AOK ( PL_is_functor(targ, FUNCTOR_colon2), NULL); + + AOK( copy_to_dictionary(dict, targ, taux, true), NULL); + AOK( PL_get_arg(2, t, t) , NULL ); + } + if (PL_is_functor(t, FUNCTOR_colon2)) { - if (!copy_to_dictionary(dict, t, taux, false)) - return NULL; - } else { - return NULL; + AOK ( copy_to_dictionary(dict, t, taux, true), NULL); } return dict; - } else if (fun == FUNCTOR_sqbrackets2) { - // - term_t targ = PL_new_term_ref(), trhs = PL_new_term_ref(); - PyObject *v; - Py_ssize_t min, max; + } + return o; +} - if (!PL_get_arg(1, t, targ)) - return NULL; - v = term_to_python(targ, true); - 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, true), 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, true), 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 *o = py_Main; - 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; - } +PyObject *compound_to_pytree(term_t t, PyObject *context) { + PyObject *o = py_Main, *no; + functor_t fun; + atom_t name; + int arity; + + o = find_obj(context, t, false); + AOK( PL_get_name_arity(t, &name, &arity), NULL ); + if (arity == 0) + return term_to_python(t, false, o); + AOK( PL_get_functor(t, &fun), NULL); + if ((no = compound_to_data(t, o, fun, false)) != o && no) { + return no; } if (!arity) { - char *s; + char *s = NULL; - if (!PL_get_atom_chars(t, &s)) - return NULL; + AOK (!PL_get_atom_chars(t, &s), NULL ); // this should never happen - return term_to_python(t, false); + return term_to_python(t, false, o); } else { const char *s; - if (!(s = PL_atom_chars(name))) + if (!(s = PL_atom_chars(name))) { return NULL; + } term_t tleft; int i; - PyObject *o1; o = PyTuple_New(arity); + DebugPrintf("Tuple %p\n", o); tleft = PL_new_term_ref(); for (i = 0; i < arity; i++) { PyObject *pArg; - if (!PL_get_arg(i + 1, t, tleft)) - return NULL; - pArg = term_to_python(tleft, false); + AOK (PL_get_arg(i + 1, t, tleft), NULL ); + pArg = term_to_python(tleft, false, NULL); if (pArg == NULL) return NULL; /* pArg reference stolen here: */ PyTuple_SET_ITEM(o, i, pArg); + Py_INCREF(pArg); } return term_to_nametuple(s, arity, t); } } -PyObject *compound_to_pyeval(term_t t, functor_t fun) { - 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); - } else if (fun == FUNCTOR_pointer1) { - void *ptr; - term_t targ = PL_new_term_ref(); +PyObject *compound_to_pyeval(term_t t, PyObject *context) { + PyObject *o = NULL, *no; + atom_t name; + int arity; + functor_t fun; - if (!PL_get_arg(1, t, targ)) - return NULL; - if (!PL_get_pointer(targ, &ptr)) - return NULL; - /* 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, true); - } else if (fun == FUNCTOR_abs1) { + o = find_obj(context, t, true); + AOK (PL_get_name_arity(t, &name, &arity), NULL ); + if (arity == 0) + return term_to_python(t, true, o); + if (!PL_get_functor(t, &fun)) + return NULL; + if ((no = compound_to_data(t, o, fun, true)) != o && no) { + return no; + } + if (fun == FUNCTOR_abs1) { return bip_abs(t); } else if (fun == FUNCTOR_all1) { return bip_all(t); @@ -1023,98 +1141,34 @@ PyObject *compound_to_pyeval(term_t t, functor_t fun) { return bip_range(t); } else if (fun == FUNCTOR_sum1) { return bip_sum(t); - } else if (fun == FUNCTOR_len1) { + } + if (fun == FUNCTOR_len1) { term_t targ = PL_new_term_ref(); PyObject *ptr; - if (!PL_get_arg(1, t, targ)) - return NULL; - ptr = term_to_python(targ, true); + AOK (PL_get_arg(1, t, targ), NULL ); + ptr = term_to_python(targ, true, NULL); return PyLong_FromLong(PyObject_Length(ptr)); - } else if (fun == FUNCTOR_dir1) { + } + if (fun == FUNCTOR_dir1) { term_t targ = PL_new_term_ref(); PyObject *ptr; - if (!PL_get_arg(1, t, targ)) - return NULL; - ptr = term_to_python(targ, true); + AOK ( PL_get_arg(1, t, targ), NULL ); + ptr = term_to_python(targ, true, NULL); return PyObject_Dir(ptr); - } else if (fun == FUNCTOR_complex2) { - 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, true); - 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); -#endif - } else { - return NULL; - } - if (!PL_get_arg(2, t, targ)) - return NULL; - rhs = term_to_python(targ, true); - 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); -#endif - } else { - return NULL; - } + } - return PyComplex_FromDoubles(d1, d2); - } else if (fun == FUNCTOR_curly1) { - 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, true)) - 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, true)) - return NULL; - } else { - return NULL; - } - return dict; - } else if (fun == FUNCTOR_plus2) { + else if (fun == FUNCTOR_plus2) { term_t targ = PL_new_term_ref(); PyObject *lhs, *rhs; if (!PL_get_arg(1, t, targ)) return NULL; - lhs = term_to_python(targ, true); - if (!PL_get_arg(2, t, targ)) - return NULL; - rhs = term_to_python(targ, true); + lhs = term_to_python(targ, true, NULL); + AOK( PL_get_arg(2, t, targ), NULL ); + rhs = term_to_python(targ, true, NULL); if (PySequence_Check(lhs) && PySequence_Check(rhs)) { return PySequence_Concat(lhs, rhs); } @@ -1129,12 +1183,12 @@ PyObject *compound_to_pyeval(term_t t, functor_t fun) { if (!PL_get_arg(1, t, targ)) return NULL; - lhs = term_to_python(targ, true); + lhs = term_to_python(targ, true, NULL); if (!PyNumber_Check(lhs)) return NULL; if (!PL_get_arg(2, t, targ)) return NULL; - rhs = term_to_python(targ, true); + rhs = term_to_python(targ, true, NULL); if (!PyNumber_Check(rhs)) return NULL; return PyNumber_Subtract(lhs, rhs); @@ -1142,12 +1196,12 @@ PyObject *compound_to_pyeval(term_t t, functor_t fun) { term_t targ = PL_new_term_ref(); PyObject *lhs, *rhs; - if (!PL_get_arg(1, t, targ)) - return NULL; - lhs = term_to_python(targ, true); - if (!PL_get_arg(2, t, targ)) - return NULL; - rhs = term_to_python(targ, true); + AOK (PL_get_arg(1, t, targ), NULL ); + (lhs = term_to_python(targ, true, NULL)); + CHECKNULL( targ, lhs); + AOK (PL_get_arg(2, t, targ), NULL ); + (rhs = term_to_python(targ, true, NULL)); + CHECKNULL( targ, rhs); if (PySequence_Check(lhs) && ( #if PY_MAJOR_VERSION < 3 PyInt_Check(rhs) || @@ -1158,134 +1212,55 @@ PyObject *compound_to_pyeval(term_t t, functor_t fun) { 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; + } + if (!arity) { + char *s = NULL; + PyObject *pValue; - if (!PL_get_arg(1, t, targ)) + AOK (PL_get_atom_chars(t, &s), NULL ); + pValue = PyObject_GetAttrString(o, s); + if (CHECKNULL(t,pValue) == NULL) { + PyErr_Print(); return NULL; - lhs = term_to_python(targ, true); - if (!PyNumber_Check(lhs)) - return NULL; - if (!PL_get_arg(2, t, targ)) - return NULL; - rhs = term_to_python(targ, true); - if (!PyNumber_Check(rhs)) - return NULL; -#if PY_MAJOR_VERSION < 3 - return PyNumber_Divide(lhs, rhs); -#else - return PyNumber_TrueDivide(lhs, rhs); -#endif - } 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; - v = term_to_python(targ, true); - 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, true), 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, true), PyObject_Size(v)); - if (!PySequence_Check(v)) - return NULL; - return PySequence_GetSlice(v, min, max); } - } else if (fun == FUNCTOR_dot2) { + return pValue; + } else { + char *s = PL_atom_chars(name); + o = lookupPySymbol(s, o, NULL); + if (CHECKNULL(t,o) == NULL) { + PyErr_Print(); + return NULL; + } + if ( !PyCallable_Check(o)) { + return term_to_nametuple(s, arity, t); + } + PyObject *pArgs = PyTuple_New(arity); + DebugPrintf("Tuple %p\n", pArgs); + int i; term_t tleft = PL_new_term_ref(); - PyObject *pArgs, *o; - long i; - int arity; - atom_t name; - - 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; + AOK (PL_get_arg(i + 1, t, tleft), NULL ); /* ignore (_) */ if (i == 0 && PL_is_variable(tleft)) { - Py_DECREF(pArgs); - pArgs = NULL; + Py_DECREF(pArgs); + pArgs = Py_None; } - pArg = term_to_python(tleft, true); - if (pArg == NULL) - return NULL; + pArg = term_to_python(tleft, true, NULL); + pArg = CHECKNULL( tleft, pArg ); /* pArg reference stolen here: */ + Py_INCREF(pArg); PyTuple_SetItem(pArgs, i, pArg); } PyObject *rc; - rc = PyObject_CallObject(o, pArgs); + + //PyObject_Print(pArgs, stderr, 0); + //PyObject_Print(o, stderr, 0); + CHECK_CALL(rc ,t, PyObject_CallObject(o, pArgs)); + Py_DECREF(pArgs); + Py_DECREF(o); + DebugPrintf("CallObject %p\n", rc); + return rc; - } else { - 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; - - out = PyTuple_New(len); - if (!out) - return NULL; - for (i = 0; i < len; i++) { - if (!PL_get_arg(i + 1, t, targ)) { - return NULL; - } - PyErr_Clear(); - PyObject *oa = term_to_python(targ, true); - PyObject *rc = PyTuple_SET_ITEM(out, i, oa); - if (rc) - PyErr_Print(); - } - return out; - } } - return NULL; } diff --git a/packages/python/pypreds.c b/packages/python/pypreds.c index b778400e4..743f6eb45 100644 --- a/packages/python/pypreds.c +++ b/packages/python/pypreds.c @@ -1,882 +1,688 @@ - -#include "python.h" - -static int conj_size(term_t source) { - if (PL_is_functor(source, FUNCTOR_comma2)) { - term_t a1 = PL_new_term_ref(), a2 = PL_new_term_ref(); - if (PL_get_arg(1, source, a1) <= 0 || PL_get_arg(2, source, a2) <= 0) - return -1; - return conj_size(a1) + conj_size(a2); - } - return 1; -} - -static int conj_copy(term_t target, PyObject *e, int pos) { - if (PL_is_functor(target, FUNCTOR_comma2)) { - term_t a1 = PL_new_term_ref(), a2 = PL_new_term_ref(); - if (PL_get_arg(1, target, a1) <= 0 || PL_get_arg(2, target, a2) <= 0) - return -1; - int p1 = conj_copy(a1, e, pos); - return conj_copy(a2, e, p1); - } else { - assign_python(py_Main, target, PyTuple_GetItem(e, pos)); - return pos + 1; - } -} - -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)) { - PyObject *pName; - - 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); -#endif - if (pName == NULL) { - { - return false; - } - } - pModule = PyImport_Import(pName); - PyErr_Clear(); - } else if (!(pModule = term_to_python(tmod, true))) { - PyErr_Clear(); - { - return false; - } - } - 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)) { - { - return false; - } - } - { - foreign_t rc = python_to_ptr(pF, tf); - return rc; - } -} - -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, true); - if (!PL_get_nchars(fname, &len, &s, CVT_ALL | CVT_EXCEPTION)) { - { - return false; - } - } - pO = PyObject_GetAttrString(pModule, s); - if (pO == NULL) { - { - return false; - } - } - { - foreign_t rc = python_to_ptr(pO, tf); - ; - return rc; - } -} - -static foreign_t python_len(term_t tobj, term_t tf) { - Py_ssize_t len; - PyObject *o; - - o = term_to_python(tobj, true); - if (o == NULL) { - return false; - } - len = PyObject_Length(o); - return PL_unify_int64(tf, len); -} - -static foreign_t python_dir(term_t tobj, term_t tf) { - PyObject *dir; - PyObject *o; - - o = term_to_python(tobj, true); - if (o == NULL) { - return false; - } - dir = PyObject_Dir(o); - { - foreign_t rc = python_to_ptr(dir, tf); - ; - return rc; - } -} - -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, true); - if (o == NULL) { - return false; - } - if (!PySequence_Check(o)) { - return false; - } - i = term_to_python(tindex, true); - if (i == NULL) { - return false; - } -#if PY_MAJOR_VERSION < 3 - f = PyObject_CallMethodObjArgs(o, PyString_FromString("getitem"), i); -#else - f = PyObject_CallMethodObjArgs(o, PyUnicode_FromString("getitem"), i); -#endif - { - foreign_t rc = python_to_ptr(f, val); - ; - return rc; - } -} - -static foreign_t python_is(term_t tobj, term_t tf) { - PyObject *o; - - o = term_to_python(tobj, true); - if (!o) { - return false; - } - foreign_t rc = python_to_ptr(o, tf); - return rc; -} - -static foreign_t python_assign_item(term_t parent, term_t indx, term_t tobj) { - PyObject *pF, *pI; - - PyObject *p; - - // get Scope ... - pI = term_to_python(indx, true); - // got Scope.Exp - // get Scope ... - p = term_to_python(parent, true); - // Exp - // get Scope ... - pF = term_to_python(parent, true); - // Exp - if (!pI || !p) { - { - return false; - } - } else if (PyObject_SetItem(p, pI, pF)) { - PyErr_Print(); - { - return false; - } - } - Py_DecRef(pI); - Py_DecRef(p); - - { - return true; - } -} - -/** assign a tuple to something: -*/ -static foreign_t python_assign_tuple(term_t t_lhs, term_t t_rhs) { - PyObject *e; - Py_ssize_t sz; - functor_t f; - - e = term_to_python(t_rhs, true); - if (!e || !PyTuple_Check(e)) { - return -1; - } - sz = PyTuple_Size(e); - switch (PL_term_type(t_lhs)) { - case PL_VARIABLE: - return PL_unify(t_lhs, t_rhs); - case PL_ATOM: - return assign_python(py_Main, t_rhs, e); - case PL_TERM: - if (PL_get_functor(t_lhs, &f)) { - term_t targ = PL_new_term_ref(); - // assign a tuple to a tuple - if (PL_functor_name(f) == ATOM_t && ((sz = PL_functor_arity(f)))) { - Py_ssize_t i; - for (i = 0; i < sz; i++) { - PL_get_arg(i + 1, t_lhs, targ); - assign_python(py_Main, targ, PyTuple_GetItem(e, i)); - } - } else if (PL_functor_name(f) == ATOM_comma) { - int n = conj_size(t_lhs); - if (n != sz) - return -1; - return conj_copy(t_lhs, e, 0); - } else if (PL_functor_name(f) == ATOM_dot) { // vectors - size_t len; - term_t tail = PL_new_term_ref(); - - PL_skip_list(t_lhs, tail, &len); - if (!PL_get_nil(tail)) - return -1; - term_t arg = tail; - size_t i; - - for (i = 0; i < len; i++) { - if (!PL_get_list(t_rhs, arg, t_rhs)) { - return -1; - } - if (assign_python(py_Main, arg, PyTuple_GetItem(e, i)) < 0) - return -1; - } - } - } - } - return -1; -} - -static foreign_t python_item(term_t parent, term_t indx, term_t tobj) { - PyObject *pF, *pI; - - PyObject *p; - - // get Scope ... - pI = term_to_python(indx, true); - // got Scope.Exp - // get Scope ... - p = term_to_python(parent, true); - // Exp - if (!pI || !p) { - return false; - } else if ((pF = PyObject_GetItem(p, pI)) == NULL) { - PyErr_Print(); - { - return false; - } - } - Py_DecRef(pI); - Py_DecRef(p); - - { - foreign_t rc; - rc = address_to_term(pF, tobj); - return rc; - } -} - -static foreign_t python_slice(term_t parent, term_t indx, term_t tobj) { - PyObject *pF, *pI; - - PyObject *p; - - // get Scope ... - pI = term_to_python(indx, true); - // got Scope.Exp - // get Scope ... - p = term_to_python(parent, true); - // Exp - if (!pI || !p) { - { - return false; - } - } else if ((pF = PySequence_GetSlice(p, 0, 0)) == NULL) { - PyErr_Print(); - { - return false; - } - } - Py_DecRef(pI); - Py_DecRef(p); - - { - foreign_t rc; - rc = address_to_term(pF, tobj); - return rc; - } -} - -static foreign_t python_apply(term_t tin, term_t targs, term_t keywds, - term_t tf) { - PyObject *pF; - PyObject *pArgs, *pKeywords; - PyObject *pValue; - int i, arity; - atom_t aname; - foreign_t out; - term_t targ = PL_new_term_ref(); - - pF = term_to_python(tin, true); - PyErr_Clear(); - if (pF == NULL) { - { - return false; - } - } - if (PL_is_atom(targs)) { - pArgs = NULL; - } else { - - if (!PL_get_name_arity(targs, &aname, &arity)) { - { - return false; - } - } - if (arity == 1 && PL_get_arg(1, targs, targ) && PL_is_variable(targ)) { - /* ignore (_) */ - pArgs = NULL; - } 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; - } - pArg = term_to_python(targ, true); - if (pArg == NULL) { - return false; - } - /* pArg reference stolen here: */ - PyTuple_SetItem(pArgs, i, pArg); - } - } - } - if (PL_is_atom(keywds)) { - pKeywords = NULL; - } else { - pKeywords = term_to_python(keywds, true); - } - if (PyCallable_Check(pF)) { - 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 - Py_IncRef(pValue); - } else if (pArgs == NULL) { - pValue = pF; - - if (pF) { - Py_IncRef(pValue); - } - } else { - PyErr_Print(); - { - return false; - } - } - if (pArgs) - Py_DECREF(pArgs); - Py_DECREF(pF); - if (pValue == NULL) { - return false; - } - out = python_to_ptr(pValue, tf); - return out; -} - -static foreign_t python_assign(term_t name, term_t exp) { - PyObject *e = term_to_python(exp, true); - - if (e == NULL) { - return false; - } - return assign_python(py_Main, name, e) >= 0; -} - -static foreign_t python_assign_field(term_t source, term_t name, term_t exp) { - PyObject *e = term_to_python(exp, true), *root = term_to_python(source, true); - - if (e == NULL) { - return false; - } - return assign_python(root, name, e) >= 0; -} - -static foreign_t python_builtin_eval(term_t caller, term_t dict, term_t out) { - PyObject *pI, *pArgs, *pOut; - PyObject *env; - atom_t name; - char *s; - int i, arity; - term_t targ = PL_new_term_ref(); - - if ((env = py_Builtin) == NULL) { - // no point in even trying - { - return false; - } - } - if (PL_get_name_arity(caller, &name, &arity)) { - if (!(s = PL_atom_chars(name))) { - return false; - } - if ((pI = PyObject_GetAttrString(env, s)) == NULL) { - PyErr_Print(); - { - return false; - } - } - } else { - // Prolog should make sure this never happens. - { - return false; - } - } - pArgs = PyTuple_New(arity); - for (i = 0; i < arity; i++) { - PyObject *pArg; - if (!PL_get_arg(i + 1, caller, targ)) { - return false; - } - /* ignore (_) */ - if (i == 0 && PL_is_variable(targ)) { - pArg = Py_None; - } else { - pArg = term_to_python(targ, true); - if (pArg == NULL) { - return false; - } - } - /* pArg reference stolen here: */ - if (PyTuple_SetItem(pArgs, i, pArg)) { - PyErr_Print(); - { - return false; - } - } - } - pOut = PyObject_CallObject(pI, pArgs); - Py_DECREF(pArgs); - Py_DECREF(pI); - if (pOut == NULL) { - PyErr_Print(); - { - return false; - } - } - { - foreign_t rc = python_to_ptr(pOut, out); - ; - return rc; - } -} - -static foreign_t python_access(term_t obj, term_t f, term_t out) { - PyObject *o = term_to_python(obj, true), *pValue, *pArgs, *pF; - atom_t name; - char *s; - int i, arity; - term_t targ = PL_new_term_ref(); - - if (o == NULL) { - return false; - } - if (PL_is_atom(f)) { - if (!PL_get_atom_chars(f, &s)) { - return false; - } - if ((pValue = PyObject_GetAttrString(o, s)) == NULL) { - PyErr_Print(); - { - return false; - } - } - { - return python_to_term(pValue, out); - } - } - if (!PL_get_name_arity(f, &name, &arity)) { - { - return false; - } - } - /* follow chains of the form a.b.c.d.e() */ - while (name == ATOM_dot && arity == 2) { - term_t tleft = PL_new_term_ref(); - PyObject *lhs; - - if (!PL_get_arg(1, f, tleft)) { - return false; - } - lhs = term_to_python(tleft, true); - if ((o = PyObject_GetAttr(o, lhs)) == NULL) { - PyErr_Print(); - { - 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) { - return false; - } - if ((pF = PyObject_GetAttrString(o, s)) == NULL) { - PyErr_Print(); - { - return false; - } - } - pArgs = PyTuple_New(arity); - for (i = 0; i < arity; i++) { - PyObject *pArg; - if (!PL_get_arg(i + 1, f, targ)) { - return false; - } - /* ignore (_) */ - if (i == 0 && PL_is_variable(targ)) { - pArgs = Py_None; - } - pArg = term_to_python(targ, true); - if (pArg == NULL) { - return false; - } - /* pArg reference stolen here: */ - PyTuple_SetItem(pArgs, i, pArg); - } - pValue = PyObject_CallObject(pF, pArgs); - Py_DECREF(pArgs); - Py_DECREF(pF); - if (pValue == NULL) { - { - return false; - } - } - { - return python_to_term(pValue, out); - } -} - -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(att, &name, &arity)) { - { - return false; - } - } else { - PyObject *p; - - // got Scope.Exp - // get Scope ... - p = term_to_python(parent, true); - // 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; - } - } - } - { - foreign_t rc; - rc = address_to_term(pF, tobj); - return rc; - } -} - -static foreign_t python_main_module(term_t mod) { - { - foreign_t rc; - rc = address_to_term(py_Main, mod); - return rc; - } -} - -static foreign_t python_function(term_t tobj) { - PyObject *obj = term_to_python(tobj, true); - foreign_t rc = PyFunction_Check(obj); - - return rc; -} - -foreign_t python_builtin(term_t out) { - { - foreign_t rc; - rc = address_to_term(py_Builtin, out); - return rc; - } -} - -static foreign_t python_run_file(term_t file) { - char *s; - size_t len; - char si[256]; - s = si; - if (PL_get_nchars(file, &len, &s, CVT_ALL | CVT_EXCEPTION)) { -#if PY_MAJOR_VERSION < 3 - PyObject *PyFileObject = PyFile_FromString(si, "r"); - PyRun_SimpleFileEx(PyFile_AsFile(PyFileObject), "test.py", 1); -#else - FILE *f = fopen(s, "r"); - if (f == NULL) { - return false; - } - PyRun_SimpleFileEx(f, s, 1); -#endif - { - { - return true; - } - } - } - { - return false; - } -} - -extern PyThreadState *YAP_save; - - -static foreign_t python_run_command(term_t cmd) { - char *s; - bool rc = false; - size_t len; - char si[256]; - - s = si; - if (PL_get_nchars(cmd, &len, &s, CVT_ALL | CVT_EXCEPTION)) { - PyRun_SimpleString(s); - rc = true; - } - return rc; -} - -static foreign_t python_run_script(term_t cmd, term_t fun) { - char si[256], sf[256]; - size_t len = 255, len1 = 255; - PyObject *pName, *pModule, *pFunc; - PyObject *pArgs = NULL, *pValue; - char *s; - - s = si; - if (PL_get_nchars(cmd, &len, &s, CVT_ALL | CVT_EXCEPTION) && - (s = sf) != NULL && - PL_get_nchars(fun, &len1, &s, CVT_ALL | CVT_EXCEPTION)) { - -#if PY_MAJOR_VERSION < 3 - pName = PyString_FromString("rbm"); -#else - // asssumes UTF-8 - pName = PyUnicode_FromString("rbm"); -#endif - /* Error checking of pName left out */ - - pModule = PyImport_Import(pName); - PyErr_Clear(); - Py_DECREF(pName); - - if (pModule != NULL) { - pFunc = PyObject_GetAttrString(pModule, sf); - /* pFunc is a new reference */ - - if (pFunc && PyCallable_Check(pFunc)) { - pValue = PyObject_CallObject(pFunc, pArgs); - if (pValue != NULL) { - Py_DECREF(pValue); - } else { - Py_DECREF(pFunc); - Py_DECREF(pModule); - PyErr_Print(); - fprintf(stderr, "Call failed\n"); - { - return false; - } - } - } else { - if (PyErr_Occurred()) - PyErr_Print(); - fprintf(stderr, "Cannot find function \"%s\"\n", sf); - } - Py_XDECREF(pFunc); - Py_DECREF(pModule); - } else { - PyErr_Print(); - { - return false; - } - } - { - return true; - } - } - { - return false; - } -} - -static foreign_t python_export(term_t t, term_t pl) { - foreign_t rc = false; - 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 */ - rc = python_to_term((PyObject *)ptr, pl); - } - return rc; -} - -static foreign_t p_python_within_python(void) { return python_in_python; } - -static int python_import(term_t mname, term_t mod) { - PyObject *pName, *pModule; - term_t arg = PL_new_term_ref(); - char s0[MAXPATHLEN], *s = s0; - - while (true) { - size_t len; - - len = (MAXPATHLEN - 1) - (s - s0); - if (PL_is_pair(mname)) { - char *sa; - if (!PL_get_arg(1, mname, arg) || !PL_get_atom_chars(arg, &sa) || - !PL_get_arg(2, mname, mname)) { - return false; - } - s = stpcpy(s, sa); - *s++ = '.'; - s[0] = '\0'; - } else if (!PL_get_nchars(mname, &len, &s, - CVT_ALL | CVT_EXCEPTION | REP_UTF8)) { - { - return false; - } - } else { - break; - } - } -#if PY_MAJOR_VERSION < 3 - pName = PyString_FromString(s0); -#else - pName = PyUnicode_FromString(s0); -#endif - if (pName == NULL) { - { - return false; - } - } - pModule = PyImport_Import(pName); - PyErr_Clear(); - Py_DECREF(pName); - if (pModule == NULL) { -#if EXTRA_MESSSAGES - if (PyErr_Occurred()) - PyErr_Print(); - PyErr_Clear(); -#endif - { - return false; - } - } - ActiveModules[active_modules++] = pModule; - { foreign_t rc = python_to_ptr(pModule, mod); - return rc; - } -} - - static PyThreadState *_saveP; - -static YAP_Int - p_python_get_GIL(void) - { - PyEval_AcquireThread(_saveP); - return true; - } - -static YAP_Int - p_python_release_GIL(void) - { - _saveP = PyEval_SaveThread(); - return true; - } - -install_t install_pypreds(void) { - PL_register_foreign("python_builtin_eval", 3, python_builtin_eval, 0); - PL_register_foreign("python_builtin", 1, python_builtin, 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_field", 3, python_field, 0); - PL_register_foreign("python_assign", 2, python_assign, 0); - PL_register_foreign("python_assign_field", 3, python_assign_field, 0); - PL_register_foreign("python_assign_tuple", 2, python_assign_tuple, 0); - PL_register_foreign("python_export", 2, python_export, 0); - PL_register_foreign("python_function", 1, python_function, 0); - PL_register_foreign("python_slice", 4, python_slice, 0); - PL_register_foreign("python_item", 3, python_item, 0); - PL_register_foreign("python_assign_item", 3, python_assign_item, 0); - PL_register_foreign("python_run_file", 1, python_run_file, 0); - PL_register_foreign("python_run_command", 1, python_run_command, 0); - PL_register_foreign("python_run_script", 2, python_run_script, 0); - PL_register_foreign("python_main_module", 1, python_main_module, 0); - PL_register_foreign("python_import", 2, python_import, 0); - PL_register_foreign("python_access", 3, python_access, 0); - PL_register_foreign("release_GIL", 0, p_python_release_GIL, 0); - PL_register_foreign("acquire_GIL", 0, p_python_get_GIL, 0); -} + +#include "python.h" + +PyObject *py_Main; + +void pyErrorHandler__(int line, const char *file, const char *code) { + // this code is called if a Python error is found. + fprintf(stderr, " Python error detected at %s %s:%d\n\n", code, file, line); + PyErr_Print(); +} +static foreign_t python_len(term_t tobj, term_t tf) { + Py_ssize_t len; + PyObject *o; + + o = term_to_python(tobj, true, NULL); + if (o == NULL) { + pyErrorAndReturn(false, false); + } + len = PyObject_Length(o); + pyErrorAndReturn(PL_unify_int64(tf, len), false); +} + +static foreign_t python_dir(term_t tobj, term_t tf) { + PyObject *dir; + PyObject *o; + + o = term_to_python(tobj, true, NULL); + if (o == NULL) { + pyErrorAndReturn(false, false); + } + dir = PyObject_Dir(o); + { + foreign_t rc = address_to_term(dir, tf); + ; + pyErrorAndReturn(rc, false); + } +} + +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, true, NULL); + if (o == NULL) { + pyErrorAndReturn(false, false); + } + if (!PySequence_Check(o)) { + pyErrorAndReturn(false, false); + } + i = term_to_python(tindex, true, NULL); + if (i == NULL) { + pyErrorAndReturn(false, false); + } +#if PY_MAJOR_VERSION < 3 + f = PyObject_CallMethodObjArgs(o, PyString_FromString("getitem"), i); +#else + f = PyObject_CallMethodObjArgs(o, PyUnicode_FromString("getitem"), i); +#endif + { + foreign_t rc = address_to_term(f, val); + ; + pyErrorAndReturn(rc, false); + } +} + +static foreign_t python_is(term_t tobj, term_t tf) { + PyObject *o; + + term_t lim = python_acquire_GIL(); + + o = term_to_python(tobj, true, NULL); + if (!o) { + python_release_GIL(lim); + pyErrorAndReturn(false, false); + } + foreign_t rc = python_to_term(o, tf); + if (rc) + PyErr_Clear(); + python_release_GIL(lim); + pyErrorAndReturn(rc, false); +} + + +static foreign_t python_proc(term_t tobj) { + PyObject *o; + + term_t lim = python_acquire_GIL(); + + o = term_to_python(tobj, true, NULL); + python_release_GIL(lim); + bool rc = o != NULL; + pyErrorAndReturn(rc , false); +} + + +static foreign_t python_slice(term_t parent, term_t indx, term_t tobj) { + PyObject *pF, *pI; + + PyObject *p; + + // get Scope ... + pI = term_to_python(indx, true, NULL); + // got Scope.Exp + // get Scope ... + p = term_to_python(parent, true, NULL); + // Exp + if (!pI || !p) { + { pyErrorAndReturn(false, false); } + } else if ((pF = PySequence_GetSlice(p, 0, 0)) == NULL) { + PyErr_Print(); + { pyErrorAndReturn(false, false); } + } + Py_DecRef(pI); + Py_DecRef(p); + Py_INCREF(pF); + { + foreign_t rc; + rc = address_to_term(pF, tobj); + pyErrorAndReturn(rc, false); + } +} + +static foreign_t python_apply(term_t tin, term_t targs, term_t keywds, + term_t tf) { + PyObject *pF; + PyObject *pArgs, *pKeywords; + PyObject *pValue; + int i, arity; + atom_t aname; + foreign_t out; + term_t targ = PL_new_term_ref(); + + pF = term_to_python(tin, true, NULL); + PyErr_Clear(); + if (pF == NULL) { + { pyErrorAndReturn(false, false); } + } + if (PL_is_atom(targs)) { + pArgs = NULL; + } else { + + if (!PL_get_name_arity(targs, &aname, &arity)) { + { pyErrorAndReturn(false, false); } + } + if (arity == 1 && PL_get_arg(1, targs, targ) && PL_is_variable(targ)) { + /* ignore (_) */ + pArgs = NULL; + } else { + + pArgs = PyTuple_New(arity); + DebugPrintf("Tuple %p\n", pArgs); + + if (!pArgs) { + pyErrorAndReturn(false, false); + } + for (i = 0; i < arity; i++) { + PyObject *pArg; + if (!PL_get_arg(i + 1, targs, targ)) { + pyErrorAndReturn(false, false); + } + pArg = term_to_python(targ, true, NULL); + if (pArg == NULL) { + pyErrorAndReturn(false, false); + } + /* pArg reference stolen here: */ + PyTuple_SetItem(pArgs, i, pArg); + } + } + } + if (PL_is_atom(keywds)) { + pKeywords = NULL; + } else { + pKeywords = term_to_python(keywds, true, NULL); + } + if (PyCallable_Check(pF)) { + 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 + Py_IncRef(pValue); + } else if (pArgs == NULL) { + pValue = pF; + + if (pF) { + Py_IncRef(pValue); + } + } else { + PyErr_Print(); + { pyErrorAndReturn(false, false); } + } + if (pArgs) + Py_DECREF(pArgs); + Py_DECREF(pF); + if (pValue == NULL) { + pyErrorAndReturn(false, false); + } + out = address_to_term(pValue, tf); + pyErrorAndReturn(out, false); +} + +static foreign_t assign_python(term_t exp, term_t name) { +term_t stackp = python_acquire_GIL(); + PyObject *e = term_to_python(exp, true, NULL); + + if (e == NULL) { + python_release_GIL(stackp); + pyErrorAndReturn(false, false); + } + bool b = python_assign(name, e, NULL); + python_release_GIL(stackp); + pyErrorAndReturn(b, false); +} + + +static foreign_t python_builtin_eval(term_t caller, term_t dict, term_t out) { + PyErr_Clear(); + PyObject *pI, *pArgs, *pOut; + PyObject *env; + atom_t name; + char *s; + int i, arity; + term_t targ = PL_new_term_ref(); + + if ((env = py_Builtin) == NULL) { + // no point in even trying + { pyErrorAndReturn(false, false); } + } + if (PL_get_name_arity(caller, &name, &arity)) { + if (!(s = PL_atom_chars(name))) { + pyErrorAndReturn(false, false); + } + if ((pI = PyObject_GetAttrString(env, s)) == NULL) { + PyErr_Print(); + { pyErrorAndReturn(false, false); } + } + Py_INCREF(pI); + } else { + // Prolog should make sure this never happens. + { pyErrorAndReturn(false, false); } + } + pArgs = PyTuple_New(arity); + DebugPrintf("Tuple %p\n", pArgs); + for (i = 0; i < arity; i++) { + PyObject *pArg; + if (!PL_get_arg(i + 1, caller, targ)) { + pyErrorAndReturn(false, false); + } + /* ignore (_) */ + if (i == 0 && PL_is_variable(targ)) { + pArg = Py_None; + } else { + pArg = term_to_python(targ, true, NULL); + if (pArg == NULL) { + pyErrorAndReturn(false, false); + } + } + /* pArg reference stolen here: */ + if (PyTuple_SetItem(pArgs, i, pArg)) { + PyErr_Print(); + { pyErrorAndReturn(false, false); } + } + } + pOut = PyObject_CallObject(pI, pArgs); + Py_DECREF(pArgs); + Py_DECREF(pI); + if (pOut == NULL) { + PyErr_Print(); + { pyErrorAndReturn(false, false); } + } + { + foreign_t rc = address_to_term(pOut, out); + ; + pyErrorAndReturn(rc, false); + } +} + +static foreign_t python_access(term_t obj, term_t f, term_t out) { + PyErr_Clear(); + PyObject *o = term_to_python(obj, true, NULL), *pValue, *pArgs, *pF; + atom_t name; + char *s = NULL; + int i, arity; + term_t targ = PL_new_term_ref(); + + if (o == NULL) { + pyErrorAndReturn(false, false); + } + if (PL_is_atom(f)) { + if (!PL_get_atom_chars(f, &s)) { + pyErrorAndReturn(false, false); + } + if ((pValue = PyObject_GetAttrString(o, s)) == NULL) { + PyErr_Print(); + { pyErrorAndReturn(false, false); } + } + Py_INCREF(pValue); + { pyErrorAndReturn(python_to_term(pValue, out), false); } + } + if (!PL_get_name_arity(f, &name, &arity)) { + { pyErrorAndReturn(false, false); } + } + s = PL_atom_chars(name); + if (!s) { + pyErrorAndReturn(false, false); + } + if ((pF = PyObject_GetAttrString(o, s)) == NULL) { + DebugPrintf("Function %p\n", pArgs); + PyErr_Print(); + { pyErrorAndReturn(false, false); } + } + pArgs = PyTuple_New(arity); + DebugPrintf("Tuple %p\n", pArgs); + for (i = 0; i < arity; i++) { + PyObject *pArg; + if (!PL_get_arg(i + 1, f, targ)) { + pyErrorAndReturn(false, false); + } + /* ignore (_) */ + if (i == 0 && PL_is_variable(targ)) { + pArgs = Py_None; + } + pArg = term_to_python(targ, true, NULL); + if (pArg == NULL) { + pyErrorAndReturn(false, false); + } + /* pArg reference stolen here: */ + PyTuple_SetItem(pArgs, i, pArg); + } + pValue = PyObject_CallObject(pF, pArgs); + Py_DECREF(pArgs); + Py_DECREF(pF); + if (pValue == NULL) { + { pyErrorAndReturn(false, false); } + } + { pyErrorAndReturn(python_to_term(pValue, out), false); } +} + +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(att, &name, &arity)) { + { pyErrorAndReturn(false, false); } + } else { + PyObject *p; + + // got Scope.Exp + // get Scope ... + p = term_to_python(parent, true, NULL); + // Exp + if (!PL_get_name_arity(att, &name, &arity)) { + { pyErrorAndReturn(false, false); } + } + s = PL_atom_chars(name); + if (arity == 1 && !strcmp(s, "()")) { + if (!PL_get_arg(1, att, att)) { + pyErrorAndReturn(false, false); + } + if (!PL_get_name_arity(att, &name, &arity)) { + { pyErrorAndReturn(false, false); } + } + s = PL_atom_chars(name); + } + if (!s || !p) { + { pyErrorAndReturn(false, false); } + } else if ((pF = PyObject_GetAttrString(p, s)) == NULL) { + PyErr_Clear(); + { pyErrorAndReturn(false, false); } + } + } + { + foreign_t rc; + rc = address_to_term(pF, tobj); + pyErrorAndReturn(rc, false); + } +} + +static foreign_t python_main_module(term_t mod) { + { + foreign_t rc; + PyErr_Clear(); + rc = address_to_term(py_Main, mod); + pyErrorAndReturn(rc, false); + } +} + +static foreign_t python_function(term_t tobj) { + PyErr_Clear(); + PyObject *obj = term_to_python(tobj, true, NULL); + foreign_t rc = PyFunction_Check(obj); + + pyErrorAndReturn(rc, false); +} + +foreign_t python_builtin(term_t out) { + { + foreign_t rc; + PyErr_Clear(); + rc = address_to_term(py_Builtin, out); + pyErrorAndReturn(rc, false); + } +} + +static foreign_t python_run_file(term_t file) { + char *s; + size_t len; + char si[256]; + s = si; + PyErr_Clear(); + if (PL_get_nchars(file, &len, &s, CVT_ALL | CVT_EXCEPTION)) { +#if PY_MAJOR_VERSION < 3 + PyObject *PyFileObject = PyFile_FromString(si, "r"); + PyRun_SimpleFileEx(PyFile_AsFile(PyFileObject), "test.py", 1); +#else + FILE *f = fopen(s, "r"); + if (f == NULL) { + pyErrorAndReturn(false, false); + } + PyRun_SimpleFileEx(f, s, 1); +#endif + { + { pyErrorAndReturn(true, false); } + } + } + { pyErrorAndReturn(false, false); } +} + +extern PyThreadState *YAP_save; + +static foreign_t python_run_command(term_t cmd) { + char *s; + bool rc = false; + size_t len; + char si[256]; + + PyErr_Clear(); + s = si; + if (PL_get_nchars(cmd, &len, &s, CVT_ALL | CVT_EXCEPTION)) { + PyRun_SimpleString(s); + rc = true; + } + pyErrorAndReturn(rc, false); +} + +static foreign_t python_run_script(term_t cmd, term_t fun) { + char si[256], sf[256]; + size_t len = 255, len1 = 255; + PyObject *pName, *pModule, *pFunc; + PyObject *pArgs = NULL, *pValue; + char *s; + + PyErr_Clear(); + s = si; + if (PL_get_nchars(cmd, &len, &s, CVT_ALL | CVT_EXCEPTION) && + (s = sf) != NULL && + PL_get_nchars(fun, &len1, &s, CVT_ALL | CVT_EXCEPTION)) { + +#if PY_MAJOR_VERSION < 3 + pName = PyString_FromString("rbm"); +#else + // asssumes UTF-8 + pName = PyUnicode_FromString("rbm"); +#endif + /* Error checking of pName left out */ + + pModule = PyImport_Import(pName); + PyErr_Clear(); + Py_DECREF(pName); + + if (pModule != NULL) { + pFunc = PyObject_GetAttrString(pModule, sf); + /* pFunc is a new reference */ + + if (pFunc && PyCallable_Check(pFunc)) { + pValue = PyObject_CallObject(pFunc, pArgs); + if (pValue != NULL) { + Py_DECREF(pValue); + } else { + Py_DECREF(pFunc); + Py_DECREF(pModule); + PyErr_Print(); + fprintf(stderr, "Call failed\n"); + { pyErrorAndReturn(false, false); } + } + } else { + pyErrorHandler(); + if (PyErr_Occurred()) + PyErr_Print(); + fprintf(stderr, "Cannot find function \"%s\"\n", sf); + } + Py_XDECREF(pFunc); + Py_DECREF(pModule); + } else { + PyErr_Print(); + { pyErrorAndReturn(false, false); } + } + { pyErrorAndReturn(true, false); } + } + { pyErrorAndReturn(false, false); } +} + +static foreign_t python_export(term_t t, term_t pl) { + foreign_t rc = false; + PyErr_Clear(); + if (PL_is_functor(t, FUNCTOR_pointer1)) { + void *ptr; + term_t targ = PL_new_term_ref(); + + if (!PL_get_arg(1, t, targ)) { + pyErrorAndReturn(false, false); + } + if (!PL_get_pointer(targ, &ptr)) { + pyErrorAndReturn(false, false); + } + Py_INCREF((PyObject *)ptr); + /* pyErrorAndReturn( __main__, false) */ + rc = python_to_term((PyObject *)ptr, pl); + } + pyErrorAndReturn(rc, false); +} + + +/** + * @pred python_import(MName, Mod) + * Import a python module to the YAP environment. + * + * @param mname module name, either an atom or a sequence of atoms, + * eg os.sys + * @param mod the pointer to the Python object + * @return success? + */ +static int python_import(term_t mname, term_t mod) { + PyObject *pName; + +term_t t0 = python_acquire_GIL(); + term_t arg = PL_new_term_ref(); + char s0[MAXPATHLEN], *s = s0; + while (true) { + size_t len; + + len = (MAXPATHLEN - 1) - (s - s0); + if (PL_is_pair(mname)) { + char *sa = NULL; + if (!PL_get_arg(1, mname, arg) || !PL_get_atom_chars(arg, &sa) || + !PL_get_arg(2, mname, mname)) { + python_release_GIL(t0); + pyErrorAndReturn(false, false); + } + PL_get_atom_chars(arg, &sa); + strcpy(s, sa); + s += strlen(s); + *s++ = '.'; + s[0] = '\0'; + } else if (!PL_get_nchars(mname, &len, &s, + CVT_ATOM | CVT_EXCEPTION | REP_UTF8)) { + python_release_GIL(t0); + pyErrorAndReturn(false, false); + } else { + break; + } + } +#if PY_MAJOR_VERSION < 3 + pName = PyString_FromString(s0); +#else + pName = PyUnicode_FromString(s0); +#endif + python_release_GIL(t0); +if (pName == NULL) { + pyErrorAndReturn(false, false); + } + + PyObject *pModule = PyImport_Import(pName); + + Py_DECREF(pName); + if (pModule == NULL) { +#if EXTRA_MESSSAGES + if (PyErr_Occurred()) + PyErr_Print(); + PyErr_Clear(); +#endif + { pyErrorAndReturn(false, false); } + } + { + foreign_t rc = address_to_term(pModule, mod); + pyErrorAndReturn(rc, false); + } +} + +static foreign_t python_to_rhs(term_t inp, term_t t) { + PyObject *pVal; + PyErr_Clear(); + pVal = term_to_python(inp, true, NULL); + if (pVal == NULL) + pyErrorAndReturn(false, false); + pyErrorAndReturn(address_to_term(pVal, t), false); +} + +// static PyThreadState *_saveP = NULL; +static bool _threaded = false; + +/* +static YAP_Int + p_python_ensure(term_t ptr) + { + PyGILState_STATE _tState = PyGILState_Ensure(); + pyErrorAndReturn( PL_unify_int64(ptr, _tState), false); + } + +static YAP_Int + p_python_release(term_t ptr) + { + + PyGILState_STATE _tState; + PL_get_int64( ptr, &_tState); + PyGILState_Release( _tState ); + pyErrorAndReturn( true, false); + } +*/ + +int _locked = 0; +PyThreadState *tstate; + +static YAP_Int p_python_threaded(void) { + + PyErr_Clear(); + PyRun_SimpleString("print( \"thread initiated\" )"); + // PyEval_ReleaseThread(tstate); + _threaded = true; + // _locked = 0; + pyErrorAndReturn(true, false); +} + +static PyGILState_STATE gstate; + + term_t python_acquire_GIL(void) { + term_t curSlot = 1; //PL_new_term_ref(); + if (!_threaded) + pyErrorAndReturn(curSlot, false); + // extern int Yap_do_low_level_trace; + // Yap_do_low_level_trace = 1; + // f[rintf( stderr, "++%d\n", ++_locked); + // if (_locked > 0) { _locked++ ; } + // else + gstate = PyGILState_Ensure(); + pyErrorAndReturn(curSlot, false); +} + +bool python_release_GIL(term_t curBlock) { + PyErr_Clear(); + // PL_reset_term_refs(curBlock); + if (_threaded) { + PyGILState_Release(gstate); + } + pyErrorAndReturn(true, false); +} + +//: prolog: release python + +install_t install_pypreds(void) { + PL_register_foreign("python_builtin_eval", 3, python_builtin_eval, 0); + PL_register_foreign("python_builtin", 1, python_builtin, 0); + PL_register_foreign("python_import", 2, python_import, 0); + PL_register_foreign("python_to_rhs", 2, python_to_rhs, 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_field", 3, python_field, 0); + PL_register_foreign("python_assign", 2, assign_python, 0); + PL_register_foreign("python_export", 2, python_export, 0); + PL_register_foreign("python_function", 1, python_function, 0); + PL_register_foreign("python_slice", 4, python_slice, 0); + PL_register_foreign("python_run_file", 1, python_run_file, 0); + PL_register_foreign("python_proc", 1, python_proc, 0); + PL_register_foreign("python_run_command", 1, python_run_command, 0); + PL_register_foreign("python_run_script", 2, python_run_script, 0); + PL_register_foreign("python_main_module", 1, python_main_module, 0); + PL_register_foreign("python_import", 2, python_import, 0); + PL_register_foreign("python_access", 3, python_access, 0); + PL_register_foreign("python_threaded", 0, p_python_threaded, 0); +} diff --git a/packages/python/python.c b/packages/python/python.c index f74353f47..942b91857 100644 --- a/packages/python/python.c +++ b/packages/python/python.c @@ -1,10 +1,8 @@ #include "python.h" -int assign_python(PyObject *root, term_t t, PyObject *e); - atom_t ATOM_true, ATOM_false, ATOM_colon, ATOM_dot, ATOM_none, ATOM_t, - ATOM_comma, ATOM_builtin, ATOM_A, ATOM_V, ATOM_self; + ATOM_comma, ATOM_builtin, ATOM_A, ATOM_V, ATOM_self; functor_t FUNCTOR_dollar1, FUNCTOR_abs1, FUNCTOR_all1, FUNCTOR_any1, FUNCTOR_bin1, FUNCTOR_brackets1, FUNCTOR_comma2, FUNCTOR_dir1, @@ -12,21 +10,16 @@ functor_t FUNCTOR_dollar1, FUNCTOR_abs1, FUNCTOR_all1, FUNCTOR_any1, 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_equal2, FUNCTOR_sqbrackets2, FUNCTOR_dot2; + FUNCTOR_colon2, FUNCTOR_comma2, FUNCTOR_equal2, FUNCTOR_sqbrackets2, + FUNCTOR_dot2, FUNCTOR_brackets1; -PyObject *py_Main; -PyObject *py_Builtin; -PyObject *py_Yapex; -PyObject *term_to_python(term_t t, bool eval); -foreign_t python_to_ptr(PyObject *pVal, term_t t); +X_API PyObject *py_Builtin; +X_API PyObject *py_Yapex; +X_API PyObject *py_Sys; +PyObject *py_Context; +PyObject *py_ModDict; -PyObject *py_F2P; -PyObject *term_to_python(term_t t, bool eval); - -int assign_python(PyObject *root, term_t t, PyObject *e); - -PyObject *ActiveModules[32]; -int active_modules = 0; +X_API PyObject *py_F2P; bool python_in_python; @@ -54,6 +47,7 @@ static void install_py_constants(void) { FUNCTOR_long1 = PL_new_functor(PL_new_atom("long"), 1); FUNCTOR_float1 = PL_new_functor(PL_new_atom("float"), 1); FUNCTOR_curly1 = PL_new_functor(PL_new_atom("{}"), 1); + FUNCTOR_brackets1 = PL_new_functor(PL_new_atom("()"), 1); FUNCTOR_dollar1 = PL_new_functor(PL_new_atom("$"), 1); FUNCTOR_pointer1 = PL_new_functor(PL_new_atom("__obj__"), 1); FUNCTOR_dir1 = PL_new_functor(PL_new_atom("dir"), 1); @@ -74,43 +68,68 @@ static void install_py_constants(void) { 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); + // if (python_in_python) { py_Main = PyImport_AddModule("__main__"); + Py_INCREF(py_Main); + py_Sys = PyImport_AddModule("sys"); + Py_INCREF(py_Sys); py_Builtin = PyImport_AddModule("__builtin__"); - py_Yapex = PyImport_AddModule("yapex"); + Py_INCREF(py_Builtin); + py_ModDict = PyObject_GetAttrString(py_Sys, "modules"); + py_Yapex = PyImport_ImportModule("yapex"); + PyObject *py_Yap = PyImport_ImportModule("yap"); + Py_INCREF(py_Yapex); + //py_F2P = PyObject_GetAttrString(py_Yap, "globals"); + py_F2P = NULL; } foreign_t end_python(void) { Py_Finalize(); - return TRUE; + return true; } -X_API bool init_python(void) { - char **argv; - python_in_python = false; - if (YAP_DelayInit(init_python, "python")) { - // wait for YAP_Init - return false; - } +static bool libpython_initialized = 0; + +bool do_init_python(void) { + // char **argv; + + if (libpython_initialized) + return true; + libpython_initialized = true; // PyGILState_STATE gstate = PyGILState_Ensure(); term_t t = PL_new_term_ref(); - if (!Py_IsInitialized()) { - python_in_python = true; - YAP_Argv(&argv); - if (argv) { -#if PY_MAJOR_VERSION < 3 - Py_SetProgramName(argv[0]); -#else - wchar_t *buf = Py_DecodeLocale(argv[0], NULL); - Py_SetProgramName(buf); -#endif - } - Py_Initialize(); - } + Py_Initialize(); install_py_constants(); PL_reset_term_refs(t); install_pypreds(); install_pl2pl(); // PyGILState_Release(gstate); return !python_in_python; + } +X_API bool init_python(void) { + + return do_init_python(); +} + +#ifdef _WIN32 + +#include + +int WINAPI win_python(HANDLE, DWORD, LPVOID); + +int WINAPI win_python(HANDLE hinst, DWORD reason, LPVOID reserved) { + switch (reason) { + case DLL_PROCESS_ATTACH: + break; + case DLL_PROCESS_DETACH: + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + return 1; +} +#endif diff --git a/packages/python/python.h b/packages/python/python.h index 91fb3fb68..1ff1be427 100644 --- a/packages/python/python.h +++ b/packages/python/python.h @@ -1,13 +1,3 @@ -#ifdef _XOPEN_SOURCE -#undef _XOPEN_SOURCE // python does its own thing -#endif -#include -#include -#ifdef HAVE_STAT -#undef HAVE_STATa -#endif -#include -#define EXTRA_MESSSAGES 1 //@{ @@ -18,6 +8,43 @@ * for related work. */ +#ifdef _XOPEN_SOURCE +#undef _XOPEN_SOURCE // python does its own thing +#endif + +#include +#include +#ifdef HAVE_STAT +#undef HAVE_STATa +#endif +#include +#include +#define EXTRA_MESSSAGES 1 + +#ifndef PYTHON_H +#define PYTHON_H 1 + +PyObject *find_obj(PyObject *ob, term_t lhs, bool eval); + +#if DEBUG_MEMORY +#define DebugPrintf(s, op) fprintf(stderr, "%s:%d: " s, __FILE__, __LINE__, op) +#else +#define DebugPrintf(s, op) +#endif + +/** + * @brief A module is store as an objet plus a list of paths. + */ +#define PY_MAX_MODLEN 16 +typedef struct s_mod_t { + PyObject *mod; + int length; + YAP_Term names[PY_MAX_MODLEN]; +} Py_mod; + +extern X_API YAP_Term pythonToYAP(PyObject *pVal); +extern X_API PyObject *yap_to_python(YAP_Term t, bool eval, PyObject *o); + typedef YAP_Arity arity_t; extern atom_t ATOM_true, ATOM_false, ATOM_colon, ATOM_dot, ATOM_none, ATOM_t, @@ -32,14 +59,20 @@ extern functor_t FUNCTOR_dollar1, FUNCTOR_abs1, FUNCTOR_all1, FUNCTOR_any1, FUNCTOR_colon2, FUNCTOR_comma2, FUNCTOR_equal2, FUNCTOR_sqbrackets2, FUNCTOR_dot2; -extern PyObject *py_Main; -extern PyObject *py_Builtin; -extern PyObject *py_Yapex; +extern X_API PyObject *py_Main; +extern X_API PyObject *py_Builtin; +extern X_API PyObject *py_Yapex; +extern X_API PyObject *py_Local; +extern X_API PyObject *py_Global; +extern X_API PyObject *py_Context; extern PyObject *py_F2P; +extern PyObject *py_Sys; +extern PyObject *py_ModDict; extern bool python_in_python; -#define PythonReturn PyGILState_Release(gstate) && return +extern bool python_release_GIL(term_t state); +extern term_t python_acquire_GIL(void); static inline Py_ssize_t get_p_int(PyObject *o, Py_ssize_t def) { if (o == NULL) @@ -77,7 +110,7 @@ static inline int proper_ascii_string(const char *s) { static inline PyObject *atom_to_python_string(term_t t) { // Yap_DebugPlWrite(YAP_GetFromSlot(t)); fprintf(stderr, " here I // am\n"); - char *s; + char *s = NULL; if (!PL_get_atom_chars(t, &s)) return NULL; /* return __main__,s */ @@ -93,28 +126,68 @@ static inline PyObject *atom_to_python_string(term_t t) { } } +#define CHECK_CALL(rc, t, call) \ + PyErr_Clear();\ + rc = call; \ + if (rc == NULL || PyErr_Occurred()) {\ + YE(t,__LINE__,__FILE__,__FUNCTION__);\ + PyErr_Print(); PyErr_Clear();\ + } + +#define CHECKNULL(t,rc) (rc != NULL ? rc : YE(t,__LINE__,__FILE__,__FUNCTION__) ) +#define AOK(rc, err) { if (!rc) YEM( #rc ,__LINE__,__FILE__,__FUNCTION__); } + + +extern PyObject *YE(term_t t, int line, const char *file, const char *code); +extern void YEM( const char *ex, int line, const char *file, const char *code); +extern void pyErrorHandler__(int line, const char *file, const char *code); + +#define pyErrorHandler() \ + { \ + if (PyErr_Occurred()) { \ + pyErrorHandler__(__LINE__, __FILE__, __FUNCTION__); \ + } \ + } + +#define pyErrorAndReturn(x, y) \ + { \ + if (PyErr_Occurred()) { \ + pyErrorHandler__(__LINE__, __FILE__, __FUNCTION__); \ + return (x); \ + } else { \ + return (x); \ + } \ + } +// #define pyErrorAndReturn( x, y ) return x + +extern PyObject *compound_to_pyeval(term_t t, PyObject *context); +extern PyObject *compound_to_pytree(term_t t, PyObject *context); + +extern PyObject *term_to_python(term_t t, bool eval, PyObject *contextxs); + extern PyObject *term_to_nametuple(const char *s, int arity, term_t t); -extern PyObject *compound_to_pyeval(term_t t, functor_t fun); -extern PyObject *compound_to_pytree(term_t t, functor_t fun); +extern foreign_t python_to_term(PyObject *pVal, term_t t); +extern bool python_assign(term_t t, PyObject *exp, PyObject *context); +extern foreign_t assign_to_symbol(term_t t, PyObject *e); -extern PyObject *yap_to_python(YAP_Term t, bool eval); -extern PyObject *term_to_python(term_t t, bool eval); -extern foreign_t python_to_ptr(PyObject *pVal, term_t t); - -foreign_t python_to_term(PyObject *pVal, term_t t); -foreign_t assign_to_symbol(term_t t, PyObject *e); - -int assign_python(PyObject *root, term_t t, PyObject *e); +extern bool python_asign(term_t t, PyObject *exp, PyObject *context); extern foreign_t python_builtin(term_t out); -extern PyObject *ActiveModules[32]; -extern int active_modules; +extern int lookupPyModule(Py_mod *q); +extern PyObject *lookupPySymbol(const char *s, PyObject *q, PyObject **d); extern install_t install_pypreds(void); extern install_t install_pl2pl(void); -extern bool init_python(void); +X_API extern bool init_python(void); +extern bool do_init_python(void); extern PyObject PyInit_yap(void); + +extern PyObject *PythonLookup(const char *s, PyObject *o); + +extern PyObject *PythonLookupSpecial(const char *s); + +#endif diff --git a/packages/python/python.pl b/packages/python/python.pl index 42e266d09..80ba7e110 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 @@ -29,6 +29,8 @@ python/2, acquire_GIL/0, release_GIL/0, + python_threaded/0, + prolog_list_to_python_list/3, (:=)/2, (:=)/1, % (<-)/2, @@ -106,6 +108,7 @@ Data types are *************************************************************************************************************/ + :- use_module(library(shlib)). :- use_module(library(lists)). :- use_module(library(apply_macros)). @@ -116,277 +119,30 @@ Data types are := P1, := P2. := import( F ) :- !, python_import(F). -:= F :- python(F,_). +:= F :- python_proc(F). -V := F :- var(V), !, python(F,V0), - python_exports(V0,V). -A := F :- - python_eval_term(F, EF), - assign(A, EF, _). - -( V <- F ) :- - var(V), !, - V0 := F, - python_exports(V0,V). -( V <- F ) :- - ground(V), !, +V <- F :- V := F. -( V <- F ) :- - copy_term(V, V0), - V0 := F, - python_exports(V0,V). -python_exports(V0, V0) :- - var(V0), !. -python_exports(V0, V0) :- - atomic(V0), !. -python_exports('__obj__'(T0), T) :- - !, - python_export('__obj__'(T0), T). -python_exports(V0, VF) :- - V0 =.. [F|L], - maplist(python_exports, L, LF), - VF =.. [F|LF]. +( V := F ) :- + python_assign(F, V). ((<- F)) :- - python( F, _). + := F. python_import(Module) :- - python_do_import(Module, _). - -python_do_import(Module, MRef) :- - python_mref_cache(Module, MRef), !. -python_do_import(Module, MRef) :- - python_import(Module, MRef), - assert( python_mref_cache(Module, MRef) ). - -fetch_module(M:E, _M1, E, MRef) :- - atom(M), - python_import(M, MRef). - -% from an exp take an object, and its corresponding Prolog representation -descend_exp(V, _Obj) :- - var(V), !, - throw(error(instantiation_error,_)). -descend_exp(Mod.Exp, Obj) :- - atom(Mod), - python_import(Mod, MObj), - !, - 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(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), - python_apply(F, isclass(Obj), {}, true). - -process_obj(Obj, _, S, Obj, NS, Dict) :- - python_callable(Obj), !, - python_check_args(S, NS, Dict). -process_obj(Obj, _, S, FObj, NS, Dict) :- - 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), !, - 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). - %% 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). - %% 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_slice(Exp,Slice, NEl). -python_eval_term(Exp[Min:Max], NEl) :- !, - python_eval_term(slice(Min,Max), Slice), - python_slide(Exp,Min,Max, NEl). -python_eval_term(Exp[Index], O) :- !, - python_item(Exp,Index,O). -% 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((A,B), Obj) :- !, - flatten_conj((A,B),Cs,[]), - maplist( python_eval_term, Cs, NCs), - Tuple =.. [t|NCs], - python_is(Tuple, Obj). -% tuples and varyadic functions. -python_eval_term(Tuple, Obj) :- - Tuple =.. [Name|TupleL], - maplist( python_eval_term, TupleL, NewTupleL), - ( - Name == t - -> - !, - NewTuple =.. [t|NewTupleL], - python_is(NewTuple, Obj) - ; - Name == open -> - !, - % calls the file constructor - NewTuple =.. [open|NewTupleL], - python_builtin_eval( NewTuple, [], Obj ) - ). -python_eval_term(Exp, Obj) :- - python_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]. - -flatten_conj( V1 ) --> - { var( V1 ) }, - !, - [V1]. -flatten_conj( (V1,V2) ) --> - !, - flatten_conj( V1 ), % propagte the RHS first. - flatten_conj( V2 ). -flatten_conj( V1 ) --> - [V1]. - -python_check_args(_Exp(), t, {}) :- - !. -python_check_args(Exp, t, {}) :- - Exp =.. [_,V], var(V), !. -python_check_args(Exp, NExp, Dict) :- - Exp =.. [_F|LArgs], !, - match_args(LArgs, NLArgs, Dict), - NExp =.. [t|NLArgs]. -python_check_args(Exp, Exp, {}). - -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). - -match_args([], [], {}). -match_args([V=A|LArgs], [], Dict) :- !, - python_eval_term(A, EvA), - match_named_args([V=EvA|LArgs], Map), - map_to_dict(Map, Dict). -match_args([A|LArgs], [VA|NLArgs], Dict) :- - python_eval_term(A, VA), - match_args(LArgs, NLArgs, Dict). - -match_named_args([], []). -match_named_args([K=A|LArgs], [K=A|Map]) :- - match_named_args(LArgs, Map). + python_import(Module, _). -map_to_dict([X=V], {X:V}) :- !. -map_to_dict([X=V|Map], {X:V,NDict}) :- - map_to_dict(Map, {NDict}). - -match_from_anames([K|_ArgNames], K, VA, [_|Defaults], [VA|Defaults]) :- !. -match_from_anames([_|ArgNames], K, VA, [V|Defaults], [V|NDefaults]) :- - match_from_anames(ArgNames, K, VA, Defaults, NDefaults). - -fetch_args(FRef, Args, Kwd, Defaults) :- - FRef = '__obj__'(_), !, - %python_mref_cache('inspect', M), - python_obj_cache(inspect:getargspec(_), F), - python_apply(F, getargspec(FRef), {}, ExtraArgs), - ExtraArgs=t(Args, _, Kwd, Defaults). -fetch_args(_, []). - - -python(Obj, Out) :- - python_eval_term(Obj, Out). +python(Exp, Out) :- + Out := Exp. 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,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 :- - python_main_module(MRef), - assert(python_mref_cache('__main__', MRef)), - python_command('import sys'), - python_import('inspect'), - python_mref_cache(inspect, InspRef), - python_field(InspRef, isclass(_), IsClass), - assert(python_obj_cache(inspect:isclass(_), IsClass)), - python_field(InspRef, getargspec(_), GetArgSpec), - assert(python_obj_cache(inspect:getargspec(_), GetArgSpec)), + python_import('inspect', _), at_halt(end_python). add_cwd_to_python :- @@ -396,41 +152,6 @@ add_cwd_to_python :- python_command("sys.argv = [\"yap\"]"). % done -assign( V, E, O ) :- - var(V), - !, - E = V, - O = V. -assign( EName, E, EName ) :- - \+ atomic(EName), - python_assign_tuple(EName, E), - !. -assign(Name, Exp, Name) :- - python_assign(Name, Exp). - -% from an exp take an object, and its corresponding Prolog representation -python_assign_field(V, _Obj) :- - var(V), !, - throw(error(instantiation_error,_)). -python_assign_field(Mod.Exp, Obj) :- - atom(Mod), - python_import(Mod, MObj), - !, - python_assign_field(MObj.Exp, Obj). -python_assign_field(C1.C2.E, Obj) :- !, - python_eval_term(C1, O1), - python_field(O1, C2, Obj0 ), - python_assign_field(Obj0.E, Obj). -python_assign_field(Exp, Obj) :- - fail, - python_mref_cache(_, MObj), - python_field(MObj, Exp, Obj), !. -python_assign_field(C1.E, Obj) :- - atom(E), - !, - python_eval_term(C1, O1), - python_assign_field(O1, E, Obj ). - -%:- initialization( load_foreign_files([libYAPPython], [], init_python), now ). +:- initialization( load_foreign_files([libYAPPython], [], init_python), now ). :- initialization( load_foreign_library(foreign(libYAPPython), init_python), now ). diff --git a/packages/python/yap_kernel/CMakeLists.txt b/packages/python/yap_kernel/CMakeLists.txt index 0992bb910..0017f46fe 100644 --- a/packages/python/yap_kernel/CMakeLists.txt +++ b/packages/python/yap_kernel/CMakeLists.txt @@ -8,8 +8,10 @@ add_custom_target ( YAPKernel ALL DEPENDS yap_kernel.py ) + set( PYTHON_INSTALL install) -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} install -f + +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} ${PYTHON_INSTALL} -f WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") install(FILES jupyter.yap diff --git a/packages/python/yap_kernel/clause.py b/packages/python/yap_kernel/clause.py deleted file mode 100644 index 671f88c1a..000000000 --- a/packages/python/yap_kernel/clause.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Paired Density and Scatterplot Matrix -===================================== - -_thumb: .5, .5 -""" -import seaborn as sns -import matplotlib.pyplot as plt -sns.set(style="white") - -df = sns.load_dataset("iris") - -g = sns.PairGrid(df, diag_sharey=False) -g.map_lower(sns.kdeplot, cmap="Blues_d") -g.map_upper(plt.scatter) -g.map_diag(sns.kdeplot, lw=3) - -""" -Grouped barplots -================ - -_thumb: .45, .5 -""" -sns.set(style="whitegrid") - -# Draw a nested barplot to show survival for class and sex -g = sns.factorplot(x="class", y="survived", hue="sex", data=[15,30,5], - size=3, kind="bar", palette="muted") -g.despine(left=True) -g.set_ylabels("survival probability") diff --git a/packages/python/yap_kernel/interactiveshell.py b/packages/python/yap_kernel/interactiveshell.py index 157f24acc..2e37043d6 100644 --- a/packages/python/yap_kernel/interactiveshell.py +++ b/packages/python/yap_kernel/interactiveshell.py @@ -161,24 +161,21 @@ class YAPInteractiveShell: # print('{0}'.format(f.getvalue())) # Execute the user code if run: - # this new vs should contain bindings to vars - vs= self.q.namedVars() - #numbervars - i=0 - # iteraw - for eq in vs: - name = eq[0] - # this is tricky, we're going to bind the variables in the term so thay we can - # output X=Y. The Python way is to use dictionares. - #Instead, we use the T function to tranform the Python term back to Prolog - binding = yap.T(eq[1]) - if binding.isVar(): - binding.unify(name) - else: - i = binding.numberVars(i, True) - print(name + " = " + binding.text()) - #ok, that was Prolog code - print("yes") + myvs = self.q.namedVarsCopy() + if myvs: + i = 0 + for peq in myvs: + name = peq[0] + bind = peq[1] + if bind.isVar(): + var = yap.YAPAtom('$VAR') + f = yap.YAPFunctor(var, 1) + bind.unify(yap.YAPApplTerm(f, (name))) + else: + i = bind.numberVars(i, True) + print(name.text() + " = " + bind.text()) + else: + print("yes") if self.q.deterministic(): self.closeq() else: diff --git a/packages/python/yap_kernel/yap_kernel.py b/packages/python/yap_kernel/yap_kernel.py index 17c072b5d..4156545be 100644 --- a/packages/python/yap_kernel/yap_kernel.py +++ b/packages/python/yap_kernel/yap_kernel.py @@ -138,9 +138,9 @@ class YAPKernel(KernelBase): implementation = 'YAP' implementation_version = release.version language_info = { - 'name': 'prolog', + 'name': 'python', 'version': sys.version.split()[0], - 'mimetype': 'text/x-prolog', + 'mimetype': 'text/x-python', 'codemirror_mode': { 'name': 'prolog', 'version': sys.version_info[0] @@ -333,7 +333,7 @@ class YAPKernel(KernelBase): elif hist_access_type == 'range': hist = self.shell.history_manager.get_range(session, start, stop, - raw=raw, output=output) + raw=raw, output=output) elif hist_access_type == 'search': hist = self.shell.history_manager.search( diff --git a/packages/python/yapex.py b/packages/python/yapex.py index e17047753..5329de897 100644 --- a/packages/python/yapex.py +++ b/packages/python/yapex.py @@ -1,7 +1,8 @@ import yap import sys -import collections +# debugging support. +import pdb def query_prolog(engine, s): @@ -12,13 +13,14 @@ def query_prolog(engine, s): print(e.args[1]) return False + # #construct a query from a one-line string # q is opaque to Python q = engine.query(s) # vs is the list of variables # you can print it out, the left-side is the variable name, # the right side wraps a handle to a variable - vs= q.namedVars() + vs = q.namedVars() # atom match either symbols, or if no symbol exists, sttrings, In this case # variable names should match strings for eq in vs: @@ -56,7 +58,10 @@ def query_prolog(engine, s): if s.startswith(';') or s.startswith('y'): continue elif s.startswith('#'): - exec(s.lstrip('#')) + try: + exec(s.lstrip('#')) + except: + raise elif s.startswith('*') or s.startswith('a'): ask = False continue @@ -70,6 +75,7 @@ def query_prolog(engine, s): def live(): engine = yap.YAPEngine() loop = True + pdb.set_trace() while loop: try: s = input("?- ") @@ -92,4 +98,4 @@ def live(): # initialize engine # engine = yap.YAPEngine(); # engine = yap.YAPEngine(yap.YAPParams()); -live() +#live() diff --git a/packages/python/examples/untitled b/x/packages/myddas/pl/myddas_mysql.yap similarity index 100% rename from packages/python/examples/untitled rename to x/packages/myddas/pl/myddas_mysql.yap