| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | % cleanup.yap | 
					
						
							|  |  |  | % Copyright (C) 2002 by Christian Thaeter | 
					
						
							|  |  |  | % | 
					
						
							|  |  |  | % public interface: | 
					
						
							|  |  |  | % | 
					
						
							|  |  |  | % :- fragile name/arity. | 
					
						
							|  |  |  | %       declares the predicate denoted by name/arity as fragile predicate. | 
					
						
							|  |  |  | %       Whenever such a fragile predicate is used in a query it will be | 
					
						
							|  |  |  | %       called through call_cleanup/1. | 
					
						
							|  |  |  | % | 
					
						
							|  |  |  | % call_cleanup(Goal). | 
					
						
							|  |  |  | % call_cleanup(Goal,CleanUpGoal). | 
					
						
							|  |  |  | %       Goal will be called in a cleanup-context, where any registered | 
					
						
							|  |  |  | %       CleanUpGoal inside of that context will be called when Goal is left, | 
					
						
							|  |  |  | %       either by a fail, cut or exeption. | 
					
						
							|  |  |  | %       It is possible to nest cleanup contexts. | 
					
						
							|  |  |  | % | 
					
						
							|  |  |  | % on_cleanup(CleanUpGoal). | 
					
						
							|  |  |  | %       registers CleanUpGoal to the current cleanup context. | 
					
						
							|  |  |  | %       CleanUpGoal's are executed in reverse order of their registration. | 
					
						
							|  |  |  | %       throws an exception if called outside of any cleanup-context. | 
					
						
							|  |  |  | % | 
					
						
							|  |  |  | % cleanup_all. | 
					
						
							| 
									
										
										
										
											2002-10-30 17:27:19 +00:00
										 |  |  | %       calls all pending CleanUpGoals and resets the cleanup-system to an initial state.  | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | %       should only be used as one of the last calls in the main program. | 
					
						
							|  |  |  | % | 
					
						
							|  |  |  | % hidden predicates: | 
					
						
							|  |  |  | % most private predicates could also be used in special cases, such as manually setting up cleanup-contexts. | 
					
						
							|  |  |  | % Read the Source. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | :- module( cleanup, [ | 
					
						
							| 
									
										
										
										
											2010-03-05 00:00:00 +00:00
										 |  |  | 		     call_cleanup/2, | 
					
						
							|  |  |  | 		     call_cleanup/1, | 
					
						
							|  |  |  | 		     on_cleanup/1, | 
					
						
							|  |  |  | 		     cleanup_all/0, | 
					
						
							|  |  |  | 		     op(1150, fx,fragile) | 
					
						
							|  |  |  | 		    ]). | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | :- multifile user:goal_expansion/3. | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | :- user_defined_directive(fragile(G), cleanup:cleanup_expansion(G)). | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | :- meta_predicate | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | 	call_cleanup(:,:), | 
					
						
							|  |  |  | 	call_cleanup(:), | 
					
						
							|  |  |  | 	on_cleanup(:), | 
					
						
							|  |  |  | 	on_cleanup(?,:), | 
					
						
							|  |  |  | 	on_cleanupz(:), | 
					
						
							|  |  |  | 	on_cleanupz(?,:). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :- initialization(init_cleanup). | 
					
						
							|  |  |  | init_cleanup :- | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | 	bb_put(expansion_toggle,1), | 
					
						
							|  |  |  | 	\+ bb_get(cleanup_level,_), | 
					
						
							|  |  |  | 	bb_put(cleanup_level,0). | 
					
						
							|  |  |  | 	% TODO: would be nice to register cleanup_all into the | 
					
						
							|  |  |  | 	% toplevel to be called after each query is finished | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | init_cleanup. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | % call goal G  with a cleanup CL in a cleanup context | 
					
						
							|  |  |  | call_cleanup(G,CL) :- | 
					
						
							|  |  |  | 	needs_cleanup(L), | 
					
						
							|  |  |  | 	on_cleanup(L,CL), | 
					
						
							|  |  |  | 	( | 
					
						
							|  |  |  | 		catch(G,X,(do_cleanup(L),throw(X))) | 
					
						
							|  |  |  | 	; | 
					
						
							|  |  |  | 		do_cleanup(L) | 
					
						
							|  |  |  | 	). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | % call a goal G in a cleanup context | 
					
						
							|  |  |  | call_cleanup(G) :- | 
					
						
							|  |  |  | 	needs_cleanup(L), | 
					
						
							|  |  |  | 	( | 
					
						
							|  |  |  | 		catch(G,X,(do_cleanup(L),throw(X))) | 
					
						
							|  |  |  | 	; | 
					
						
							|  |  |  | 		do_cleanup(L) | 
					
						
							|  |  |  | 	). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | % begin cleanup level | 
					
						
							|  |  |  | needs_cleanup(CL) :- | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | 	bb_get(cleanup_level,L), | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | 	CL is L + 1, | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | 	bb_put(cleanup_level,CL). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | cleanup_context(CL) :- | 
					
						
							|  |  |  | 	bb_get(cleanup_level,CL). | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | % leave cleanup level, call all registred cleanup predicates within | 
					
						
							|  |  |  | do_cleanup(CL) :- | 
					
						
							|  |  |  | 	CN is CL - 1, | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | 	bb_put(cleanup_level,CN), | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | 	next_cleanup(CL). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | next_cleanup(CL) :- | 
					
						
							|  |  |  | 	!,recorded(cleanup:handle,(L,G),R), | 
					
						
							|  |  |  | 	CL =< L, | 
					
						
							|  |  |  | 	erase(R), | 
					
						
							|  |  |  | 	(call(G);true), | 
					
						
							|  |  |  | 	next_cleanup(CL). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | % clean up all remaining stuff / reinitialize cleanup-module | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | cleanup_all :- | 
					
						
							|  |  |  | 	do_cleanup(1). | 
					
						
							|  |  |  | cleanup_all. | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | % register a cleanup predicate (normal reverse-order cleanup) | 
					
						
							|  |  |  | on_cleanup(G) :- | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | 	bb_get(cleanup_level,L), | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | 	on_cleanup(L,G). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | on_cleanup(L,G) :- | 
					
						
							|  |  |  | 	L =< 0, | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | 	throw(error(instantiation_error,no_cleanup_context(G))). | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | on_cleanup(L,G) :- | 
					
						
							|  |  |  | 	callable(G), | 
					
						
							|  |  |  | 	recorda(cleanup:handle,(L,G),_). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | % register a cleanup predicate (reverse-reverse-order cleanup) | 
					
						
							|  |  |  | on_cleanupz(G) :- | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | 	bb_get(cleanup_level,L), | 
					
						
							| 
									
										
										
										
											2002-10-03 13:54:35 +00:00
										 |  |  | 	on_cleanupz(L,G). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | on_cleanupz(L,G) :- | 
					
						
							|  |  |  | 	L =< 0, | 
					
						
							|  |  |  | 	throw(no_cleanup_context(G)). | 
					
						
							|  |  |  | on_cleanupz(L,G) :- | 
					
						
							|  |  |  | 	callable(G), | 
					
						
							|  |  |  | 	recordz(cleanup:handle,(L,G),_). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | % helpers | 
					
						
							|  |  |  | cleanup_expansion(X) :- | 
					
						
							|  |  |  | 	var(X),!,throw(error(instantiation_error,fragile(X))). | 
					
						
							| 
									
										
										
										
											2002-10-27 18:11:01 +00:00
										 |  |  | cleanup_expansion((H,T)) :- !,cleanup_expansion(H),cleanup_expansion(T). | 
					
						
							|  |  |  | cleanup_expansion([H,T]) :- !, cleanup_expansion(H), | 
					
						
							|  |  |  | 	( T = [] -> true ; cleanup_expansion(T) ). | 
					
						
							|  |  |  | cleanup_expansion(M:G/A) :- | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  |  	atom(G),integer(A),!, | 
					
						
							|  |  |  | 	compose_var_goal(G/A,GG), | 
					
						
							| 
									
										
										
										
											2002-10-14 16:09:08 +00:00
										 |  |  |         \+ user:goal_expansion(GG,M,call_cleanup(M:GG)), | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | 	assert((   user:goal_expansion(GG,M,NG) | 
					
						
							|  |  |  | 	       :-  bb_get(expansion_toggle,1) | 
					
						
							|  |  |  | 	       ->  bb_put(expansion_toggle,0), | 
					
						
							|  |  |  | 		   NG=call_cleanup(M:GG) | 
					
						
							|  |  |  | 	       ;   bb_put(expansion_toggle,1), | 
					
						
							|  |  |  | 		   NG=M:GG )). | 
					
						
							| 
									
										
										
										
											2002-10-27 18:11:01 +00:00
										 |  |  | cleanup_expansion(G/A) :- | 
					
						
							|  |  |  |        !,prolog_flag(typein_module,M),cleanup_expansion(M:G/A). | 
					
						
							| 
									
										
										
										
											2002-10-11 03:39:11 +00:00
										 |  |  | cleanup_expansion(X) :- | 
					
						
							|  |  |  | 	!,throw(error(instantiation_error,fragile(X))). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | compose_var_goal(G/A,NG) :- | 
					
						
							|  |  |  | 	arity_to_vars(A,L), NG =.. [G|L]. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | arity_to_vars(N,L) :- | 
					
						
							|  |  |  | 	arity_to_vars(N,[],L). | 
					
						
							|  |  |  | arity_to_vars(N,L1,L2) :- | 
					
						
							|  |  |  | 	N > 0, | 
					
						
							|  |  |  | 	NN is N-1, | 
					
						
							|  |  |  | 	LT = [L|L1], | 
					
						
							|  |  |  | 	arity_to_vars(NN,LT,L2). | 
					
						
							|  |  |  | arity_to_vars(0,L,L). |