/* Prolog rules for query evaluation */

:- library(fast_bagof).

query(Query) :-
   put_in_vars(Query,NewQuery,[],_),
   answer1(NewQuery).

answer1([all,X,Cond,Q]) :- !,
   not((answer1(Cond),not(answer1(Q)))).
answer1([exists,X,Cond,Q]) :- !,
   answer1(Cond), answer1(Q), !.
answer1([the,X,Cond,Q]) :- !,
   (unique_answer1(X,Cond); error('False presupposition',[Cond])), !,
   answer1(Q).
answer1([printout,X]) :- !,
   write(X), nl.
answer1([and,X,Y]) :- !,
   answer1(X),
   answer1(Y).
answer1([or,X,Y]) :- !,
   (answer1(X); answer1(Y)).
answer1([not,X]) :- !,
   not(answer1(X)).
answer1(Prop) :-
   Goal =.. Prop,
   call(Goal).

unique_answer1(X,Cond) :-
   fast_bagof(X,answer1(Cond),[X]), !.


;;; Translating words beginning with "X" in the query to Prolog variables

put_in_vars(X,Y,E1,E2) :-
   atom(X),
   name(X,[88|_]), !,
   lookup(X,Y,E1,E2).
put_in_vars(X,X,E1,E1) :-
   atomic(X), !.
put_in_vars(X,Y,E1,E2) :-
   functor(X,F,N),
   functor(Y,F,N),
   put_in_vars_args(N,X,Y,E1,E2).

put_in_vars_args(0,_,_,E,E) :- !.
put_in_vars_args(N,X,Y,E1,E3) :-
   N1 is N - 1,
   arg(N,X,A1),
   arg(N,Y,A2),
   put_in_vars(A1,A2,E1,E2),
   put_in_vars_args(N1,X,Y,E2,E3).

lookup(X,Y,E,E) :- member([X|Y],E), !.
lookup(X,Y,E,[[X|Y]|E]).

member(X,[X|L]).
member(X,[Y|L]) :- member(X,L).

;;; Query evaluation - sends the semanic interpretation to Prolog

:- prolog_language(pop11).

define query(list);
   vars goal;
   prolog_maketerm(list,"query",1) -> goal;
   if prolog_invoke(goal) then
      [yes]=>
   else
      [no]=>
   endif
enddefine;
