parser: differentiate all P* and A* production classes
[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 node isa PPropdef then
496 return null
497 end
498 assert n isa PPropdef
499 var d = n.n_doc
500 if d == null then
501 return null
502 end
503 assert d isa ADoc
504 if d.n_comment.is_empty then
505 return null
506 else
507 return d
508 end
509 end
510 end
511 redef class MMMethod
512 redef fun kind do return if global.is_init then "init" else "meth"
513 end
514 redef class MMAttribute
515 redef fun kind do return "attr"
516 end
517 redef class MMTypeProperty
518 redef fun kind do return "type"
519 end
520
521 redef class MMSrcModule
522 # Extract and generate html file for the module
523 fun extract_module_doc(dctx: DocContext)
524 do
525 dctx.info("Generating HTML for module {name}",1)
526 dctx.register(self)
527
528 dctx.clear
529 extract_module_doc_inside(dctx)
530 dctx.write_to("{dctx.dir}/{name}.html")
531
532 dctx.intrude_mode = true
533 dctx.clear
534 extract_module_doc_inside(dctx)
535 dctx.write_to("{dctx.dir}/{name}__.html")
536 dctx.intrude_mode = false
537
538 if directory.owner == self then
539 dctx.inside_mode = true
540 dctx.clear
541 extract_module_doc_inside(dctx)
542 dctx.write_to("{dctx.dir}/{name}_.html")
543 dctx.inside_mode = false
544 end
545 end
546
547 fun extract_module_doc_inside(dctx: DocContext)
548 do
549 dctx.add_header("Module {self}")
550 dctx.add("<h1>Module {self}</h1>\n<dl>")
551 var s = ""
552 var d: nullable MMDirectory = directory
553 while d == null do
554 if d.owner != null and (d.owner != self or dctx.inside_mode or dctx.intrude_mode) then
555 s = "{d.owner.html_link(dctx)}::{s}"
556 end
557 d = d.parent
558 end
559 dctx.add("{s}<br/>{prototype_head(dctx)}<b>{self}</b>{prototype_body(dctx)}<br/>\n")
560
561 var strs = new Array[String]
562 var intrude_modules = new Array[MMModule]
563 var public_modules = new Array[MMModule]
564 var private_modules = new Array[MMModule]
565 var owned_modules = dctx.owned_modules
566 owned_modules.clear
567 for m in mhe.greaters do
568 var v = visibility_for(m)
569 if not dctx.inside_mode and not dctx.intrude_mode and m.directory.owner == self then
570 if v >= 2 then owned_modules.add(m)
571 continue
572 end
573 if v == 3 then
574 intrude_modules.add(m)
575 else if v == 2 then
576 public_modules.add(m)
577 else if v == 1 then
578 private_modules.add(m)
579 end
580 end
581 if not intrude_modules.is_empty then
582 var mods = mhe.order.select_smallests(intrude_modules)
583 for i in mods do strs.add(i.html_link(dctx))
584 dctx.add("<dt>Intruded modules: <dd>{strs.join(", ")}\n")
585 end
586 if not public_modules.is_empty then
587 strs.clear
588 var mods = mhe.order.select_smallests(public_modules)
589 for i in mods do strs.add(i.html_link(dctx))
590 dctx.add("<dt>Imported modules: <dd>{strs.join(", ")}\n")
591 end
592 if not private_modules.is_empty then
593 strs.clear
594 var mods = mhe.order.select_smallests(private_modules)
595 for i in mods do strs.add(i.html_link(dctx))
596 dctx.add("<dt>Privatly imported modules: <dd>{strs.join(", ")}\n")
597 end
598 dctx.add("</dl>\n")
599
600 var doc = doc
601 if doc != null then dctx.add("<pre>{doc.to_html}</pre>\n")
602
603 var new_classes = new Array[MMLocalClass]
604 for c in local_classes do
605 if c.need_doc(dctx) then
606 new_classes.add(c)
607 if c.global.intro == c then
608 dctx.register(c)
609 end
610 else
611 for m in owned_modules do
612 if m.global_classes.has(c.global) then
613 var mc = m[c.global]
614 if mc.need_doc(dctx) then
615 new_classes.add(c)
616 break
617 end
618 end
619 end
620 end
621 end
622
623 if not new_classes.is_empty then
624 dctx.sort(new_classes)
625 dctx.add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
626 dctx.add("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\"><big>Class Summary of {self}</big></th><tr>\n")
627 for c in new_classes do
628 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")
629 end
630 dctx.add("</table><br/>\n")
631 end
632
633 if not new_classes.is_empty then
634 dctx.add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
635 dctx.add("<tr bgcolor=\"#CCCCFF\"><th><big>Class Detail of {self}</big></th><tr>\n")
636 dctx.add("</table>\n")
637
638 for c in new_classes do
639 c.extract_class_doc(dctx)
640 end
641 end
642
643 dctx.add("</body></html>\n")
644 end
645
646 redef fun short_doc
647 do
648 var d = doc
649 if d != null then
650 return d.short
651 else
652 return "&nbsp;"
653 end
654 end
655
656 redef fun doc
657 do
658 var n = node
659 if n.n_packagedecl == null then
660 return null
661 end
662 var np = n.n_packagedecl
663 assert np isa APackagedecl
664 var d = np.n_doc
665 if d == null then
666 return null
667 end
668 assert d isa ADoc
669 if d.n_comment.is_empty then
670 return null
671 else
672 return d
673 end
674 end
675 end
676
677 redef class ADoc
678 # Html transcription of the doc
679 fun to_html: String
680 do
681 var res = new Buffer
682 for c in n_comment do
683 res.append(c.text.substring_from(1))
684 end
685 return res.to_s
686 end
687
688 # Oneliner transcription of the doc
689 fun short: String
690 do
691 return n_comment.first.text.substring_from(1)
692 end
693 end
694
695 redef class MMLocalClass
696 special MMEntity
697 # Anchor of the class description in the module html file
698 fun html_anchor: String do return "CLASS_{self}"
699
700 redef fun html_link(dctx)
701 do
702 var m = module
703 if not need_doc(dctx) then m = global.module
704 var m = dctx.known_owner_of(m)
705 if m == dctx.module then
706 return "<a href=\"#{html_anchor}\">{self}</a>"
707 else
708 return "<a href=\"{m}.html#{html_anchor}\">{self}</a>"
709 end
710 end
711
712 redef fun short_doc do return global.intro.short_doc
713
714 redef fun doc do return global.intro.doc
715
716 redef fun need_doc(dctx) do
717 if module == dctx.module then
718 for m in dctx.owned_modules do
719 if m.global_classes.has(global) then
720 var c = m[global]
721 if c.need_doc(dctx) then return true
722 end
723 end
724 end
725 return false
726 end
727
728 redef fun locate(dctx) do return "in {module.html_link(dctx)}"
729
730 fun known_intro(dctx: DocContext): MMLocalClass do return dctx.known_owner_of(global.intro.module)[global]
731
732 redef fun prototype_head(dctx)
733 do
734 var res = new Buffer
735 var ki = known_intro(dctx)
736 var is_redef = ki != self
737 if is_redef then res.append("redef ")
738 if global.visibility_level == 3 then res.append("private ")
739 res.append("class ")
740 if is_redef then res.append("{ki.module.html_link(dctx)}::")
741 return res.to_s
742 end
743
744 redef fun prototype_body(dctx)
745 do
746 var res = new Buffer
747 if arity > 0 then
748 res.append("[")
749 for i in [0..arity[ do
750 var t = get_formal(i)
751 res.append(t.name.to_s)
752 res.append(": ")
753 res.append(t.bound.html_link(dctx))
754 end
755 res.append("]")
756 end
757 return res.to_s
758 end
759
760 # Extract the doc of a class
761 fun extract_class_doc(dctx: DocContext)
762 do
763 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")
764 dctx.add("<blockquote>\n")
765 dctx.add("<dl>\n")
766
767 var sup2 = new Array[String]
768 var intro_module = dctx.known_owner_of(global.module)
769 if intro_module != module then
770 dctx.add("<dt>Refine {self} from: <dd>{intro_module.html_link(dctx)}\n")
771 sup2.clear
772 var mods = new Array[MMModule]
773 for c in crhe.greaters do
774 if c.need_doc(dctx) then
775 var km = dctx.known_owner_of(c.module)
776 if km != module and km != intro_module and not mods.has(km) then
777 mods.add(km)
778 end
779 end
780 end
781 for c in crhe.linear_extension do
782 if mods.has(c.module) then sup2.add(c.module.html_link(dctx))
783 end
784 if not sup2.is_empty then dctx.add("<dt>Previous refinements in: <dd>{sup2.join(", ")}\n")
785 end
786 if not cshe.greaters.is_empty then
787 sup2.clear
788 var clas = new Array[MMLocalClass]
789 for c in cshe.direct_greaters do
790 sup2.add(c.html_link(dctx))
791 end
792 dctx.add("<dt>Direct superclasses: <dd>{sup2.join(", ")}\n")
793 sup2.clear
794 for c in cshe.linear_extension do
795 if c != self then sup2.add(c.html_link(dctx))
796 end
797 dctx.add("<dt>All superclasses: <dd>{sup2.join(", ")}\n")
798 end
799 if not cshe.direct_smallers.is_empty then
800 sup2.clear
801 for c in cshe.direct_smallers do
802 sup2.add(c.html_link(dctx))
803 end
804 dctx.add("<dt>Direct subclasses: <dd>{sup2.join(", ")}\n")
805 end
806 sup2.clear
807 for c in crhe.smallers do
808 c.compute_super_classes
809 for c2 in c.module.local_classes do
810 if not c2 isa MMConcreteClass then continue
811 c2.compute_super_classes
812 c2.compute_ancestors
813 c2.inherit_global_properties
814 end
815 for c2 in c.cshe.direct_smallers do
816 if c2.global.intro == c2 then
817 sup2.add("{c2.html_link(dctx)}")
818 end
819 end
820 end
821 if not sup2.is_empty then
822 dctx.add("<dt>Other direct subclasses in known modules: <dd>{sup2.join(", ")}\n")
823 end
824 sup2.clear
825 for c in crhe.order do
826 if not module.mhe <= c.module and c.need_doc(dctx) then
827 sup2.add(c.module.html_link(dctx))
828 end
829 end
830 if not sup2.is_empty then
831 dctx.add("<dt>Refinements in known modules: <dd>{sup2.join(", ")}\n")
832 end
833 dctx.add("</dl>\n")
834
835 var doc = doc
836 if doc != null then
837 dctx.add("<pre>{doc.to_html}</pre>\n")
838 end
839
840 var details = new Array[Array[MMLocalProperty]]
841 for i in [0..4[ do details.add(property_summary(dctx, i))
842 for i in [0..4[ do property_detail(dctx, i, details[i])
843
844 dctx.add("</blockquote><hr/>\n")
845 end
846
847 fun pass_name(pass: Int): String
848 do
849 var names = once ["Virtual Types", "Consructors", "Methods", "Attributes"]
850 return names[pass]
851 end
852
853 fun accept_prop(p: MMLocalProperty, pass: Int): Bool
854 do
855 if pass == 0 then
856 return p isa MMTypeProperty
857 else if pass == 1 then
858 return p.global.is_init
859 else if pass == 2 then
860 return p isa MMMethod and not p.global.is_init
861 else if pass == 3 then
862 return p isa MMAttribute
863 end
864 abort
865 end
866
867 fun property_summary(dctx: DocContext, pass: Int): Array[MMLocalProperty]
868 do
869 var passname = pass_name(pass)
870 dctx.open_stage
871 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
872 dctx.stage("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\">{passname} Summary of {self}</th></tr>\n")
873
874 var new_props = new Array[MMLocalProperty]
875 for g in global_properties do
876 if not accept_prop(g.intro, pass) then continue
877 if module.visibility_for(g.intro.module) < g.visibility_level then continue
878 var p = self[g]
879 if p.local_class != self or not p.need_doc(dctx) then
880 var cla = new Array[MMLocalClass]
881 for m in dctx.owned_modules do
882 if not m.global_classes.has(global) then continue
883 var c = m[global]
884 if not c isa MMConcreteClass then continue
885 if not c.has_global_property(g) then continue
886 var p2 = c[g]
887 if p2.local_class != c or not p2.need_doc(dctx) then continue
888 cla.add(c)
889 end
890 if cla.is_empty then continue
891 cla = crhe.order.select_smallests(cla)
892 end
893
894 new_props.add(p)
895 if p.global.intro == p then
896 dctx.register(p)
897 end
898 end
899 dctx.sort(new_props)
900 for p in new_props do
901 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")
902 end
903 dctx.stage("</table><br/>\n")
904
905 dctx.open_stage
906 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
907 if pass != 1 then
908 # skip pass 1 because constructors are not inherited
909 var cmap = new HashMap[MMLocalClass, Array[MMLocalProperty]]
910 var mmap = new HashMap[MMModule, Array[MMLocalProperty]]
911 var props = new Array[MMLocalClass]
912 for c in che.greaters do
913 if c isa MMSrcLocalClass then
914 var km = dctx.known_owner_of(c.module)
915 var kc = km[c.global]
916 if kc == self then continue
917 var props: Array[MMLocalProperty]
918 if km == module then
919 if cmap.has_key(kc) then
920 props = cmap[kc]
921 else
922 props = new Array[MMLocalProperty]
923 cmap[kc] = props
924 end
925 else
926 if mmap.has_key(km) then
927 props = mmap[km]
928 else
929 props = new Array[MMLocalProperty]
930 mmap[km] = props
931 end
932 end
933 for g in c.global_properties do
934 var p = c[g]
935 if p.local_class == c and p.need_doc(dctx) and accept_prop(p, pass) then
936 props.add(kc[g])
937 end
938 end
939 end
940 end
941 dctx.open_stage
942 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Inherited {passname}</small></th><tr>\n")
943 for c in cshe.linear_extension do
944 if not cmap.has_key(c) then continue
945 var props = cmap[c]
946 if props.is_empty then continue
947 dctx.sort(props)
948 var properties = new Array[String]
949 for p in props do properties.add(p.html_link(dctx))
950 dctx.add("<tr><td width=\"20%\"><small>from {c.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
951 end
952 dctx.close_stage
953
954 dctx.open_stage
955 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Imported {passname}</small></th><tr>\n")
956 for m in module.mhe.linear_extension do
957 if not mmap.has_key(m) then continue
958 var props = mmap[m]
959 if props.is_empty then continue
960 dctx.sort(props)
961 var properties = new Array[String]
962 for p in props do properties.add(p.html_link(dctx))
963 dctx.add("<tr><td width=\"20%\"><small>from {m.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
964 end
965 dctx.close_stage
966 end
967
968 var mmap = new HashMap[MMModule, Array[MMLocalProperty]]
969 var props = new Array[MMLocalClass]
970 for c in crhe.order do
971 if module.mhe <= c.module or dctx.owned_modules.has(c.module) or not c isa MMSrcLocalClass then continue
972 var km = dctx.known_owner_of(c.module)
973 if module.mhe <= km then continue
974 var kc = km[c.global]
975 var props: Array[MMLocalProperty]
976 if mmap.has_key(km) then
977 props = mmap[km]
978 else
979 props = new Array[MMLocalProperty]
980 mmap[km] = props
981 end
982 for g in c.global_properties do
983 var p = c[g]
984 if p.local_class == c and p.need_doc(dctx) and accept_prop(p, pass) then
985 var kp = kc[g]
986 if not props.has(kp) then props.add(kp)
987 end
988 end
989 # c.properties_inherited_from(dctx, self, pass)
990 end
991 dctx.open_stage
992 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Added {passname} in known modules</small></th><tr>\n")
993 for c in crhe.order do
994 var m = c.module
995 if not mmap.has_key(m) then continue
996 var props = mmap[m]
997 if props.is_empty then continue
998 dctx.sort(props)
999 var properties = new Array[String]
1000 for p in props do properties.add(p.html_link(dctx))
1001 dctx.add("<tr><td width=\"20%\"><small>in {m.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
1002 end
1003 dctx.close_stage
1004 dctx.stage("</table><br/><br/>\n")
1005 dctx.close_stage
1006
1007 dctx.close_stage
1008 return new_props
1009 end
1010
1011 fun property_detail(dctx: DocContext, pass: Int, new_props: Array[MMLocalProperty])
1012 do
1013 var passname = pass_name(pass)
1014 dctx.open_stage
1015 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
1016 dctx.stage("<tr bgcolor=\"#CCCCFF\"><th>{passname} Detail of {self}</th><tr>\n")
1017 dctx.stage("</table>\n")
1018
1019 dctx.open_stage
1020 for p in new_props do
1021 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")
1022 dctx.add("<blockquote>")
1023 var doc = p.doc
1024 if doc != null then
1025 dctx.add("<pre>{doc.to_html}</pre>\n")
1026 end
1027 dctx.stage("</blockquote>\n")
1028 dctx.close_stage
1029
1030 dctx.open_stage
1031 dctx.stage("<hr/>\n")
1032 end
1033 dctx.close_stage
1034
1035 dctx.close_stage
1036 end
1037
1038 # Add rows for properties inheriterd to some heirs
1039 fun properties_inherited_from(dctx: DocContext, heir: MMLocalClass, pass: Int)
1040 do
1041 var properties = new Array[String]
1042 for g in global_properties do
1043 var p = self[g]
1044 if p.local_class == self and p.need_doc(dctx) and accept_prop(p, pass) then
1045 properties.add(p.html_link(dctx))
1046 end
1047 end
1048 if not properties.is_empty then
1049 var s: String
1050 if heir.global == global then
1051 s = module.html_link(dctx)
1052 else
1053 s = self.html_link(dctx)
1054 end
1055 dctx.add("<tr><td width=\"20%\"><small>in {s}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
1056 end
1057 end
1058 end
1059
1060 redef class MMSrcLocalClass
1061 redef fun short_doc
1062 do
1063 var d = doc
1064 if d != null then
1065 return d.short
1066 else if global.intro == self then
1067 return "&nbsp;"
1068 else
1069 var bc = global.intro
1070 return bc.short_doc
1071 end
1072 end
1073
1074 redef fun doc
1075 do
1076 var n = node
1077 if not n isa AStdClassdef then
1078 return null
1079 end
1080 assert n isa AStdClassdef
1081 var d = n.n_doc
1082 if d == null then
1083 return null
1084 end
1085 assert d isa ADoc
1086 if d.n_comment.is_empty then
1087 return null
1088 else
1089 return d
1090 end
1091 end
1092
1093 redef fun need_doc(dctx)
1094 do
1095 if global.visibility_level >= 3 then
1096 if not dctx.intrude_mode then return false
1097 if dctx.module.visibility_for(module) == 0 then return false
1098 end
1099 if global.intro == self then
1100 return true
1101 end
1102 for p in src_local_properties do
1103 if p.need_doc(dctx) then
1104 return true
1105 end
1106 end
1107 return super
1108 end
1109 end
1110
1111 redef class MMSignature
1112 # Htlm transcription of the signature (with nested links)
1113 fun to_html(dctx: DocContext): String
1114 do
1115 var res = new Buffer
1116 if arity > 0 then
1117 res.append("(")
1118 res.append(self[0].html_link(dctx))
1119 for i in [1..arity[ do
1120 res.append(", ")
1121 res.append(self[i].html_link(dctx))
1122 end
1123 res.append(")")
1124 end
1125 if return_type != null then
1126 res.append(": ")
1127 res.append(return_type.html_link(dctx))
1128 end
1129 return res.to_s
1130 end
1131 end
1132
1133 redef class MMType
1134 # Htlm transcription of the type (with nested links)
1135 fun html_link(dctx: DocContext): String do return to_s
1136 end
1137
1138 redef class MMTypeSimpleClass
1139 redef fun html_link(dctx) do return local_class.html_link(dctx)
1140 end
1141
1142 redef class MMTypeGeneric
1143 redef fun html_link(dctx)
1144 do
1145 var res = new Buffer
1146 res.append(local_class.html_link(dctx))
1147 res.append("[")
1148 res.append(params[0].html_link(dctx))
1149 for i in [1..params.length[ do
1150 res.append(", ")
1151 res.append(params[i].html_link(dctx))
1152 end
1153 res.append("]")
1154 return res.to_s
1155 end
1156 end
1157
1158 var c = new DocContext
1159 c.exec_cmd_line