36
37:- module(pldoc_modes,
38 [ process_modes/6, 39 compile_mode/2, 40 mode/2, 41 is_mode/1, 42 mode_indicator/1, 43 modes_to_predicate_indicators/2, 44 compile_clause/2 45 ]). 46:- use_module(library(lists)). 47:- use_module(library(apply)). 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 format(string(S), '~s~w', [Text, End]),
185 setup_call_cleanup(
186 open_string(S, In),
187 read_modes(In, File, Line, Terms),
188 close(In)).
189
190read_modes(In, File, Line, Terms) :-
191 ( atom(File) 192 -> set_stream(In, file_name(File))
193 ; true
194 ),
195 stream_property(In, position(Pos0)),
196 set_line(Pos0, Line, Pos),
197 set_stream_position(In, Pos),
198 read_modes(In, Terms).
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).
404is_det(undefined).
405
406is_head(Var) :-
407 var(Var), !, fail.
408is_head(//(Head)) :-
409 !,
410 is_mhead(Head).
411is_head(M:(//(Head))) :-
412 !,
413 atom(M),
414 is_phead(Head).
415is_head(Head) :-
416 is_mhead(Head).
417
418is_mhead(M:Head) :-
419 !,
420 atom(M),
421 is_phead(Head).
422is_mhead(Head) :-
423 is_phead(Head).
424
425is_phead(Head) :-
426 callable(Head),
427 functor(Head, _Name, Arity),
428 is_head_args(0, Arity, Head).
429
430is_head_args(A, A, _) :- !.
431is_head_args(I0, Arity, Head) :-
432 I is I0 + 1,
433 arg(I, Head, Arg),
434 is_head_arg(Arg),
435 is_head_args(I, Arity, Head).
436
437is_head_arg(Arg) :-
438 var(Arg),
439 !.
440is_head_arg(...(Arg)) :-
441 !,
442 is_head_arg_nva(Arg).
443is_head_arg(Arg) :-
444 is_head_arg_nva(Arg).
445
446is_head_arg_nva(Arg) :-
447 var(Arg),
448 !.
449is_head_arg_nva(Arg) :-
450 Arg =.. [Ind,Arg1],
451 mode_indicator(Ind),
452 is_head_arg(Arg1).
453is_head_arg_nva(Arg:Type) :-
454 var(Arg),
455 is_type(Type).
456
457is_type(Type) :-
458 var(Type),
459 !. 460is_type(Type) :-
461 callable(Type).
467mode_indicator(+). 468mode_indicator(-). 469mode_indicator(++). 470mode_indicator(--). 471mode_indicator(?). 472mode_indicator(:). 473mode_indicator(@). 474mode_indicator(!). 475
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).
483mode_ind(!(X), !, X).
495modes_to_predicate_indicators(Modes, PIs) :-
496 modes_to_predicate_indicators2(Modes, PIs0),
497 list_to_set(PIs0, PIs).
498
499modes_to_predicate_indicators2([], []).
500modes_to_predicate_indicators2([mode(H,_B)|T0], [PI|T]) :-
501 mode_to_pi(H, PI),
502 modes_to_predicate_indicators2(T0, T).
503
504mode_to_pi(Head is _Det, PI) :-
505 !,
506 head_to_pi(Head, PI).
507mode_to_pi(Head, PI) :-
508 head_to_pi(Head, PI).
509
510head_to_pi(M:Head, M:PI) :-
511 atom(M),
512 !,
513 head_to_pi(Head, PI).
514head_to_pi(//(Head), Name//Arity) :-
515 !,
516 functor(Head, Name, Arity).
517head_to_pi(Head, Name/Arity) :-
518 functor(Head, Name, Arity).
532compile_clause(Term, File:Line) :-
533 '$set_source_module'(SM, SM),
534 strip_module(SM:Term, M, Plain),
535 clause_head(Plain, Head),
536 functor(Head, Name, Arity),
537 multifile(M:(Name/Arity)),
538 ( M == SM
539 -> Clause = Term
540 ; Clause = M:Term
541 ),
542 '$store_clause'('$source_location'(File, Line):Clause, File).
543
544clause_head((Head :- _Body), Head) :- !.
545clause_head(Head, Head).
546
547
548 551
552:- multifile
553 prolog:message//1. 554
555prolog:message(pldoc(invalid_mode(Mode))) -->
556 [ '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.