36
37:- module(pldoc_process,
38 [ doc_comment/4, 39 doc_file_has_comments/1, 40 is_structured_comment/2, 41 parse_comment/3, 42 comment_modes/2, 43 process_comments/3, 44 doc_file_name/3, 45 doc_clean/1 46 ]). 47
48:- dynamic user:file_search_path/2. 49:- multifile user:file_search_path/2. 50
51user:file_search_path(pldoc, library(pldoc)).
52
53:- use_module(pldoc(doc_register)). 54:- use_module(pldoc(doc_modes)). 55:- use_module(pldoc(doc_wiki)). 56:- use_module(library(debug)). 57:- use_module(library(option)). 58:- use_module(library(lists)). 59:- use_module(library(apply)). 60:- use_module(library(operators)). 61:- use_module(library(prolog_source)). 62
63
71
72:- predicate_options(doc_file_name/3, 3,
73 [ format(oneof([html,tex]))
74 ]). 75
80
81:- multifile
82 prolog:predicate_summary/2. 83
84
90
(Comment, Prefixes) :-
92 is_structured_comment(Comment, Prefixes, _Style).
93
(_Pos-Comment, Prefixes, Style) :-
95 !,
96 is_structured_comment(Comment, Prefixes, Style).
97is_structured_comment(Comment, Prefixes, Style) :-
98 is_list(Comment),
99 !,
100 ( phrase(structured_comment(Prefixes, Style), Comment, _)
101 -> true
102 ).
103is_structured_comment(Comment, Prefixes, Style) :-
104 atom_string(CommentA, Comment),
105 structured_command_start(Start, Prefixes, Style),
106 sub_atom(CommentA, 0, Len, _, Start),
107 !,
108 sub_atom(CommentA, Len, 1, _, Space),
109 char_type(Space, space),
110 ( Style == block
111 -> true
112 ; \+ blanks_to_nl(CommentA)
113 ).
114
115structured_command_start('%%', ["%"], percent_percent). 116structured_command_start('%!', ["%"], percent_bang). 117structured_command_start('/**', ["/**", " *"], block). 118
119blanks_to_nl(CommentA) :-
120 sub_atom(CommentA, At, 1, _, Char),
121 At >= 2,
122 ( char_type(Char, end_of_line)
123 -> !
124 ; ( char_type(Char, space)
125 ; Char == '%'
126 )
127 -> fail
128 ; !, fail
129 ).
130blanks_to_nl(_).
131
136
(["%"], percent_percent) -->
138 "%%", space,
139 \+ separator_line.
140structured_comment(["%"], percent_bang) -->
141 "%!", space.
142structured_comment(Prefixes, block) -->
143 "/**", space,
144 { Prefixes = ["/**", " *"]
145 }.
146
147space -->
148 [H],
149 { code_type(H, space) }.
150
154
155separator_line -->
156 string(S), "\n",
157 !,
158 { maplist(blank_or_percent, S)
159 ; contains(S, " SWI ")
160 ; contains(S, " SICStus ")
161 ; contains(S, " Mats ")
162 }.
163
164string([]) --> [].
165string([H|T]) --> [H], string(T).
166
167blank_or_percent(0'%) :- !.
168blank_or_percent(C) :-
169 code_type(C, space).
170
171contains(Haystack, Needle) :-
172 string_codes(Needle, NeedleCodes),
173 append(_, Start, Haystack),
174 append(NeedleCodes, _, Start),
175 !.
176
177
190
191doc_file_name(Source, Doc, Options) :-
192 option(format(Format), Options, html),
193 file_name_extension(Base, _Ext, Source),
194 file_name_extension(Base, Format, Doc),
195 ( Source == Doc
196 -> throw(error(permission_error(overwrite, Source), _))
197 ; true
198 ).
199
203
(Source) :-
205 source_file_property(Source, module(M)),
206 locally_defined(M:'$pldoc'/4),
207 M:'$pldoc'(_, _, _, _),
208 !.
209
210
233
(Object, Pos, Summary, Comment) :-
235 var(Object),
236 !,
237 locally_defined(M:'$pldoc'/4),
238 M:'$pldoc'(Obj, Pos, Summary, Comment),
239 qualify(M, Obj, Object0),
240 ( locally_defined(M:'$pldoc_link'/2),
241 findall(L, M:'$pldoc_link'(L, Obj), Ls), Ls \== []
242 -> maplist(qualify(M), Ls, QLs),
243 Object = [Object0|QLs]
244 ; Object = Object0
245 ).
246doc_comment(M:Object, Pos, Summary, Comment) :-
247 !,
248 locally_defined(M:'$pldoc'/4),
249 ( M:'$pldoc'(Object, Pos, Summary, Comment)
250 ; locally_defined(M:'$pldoc_link'/2),
251 M:'$pldoc_link'(Object, Obj2),
252 M:'$pldoc'(Obj2, Pos, Summary, Comment)
253 ).
254doc_comment(Name/Arity, Pos, Summary, Comment) :-
255 system_module(M),
256 doc_comment(M:Name/Arity, Pos, Summary, Comment).
257
258
259locally_defined(M:Name/Arity) :-
260 current_predicate(M:Name/Arity),
261 functor(Head, Name, Arity),
263 \+ '$get_predicate_attribute'(M:Head, imported, _).
264
265
266qualify(M, H, H) :- system_module(M), !.
267qualify(M, H, H) :- sub_atom(M, 0, _, _, $), !.
268qualify(M, H, M:H).
269
270system_module(user).
271system_module(system).
272
273
275
276prolog:predicate_summary(PI, Summary) :-
277 doc_comment(PI, _, Summary, _).
278
279
280 283
305
([], _, _).
307process_comments([Pos-Comment|T], TermPos, File) :-
308 ( Pos @> TermPos 309 -> true
310 ; process_comment(Pos, Comment, File),
311 process_comments(T, TermPos, File)
312 ).
313
(Pos, Comment, File) :-
315 is_structured_comment(Comment, Prefixes, Style),
316 !,
317 stream_position_data(line_count, Pos, Line),
318 FilePos = File:Line,
319 process_structured_comment(FilePos, Comment, Prefixes, Style).
320process_comment(_, _, _).
321
338
(Comment, FilePos, Parsed) :-
340 is_structured_comment(Comment, Prefixes),
341 !,
342 compile_comment(Comment, FilePos, Prefixes, Parsed).
343
344
346
(Comment, Modes) :-
348 is_structured_comment(Comment, Prefixes),
349 string_codes(Comment, CommentCodes),
350 indented_lines(CommentCodes, Prefixes, Lines),
351 ( prolog_load_context(module, Module)
352 -> true
353 ; Module = user
354 ),
355 process_modes(Lines, Module, dummy:0, Modes0, _Vars, _),
356 maplist(bind_mode, Modes0, Modes).
357
358bind_mode(mode(Mode, Bindings), Mode) :-
359 maplist(bind_var, Bindings).
360
361bind_var(Name=Name).
362
376
(FilePos, Comment, _, _) :- 378 prolog_load_context(module, M),
379 locally_defined(M:'$pldoc'/4),
380 catch(M:'$pldoc'(_, FilePos, _, Comment), _, fail),
381 ( FilePos = File:_,
382 source_file_property(File, reloading)
383 -> debug(pldoc(reload), 'Reloading ~q', [FilePos]),
384 fail
385 ; true
386 ),
387 !.
388process_structured_comment(FilePos, Comment, Prefixes, Style) :-
389 catch(compile_comment(Comment, FilePos, Prefixes, Compiled), E,
390 comment_warning(Style, E)),
391 maplist(store_comment(FilePos), Compiled).
392process_structured_comment(FilePos, Comment, _Prefixes, Style) :-
393 comment_style_warning_level(Style, Level),
394 print_message(Level,
395 pldoc(invalid_comment(FilePos, Comment))).
396
(percent_percent, silent) :- !.
398comment_style_warning_level(_, warning).
399
405
(Style, E) :-
407 comment_style_warning_level(Style, Level),
408 print_message(Level, E),
409 fail.
410
417
(Comment, FilePos, Prefixes, Compiled) :-
419 string_codes(Comment, CommentCodes),
420 indented_lines(CommentCodes, Prefixes, Lines),
421 ( section_comment_header(Lines, Header, _RestLines)
422 -> Header = \section(Type, Title),
423 Id =.. [Type,Title],
424 Compiled = [section(Id, Title, Comment)]
425 ; prolog_load_context(module, Module),
426 process_modes(Lines, Module, FilePos, Modes, _, RestLines)
427 -> maplist(compile_mode, Modes, ModeDecls),
428 modes_to_predicate_indicators(Modes, AllPIs),
429 decl_module(AllPIs, M, [PI0|PIs]),
430 maplist(link_term(M:PI0), PIs, Links),
431 summary_from_lines(RestLines, Codes),
432 string_codes(Summary, Codes),
433 append([ ModeDecls,
434 [ predicate(M:PI0, Summary, Comment) ],
435 Links
436 ], Compiled)
437 ),
438 !.
439
440
(Pos, section(Id, Title, Comment)) :-
442 !,
443 compile_clause('$pldoc'(Id, Pos, Title, Comment), Pos).
444store_comment(Pos, predicate(M:PI, Summary, Comment)) :-
445 !,
446 compile_clause(M:'$pldoc'(PI, Pos, Summary, Comment), Pos).
447store_comment(Pos, link(PI, M:PI0)) :-
448 !,
449 compile_clause(M:'$pldoc_link'(PI, PI0), Pos).
450store_comment(Pos, mode(Head, Det)) :-
451 !,
452 compile_clause('$mode'(Head, Det), Pos).
453store_comment(_, Term) :-
454 type_error(pldoc_term, Term).
455
456link_term(To, From, link(From,To)).
457
458decl_module([], M, []) :-
459 ( var(M)
460 -> prolog_load_context(module, M)
461 ; true
462 ).
463decl_module([H0|T0], M, [H|T]) :-
464 ( H0 = M1:H
465 -> M = M1
466 ; H = H0
467 ),
468 decl_module(T0, M, T).
469
473
474doc_clean(Module) :-
475 abolish(Module:'$mode'/2),
476 abolish(Module:'$pldoc'/4),
477 abolish(Module:'$pldoc_link'/2).
478
479
480 483
484:- multifile
485 prolog:message//1. 486
487prolog:message(pldoc(invalid_comment(File:Line, Comment))) -->
488 [ url(File:Line), ': PlDoc: failed to process structured comment:~n~s~n'-
489 [Comment]
490 ]