parser: rename package-related classes and properties
[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 mmmodule
69 readable var _mmmodule: 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 _mmmodule = 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 _mmmodule = 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 mod = mmmodule
191 if (not inside_mode and not intrude_mode) or mod == null then
192 add("<b>Public</b>&nbsp; ")
193 else
194 add("<a href=\"{mod}.html\"><b>Public</b></a>&nbsp; ")
195 end
196 if inside_mode or mod == null then
197 add("<b>Inside</b>&nbsp; ")
198 else if mod.directory.owner != mod then
199 add("<strike><b>Inside</b></strike>&nbsp; ")
200 else
201 add("<a href=\"{mod}_.html\"><b>Inside</b></a>&nbsp; ")
202 end
203 if intrude_mode or mod == null then
204 add("<b>Intrude</b>&nbsp; ")
205 else
206 add("<a href=\"{mod}__.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 mod = mmmodule
227 if mod == null then return m
228 var res = mod.known_owner_of(m)
229 if not inside_mode and not intrude_mode and res.directory.owner == mod then
230 return mod
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.mmmodule == 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(mod: MMModule): MMModule
349 do
350 if _known_owner_of_cache.has_key(mod) then return _known_owner_of_cache[mod]
351 var res = mod
352 # is module is publicly imported by self?
353 if mhe < mod and visibility_for(mod) != 0 then
354 res = known_owner_of_intern(mod, self, false)
355 else
356 # Return the canonnical owner of module from the point of view of self
357 res = mod.owner(self)
358 end
359 _known_owner_of_cache[mod] = 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(mod: MMModule, from: MMModule, as_owner: Bool): MMModule
378 do
379 if mod == 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 <= mod then continue
384 candidates.add(m.known_owner_of_intern(mod, from, true))
385 end
386 # FIXME: I do not know what this does
387 if candidates.is_empty then return mod.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 = mmmodule
412 if not need_doc(dctx) then m = global.intro.mmmodule
413 m = dctx.known_owner_of(m)
414 if m == dctx.mmmodule 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 {mmmodule.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.mmmodule)
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(" {mmmodule[intro_class.global].html_link(dctx)}::")
453 else if intro_class.mmmodule != mmmodule then
454 res.append(" {intro_class.mmmodule.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.mmmodule.visibility_for(mmmodule) == 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_moduledecl == null then
665 return null
666 end
667 var np = n.n_moduledecl
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 = mmmodule
706 if not need_doc(dctx) then m = global.mmmodule
707 m = dctx.known_owner_of(m)
708 if m == dctx.mmmodule 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 mmmodule == dctx.mmmodule 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 {mmmodule.html_link(dctx)}"
732
733 fun known_intro(dctx: DocContext): MMLocalClass do return dctx.known_owner_of(global.intro.mmmodule)[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.mmmodule.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>{mmmodule.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.mmmodule)
772 if intro_module != mmmodule 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.mmmodule)
779 if km != mmmodule 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.mmmodule) then sup2.add(c.mmmodule.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.mmmodule.local_classes do
813 if not c2 isa MMConcreteClass then continue
814 c2.compute_super_classes
815 c2.compute_ancestors
816 end
817 for c2 in c.cshe.direct_smallers do
818 if c2.global.intro == c2 then
819 sup2.add("{c2.html_link(dctx)}")
820 end
821 end
822 end
823 if not sup2.is_empty then
824 dctx.add("<dt>Other direct subclasses in known modules: <dd>{sup2.join(", ")}\n")
825 end
826 sup2.clear
827 for c in crhe.order do
828 if not mmmodule.mhe <= c.mmmodule and c.need_doc(dctx) then
829 sup2.add(c.mmmodule.html_link(dctx))
830 end
831 end
832 if not sup2.is_empty then
833 dctx.add("<dt>Refinements in known modules: <dd>{sup2.join(", ")}\n")
834 end
835 dctx.add("</dl>\n")
836
837 var doc = doc
838 if doc != null then
839 dctx.add("<pre>{doc.to_html}</pre>\n")
840 end
841
842 var details = new Array[Array[MMLocalProperty]]
843 for i in [0..4[ do details.add(property_summary(dctx, i))
844 for i in [0..4[ do property_detail(dctx, i, details[i])
845
846 dctx.add("</blockquote><hr/>\n")
847 end
848
849 fun pass_name(pass: Int): String
850 do
851 var names = once ["Virtual Types", "Consructors", "Methods", "Attributes"]
852 return names[pass]
853 end
854
855 fun accept_prop(p: MMLocalProperty, pass: Int): Bool
856 do
857 if pass == 0 then
858 return p isa MMTypeProperty
859 else if pass == 1 then
860 return p.global.is_init
861 else if pass == 2 then
862 return p isa MMMethod and not p.global.is_init
863 else if pass == 3 then
864 return p isa MMAttribute
865 end
866 abort
867 end
868
869 fun property_summary(dctx: DocContext, pass: Int): Array[MMLocalProperty]
870 do
871 var passname = pass_name(pass)
872 dctx.open_stage
873 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
874 dctx.stage("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\">{passname} Summary of {self}</th></tr>\n")
875
876 var new_props = new Array[MMLocalProperty]
877 for g in global_properties do
878 if not accept_prop(g.intro, pass) then continue
879 if mmmodule.visibility_for(g.intro.mmmodule) < g.visibility_level then continue
880 var p = self[g]
881 if p.local_class != self or not p.need_doc(dctx) then
882 var cla = new Array[MMLocalClass]
883 for m in dctx.owned_modules do
884 if not m.global_classes.has(global) then continue
885 var c = m[global]
886 if not c isa MMConcreteClass then continue
887 if not c.has_global_property(g) then continue
888 var p2 = c[g]
889 if p2.local_class != c or not p2.need_doc(dctx) then continue
890 cla.add(c)
891 end
892 if cla.is_empty then continue
893 cla = crhe.order.select_smallests(cla)
894 end
895
896 new_props.add(p)
897 if p.global.intro == p then
898 dctx.register(p)
899 end
900 end
901 dctx.sort(new_props)
902 for p in new_props do
903 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")
904 end
905 dctx.stage("</table><br/>\n")
906
907 dctx.open_stage
908 dctx.stage("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
909 if pass != 1 then
910 # skip pass 1 because constructors are not inherited
911 var cmap = new HashMap[MMLocalClass, Array[MMLocalProperty]]
912 var mmap = new HashMap[MMModule, Array[MMLocalProperty]]
913 for c in che.greaters do
914 if c isa MMSrcLocalClass then
915 var km = dctx.known_owner_of(c.mmmodule)
916 var kc = km[c.global]
917 if kc == self then continue
918 var props: Array[MMLocalProperty]
919 if km == mmmodule then
920 if cmap.has_key(kc) then
921 props = cmap[kc]
922 else
923 props = new Array[MMLocalProperty]
924 cmap[kc] = props
925 end
926 else
927 if mmap.has_key(km) then
928 props = mmap[km]
929 else
930 props = new Array[MMLocalProperty]
931 mmap[km] = props
932 end
933 end
934 for g in c.global_properties do
935 var p = c[g]
936 if p.local_class == c and p.need_doc(dctx) and accept_prop(p, pass) then
937 props.add(kc[g])
938 end
939 end
940 end
941 end
942 dctx.open_stage
943 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Inherited {passname}</small></th><tr>\n")
944 for c in cshe.linear_extension do
945 if not cmap.has_key(c) then continue
946 var props = cmap[c]
947 if props.is_empty then continue
948 dctx.sort(props)
949 var properties = new Array[String]
950 for p in props do properties.add(p.html_link(dctx))
951 dctx.add("<tr><td width=\"20%\"><small>from {c.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
952 end
953 dctx.close_stage
954
955 dctx.open_stage
956 dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Imported {passname}</small></th><tr>\n")
957 for m in mmmodule.mhe.linear_extension do
958 if not mmap.has_key(m) then continue
959 var props = mmap[m]
960 if props.is_empty then continue
961 dctx.sort(props)
962 var properties = new Array[String]
963 for p in props do properties.add(p.html_link(dctx))
964 dctx.add("<tr><td width=\"20%\"><small>from {m.html_link(dctx)}</small></td><td><small>{properties.join(", ")}</small></td><tr>\n")
965 end
966 dctx.close_stage
967 end
968
969 var mmap = new HashMap[MMModule, Array[MMLocalProperty]]
970 for c in crhe.order do
971 if mmmodule.mhe <= c.mmmodule or dctx.owned_modules.has(c.mmmodule) or not c isa MMSrcLocalClass then continue
972 var km = dctx.known_owner_of(c.mmmodule)
973 if mmmodule.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.mmmodule
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.mmmodule.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 = mmmodule.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 var d = n.n_doc
1081 if d == null then
1082 return null
1083 end
1084 if d.n_comment.is_empty then
1085 return null
1086 else
1087 return d
1088 end
1089 end
1090
1091 redef fun need_doc(dctx)
1092 do
1093 if global.visibility_level >= 3 then
1094 if not dctx.intrude_mode then return false
1095 if dctx.mmmodule.visibility_for(mmmodule) == 0 then return false
1096 end
1097 if global.intro == self then
1098 return true
1099 end
1100 for p in src_local_properties do
1101 if p.need_doc(dctx) then
1102 return true
1103 end
1104 end
1105 return super
1106 end
1107 end
1108
1109 redef class MMSignature
1110 # Htlm transcription of the signature (with nested links)
1111 fun to_html(dctx: DocContext, with_closure: Bool): String
1112 do
1113 var res = new Buffer
1114 if arity > 0 then
1115 res.append("(")
1116 res.append(self[0].html_link(dctx))
1117 for i in [1..arity[ do
1118 res.append(", ")
1119 res.append(self[i].html_link(dctx))
1120 end
1121 res.append(")")
1122 end
1123 if return_type != null then
1124 res.append(": ")
1125 res.append(return_type.html_link(dctx))
1126 end
1127 if with_closure then
1128 for c in closures do
1129 res.append(" ")
1130 if c.is_optional then res.append("[")
1131 if c.is_break then res.append("break ")
1132 res.append("!{c.name}")
1133 res.append(c.signature.to_html(dctx, false))
1134 if c.is_optional then res.append("]")
1135 end
1136 end
1137 return res.to_s
1138 end
1139 end
1140
1141 redef class MMType
1142 # Htlm transcription of the type (with nested links)
1143 fun html_link(dctx: DocContext): String do return to_s
1144 end
1145
1146 redef class MMTypeSimpleClass
1147 redef fun html_link(dctx) do return local_class.html_link(dctx)
1148 end
1149
1150 redef class MMTypeGeneric
1151 redef fun html_link(dctx)
1152 do
1153 var res = new Buffer
1154 res.append(local_class.html_link(dctx))
1155 res.append("[")
1156 res.append(params[0].html_link(dctx))
1157 for i in [1..params.length[ do
1158 res.append(", ")
1159 res.append(params[i].html_link(dctx))
1160 end
1161 res.append("]")
1162 return res.to_s
1163 end
1164 end
1165
1166 var c = new DocContext
1167 c.exec_cmd_line