35
36:- module(pldoc_modes,
37 [ process_modes/6, 38 compile_mode/2, 39 mode/2, 40 is_mode/1, 41 mode_indicator/1, 42 modes_to_predicate_indicators/2, 43 compile_clause/2 44 ]). 45:- use_module(library(lists)). 46:- use_module(library(apply)). 47:- use_module(library(memfile)). 48:- use_module(library(operators)). 49:- use_module(library(error)).
61:- op(750, xf, ...). 62:- op(650, fx, +). 63:- op(650, fx, -). 64:- op(650, fx, ++). 65:- op(650, fx, --). 66:- op(650, fx, ?). 67:- op(650, fx, :). 68:- op(650, fx, @). 69:- op(650, fx, !). 70:- op(200, xf, //). 71
72
88process_modes(Lines, Module, FilePos, ModeDecls, Vars, RestLines) :-
89 mode_lines(Lines, ModeText, [], RestLines),
90 modes(ModeText, Module, FilePos, ModeDecls),
91 extract_varnames(ModeDecls, Vars0, []),
92 sort(Vars0, Vars).
107mode_lines(Lines0, ModeText, ModeTail, Lines) :-
108 percent_mode_line(Lines0, C, ModeText, ModeTail0, Lines1),
109 !,
110 percent_mode_lines(Lines1, C, ModeTail0, ModeTail, Lines).
111mode_lines(Lines0, ModeText, ModeTail, Lines) :-
112 empty_lines(Lines0, Lines1),
113 non_empty_lines(Lines1, ModeText, ModeTail, Lines).
114
115percent_mode_line([1-[C|L]|Lines], C, ModeText, ModeTail, Lines) :-
116 percent_mode_char(C),
117 append(L, [10|ModeTail], ModeText).
118
119percent_mode_char(0'%).
120percent_mode_char(0'!).
121
122percent_mode_lines(Lines0, C, ModeText, ModeTail, Lines) :-
123 percent_mode_line(Lines0, C, ModeText, ModeTail1, Lines1),
124 !,
125 percent_mode_lines(Lines1, C, ModeTail1, ModeTail, Lines).
126percent_mode_lines(Lines, _, Mode, Mode, Lines).
127
128empty_lines([_-[]|Lines0], Lines) :-
129 !,
130 empty_lines(Lines0, Lines).
131empty_lines(Lines, Lines).
132
133non_empty_lines([], ModeTail, ModeTail, []).
134non_empty_lines([_-[]|Lines], ModeTail, ModeTail, Lines) :- !.
135non_empty_lines([_-L|Lines0], ModeText, ModeTail, Lines) :-
136 append(L, [10|ModeTail0], ModeText),
137 non_empty_lines(Lines0, ModeTail0, ModeTail, Lines).
149modes(Text, Module, FilePos, Decls) :-
150 prepare_module_operators(Module),
151 modes(Text, FilePos, Decls).
152
153modes(Text, FilePos, Decls) :-
154 catch(read_mode_terms(Text, FilePos, '', Decls), E, true),
155 ( var(E)
156 -> !
157 ; E = error(syntax_error(end_of_file), _)
158 -> fail
159 ; !, mode_syntax_error(E),
160 Decls = []
161 ).
162modes(Text, FilePos, Decls) :-
163 catch(read_mode_terms(Text, FilePos, ' . ', Decls), E, true),
164 ( var(E)
165 -> !
166 ; mode_syntax_error(E),
167 fail
168 ).
169modes(_, _, []).
176mode_syntax_error(E) :-
177 current_prolog_flag(pldoc_errors, true),
178 !,
179 print_message(warning, E).
180mode_syntax_error(_).
181
182
183read_mode_terms(Text, File:Line, End, Terms) :-
184 new_memory_file(MemFile),
185 open_memory_file(MemFile, write, Out),
186 format(Out, '~s~w', [Text, End]),
187 close(Out),
188 open_memory_file(MemFile, read, In),
189 ( atom(File) 190 -> set_stream(In, file_name(File))
191 ; true
192 ),
193 stream_property(In, position(Pos0)),
194 set_line(Pos0, Line, Pos),
195 set_stream_position(In, Pos),
196 call_cleanup(read_modes(In, Terms),
197 ( close(In),
198 free_memory_file(MemFile))).
199
200set_line('$stream_position'(CharC, _, LinePos, ByteC),
201 Line,
202 '$stream_position'(CharC, Line, LinePos, ByteC)).
203
204read_modes(In, Terms) :-
205 read_mode_term(In, Term0),
206 read_modes(Term0, In, Terms).
207
208read_modes(mode(end_of_file,[]), _, []) :- !.
209read_modes(T0, In, [T0|Rest]) :-
210 T0 = mode(Mode, _),
211 is_mode(Mode),
212 !,
213 read_mode_term(In, T1),
214 read_modes(T1, In, Rest).
215read_modes(mode(Mode, Bindings), In, Modes) :-
216 maplist(call, Bindings),
217 print_message(warning, pldoc(invalid_mode(Mode))),
218 read_mode_term(In, T1),
219 read_modes(T1, In, Modes).
220
221read_mode_term(In, mode(Term, Bindings)) :-
222 read_term(In, Term,
223 [ variable_names(Bindings),
224 module(pldoc_modes)
225 ]).
232:- dynamic
233 prepared_module/2. 234
235prepare_module_operators(Module) :-
236 ( prepared_module(Module, _)
237 -> true
238 ; unprepare_module_operators,
239 public_operators(Module, Ops),
240 ( Ops \== []
241 -> push_operators(Ops, Undo),
242 asserta(prepared_module(Module, Undo))
243 ; true
244 )
245 ).
246
247unprepare_module_operators :-
248 forall(retract(prepared_module(_, Undo)),
249 pop_operators(Undo)).
257public_operators(Module, List) :-
258 module_property(Module, exported_operators(List)),
259 !.
260public_operators(_, []).
271extract_varnames([], VN, VN) :- !.
272extract_varnames([H|T], VN0, VN) :-
273 !,
274 extract_varnames(H, VN0, VN1),
275 extract_varnames(T, VN1, VN).
276extract_varnames(mode(_, Bindings), VN0, VN) :-
277 !,
278 extract_varnames(Bindings, VN0, VN).
279extract_varnames(Name=_, [Name|VN], VN).
288compile_mode(mode(Mode, _Bindings), Compiled) :-
289 compile_mode2(Mode, Compiled).
290
291compile_mode2(Var, _) :-
292 var(Var),
293 !,
294 throw(error(instantiation_error,
295 context(_, 'PlDoc: Mode declaration expected'))).
296compile_mode2(Head0 is Det, mode(Head, Det)) :-
297 !,
298 dcg_expand(Head0, Head).
299compile_mode2(Head0, mode(Head, unknown)) :-
300 dcg_expand(Head0, Head).
301
302dcg_expand(M:Head0, M:Head) :-
303 atom(M),
304 !,
305 dcg_expand(Head0, Head).
306dcg_expand(//(Head0), Head) :-
307 !,
308 Head0 =.. [Name|List0],
309 maplist(remove_argname, List0, List1),
310 append(List1, [?list, ?list], List2),
311 Head =.. [Name|List2].
312dcg_expand(Head0, Head) :-
313 remove_argnames(Head0, Head).
314
315remove_argnames(Var, _) :-
316 var(Var),
317 !,
318 instantiation_error(Var).
319remove_argnames(M:Head0, M:Head) :-
320 !,
321 must_be(atom, M),
322 remove_argnames(Head0, Head).
323remove_argnames(Head0, Head) :-
324 functor(Head0, Name, Arity),
325 functor(Head, Name, Arity),
326 remove_argnames(0, Arity, Head0, Head).
327
328remove_argnames(Arity, Arity, _, _) :- !.
329remove_argnames(I0, Arity, H0, H) :-
330 I is I0 + 1,
331 arg(I, H0, A0),
332 remove_argname(A0, A),
333 arg(I, H, A),
334 remove_argnames(I, Arity, H0, H).
335
336remove_argname(T, ?(any)) :-
337 var(T),
338 !.
339remove_argname(...(T0), ...(T)) :-
340 !,
341 remove_argname(T0, T).
342remove_argname(A0, A) :-
343 mode_ind(A0, M, A1),
344 !,
345 remove_aname(A1, A2),
346 mode_ind(A, M, A2).
347remove_argname(A0, ?A) :-
348 remove_aname(A0, A).
349
350remove_aname(Var, any) :-
351 var(Var),
352 !.
353remove_aname(_:Type, Type) :- !.
364:- module_transparent
365 mode/2. 366
367mode(Head, Det) :-
368 var(Head),
369 !,
370 current_module(M),
371 '$c_current_predicate'(_, M:'$mode'(_,_)),
372 M:'$mode'(H,Det),
373 qualify(M,H,Head).
374mode(M:Head, Det) :-
375 current_module(M),
376 '$c_current_predicate'(_, M:'$mode'(_,_)),
377 M:'$mode'(Head,Det).
378
379qualify(system, H, H) :- !.
380qualify(user, H, H) :- !.
381qualify(M, H, M:H).
388is_mode(Var) :-
389 var(Var), !, fail.
390is_mode(Head is Det) :-
391 !,
392 is_det(Det),
393 is_head(Head).
394is_mode(Head) :-
395 is_head(Head).
396
397is_det(Var) :-
398 var(Var), !, fail.
399is_det(failure).
400is_det(det).
401is_det(semidet).
402is_det(nondet).
403is_det(multi).
404
405is_head(Var) :-
406 var(Var), !, fail.
407is_head(//(Head)) :-
408 !,
409 is_mhead(Head).
410is_head(M:(//(Head))) :-
411 !,
412 atom(M),
413 is_phead(Head).
414is_head(Head) :-
415 is_mhead(Head).
416
417is_mhead(M:Head) :-
418 !,
419 atom(M),
420 is_phead(Head).
421is_mhead(Head) :-
422 is_phead(Head).
423
424is_phead(Head) :-
425 callable(Head),
426 functor(Head, _Name, Arity),
427 is_head_args(0, Arity, Head).
428
429is_head_args(A, A, _) :- !.
430is_head_args(I0, Arity, Head) :-
431 I is I0 + 1,
432 arg(I, Head, Arg),
433 is_head_arg(Arg),
434 is_head_args(I, Arity, Head).
435
436is_head_arg(Arg) :-
437 var(Arg),
438 !.
439is_head_arg(...(Arg)) :-
440 !,
441 is_head_arg_nva(Arg).
442is_head_arg(Arg) :-
443 is_head_arg_nva(Arg).
444
445is_head_arg_nva(Arg) :-
446 var(Arg),
447 !.
448is_head_arg_nva(Arg) :-
449 Arg =.. [Ind,Arg1],
450 mode_indicator(Ind),
451 is_head_arg(Arg1).
452is_head_arg_nva(Arg:Type) :-
453 var(Arg),
454 is_type(Type).
455
456is_type(Type) :-
457 var(Type),
458 !. 459is_type(Type) :-
460 callable(Type).
466mode_indicator(+). 467mode_indicator(-). 468mode_indicator(++). 469mode_indicator(--). 470mode_indicator(?). 471mode_indicator(:). 472mode_indicator(@). 473mode_indicator(!). 474
475mode_ind(+(X), +, X).
476mode_ind(-(X), -, X).
477mode_ind(++(X), ++, X).
478mode_ind(--(X), --, X).
479mode_ind(?(X), ?, X).
480mode_ind(:(X), :, X).
481mode_ind(@(X), @, X).
482mode_ind(!(X), !, X).
494modes_to_predicate_indicators(Modes, PIs) :-
495 modes_to_predicate_indicators2(Modes, PIs0),
496 list_to_set(PIs0, PIs).
497
498modes_to_predicate_indicators2([], []).
499modes_to_predicate_indicators2([mode(H,_B)|T0], [PI|T]) :-
500 mode_to_pi(H, PI),
501 modes_to_predicate_indicators2(T0, T).
502
503mode_to_pi(Head is _Det, PI) :-
504 !,
505 head_to_pi(Head, PI).
506mode_to_pi(Head, PI) :-
507 head_to_pi(Head, PI).
508
509head_to_pi(M:Head, M:PI) :-
510 atom(M),
511 !,
512 head_to_pi(Head, PI).
513head_to_pi(//(Head), Name//Arity) :-
514 !,
515 functor(Head, Name, Arity).
516head_to_pi(Head, Name/Arity) :-
517 functor(Head, Name, Arity).
531compile_clause(Term, File:Line) :-
532 '$set_source_module'(SM, SM),
533 strip_module(SM:Term, M, Plain),
534 clause_head(Plain, Head),
535 functor(Head, Name, Arity),
536 multifile(M:(Name/Arity)),
537 ( M == SM
538 -> Clause = Term
539 ; Clause = M:Term
540 ),
541 '$store_clause'('$source_location'(File, Line):Clause, File).
542
543clause_head((Head :- _Body), Head) :- !.
544clause_head(Head, Head).
545
546
547 550
551:- multifile
552 prolog:message//1. 553
554prolog:message(pldoc(invalid_mode(Mode))) -->
555 [ 'Invalid mode declaration in PlDoc comment: ~q'-[Mode] ]
Analyse PlDoc mode declarations
This module analyzes the formal part of the documentation of a predicate. The formal part is processed by read_term/3 using the operator declarations in this module.