Add mechanism to stop query

This commit is contained in:
bakaq
2024-09-07 02:06:01 -03:00
parent a885e87ef7
commit fdd6579230

View File

@@ -192,8 +192,7 @@ instruction_match(Term, VarList) :-
( atom(Item) -> ( atom(Item) ->
( Item == user -> ( Item == user ->
catch(load(user_input), E, print_exception_with_check(E)) catch(load(user_input), E, print_exception_with_check(E))
; ; submit_query_and_print_results(consult(Item), [])
submit_query_and_print_results(consult(Item), [])
) )
; catch(type_error(atom, Item, repl/0), ; catch(type_error(atom, Item, repl/0),
E, E,
@@ -201,24 +200,24 @@ instruction_match(Term, VarList) :-
) )
; Term = end_of_file -> ; Term = end_of_file ->
halt halt
; ; submit_query_and_print_results(Term, VarList)
submit_query_and_print_results(Term, VarList)
). ).
%% run_query(+QueryChars, +Callback_2, +Options) %% run_query(+QueryChars, +Callback_3, +Options)
% %
% Runs a query from a string of chars, calling `Callback_2` on each leaf answer. % Runs a query from a string of chars, calling `Callback_3` on each leaf answer.
% See `run_query_goal/4` for details. % See `run_query_goal/4` for details.
run_query(QueryChars, Callback_2, Options) :- run_query(QueryChars, Callback_3, Options) :-
read_term_from_chars(QueryChars, QueryGoal, [variable_names(VarNames)]), read_term_from_chars(QueryChars, QueryGoal, [variable_names(VarNames)]),
run_query_goal(QueryGoal, VarNames, Callback_2, Options). run_query_goal(QueryGoal, VarNames, Callback_3, Options).
%% run_query_goal(+QueryGoal, +VarNames, +Callback_2, +Options) %% run_query_goal(+QueryGoal, +VarNames, +Callback_3, +Options)
% %
% Run a query from a goal, calling `Callback_2` on each leaf answer. % Run a query from a goal, calling `Callback_3` on each leaf answer.
% `VarNames` needs to have the same format as the one from the `variable_names(-VarNames)` % `VarNames` needs to have the same format as the one from the `variable_names(-VarNames)`
% option in `read_term/3`. That is, a list of terms of the form `Name=Var`, where `Name` % option in `read_term/3`. That is, a list of terms of the form `Name=Var`, where `Name`
% is an atom and `Var` is a variable. The possible first arguments to `Callback_2` are: % is an atom and `Var` is a variable. `Callback_3` should have the form
% `callback(+LeafAnswer, +Info, -Stop)`, where `LeafAnswer` will be one of those:
% %
% - `final(false)` % - `final(false)`
% - `final(exception(Exception))`, where `Exception` is the exception thrown % - `final(exception(Exception))`, where `Exception` is the exception thrown
@@ -237,11 +236,13 @@ run_query(QueryChars, Callback_2, Options) :-
% The variants with principal functor `final/1` mean that there will be no more leaf answers, % The variants with principal functor `final/1` mean that there will be no more leaf answers,
% and the ones with `pending/1` mean that there will be more leaf answers. % and the ones with `pending/1` mean that there will be more leaf answers.
% %
% The second argument is a list with extra information that can be activated with options. % The second argument of the callback (`Info`) is a list with extra information that can
% be activated with options. The third argument `Stop` controls whether the query will continue
% or stop, and should be instantiated by the callback to either `continue` or `stop`.
% %
% `Option` is a list of options. There are none currently, but in the future support for % `Option` is a list of options. There are none currently, but in the future support for
% inference limits and timeouts may be implemented. % inference limits and timeouts may be implemented.
run_query_goal(QueryGoal, VarNames, Callback_2, _) :- run_query_goal(QueryGoal, VarNames, Callback_3, _) :-
% The b value in the WAM basically represents which choicepoint we are at. % The b value in the WAM basically represents which choicepoint we are at.
% By recording it before and after we can then compare the values to know % By recording it before and after we can then compare the values to know
% if we are still inside the query or not. % if we are still inside the query or not.
@@ -258,11 +259,15 @@ run_query_goal(QueryGoal, VarNames, Callback_2, _) :-
), ),
( Excepted == true -> ( Excepted == true ->
!, !,
call(Callback_2, final(exception(Exception)), []) call(Callback_3, final(exception(Exception)), [], _)
; ( VarNames == [], ResGoals == [] -> ; ( VarNames == [], ResGoals == [] ->
( Pending == true -> ( Pending == true ->
call(Callback_2, pending(true), []) call(Callback_3, pending(true), [], Stop),
; call(Callback_2, final(true), []) ( Stop == stop -> !
; Stop == continue -> true
; domain_error(stop_or_continue, Stop, run_query_goal/4)
)
; call(Callback_3, final(true), [], _)
) )
; copy_term([Vars1, ResVars], [Vars1, ResVars], ResGoals), ; copy_term([Vars1, ResVars], [Vars1, ResVars], ResGoals),
term_variables(ResGoals, ResGoalVars), term_variables(ResGoals, ResGoalVars),
@@ -274,26 +279,31 @@ run_query_goal(QueryGoal, VarNames, Callback_2, _) :-
term_variables(Vars3, Vars4), % deduplicate vars of Vars1 but preserve their order. term_variables(Vars3, Vars4), % deduplicate vars of Vars1 but preserve their order.
charsio:extend_var_list(Vars4, VarNames, NewVarNames1, fabricated), charsio:extend_var_list(Vars4, VarNames, NewVarNames1, fabricated),
( Pending == true -> ( Pending == true ->
call(Callback_2, pending(leaf_answer(Bindings, ResGoals, NewVarNames1)), []) call(
; call(Callback_2, final(leaf_answer(Bindings, ResGoals, NewVarNames1)), []) Callback_3,
pending(leaf_answer(Bindings, ResGoals, NewVarNames1)),
[],
Stop
),
( Stop == stop -> !
; Stop == continue -> true
; domain_error(stop_or_continue, Stop, run_query_goal/4)
)
; call(Callback_3, final(leaf_answer(Bindings, ResGoals, NewVarNames1)), [], _)
) )
) )
). ).
run_query_goal(_, _, Callback_2, _) :- run_query_goal(_, _, Callback_3, _) :-
% If the whole query failed or we didn't cut in the previous definition of % If the whole query failed or we didn't cut in the previous definition of
% run_query_goal/4 (which means we are still in the query but it has failed) % run_query_goal/4 (which means we are still in the query but it has failed)
% then we get here so we have a (tail) false. % then we get here so we have a (tail) false.
call(Callback_2, final(false), []). call(Callback_3, final(false), [], _).
submit_query_and_print_results(QueryTerm, VarNames) :- submit_query_and_print_results(QueryTerm, VarNames) :-
bb_put('$answer_count', 0), bb_put('$answer_count', 0),
bb_put('$report_all', false), bb_put('$report_all', false),
bb_put('$report_n_more', 0), bb_put('$report_n_more', 0),
catch( run_query_goal(QueryTerm, VarNames, toplevel_query_callback, []).
run_query_goal(QueryTerm, VarNames, toplevel_query_callback, []),
'$stop_query',
true
).
handle_first_answer :- handle_first_answer :-
( bb_get('$answer_count', 0) -> ( bb_get('$answer_count', 0) ->
@@ -306,12 +316,12 @@ increment_answer_count :-
Count is Count0 + 1, Count is Count0 + 1,
bb_put('$answer_count', Count). bb_put('$answer_count', Count).
toplevel_query_callback(pending(LeafAnswer), _) :- toplevel_query_callback(pending(LeafAnswer), _, Stop) :-
handle_first_answer, handle_first_answer,
increment_answer_count, increment_answer_count,
write_leaf_answer(LeafAnswer, []), write_leaf_answer(LeafAnswer, []),
read_input(LeafAnswer). read_input(LeafAnswer, Stop).
toplevel_query_callback(final(LeafAnswer), _) :- toplevel_query_callback(final(LeafAnswer), _, continue) :-
( exception(Exception) = LeafAnswer -> ( exception(Exception) = LeafAnswer ->
print_exception(Exception) print_exception(Exception)
; handle_first_answer, ; handle_first_answer,
@@ -330,7 +340,7 @@ write_leaf_answer(leaf_answer(Bindings, ResGoals, VarNames), Options) :-
; write_eq(ThreadedGoals, VarNames, 20) ; write_eq(ThreadedGoals, VarNames, 20)
). ).
read_input(LeafAnswer) :- read_input(LeafAnswer, Stop) :-
( bb_get('$report_all', true) -> ( bb_get('$report_all', true) ->
C = n C = n
; bb_get('$report_n_more', N), N > 1 -> ; bb_get('$report_n_more', N), N > 1 ->
@@ -339,33 +349,35 @@ read_input(LeafAnswer) :-
C = n C = n
; get_single_char(C) ; get_single_char(C)
), ),
( C = w -> ( member(C, ['\n', .]) ->
nl,
write(' '),
write_leaf_answer(LeafAnswer, [depth(deep)]),
read_input(LeafAnswer)
; C = p ->
nl,
write(' '),
write_leaf_answer(LeafAnswer, [depth(shallow)]),
read_input(LeafAnswer)
; member(C, [';', ' ', n]) ->
nl, write('; ')
; C = h ->
help_message,
read_input(LeafAnswer)
; member(C, ['\n', .]) ->
nl, write('; ... .'), nl, nl, write('; ... .'), nl,
throw('$stop_query') Stop = stop
; C = a -> ; Stop = continue,
bb_put('$report_all', true), ( C = w ->
nl, write('; ') nl,
; C = f -> write(' '),
bb_get('$answer_count', Count), write_leaf_answer(LeafAnswer, [depth(deep)]),
More is 5 - Count mod 5, read_input(LeafAnswer)
bb_put('$report_n_more', More), ; C = p ->
nl, write('; ') nl,
; read_input(LeafAnswer) write(' '),
write_leaf_answer(LeafAnswer, [depth(shallow)]),
read_input(LeafAnswer)
; member(C, [';', ' ', n]) ->
nl, write('; ')
; C = h ->
help_message,
read_input(LeafAnswer)
; C = a ->
bb_put('$report_all', true),
nl, write('; ')
; C = f ->
bb_get('$answer_count', Count),
More is 5 - Count mod 5,
bb_put('$report_n_more', More),
nl, write('; ')
; read_input(LeafAnswer)
)
). ).
needs_bracketing(Value, Op) :- needs_bracketing(Value, Op) :-