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