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