/* File:      flrcontrol.P
**
** Author(s): Michael Kifer
**            Guizhen Yang
**
** Contact:   flora-users@lists.sourceforge.net
**
** Copyright (C) The Research Foundation of SUNY, 2001
**
** FLORA-2 is free software; you can redistribute it and/or modify it under the
** terms of the GNU Library General Public License as published by the Free
** Software Foundation; either version 2 of the License, or (at your option)
** any later version.
** 
** FLORA-2 is distributed in the hope that it will be useful, but WITHOUT ANY
** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
** more details.
** 
** You should have received a copy of the GNU Library General Public License
** along with FLORA-2; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
** 
** $Id: flrcontrol.P,v 1.17 2003/06/18 07:01:20 kifer Exp $
** 
*/


:- compiler_options([xpp_on]).

#include "flora_terms.flh"
#include "flora_porting.flh"

:- import flora_commit_storage/0 from flrutils.


/***************************************************************************
  if-then-else statement
***************************************************************************/
FLLIBIFTHENELSE(Cond,Then,_Else) :-
	call(Cond),
	call(Then).

FLLIBIFTHENELSE(Cond,_Then,Else) :-
	FLORA_TNOT(Cond),
	call(Else).


/***************************************************************************
  if-then statement

  The semantics is such that the entire statement succeeds when the
  condition part fails.
***************************************************************************/
FLLIBIFTHEN(Cond,Then) :-
	call(Cond),
	call(Then).

FLLIBIFTHEN(Cond,_Then) :-
	FLORA_TNOT(Cond).


%% UNLESS ... DO ... is like IF...THEN true ELSE ...
FLLIBUNLESSDO(Cond,_Action) :- call(Cond).
FLLIBUNLESSDO(Cond,Action) :- FLORA_TNOT(Cond), call(Action).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%   while-do and do-until loops commit storage after each iteration
%%%%   so they are not backtrackable (backtracking over updates can occur
%%%%   only within the condition or action parts, but not after an iteration
%%%%   is finished)
%%%%   These loops fail only if Action fails.
%%%%   Variables that were unbound at the time of the call stay unbound
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% This should fail ONLY if Cond is true, but Action fails.
%% We use catch/throw to achieve this
FLLIBWHILEDO(Cond,Action) :- 
	FLORA_SYMBOL('catch')((call(Cond),
			       (call(Action) -> flora_commit_storage, fail
			       ; throw(quitLoop)
			       )
			      ; true
			      ),
			      quitLoop,	% catcher
			      fail). % fail, if condition was thrown

%% Fails only if Action becomes false before Cond becomes true
FLLIBDOUNTIL(Action,Cond) :-
	call(Action),
	flora_commit_storage,
	call(Cond).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% while-loop and loop-until
%%%% These loops are fully backtrackable, but they are more expensive, 
%%%% since they are recursive.
%%%% These loops fail only if Action fails.
%%%% Variables that were unbound at the time of the call stay unbound
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FLLIBWHILELOOP(Cond,Action) :- 
	%% Must copy_term Action&Cond together so the variables
	%% will be preserved
	copy_term((Action,Cond),(Action1,Cond1)),
	(call(Cond1) ->
	    (call(Action1), !, FLLIBWHILELOOP(Cond,Action)
	    ; fail
	    )
	; true
	).
	/*
	FLORA_SYMBOL('catch')(
			      (call(Cond1) ->
				  (call(Action1), ! ; throw(quitLoop)),
				  FLLIBWHILELOOP(Cond,Action)
			      ; true
			      ),
			      quitLoop, % catcher
			      fail % fail if action failed
			     ).
	*/

%% Cond shouldn't be tabled!!! Otherwise "not" barks!!!
%% We can't use FLORA_TNOT instead of "not" because FLORA_TNOT
%% would table Cond and cause more iterations than necessary.
%% We could call abolish_all_tables from within FLORA_TNOT,
%% but this is dangerous:
%%    If there is a recursive dependency on Cond then abolishing tables
%%    while computing them can crash XSB
FLLIBLOOPUNTIL(Action,Cond) :-
	%% Must copy_term Action&Cond together so the variables
	%% will be preserved
	copy_term((Action,Cond),(Action1,Cond1)),
	FLORA_SYMBOL('catch')(
			      ((call(Action1), ! ; throw(quitLoop)),
				  (not(call(Cond1))
				  -> FLLIBLOOPUNTIL(Action,Cond)
				  ; true
				  )
			      ),
			      quitLoop, % catcher
			      fail % fail if action failed
			     ).


%% These exist in order to be able to hide the calls 
%% to catch/throw in the debugger
FLORA_SYMBOL('catch')(X,Y,Z) :- catch(X,Y,Z).


syntax highlighted by Code2HTML, v. 0.9.1