/* File:      flrshell.P  -- The Flora interactive shell
**
** Author(s): Bertram Ludaescher
**            Michael Kifer
**            Guizhen Yang
**
** Contact:   flora-users@lists.sourceforge.net
**
** Copyright (C) The Research Foundation of SUNY, 1999-2002
**
** 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: flrshell.P,v 1.51 2003/06/18 07:01:36 kifer Exp $
**
*/


:- compiler_options([xpp_on]).
#include "extensions_xsb.h"

#include "flora_exceptions.flh"
#include "flora_terms.flh"

#define PROLOG_PFILE_EXT	XSB_SRC_EXTENSION_ATOM_SANS_DOT
#define PROLOG_OFILE_EXT	XSB_OBJ_EXTENSION_ATOM_SANS_DOT
#define PROLOG_HFILE_EXT	XSB_HDR_EXTENSION_ATOM_SANS_DOT

/*********************************************************************/
flora_shell_loop :-
	flora_init_shell,
	repeat,
	catch(flora_shell_loop_body, Exception, flora_shell_loop_handler(Exception)).

flora_shell_loop_body :-
	(flora_banner_control(noprompt) ; flora_shell_prompt),
	flora_shell_command_line(Code,Options,Status),
	( flora_good_command(Status) ->
	    findall(SysLibOp,member(FLSYSLIB(SysLibOp),Options),SysLibList),
	    flora_load_library(SysLibList),
	    findall(SysModOp,member(FLSYSMOD(SysModOp),Options),SysModList),
	    flora_load_system_module(SysModList),
	    call(Code)
	;
	  true
        ),
	flora_loop_guard(Status).


flora_shell_loop_handler(Error) :-
	var(Error),
	!,
	flora_error_line('Unbound variable thrown as exception - caught'), 
	flora_stderr_nl,
	fail.
%% If end_of_flora_shell was thrown then true (exit)
%% Othewrwise - fail (continue the loop)
flora_shell_loop_handler(END_OF_FLORA_SHELL) :-
	!.
flora_shell_loop_handler(FLORA_CMD_LINE_ARGUMENT_DONE) :-
	!,
	fail.
flora_shell_loop_handler(FLORA_TOP_LEVEL) :-
	!,
	fail.
flora_shell_loop_handler(FLORA_UNDEFINED_EXCEPTION(_,ErrorMsg)) :-
	!,
	flora_error_line(ErrorMsg),
	fail.
flora_shell_loop_handler(error(undefined_predicate(PredName,Arity,Module),_Msg)) :-
	flora_undefined_predicate_hook(PredName,Arity,Module),
	!,
	fail.
flora_shell_loop_handler(error(existence_error(module,Module),_Msg)) :-
	flora_error_line('attempt to call a Prolog predicate in a not found module `~w''',
			 [Module]),
	!,
	fail.
flora_shell_loop_handler(FLORA_ABORT) :-
	!,
	flora_stderr_string('++Abort[FLORA]'), flora_stderr_nl,
	fail.
flora_shell_loop_handler(FLORA_ABORT(Msg)) :-
	!,
	flora_stderr_string('++Abort[FLORA]> ~w', [Msg]), flora_stderr_nl,
	fail.
flora_shell_loop_handler('_$abort_ball') :-
	!,
	flora_stderr_string('++Abort[Prolog]'), flora_stderr_nl,
	fail.
flora_shell_loop_handler('_$abort_ball'(Exception)) :-
	!,
	flora_stderr_string('++Abort[Prolog]> '),
	flora_stderr_string(Exception), flora_stderr_nl,
	fail.
flora_shell_loop_handler(Exception) :-
	flora_error_line('~w', [Exception]), flora_stderr_nl,
	fail.



/*********************************************************************/
flora_init_shell :-
	consult(flrundefhook),
	consult(flrutils),
	flora_load_library(FLLIBSHELLANS),
	flora_load_library(FLLIBLOAD),
	flora_load_library(FLLIBDISPLAY),
	flora_load_library(FLLIBIMPORTEDCALLS),
	flloadtrailer(NONE),
	(flora_banner_control(nobanner) ; flora_welcome_msg),
	flAll,
	flChatter,
	flora_set_counter(flora_shell_loaded,1),
	!.


/*********************************************************************/
flora_welcome_msg :-
	flora_configuration(version,V),
	flora_stdmsg_string('~nFLORA-2 Version ~w~n~n',[V]),
	flora_stdmsg_line('Type `flHelp.'' to display help.'),
	flora_stdmsg_line('Type `flDemo(demoName).'' to run a demo.'),
	flora_stdmsg_nl,
	!.


/*********************************************************************/
flora_shell_prompt :- flora_stdfdbk_string('flora2 ?- ').


/*********************************************************************/
%% Check for end of input
flora_loop_guard(Status) :-
	( flora_end_of_input(Status) ->
	    ( pop_stdin(cmd_line_argument) ->
		%% end of input from -e option string to XSB
		flora_stdfdbk_string('~n'),
		throw(FLORA_CMD_LINE_ARGUMENT_DONE)
	    ;
	      flEnd
	    )
	;
	    %% We have to throw -- can't fail -- because we don't want
	    %% backtracking over the executed goal. Instead, we want
	    %% to return to FLORA's top level
	    throw(FLORA_TOP_LEVEL)
	).


/*********************************************************************/
#mode save
#mode nostring "\!#'"
flHelp :-
	flora_stdmsg_line('~nFLORA shell commands:~n'),
	flora_stdmsg_line('o flHelp'),
	flora_stdmsg_line('    show this info'),
	flora_stdmsg_line('o FL_COMPILE FILE'),
	flora_stdmsg_line('    compile FILE.flr for the shell module `main'''),
	flora_stdmsg_line('o FL_COMPILE FILE>>Module'),
	flora_stdmsg_line('    compile FILE.flr for Module'),
	flora_stdmsg_line('o FL_LOAD FILE>>Module  OR  [FILE >> Module,...]'),
	flora_stdmsg_line('    load FILE.flr into Module'),
	flora_stdmsg_string('    specifying FILE.~w or FILE.~w loads these files;',
			    [PROLOG_PFILE_EXT,PROLOG_OFILE_EXT]),
	flora_stdmsg_nl,
	flora_stdmsg_line('    the [...] version can load a list of files'),
	flora_stdmsg_line('o FL_LOAD FILE  OR  [FILE,...]'),
	flora_stdmsg_line('    load FILE.flr into the shell module `main'''),
	flora_stdmsg_line('o flDemo(FILE)'),
	flora_stdmsg_line('    run a demo from FLORA demos directory'),
	flora_stdmsg_line('o FL_EQUALITY {none|basic|flogic}'),
	flora_stdmsg_line('    set support for the equality predicate in the shell module `main'' to'),
	flora_stdmsg_line('    none, standard first-order, or F-logic style'),
	flora_stdmsg_line('o newmodule{MODULENAME [, none|basic|flogic]}'),
	flora_stdmsg_line('    create new module MODULENAME with given equality maintenance level'),
	flora_stdmsg_line('o FL_ARGUMENTS Functor({FL_OID|FL_BODYFORMULA},...)'),
	flora_stdmsg_line('    define the predicate argument type in shell mode'),
	flora_stdmsg_line('o FL_OP(Precedence,Associativity,Operator)'),
	flora_stdmsg_line('    define an operator in shell mode'),
	flora_stdmsg_line('o flReset(FL_ARGUMENTS|FL_OP)'),
	flora_stdmsg_line('    clear all dynamic FL_ARGUMENTS or operator (FL_OP) declarations'),
	flora_stdmsg_line('o abolish_all_tables'),
	flora_stdmsg_line('    flush all tabled data'),
	flora_stdmsg_line('    in the FLORA shell'),
	flora_stdmsg_line('o flAll'),
	flora_stdmsg_line('    show all solutions (default)'),
	flora_stdmsg_line('o flOne'),
	flora_stdmsg_line('    show solutions one by one'),
	flora_stdmsg_line('o flMaxerr(all|N)'),
	flora_stdmsg_line('    set/show the maximum number of errors FLORA reports'),
	flora_stdmsg_line('o flTrace/flNoTrace'),
	flora_stdmsg_line('    turn on/off FLORA trace'),
	flora_stdmsg_line('o flEnd'),
	flora_stdmsg_line('    say Ciao to FLORA, stay in Prolog'),
	flora_stdmsg_line('o flHalt'),
	flora_stdmsg_line('    quit both FLORA and Prolog').
#mode restore


/*********************************************************************/
flReset(X) :-
	var(X),
	!,
	flora_error_line('invalid argument to flReset'),
	fail.

%%flReset(FL_PROLOG) :- !, flora_shreset_prolog.
%%flReset(FL_ARGUMENTS) :- !, flora_shreset_arguments.
flReset(FL_OP) :- !, flora_shreset_operator.

flReset(_) :-
	flora_error_line('invalid argument to flReset'),
	!,
	fail.


/*********************************************************************/
flAll :-
	( flora_switch(all) -> true
	;
	  assert(flora_switch(all))
	).

flOne :-
	retractall(flora_switch(all)).


/*********************************************************************/
flEnd :-
	unstrap_flora,
	flora_stdmsg_line('~n~nCiao!'),
	throw(END_OF_FLORA_SHELL).


/*********************************************************************/
%% This is needed so we could designate this predicate as unprintable 
%% by the debugger and avoid traicing inside 
%% assert(flora_switch(low_level_trace))
flora_set_switch(Switch) :-
	assert(flora_switch(Switch)).
/*********************************************************************/
%% Enable Flora high-level debugging
flTrace :- flora_trace.
flNoTrace :- 
	make_trace_interactive,
	flora_notrace.

%% Dumps profile into File
flTrace(File) :-
	dump_trace_to_file(File),
	flTrace.

%% Enables low-level Prolog debugging
flTraceLow :-
	flTrace,
	flora_set_switch(low_level_trace).
flTraceLow(File) :-
	flTrace(File),
	flora_set_switch(low_level_trace).
flNoTraceLow :-
	flNoTrace,
	retractall(flora_switch(low_level_trace)).


dump_trace_to_file(File) :-
	debug_ctl(prompt,off),
	debug_ctl(profile,on),
	debug_ctl(redirect,File).
make_trace_interactive :-
	debug_ctl(prompt,on),
	debug_ctl(profile,off),
	debug_ctl(redirect,tty).



/*********************************************************************/
flChatter :- flora_set_switch(chatter).
flNoChatter :- retractall(flora_switch(chatter)).


/*********************************************************************/
flDemo(File) :-
	flora_check_filename(File),
	flora_configuration(installdir,FloraDir),
	flora_slash(Slash),
	%% Add the demo directory to the module search path
	flora_concat_atoms([FloraDir,Slash,'demos'],DemoDir),
	( flora_module_path_get(DemoDir) ->
	    true
	; flora_module_path_add(DemoDir)
	),
	cwd(CurrWorkingDir),
	cd(DemoDir),
	flora_load_module_internal(File),
	cd(CurrWorkingDir),
	flora_module_path_remove(DemoDir).


syntax highlighted by Code2HTML, v. 0.9.1