parser: rename all P* prod classes to A*
[nit.git] / src / nitdoc.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # The main module of the nitdoc program
18 package nitdoc
19
20 import syntax
21 private import utils
22 import abstracttool
23
24
25 # Store knowledge and facilities to generate files
26 class DocContext
27 special AbstractCompiler
28 # Destination directory
29 readable writable var _dir: String = "."
30
31 # Content of a generated file
32 var _stage_context: StageContext = new StageContext(null)
33
34 # Add a string in the content
35 fun add(s: String) do
36 _stage_context.content.add(s)
37 _stage_context.validate = true
38 end
39
40 # Add a string in the content iff some other string are added
41 fun stage(s: String) do _stage_context.content.add(s)
42
43 # Create a new stage in the content
44 fun open_stage do _stage_context = new StageContext(_stage_context)
45
46 # Close the current stage in the content
47 fun close_stage
48 do
49 var s = _stage_context.parent
50 if _stage_context.validate then
51 s.content.add_all(_stage_context.content)
52 s.validate = true
53 end
54 assert s != null
55 _stage_context = s
56 end
57
58 # Write the content to a new file
59 fun write_to(filename: String)
60 do
61 var f = new OFStream.open(filename)
62 for s in _stage_context.content do
63 f.write(s)
64 end
65 f.close
66 end
67
68 # Currently computed module
69 readable var _module: nullable MMSrcModule
70
71 # Is the current directory module computed as a simple modude ?
72 readable writable var _inside_mode: Bool = false
73
74 # Is the current module computed as a intruded one ?
75 readable writable var _intrude_mode: Bool = false
76
77 # Compued introducing entities (for the index)
78 var _entities: Array[MMEntity] = new Array[MMEntity]
79
80 # Register an entity (for the index)
81 fun register(e: MMEntity)
82 do
83 _entities.add(e)
84 if e isa MMSrcModule then
85 _module = e
86 end
87 end
88
89 # Start a new file
90 fun clear
91 do
92 _stage_context = new StageContext(null)
93 end
94
95 # Generate common files (frames, index, overview)
96 fun extract_other_doc
97 do
98 info("Generating other files",1)
99 _module = null
100 inside_mode = false
101 intrude_mode = false
102 clear
103 add("<html><body>\n")
104 add("<a href=\"overview.html\" target=\"mainFrame\">Overview</a><br/>\n")
105 add("<a href=\"index-1.html\" target=\"mainFrame\">Index</a><br/>\n")
106 var modules = modules.to_a
107 sort(modules)
108
109 var rootdirs = new Array[MMDirectory]
110 for m in modules do
111 var md = m.directory
112 if md.parent == null and not rootdirs.has(md) then
113 rootdirs.add(md)
114 end
115 end
116
117 var done = new Array[MMModule]
118 for root in rootdirs do
119 var dirstack = [root]
120 var curdir = root
121 add("{root.name}<br/>\n")
122 var indent = "&nbsp; "
123 while not dirstack.is_empty do
124 var redo = false
125 for m in modules do
126 if done.has(m) then continue
127 var md = m.directory
128 if md.owner == m and md.parent == curdir then
129 # It's a directory module
130 add("{indent}<a href=\"{m}.html\" target=\"mainFrame\">{m}</a><br/>\n")
131 curdir = md
132 dirstack.push(curdir)
133 indent = "&nbsp " * dirstack.length
134 redo = true
135 break # restart to preserve alphabetic order
136 else if md == curdir then
137 if md.owner == m then
138 add("{indent}<a href=\"{m}_.html\" target=\"mainFrame\">{m}</a><br/>\n")
139 else
140 add("{indent}<a href=\"{m}.html\" target=\"mainFrame\">{m}</a><br/>\n")
141 end
142 done.add(m)
143 redo = true
144 end
145 end
146 if not redo then
147 dirstack.pop
148 if not dirstack.is_empty then
149 curdir = dirstack[dirstack.length-1]
150 indent = "&nbsp " * dirstack.length
151 end
152 end
153 end
154 end
155 add("</body></html>\n")
156 write_to("{dir}/menu-frame.html")
157
158 clear
159 add_header("Index")
160 add("<dl>\n")
161 sort(_entities)
162 for e in _entities do
163 add("<dt><b>{e.html_link(self)}</b> - {e.prototype_head(self)} <b>{e}</b>{e.prototype_body(self)} {e.locate(self)}<dd>{e.short_doc}\n")
164 end
165 add("</dl></body></html>\n")
166 write_to("{dir}/index-1.html")
167
168 clear
169 add_header("Overview")
170 add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
171 add("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\"><big>Overview of all Modules</big></th><tr>\n")
172 for m in modules do
173 add("<tr><td width=\"20%\" align=\"right\">{m.html_link(self)}</td><td>{m.short_doc}</td><tr>\n")
174 end
175 add("</table></body></html>\n")
176 write_to("{dir}/overview.html")
177
178 clear
179 add("<html>\n<frameset cols=\"20%,80%\">\n<frame src=\"menu-frame.html\" name=\"menuFrame\" title=\"Menu\">\n<frame src=\"overview.html\" name=\"mainFrame\" title=\"Main\" scrolling=\"yes\">\n</frameset></html>\n")
180 write_to("{dir}/index.html")
181 end
182
183 fun add_header(title: String)
184 do
185 add("<html><head><title>{title}</title></head>\n<body>\n")
186 add("<table border=\"0\" width=\"100%\" cellpadding=\"1\" cellspacing=\"0\"><tr><td bgcolor=\"#eeeeff\">\n")
187 add("<a href=\"overview.html\"><b>Overview</b></a>&nbsp; <a href=\"index-1.html\"><b>Index</b></a>&nbsp; <a href=\"index.html\" target=\"_top\"><b>With Frames</b></a>\n")
188 add("</td></tr></table>")
189 add("Visibility: ")
190 if (not inside_mode and not intrude_mode) or module == null then
191 add("<b>Public</b>&nbsp; ")
192 else
193 add("<a href=\"{module}.html\"><b>Public</b></a>&nbsp; ")
194 end
195 if inside_mode or module == null then
196 add("<b>Inside</b>&nbsp; ")
197 else if module.directory.owner != module then
198 add("<strike><b>Inside</b></strike>&nbsp; ")
199 else
200 add("<a href=\"{module}_.html\"><b>Inside</b></a>&nbsp; ")
201 end
202 if intrude_mode or module == null then
203 add("<b>Intrude</b>&nbsp; ")
204 else
205 add("<a href=\"{module}__.html\"><b>Intrude</b></a>&nbsp; ")
206 end
207 add("<br/>")
208 end
209
210 # Sorter of entities in alphabetical order
211 var _sorter: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
212
213 # Sort entities in the alphabetical order
214 fun sort(array: Array[MMEntity])
215 do
216 _sorter.sort(array)
217 end
218
219 readable writable var _owned_modules: Array[MMModule] = new Array[MMModule]
220
221 # Return the known_owner for current module
222 # if inside_mode is set, it could be a different result
223 fun known_owner_of(m: MMModule): MMModule
224 do
225 var module = module
226 if module == null then return m
227 var res = module.known_owner_of(m)
228 if not inside_mode and not intrude_mode and res.directory.owner == module then
229 return module
230 else
231 return res
232 end
233 end
234
235 readable var _opt_dir: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
236
237 redef fun perform_work(mods)
238 do
239 dir.mkdir
240
241 for mod in modules do
242 assert mod isa MMSrcModule
243 mod.extract_module_doc(self)
244 end
245 self.extract_other_doc
246 end
247
248 init
249 do
250 keep_ast = true
251 super("nitdoc")
252 option_context.add_option(opt_dir)
253 end
254
255 redef fun process_options
256 do
257 super
258 var d = opt_dir.value
259 if d != null then dir = d
260 end
261 end
262
263 # Conditionnal part of the text content of a DocContext
264 class StageContext
265 # Content of the current stage
266 readable var _content: Array[String] = new Array[String]
267
268 # Is a normal string already added?
269 readable writable var _validate: Bool = false
270
271 # Parent stage is any
272 readable var _parent: nullable StageContext = null
273
274 init(parent: nullable StageContext) do _parent = parent
275 end
276
277
278 # Efficiently sort object with their to_s method
279 class AlphaSorter[E: Object]
280 special AbstractSorter[E]
281 redef fun compare(a, b)
282 do
283 var sa: String
284 var sb: String
285 var d = _dico
286 if d.has_key(a) then
287 sa = d[a]
288 else
289 sa = a.to_s
290 d[a] = sa
291 end
292 if d.has_key(b) then
293 sb = d[b]
294 else
295 sb = b.to_s
296 d[b] = sb
297 end
298 return sa <=> sb
299 end
300
301 # Keep track of to_s values
302 var _dico: HashMap[Object, String] = new HashMap[Object, String]
303
304 init do end
305 end
306
307 # Generalization of metamodel entities
308 class MMEntity
309 # Return a link to
310 fun html_link(dctx: DocContext): String is abstract
311
312 # Is the entity should appear in the generaed doc
313 fun need_doc(dctx: DocContext): Bool is abstract
314
315 # Return a one liner description
316 fun short_doc: String do return "&nbsp;"
317
318 # The doc node from the AST
319 # Return null is none
320 fun doc: nullable ADoc do return null
321
322 # Human redable location of the entity (module/class/property)
323 fun locate(dctx: DocContext): String do return ""
324
325 # Part of the prototype before the name (kind, modifiers, qualifier)
326 fun prototype_head(dctx: DocContext): String is abstract
327
328 # Part of the property after the name (signature, modifiers)
329 fun prototype_body(dctx: DocContext): String do return ""
330 end
331
332 redef class MMModule
333 special MMEntity
334 redef fun html_link(dctx) do
335 if dctx.module == self then
336 return "{self}"
337 else
338 return "<a href=\"{self}.html\">{self}</a>"
339 end
340 end
341 redef fun need_doc(dctx) do return true
342 redef fun prototype_head(dctx) do return "module "
343
344 var _known_owner_of_cache: Map[MMModule, MMModule] = new HashMap[MMModule, MMModule]
345 fun known_owner_of(module: MMModule): MMModule
346 do
347 if _known_owner_of_cache.has_key(module) then return _known_owner_of_cache[module]
348 var res = module
349 if mhe < module and visibility_for(module) != 0 then
350 res = known_owner_of_intern(module, self, false)
351 else
352 res = module.owner(self)
353 end
354 _known_owner_of_cache[module] = res
355 return res
356 end
357
358 # Return the most general module that own self
359 fun owner(from: MMModule): MMModule
360 do
361 var res = self
362 var d: nullable MMDirectory = directory
363 while d != null and d != from.directory do
364 var o = d.owner
365 if o != null and o.mhe <= res then res = o
366 d = d.parent
367 end
368 return res
369 end
370
371 private fun known_owner_of_intern(module: MMModule, from: MMModule, as_owner: Bool): MMModule
372 do
373 if module == self then return self
374 var candidates = new Array[MMModule]
375 for m in explicit_imported_modules do
376 if from.visibility_for(m) == 0 then continue
377 if not m.mhe <= module then continue
378 candidates.add(m.known_owner_of_intern(module, from, true))
379 end
380 assert not candidates.is_empty
381 var max = candidates.first
382 for m in candidates do
383 if max.mhe < m then max = m
384 end
385 if as_owner and max.directory.owner == self then
386 return self
387 else
388 return max
389 end
390 end
391
392 end
393
394 redef class MMLocalProperty
395 special MMEntity
396 # Anchor of the property description in the module html file
397 fun html_anchor: String
398 do
399 return "PROP_{local_class}_{cmangle(name)}"
400 end
401
402 redef fun html_link(dctx)
403 do
404 var m = module
405 if not need_doc(dctx) then m = global.intro.module
406 var m = dctx.known_owner_of(m)
407 if m == dctx.module then
408 return "<a href=\"#{html_anchor}\">{self}</a>"
409 else
410 return "<a href=\"{m}.html#{html_anchor}\">{self}</a>"
411 end
412 end
413
414 # Kind of property (fun, attr, etc.)
415 fun kind: String is abstract
416
417 redef fun locate(dctx)
418 do
419 return "in {module.html_link(dctx)}::{local_class.html_link(dctx)}"
420 end
421
422 fun known_intro_class(dctx: DocContext): MMLocalClass
423 do
424 var mod = dctx.known_owner_of(global.intro.local_class.module)
425 var cla = mod[global.intro.local_class.global]
426 return cla
427 end
428
429 redef fun prototype_head(dctx)
430 do
431 var res = new Buffer
432 var intro_class = known_intro_class(dctx)
433 var is_redef = local_class != intro_class
434
435 if is_redef then res.append("redef ")
436 if global.visibility_level == 2 then
437 res.append("protected ")
438 else if global.visibility_level == 3 then
439 res.append("private ")
440 end
441 res.append(kind)
442 if is_redef then
443 var gp = global.intro
444 if intro_class.global != local_class.global then
445 res.append(" {module[intro_class.global].html_link(dctx)}::")
446 else if intro_class.module != module then
447 res.append(" {intro_class.module.html_link(dctx)}::")
448 end
449 end
450 return res.to_s
451 end
452
453 redef fun prototype_body(dctx)
454 do
455 var res = new Buffer
456 res.append(signature.to_html(dctx))
457 var s = self
458 if s isa MMMethod then
459 if s.is_abstract then
460 res.append(" is abstract")
461 else if s.is_intern then
462 res.append(" is intern")
463 end
464 end
465 return res.to_s
466 end
467
468 redef fun need_doc(dctx)
469 do
470 if global.visibility_level >= 3 or self isa MMAttribute then
471 if not dctx.intrude_mode then return false
472 if dctx.module.visibility_for(module) == 0 then return false
473 end
474 if global.intro == self then
475 return true
476 end
477 return doc != null
478 end
479
480 redef fun short_doc
481 do
482 var d = doc
483 if d != null then
484 return d.short
485 else if global.intro == self then
486 return "&nbsp;"
487 else
488 return global.intro.short_doc
489 end
490 end
491
492 redef fun doc
493 do
494 var n = node
495 if n == null or not n isa APropdef then
496 return null
497 end
498 var d = n.n_doc
499 if d == null then
500 return null
501 end
502 if d.n_comment.is_empty then
503 return null
504 else
505 return d
506 end
507 end
508 end
509 redef class MMMethod
510 redef fun kind do return if global.is_init then "init" else "meth"
511 end
512 redef class MMAttribute
513 redef fun kind do return "attr"
514 end
515 redef class MMTypeProperty
516 redef fun kind do return "type"
517 end
518
519 redef class MMSrcModule
520 # Extract and generate html file for the module
521 fun extract_module_doc(dctx: DocContext)
522 do
523 dctx.info("Generating HTML for module {name}",1)
524 dctx.register(self)
525
526 dctx.clear
527 extract_module_doc_inside(dctx)
528 dctx.write_to("{dctx.dir}/{name}.html")
529
530 dctx.intrude_mode = true
531 dctx.clear
532 extract_module_doc_inside(dctx)
533 dctx.write_to("{dctx.dir}/{name}__.html")
534 dctx.intrude_mode = false
535
536 if directory.owner == self then
537 dctx.inside_mode = true
538 dctx.clear
539 extract_module_doc_inside(dctx)
540 dctx.write_to("{dctx.dir}/{name}_.html")
541 dctx.inside_mode = false
542 end
543 end
544
545 fun extract_module_doc_inside(dctx: DocContext)
546 do
547 dctx.add_header("Module {self}")
548 dctx.add("<h1>Module {self}</h1>\n<dl>")
549 var s = ""
550 var d: nullable MMDirectory = directory
551 while d == null do
552 if d.owner != null and (d.owner != self or dctx.inside_mode or dctx.intrude_mode) then
553 s = "{d.owner.html_link(dctx)}::{s}"
554 end
555 d = d.parent
556 end
557 dctx.add("{s}<br/>{prototype_head(dctx)}<b>{self}</b>{prototype_body(dctx)}<br/>\n")
558
559 var strs = new Array[String]
560 var intrude_modules = new Array[MMModule]
561 var public_modules = new Array[MMModule]
562 var private_modules = new Array[MMModule]
563 var owned_modules = dctx.owned_modules
564 owned_modules.clear
565 for m in mhe.greaters do
566 var v = visibility_for(m)
567 if not dctx.inside_mode and not dctx.intrude_mode and m.directory.owner == self then
568 if v >= 2 then owned_modules.add(m)
569 continue
570 end
571 if v == 3 then
572 intrude_modules.add(m)
573 else if v == 2 then
574 public_modules.add(m)
575 else if v == 1 then
576 private_modules.add(m)
577 end
578 end
579 if not intrude_modules.is_empty then
580 var mods = mhe.order.select_smallests(intrude_modules)
581 for i in mods do strs.add(i.html_link(dctx))
582 dctx.add("<dt>Intruded modules: <dd>{strs.join(", ")}\n")
583 end
584 if not public_modules.is_empty then
585 strs.clear
586 var mods = mhe.order.select_smallests(public_modules)
587 for i in mods do strs.add(i.html_link(dctx))
588 dctx.add("<dt>Imported modules: <dd>{strs.join(", ")}\n")
589 end
590 if not private_modules.is_empty then
591 strs.clear
592 var mods = mhe.order.select_smallests(private_modules)
593 for i in mods do strs.add(i.html_link(dctx))
594 dctx.add("<dt>Privatly imported modules: <dd>{strs.join(", ")}\n")
595 end
596 dctx.add("</dl>\n")
597
598 var doc = doc
599 if doc != null then dctx.add("<pre>{doc.to_html}</pre>\n")
600
601 var new_classes = new Array[MMLocalClass]
602 for c in local_classes do
603 if c.need_doc(dctx) then
604 new_classes.add(c)
605 if c.global.intro == c then
606 dctx.register(c)
607 end
608 else
609 for m in owned_modules do
610 if m.global_classes.has(c.global) then
611 var mc = m[c.global]
612 if mc.need_doc(dctx) then
613 new_classes.add(c)
614 break
615 end
616 end
617 end
618 end
619 end
620
621 if not new_classes.is_empty then
622 dctx.sort(new_classes)
623 dctx.add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
624 dctx.add("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\"><big>Class Summary of {self}</big></th><tr>\n")
625 for c in new_classes do
626 dctx.add("<tr><td width=\"20%\" align=\"right\">{c.prototype_head(dctx)}</td><td><b>{c.html_link(dctx)}</b>{c.prototype_body(dctx)}<br/>{c.short_doc}</td><tr>\n")
627 end
628 dctx.add("</table><br/>\n")
629 end
630
631 if not new_classes.is_empty then
632 dctx.add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
633 dctx.add("<tr bgcolor=\"#CCCCFF\"><th><big>Class Detail of {self}</big></th><tr>\n")
634 dctx.add("</table>\n")
635
636 for c in new_classes do
637 c.extract_class_doc(dctx)
638 end
639 end
640
641 dctx.add("</body></html>\n")
642 end
643
644 redef fun short_doc
645 do
646 var d = doc
647 if d != null then
648 return d.short
649 else
650 return "&nbsp;"
651 end
652 end
653
654 redef fun doc
655 do
656 var n = node
657 if n.n_packagedecl == null then
658 return null
659 end
660 var np = n.n_packagedecl
661 var d = np.n_doc
662 if d == null then
663 return null
664 end
665 if d.n_comment.is_empty then
666 return null
667 else
668 return d
669 end
670 end
671 end
672
673 redef class ADoc
674 # Html transcription of the doc
675 fun to_html: String
676 do
677 var res = new Buffer
678 for c in n_comment do
679 res.append(c.text.substring_from(1))
680 end
681 return res.to_s
682 end
683
684 # Oneliner transcription of the doc
685 fun short: String
686 do
687 return n_comment.first.text.substring_from(1)
688 end
689 end
690
691 redef class MMLocalClass
692 special MMEntity
693 # Anchor of the class description in the module html file
694 fun html_anchor: String do return "CLASS_{self}"
695
696 redef fun html_link(dctx)
697 do
698 var m = module
699 if not need_doc(dctx) then m = global.module
700 var m = dctx.known_owner_of(m)
701 if m == dctx.module then
702 return "<a href=\"#{html_anchor}\">{self}</a>"
703 else
704 return "<a href=\"{m}.html#{html_anchor}\">{self}</a>"
705 end
706 end
707
708 redef fun short_doc do return global.intro.short_doc
709
710 redef fun doc do return global.intro.doc
711
712 redef fun need_doc(dctx) do
713 if module == dctx.module then
714 for m in dctx.owned_modules do
715 if m.global_classes.has(global) then
716 var c = m[global]
717 if c.need_doc(dctx) then return true
718 end
719 end
720 end
721 return false
722 end
723
724 redef fun locate(dctx) do return "in {module.html_link(dctx)}"
725
726 fun known_intro(dctx: DocContext): MMLocalClass do return dctx.known_owner_of(global.intro.module)[global]
727
728 redef fun prototype_head(dctx)
729 do
730 var res = new Buffer
731 var ki = known_intro(dctx)
732 var is_redef = ki != self
733 if is_redef then res.append("redef ")
734 if global.visibility_level == 3 then res.append("private ")
735 res.append("class ")
736 if is_redef then res.append("{ki.module.html_link(dctx)}::")
737 return res.to_s
738 end
739
740 redef fun prototype_body(dctx)
741 do
742 var res = new Buffer
743 if arity > 0 then
744 res.append("[")
745 for i in [0..arity[ do
746 var t = get_formal(i)
747 res.append(t.name.to_s)
748 res.append(": ")
749 res.append(t.bound.html_link(dctx))
750 end
751 res.append("]")
752 end
753 return res.to_s
754 end
755
756 # Extract the doc of a class
757 fun extract_class_doc(dctx: DocContext)
758 do
759 dctx.add("<a name=\"{html_anchor}\"></a><h2>{self}</h2><small>{module.html_link(dctx)}::</small><br/>{prototype_head(dctx)}<b>{self}</b>{prototype_body(dctx)}\n")
760 dctx.add("<blockquote>\n")
761 dctx.add("<dl>\n")
762
763 var sup2 = new Array[String]
764 var intro_module = dctx.known_owner_of(global.module)
765 if intro_module != module then
766 dctx.add("<dt>Refine {self} from: <dd>{intro_module.html_link(dctx)}\n")
767 sup2.clear
768 var mods = new Array[MMModule]
769 for c in crhe.greaters do
770 if c.need_doc(dctx) then
771 var km = dctx.known_owner_of(c.module)
772 if km != module and km != intro_module and not mods.has(km) then
773 mods.add(km)
774 end
775 end
776 end
777 for c in crhe.linear_extension do
778 if mods.has(c.module) then sup2.add(c.module.html_link(dctx))
779 end
780 if not sup2.is_empty then dctx.add("<dt>Previous refinements in: <dd>{sup2.join(", ")}\n")
781 end
782 if not cshe.greaters.is_empty then
783 sup2.clear
784 var clas = new Array[MMLocalClass]
785 for c in cshe.direct_greaters do
786 sup2.add(c.html_link(dctx))
787 end
788 dctx.add("<dt>Direct superclasses: <dd>{sup2.join(", ")}\n")
789 sup2.clear
790 for c in cshe.linear_extension do
791 if c != self then sup2.add(c.html_link(dctx))
792 end
793 dctx.add("<dt>All superclasses: <dd>{sup2.join(", ")}\n")
794 end
795 if not cshe.direct_smallers.is_empty then
796 sup2.clear
797 for c in cshe.direct_smallers do
798 sup2.add(c.html_link(dctx))
799 end
800 dctx.add("<dt>Direct subclasses: <dd>{sup2.join(", ")}\n")
801 end
802 sup2.clear
803 for c in crhe.smallers do
804 c.compute_super_classes
805 for c2 in c.module.local_classes do
806 if not c2 isa MMConcreteClass then continue
807 c2.compute_super_classes
808 c2.compute_ancestors
809 c2.inherit_global_properties
810 end
811 for c2 in c.cshe.direct_smallers do
812 if c2.global.intro == c2 then
813 sup2.add("{c2.html_link(dctx)}")
814 end
815 end
816 end
817 if not sup2.is_empty then
818 dctx.add("<dt>Other direct subclasses in known modules: <dd>{sup2.join(", ")}\n")
819 end
820 sup2.clear
821 for c in crhe.order do
822 if not module.mhe <= c.module and c.need_doc(dctx) then
823 sup2.add(c.module.html_link(dctx))
824 end
825 end
826 if not sup2.is_empty then
827 dctx.add("<dt>Refinements in known modules: <dd>{sup2.join(", ")}\n")
828 end
829 dctx.add("</dl>\n")
830
831 var doc = doc
832 if doc != null then
833 dctx.add("<pre>{doc.to_html}</pre>\n")
834 end
835
836 var details = new Array[Array[MMLocalProperty]]
837 for i in [0..4[ do details.add(property_summary(dctx, i))
838 for i in [0..4[ do property_detail(dctx, i, details[i])
839
840 dctx.add("</blockquote><hr/>\n")
841 end
842
843 fun pass_name(pass: Int): String
844 do
845 var names = once ["Virtual Types", "Consructors", "Methods", "Attributes"]
846 return names[pass]
847 end
848
849 fun accept_prop(p: MMLocalProperty, pass: Int): Bool
850 do
851 if pass == 0 then
852 return p isa MMTypeProperty
853 else if pass == 1 then
854 return p.global.is_init
855 else if pass == 2 then
856 return p isa MMMethod and not p.global.is_init
857 else if pass == 3 then
858 return p isa MMAttribute
859 end
860 abort
861 end
862
863 fun property_summary(dctx: DocContext, pass: Int): Array[MMLocalProperty]
864 do
865 var passname = pass_name(pass)
866 dctx.open_stage
867 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
868 dctx.stage("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\">{passname} Summary of {self}</th></tr>\n")
869
870 var new_props = new Array[MMLocalProperty]
871 for g in global_properties do
872 if not accept_prop(g.intro, pass) then continue
873 if module.visibility_for(g.intro.module) < g.visibility_level then continue
874 var p = self[g]
875 if p.local_class != self or not p.need_doc(dctx) then
876 var cla = new Array[MMLocalClass]
877 for m in dctx.owned_modules do
878 if not m.global_classes.has(global) then continue
879 var c = m[global]
880 if not c isa MMConcreteClass then continue
881 if not c.has_global_property(g) then continue
882 var p2 = c[g]
883 if p2.local_class != c or not p2.need_doc(dctx) then continue
884 cla.add(c)
885 end
886 if cla.is_empty then continue
887 cla = crhe.order.select_smallests(cla)
888 end
889
890 new_props.add(p)
891 if p.global.intro == p then
892 dctx.register(p)
893 end
894 end
895 dctx.sort(new_props)
896 for p in new_props do
897 dctx.add("<tr><td width=\"20%\" align=\"right\">{p.prototype_head(dctx)}</td><td><b>{p.html_link(dctx)}</b>{p.prototype_body(dctx)}<br/>&nbsp;&nbsp;&nbsp;&nbsp;{p.short_doc}</td></tr>\n")
898 end
899 dctx.stage("</table><br/>\n")
900
901 dctx.open_stage
902 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
903 if pass != 1 then
904 # skip pass 1 because constructors are not inherited
905 var cmap = new HashMap[MMLocalClass, Array[MMLocalProperty]]
906 var mmap = new HashMap[MMModule, Array[MMLocalProperty]]
907 var props = new Array[MMLocalClass]
908 for c in che.greaters do
909 if c isa MMSrcLocalClass then
910 var km = dctx.known_owner_of(c.module)
911 var kc = km[c.global]
912 if kc == self then continue
913 var props: Array[MMLocalProperty]
914 if km == module then
915 if cmap.has_key(kc) then
916 props = cmap[kc]
917 else
918 props = new Array[MMLocalProperty]
919 cmap[kc] = props
920 end
921 else
922 if mmap.has_key(km) then
923 props = mmap[km]
924 else
925 props = new Array[MMLocalProperty]
926 mmap[km] = props
927 end
928 end
929 for g in c.global_properties do
930 var p = c[g]
931 if p.local_class == c and p.need_doc(dctx) and accept_prop(p, pass) then
932 props.add(kc[g])
933 end
934 end
935 end
936 end
937 dctx.open_stage
938 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Inherited {passname}</small></th><tr>\n")
939 for c in cshe.linear_extension do
940 if not cmap.has_key(c) then continue
941 var props = cmap[c]
942 if props.is_empty then continue
943 dctx.sort(props)
944 var properties = new Array[String]
945 for p in props do properties.add(p.html_link(dctx))
946 dctx.add("<tr><td width=\"20%\"><small>from {c.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
947 end
948 dctx.close_stage
949
950 dctx.open_stage
951 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Imported {passname}</small></th><tr>\n")
952 for m in module.mhe.linear_extension do
953 if not mmap.has_key(m) then continue
954 var props = mmap[m]
955 if props.is_empty then continue
956 dctx.sort(props)
957 var properties = new Array[String]
958 for p in props do properties.add(p.html_link(dctx))
959 dctx.add("<tr><td width=\"20%\"><small>from {m.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
960 end
961 dctx.close_stage
962 end
963
964 var mmap = new HashMap[MMModule, Array[MMLocalProperty]]
965 var props = new Array[MMLocalClass]
966 for c in crhe.order do
967 if module.mhe <= c.module or dctx.owned_modules.has(c.module) or not c isa MMSrcLocalClass then continue
968 var km = dctx.known_owner_of(c.module)
969 if module.mhe <= km then continue
970 var kc = km[c.global]
971 var props: Array[MMLocalProperty]
972 if mmap.has_key(km) then
973 props = mmap[km]
974 else
975 props = new Array[MMLocalProperty]
976 mmap[km] = props
977 end
978 for g in c.global_properties do
979 var p = c[g]
980 if p.local_class == c and p.need_doc(dctx) and accept_prop(p, pass) then
981 var kp = kc[g]
982 if not props.has(kp) then props.add(kp)
983 end
984 end
985 # c.properties_inherited_from(dctx, self, pass)
986 end
987 dctx.open_stage
988 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Added {passname} in known modules</small></th><tr>\n")
989 for c in crhe.order do
990 var m = c.module
991 if not mmap.has_key(m) then continue
992 var props = mmap[m]
993 if props.is_empty then continue
994 dctx.sort(props)
995 var properties = new Array[String]
996 for p in props do properties.add(p.html_link(dctx))
997 dctx.add("<tr><td width=\"20%\"><small>in {m.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
998 end
999 dctx.close_stage
1000 dctx.stage("</table><br/><br/>\n")
1001 dctx.close_stage
1002
1003 dctx.close_stage
1004 return new_props
1005 end
1006
1007 fun property_detail(dctx: DocContext, pass: Int, new_props: Array[MMLocalProperty])
1008 do
1009 var passname = pass_name(pass)
1010 dctx.open_stage
1011 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
1012 dctx.stage("<tr bgcolor=\"#CCCCFF\"><th>{passname} Detail of {self}</th><tr>\n")
1013 dctx.stage("</table>\n")
1014
1015 dctx.open_stage
1016 for p in new_props do
1017 dctx.add("<a name=\"{p.html_anchor}\"></a><h3>{p}</h3><p><small>{p.module.html_link(dctx)}::{p.local_class.html_link(dctx)}::</small><br/>{p.prototype_head(dctx)} <b>{p.name}</b>{p.prototype_body(dctx)}</p>\n")
1018 dctx.add("<blockquote>")
1019 var doc = p.doc
1020 if doc != null then
1021 dctx.add("<pre>{doc.to_html}</pre>\n")
1022 end
1023 dctx.stage("</blockquote>\n")
1024 dctx.close_stage
1025
1026 dctx.open_stage
1027 dctx.stage("<hr/>\n")
1028 end
1029 dctx.close_stage
1030
1031 dctx.close_stage
1032 end
1033
1034 # Add rows for properties inheriterd to some heirs
1035 fun properties_inherited_from(dctx: DocContext, heir: MMLocalClass, pass: Int)
1036 do
1037 var properties = new Array[String]
1038 for g in global_properties do
1039 var p = self[g]
1040 if p.local_class == self and p.need_doc(dctx) and accept_prop(p, pass) then
1041 properties.add(p.html_link(dctx))
1042 end
1043 end
1044 if not properties.is_empty then
1045 var s: String
1046 if heir.global == global then
1047 s = module.html_link(dctx)
1048 else
1049 s = self.html_link(dctx)
1050 end
1051 dctx.add("<tr><td width=\"20%\"><small>in {s}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
1052 end
1053 end
1054 end
1055
1056 redef class MMSrcLocalClass
1057 redef fun short_doc
1058 do
1059 var d = doc
1060 if d != null then
1061 return d.short
1062 else if global.intro == self then
1063 return "&nbsp;"
1064 else
1065 var bc = global.intro
1066 return bc.short_doc
1067 end
1068 end
1069
1070 redef fun doc
1071 do
1072 var n = node
1073 if not n isa AStdClassdef then
1074 return null
1075 end
1076 var d = n.n_doc
1077 if d == null then
1078 return null
1079 end
1080 if d.n_comment.is_empty then
1081 return null
1082 else
1083 return d
1084 end
1085 end
1086
1087 redef fun need_doc(dctx)
1088 do
1089 if global.visibility_level >= 3 then
1090 if not dctx.intrude_mode then return false
1091 if dctx.module.visibility_for(module) == 0 then return false
1092 end
1093 if global.intro == self then
1094 return true
1095 end
1096 for p in src_local_properties do
1097 if p.need_doc(dctx) then
1098 return true
1099 end
1100 end
1101 return super
1102 end
1103 end
1104
1105 redef class MMSignature
1106 # Htlm transcription of the signature (with nested links)
1107 fun to_html(dctx: DocContext): String
1108 do
1109 var res = new Buffer
1110 if arity > 0 then
1111 res.append("(")
1112 res.append(self[0].html_link(dctx))
1113 for i in [1..arity[ do
1114 res.append(", ")
1115 res.append(self[i].html_link(dctx))
1116 end
1117 res.append(")")
1118 end
1119 if return_type != null then
1120 res.append(": ")
1121 res.append(return_type.html_link(dctx))
1122 end
1123 return res.to_s
1124 end
1125 end
1126
1127 redef class MMType
1128 # Htlm transcription of the type (with nested links)
1129 fun html_link(dctx: DocContext): String do return to_s
1130 end
1131
1132 redef class MMTypeSimpleClass
1133 redef fun html_link(dctx) do return local_class.html_link(dctx)
1134 end
1135
1136 redef class MMTypeGeneric
1137 redef fun html_link(dctx)
1138 do
1139 var res = new Buffer
1140 res.append(local_class.html_link(dctx))
1141 res.append("[")
1142 res.append(params[0].html_link(dctx))
1143 for i in [1..params.length[ do
1144 res.append(", ")
1145 res.append(params[i].html_link(dctx))
1146 end
1147 res.append("]")
1148 return res.to_s
1149 end
1150 end
1151
1152 var c = new DocContext
1153 c.exec_cmd_line