nitdoc: handle vararg in signature
[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 super AbstractCompiler
28 # Destination directory
29 readable writable var _dir: String = "doc"
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 # Start a new file
69 fun clear
70 do
71 _stage_context = new StageContext(null)
72 end
73
74 # Sorter of entities in alphabetical order
75 var _sorter: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity]
76
77 # Sort entities in the alphabetical order
78 fun sort(array: Array[MMEntity])
79 do
80 _sorter.sort(array)
81 end
82
83 readable var _opt_dir: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir")
84 readable var _opt_source: OptionString = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source")
85 readable var _opt_public: OptionBool = new OptionBool("Generate only the public API", "--public")
86 readable var _opt_private: OptionBool = new OptionBool("Generate the private API", "--private")
87 readable var _opt_nodot: OptionBool = new OptionBool("Do not generate graphes with graphviz", "--no-dot")
88 readable var _opt_sharedir: OptionString = new OptionString("Directory containing the nitdoc files", "--sharedir")
89 var sharedir: nullable String
90
91 fun public_only: Bool
92 do
93 if self._opt_public.value == true then return true
94 return false
95 end
96
97 fun with_private: Bool
98 do
99 if self._opt_private.value == true then return true
100 return false
101 end
102
103 # The current processed filename
104 var filename: String
105
106 # The main virtual module
107 var mainmod: nullable MMVirtualModule
108
109 redef fun perform_work(mods)
110 do
111 mainmod = new MMVirtualModule(self, mods)
112
113 dir.mkdir
114
115 sys.system("cp -r '{sharedir.to_s}'/* {dir}/")
116
117 # Compute the set of direct owned nested modules
118 var owns = new HashMap[MMModule, Array[MMModule]]
119 for mod in modules do
120 owns[mod] = new Array[MMModule]# [mod]
121 end
122 for mod in modules do
123 if mod == mainmod then continue
124 var d = mod.directory
125 loop
126 var o = d.owner
127 if o != null and o != mod then
128 owns[o].add(mod)
129 end
130 var dp = d.parent
131 if dp == null or dp == d then break
132 d = dp
133 end
134 end
135
136 # Builds the various module hierarchies
137 var mnh = new PartialOrder[MMModule] # nested module hierarchy
138 var tmh = new PartialOrder[MMModule] # top module import hierrchy
139 var ms = mainmod.mhe.linear_extension.reversed
140 for m in ms do
141 if ms == mainmod then continue
142 m.mnhe_ = mnh.add(m, owns[m])
143 var pub = new Array[MMModule]
144 for m2 in m.mhe.greaters do
145 if m2.toplevel_owner != m2 and m2.toplevel_owner != m.toplevel_owner then continue
146 if m.mnhe <= m2 then continue
147 if m.visibility_for(m2) <= 0 then
148 # nothing
149 else if m.visibility_for(m2) == 1 then
150 else
151 pub.add(m2)
152 end
153 end
154 m.tmhe_ = tmh.add(m, pub)
155 end
156
157 var head = "<meta charset=\"utf-8\">" +
158 "<script type=\"text/javascript\" src=\"scripts/jquery-1.7.1.min.js\"></script>\n" +
159 "<script type=\"text/javascript\" src=\"scripts/js-facilities.js\"></script>\n" +
160 "<link rel=\"stylesheet\" href=\"styles/main.css\" type=\"text/css\" media=\"screen\" />"
161
162 var action_bar = "<header><nav class='main'><ul><li class=\"current\">Overview</li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
163
164 # generate the index
165 self.filename = "index.html"
166 clear
167 add("<!DOCTYPE html>")
168 add("<html><head>{head}<title>Index</title></head><body>\n")
169 add(action_bar)
170 add("<div class=\"page\">")
171 add("<div class=\"content fullpage\">")
172 add("<h1>Modules</h1>\n<article class='overview'><ul>")
173 var modss = mainmod.mhe.greaters_and_self.to_a
174 sort(modss)
175 for mod in modss do
176 if not mod.is_toplevel then continue
177 if not mod.require_doc(self) then continue
178 assert mod isa MMSrcModule
179 add("<li>{mod.html_link(self)} {mod.short_doc}</li>")
180
181 end
182 add("</ul>")
183
184 var op = new Buffer
185 op.append("digraph dep \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
186 for mod in modss do
187 if not mod.is_toplevel then continue
188 if not mod.require_doc(self) then continue
189 op.append("\"{mod.name}\"[URL=\"{mod.html_name}.html\"];\n")
190 for mod2 in mod.tmhe.direct_greaters do
191 if not modss.has(mod2) then continue
192 op.append("\"{mod.name}\"->\"{mod2.name}\";\n")
193 end
194 end
195 op.append("\}\n")
196 self.gen_dot(op.to_s, "dep", "Modules hierarchy")
197 add("</article></div>")
198 add("<div class='clear'></div>")
199 add("</div>")
200 add("</body></html>\n")
201 write_to("{dir}/index.html")
202
203 # Generate page for modules
204 for mod in modules do
205 if mod == mainmod then continue
206 assert mod isa MMSrcModule
207 if not mod.require_doc(self) then continue
208 self.filename = mod.html_name
209 action_bar = "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li class=\"current\">{mod.name}</li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
210 clear
211 add("<!DOCTYPE html>")
212 add("<html><head>{head}<title>Module {mod.name}</title></head><body>\n")
213 add(action_bar)
214 add("<div class=\"page\">")
215 mod.file_page_doc(self)
216 add("</div>")
217 add("</body></html>\n")
218 write_to("{dir}/{mod.html_name}.html")
219 end
220
221 # Generate pages for global classes
222 for c in mainmod.local_classes do
223 if not c.require_doc(self) then continue
224 self.filename = c.html_name
225 action_bar = "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li>{c.global.intro.mmmodule.toplevel_owner.html_link(self)}</li><li class=\"current\">{c.name}</li><li><a href='full-index.html'>Full Index</a></li></ul></nav></header>\n"
226 clear
227 add("<!DOCTYPE html>")
228 add("<html><head>{head}<title>Class {c.name}</title></head><body>\n")
229 add(action_bar)
230 add("<div class=\"page\">")
231 c.file_page_doc(self)
232 add("</div>")
233 add("</body></html>\n")
234 write_to("{dir}/{c.html_name}.html")
235 end
236
237 self.filename = "fullindex"
238 action_bar = "<header><nav class='main'><ul><li><a href='./'>Overview</a></li><li class=\"current\">Full Index</li></ul></nav></header>\n"
239 clear
240 add("<!DOCTYPE html>")
241 add("<html><head>{head}<title>Full Index</title></head><body>\n")
242 add(action_bar)
243 add("<div class=\"page\">")
244 add("<div class=\"content fullpage\">")
245 mainmod.file_index_page_doc(self)
246 add("</div>")
247 add("</div>")
248 add("</body></html>\n")
249 write_to("{dir}/full-index.html")
250 end
251
252
253 # Add a (source) link fo a given location
254 fun show_source(l: Location)
255 do
256 var s = opt_source.value
257 if s == null then
258 add("in #{l.file.filename.simplify_path}")
259 else
260 # THIS IS JUST UGLY ! (but there is no replace yet)
261 var x = s.split_with("%f")
262 s = x.join(l.file.filename.simplify_path)
263 x = s.split_with("%l")
264 s = x.join(l.line_start.to_s)
265 x = s.split_with("%L")
266 s = x.join(l.line_end.to_s)
267 add(" (<a href=\"{s}\">show code</a>)")
268 end
269 end
270
271 # Generate a clicable graphiz image using a dot content.
272 # `name' refer to the filename (without extension) and the id name of the map.
273 # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...)
274 fun gen_dot(dot: String, name: String, alt: String)
275 do
276 if opt_nodot.value then return
277 var f = new OFStream.open("{self.dir}/{name}.dot")
278 f.write(dot)
279 f.close
280 sys.system("\{ test -f {self.dir}/{name}.png && test -f {self.dir}/{name}.s.dot && diff {self.dir}/{name}.dot {self.dir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {self.dir}/{name}.dot {self.dir}/{name}.s.dot && dot -Tpng -o{self.dir}/{name}.png -Tcmapx -o{self.dir}/{name}.map {self.dir}/{name}.s.dot ; \}")
281 self.add("<article class=\"graph\"><img src=\"{name}.png\" usemap=\"#{name}\" style=\"margin:auto\" alt=\"{alt}\"/></article>")
282 var fmap = new IFStream.open("{self.dir}/{name}.map")
283 self.add(fmap.read_all)
284 fmap.close
285 end
286
287 init
288 do
289 keep_ast = true
290 super("nitdoc")
291 filename = "-unset-"
292 option_context.add_option(opt_public)
293 option_context.add_option(opt_private)
294 option_context.add_option(opt_dir)
295 option_context.add_option(opt_source)
296 option_context.add_option(opt_nodot)
297 option_context.add_option(opt_sharedir)
298 end
299
300 redef fun process_options
301 do
302 super
303 var d = opt_dir.value
304 if d != null then dir = d
305
306 if not opt_nodot.value then
307 # Test if dot is runable
308 var res = sys.system("sh -c dot </dev/null >/dev/null 2>&1")
309 if res != 0 then
310 stderr.write "--no-dot implied since `dot' is not available. Try to install graphviz.\n"
311 opt_nodot.value = true
312 end
313 end
314
315 sharedir = opt_sharedir.value
316 if sharedir == null then
317 var dir = once ("NIT_DIR".to_symbol).environ
318 if dir.is_empty then
319 dir = "{sys.program_name.dirname}/../share/nitdoc"
320 if dir.file_exists then sharedir = dir
321 else
322 dir = "{dir}/share/nitdoc"
323 if dir.file_exists then sharedir = dir
324 end
325 if sharedir == null then
326 fatal_error(null, "Error: Cannot locate nitdoc shared files. Uses --sharedir or envvar NIT_DIR.")
327 end
328 dir = "{sharedir.to_s}/scripts/js-facilities.js"
329 if sharedir == null then
330 fatal_error(null, "Error: Invalid nitdoc shared files. Check --sharedir or envvar NIT_DIR.")
331 end
332
333 end
334 end
335
336 redef fun handle_property_conflict(lc, impls)
337 do
338 # THIS IS SO UGLY! See MMVirtualModule
339 if lc.mmmodule == self.mainmod then
340 return # We just accept, so one in impls is arbitrary inherited
341 end
342 super
343 end
344 end
345
346 redef class String
347 # Replace all occurence of pattern ith string
348 fun replace(p: Pattern, string: String): String
349 do
350 return self.split_with(p).join(string)
351 end
352
353 # Escape the following characters < > & and " with their html counterpart
354 fun html_escape: String
355 do
356 var ret = self
357 if ret.has('&') then ret = ret.replace('&', "&amp;")
358 if ret.has('<') then ret = ret.replace('<', "&lt;")
359 if ret.has('>') then ret = ret.replace('>', "&gt;")
360 if ret.has('"') then ret = ret.replace('"', "&quot;")
361 return ret
362 end
363
364 # Remove "/./", "//" and "bla/../"
365 fun simplify_path: String
366 do
367 var a = self.split_with("/")
368 var a2 = new Array[String]
369 for x in a do
370 if x == "." then continue
371 if x == "" and not a2.is_empty then continue
372 if x == ".." and not a2.is_empty then
373 a2.pop
374 continue
375 end
376 a2.push(x)
377 end
378 return a2.join("/")
379 end
380 end
381
382 # A virtual module is used to work as an implicit main module that combine unrelated modules
383 # Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled
384 class MMVirtualModule
385 super MMModule
386 init(ctx: MMContext, mods: Array[MMModule])
387 do
388 # We need to compute the whole metamodel since there is no mmbuilder to do it
389 super(" main".to_symbol, mods.first.directory, ctx, new Location(null,0,0,0,0))
390 ctx.add_module(self, mods)
391 for m in mods do
392 self.add_super_module(m, 1)
393 end
394 self.import_global_classes
395 self.import_local_classes
396 for c in self.local_classes do
397 c.compute_super_classes
398 end
399 for c in self.local_classes do
400 c.compute_ancestors
401 end
402
403 end
404 redef fun require_doc(dctx) do return false
405 end
406
407 # Conditionnal part of the text content of a DocContext
408 class StageContext
409 # Content of the current stage
410 readable var _content: Array[String] = new Array[String]
411
412 # Is a normal string already added?
413 readable writable var _validate: Bool = false
414
415 # Parent stage is any
416 readable var _parent: nullable StageContext = null
417
418 init(parent: nullable StageContext) do _parent = parent
419 end
420
421
422 # Efficiently sort object with their to_s method
423 class AlphaSorter[E: Object]
424 super AbstractSorter[E]
425 redef fun compare(a, b)
426 do
427 var sa: String
428 var sb: String
429 var d = _dico
430 if d.has_key(a) then
431 sa = d[a]
432 else
433 sa = a.to_s
434 d[a] = sa
435 end
436 if d.has_key(b) then
437 sb = d[b]
438 else
439 sb = b.to_s
440 d[b] = sb
441 end
442 return sa <=> sb
443 end
444
445 # Keep track of to_s values
446 var _dico: HashMap[Object, String] = new HashMap[Object, String]
447
448 init do end
449 end
450
451 # Generalization of metamodel entities
452 class MMEntity
453 # Return a link to
454 fun html_link(dctx: DocContext): String is abstract
455
456 # Return a one liner description
457 fun short_doc: String do return "&nbsp;"
458
459 # The doc node from the AST
460 # Return null is none
461 fun doc: nullable ADoc do return null
462 end
463
464 redef class MMModule
465 super MMEntity
466 redef fun html_link(dctx) do
467 return "<a href=\"{html_name}.html\" title=\"{short_doc}\">{self}</a>"
468 end
469
470 fun require_doc(dctx: DocContext): Bool
471 do
472 if dctx.public_only and not is_toplevel then return false
473 return true
474 end
475
476 # Return true if the module is a top-level owner or a top-level module
477 fun is_toplevel: Bool
478 do
479 var pd = directory.parent
480 return pd == null or (pd.owner == null and directory.owner == self)
481 end
482
483 # Element in the module nesting tree
484 fun mnhe: PartialOrderElement[MMModule] do return mnhe_.as(not null)
485 var mnhe_: nullable PartialOrderElement[MMModule] = null
486
487 # Element in the top level module importation hierarchy
488 fun tmhe: PartialOrderElement[MMModule] do return tmhe_.as(not null)
489 var tmhe_: nullable PartialOrderElement[MMModule] = null
490
491 fun toplevel_owner: MMModule
492 do
493 var m = self
494 loop
495 var ds = m.mnhe.direct_smallers
496 if ds.length == 0 then return m
497 if ds.length == 1 then m = ds.first else abort
498 end
499 end
500
501 fun html_name: String
502 do
503 return "{name}"
504 end
505
506 fun direct_owner: nullable MMModule
507 do
508 var d = directory
509 while d.owner == self do d = d.parent.as(not null)
510 return d.owner
511 end
512
513 # Fill the body for the page associated to the module
514 fun file_page_doc(dctx: DocContext)
515 do
516 dctx.add("<div class=\"menu\">\n")
517
518 var mods = new Array[MMModule]
519 mods = self.mhe.greaters.to_a
520 dctx.sort(mods)
521
522 dctx.open_stage
523 dctx.stage("<nav>\n")
524 dctx.stage("<h3>Module Hierarchy</h3>\n")
525 dctx.stage("<h4>All dependencies</h4>\n")
526 dctx.stage("<ul>\n")
527 for mod in mods do
528 if not mod.require_doc(dctx) then continue
529 if self.mnhe <= mod then continue # do not want nested stuff
530 if mod.direct_owner != null and not mod.direct_owner.mnhe <= self then continue # not in the right nesting
531 dctx.add("<li>{mod.html_link(dctx)}</li>")
532 end
533 dctx.stage("</ul>\n")
534
535 mods = self.mhe.smallers.to_a
536 dctx.sort(mods)
537 dctx.stage("<h4>All clients</h4>\n")
538 dctx.stage("<ul>\n")
539 for mod in mods do
540 if not mod.require_doc(dctx) then continue
541 if self.mnhe <= mod then continue # do not want nested stuff
542 if mod.direct_owner != null and not mod.direct_owner.mnhe <= self then continue # not in the right nesting
543 dctx.add("<li>{mod.html_link(dctx)}</li>")
544 end
545 dctx.stage("</ul>\n")
546 dctx.stage("</nav>\n")
547 dctx.close_stage
548
549 if not dctx.public_only then
550 mods = self.mnhe.direct_greaters.to_a
551 dctx.sort(mods)
552 dctx.open_stage
553 dctx.stage("<nav>\n")
554 dctx.stage("<h3>Nested Modules</h3><ul>\n")
555 for mod in mods do
556 if not mod.require_doc(dctx) then continue
557 dctx.add("<li>{mod.html_link(dctx)}</li>")
558 end
559 dctx.stage("</ul></nav>\n")
560 dctx.close_stage
561 end
562
563 dctx.add("</div>") # metadata
564
565 dctx.add("<div class=\"content\">\n")
566 dctx.add("<h1>{name}</h1>\n")
567 dctx.add("<div class='subtitle'>module ")
568 for m in mnhe.smallers do
569 dctx.add("{m.html_link(dctx)}::")
570 end
571 dctx.add("{self.name}</div>\n")
572
573 dctx.add("<section class='description'>\n")
574
575 var doc = doc
576 if doc != null then
577 dctx.add("<div id=\"description\">\n")
578 dctx.add("<pre>{doc.to_html}</pre>\n")
579 dctx.add("</div>\n")
580 end
581
582 var op = new Buffer
583 op.append("digraph {name} \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
584 var ms = new Array[nullable MMModule]
585 do
586 var m0: nullable MMModule = self
587 while m0 != null do
588 m0 = m0.direct_owner
589 ms.add(m0)
590 end
591 end
592 var cla = new HashSet[MMModule]
593 cla.add(self)
594 for m0 in self.mhe.greaters do
595 if not m0.require_doc(dctx) then continue
596 if self.visibility_for(m0) <= 1 then continue # private or hidden
597 if self.mnhe <= m0 then continue # do not want nested stuff
598 if m0.direct_owner != null and not m0.direct_owner.mnhe <= self then continue # not in the right nesting
599 cla.add(m0)
600 end
601 for m0 in self.mhe.smallers do
602 if not m0.require_doc(dctx) then continue
603 if m0.visibility_for(self) <= 1 then continue # private or hidden
604 if m0.direct_owner != null and not m0.direct_owner.mnhe <= self then continue # not in the right nesting
605 cla.add(m0)
606 end
607 for m0 in self.mnhe.smallers do
608 cla.add(m0)
609 end
610 ms = ms.reversed
611 for m0 in ms do
612 if m0 != null then
613 op.append("subgraph \"cluster_{m0.name}\"\{\n")
614 end
615 for c in cla do
616 if c.direct_owner != m0 then continue
617 if c == self then
618 op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
619 else
620 op.append("\"{c.name}\"[URL=\"{c.html_name}.html\"];\n")
621 end
622 end
623 if m0 != null then
624 op.append("\"{m0.name}\"[URL=\"{m0.html_name}.html\"];\n")
625 for c in m0.mhe.direct_greaters do
626 if not cla.has(c) then continue
627 op.append("\"{m0.name}\"->\"{c.name}\";\n")
628 end
629 end
630 end
631 for m0 in ms do
632 # Close the nesting subgraph
633 if m0 != null then
634 op.append("\}\n")
635 end
636 end
637 for c in cla do
638 for c2 in c.tmhe.direct_greaters do
639 if not cla.has(c2) then continue
640 op.append("\"{c.name}\"->\"{c2.name}\";\n")
641 end
642 end
643 op.append("\}\n")
644 dctx.gen_dot(op.to_s, name.to_s, "Dependency graph for module {name}")
645 dctx.add("</section>")
646
647 var clas = new Array[MMLocalClass]
648 var props = new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
649 var gprops = new Array[MMLocalProperty]
650 do
651 var m = self
652 for g in m.global_classes do
653 var lc = m[g]
654 if not lc.require_doc(dctx) then continue
655 var im = g.intro.mmmodule
656 if self.visibility_for(im) <= 1 then continue # private import or invisible import
657 var keep = false
658 for lc2 in lc.crhe.greaters_and_self do
659 if not lc2 isa MMSrcLocalClass then continue
660 if not self.mnhe <= lc2.mmmodule then continue # not introduced/redefined here/stolen
661 keep = true
662 end
663 if not keep then continue
664 clas.add(self[g])
665 lc.compute_super_classes
666 for gp in lc.global_properties do
667 if self.visibility_for(gp.intro.local_class.mmmodule) <= 1 then continue # private import or invisible import
668 var lp = lc[gp]
669 var mp = lp.local_class.mmmodule
670 if not self.mnhe <= mp then continue # not introduced/redefined here/stolen
671 lp = self[g][gp]
672 if not lp.require_doc(dctx) then continue
673 if props.has_key(lp.global) then
674 if not props[lp.global].has(lp) then
675 props[lp.global].add(lp)
676 end
677 else
678 props[lp.global] = [lp]
679 gprops.add(lp.global.intro)
680 end
681 end
682 end
683 end
684 dctx.add("<section class=\"module\">\n")
685 dctx.open_stage
686 dctx.stage("<article class=\"classes filterable\">\n")
687 dctx.stage("<h2>Classes</h2>\n")
688 dctx.sort(clas)
689 dctx.stage("<ul>\n")
690 for lc in clas do
691 if self.mnhe <= lc.global.intro.mmmodule then
692 dctx.add("<li class='intro'><span title='introduced in this module'>I</span>&nbsp;")
693 else
694 dctx.add("<li class='redef'><span title='refined in this module'>R</span>&nbsp;")
695 end
696 dctx.add("{lc.html_link(dctx)}</li>\n")
697 end
698 dctx.stage("</ul></article>\n")
699 dctx.close_stage
700
701 dctx.open_stage
702 dctx.stage("<article class=\"properties filterable\">\n")
703 dctx.stage("<h2>Properties</h2>\n")
704 dctx.sort(gprops)
705 dctx.stage("<ul>\n")
706 for lgp in gprops do
707 var gp = lgp.global
708 var lps = props[gp]
709
710 if gp.intro isa MMAttribute then continue
711
712 var lpi = self[gp.intro.local_class.global][gp]
713
714 if lps.has(lpi) then
715 dctx.add("<li class='intro'><span title='introduction in an other module'>I</span>&nbsp;{lpi.html_open_link(dctx)}{lpi.html_name}&nbsp;({lpi.local_class})</a></li>\n")
716 lps.remove(lpi)
717 else
718 dctx.add("<li class='intro'><span title='introduction in this module'>I</span>&nbsp;{lpi.html_name}")
719 dctx.add("&nbsp;({lpi.local_class})</li>\n")
720 end
721 if lps.length >= 1 then
722 dctx.sort(lps)
723 for lp in lps do
724 dctx.add("<li class='redef'><span title='redefinition'>R</span>&nbsp;{lp.html_open_link(dctx)}{lp.html_name}&nbsp;({lp.local_class})</a></li>")
725 end
726 end
727 end
728 dctx.stage("</ul></article>\n")
729 dctx.close_stage
730 dctx.add("</section>\n")
731 dctx.add("</div>\n")
732 end
733
734 # Fill the body for the page associated to the full index
735 fun file_index_page_doc(dctx: DocContext)
736 do
737
738 dctx.add("<h1>Full Index</h1>\n")
739
740 var clas = new Array[MMLocalClass]
741 var props = new HashMap[MMGlobalProperty, Array[MMLocalProperty]]
742 var gprops = new Array[MMLocalProperty]
743 var mods = new Array[MMModule]
744 for m in mhe.greaters_and_self do
745 if not m.require_doc(dctx) then continue
746 mods.add(m)
747 end
748 for g in global_classes do
749 var lc = self[g]
750 if not lc.require_doc(dctx) then continue
751 clas.add(lc)
752 for gp in lc.global_properties do
753 var lp = lc[gp]
754 if not lp.require_doc(dctx) then continue
755 if props.has_key(lp.global) then
756 if not props[lp.global].has(lp) then
757 props[lp.global].add(lp)
758 end
759 else
760 props[lp.global] = [lp]
761 gprops.add(lp.global.intro)
762 end
763 end
764 end
765 dctx.open_stage
766 dctx.stage("<article class=\"modules filterable\">\n")
767 dctx.stage("<h2>Modules</h2>\n")
768 dctx.sort(mods)
769 dctx.stage("<ul>\n")
770 for m in mods do
771 dctx.add("<li>{m.html_link(dctx)}</li>")
772 end
773 dctx.stage("</ul></article>\n")
774 dctx.close_stage
775
776 dctx.open_stage
777 dctx.stage("<article class=\"classes filterable\">\n")
778 dctx.stage("<h2>Classes</h2>\n")
779 dctx.sort(clas)
780 dctx.stage("<ul>\n")
781 for lc in clas do
782 dctx.add("<li>{lc.html_link(dctx)}</li>")
783 end
784 dctx.stage("</ul></article>\n")
785 dctx.close_stage
786
787 dctx.open_stage
788 dctx.stage("<article class=\"properties filterable\">\n")
789 dctx.stage("<h2>Properties</h2>\n")
790 dctx.sort(gprops)
791 dctx.stage("<ul>\n")
792 for lgp in gprops do
793 var gp = lgp.global
794 var lps = props[gp]
795
796 if gp.intro isa MMAttribute then continue
797
798 var lpi = self[gp.intro.local_class.global][gp]
799
800 lps.remove(lpi)
801 dctx.add("<li class='intro'><span title='introduction'>I</span>&nbsp;{lpi.html_open_link(dctx)}{lpi.html_name}&nbsp;({lpi.local_class})</a></li>\n")
802 if lps.length >= 1 then
803 dctx.sort(lps)
804 for lp in lps do
805 dctx.add("<li class='redef'><span title='redefinition'>R</span>&nbsp;{lp.html_open_link(dctx)}{lp.html_name}&nbsp;({lp.local_class})</a></li>\n")
806 end
807 end
808 end
809 dctx.stage("</ul></article>\n")
810 dctx.close_stage
811 end
812 end
813
814 redef class MMLocalProperty
815 super MMEntity
816 # Anchor of the property description in the module html file
817 fun html_anchor: String
818 do
819 return "PROP_{local_class}_{cmangle(name)}"
820 end
821
822 fun html_open_link(dctx: DocContext): String
823 do
824 if not require_doc(dctx) then print "not required {self}"
825 var title = "{html_name}{signature.to_s}"
826 if short_doc != "&nbsp;" then
827 title += " #{short_doc}"
828 end
829 return "<a href=\"{local_class.html_name}.html#{html_anchor}\" title=\"{title}\">"
830 end
831
832 fun html_name: String
833 do
834 return self.name.to_s.html_escape
835 end
836
837 redef fun html_link(dctx)
838 do
839 if not require_doc(dctx) then print "not required {self}"
840 var title = "{html_name}{signature.to_s}"
841 if short_doc != "&nbsp;" then
842 title += " #{short_doc}"
843 end
844 return "<a href=\"{local_class.html_name}.html#{html_anchor}\" title=\"{title}\">{html_name}</a>"
845 end
846
847 fun html_link_special(dctx: DocContext, lc: MMLocalClass): String
848 do
849 if not require_doc(dctx) then print "not required {self}"
850 var title = "{html_name}{signature_for(lc.get_type)}"
851 if short_doc != "&nbsp;" then
852 title += " #{short_doc}"
853 end
854 return "<a href=\"{lc.html_name}.html#{html_anchor}\" title=\"{title}\">{html_name}</a>"
855 end
856
857 # Kind of property (fun, attr, etc.)
858 fun kind: String is abstract
859
860 redef fun short_doc
861 do
862 var d = doc
863 if d != null then
864 return d.short
865 else if global.intro == self then
866 return "&nbsp;"
867 else
868 return global.intro.short_doc
869 end
870 end
871
872 redef fun doc
873 do
874 var n = node
875 if n == null or not n isa APropdef then
876 return null
877 end
878 var d = n.n_doc
879 if d == null then
880 return null
881 end
882 if d.n_comment.is_empty then
883 return null
884 else
885 return d
886 end
887 end
888
889 # The most specific module in the nesting hierarchy that exports the intro of self
890 fun intro_module: MMModule
891 do
892 var m = global.intro.mmmodule
893 var mo = m.direct_owner
894 while mo != null and mo.visibility_for(m) >= 2 do
895 m = mo
896 mo = m.direct_owner
897 end
898 return m
899 end
900
901 # Is the intro of self exported by the top-level module ?
902 fun is_toplevel: Bool
903 do
904 var m = intro_module
905 return m == m.toplevel_owner
906 end
907
908 # Return true if the global property must be documented according to the visibility configured
909 fun require_doc(dctx: DocContext): Bool
910 do
911 if global.visibility_level == 3 and not dctx.with_private then return false # Private
912 if dctx.public_only then
913 var m = intro_module
914 if m != m.toplevel_owner then return false # Unexported
915 end
916 return true
917 end
918
919 # Document the global property in the global class lc
920 fun full_documentation(dctx: DocContext, lc: MMLocalClass)
921 do
922 var visibility: String
923 if global.visibility_level == 1 then
924 visibility = "public"
925 else if global.visibility_level == 2 then
926 visibility = "protected"
927 else if global.visibility_level == 3 then
928 visibility = "private"
929 else
930 abort
931 end
932
933 var intro_class = global.intro.local_class
934 var is_redef = local_class.global != intro_class.global or local_class.mmmodule.toplevel_owner != intro_class.mmmodule.toplevel_owner
935
936 dctx.add("<article id=\"{html_anchor}\" class=\"{kind} {visibility} {if is_redef then "redef" else ""}\">\n")
937 dctx.add("<h3 class=\"signature\">{html_name}{signature.to_html(dctx, true)}</h3>\n")
938 dctx.add("<div class=\"info\">\n")
939 #dctx.add("<p>LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}</p>")
940
941 if is_redef then
942 dctx.add("redef ")
943 end
944 if not is_toplevel then
945 dctx.add("(unexported) ")
946 end
947 if global.visibility_level == 2 then
948 dctx.add("protected ")
949 else if global.visibility_level == 3 then
950 dctx.add("private ")
951 end
952 dctx.add(kind)
953 dctx.add(" {intro_class.mmmodule.toplevel_owner.name}")
954 if intro_class.global == lc.global then
955 dctx.add("::{lc.name}")
956 else
957 dctx.add("::{mmmodule[intro_class.global].html_link(dctx)}")
958 end
959 if is_redef then
960 dctx.add("::{mmmodule[intro_class.global][global].html_link(dctx)}")
961 else
962 dctx.add("::{html_name}")
963 end
964 dctx.add("</div>")
965
966 dctx.add("<div class=\"description\">")
967
968 # Collect all refinement of the global property in the same global property
969 var lps = new Array[MMLocalProperty]
970 for l in prhe.greaters_and_self do
971 lps.add(l)
972 end
973
974 var introdoc = false
975 if global.intro.doc != null then
976 for lp in lps do
977 if lp.doc == null then introdoc = true
978 end
979 end
980 if introdoc then
981 dctx.add("<pre>{global.intro.doc.to_html}</pre>")
982 end
983
984 var tlmods = new Array[MMModule]
985 for lp in lps do
986 var bm = lp.mmmodule.toplevel_owner
987 var lcm = lc.global.intro.mmmodule
988 if lcm.mhe < lp.mmmodule then bm = lcm.toplevel_owner
989 if not tlmods.has(bm) then tlmods.add(bm)
990 end
991
992 for tm in tlmods do
993 # Document the top level property for the current top level module
994 var tlp
995 if tm.global_classes.has(lc.global) then
996 tlp = tm[lc.global][self.global]
997 assert lps.has(tlp)
998 else if tm.global_classes.has(self.local_class.global) then
999 # Self is the inherited property. Process it
1000 tlp = tm[self.local_class.global][self.global]
1001 assert lps.has(tlp)
1002 else
1003 # We skip this module since the props defined by the module is
1004 continue
1005 end
1006
1007 var tlcm = lc.global.intro.mmmodule.toplevel_owner
1008 if not tlcm.mhe <= tm then
1009 dctx.add("<h4>In module {tm.html_link(dctx)} :</h4>")
1010 end
1011
1012 #dctx.add("<p>TLP: {tm} x {lc} : {tlp.full_name}</p>")
1013
1014 var doc = tlp.doc
1015 if doc != null and (not introdoc or global.intro.doc != doc) then
1016 dctx.add("<pre>{doc.to_html}</pre>")
1017 end
1018 dctx.add("<p>")
1019 if tlp.local_class.global != lc.global then
1020 dctx.add("inherited from {tlp.local_class.html_link(dctx)} ")
1021 end
1022 if tm != tlp.mmmodule then
1023 dctx.add("defined by the module {tlp.mmmodule.html_link(dctx)} ")
1024 end
1025 var n = tlp.node
1026 if n != null then
1027 var l = n.location
1028 dctx.show_source(l)
1029 end
1030
1031 dctx.open_stage
1032 dctx.stage(". previously defined by:")
1033 for lp in lps do
1034 var tl = lp.mmmodule.toplevel_owner
1035 if tl != tm then continue
1036 if lp == tlp then continue
1037 dctx.add(" {lp.mmmodule.html_link(dctx)}")
1038 if lp.local_class.global != lc.global then
1039 dctx.add(" for {lp.local_class.html_link(dctx)}")
1040 end
1041
1042 n = lp.node
1043 if n != null then
1044 var l = n.location
1045 dctx.show_source(l)
1046 end
1047
1048 #var doc = lp.doc
1049 #if doc != null and (not introdoc or global.intro.doc != doc) then
1050 # dctx.add("<pre>{doc.to_html}</pre>")
1051 #end
1052 end
1053 dctx.close_stage
1054 dctx.add("</p>")
1055 end
1056 dctx.add("</div>")
1057 dctx.add("</article>")
1058 end
1059 end
1060 redef class MMMethod
1061 redef fun kind do return if global.is_init then "init" else "fun"
1062 end
1063 redef class MMAttribute
1064 redef fun kind do return "var"
1065 end
1066 redef class MMTypeProperty
1067 redef fun kind do return "type"
1068 end
1069
1070 redef class MMSrcModule
1071 redef fun short_doc
1072 do
1073 var d = doc
1074 if d != null then
1075 return d.short
1076 else
1077 return "&nbsp;"
1078 end
1079 end
1080
1081 redef fun doc
1082 do
1083 var n = node
1084 if n.n_moduledecl == null then
1085 return null
1086 end
1087 var np = n.n_moduledecl
1088 var d = np.n_doc
1089 if d == null then
1090 return null
1091 end
1092 if d.n_comment.is_empty then
1093 return null
1094 else
1095 return d
1096 end
1097 end
1098 end
1099
1100 redef class ADoc
1101 # Html transcription of the doc
1102 fun to_html: String
1103 do
1104 var res = new Buffer
1105 for c in n_comment do
1106 res.append(c.text.substring_from(1))
1107 end
1108 return res.to_s.html_escape
1109 end
1110
1111 # Oneliner transcription of the doc
1112 fun short: String
1113 do
1114 return n_comment.first.text.substring_from(1).html_escape
1115 end
1116 end
1117
1118 redef class MMLocalClass
1119 super MMEntity
1120
1121 # Anchor of the class description in the module html file
1122 fun html_anchor: String do return "CLASS_{self}"
1123
1124 fun html_name: String do return "{self}"
1125
1126 redef fun html_link(dctx)
1127 do
1128 if not require_doc(dctx) then print "{dctx.filename}: not required {self}"
1129 return "<a href=\"{html_name}.html\" title=\"{short_doc}\">{self}</a>"
1130 end
1131
1132 redef fun short_doc do return global.intro.short_doc
1133
1134 redef fun doc do return global.intro.doc
1135
1136 fun kind: String
1137 do
1138 if global.is_interface then
1139 return "interface"
1140 else if global.is_abstract then
1141 return "abstract class"
1142 else if global.is_enum then
1143 return "enum"
1144 else
1145 return "class"
1146 end
1147 end
1148
1149 # The most specific module in the nesting hierarchy that exports the intro of self
1150 fun intro_module: MMModule
1151 do
1152 var m = global.intro.mmmodule
1153 var mo = m.direct_owner
1154 while mo != null and mo.visibility_for(m) >= 2 do
1155 m = mo
1156 mo = m.direct_owner
1157 end
1158 return m
1159 end
1160
1161 fun menu_link(dctx: DocContext, p: MMLocalProperty)
1162 do
1163 if p.local_class.global != self.global then
1164 if p.global.intro.local_class.name == "Object".to_symbol then return
1165 if p.global.is_init or p isa MMTypeProperty then
1166 dctx.add("<li class='inherit'><span title='Inherited'>H</span>&nbsp;{p.html_link_special(dctx, self)}</li>\n")
1167 else
1168 dctx.add("<li class='inherit'><span title='Inherited'>H</span>&nbsp;{p.html_link(dctx)}</li>\n")
1169 end
1170 else if p.global.intro.local_class.global == self.global then
1171 dctx.add("<li class='intro'><span title='Introduced'>I</span>&nbsp;{p.html_link_special(dctx, self)}</li>\n")
1172 else
1173 dctx.add("<li class='redef'><span title='Redefined'>R</span>&nbsp;{p.html_link_special(dctx, self)}</li>\n")
1174 end
1175 end
1176
1177 # Return true if the global class must be documented according to the visibility configured
1178 fun require_doc(dctx: DocContext): Bool
1179 do
1180 if global.visibility_level == 3 and not dctx.with_private then return false # Private
1181 if dctx.public_only then
1182 var m = intro_module
1183 if m != m.toplevel_owner then return false # Unexported
1184 end
1185 return true
1186 end
1187
1188 # Fill the body for the page associated to the global class
1189 fun file_page_doc(dctx: DocContext)
1190 do
1191 dctx.add("<div class=\"menu\">\n")
1192
1193 var props = new Array[MMLocalProperty]
1194 var inh = new HashMap[MMLocalClass, Array[MMLocalProperty]]
1195 var inhs = new Array[MMLocalClass]
1196 for g in global_properties do
1197 var p = self[g]
1198 if not p.require_doc(dctx) then continue
1199 if p.local_class.global == global or g.is_init_for(self) or p isa MMTypeProperty then
1200 props.add(p)
1201 else
1202 var lc = mmmodule[p.local_class.global]
1203 if inh.has_key(lc) then
1204 inh[lc].add(p)
1205 else
1206 inh[lc] = [p]
1207 inhs.add(lc)
1208 end
1209 props.add(p)
1210 end
1211 end
1212 dctx.sort(props)
1213
1214 dctx.add("<nav class=\"properties filterable\">\n")
1215 dctx.add("<h3>Properties</h3>\n")
1216 dctx.open_stage
1217 dctx.stage("<h4>Virtual Types</h4>\n<ul>\n")
1218 for p in props do
1219 if p isa MMTypeProperty then
1220 menu_link(dctx, p)
1221 end
1222 end
1223 dctx.stage("</ul>\n")
1224 dctx.close_stage
1225 dctx.open_stage
1226 dctx.stage("<h4>Constructors</h4>\n<ul>\n")
1227 for p in props do
1228 if p.global.is_init_for(self) then
1229 menu_link(dctx, p)
1230 end
1231 end
1232 dctx.stage("</ul>\n")
1233 dctx.close_stage
1234 dctx.open_stage
1235 dctx.stage("<h4>Methods</h4>\n<ul>\n")
1236 for p in props do
1237 if not p.global.is_init and p isa MMMethod then
1238 menu_link(dctx, p)
1239 end
1240 end
1241 dctx.stage("</ul>\n")
1242 dctx.close_stage
1243 dctx.add("</nav>\n")
1244
1245 dctx.add("<nav class=\"inheritance filterable\">\n")
1246 dctx.add("<h3>Inheritance</h3>\n")
1247 dctx.add("<h4>Superclasses</h4>\n<ul>\n")
1248 for lc in cshe.linear_extension do
1249 if lc == self then continue
1250 if not lc.require_doc(dctx) then continue
1251 dctx.add("<li>{lc.html_link(dctx)}</li>\n")
1252 end
1253 dctx.add("</ul>\n")
1254 if cshe.smallers.length == 0 then
1255 dctx.add("<h4>No Known Subclasses</h4>\n")
1256 else if cshe.smallers.length <= 100 then
1257 dctx.add("<h4>Subclasses</h4>\n")
1258 dctx.add("<ul>\n")
1259 for lc in cshe.smallers do
1260 if not lc.require_doc(dctx) then continue
1261 dctx.add("<li>{lc.html_link(dctx)}</li>\n")
1262 end
1263 dctx.add("</ul>\n")
1264 else if cshe.direct_smallers.length <= 100 then
1265 dctx.add("<h4>Direct Subclasses Only</h4>\n<ul>\n")
1266 for lc in cshe.direct_smallers do
1267 if not lc.require_doc(dctx) then continue
1268 dctx.add("<li>{lc.html_link(dctx)}</li>\n")
1269 end
1270 dctx.add("</ul>\n")
1271 else
1272 dctx.add("<h4>Too much Subclasses to list</h4>\n")
1273 end
1274 dctx.add("</nav>\n")
1275
1276 dctx.add("</div>\n")
1277
1278
1279 dctx.add("<div class=\"content\">\n")
1280 dctx.add("<h1>{name}</h1>\n")
1281 dctx.add("<div class='subtitle'>")
1282 if global.visibility_level == 2 then
1283 abort
1284 else if global.visibility_level == 3 then
1285 dctx.add("private ")
1286 else if self.global.intro.mmmodule.toplevel_owner.visibility_for(self.global.intro.mmmodule) <= 1 then
1287 dctx.add("(unexported) ")
1288 end
1289 dctx.add("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}</div>")
1290
1291 dctx.add("<section class=\"description\">\n")
1292 var doc = doc
1293 if doc != null then
1294 dctx.add("<pre>{doc.to_html}</pre>\n")
1295 end
1296
1297 var cla = new HashSet[MMLocalClass]
1298 var sm = new HashSet[MMLocalClass]
1299 var sm2 = new HashSet[MMLocalClass]
1300 sm.add(self)
1301 while cla.length + sm.length < 10 and sm.length > 0 do
1302 cla.add_all(sm)
1303 sm2.clear
1304 for x in sm do
1305 sm2.add_all(x.cshe.direct_smallers)
1306 end
1307 var t = sm
1308 sm = sm2
1309 sm2 = t
1310 end
1311 cla.add_all(cshe.greaters_and_self)
1312
1313 var op = new Buffer
1314 op.append("digraph {name} \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
1315 for c in cla do
1316 if c == self then
1317 op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
1318 else
1319 op.append("\"{c.name}\"[URL=\"{c.html_name}.html\"];\n")
1320 end
1321 for c2 in c.cshe.direct_greaters do
1322 if not cla.has(c2) then continue
1323 op.append("\"{c.name}\"->\"{c2.name}\";\n")
1324 end
1325 if not c.cshe.direct_smallers.is_empty then
1326 var others = true
1327 for c2 in c.cshe.direct_smallers do
1328 if cla.has(c2) then others = false
1329 end
1330 if others then
1331 op.append("\"{c.name}...\"[label=\"\"];\n")
1332 op.append("\"{c.name}...\"->\"{c.name}\"[style=dotted];\n")
1333 end
1334 end
1335 end
1336 op.append("\}\n")
1337 dctx.gen_dot(op.to_s, name.to_s, "Inheritance graph for class {name}")
1338
1339
1340 var mods = new Array[MMModule]
1341 mods.add(global.intro.mmmodule.toplevel_owner)
1342 for lc in crhe.greaters do
1343 if not lc isa MMSrcLocalClass then continue
1344 var m = lc.mmmodule.toplevel_owner
1345 if not mods.has(m) then mods.add(m)
1346 end
1347 dctx.sort(mods)
1348 for m in mods do
1349 if m == global.intro.mmmodule.toplevel_owner then
1350 dctx.add("<p>Introduced by {m.html_link(dctx)}")
1351 else
1352 dctx.add("<p>Refined by {m.html_link(dctx)}")
1353 end
1354 dctx.open_stage
1355 dctx.stage(". Definition in:")
1356 for lc in crhe.greaters do
1357 if lc.mmmodule.toplevel_owner != m then continue
1358 dctx.add(" {lc.mmmodule.html_link(dctx)}")
1359 assert lc isa MMSrcLocalClass
1360 var n = lc.node
1361 if n != null then
1362 dctx.show_source(n.location)
1363 end
1364 end
1365 dctx.close_stage
1366 dctx.add("</p>\n")
1367 end
1368 dctx.add("</section>\n")
1369
1370 dctx.open_stage
1371 dctx.stage("<section class=\"types\">\n")
1372 dctx.stage("<h2>Formal and Virtual Types</h2>\n")
1373 for i in [0..arity[ do
1374 var f = get_formal(i)
1375 f.full_documentation(dctx, self)
1376 end
1377 for p in props do
1378 if not p isa MMTypeProperty then continue
1379 p.full_documentation(dctx, self)
1380 end
1381 dctx.stage("</section>\n")
1382 dctx.close_stage
1383
1384 dctx.open_stage
1385 dctx.stage("<section class=\"constructors\">\n")
1386 dctx.stage("<h2 class=\"section-header\">Constructors</h2>\n")
1387 for p in props do
1388 if not p.global.is_init_for(self) then continue
1389 p.full_documentation(dctx, self)
1390 end
1391 dctx.stage("</section>\n")
1392 dctx.close_stage
1393
1394 dctx.open_stage
1395 dctx.stage("<section class=\"methods\">\n")
1396 dctx.stage("<h2 class=\"section-header\">Methods</h2>\n")
1397 for p in props do
1398 if p.global.is_init then continue
1399 if p.local_class.global != self.global then continue
1400 if not p isa MMMethod then continue
1401 p.full_documentation(dctx, self)
1402 end
1403 if not inhs.is_empty then
1404 dctx.open_stage
1405 dctx.stage("<h3>Inherited Methods</h3>\n")
1406 for lc in inhs do
1407 dctx.open_stage
1408 dctx.stage("<p>Defined in {lc.html_link(dctx)}:")
1409 for p in inh[lc] do
1410 if p.global.is_init then continue
1411 if not p isa MMMethod then continue
1412 dctx.add(" {p.html_link(dctx)}")
1413 end
1414 dctx.stage("</p>")
1415 dctx.close_stage
1416 end
1417 dctx.close_stage
1418 end
1419 dctx.add("</section>\n")
1420 dctx.close_stage
1421 dctx.add("</div> <!-- end class {name} -->\n")
1422 end
1423 end
1424
1425 redef class MMSrcLocalClass
1426 redef fun short_doc
1427 do
1428 var d = doc
1429 if d != null then
1430 return d.short
1431 else if global.intro == self then
1432 return "&nbsp;"
1433 else
1434 var bc = global.intro
1435 return bc.short_doc
1436 end
1437 end
1438
1439 redef fun doc
1440 do
1441 var n = node
1442 if not n isa AStdClassdef then
1443 return null
1444 end
1445 var d = n.n_doc
1446 if d == null then
1447 return null
1448 end
1449 if d.n_comment.is_empty then
1450 return null
1451 else
1452 return d
1453 end
1454 end
1455 end
1456
1457 redef class MMSignature
1458 # Htlm transcription of the signature (with nested links)
1459 fun to_html(dctx: DocContext, with_closure: Bool): String
1460 do
1461 var res = new Buffer
1462 if arity > 0 then
1463 res.append("(")
1464 for i in [0..arity[ do
1465 if i > 0 then res.append(", ")
1466 res.append(self.params[i].name.to_s)
1467 res.append(": ")
1468 res.append(self[i].html_link(dctx))
1469 if self.vararg_rank == i then
1470 res.append("...")
1471 end
1472 end
1473 res.append(")")
1474 end
1475 if return_type != null then
1476 res.append(": ")
1477 res.append(return_type.html_link(dctx))
1478 end
1479 if with_closure then
1480 for c in closures do
1481 res.append(" ")
1482 if c.is_optional then res.append("[")
1483 if c.is_break then res.append("break ")
1484 res.append("!{c.name}")
1485 res.append(c.signature.to_html(dctx, false))
1486 if c.is_optional then res.append("]")
1487 end
1488 end
1489 return res.to_s
1490 end
1491 end
1492
1493 redef class MMType
1494 # Htlm transcription of the type (with nested links)
1495 fun html_link(dctx: DocContext): String do return to_s
1496 end
1497
1498 redef class MMTypeSimpleClass
1499 redef fun html_link(dctx) do return local_class.html_link(dctx)
1500 end
1501
1502 redef class MMTypeGeneric
1503 redef fun html_link(dctx)
1504 do
1505 var res = new Buffer
1506 res.append(local_class.html_link(dctx))
1507 res.append("[")
1508 res.append(params[0].html_link(dctx))
1509 for i in [1..params.length[ do
1510 res.append(", ")
1511 res.append(params[i].html_link(dctx))
1512 end
1513 res.append("]")
1514 return res.to_s
1515 end
1516 end
1517
1518 redef class MMTypeFormalParameter
1519 fun html_anchor: String
1520 do
1521 return "FT_{local_class}_{cmangle(name)}"
1522 end
1523 redef fun html_link(dctx)
1524 do
1525 return "<a href=\"#{html_anchor}\">{name}</a>"
1526 end
1527 fun full_documentation(dctx: DocContext, lc: MMLocalClass)
1528 do
1529 dctx.add("<article id=\"{html_anchor}\">\n")
1530 dctx.add("<h3 class=\"signature\">{name}: {bound.html_link(dctx)}</h3>\n")
1531 dctx.add("<div class=\"info\">")
1532 dctx.add("formal generic type")
1533 dctx.add("</div>")
1534 dctx.add("</article>")
1535 end
1536 end
1537
1538 redef class MMNullableType
1539 redef fun html_link(dctx) do return "nullable " + as_notnull.html_link(dctx)
1540 end
1541
1542 redef class MMVirtualType
1543 redef fun html_link(dctx) do return property.html_link(dctx)
1544 end
1545
1546 var c = new DocContext
1547 c.exec_cmd_line