View source with raw comments or as raw
    1/*  Part of CHR (Constraint Handling Rules)
    2
    3    Author:        Tom Schrijvers and Jan Wielemaker
    4    E-mail:        Tom.Schrijvers@cs.kuleuven.be
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2004-2015, K.U. Leuven
    7    All rights reserved.
    8
    9    Redistribution and use in source and binary forms, with or without
   10    modification, are permitted provided that the following conditions
   11    are met:
   12
   13    1. Redistributions of source code must retain the above copyright
   14       notice, this list of conditions and the following disclaimer.
   15
   16    2. Redistributions in binary form must reproduce the above copyright
   17       notice, this list of conditions and the following disclaimer in
   18       the documentation and/or other materials provided with the
   19       distribution.
   20
   21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32    POSSIBILITY OF SUCH DAMAGE.
   33*/
   36:- module(chr,
   37	  [ op(1180, xfx, ==>),
   38	    op(1180, xfx, <=>),
   39	    op(1150, fx, constraints),
   40	    op(1150, fx, chr_constraint),
   41	    op(1150, fx, chr_preprocessor),
   42	    op(1150, fx, handler),
   43	    op(1150, fx, rules),
   44	    op(1100, xfx, \),
   45	    op(1200, xfx, @),
   46	    op(1190, xfx, pragma),
   47	    op( 500, yfx, #),
   48	    op(1150, fx, chr_type),
   49	    op(1150, fx, chr_declaration),
   50	    op(1130, xfx, --->),
   51	    op(1150, fx, (?)),
   52	    chr_show_store/1,		% +Module
   53	    find_chr_constraint/1,	% +Pattern
   54	    chr_trace/0,
   55	    chr_notrace/0,
   56	    chr_leash/1			% +Ports
   57	  ]).   58
   59:- expects_dialect(swi).   60
   61:- set_prolog_flag(generate_debug_info, false).   62
   63:- multifile
   64	debug_ask_continue/1,
   65	preprocess/2.   66
   67:- multifile user:file_search_path/2.   68:- dynamic   user:file_search_path/2.   69:- dynamic   chr_translated_program/1.   70
   71user:file_search_path(chr, library(chr)).
   72
   73:- load_files([ chr(chr_translate),
   74		chr(chr_runtime),
   75		chr(chr_messages),
   76		chr(chr_hashtable_store),
   77		chr(chr_compiler_errors)
   78	      ],
   79	      [ if(not_loaded),
   80		silent(true)
   81	      ]).   82
   83:- use_module(library(lists), [member/2]).
  120:- multifile chr:'$chr_module'/1.  121
  122:- dynamic chr_term/3.		% File, Term
  123
  124:- dynamic chr_pp/2.		% File, Term
  125
  126%	chr_expandable(+Term)
  127%
  128%	Succeeds if Term is a  rule  that   must  be  handled by the CHR
  129%	compiler. Ideally CHR definitions should be between
  130%
  131%		:- constraints ...
  132%		...
  133%		:- end_constraints.
  134%
  135%	As they are not we have to   use  some heuristics. We assume any
  136%	file is a CHR after we've seen :- constraints ...
  137
  138chr_expandable((:- constraints _)).
  139chr_expandable((constraints _)).
  140chr_expandable((:- chr_constraint _)).
  141chr_expandable((:- chr_type _)).
  142chr_expandable((chr_type _)).
  143chr_expandable((:- chr_declaration _)).
  144chr_expandable(option(_, _)).
  145chr_expandable((:- chr_option(_, _))).
  146chr_expandable((handler _)).
  147chr_expandable((rules _)).
  148chr_expandable((_ <=> _)).
  149chr_expandable((_ @ _)).
  150chr_expandable((_ ==> _)).
  151chr_expandable((_ pragma _)).
  152
  153%	chr_expand(+Term, -Expansion)
  154%
  155%	Extract CHR declarations and rules from the file and run the
  156%	CHR compiler when reaching end-of-file.
  159extra_declarations([ (:- use_module(chr(chr_runtime))),
  160		     (:- style_check(-discontiguous)),
  161		     (:- style_check(-singleton)),
  162		     (:- style_check(-no_effect)),
  163		     (:- set_prolog_flag(generate_debug_info, false))
  164		   | Tail
  165		   ], Tail).
  175chr_expand(Term, []) :-
  176	chr_expandable(Term), !,
  177	prolog_load_context(source,File),
  178	prolog_load_context(term_position,Pos),
  179	stream_position_data(line_count,Pos,LineNumber),
  180	add_pragma_to_chr_rule(Term,line_number(LineNumber),NTerm),
  181	assert(chr_term(File, LineNumber, NTerm)).
  182chr_expand(Term, []) :-
  183	Term = (:- chr_preprocessor Preprocessor), !,
  184	prolog_load_context(source,File),
  185	assert(chr_pp(File, Preprocessor)).
  186chr_expand(end_of_file, FinalProgram) :-
  187	extra_declarations(FinalProgram,Program),
  188	prolog_load_context(source,File),
  189	findall(T, retract(chr_term(File,_Line,T)), CHR0),
  190	CHR0 \== [],
  191	prolog_load_context(module, Module),
  192	add_debug_decl(CHR0, CHR1),
  193	add_optimise_decl(CHR1, CHR2),
  194	call_preprocess(CHR2, CHR3),
  195	CHR4 = [ (:- module(Module, [])) | CHR3 ],
  196	findall(P, retract(chr_pp(File, P)), Preprocessors),
  197	( Preprocessors = [] ->
  198		CHR4 = CHR
  199	; Preprocessors = [Preprocessor] ->
  200		chr_compiler_errors:chr_info(preprocessor,'\tPreprocessing with ~w.\n',[Preprocessor]),
  201		call_chr_preprocessor(Preprocessor,CHR4,CHR)
  202	;
  203		chr_compiler_errors:print_chr_error(error(syntax(Preprocessors),'Too many preprocessors! Only one is allowed!\n',[])),
  204		fail
  205	),
  206	catch(call_chr_translate(File,
  207			   [ (:- module(Module, []))
  208			   | CHR
  209			   ],
  210			   Program0),
  211		chr_error(Error),
  212		(	chr_compiler_errors:print_chr_error(Error),
  213			fail
  214		)
  215	),
  216	delete_header(Program0, Program).
  217
  218
  219delete_header([(:- module(_,_))|T0], T) :- !,
  220	delete_header(T0, T).
  221delete_header(L, L).
  222
  223add_debug_decl(CHR, CHR) :-
  224	member(option(Name, _), CHR), Name == debug, !.
  225add_debug_decl(CHR, CHR) :-
  226	member((:- chr_option(Name, _)), CHR), Name == debug, !.
  227add_debug_decl(CHR, [(:- chr_option(debug, Debug))|CHR]) :-
  228	(   chr_current_prolog_flag(generate_debug_info, true)
  229	->  Debug = on
  230	;   Debug = off
  231	).
  234chr_current_prolog_flag(Flag,Val) :- current_prolog_flag(Flag,Val).
  237add_optimise_decl(CHR, CHR) :-
  238	\+(\+(memberchk((:- chr_option(optimize, _)), CHR))), !.
  239add_optimise_decl(CHR, [(:- chr_option(optimize, full))|CHR]) :-
  240	chr_current_prolog_flag(optimize, full), !.
  241add_optimise_decl(CHR, CHR).
 call_preprocess(+CHR0, -CHR) is det
Call user chr:preprocess(CHR0, CHR).
  247call_preprocess(CHR0, CHR) :-
  248	preprocess(CHR0, CHR), !.
  249call_preprocess(CHR, CHR).
  250
  251%	call_chr_translate(+File, +In, -Out)
  252%
  253%	The entire chr_translate/2 translation may fail, in which case we'd
  254%	better issue a warning  rather  than   simply  ignoring  the CHR
  255%	declarations.
  256
  257call_chr_translate(File, In, _Out) :-
  258	( chr_translate_line_info(In, File, Out0) ->
  259	    nb_setval(chr_translated_program,Out0),
  260	    fail
  261	).
  262call_chr_translate(_, _In, Out) :-
  263	nb_current(chr_translated_program,Out), !,
  264	nb_delete(chr_translated_program).
  265
  266call_chr_translate(File, _, []) :-
  267	print_message(error, chr(compilation_failed(File))).
  268
  269call_chr_preprocessor(Preprocessor,CHR,_NCHR) :-
  270	( call(Preprocessor,CHR,CHR0) ->
  271		nb_setval(chr_preprocessed_program,CHR0),
  272		fail
  273	).
  274call_chr_preprocessor(_,_,NCHR)	:-
  275	nb_current(chr_preprocessed_program,NCHR), !,
  276	nb_delete(chr_preprocessed_program).
  277call_chr_preprocessor(Preprocessor,_,_) :-
  278	chr_compiler_errors:print_chr_error(error(preprocessor,'Preprocessor `~w\' failed!\n',[Preprocessor])).
  282		 /*******************************
  283		 *      SYNCHRONISE TRACER	*
  284		 *******************************/
  285
  286:- multifile
  287	user:message_hook/3,
  288	chr:debug_event/2,
  289	chr:debug_interact/3.  290:- dynamic
  291	user:message_hook/3.  292
  293user:message_hook(trace_mode(OnOff), _, _) :-
  294	(   OnOff == on
  295	->  chr_trace
  296	;   chr_notrace
  297	),
  298	fail.				% backtrack to other handlers
  299
  300:- public
  301	debug_event/2,
  302	debug_interact/3.
 debug_event(+State, +Event)
Hook into the CHR debugger. At this moment we will discard CHR events if we are in a Prolog `skip' and we ignore the
  309debug_event(_State, _Event) :-
  310	tracing,			% are we tracing?
  311	prolog_skip_level(Skip, Skip),
  312	Skip \== very_deep,
  313	prolog_current_frame(Me),
  314	prolog_frame_attribute(Me, level, Level),
  315	Level > Skip, !.
 debug_interact(+Event, +Depth, -Command)
Hook into the CHR debugger to display Event and ask for the next command to execute. This definition causes the normal Prolog debugger to be used for the standard ports.
  323debug_interact(Event, _Depth, creep) :-
  324	prolog_event(Event),
  325	tracing, !.
  326
  327prolog_event(call(_)).
  328prolog_event(exit(_)).
  329prolog_event(fail(_)).
 debug_ask_continue(-Command) is semidet
Hook to ask for a CHR debug continuation. Must bind Command to one of creep, skip, ancestors, nodebug, abort, fail, break, help or exit.
  338		 /*******************************
  339		 *	      MESSAGES		*
  340		 *******************************/
  341
  342:- multifile
  343	prolog:message/3.  344
  345prolog:message(chr(CHR)) -->
  346	chr_message(CHR).
  347
  348:- multifile
  349        check:trivial_fail_goal/1.  350
  351check:trivial_fail_goal(_:Goal) :-
  352        functor(Goal, Name, _),
  353        sub_atom(Name, 0, _, _, '$chr_store_constants_').
  354
  355		 /*******************************
  356		 *	 TOPLEVEL PRINTING	*
  357		 *******************************/
  358
  359:- create_prolog_flag(chr_toplevel_show_store, true, []).  360
  361:- residual_goals(chr_residuals).
 chr_residuals// is det
Find the CHR constraints from the store. These are accessible through the nondet predicate current_chr_constraint/1. Doing a findall/4 however would loose the bindings. We therefore rolled findallv/4, which exploits non-backtrackable assignment and realises a copy of the template without disturbing the bindings using this strangely looking construct. Note that the bindings created by the unifications are in New, which is newer then the latest choicepoint and therefore the bindings are not trailed.
duplicate_term(Templ, New),
New = Templ
  379chr_residuals(Residuals, Tail) :-
  380	chr_current_prolog_flag(chr_toplevel_show_store,true),
  381	nb_current(chr_global, _), !,
  382	Goal = _:_,
  383	findallv(Goal, current_chr_constraint(Goal), Residuals, Tail).
  384chr_residuals(Residuals, Residuals).
  385
  386:- meta_predicate
  387	findallv(?, 0, ?, ?).  388
  389findallv(Templ, Goal, List, Tail) :-
  390	List2 = [x|_],
  391	State = state(List2),
  392	(   call(Goal),
  393	    arg(1, State, L),
  394	    duplicate_term(Templ, New),
  395	    New = Templ,
  396	    Cons = [New|_],
  397	    nb_linkarg(2, L, Cons),
  398	    nb_linkarg(1, State, Cons),
  399	    fail
  400	;   List2 = [x|List],
  401	    arg(1, State, Last),
  402	    arg(2, Last, Tail)
  403	).
  404
  405
  406		 /*******************************
  407		 *	   MUST BE LAST!	*
  408		 *******************************/
  409
  410:- multifile system:term_expansion/2.  411:- dynamic   system:term_expansion/2.  412
  413system:term_expansion(In, Out) :-
  414	\+ current_prolog_flag(xref, true),
  415	chr_expand(In, Out).
:- dynamic current_toplevel_show_store/1, current_generate_debug_info/1, current_optimize/1.

current_toplevel_show_store(on).

current_generate_debug_info(false).

current_optimize(off).

chr_current_prolog_flag(generate_debug_info, X) :- chr_flag(generate_debug_info, X, X). chr_current_prolog_flag(optimize, X) :- chr_flag(optimize, X, X).
chr_flag(Flag, Old, New) :- Goal = chr_flag(Flag,Old,New), g must_be(Flag, oneof([toplevel_show_store,generate_debug_info,optimize]), Goal, 1), chr_flag(Flag, Old, New, Goal).
chr_flag(toplevel_show_store, Old, New, Goal) :- clause(current_toplevel_show_store(Old), true, Ref), ( New==Old -> true ; must_be(New, oneof([on,off]), Goal, 3), erase(Ref), assertz(current_toplevel_show_store(New)) ). chr_flag(generate_debug_info, Old, New, Goal) :- clause(current_generate_debug_info(Old), true, Ref), ( New==Old -> true ; must_be(New, oneof([false,true]), Goal, 3), erase(Ref), assertz(current_generate_debug_info(New)) ). chr_flag(optimize, Old, New, Goal) :- clause(current_optimize(Old), true, Ref), ( New==Old -> true ; must_be(New, oneof([full,off]), Goal, 3), erase(Ref), assertz(current_optimize(New)) ).
all_stores_goal(Goal, CVAs) :- chr_flag(toplevel_show_store, on, on), !, findall(C-CVAs, find_chr_constraint(C), Pairs), andify(Pairs, Goal, CVAs). all_stores_goal(true, _).

andify([], true, _). andify([X-Vs|L], Conj, Vs) :- andify(L, X, Conj, Vs).

andify([], X, X, _). andify([Y-Vs|L], X, (X,Conj), Vs) :- andify(L, Y, Conj, Vs).

:- multifile term_expansion/6.

user:term_expansion(In, _, Ids, Out, [], [chr|Ids]) :- nonvar(In), nonmember(chr, Ids), chr_expand(In, Out), !.

% SICStus end

  485%%% for SSS %%%
  486
  487add_pragma_to_chr_rule((Name @ Rule), Pragma, Result) :- !,
  488	add_pragma_to_chr_rule(Rule,Pragma,NRule),
  489	Result = (Name @ NRule).
  490add_pragma_to_chr_rule((Rule pragma Pragmas), Pragma, Result) :- !,
  491	Result = (Rule pragma (Pragma,Pragmas)).
  492add_pragma_to_chr_rule((Head ==> Body), Pragma, Result) :- !,
  493	Result = (Head ==> Body pragma Pragma).
  494add_pragma_to_chr_rule((Head <=> Body), Pragma, Result) :- !,
  495	Result = (Head <=> Body pragma Pragma).
  496add_pragma_to_chr_rule(Term,_,Term).
  497
  498
  499		 /*******************************
  500		 *	  SANDBOX SUPPORT	*
  501		 *******************************/
  502
  503:- multifile
  504	sandbox:safe_primitive/1.  505
  506% CHR uses a lot of global variables. We   don't  really mind as long as
  507% the user does not mess around  with   global  variable that may have a
  508% predefined meaning.
  509
  510sandbox:safe_primitive(system:b_setval(V, _)) :-
  511	chr_var(V).
  512sandbox:safe_primitive(system:nb_linkval(V, _)) :-
  513	chr_var(V).
  514sandbox:safe_primitive(chr:debug_event(_,_)).
  515sandbox:safe_primitive(chr:debug_interact(_,_,_)).
  516
  517chr_var(Name) :- sub_atom(Name, 0, _, _, '$chr').
  518chr_var(Name) :- sub_atom(Name, 0, _, _, 'chr').
  519
  520
  521		 /*******************************
  522		 *     SYNTAX HIGHLIGHTING	*
  523		 *******************************/
  524
  525:- multifile
  526	prolog_colour:term_colours/2,
  527	prolog_colour:goal_colours/2.
 term_colours(+Term, -Colours)
Colourisation of a toplevel term as read from the file.
  533term_colours((_Name @ Rule), delimiter - [ identifier, RuleColours ]) :- !,
  534	term_colours(Rule, RuleColours).
  535term_colours((Rule pragma _Pragma), delimiter - [RuleColours,pragma]) :- !,
  536	term_colours(Rule, RuleColours).
  537term_colours((Head <=> Body), delimiter - [ HeadColours, BodyColours ]) :- !,
  538	chr_head(Head, HeadColours),
  539	chr_body(Body, BodyColours).
  540term_colours((Head ==> Body), delimiter - [ HeadColours, BodyColours ]) :- !,
  541	chr_head(Head, HeadColours),
  542	chr_body(Body, BodyColours).
  543
  544chr_head(_C#_Id, delimiter - [ head, identifier ]) :- !.
  545chr_head((A \ B), delimiter - [ AC, BC ]) :- !,
  546	chr_head(A, AC),
  547	chr_head(B, BC).
  548chr_head((A, B), functor - [ AC, BC ]) :- !,
  549	chr_head(A, AC),
  550	chr_head(B, BC).
  551chr_head(_, head).
  552
  553chr_body((Guard|Goal), delimiter - [ GuardColour, GoalColour ]) :- !,
  554	chr_body(Guard, GuardColour),
  555	chr_body(Goal, GoalColour).
  556chr_body(_, body).
 goal_colours(+Goal, -Colours)
Colouring of special goals.
  563goal_colours(constraints(Decls), deprecated-[DeclColours]) :-
  564	chr_constraint_colours(Decls, DeclColours).
  565goal_colours(chr_constraint(Decls), built_in-[DeclColours]) :-
  566	chr_constraint_colours(Decls, DeclColours).
  567goal_colours(chr_type(TypeDecl), built_in-[DeclColours]) :-
  568	chr_type_decl_colours(TypeDecl, DeclColours).
  569goal_colours(chr_option(Option,Value), built_in-[OpC,ValC]) :-
  570	chr_option_colours(Option, Value, OpC, ValC).
  571
  572chr_constraint_colours(Var, instantiation_error(Var)) :-
  573	var(Var), !.
  574chr_constraint_colours((H,T), classify-[HeadColours,BodyColours]) :- !,
  575	chr_constraint_colours(H, HeadColours),
  576	chr_constraint_colours(T, BodyColours).
  577chr_constraint_colours(PI, Colours) :-
  578	pi_to_term(PI, Goal), !,
  579	Colours = predicate_indicator-[ goal(constraint(0), Goal),
  580					arity
  581				      ].
  582chr_constraint_colours(Goal, Colours) :-
  583	atom(Goal), !,
  584	Colours = goal(constraint(0), Goal).
  585chr_constraint_colours(Goal, Colours) :-
  586	compound(Goal), !,
  587	compound_name_arguments(Goal, _Name, Args),
  588	maplist(chr_argspec, Args, ArgColours),
  589	Colours = goal(constraint(0), Goal)-ArgColours.
  590
  591chr_argspec(Term, mode(Mode)-[chr_type(Type)]) :-
  592	compound(Term),
  593	compound_name_arguments(Term, Mode, [Type]),
  594	chr_mode(Mode).
  595
  596chr_mode(+).
  597chr_mode(?).
  598chr_mode(-).
  599
  600pi_to_term(Name/Arity, Term) :-
  601	atom(Name), integer(Arity), Arity >= 0, !,
  602	functor(Term, Name, Arity).
  603
  604chr_type_decl_colours((Type ---> Def), built_in-[chr_type(Type), DefColours]) :-
  605	chr_type_colours(Def, DefColours).
  606chr_type_decl_colours((Type == Alias), built_in-[chr_type(Type), chr_type(Alias)]).
  607
  608chr_type_colours(Var, classify) :-
  609	var(Var), !.
  610chr_type_colours((A;B), control-[CA,CB]) :- !,
  611	chr_type_colours(A, CA),
  612	chr_type_colours(B, CB).
  613chr_type_colours(T, chr_type(T)).
  614
  615chr_option_colours(Option, Value, identifier, ValCol) :-
  616	chr_option_range(Option, Values), !,
  617	(   nonvar(Value),
  618	    memberchk(Value, Values)
  619	->  ValCol = classify
  620	;   ValCol = error
  621	).
  622chr_option_colours(_, _, error, classify).
  623
  624chr_option_range(check_guard_bindings, [on,off]).
  625chr_option_range(optimize, [off, full]).
  626chr_option_range(debug, [on, off]).
  627
  628prolog_colour:term_colours(Term, Colours) :-
  629	term_colours(Term, Colours).
  630prolog_colour:goal_colours(Term, Colours) :-
  631	goal_colours(Term, Colours)