syntax: fix code using superstrings with nullables
[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 var module = module
191 if (not inside_mode and not intrude_mode) or module == null then
192 add("<b>Public</b>&nbsp; ")
193 else
194 add("<a href=\"{module}.html\"><b>Public</b></a>&nbsp; ")
195 end
196 if inside_mode or module == null then
197 add("<b>Inside</b>&nbsp; ")
198 else if module.directory.owner != module then
199 add("<strike><b>Inside</b></strike>&nbsp; ")
200 else
201 add("<a href=\"{module}_.html\"><b>Inside</b></a>&nbsp; ")
202 end
203 if intrude_mode or module == null then
204 add("<b>Intrude</b>&nbsp; ")
205 else
206 add("<a href=\"{module}__.html\"><b>Intrude</b></a>&nbsp; ")
207 end
208 add("<br/>")
209 end
210
211 # Sorter of entities in alphabetical order
212 var _sorter: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
213
214 # Sort entities in the alphabetical order
215 fun sort(array: Array[MMEntity])
216 do
217 _sorter.sort(array)
218 end
219
220 readable writable var _owned_modules: Array[MMModule] = new Array[MMModule]
221
222 # Return the known_owner for current module
223 # if inside_mode is set, it could be a different result
224 fun known_owner_of(m: MMModule): MMModule
225 do
226 var module = module
227 if module == null then return m
228 var res = module.known_owner_of(m)
229 if not inside_mode and not intrude_mode and res.directory.owner == module then
230 return module
231 else
232 return res
233 end
234 end
235
236 readable var _opt_dir: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
237
238 redef fun perform_work(mods)
239 do
240 dir.mkdir
241
242 for mod in modules do
243 assert mod isa MMSrcModule
244 mod.extract_module_doc(self)
245 end
246 self.extract_other_doc
247 end
248
249 init
250 do
251 keep_ast = true
252 super("nitdoc")
253 option_context.add_option(opt_dir)
254 end
255
256 redef fun process_options
257 do
258 super
259 var d = opt_dir.value
260 if d != null then dir = d
261 end
262 end
263
264 # Conditionnal part of the text content of a DocContext
265 class StageContext
266 # Content of the current stage
267 readable var _content: Array[String] = new Array[String]
268
269 # Is a normal string already added?
270 readable writable var _validate: Bool = false
271
272 # Parent stage is any
273 readable var _parent: nullable StageContext = null
274
275 init(parent: nullable StageContext) do _parent = parent
276 end
277
278
279 # Efficiently sort object with their to_s method
280 class AlphaSorter[E: Object]
281 special AbstractSorter[E]
282 redef fun compare(a, b)
283 do
284 var sa: String
285 var sb: String
286 var d = _dico
287 if d.has_key(a) then
288 sa = d[a]
289 else
290 sa = a.to_s
291 d[a] = sa
292 end
293 if d.has_key(b) then
294 sb = d[b]
295 else
296 sb = b.to_s
297 d[b] = sb
298 end
299 return sa <=> sb
300 end
301
302 # Keep track of to_s values
303 var _dico: HashMap[Object, String] = new HashMap[Object, String]
304
305 init do end
306 end
307
308 # Generalization of metamodel entities
309 class MMEntity
310 # Return a link to
311 fun html_link(dctx: DocContext): String is abstract
312
313 # Is the entity should appear in the generaed doc
314 fun need_doc(dctx: DocContext): Bool is abstract
315
316 # Return a one liner description
317 fun short_doc: String do return "&nbsp;"
318
319 # The doc node from the AST
320 # Return null is none
321 fun doc: nullable ADoc do return null
322
323 # Human redable location of the entity (module/class/property)
324 fun locate(dctx: DocContext): String do return ""
325
326 # Part of the prototype before the name (kind, modifiers, qualifier)
327 fun prototype_head(dctx: DocContext): String is abstract
328
329 # Part of the property after the name (signature, modifiers)
330 fun prototype_body(dctx: DocContext): String do return ""
331 end
332
333 redef class MMModule
334 special MMEntity
335 redef fun html_link(dctx) do
336 if dctx.module == self then
337 return "{self}"
338 else
339 return "<a href=\"{self}.html\">{self}</a>"
340 end
341 end
342 redef fun need_doc(dctx) do return true
343 redef fun prototype_head(dctx) do return "module "
344
345 var _known_owner_of_cache: Map[MMModule, MMModule] = new HashMap[MMModule, MMModule]
346
347 # Return the owner of `module` from the point of view of `self`
348 fun known_owner_of(module: MMModule): MMModule
349 do
350 if _known_owner_of_cache.has_key(module) then return _known_owner_of_cache[module]
351 var res = module
352 # is module is publicly imported by self?
353 if mhe < module and visibility_for(module) != 0 then
354 res = known_owner_of_intern(module, self, false)
355 else
356 # Return the canonnical owner of module from the point of view of self
357 res = module.owner(self)
358 end
359 _known_owner_of_cache[module] = res
360 return res
361 end
362
363 # Return the most general module that own self
364 fun owner(from: MMModule): MMModule
365 do
366 var res = self
367 var d: nullable MMDirectory = directory
368 while d != null and d != from.directory do
369 var o = d.owner
370 if o != null and o.mhe <= res then res = o
371 d = d.parent
372 end
373 return res
374 end
375
376 # ???
377 private fun known_owner_of_intern(module: MMModule, from: MMModule, as_owner: Bool): MMModule
378 do
379 if module == self then return self
380 var candidates = new Array[MMModule]
381 for m in explicit_imported_modules do
382 if from.visibility_for(m) == 0 then continue
383 if not m.mhe <= module then continue
384 candidates.add(m.known_owner_of_intern(module, from, true))
385 end
386 # FIXME: I do not know what this does
387 if candidates.is_empty then return module.owner(from)
388 var max = candidates.first
389 for m in candidates do
390 if max.mhe < m then max = m
391 end
392 if as_owner and max.directory.owner == self then
393 return self
394 else
395 return max
396 end
397 end
398
399 end
400
401 redef class MMLocalProperty
402 special MMEntity
403 # Anchor of the property description in the module html file
404 fun html_anchor: String
405 do
406 return "PROP_{local_class}_{cmangle(name)}"
407 end
408
409 redef fun html_link(dctx)
410 do
411 var m = module
412 if not need_doc(dctx) then m = global.intro.module
413 m = dctx.known_owner_of(m)
414 if m == dctx.module then
415 return "<a href=\"#{html_anchor}\">{self}</a>"
416 else
417 return "<a href=\"{m}.html#{html_anchor}\">{self}</a>"
418 end
419 end
420
421 # Kind of property (fun, attr, etc.)
422 fun kind: String is abstract
423
424 redef fun locate(dctx)
425 do
426 return "in {module.html_link(dctx)}::{local_class.html_link(dctx)}"
427 end
428
429 fun known_intro_class(dctx: DocContext): MMLocalClass
430 do
431 var mod = dctx.known_owner_of(global.intro.local_class.module)
432 var cla = mod[global.intro.local_class.global]
433 return cla
434 end
435
436 redef fun prototype_head(dctx)
437 do
438 var res = new Buffer
439 var intro_class = known_intro_class(dctx)
440 var is_redef = local_class != intro_class
441
442 if is_redef then res.append("redef ")
443 if global.visibility_level == 2 then
444 res.append("protected ")
445 else if global.visibility_level == 3 then
446 res.append("private ")
447 end
448 res.append(kind)
449 if is_redef then
450 var gp = global.intro
451 if intro_class.global != local_class.global then
452 res.append(" {module[intro_class.global].html_link(dctx)}::")
453 else if intro_class.module != module then
454 res.append(" {intro_class.module.html_link(dctx)}::")
455 end
456 end
457 return res.to_s
458 end
459
460 redef fun prototype_body(dctx)
461 do
462 var res = new Buffer
463 res.append(signature.to_html(dctx, true))
464 var s = self
465 if s isa MMMethod then
466 if s.is_abstract then
467 res.append(" is abstract")
468 else if s.is_intern then
469 res.append(" is intern")
470 end
471 end
472 return res.to_s
473 end
474
475 redef fun need_doc(dctx)
476 do
477 if global.visibility_level >= 3 or self isa MMAttribute then
478 if not dctx.intrude_mode then return false
479 if dctx.module.visibility_for(module) == 0 then return false
480 end
481 if global.intro == self then
482 return true
483 end
484 return doc != null
485 end
486
487 redef fun short_doc
488 do
489 var d = doc
490 if d != null then
491 return d.short
492 else if global.intro == self then
493 return "&nbsp;"
494 else
495 return global.intro.short_doc
496 end
497 end
498
499 redef fun doc
500 do
501 var n = node
502 if n == null or not n isa APropdef then
503 return null
504 end
505 var d = n.n_doc
506 if d == null then
507 return null
508 end
509 if d.n_comment.is_empty then
510 return null
511 else
512 return d
513 end
514 end
515 end
516 redef class MMMethod
517 redef fun kind do return if global.is_init then "init" else "fun"
518 end
519 redef class MMAttribute
520 redef fun kind do return "var"
521 end
522 redef class MMTypeProperty
523 redef fun kind do return "type"
524 end
525
526 redef class MMSrcModule
527 # Extract and generate html file for the module
528 fun extract_module_doc(dctx: DocContext)
529 do
530 dctx.info("Generating HTML for module {name}",1)
531 dctx.register(self)
532
533 dctx.clear
534 extract_module_doc_inside(dctx)
535 dctx.write_to("{dctx.dir}/{name}.html")
536
537 dctx.intrude_mode = true
538 dctx.clear
539 extract_module_doc_inside(dctx)
540 dctx.write_to("{dctx.dir}/{name}__.html")
541 dctx.intrude_mode = false
542
543 if directory.owner == self then
544 dctx.inside_mode = true
545 dctx.clear
546 extract_module_doc_inside(dctx)
547 dctx.write_to("{dctx.dir}/{name}_.html")
548 dctx.inside_mode = false
549 end
550 end
551
552 fun extract_module_doc_inside(dctx: DocContext)
553 do
554 dctx.add_header("Module {self}")
555 dctx.add("<h1>Module {self}</h1>\n<dl>")
556 var s = ""
557 var d: nullable MMDirectory = directory
558 while d != null do
559 if d.owner != null and (d.owner != self or dctx.inside_mode or dctx.intrude_mode) then
560 s = "{d.owner.html_link(dctx)}::{s}"
561 end
562 d = d.parent
563 end
564 dctx.add("{s}<br/>{prototype_head(dctx)}<b>{self}</b>{prototype_body(dctx)}<br/>\n")
565
566 var strs = new Array[String]
567 var intrude_modules = new Array[MMModule]
568 var public_modules = new Array[MMModule]
569 var private_modules = new Array[MMModule]
570 var owned_modules = dctx.owned_modules
571 owned_modules.clear
572 for m in mhe.greaters do
573 var v = visibility_for(m)
574 if not dctx.inside_mode and not dctx.intrude_mode and m.directory.owner == self then
575 if v >= 2 then owned_modules.add(m)
576 continue
577 end
578 if v == 3 then
579 intrude_modules.add(m)
580 else if v == 2 then
581 public_modules.add(m)
582 else if v == 1 then
583 private_modules.add(m)
584 end
585 end
586 if not intrude_modules.is_empty then
587 var mods = mhe.order.select_smallests(intrude_modules)
588 for i in mods do strs.add(i.html_link(dctx))
589 dctx.add("<dt>Intruded modules: <dd>{strs.join(", ")}\n")
590 end
591 if not public_modules.is_empty then
592 strs.clear
593 var mods = mhe.order.select_smallests(public_modules)
594 for i in mods do strs.add(i.html_link(dctx))
595 dctx.add("<dt>Imported modules: <dd>{strs.join(", ")}\n")
596 end
597 if not private_modules.is_empty then
598 strs.clear
599 var mods = mhe.order.select_smallests(private_modules)
600 for i in mods do strs.add(i.html_link(dctx))
601 dctx.add("<dt>Privatly imported modules: <dd>{strs.join(", ")}\n")
602 end
603 dctx.add("</dl>\n")
604
605 var doc = doc
606 if doc != null then dctx.add("<pre>{doc.to_html}</pre>\n")
607
608 var new_classes = new Array[MMLocalClass]
609 for c in local_classes do
610 if c.need_doc(dctx) then
611 new_classes.add(c)
612 if c.global.intro == c then
613 dctx.register(c)
614 end
615 else
616 for m in owned_modules do
617 if m.global_classes.has(c.global) then
618 var mc = m[c.global]
619 if mc.need_doc(dctx) then
620 new_classes.add(c)
621 break
622 end
623 end
624 end
625 end
626 end
627
628 if not new_classes.is_empty then
629 dctx.sort(new_classes)
630 dctx.add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
631 dctx.add("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\"><big>Class Summary of {self}</big></th><tr>\n")
632 for c in new_classes do
633 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")
634 end
635 dctx.add("</table><br/>\n")
636 end
637
638 if not new_classes.is_empty then
639 dctx.add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
640 dctx.add("<tr bgcolor=\"#CCCCFF\"><th><big>Class Detail of {self}</big></th><tr>\n")
641 dctx.add("</table>\n")
642
643 for c in new_classes do
644 c.extract_class_doc(dctx)
645 end
646 end
647
648 dctx.add("</body></html>\n")
649 end
650
651 redef fun short_doc
652 do
653 var d = doc
654 if d != null then
655 return d.short
656 else
657 return "&nbsp;"
658 end
659 end
660
661 redef fun doc
662 do
663 var n = node
664 if n.n_packagedecl == null then
665 return null
666 end
667 var np = n.n_packagedecl
668 var d = np.n_doc
669 if d == null then
670 return null
671 end
672 if d.n_comment.is_empty then
673 return null
674 else
675 return d
676 end
677 end
678 end
679
680 redef class ADoc
681 # Html transcription of the doc
682 fun to_html: String
683 do
684 var res = new Buffer
685 for c in n_comment do
686 res.append(c.text.substring_from(1))
687 end
688 return res.to_s
689 end
690
691 # Oneliner transcription of the doc
692 fun short: String
693 do
694 return n_comment.first.text.substring_from(1)
695 end
696 end
697
698 redef class MMLocalClass
699 special MMEntity
700 # Anchor of the class description in the module html file
701 fun html_anchor: String do return "CLASS_{self}"
702
703 redef fun html_link(dctx)
704 do
705 var m = module
706 if not need_doc(dctx) then m = global.module
707 m = dctx.known_owner_of(m)
708 if m == dctx.module then
709 return "<a href=\"#{html_anchor}\">{self}</a>"
710 else
711 return "<a href=\"{m}.html#{html_anchor}\">{self}</a>"
712 end
713 end
714
715 redef fun short_doc do return global.intro.short_doc
716
717 redef fun doc do return global.intro.doc
718
719 redef fun need_doc(dctx) do
720 if module == dctx.module then
721 for m in dctx.owned_modules do
722 if m.global_classes.has(global) then
723 var c = m[global]
724 if c.need_doc(dctx) then return true
725 end
726 end
727 end
728 return false
729 end
730
731 redef fun locate(dctx) do return "in {module.html_link(dctx)}"
732
733 fun known_intro(dctx: DocContext): MMLocalClass do return dctx.known_owner_of(global.intro.module)[global]
734
735 redef fun prototype_head(dctx)
736 do
737 var res = new Buffer
738 var ki = known_intro(dctx)
739 var is_redef = ki != self
740 if is_redef then res.append("redef ")
741 if global.visibility_level == 3 then res.append("private ")
742 res.append("class ")
743 if is_redef then res.append("{ki.module.html_link(dctx)}::")
744 return res.to_s
745 end
746
747 redef fun prototype_body(dctx)
748 do
749 var res = new Buffer
750 if arity > 0 then
751 res.append("[")
752 for i in [0..arity[ do
753 var t = get_formal(i)
754 res.append(t.name.to_s)
755 res.append(": ")
756 res.append(t.bound.html_link(dctx))
757 end
758 res.append("]")
759 end
760 return res.to_s
761 end
762
763 # Extract the doc of a class
764 fun extract_class_doc(dctx: DocContext)
765 do
766 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")
767 dctx.add("<blockquote>\n")
768 dctx.add("<dl>\n")
769
770 var sup2 = new Array[String]
771 var intro_module = dctx.known_owner_of(global.module)
772 if intro_module != module then
773 dctx.add("<dt>Refine {self} from: <dd>{intro_module.html_link(dctx)}\n")
774 sup2.clear
775 var mods = new Array[MMModule]
776 for c in crhe.greaters do
777 if c.need_doc(dctx) then
778 var km = dctx.known_owner_of(c.module)
779 if km != module and km != intro_module and not mods.has(km) then
780 mods.add(km)
781 end
782 end
783 end
784 for c in crhe.linear_extension do
785 if mods.has(c.module) then sup2.add(c.module.html_link(dctx))
786 end
787 if not sup2.is_empty then dctx.add("<dt>Previous refinements in: <dd>{sup2.join(", ")}\n")
788 end
789 if not cshe.greaters.is_empty then
790 sup2.clear
791 var clas = new Array[MMLocalClass]
792 for c in cshe.direct_greaters do
793 sup2.add(c.html_link(dctx))
794 end
795 dctx.add("<dt>Direct superclasses: <dd>{sup2.join(", ")}\n")
796 sup2.clear
797 for c in cshe.linear_extension do
798 if c != self then sup2.add(c.html_link(dctx))
799 end
800 dctx.add("<dt>All superclasses: <dd>{sup2.join(", ")}\n")
801 end
802 if not cshe.direct_smallers.is_empty then
803 sup2.clear
804 for c in cshe.direct_smallers do
805 sup2.add(c.html_link(dctx))
806 end
807 dctx.add("<dt>Direct subclasses: <dd>{sup2.join(", ")}\n")
808 end
809 sup2.clear
810 for c in crhe.smallers do
811 c.compute_super_classes
812 for c2 in c.module.local_classes do
813 if not c2 isa MMConcreteClass then continue
814 c2.compute_super_classes
815 c2.compute_ancestors
816 c2.inherit_global_properties
817 end
818 for c2 in c.cshe.direct_smallers do
819 if c2.global.intro == c2 then
820 sup2.add("{c2.html_link(dctx)}")
821 end
822 end
823 end
824 if not sup2.is_empty then
825 dctx.add("<dt>Other direct subclasses in known modules: <dd>{sup2.join(", ")}\n")
826 end
827 sup2.clear
828 for c in crhe.order do
829 if not module.mhe <= c.module and c.need_doc(dctx) then
830 sup2.add(c.module.html_link(dctx))
831 end
832 end
833 if not sup2.is_empty then
834 dctx.add("<dt>Refinements in known modules: <dd>{sup2.join(", ")}\n")
835 end
836 dctx.add("</dl>\n")
837
838 var doc = doc
839 if doc != null then
840 dctx.add("<pre>{doc.to_html}</pre>\n")
841 end
842
843 var details = new Array[Array[MMLocalProperty]]
844 for i in [0..4[ do details.add(property_summary(dctx, i))
845 for i in [0..4[ do property_detail(dctx, i, details[i])
846
847 dctx.add("</blockquote><hr/>\n")
848 end
849
850 fun pass_name(pass: Int): String
851 do
852 var names = once ["Virtual Types", "Consructors", "Methods", "Attributes"]
853 return names[pass]
854 end
855
856 fun accept_prop(p: MMLocalProperty, pass: Int): Bool
857 do
858 if pass == 0 then
859 return p isa MMTypeProperty
860 else if pass == 1 then
861 return p.global.is_init
862 else if pass == 2 then
863 return p isa MMMethod and not p.global.is_init
864 else if pass == 3 then
865 return p isa MMAttribute
866 end
867 abort
868 end
869
870 fun property_summary(dctx: DocContext, pass: Int): Array[MMLocalProperty]
871 do
872 var passname = pass_name(pass)
873 dctx.open_stage
874 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
875 dctx.stage("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\">{passname} Summary of {self}</th></tr>\n")
876
877 var new_props = new Array[MMLocalProperty]
878 for g in global_properties do
879 if not accept_prop(g.intro, pass) then continue
880 if module.visibility_for(g.intro.module) < g.visibility_level then continue
881 var p = self[g]
882 if p.local_class != self or not p.need_doc(dctx) then
883 var cla = new Array[MMLocalClass]
884 for m in dctx.owned_modules do
885 if not m.global_classes.has(global) then continue
886 var c = m[global]
887 if not c isa MMConcreteClass then continue
888 if not c.has_global_property(g) then continue
889 var p2 = c[g]
890 if p2.local_class != c or not p2.need_doc(dctx) then continue
891 cla.add(c)
892 end
893 if cla.is_empty then continue
894 cla = crhe.order.select_smallests(cla)
895 end
896
897 new_props.add(p)
898 if p.global.intro == p then
899 dctx.register(p)
900 end
901 end
902 dctx.sort(new_props)
903 for p in new_props do
904 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")
905 end
906 dctx.stage("</table><br/>\n")
907
908 dctx.open_stage
909 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
910 if pass != 1 then
911 # skip pass 1 because constructors are not inherited
912 var cmap = new HashMap[MMLocalClass, Array[MMLocalProperty]]
913 var mmap = new HashMap[MMModule, Array[MMLocalProperty]]
914 for c in che.greaters do
915 if c isa MMSrcLocalClass then
916 var km = dctx.known_owner_of(c.module)
917 var kc = km[c.global]
918 if kc == self then continue
919 var props: Array[MMLocalProperty]
920 if km == module then
921 if cmap.has_key(kc) then
922 props = cmap[kc]
923 else
924 props = new Array[MMLocalProperty]
925 cmap[kc] = props
926 end
927 else
928 if mmap.has_key(km) then
929 props = mmap[km]
930 else
931 props = new Array[MMLocalProperty]
932 mmap[km] = props
933 end
934 end
935 for g in c.global_properties do
936 var p = c[g]
937 if p.local_class == c and p.need_doc(dctx) and accept_prop(p, pass) then
938 props.add(kc[g])
939 end
940 end
941 end
942 end
943 dctx.open_stage
944 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Inherited {passname}</small></th><tr>\n")
945 for c in cshe.linear_extension do
946 if not cmap.has_key(c) then continue
947 var props = cmap[c]
948 if props.is_empty then continue
949 dctx.sort(props)
950 var properties = new Array[String]
951 for p in props do properties.add(p.html_link(dctx))
952 dctx.add("<tr><td width=\"20%\"><small>from {c.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
953 end
954 dctx.close_stage
955
956 dctx.open_stage
957 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Imported {passname}</small></th><tr>\n")
958 for m in module.mhe.linear_extension do
959 if not mmap.has_key(m) then continue
960 var props = mmap[m]
961 if props.is_empty then continue
962 dctx.sort(props)
963 var properties = new Array[String]
964 for p in props do properties.add(p.html_link(dctx))
965 dctx.add("<tr><td width=\"20%\"><small>from {m.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
966 end
967 dctx.close_stage
968 end
969
970 var mmap = new HashMap[MMModule, Array[MMLocalProperty]]
971 for c in crhe.order do
972 if module.mhe <= c.module or dctx.owned_modules.has(c.module) or not c isa MMSrcLocalClass then continue
973 var km = dctx.known_owner_of(c.module)
974 if module.mhe <= km then continue
975 var kc = km[c.global]
976 var props: Array[MMLocalProperty]
977 if mmap.has_key(km) then
978 props = mmap[km]
979 else
980 props = new Array[MMLocalProperty]
981 mmap[km] = props
982 end
983 for g in c.global_properties do
984 var p = c[g]
985 if p.local_class == c and p.need_doc(dctx) and accept_prop(p, pass) then
986 var kp = kc[g]
987 if not props.has(kp) then props.add(kp)
988 end
989 end
990 # c.properties_inherited_from(dctx, self, pass)
991 end
992 dctx.open_stage
993 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Added {passname} in known modules</small></th><tr>\n")
994 for c in crhe.order do
995 var m = c.module
996 if not mmap.has_key(m) then continue
997 var props = mmap[m]
998 if props.is_empty then continue
999 dctx.sort(props)
1000 var properties = new Array[String]
1001 for p in props do properties.add(p.html_link(dctx))
1002 dctx.add("<tr><td width=\"20%\"><small>in {m.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
1003 end
1004 dctx.close_stage
1005 dctx.stage("</table><br/><br/>\n")
1006 dctx.close_stage
1007
1008 dctx.close_stage
1009 return new_props
1010 end
1011
1012 fun property_detail(dctx: DocContext, pass: Int, new_props: Array[MMLocalProperty])
1013 do
1014 var passname = pass_name(pass)
1015 dctx.open_stage
1016 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
1017 dctx.stage("<tr bgcolor=\"#CCCCFF\"><th>{passname} Detail of {self}</th><tr>\n")
1018 dctx.stage("</table>\n")
1019
1020 dctx.open_stage
1021 for p in new_props do
1022 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")
1023 dctx.add("<blockquote>")
1024 var doc = p.doc
1025 if doc != null then
1026 dctx.add("<pre>{doc.to_html}</pre>\n")
1027 end
1028 dctx.stage("</blockquote>\n")
1029 dctx.close_stage
1030
1031 dctx.open_stage
1032 dctx.stage("<hr/>\n")
1033 end
1034 dctx.close_stage
1035
1036 dctx.close_stage
1037 end
1038
1039 # Add rows for properties inheriterd to some heirs
1040 fun properties_inherited_from(dctx: DocContext, heir: MMLocalClass, pass: Int)
1041 do
1042 var properties = new Array[String]
1043 for g in global_properties do
1044 var p = self[g]
1045 if p.local_class == self and p.need_doc(dctx) and accept_prop(p, pass) then
1046 properties.add(p.html_link(dctx))
1047 end
1048 end
1049 if not properties.is_empty then
1050 var s: String
1051 if heir.global == global then
1052 s = module.html_link(dctx)
1053 else
1054 s = self.html_link(dctx)
1055 end
1056 dctx.add("<tr><td width=\"20%\"><small>in {s}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
1057 end
1058 end
1059 end
1060
1061 redef class MMSrcLocalClass
1062 redef fun short_doc
1063 do
1064 var d = doc
1065 if d != null then
1066 return d.short
1067 else if global.intro == self then
1068 return "&nbsp;"
1069 else
1070 var bc = global.intro
1071 return bc.short_doc
1072 end
1073 end
1074
1075 redef fun doc
1076 do
1077 var n = node
1078 if not n isa AStdClassdef then
1079 return null
1080 end
1081 var d = n.n_doc
1082 if d == null then
1083 return null
1084 end
1085 if d.n_comment.is_empty then
1086 return null
1087 else
1088 return d
1089 end
1090 end
1091
1092 redef fun need_doc(dctx)
1093 do
1094 if global.visibility_level >= 3 then
1095 if not dctx.intrude_mode then return false
1096 if dctx.module.visibility_for(module) == 0 then return false
1097 end
1098 if global.intro == self then
1099 return true
1100 end
1101 for p in src_local_properties do
1102 if p.need_doc(dctx) then
1103 return true
1104 end
1105 end
1106 return super
1107 end
1108 end
1109
1110 redef class MMSignature
1111 # Htlm transcription of the signature (with nested links)
1112 fun to_html(dctx: DocContext, with_closure: Bool): String
1113 do
1114 var res = new Buffer
1115 if arity > 0 then
1116 res.append("(")
1117 res.append(self[0].html_link(dctx))
1118 for i in [1..arity[ do
1119 res.append(", ")
1120 res.append(self[i].html_link(dctx))
1121 end
1122 res.append(")")
1123 end
1124 if return_type != null then
1125 res.append(": ")
1126 res.append(return_type.html_link(dctx))
1127 end
1128 if with_closure then
1129 for c in closures do
1130 res.append(" ")
1131 if c.is_optional then res.append("[")
1132 if c.is_break then res.append("break ")
1133 res.append("!{c.name}")
1134 res.append(c.signature.to_html(dctx, false))
1135 if c.is_optional then res.append("]")
1136 end
1137 end
1138 return res.to_s
1139 end
1140 end
1141
1142 redef class MMType
1143 # Htlm transcription of the type (with nested links)
1144 fun html_link(dctx: DocContext): String do return to_s
1145 end
1146
1147 redef class MMTypeSimpleClass
1148 redef fun html_link(dctx) do return local_class.html_link(dctx)
1149 end
1150
1151 redef class MMTypeGeneric
1152 redef fun html_link(dctx)
1153 do
1154 var res = new Buffer
1155 res.append(local_class.html_link(dctx))
1156 res.append("[")
1157 res.append(params[0].html_link(dctx))
1158 for i in [1..params.length[ do
1159 res.append(", ")
1160 res.append(params[i].html_link(dctx))
1161 end
1162 res.append("]")
1163 return res.to_s
1164 end
1165 end
1166
1167 var c = new DocContext
1168 c.exec_cmd_line