From f1ddb5822eb8b36b5c089f1a97214a043869e4d9 Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Tue, 6 Jun 2017 12:47:59 +0100 Subject: [PATCH] fix predicate search --- C/adtdefs.c | 4 +- C/cdmgr.c | 41 +++++------- C/exec.c | 2 +- CXX/yapi.cpp | 7 +- H/Yatom.h | 9 ++- packages/python/swig/yapi.py | 18 +++-- packages/python/swig/yapi.yap | 120 +++++++++++++--------------------- packages/swig/yap.i | 1 + pl/directives.yap | 1 + pl/errors.yap | 2 +- pl/messages.yap | 5 +- pl/undefined.yap | 6 +- 12 files changed, 95 insertions(+), 121 deletions(-) diff --git a/C/adtdefs.c b/C/adtdefs.c index 605b3dc13..8dbbfd6a5 100755 --- a/C/adtdefs.c +++ b/C/adtdefs.c @@ -834,7 +834,7 @@ Prop Yap_PredPropByFunctorNonThreadLocal(Functor f, Term cur_mod) if ((p->ModuleOfPred == cur_mod || !(p->ModuleOfPred))) { /* don't match multi-files */ - if (!(p->PredFlags & MultiFileFlag) || p->ModuleOfPred || !cur_mod || + if (/*!(p->PredFlags & MultiFileFlag) ||*/ true || p->ModuleOfPred || !cur_mod || cur_mod == TermProlog) { FUNC_WRITE_UNLOCK(f); return AbsPredProp(p); @@ -871,7 +871,7 @@ Prop Yap_PredPropByAtomNonThreadLocal(Atom at, Term cur_mod) if (pe->KindOfPE == PEProp && (pe->ModuleOfPred == cur_mod || !pe->ModuleOfPred)) { /* don't match multi-files */ - if (!(pe->PredFlags & MultiFileFlag) || pe->ModuleOfPred || !cur_mod || + if (/*!(pe->PredFlags & MultiFileFlag) ||*/ true || pe->ModuleOfPred || !cur_mod || cur_mod == TermProlog) { WRITE_UNLOCK(ae->ARWLock); return (p0); diff --git a/C/cdmgr.c b/C/cdmgr.c index 2497b8cc6..72ca6d06a 100644 --- a/C/cdmgr.c +++ b/C/cdmgr.c @@ -1019,7 +1019,7 @@ static void retract_all(PredEntry *p, int in_use) { } p->cs.p_code.FirstClause = NULL; p->cs.p_code.LastClause = NULL; - if (p->PredFlags & (DynamicPredFlag | LogUpdatePredFlag | MultiFileFlag)) { + if (is_live(p)) { p->OpcodeOfPred = FAIL_OPCODE; } else { p->OpcodeOfPred = UNDEF_OPCODE; @@ -1742,8 +1742,9 @@ bool Yap_addclause(Term t, yamop *cp, Term tmode, Term mod, Term *t4ref) if (pflags & IndexedPredFlag) { Yap_AddClauseToIndex(p, cp, mode == asserta); } - if (pflags & (SpiedPredFlag | CountPredFlag | ProfiledPredFlag)) + if (pflags & (SpiedPredFlag | CountPredFlag | ProfiledPredFlag)) { spy_flag = true; + } if (Yap_discontiguous(p, tmode PASS_REGS)) { Term disc[3], sc[4]; if (p->ArityOfPE) { @@ -1914,12 +1915,12 @@ void Yap_EraseStaticClause(StaticClause *cl, PredEntry *ap, Term mod) { if (ap->cs.p_code.LastClause == cl->ClCode) { /* got rid of all clauses */ ap->cs.p_code.LastClause = ap->cs.p_code.FirstClause = NULL; - if (!(ap->PredFlags & MultiFileFlag)) { + if (is_live(ap)) { ap->OpcodeOfPred = FAIL_OPCODE; - } else { - ap->OpcodeOfPred = UNDEF_OPCODE; - ap->PredFlags |= UndefPredFlag; - } + } else { + ap->OpcodeOfPred = UNDEF_OPCODE; + ap->PredFlags |= UndefPredFlag; + } ap->cs.p_code.TrueCodeOfPred = (yamop *)(&(ap->OpcodeOfPred)); } else { @@ -2434,23 +2435,21 @@ static Int p_new_multifile(USES_REGS1) { /* '$new_multifile'(+N,+Ar,+Mod) */ else pe = RepPredProp(PredPropByFunc(Yap_MkFunctor(at, arity), mod)); PELOCK(26, pe); - if (pe->PredFlags & - (UserCPredFlag | CArgsPredFlag | NumberDBPredFlag | AtomDBPredFlag | - TestPredFlag | AsmPredFlag | CPredFlag | BinaryPredFlag)) { - UNLOCKPE(26, pe); - addcl_permission_error(RepAtom(at), arity, FALSE); - return false; -} -pe->PredFlags &= ~UndefPredFlag; if (pe->PredFlags & MultiFileFlag) { UNLOCKPE(26, pe); return true; } + if (pe->PredFlags & (TabledPredFlag|ForeignPredFlags)) { + UNLOCKPE(26, pe); + addcl_permission_error(RepAtom(at), arity, FALSE); + return false; + } if (pe->cs.p_code.NOfClauses) { UNLOCKPE(26, pe); addcl_permission_error(RepAtom(at), arity, FALSE); return false; } + pe->PredFlags &= ~UndefPredFlag; pe->PredFlags |= MultiFileFlag; /* mutifile-predicates are weird, they do not seat really on the default * module */ @@ -2727,7 +2726,7 @@ static Int p_pred_exists(USES_REGS1) { /* '$pred_exists'(+P,+M) */ UNLOCKPE(54, pe); return false; } - out = (pe->OpcodeOfPred != UNDEF_OPCODE); + out = (is_live(pe) || pe->OpcodeOfPred != UNDEF_OPCODE); UNLOCKPE(55, pe); return out; } @@ -2786,8 +2785,7 @@ static Int undefp_handler(USES_REGS1) { /* '$undefp_handler'(P,Mod) */ if (EndOfPAEntr(pe)) return false; PELOCK(59, pe); - if (pe->OpcodeOfPred == UNDEF_OPCODE && - !(pe->PredFlags & (LogUpdatePredFlag|DynamicPredFlag|MultiFileFlag))) { + if (pe->OpcodeOfPred == UNDEF_OPCODE) { UNLOCKPE(59, pe); return false; } @@ -2803,12 +2801,7 @@ static Int p_undefined(USES_REGS1) { /* '$undefined'(P,Mod) */ if (EndOfPAEntr(pe)) return TRUE; PELOCK(36, pe); - if (pe->PredFlags & (CPredFlag | UserCPredFlag | TestPredFlag | AsmPredFlag |MultiFileFlag| - DynamicPredFlag | LogUpdatePredFlag | TabledPredFlag)) { - UNLOCKPE(57, pe); - return FALSE; - } - if (pe->OpcodeOfPred == UNDEF_OPCODE) { + if (!is_live(pe) && pe->OpcodeOfPred == UNDEF_OPCODE) { UNLOCKPE(58, pe); return TRUE; } diff --git a/C/exec.c b/C/exec.c index 9058b6bfc..9447a4399 100755 --- a/C/exec.c +++ b/C/exec.c @@ -2108,7 +2108,7 @@ static Int jump_env(USES_REGS1) { Yap_find_prolog_culprit(PASS_REGS1); // LOCAL_Error_TYPE = ERROR_EVENT; Term t1 = ArgOfTerm(1, t); - if (IsApplTerm(t) && IsAtomTerm((t2 = ArgOfTerm(1, t1)))) { + if (IsApplTerm(t1) && IsAtomTerm((t2 = ArgOfTerm(1, t1)))) { LOCAL_ActiveError->errorAsText = AtomOfTerm(t2); LOCAL_ActiveError->classAsText = NameOfFunctor(FunctorOfTerm(t1)); } else if (IsAtomTerm(t)) { diff --git a/CXX/yapi.cpp b/CXX/yapi.cpp index 690fd9965..eafe17660 100644 --- a/CXX/yapi.cpp +++ b/CXX/yapi.cpp @@ -487,10 +487,9 @@ bool YAPEngine::mgoal(Term t, Term tmod) if (ap == nullptr || ap->OpcodeOfPred == UNDEF_OPCODE) { ap = rewriteUndefEngineQuery(ap, t, tmod); - } - if (ap==nullptr) - - return false; + if (ap == nullptr || ap->OpcodeOfPred == UNDEF_OPCODE) + return false; + } else { /* legal ap */ arity_t arity = ap->ArityOfPE; diff --git a/H/Yatom.h b/H/Yatom.h index 15e2b02a1..916c774e4 100755 --- a/H/Yatom.h +++ b/H/Yatom.h @@ -487,7 +487,9 @@ typedef uint64_t pred_flags_t; #define ForeignPredFlags \ (AsmPredFlag | SWIEnvPredFlag | CPredFlag | BinaryPredFlag | UDIPredFlag | \ CArgsPredFlag | UserCPredFlag | SafePredFlag | BackCPredFlag) - +#define LivePredFlags \ + (LogUpdatePredFlag|MultiFileFlag|TabledPredFlag|ForeignPredFlags) + #define StatePredFlags \ (InUsePredFlag | CountPredFlag | SpiedPredFlag | IndexedPredFlag) #define is_system(pe) (pe->PredFlags & SystemPredFlags) @@ -495,6 +497,7 @@ typedef uint64_t pred_flags_t; #define is_foreign(pe) (pe->PredFlags & ForeignPredFlags) #define is_static(pe) (pe->PredFlags & CompiledPredFlag) #define is_logupd(pe) (pe->PredFlags & LogUpdatePredFlag) +#define is_live(pe) (pe->PredFlags & LivePredFlags) #ifdef TABLING #define is_tabled(pe) (pe->PredFlags & TabledPredFlag) #endif /* TABLING */ @@ -1414,7 +1417,7 @@ GetPredPropByFuncAndModHavingLock(FunctorEntry *fe, Term cur_mod) { if (!(p = RepPredProp(fe->PropsOfFE))) { return NIL; } - if (p->ModuleOfPred == cur_mod) { + if (p->ModuleOfPred == cur_mod || p->ModuleOfPred == 0) { #ifdef THREADS /* Thread Local Predicates */ if (p->PredFlags & ThreadLocalPredFlag) { @@ -1498,7 +1501,7 @@ INLINE_ONLY EXTERN inline Prop PredPropByAtomAndMod(Atom at, Term cur_mod) p0 = ae->PropsOfAE; while (p0) { PredEntry *pe = RepPredProp(p0); - if (pe->KindOfPE == PEProp && (pe->ModuleOfPred == cur_mod)) { + if (pe->KindOfPE == PEProp && (pe->ModuleOfPred == cur_mod || pe->ModuleOfPred == 0)) { #ifdef THREADS /* Thread Local Predicates */ if (pe->PredFlags & ThreadLocalPredFlag) { diff --git a/packages/python/swig/yapi.py b/packages/python/swig/yapi.py index 156da458a..fe8089e99 100644 --- a/packages/python/swig/yapi.py +++ b/packages/python/swig/yapi.py @@ -18,12 +18,15 @@ yap_query = namedtuple( 'yap_query', 'query owner') jupyter_query = namedtuple( 'jupyter_query', 'vars dict') python_query = namedtuple( 'python_query', 'vars dict') yapi_query = namedtuple( 'yapi_query', 'vars dict') +show_answer = namedtuple( 'show_answer', 'vars dict') +def v(): + return yap.YAPVarTerm() def numbervars( q ): Dict = {} if True: - engine.goal(yapi_query( q.namedVars(), Dict)) + engine.goal(show_answer( q.namedVars(), Dict)) return Dict rc = q.namedVarsVector() q.r = q.goal().numbervars() @@ -42,7 +45,10 @@ def numbervars( q ): def answer(q): try: - return q.next() + v = q.next() + if v: + print( bindings ) + return v except Exception as e: print(e.args[1]) return False @@ -52,7 +58,8 @@ def query_prolog(engine, s): # # construct a query from a one-line string # q is opaque to Python - q = engine.query(s) + bindings = {} + q = engine.query(python_query(s, bindings)) # 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 @@ -64,10 +71,9 @@ def query_prolog(engine, s): # if not isinstance(eq[0],str): # print( "Error: Variable Name matches a Python Symbol") # return - # ask = True + ask = True # launch the query while answer(q): - print( handler( q )) # deterministic = one solution if q.deterministic(): # done @@ -98,7 +104,7 @@ def boot_yap(**kwargs): args.setYapLibDir(yap_lib_path) args.setSavedState(os.path.join(yap_lib_path,"startup.yss")) engine = yap.YAPEngine(args) - engine.goal( use_module(library('python') ) ) + engine.goal( use_module(library('yapi') ) ) return engine def live(**kwargs): diff --git a/packages/python/swig/yapi.yap b/packages/python/swig/yapi.yap index 82278eea4..a1d964362 100644 --- a/packages/python/swig/yapi.yap +++ b/packages/python/swig/yapi.yap @@ -12,24 +12,27 @@ :- use_module( library(maplist) ). :- use_module( library(rbtrees) ). :- use_module( library(terms) ). +:- use_module( library(python) ). - %% @pred yap_query(sGoal, + VarList, +OutStream, - Dictionary) +%% @pred yap_query(sGoal, + VarList, +OutStream, - Dictionary) %% @pred yap_query(0:Goal, + VarList, - Dictionary) %% %% dictionary, Examples %% %% -python_query( Engine, String, Dict ) :- +python_query( String, D ) :- atomic_to_term( String, Goal, VarNames ), - yap_query( Goal, VarNames, user_error, Dict). + yap_query( Goal, VarNames, user_error, Dict), + D := Dict, + yap4py.yapi.bindings := Dict. %% @pred yapi_query( + VarList, - Dictionary) %% %% dictionary, Examples %% %% - prologun:yapi_query( VarNames, Dict ) :- + yapi_query( VarNames, Dict ) :- show_answer(VarNames, Dict). @@ -42,34 +45,48 @@ python_query( Engine, String, Dict ) :- %% yap_query( Goal, VarNames, Stream, Dictionary) :- ( - call(Goal) + call(Goal) *-> - !, - show_answer(VarNames, Stream, Dictionary) - ). + !, + show_answer(VarNames, Stream, Dictionary) + ). -yapi_query( VarNames, Dictionary) :- +yap_query( VarNames, Dictionary) :- yap_query( VarNames, user_output, Dictionary). show_answer(QVs0, Dict) :- - show_answer(QVs0, user_error, Dict). + show_answer(QVs0, user_error, Dict). -show_answer(QVs0, Stream, {Dict}) :- +show_answer(QVs0, Stream, Dict) :- copy_term(QVs0, QVs), - writeln(ivs-IVs), - term_variables(Goal, IVs), - foldl(enumerate, IVs, 0, _Ns), + copy_term(QVs0, QVs1), + rb_new(RB), + foldl2(bind_qv, QVs, QVs1, [], LP, {}-RB, Dict-_), !, - out(QVs, Stream, D). - Dictt := {D}. + term_variables(QVs, IVs), + term_variables(QVs1, IVs1), + foldl( enumerate, IVs, IVs1, 1, _ ), + out(LP, Stream ). show_answer(_, _, {}) :- - format(' yes.~n', [] ). + format(' yes.~n', [] ). -bind_qv(V=V0, Vs, Vs) :- var(V0), !, V0='$VAR'(V). -bind_qv(V=V, Vs, Vs) :- !. -bind_qv(V=S, Vs, [V=S|Vs]). +bind_qv(V=V0, V1 = V01, Vs, Vs, Vs1-RB, Vs1-RB) :- + var(V0), + !, + '$VAR'(V) = V0, + V1 = V01. +% atom_string(V1, V01). +bind_qv(V='$VAR'(Vi), V1=S1, Vs, [V='$VAR'(Vi)|Vs], D0-RB, D-RB) :- !, + add2dict(D0, V1:S1, D). +bind_qv(V=S, V1=S1, Vs, [V=S|Vs], D0-RB0, D-RB0) :- +% fix_tree( S, SS, S1, SS1, RB0, RBT), + add2dict(D0, V1:S1, D). -enumerate('$VAR'(A), I, I1) :- + +add2dict({}, B, {B}). +add2dict({C}, B, {B,C}). + +enumerate('$VAR'(A), A, I, I1) :- enum(I, Chars), atom_codes(A,[0'_|Chars]), I1 is I + 1. @@ -84,65 +101,18 @@ enum(I, [C|Cs]) :- C is "A" +K, enum(J, Cs). -out(Bs, S, _Dict) :- +out(Bs, S) :- output(Bs, S), - fail. -out(Bs, _S, Dict) :- - bvs(Bs, Dict). - -v2py(v(I0) = _V, I0, I) :- - !, - I is I0+1. -v2py(v(I0) = v(I0), I0, I) :- - I is I0+1. + !. +out([_|Bs], S) :- + out(Bs, S). output([V=B], S) :- !, format(S, '~a = ~q~n', [V, B]). -output([V=B|Ns], S) :- - format( S, '~a = ~q.~n', [V, B]), - output( Ns, S). - -bvs([V=B], S:B) :- - atom_atring(V,S), - !. -bvs([V=B|Ns], (S:B,N) ) :- - atom_string(V,S), - output( Ns, N). - - bindvars( L, NL ) :- - rb_new(T), - foldl2( bind, L, NL, T, _ , 0, _), - term_variables(NL, Vs), - foldl( bind_new, Vs, 0, _). +output([V=B|_Ns], S) :- + format( S, '~a = ~q.~n', [V, B]), + fail. - bind(X=Y, X=X, T0, T, N, N) :- - var(Y), - !, - rb_update(T0, Y, X, T). - bind(X = G, X = G, T, T, N0, N0) :- - ground(G), - !. - bind(X = C, X = NC, T, NT, N0, NF) :- - C =.. [N|L], - foldl2( bind_new, L, NL, T, NT, N0, NF), - NC =.. [N|NL]. - bind_new(Y, X, T, T, N, N) :- - var(Y), - rb_lookup(Y, X, T), - !. - bind_new(Y, X, T, TN, N, NF) :- - var(Y), - !, - rb_insert(Y, T, X, TN), - NF is N+1, - atomic_concat('_',N,X). - bind_new(Y, Y, T, T, N, N) :- - ground(Y), - !. - bind_new(Y, X, T, NT, N0, NF) :- - Y =.. [N|L], - foldl2(v, L, NL, T, NT, N0, NF), - X =.. [N|NL]. diff --git a/packages/swig/yap.i b/packages/swig/yap.i index 127ecded5..6804944fe 100644 --- a/packages/swig/yap.i +++ b/packages/swig/yap.i @@ -108,6 +108,7 @@ class YAPEngine; //%typemap(in) YAPTerm { $1 = new YAPTerm(pythonToYAP($input)); PyErr_Clear(); } %typemap(in) YAP_Term { $1 = pythonToYAP($input); PyErr_Clear(); } %typemap(in) Term { $1 = pythonToYAP($input); PyErr_Clear(); } +%typemap(in) YAPTerm { YAPTerm(($1 = pythonToYAP($input))); PyErr_Clear(); } %typecheck(2) Int { $1 = PyLong_Check($input); } %typecheck(3) double { $1 = PyFloat_Check($input); } diff --git a/pl/directives.yap b/pl/directives.yap index 79a254e0b..bf76a60de 100644 --- a/pl/directives.yap +++ b/pl/directives.yap @@ -115,6 +115,7 @@ '$discontiguous'(D,M). /** @pred initialization + Execute the goals defined by initialization/1. Only the first answer is considered. diff --git a/pl/errors.yap b/pl/errors.yap index 410a80a01..bb309577e 100644 --- a/pl/errors.yap +++ b/pl/errors.yap @@ -142,7 +142,7 @@ system_error(Type,Goal,Culprit) :- functor(Error, Severity, _), print_message(Severity, Error), !. %'$process_error'(error(Msg, Where), _) :- -% print_message(error,error(Msg, [g|Where])), !. +% Print_message(error,error(Msg, [g|Where])), !. '$process_error'(Throw, _) :- print_message(error,error(unhandled_exception,Throw)). diff --git a/pl/messages.yap b/pl/messages.yap index d61f52f33..9450dbea7 100644 --- a/pl/messages.yap +++ b/pl/messages.yap @@ -108,8 +108,9 @@ In YAP, the infoo field describes: :- use_system_module( user, [message_hook/3]). +%:- start_low_level_trace. :- multifile prolog:message/3. - +%:- stop_low_level_trace. :- multifile user:message_hook/3. @@ -910,7 +911,7 @@ If you need to report errors from your own predicates, we advise you to stick to the existing error terms if you can; but should you need to invent new ones, you can define corresponding error messages by asserting clauses for `prolog:message/2`. You will need to declare -the predicate as multifile. +the predicate as multifile/1. Note: errors in the implementation of print_message/2 are very confusing to YAP (who will process the error?). So we write this small diff --git a/pl/undefined.yap b/pl/undefined.yap index 29487997b..a4ef740f8 100644 --- a/pl/undefined.yap +++ b/pl/undefined.yap @@ -60,15 +60,15 @@ a call to a predicate for which no clauses were defined will result in the output of a message of the form: ~~~~~{.prolog} -Undefined predicate: user:xyz(A1 ,A2) +Undefined predicate: ~~~~~ followed by the failure of that call. */ :- multifile user:unknown_predicate_handler/3. undefined_query(G0, M0, Cut) :- -'$undefp_search'(M0:G0, M:G), - '$call'(G, Cut, G, M). + recorded('$import','$import'(M,M0,G,G0,_,_),_), + '$call'(G, Cut, G, M). '$handle_error'(error,Goal,Mod) :- functor(Goal,Name,Arity),