From 1ff06fd2e019ef085c95074d1358366cf2144474 Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Mon, 19 Mar 2018 15:41:53 +0000 Subject: [PATCH 1/8] integrate backcall --- CMakeLists.txt | 1 - info/meta.yaml | 1 - packages/python/yap_kernel/setup.py | 2 +- .../yap_kernel/yap_ipython/core/backcall.py | 109 ++++++++++++++++++ .../yap_ipython/core/tests/test_events.py | 2 +- 5 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 packages/python/yap_kernel/yap_ipython/core/backcall.py diff --git a/CMakeLists.txt b/CMakeLists.txt index d3f950bf7..27d15849c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -688,7 +688,6 @@ if (PYTHONLIBS_FOUND AND SWIG_FOUND) find_python_module(jupyter) find_python_module(wheel) find_python_module(setuptools) - find_python_module(backcall) if (PY_JUPYTER AND PY_WHEEL AND PY_SETUPTOOLS AND PY_BACKCALL) add_subdirectory(packages/python/yap_kernel) ENDIF () diff --git a/info/meta.yaml b/info/meta.yaml index 24b367100..cd9f197cd 100644 --- a/info/meta.yaml +++ b/info/meta.yaml @@ -19,7 +19,6 @@ requirements: - libxml2 - backcall run: - - backcall - jupyterlab - python - readline diff --git a/packages/python/yap_kernel/setup.py b/packages/python/yap_kernel/setup.py index 9e0b36d09..dd108a73e 100644 --- a/packages/python/yap_kernel/setup.py +++ b/packages/python/yap_kernel/setup.py @@ -67,7 +67,7 @@ setup_args = dict( version = version_ns['__version__'], scripts = glob(pjoin('scripts', '*')), packages = packages, - py_modules = ['yap_kernel_launcher'], + py_modules = ['yap_kernel_launcher','backcall'], package_data = package_data, #package_dir = {'':here}, description = "YAP Kernel for Jupyter", diff --git a/packages/python/yap_kernel/yap_ipython/core/backcall.py b/packages/python/yap_kernel/yap_ipython/core/backcall.py new file mode 100644 index 000000000..fe1fdb547 --- /dev/null +++ b/packages/python/yap_kernel/yap_ipython/core/backcall.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Jan 13 18:17:15 2014 + +@author: takluyver +""" +import sys +PY3 = (sys.version_info[0] >= 3) + +try: + from inspect import signature, Parameter # Python >= 3.3 +except ImportError: + from ._signatures import signature, Parameter + +if PY3: + from functools import wraps +else: + from functools import wraps as _wraps + def wraps(f): + def dec(func): + _wraps(f)(func) + func.__wrapped__ = f + return func + + return dec + +def callback_prototype(prototype): + """Decorator to process a callback prototype. + + A callback prototype is a function whose signature includes all the values + that will be passed by the callback API in question. + + The original function will be returned, with a ``prototype.adapt`` attribute + which can be used to prepare third party callbacks. + """ + protosig = signature(prototype) + positional, keyword = [], [] + for name, param in protosig.parameters.items(): + if param.kind in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD): + raise TypeError("*args/**kwargs not supported in prototypes") + + if (param.default is not Parameter.empty) \ + or (param.kind == Parameter.KEYWORD_ONLY): + keyword.append(name) + else: + positional.append(name) + + kwargs = dict.fromkeys(keyword) + def adapt(callback): + """Introspect and prepare a third party callback.""" + sig = signature(callback) + try: + # XXX: callback can have extra optional parameters - OK? + sig.bind(*positional, **kwargs) + return callback + except TypeError: + pass + + # Match up arguments + unmatched_pos = positional[:] + unmatched_kw = kwargs.copy() + unrecognised = [] + # TODO: unrecognised parameters with default values - OK? + for name, param in sig.parameters.items(): + # print(name, param.kind) #DBG + if param.kind == Parameter.POSITIONAL_ONLY: + if len(unmatched_pos) > 0: + unmatched_pos.pop(0) + else: + unrecognised.append(name) + elif param.kind == Parameter.POSITIONAL_OR_KEYWORD: + if (param.default is not Parameter.empty) and (name in unmatched_kw): + unmatched_kw.pop(name) + elif len(unmatched_pos) > 0: + unmatched_pos.pop(0) + else: + unrecognised.append(name) + elif param.kind == Parameter.VAR_POSITIONAL: + unmatched_pos = [] + elif param.kind == Parameter.KEYWORD_ONLY: + if name in unmatched_kw: + unmatched_kw.pop(name) + else: + unrecognised.append(name) + else: # VAR_KEYWORD + unmatched_kw = {} + + # print(unmatched_pos, unmatched_kw, unrecognised) #DBG + + if unrecognised: + raise TypeError("Function {!r} had unmatched arguments: {}".format(callback, unrecognised)) + + n_positional = len(positional) - len(unmatched_pos) + + @wraps(callback) + def adapted(*args, **kwargs): + """Wrapper for third party callbacks that discards excess arguments""" +# print(args, kwargs) + args = args[:n_positional] + for name in unmatched_kw: + # XXX: Could name not be in kwargs? + kwargs.pop(name) +# print(args, kwargs, unmatched_pos, cut_positional, unmatched_kw) + return callback(*args, **kwargs) + + return adapted + + prototype.adapt = adapt + return prototype \ No newline at end of file diff --git a/packages/python/yap_kernel/yap_ipython/core/tests/test_events.py b/packages/python/yap_kernel/yap_ipython/core/tests/test_events.py index d95024cf9..fa2ec60e0 100644 --- a/packages/python/yap_kernel/yap_ipython/core/tests/test_events.py +++ b/packages/python/yap_kernel/yap_ipython/core/tests/test_events.py @@ -1,4 +1,4 @@ -from backcall import callback_prototype +from yap_ipython.core.backcall import callback_prototype import unittest from unittest.mock import Mock import nose.tools as nt From da68741b745c3de0d2f418abc135bd34b3dda1e4 Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Mon, 19 Mar 2018 15:43:06 +0000 Subject: [PATCH 2/8] integrate backcall --- packages/python/yap_kernel/yap_ipython/core/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/python/yap_kernel/yap_ipython/core/events.py b/packages/python/yap_kernel/yap_ipython/core/events.py index 3431a5398..64d05e919 100644 --- a/packages/python/yap_kernel/yap_ipython/core/events.py +++ b/packages/python/yap_kernel/yap_ipython/core/events.py @@ -13,7 +13,7 @@ events and the arguments which will be passed to them. This API is experimental in yap_ipython 2.0, and may be revised in future versions. """ -from backcall import callback_prototype +from yap_ipython.core.backcall import callback_prototype class EventManager(object): From 56e676ef65e57a63b220c8597449f27b771748b7 Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Fri, 23 Mar 2018 18:48:16 +0000 Subject: [PATCH 3/8] undef --- C/absmi.c | 71 ++++++++++++++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/C/absmi.c b/C/absmi.c index 1c33eabdc..4a4158363 100755 --- a/C/absmi.c +++ b/C/absmi.c @@ -916,9 +916,7 @@ static int interrupt_dexecute(USES_REGS1) { static void undef_goal(USES_REGS1) { PredEntry *pe = PredFromDefCode(P); - CELL *b; - CELL *b0; - + BEGD(d0); /* avoid trouble with undefined dynamic procedures */ /* I assume they were not locked beforehand */ @@ -928,6 +926,15 @@ static void undef_goal(USES_REGS1) { PP = pe; } #endif + if (pe->PredFlags & (DynamicPredFlag | LogUpdatePredFlag | MultiFileFlag) ) { +#if defined(YAPOR) || defined(THREADS) + UNLOCKPE(19, PP); + PP = NULL; +#endif + CalculateStackGap(PASS_REGS1); + P = FAILCODE; + return; + } if (UndefCode == NULL || UndefCode->OpcodeOfPred == UNDEF_OPCODE) { fprintf(stderr,"call to undefined Predicates %s ->", IndicatorOfPred(pe)); Yap_DebugPlWriteln(ARG1); @@ -937,15 +944,6 @@ static void undef_goal(USES_REGS1) { #if defined(YAPOR) || defined(THREADS) UNLOCKPE(19, PP); PP = NULL; -#endif - CalculateStackGap(PASS_REGS1); - P = FAILCODE; - return; - } - if (pe->PredFlags & (DynamicPredFlag | LogUpdatePredFlag | MultiFileFlag) ) { -#if defined(YAPOR) || defined(THREADS) - UNLOCKPE(19, PP); - PP = NULL; #endif CalculateStackGap(PASS_REGS1); P = FAILCODE; @@ -955,27 +953,16 @@ static void undef_goal(USES_REGS1) { UNLOCKPE(19, PP); PP = NULL; #endif - d0 = pe->ArityOfPE; - if (pe->ModuleOfPred == PROLOG_MODULE) { - if (CurrentModule == PROLOG_MODULE) - HR[0] = MkAtomTerm(Yap_LookupAtom("prolog")); - else - HR[0] = CurrentModule; + if (pe->ArityOfPE == 0) { + d0 = MkAtomTerm((Atom)(pe->FunctorOfPred)); } else { - HR[0] = Yap_Module_Name(pe); - } - b = b0 = HR; - HR += 2; - if (d0 == 0) { - b[1] = MkAtomTerm((Atom)(pe->FunctorOfPred)); - } else { - b[1] = AbsAppl(b+2); + d0 = AbsAppl(HR); *HR++ = (CELL)pe->FunctorOfPred; - b += 3; - HR += d0; + CELL *ip=HR, *imax = HR+pe->ArityOfPE; + HR = imax; BEGP(pt1); pt1 = XREGS + 1; - for (; d0 > 0; --d0) { + for (; ip < imax; ip++) { BEGD(d1); BEGP(pt0); pt0 = pt1++; @@ -983,18 +970,17 @@ static void undef_goal(USES_REGS1) { deref_head(d1, undef_unk); undef_nonvar: /* just copy it to the heap */ - *b++ = d1; + *ip = d1; continue; derefa_body(d1, pt0, undef_unk, undef_nonvar); if (pt0 <= HR) { /* variable is safe */ - *b++ = (CELL)pt0; + *ip = (CELL)pt0; } else { /* bind it, in case it is a local variable */ - d1 = Unsigned(HR); - RESET_VARIABLE(HR); - HR += 1; + d1 = Unsigned(ip); + RESET_VARIABLE(ip); Bind_Local(pt0, d1); } ENDP(pt0); @@ -1002,9 +988,20 @@ static void undef_goal(USES_REGS1) { } ENDP(pt1); } - ENDD(d0); - ARG1 = AbsPair(b0); - ARG2 = Yap_getUnknownModule(Yap_GetModuleEntry(b0[0])); + ARG1 = AbsPair(HR); + HR[1] = d0; +ENDD(d0); + if (pe->ModuleOfPred == PROLOG_MODULE) { + if (CurrentModule == PROLOG_MODULE) + HR[0] = TermProlog; + else + HR[0] = CurrentModule; + } else { + HR[0] = Yap_Module_Name(pe); + } + ARG2 = Yap_getUnknownModule(Yap_GetModuleEntry(HR[0])); + HR += 2; + #ifdef LOW_LEVEL_TRACER if (Yap_do_low_level_trace) low_level_trace(enter_pred, UndefCode, XREGS + 1); From 13cdd5124aaa0504174ee542bdf0e923dea1ad1d Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Fri, 23 Mar 2018 18:48:48 +0000 Subject: [PATCH 4/8] typo --- pl/qly.yap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pl/qly.yap b/pl/qly.yap index 679760178..31b669095 100755 --- a/pl/qly.yap +++ b/pl/qly.yap @@ -240,7 +240,7 @@ qend_program :- X \= argv, X \= os_argv, X \= language, - X \= encoding. + X \= encoding, fail. qsave_file(F0) :- From 7e0611b5265f61dccf1dceea3333f32e13d56e72 Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Fri, 23 Mar 2018 19:17:20 +0000 Subject: [PATCH 5/8] fix typo (by Paulo Moura) --- packages/jpl/jpl.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jpl/jpl.pl b/packages/jpl/jpl.pl index 89c9488b4..1ccfaa932 100644 --- a/packages/jpl/jpl.pl +++ b/packages/jpl/jpl.pl @@ -4506,7 +4506,7 @@ location(java_root, _, JRE) :- member(Root, [ '/usr/lib', '/usr/local/lib', '/opt/lib', - '/Library/Java/JavaVirtual hines', + '/Library/Java/JavaVirtualMachines', '/System/Library/Frameworks' ]), exists_directory(Root), From 4dfad0a7fec4b78c7b07cbaf4df3fe0936b178d0 Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Sat, 24 Mar 2018 22:55:32 +0000 Subject: [PATCH 6/8] ninja --- configure | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 284cb35a4..5962f82d6 100755 --- a/configure +++ b/configure @@ -291,12 +291,10 @@ while [ $# != 0 ]; do "--docdir") CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_INSTALL_DOCDIR=$(quote "$2")"; shift;; - "-G=|--generator="*) - GENERATOR="$CMAKE_ARGS -G $(1#*=)";; - + "-G="|"--generator="*) + CMAKE_ARGS+="-G"${1#*=};; "-G"|"--generator") - GENERATOR="$CMAKE_ARGS -G$(quote "$2")"; - shift;; + CMAKE_ARGS+="-G$"$2; shift;; "CC="*) CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_C_COMPILER=$(quote "${1#*=}")";; From 0b67a66533dbc1a8d6b84ec217afdfe9c515a05c Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Sat, 24 Mar 2018 22:56:21 +0000 Subject: [PATCH 7/8] fix dlls --- packages/bdd/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/bdd/CMakeLists.txt b/packages/bdd/CMakeLists.txt index 88b7de0b5..d748929ef 100644 --- a/packages/bdd/CMakeLists.txt +++ b/packages/bdd/CMakeLists.txt @@ -1,4 +1,3 @@ -CMAKE_MINIMUM_REQUIRED ( VERSION 2.8 ) PROJECT ( YAP_BDD C ) From e02884a94f37871fd2d44cfedd3e9ef9f28f0464 Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Sat, 24 Mar 2018 22:56:52 +0000 Subject: [PATCH 8/8] error handling --- CXX/yapi.cpp | 15 +++---- packages/python/swig/yap4py/yapi.py | 65 +++++++++++++++-------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/CXX/yapi.cpp b/CXX/yapi.cpp index 85b6e6fb3..0802b719d 100644 --- a/CXX/yapi.cpp +++ b/CXX/yapi.cpp @@ -437,6 +437,7 @@ bool YAPEngine::call(YAPPredicate ap, YAPTerm ts[]) { LOCAL_RestartEnv = &buf; if (sigsetjmp(*LOCAL_RestartEnv, false)) { std::cerr << "Restart\n"; + throw *new YAPError(); //q.e = new YAPError(); } // don't forget, on success these bindings will still be there); @@ -490,7 +491,7 @@ bool YAPEngine::mgoal(Term t, Term tmod) { if (sigsetjmp(*LOCAL_RestartEnv, false)) { // PyEval_RestoreThread(_save); std::cerr << "Restart\n"; - //throw new YAPError(); + throw *new YAPError(); } // don't forget, on success these guys may create slots __android_log_print(ANDROID_LOG_INFO, "YAPDroid", "exec "); @@ -567,10 +568,7 @@ Term YAPEngine::fun(Term t) { sigjmp_buf buf, *oldp = LOCAL_RestartEnv; LOCAL_RestartEnv = &buf; if (sigsetjmp(*LOCAL_RestartEnv, false)) { - // throw new YAPError(); - LOCAL_RestartEnv = oldp; - RECOVER_MACHINE_REGS(); - return 0; + throw *new YAPError(); } // don't forget, on success these guys may create slots __android_log_print(ANDROID_LOG_INFO, "YAPDroid", "exec "); @@ -693,7 +691,7 @@ bool YAPQuery::next() { return false; LOCAL_RestartEnv = &buf; if (sigsetjmp(*LOCAL_RestartEnv, false)) { - //e = new YAPError(); + throw *new YAPError(); } // don't forget, on success these guys may create slots __android_log_print(ANDROID_LOG_INFO, "YAPDroid", "exec "); @@ -712,10 +710,9 @@ bool YAPQuery::next() { } q_state = 1; if ((terr = Yap_PeekException())) { - LOCAL_RestartEnv = &buf; + throw * new YAPError(); - result = false; - } + } __android_log_print(ANDROID_LOG_INFO, "YAPDroid", "out %d", result); if (!result) { diff --git a/packages/python/swig/yap4py/yapi.py b/packages/python/swig/yap4py/yapi.py index a26d3b007..56ba37a59 100644 --- a/packages/python/swig/yap4py/yapi.py +++ b/packages/python/swig/yap4py/yapi.py @@ -144,38 +144,41 @@ class YAPShell: # if not isinstance(eq[0],str): # print( "Error: Variable Name matches a Python Symbol") # return - self.do_ask = True - engine = self.engine - bindings = [] - g = python_query(self, query) - if not self.q: - self.q = Query( engine, g ) - for bind in self.q: - bindings += [bind] - if self.do_ask: - print(bindings) - bindings = [] + try: + engine = self.engine + bindings = [] + loop = False + g = python_query(self, query) + if not self.q: + self.q = Query( engine, g ) + for bind in self.q: + bindings += [bind] + if loop: + continue + if not self.q: + break s = input("more(;), all(*), no(\\n), python(#) ?").lstrip() - else: - s = ";" - if s.startswith(';') or s.startswith('y'): - continue - elif s.startswith('#'): - try: - exec(s.lstrip('#')) - except: - raise - elif s.startswith('*') or s.startswith('a'): - self.do_ask = False - continue - else: - break - if self.q: - self.os = query - if bindings: - return True,bindings - print("No (more) answers") - return False, None + if s.startswith(';') or s.startswith('y'): + continue + elif s.startswith('#'): + try: + exec(s.lstrip('#')) + except: + raise + elif s.startswith('*') or s.startswith('a'): + loop = True + continue + else: + break + if self.q: + self.os = query + if bindings: + return True,bindings + print("No (more) answers") + return False, None + except e: + print("Exception") + print(e) def live(self, engine, **kwargs):