35
36:- module(pldoc_process,
37 [ doc_comment/4, 38 doc_file_has_comments/1, 39 is_structured_comment/2, 40 parse_comment/3, 41 process_comments/3, 42 doc_file_name/3 43 ]).
44
45:- dynamic user:file_search_path/2.
46:- multifile user:file_search_path/2.
47
48user:file_search_path(pldoc, library(pldoc)).
49
50:- load_files([ pldoc(doc_register),
51 pldoc(doc_modes),
52 pldoc(doc_wiki),
53 library(debug),
54 library(option),
55 library(lists),
56 library(apply),
57 library(operators),
58 library(prolog_source)
59 ],
60 [ silent(true),
61 if(not_loaded)
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
232
(Object, Pos, Summary, Comment) :-
234 var(Object),
235 !,
236 locally_defined(M:'$pldoc'/4),
237 M:'$pldoc'(Obj, Pos, Summary, Comment),
238 qualify(M, Obj, Object0),
239 ( locally_defined(M:'$pldoc_link'/2),
240 findall(L, M:'$pldoc_link'(L, Obj), Ls), Ls \== []
241 -> maplist(qualify(M), Ls, QLs),
242 Object = [Object0|QLs]
243 ; Object = Object0
244 ).
245doc_comment(M:Object, Pos, Summary, Comment) :-
246 !,
247 locally_defined(M:'$pldoc'/4),
248 ( M:'$pldoc'(Object, Pos, Summary, Comment)
249 ; locally_defined(M:'$pldoc_link'/2),
250 M:'$pldoc_link'(Object, Obj2),
251 M:'$pldoc'(Obj2, Pos, Summary, Comment)
252 ).
253doc_comment(Name/Arity, Pos, Summary, Comment) :-
254 system_module(M),
255 doc_comment(M:Name/Arity, Pos, Summary, Comment).
256
257
258locally_defined(M:Name/Arity) :-
259 current_module(M),
260 current_predicate(M:Name/Arity),
261 functor(Head, Name, Arity),
262 \+ predicate_property(M:Head, imported_from(_)).
263
264
265qualify(M, H, H) :- system_module(M), !.
266qualify(M, H, H) :- sub_atom(M, 0, _, _, $), !.
267qualify(M, H, M:H).
268
269system_module(user).
270system_module(system).
271
272
274
275prolog:predicate_summary(PI, Summary) :-
276 doc_comment(PI, _, Summary, _).
277
278
279 282
304
([], _, _).
306process_comments([Pos-Comment|T], TermPos, File) :-
307 ( Pos @> TermPos 308 -> true
309 ; process_comment(Pos, Comment, File),
310 process_comments(T, TermPos, File)
311 ).
312
(Pos, Comment, File) :-
314 is_structured_comment(Comment, Prefixes, Style),
315 !,
316 stream_position_data(line_count, Pos, Line),
317 FilePos = File:Line,
318 process_structured_comment(FilePos, Comment, Prefixes, Style).
319process_comment(_, _, _).
320
337
(Comment, FilePos, Parsed) :-
339 is_structured_comment(Comment, Prefixes),
340 !,
341 compile_comment(Comment, FilePos, Prefixes, Parsed).
342
343
357
(FilePos, Comment, _, _) :- 359 prolog_load_context(module, M),
360 locally_defined(M:'$pldoc'/4),
361 catch(M:'$pldoc'(_, FilePos, _, Comment), _, fail),
362 ( FilePos = File:_,
363 source_file_property(File, reloading)
364 -> debug(pldoc(reload), 'Reloading ~q', [FilePos]),
365 fail
366 ; true
367 ),
368 !.
369process_structured_comment(FilePos, Comment, Prefixes, Style) :-
370 catch(compile_comment(Comment, FilePos, Prefixes, Compiled), E,
371 comment_warning(Style, E)),
372 maplist(store_comment(FilePos), Compiled).
373process_structured_comment(FilePos, Comment, _Prefixes, Style) :-
374 comment_style_warning_level(Style, Level),
375 print_message(Level,
376 pldoc(invalid_comment(FilePos, Comment))).
377
(percent_percent, silent) :- !.
379comment_style_warning_level(_, warning).
380
386
(Style, E) :-
388 comment_style_warning_level(Style, Level),
389 print_message(Level, E),
390 fail.
391
398
(Comment, FilePos, Prefixes, Compiled) :-
400 string_codes(Comment, CommentCodes),
401 indented_lines(CommentCodes, Prefixes, Lines),
402 ( section_comment_header(Lines, Header, _RestLines)
403 -> Header = \section(Type, Title),
404 Id =.. [Type,Title],
405 Compiled = [section(Id, Title, Comment)]
406 ; prolog_load_context(module, Module),
407 process_modes(Lines, Module, FilePos, Modes, _, RestLines)
408 -> maplist(compile_mode, Modes, ModeDecls),
409 modes_to_predicate_indicators(Modes, AllPIs),
410 decl_module(AllPIs, M, [PI0|PIs]),
411 maplist(link_term(M:PI0), PIs, Links),
412 summary_from_lines(RestLines, Codes),
413 string_codes(Summary, Codes),
414 append([ ModeDecls,
415 [ predicate(M:PI0, Summary, Comment) ],
416 Links
417 ], Compiled)
418 ),
419 !.
420
421
(Pos, section(Id, Title, Comment)) :-
423 !,
424 compile_clause('$pldoc'(Id, Pos, Title, Comment), Pos).
425store_comment(Pos, predicate(M:PI, Summary, Comment)) :-
426 !,
427 compile_clause(M:'$pldoc'(PI, Pos, Summary, Comment), Pos).
428store_comment(Pos, link(PI, M:PI0)) :-
429 !,
430 compile_clause(M:'$pldoc_link'(PI, PI0), Pos).
431store_comment(Pos, mode(Head, Det)) :-
432 !,
433 compile_clause('$mode'(Head, Det), Pos).
434store_comment(_, Term) :-
435 type_error(pldoc_term, Term).
436
437link_term(To, From, link(From,To)).
438
439decl_module([], M, []) :-
440 ( var(M)
441 -> prolog_load_context(module, M)
442 ; true
443 ).
444decl_module([H0|T0], M, [H|T]) :-
445 ( H0 = M1:H
446 -> M = M1
447 ; H = H0
448 ),
449 decl_module(T0, M, T).
450
451
452 455
456:- multifile
457 prolog:message//1.
458
459prolog:message(pldoc(invalid_comment(File:Line, Comment))) -->
460 [ '~w:~d: PlDoc: failed to process structured comment:~n~s~n'-
461 [File, Line, Comment]
462 ].