1 % (c) 2009-2019 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 % This module provides a plugin mechanism for ProB
6 % Each plugin has an unique ID. It should be registered in the module
7 % plugin_registry
8
9 :- module(plugins, [initialise_plugins/0
10 ,is_registered_plugin/1,is_registered_plugin/2
11 ,active_plugin/1,tcl_plugin_syntax_colouring/2
12 ,plugin_file_extensions/1
13 ,available_plugins_for_mode/1,plugin_is_available_for_mode/0
14 ,plugin_has_preferences/0,plugins_with_preferences/1
15 ,plugin_has_output/1
16 ,plugin_get_output/2
17 ,is_plugin_file_extension/2
18 ,load_plugin_file/2
19 ,setup_transition_skeleton/2
20 ,plugin_transition/5
21 ,plugin_state_property/3
22 ,plugin_parse/7
23 ,plugin_compute_expression/4
24 ,plugin_evaluate_predicate/3
25 ,plugin_evaluate_transition_predicate/3
26 ,notify_new_transition_to_plugin/4 ,notify_new_transition_to_plugin/5
27 ,plugin_is_initialised_state/2
28 ,start_plugin_for_current_mode/1,stop_plugin/0
29 ,plugin_prettyprint_transition/3
30 ,plugin_prettyprint_property/3
31 ,plugin_prettyprint_value/3
32 % ,plugin_advanced_eclipse_preference/2 % TO DO: not used nor defined at the moment
33 ,plugin_preference_default_value/2
34 ,plugin_preference_description/2
35 ,plugin_preference_val_type/2
36 ,plugin_preference_category/2
37 ,plugin_check_invariantKO/3
38 ,plugin_get_internal/2
39 ,compiletime_init_plugins/0
40 ]).
41
42 :- use_module(library(lists)).
43 :- use_module(library(codesio)).
44 :- use_module(library(file_systems)).
45
46 :- use_module(tools_strings,[ajoin/2]).
47 :- use_module(module_information,[module_info/2]).
48
49 :- use_module(specfile,[animation_mode/1,animation_minor_mode/1,set_animation_mode/1,set_animation_minor_mode/1]).
50
51 :- use_module(error_manager,[add_error/2]).
52 :- use_module(preferences,[get_preference/2]).
53
54 :- module_info(group,infrastructure).
55 :- module_info(description,'A plugin mechanism for ProB.').
56
57 :- public author/2. % for Spider
58 :- dynamic
59 plugin/2,
60 pname/2,
61 status/2,
62 author/2,
63 file_extensions/2,
64 file_loader/2,
65 transition_skeleton/2,
66 transition_pred/2,
67 initialisation_pred/2,
68 state_property_pred/2,
69 parser_pred/2,
70 compute_expression_pred/2,
71 evaluate_predicate_pred/2,
72 evaluate_transition_pred/2,
73 is_initialised_state_pred/2,
74 prettyprint_transition_pred/2,
75 prettyprint_property_pred/2,
76 prettyprint_value_pred/2,
77 syntax_colouring/2,
78 plugin_for_modes/2,
79 plugin_init_pred/2,
80 plugin_new_transition_pred/2,
81 plugin_preferences_pred/2,
82 plugin_check_invariant_pred/2,
83 plugin_output_pred/2,
84 plugin_internal_representation_pred/2.
85
86 % TODO: deactivated plugin mechanism for next release -- keeping the number of
87 % modules smaller until the report is better structured
88 % load_compiletime_plugins :- !.
89 load_compiletime_plugins :- print(load_compiletime_plugins),nl,
90 findall(Module,
91 ( directory_member_of_directory(plugins('.'),Dir,Fullname),
92 atom_concat(Dir,'.pl',PrologFilename),
93 file_member_of_directory(Fullname,PrologFilename,_),
94 ajoin([Dir,'/',PrologFilename], Modulename),
95 Module = plugins(Modulename) ),
96 Plugins),
97 %print(loading_plugins(Plugins)),nl,
98 load_plugins2(Plugins).
99
100 % these plug-ins are not stable enough to load for the normal user:
101 do_not_load_plugin(plugins('probvm/probvm.pl')).
102
103 load_plugins2([]).
104 load_plugins2([Module|Prest]) :- do_not_load_plugin(Module),!, load_plugins2(Prest).
105 load_plugins2([Module|Prest]) :-
106 load_plugin(Module,Id),
107 (nonvar(Id) -> assert(plugin(Id,Module)); true),
108 load_plugins2(Prest).
109
110 load_plugin(Module,Id) :-
111 catch( ( load_plugin2(Module,Id) ->
112 ajoin(['Loaded plugin ', Id], Msg),
113 print_message(informational, Msg)
114 ; otherwise ->
115 ajoin(['Loading of module ', Module, ' failed: '], Msg),
116 print_message(error, Msg)),
117 E,
118 ( ajoin(['Loading of module ', Module, ' raised an exception: ', E], Msg),
119 print_message(error, Msg))).
120
121 load_plugin2(Module,Id) :-
122 use_module(IdVar,Module,[]), % SICStus 4.3.3 now keeps IdVar a variable !
123 (var(IdVar) -> get_plugin_module_name(Module,Id)
124 ; IdVar = Id),
125 %print(used_module(Id,Module)),nl,
126 ( plugin(Id,_) ->
127 ajoin(['Plugin ID ',Id,' used twice'],Msg),
128 print_message(error,Msg),
129 fail
130 ; otherwise ->
131 true).
132
133 :- use_module(tools,[get_modulename_filename/2]).
134 get_plugin_module_name(plugins(F),ModuleName) :- !, tools:get_modulename_filename(F,ModuleName).
135 get_plugin_module_name(F,ModuleName) :- tools:get_modulename_filename(F,ModuleName).
136
137 %:- load_compiletime_plugins. % now done here : compiletime_init_plugins
138
139 :- use_module(eventhandling,[register_event_listener/3]).
140 :- register_event_listener(compile_prob,compiletime_init_plugins,
141 'Load compile time plugins and initialise them.').
142 compiletime_init_plugins :- load_compiletime_plugins,initialise_plugins.
143
144
145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146
147 initialise_plugins :-
148 reset_plugin_db,
149 fail.
150 initialise_plugins :-
151 ? plugin(Id,_Module),
152 initialise_plugin(Id),
153 fail.
154 initialise_plugins.
155
156 reset_plugin_db :-
157 retractpred(pname/2),
158 retractpred(status/2),
159 retractpred(author/2),
160 retractpred(file_extensions/2),
161 retractpred(file_loader/2),
162 retractpred(transition_skeleton/2),
163 retractpred(transition_pred/2),
164 retractpred(initialisation_pred/2),
165 retractpred(state_property_pred/2),
166 retractpred(parser_pred/2),
167 retractpred(compute_expression_pred/2),
168 retractpred(evaluate_predicate_pred/2),
169 retractpred(evaluate_transition_pred/2),
170 retractpred(is_initialised_state_pred/2),
171 retractpred(prettyprint_transition_pred/2),
172 retractpred(prettyprint_property_pred/2),
173 retractpred(prettyprint_value_pred/2),
174 retractpred(syntax_colouring/2),
175 retractpred(plugin_for_modes/2),
176 retractpred(plugin_init_pred/2),
177 retractpred(plugin_new_transition_pred/2),
178 retractpred(plugin_preferences_pred/2),
179 retractpred(plugin_check_invariant_pred/2),
180 retractpred(plugin_output_pred/2),
181 retractpred(plugin_internal_representation_pred/2).
182
183 retractpred(F/A) :-
184 functor(Fact,F,A), retractall(Fact).
185
186 initialise_plugin(Id) :-
187 plugin(Id,_Module),
188 call(Id:plugin_info(Info)),
189 %print(init_plugin(Id,Info)),nl,
190 initialise_plugin2(Id,Info),
191 !.
192
193 initialise_plugin2(Id,Info) :-
194 %check_options(Info,Id),
195 register_infos(Info,Id,_Used).
196 register_infos([],_Id,[]).
197 register_infos([Info|IRest],Id,Used) :-
198 register_info(Info,Id,U),
199 append(U,RUsed,Used),
200 register_infos(IRest,Id,RUsed).
201 register_info(Info,Id,Used) :-
202 ( Info = (Name=Value) ->
203 ( register_info2(Name,Value,Id) ->
204 Used = [Name]
205 ; otherwise ->
206 ajoin(['Failed analysing plugin info for plugin ', Id,
207 ': ', Name, ' = ', Value], Msg),
208 print_message(error, Msg),
209 Used = [])
210 ; otherwise ->
211 ajoin(['Invalid plugin info for plugin ', Id,
212 ': ', Info], Msg),
213 print_message(error, Msg),
214 Used = []).
215
216 :- public check_options/2.
217 check_options(Info,Id) :-
218 findall(O,mandatory_option(O),Mandatory),
219 check_options2(Mandatory,Info,Id,_).
220 check_options2([],_Info,_Id,true).
221 check_options2([Mandatory1|Mrest],Info,Id,Verdict) :-
222 ( is_list(Mandatory1) -> Mandatory = Mandatory1
223 ; otherwise -> Mandatory = [Mandatory1]),
224 check_option(Mandatory,Info,Id,Verdict),
225 check_options2(Mrest,Info,Id,Verdict).
226
227 check_option(Mandatory,Info,_Id,_Verdict) :-
228 member(M,Mandatory),
229 memberchk( (M=_), Info),!.
230 check_option(Mandatory,_Info,Id,false) :-
231 ( Mandatory = [M] ->
232 Msg = ['Missing plugin info ', M]
233 ; otherwise ->
234 Msg = ['Missing one plugin info of ', Mandatory]),
235 ajoin(['Plugin ',Id,': '|Msg], Msg1),
236 print_message(error,Msg1),
237 fail.
238
239 mandatory_option(name).
240 mandatory_option(load_file).
241 mandatory_option([file_extensions,plugin_for_modes]).
242 mandatory_option(transition).
243 mandatory_option(initialisation).
244
245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246 % handling options
247
248 register_info2(name,Name,Id) :-
249 regassert(Id,name,pname(Name)).
250 register_info2(status,Status,Id) :-
251 ( memberchk(Status,[stable,unstable]) ->
252 regassert(Id,name,status(Status))
253 ; otherwise ->
254 ajoin(['Plugin ',Id,': Invalid status, ignoring'],Msg),
255 print_message(warning,Msg)).
256 register_info2(load_file,Proc,Id) :-
257 reg_proc_assert(Id,load_file,file_loader,Proc,1).
258 register_info2(author,Author,Id) :-
259 regassert(Id,author,author(Author)).
260 register_info2(file_extensions,Ext,Id) :-
261 regassert(Id,file_extensions,file_extensions(Ext)).
262 register_info2(transition_skeleton,Proc,Id) :-
263 reg_proc_assert(Id,transition_skeleton,transition_skeleton,Proc,1).
264 register_info2(transition,Proc,Id) :-
265 reg_proc_assert(Id,transition,transition_pred,Proc,4).
266 register_info2(initialisation,Proc,Id) :-
267 reg_proc_assert(Id,initialisation,initialisation_pred,Proc,3).
268 register_info2(state_property,Proc,Id) :-
269 reg_proc_assert(Id,state_property,state_property_pred,Proc,2).
270 register_info2(parser,Proc,Id) :-
271 reg_proc_assert(Id,parser,parser_pred,Proc,6).
272 register_info2(compute_expression,Proc,Id) :-
273 reg_proc_assert(Id,compute_expression,compute_expression_pred,Proc,3).
274 register_info2(evaluate_predicate,Proc,Id) :-
275 reg_proc_assert(Id,evaluate_predicate,evaluate_predicate_pred,Proc,2).
276 register_info2(evaluate_transition,Proc,Id) :-
277 reg_proc_assert(Id,evaluate_transition,evaluate_transition_pred,Proc,2).
278 register_info2(is_initialised_state,Proc,Id) :-
279 reg_proc_assert(Id,is_initialised_state,is_initialised_state_pred,Proc,1).
280 register_info2(prettyprint_transition,Proc,Id) :-
281 reg_proc_assert(Id,prettyprint_transition,prettyprint_transition_pred,Proc,2).
282 register_info2(prettyprint_property,Proc,Id) :-
283 reg_proc_assert(Id,prettyprint_property,prettyprint_property_pred,Proc,2).
284 register_info2(prettyprint_value,Proc,Id) :-
285 reg_proc_assert(Id,prettyprint_value,prettyprint_value_pred,Proc,2).
286 register_info2(syntax_colouring,Rules,Id) :-
287 check_syntax_colouring(Rules,Id),
288 regassert(Id,syntax_colouring,syntax_colouring(Rules)).
289 register_info2(plugin_for_modes,Modes,Id) :-
290 regassert(Id,syntax_colouring,plugin_for_modes(Modes)).
291 register_info2(plugin_init,Proc,Id) :-
292 reg_proc_assert(Id,plugin_init,plugin_init_pred,Proc,0).
293 register_info2(new_transition_notification,Proc,Id) :-
294 reg_proc_assert(Id,new_transition_notification,plugin_new_transition_pred,Proc,4).
295 register_info2(preferences,Proc,Id) :-
296 reg_proc_assert(Id,preferences,plugin_preferences_pred,Proc,4).
297 register_info2(check_invariant,Proc,Id) :-
298 reg_proc_assert(Id,check_invariant,plugin_check_invariant_pred,Proc,2).
299 register_info2(output,Proc,Id) :-
300 reg_proc_assert(Id,output,plugin_output_pred,Proc,3).
301 register_info2(internal_representation,Proc,Id) :-
302 reg_proc_assert(Id,internal_representation,plugin_internal_representation_pred,Proc,1).
303
304 % helper predicates
305
306 regassert(Id,Name,Fact) :-
307 functor(Fact,F,Arity),
308 NArity is Arity+1,
309 functor(Check,F,NArity), arg(1,Check,Id),
310 ( call(Check) ->
311 ajoin(['Plugin ', Id, ': multiple occurence of info ',
312 Name, ', ignoring'],Msg),
313 print_message(warning,Msg)
314 ; otherwise ->
315 Fact=..[F|Args],
316 NFact=..[F,Id|Args],
317 assert(NFact)).
318
319 reg_proc_assert(Id,Name,Fact,Proc,Arity) :-
320 ( Proc = M:P/Arity -> true
321 ; Proc = P/Arity -> M:P/Arity = Id:Proc
322 ; otherwise ->
323 ajoin(['Predicate in info ',Name,' of plugin ',
324 Id,' is not valid: ',Proc],Msg),
325 print_message(error, Msg),fail),
326 Fact =.. [F|Args], append(Args,[M:P/Arity],AllArgs),
327 NFact =.. [F|AllArgs],
328 regassert(Id,Name,NFact).
329
330 check_syntax_colouring(Rules,Id) :-
331 ( syntax_colouring_error(Rules,Error) ->
332 ajoin(['Error in syntax colouring rules for plugin ',Id,
333 ': ', Error],Msg),
334 print_message(warning,Msg),
335 fail
336 ; otherwise ->
337 true).
338 syntax_colouring_error([],_) :- !,fail.
339 syntax_colouring_error([Rule|_],Error) :-
340 syntax_colouring_error2(Rule,Error),!.
341 syntax_colouring_error([_|Rest],Error) :- !,
342 syntax_colouring_error(Rest,Error).
343 syntax_colouring_error(_,'list expected').
344
345 syntax_colouring_error2(expression(_Regex,Type),Error) :- !,
346 check_syntax_colouring_type(Type,Error).
347 syntax_colouring_error2(pair(_RegexA,_RegexB,Type),Error) :- !,
348 check_syntax_colouring_type(Type,Error).
349 syntax_colouring_error2(_,'expected expression(Regex,Type) or pair(Begin,End,Type)').
350
351 check_syntax_colouring_type(Type,Error) :-
352 Keys = [syntax_comment,syntax_keyword,syntax_type,
353 syntax_assignment, syntax_operator, syntax_logical,
354 syntax_unsupported],
355 ( memberchk(Type,Keys) -> fail
356 ; otherwise ->
357 ajoin(['unexpected colouring type ',Type],Error)).
358
359 % :- initialise_plugins. now done in compiletime_init_plugins
360
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362
363 active_plugin(Id) :-
364 animation_mode(Id),
365 is_registered_plugin(Id).
366
367 is_registered_plugin(Id) :-
368 ? pname(Id,_Name).
369
370 is_registered_plugin(Id,Name) :-
371 pname(Id,Name).
372
373 plugin_is_stable(Id) :-
374 ( status(Id,Status) -> Status==stable
375 ; otherwise -> true).
376
377 plugin_file_extensions(list(Ext)) :-
378 get_preference(user_is_an_expert_with_accessto_source_distribution,Expert),
379 findall( list([Description, list(Suffixes)]),
380 ( file_extensions(Id,Ext),
381 ( Expert==true -> true ; plugin_is_stable(Id) ),
382 member( (Description,Suffixes), Ext)),
383 Ext).
384
385 available_plugins_for_mode(list(Plugins)) :-
386 get_preference(user_is_an_expert_with_accessto_source_distribution,Expert),
387 animation_mode(Mode),
388 findall( list([Pl,Name]),
389 ( plugin_for_modes(Pl,Modes),
390 ( Expert==true -> true ; plugin_is_stable(Pl) ),
391 member(Mode,Modes),
392 pname(Pl,Name)),
393 Plugins).
394
395 plugin_is_available_for_mode :-
396 available_plugins_for_mode(list([_|_])),!.
397
398 plugins_with_preferences(list(Plugins)) :-
399 get_preference(user_is_an_expert_with_accessto_source_distribution,Expert),
400 findall( list([Pl,Name]),
401 ( is_registered_plugin(Pl),
402 ( Expert==true -> true ; plugin_is_stable(Pl) ),
403 plugin_preferences_pred(Pl,_),
404 pname(Pl,Name)),
405 Plugins).
406
407 plugin_has_preferences :-
408 plugins_with_preferences(list([_|_])),!.
409
410 plugin_get_output(list(Outputs),SortOfOutput) :-
411 active_plugin(Id),
412 plugin_output_pred(Id,Module:Pred/3),
413 findall(list([Name,Output]),
414 (call(Module:Pred,Name,Output,Sorts),member(SortOfOutput,Sorts)),
415 Outputs).
416
417 plugin_get_output(Name,Output) :-
418 active_plugin(Id),
419 plugin_output_pred(Id,Module:Pred/3),
420 call(Module:Pred,Name,Output,_).
421
422 plugin_has_output(SortOfOutput) :-
423 plugin_get_output(list([_|_]),SortOfOutput).
424
425 start_plugin_for_current_mode(Id) :-
426 ? animation_mode(Mode),
427 ? is_registered_plugin(Id),
428 ? set_animation_mode(Id),
429 ? set_animation_minor_mode(Mode),
430 ? ( plugin_init_pred(Id,Module:Pred/0) ->
431 ? call(Module:Pred)
432 ; otherwise -> true).
433
434 stop_plugin :-
435 animation_minor_mode(Mode),
436 set_animation_mode(Mode).
437 stop_plugin :-
438 set_animation_mode(b).
439
440 tcl_plugin_syntax_colouring(Id,list(Rules)) :-
441 findall(L, tcl_syntax_colouring2(Id,L), Rules).
442 tcl_syntax_colouring2(Id,TclRule) :-
443 syntax_colouring(Id,Rules),
444 member(PRule,Rules),
445 tcl_syntax_colouring3(PRule,TclRule).
446 tcl_syntax_colouring3(expression(Pattern,Type), list([expression,Pattern,Type])).
447 tcl_syntax_colouring3(pair(Begin,End,Type), list([pair,Begin,End,Type])).
448
449 is_plugin_file_extension(Ext,Id) :-
450 file_extensions(Id,AllExtensions),
451 member( (_,Extensions), AllExtensions),
452 member(Ext,Extensions), !.
453
454 load_plugin_file(Id,Filename) :-
455 user:tcltk_clear_machine,
456 ( plugin_init_pred(Id,Module:Pred/0) ->
457 call(Module:Pred)
458 ; otherwise -> true),
459 file_loader(Id,Module:Pred/1),
460 call(Module:Pred,Filename),!,
461 set_animation_mode(Id).
462
463 setup_transition_skeleton(Id,Skeleton) :-
464 transition_skeleton(Id,Module:Pred/1),!,
465 call(Module:Pred,Skeleton).
466 setup_transition_skeleton(_Id,_Skeleton).
467
468 plugin_transition(Id,Org,Trans,Dst,Infos) :-
469 ? ( Org==root ->
470 initialisation_pred(Id,Module:Pred/3),
471 call(Module:Pred,Trans,Dst,Infos)
472 ? ; otherwise ->
473 ? transition_pred(Id,Module:Pred/4),
474 ? call(Module:Pred,Org,Trans,Dst,Infos)).
475
476 plugin_state_property(Id,State,Property) :-
477 State \== root,
478 ( state_property_pred(Id,Module:Pred/2) ->
479 call(Module:Pred,State,Property)
480 ; otherwise ->
481 Property = State).
482
483 plugin_parse(Id,ExprStrings,PredStrings,TransPredStrings,Exprs,Preds,Trans) :-
484 parser_pred(Id,Module:Pred/6),
485 call(Module:Pred,ExprStrings,PredStrings,TransPredStrings,Exprs,Preds,Trans).
486
487 plugin_compute_expression(Id,Expression,State,Result) :-
488 compute_expression_pred(Id,Module:Pred/3),
489 call(Module:Pred,Expression,State,Result).
490
491 plugin_evaluate_predicate(Id,Predicate,State) :-
492 evaluate_predicate_pred(Id,Module:Pred/3),
493 call(Module:Pred,Predicate,State).
494
495 plugin_evaluate_transition_predicate(Id,Predicate,Transition) :-
496 evaluate_transition_pred(Id,Module:Pred/2),
497 call(Module:Pred,Predicate,Transition).
498
499 plugin_is_initialised_state(Id,State) :-
500 ( is_initialised_state_pred(Id,Module:Pred/1) ->
501 call(Module:Pred,State)
502 ; otherwise -> true).
503
504 plugin_get_internal(Id,InternalRepresentation) :-
505 active_plugin(Id),
506 plugin_internal_representation_pred(Id,Module:Pred/1),
507 call(Module:Pred,InternalRepresentation).
508
509 plugin_prettyprint_transition(Id,Transition,Atom) :-
510 ( prettyprint_transition_pred(Id,Module:Pred/2) ->
511 call(Module:Pred,Transition,Codes)
512 ; otherwise ->
513 write_to_codes(Transition,Codes)),
514 ( atomic(Codes) -> Atom=Codes
515 ; otherwise -> atom_codes(Atom,Codes)).
516
517 plugin_prettyprint_property(Id,Property,Atom) :-
518 ( prettyprint_property_pred(Id,Module:Pred/2) ->
519 call(Module:Pred,Property,Codes)
520 ; otherwise ->
521 write_to_codes(Property,Codes)),
522 ( atomic(Codes) -> Atom=Codes
523 ; otherwise -> atom_codes(Atom,Codes)).
524
525 plugin_prettyprint_value(Id,Property,Codes) :-
526 ( prettyprint_value_pred(Id,Module:Pred/2) ->
527 call(Module:Pred,Property,Codes)
528 ; otherwise ->
529 write_to_codes(Property,Codes)).
530
531 notify_new_transition_to_plugin(FromId,TransId,DstId,Exists) :-
532 animation_mode(Mode),
533 notify_new_transition_to_plugin(Mode,FromId,TransId,DstId,Exists).
534
535 notify_new_transition_to_plugin(ModeId,FromId,TransId,DstId,Exists) :-
536 plugin_new_transition_pred(ModeId,Module:Pred/4),
537 !,
538 ( call(Module:Pred,FromId,TransId,DstId,Exists) ->
539 true
540 ; otherwise ->
541 ajoin(['Notification of new transition failed for plugin ',ModeId,', ',call(Pred,FromId,TransId,DstId,Exists)],Msg),
542 add_error(plugins,Msg)).
543 notify_new_transition_to_plugin(_Id,_FromId,_TransId,_DstId,_Exists).
544
545 plugin_preference_default_value(plugin(Id,Key),Value) :-
546 is_registered_plugin(Id),
547 plugin_preferences_pred(Id,Module:Pred/4),
548 call(Module:Pred,Key,Value,_,_).
549
550 plugin_preference_description(plugin(Id,Key),Description) :-
551 ? is_registered_plugin(Id),
552 ? plugin_preferences_pred(Id,Module:Pred/4),
553 ? call(Module:Pred,Key,_,Description,_).
554
555 plugin_preference_val_type(plugin(Id,Key),Type) :-
556 ? is_registered_plugin(Id),
557 ? plugin_preferences_pred(Id,Module:Pred/4),
558 ? call(Module:Pred,Key,_,_,Type).
559
560 plugin_preference_category(plugin(Id,Key), plugin(Id)) :-
561 ? is_registered_plugin(Id),
562 ? plugin_preferences_pred(Id,Module:Pred/4),
563 ? call(Module:Pred,Key,_,_,_).
564
565 plugin_check_invariantKO(IdPlugin,IdProB,State) :-
566 plugin_check_invariant_pred(IdPlugin,Module:Pred/2),
567 call(Module:Pred,IdProB,State).
568
569