From 4592ad54939313826c8e6d97b3357783993f5d9b Mon Sep 17 00:00:00 2001 From: Jean Privat Date: Fri, 3 Feb 2012 16:26:17 -0500 Subject: [PATCH] nitdoc: complete rewrite Signed-off-by: Jean Privat --- src/nitdoc.nit | 1702 +++++++++++++++++++++++++------------------- tests/sav/nitdoc.sav | 2 + tests/sav/nitdoc_args1.sav | 659 ++++++++++++++++- 3 files changed, 1598 insertions(+), 765 deletions(-) diff --git a/src/nitdoc.nit b/src/nitdoc.nit index 5e69d6b..7777177 100644 --- a/src/nitdoc.nit +++ b/src/nitdoc.nit @@ -26,7 +26,7 @@ import abstracttool class DocContext super AbstractCompiler # Destination directory - readable writable var _dir: String = "." + readable writable var _dir: String = "doc" # Content of a generated file var _stage_context: StageContext = new StageContext(null) @@ -65,204 +65,212 @@ class DocContext f.close end - # Currently computed mmmodule - readable var _mmmodule: nullable MMSrcModule - - # Is the current directory module computed as a simple modude ? - readable writable var _inside_mode: Bool = false - - # Is the current module computed as a intruded one ? - readable writable var _intrude_mode: Bool = false + # Start a new file + fun clear + do + _stage_context = new StageContext(null) + end - # Compued introducing entities (for the index) - var _entities: Array[MMEntity] = new Array[MMEntity] + # Sorter of entities in alphabetical order + var _sorter: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity] - # Register an entity (for the index) - fun register(e: MMEntity) + # Sort entities in the alphabetical order + fun sort(array: Array[MMEntity]) do - if not _entities.has(e) then - _entities.add(e) - if e isa MMSrcModule then - _mmmodule = e - end - end + _sorter.sort(array) end - # Start a new file - fun clear + readable var _opt_dir: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir") + readable var _opt_source: OptionString = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source") + readable var _opt_public: OptionBool = new OptionBool("Generate only the public API", "--public") + + fun public_only: Bool do - _stage_context = new StageContext(null) + if self._opt_public.value == true then return true + return false end - # Generate common files (frames, index, overview) - fun extract_other_doc + # The current processed filename + var filename: String + + # The main virtual module + var mainmod: nullable MMVirtualModule + + redef fun perform_work(mods) do - info("Generating other files",1) - _mmmodule = null - inside_mode = false - intrude_mode = false - clear - add("\n") - add("Overview
\n") - add("Index
\n") - var modules = modules.to_a - sort(modules) - - var rootdirs = new Array[MMDirectory] - for m in modules do - var md = m.directory - if md.parent == null and not rootdirs.has(md) then - rootdirs.add(md) - end - end + mainmod = new MMVirtualModule(self, mods) - var done = new Array[MMModule] - for root in rootdirs do - var dirstack = [root] - var curdir = root - add("{root.name}
\n") - var indent = "  " - while not dirstack.is_empty do - var redo = false - for m in modules do - if done.has(m) then continue - var md = m.directory - if md.owner == m and md.parent == curdir then - # It's a directory module - add("{indent}{m}
\n") - curdir = md - dirstack.push(curdir) - indent = "  " * dirstack.length - redo = true - break # restart to preserve alphabetic order - else if md == curdir then - if md.owner == m then - add("{indent}{m}
\n") - else - add("{indent}{m}
\n") - end - done.add(m) - redo = true - end - end - if not redo then - dirstack.pop - if not dirstack.is_empty then - curdir = dirstack[dirstack.length-1] - indent = "  " * dirstack.length - end + dir.mkdir + + # Compute the set of direct owned nested modules + var owns = new HashMap[MMModule, Array[MMModule]] + for mod in modules do + owns[mod] = new Array[MMModule]# [mod] + end + for mod in modules do + if mod == mainmod then continue + var d = mod.directory + loop + var o = d.owner + if o != null and o != mod then + owns[o].add(mod) end + var dp = d.parent + if dp == null or dp == d then break + d = dp end end - add("\n") - write_to("{dir}/menu-frame.html") - clear - add_header("Index") - add("
\n") - sort(_entities) - for e in _entities do - add("
{e.html_link(self)} - {e.prototype_head(self)} {e}{e.prototype_body(self)} {e.locate(self)}
{e.short_doc}\n") + # Builds the various module hierarchies + var mnh = new PartialOrder[MMModule] # nested module hierarchy + var tmh = new PartialOrder[MMModule] # top module import hierrchy + var ms = mainmod.mhe.linear_extension.reversed + for m in ms do + if ms == mainmod then continue + m.mnhe_ = mnh.add(m, owns[m]) + var pub = new Array[MMModule] + for m2 in m.mhe.greaters do + if m2.toplevel_owner != m2 and m2.toplevel_owner != m.toplevel_owner then continue + if m.mnhe <= m2 then continue + if m.visibility_for(m2) <= 0 then + # nothing + else if m.visibility_for(m2) == 1 then + else + pub.add(m2) + end + end + m.tmhe_ = tmh.add(m, pub) end - add("
\n") - write_to("{dir}/index-1.html") - clear - add_header("Overview") + var head = "\n" + + "\n" + + "" - var f = new OFStream.open("{_dir}/all_.module_hierarchy.dot") - f.write(module_hierarchy.to_dot) - f.close - - sys.system("dot -Tpng {_dir}/all_.module_hierarchy.dot -o {_dir}/all_.module_hierarchy.png") - - add("") - add("
\"module

\n") - - add("\n") - add("\n") - for m in modules do - add("\n") - end - add("
Overview of all Modules
{m.html_link(self)}{m.short_doc}
\n") - write_to("{dir}/overview.html") + var action_bar = "
\n" + # generate the index + self.filename = "index.html" clear - add("\n\n\n\n\n") - write_to("{dir}/index.html") - end + add("{head}\n") + add(action_bar) + add("
") + add("
") + add("

Modules

\n
    ") + var modss = mainmod.mhe.greaters_and_self.to_a + sort(modss) + for mod in modss do + if not mod.is_toplevel then continue + if not mod.require_doc(self) then continue + assert mod isa MMSrcModule + add("
  • {mod.html_link(self)} {mod.short_doc}
  • ") - fun add_header(title: String) - do - add("{title}\n\n") - add("
    \n") - add("Overview  Index  With Frames\n") - add("
    ") - add("Visibility: ") - var mod = mmmodule - if (not inside_mode and not intrude_mode) or mod == null then - add("Public  ") - else - add("Public  ") end - if inside_mode or mod == null then - add("Inside  ") - else if mod.directory.owner != mod then - add("Inside  ") - else - add("Inside  ") - end - if intrude_mode or mod == null then - add("Intrude  ") - else - add("Intrude  ") - end - add("
    ") - end + add("
") - # Sorter of entities in alphabetical order - var _sorter: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity] + var op = new Buffer + 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") + for mod in modss do + if not mod.is_toplevel then continue + if not mod.require_doc(self) then continue + op.append("\"{mod.name}\"[URL=\"{mod.html_name}.html\"];\n") + for mod2 in mod.tmhe.direct_greaters do + if not modss.has(mod2) then continue + op.append("\"{mod.name}\"->\"{mod2.name}\";\n") + end + end + op.append("\}\n") + self.gen_dot(op.to_s, "dep") + add("
") + add("
") + add("
") + add("\n") + write_to("{dir}/index.html") - # Sort entities in the alphabetical order - fun sort(array: Array[MMEntity]) - do - _sorter.sort(array) + # Generate page for modules + for mod in modules do + if mod == mainmod then continue + assert mod isa MMSrcModule + if not mod.require_doc(self) then continue + self.filename = mod.html_name + clear + add("{head}Module {mod.name}\n") + add(action_bar) + add("
") + mod.file_page_doc(self) + add("
") + add("\n") + write_to("{dir}/{mod.html_name}.html") + end + + # Generate pages for global classes + for c in mainmod.local_classes do + if not c.require_doc(self) then continue + self.filename = c.html_name + clear + add("{head}Class {c.name}\n") + add(action_bar) + add("
") + c.file_page_doc(self) + add("
") + add("\n") + write_to("{dir}/{c.html_name}.html") + end + + self.filename = "fullindex" + clear + add("{head}\n") + add(action_bar) + add("
") + add("
") + mainmod.file_index_page_doc(self) + add("
") + add("
") + add("\n") + write_to("{dir}/full-index.html") end - readable writable var _owned_modules: Array[MMModule] = new Array[MMModule] - # Return the known_owner for current module - # if inside_mode is set, it could be a different result - fun known_owner_of(m: MMModule): MMModule + # Add a (source) link fo a given location + fun show_source(l: Location) do - var mod = mmmodule - if mod == null then return m - var res = mod.known_owner_of(m) - if not inside_mode and not intrude_mode and res.directory.owner == mod then - return mod + var s = opt_source.value + if s == null then + add("in #{l.file.filename}") else - return res + # THIS IS JUST UGLY ! (but there is no replace yet) + var x = s.split_with("%f") + s = x.join(l.file.filename) + x = s.split_with("%l") + s = x.join(l.line_start.to_s) + x = s.split_with("%L") + s = x.join(l.line_end.to_s) + add(" (show code)") end end - readable var _opt_dir: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir") - - redef fun perform_work(mods) + # Generate a clicable graphiz image using a dot content. + # `name' refer to the filename (without extension) and the id name of the map. + # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...) + fun gen_dot(dot: String, name: String) do - dir.mkdir - - for mod in modules do - assert mod isa MMSrcModule - mod.extract_module_doc(self) - end - self.extract_other_doc + var f = new OFStream.open("{self.dir}/{name}.dot") + f.write(dot) + f.close + 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 ; \}") + self.add("
") + var fmap = new IFStream.open("{self.dir}/{name}.map") + self.add(fmap.read_all) + fmap.close end init do keep_ast = true super("nitdoc") + filename = "-unset-" + option_context.add_option(opt_public) option_context.add_option(opt_dir) + option_context.add_option(opt_source) end redef fun process_options @@ -271,6 +279,40 @@ class DocContext var d = opt_dir.value if d != null then dir = d end + + redef fun handle_property_conflict(lc, impls) + do + # THIS IS SO UGLY! See MMVirtualModule + if lc.mmmodule == self.mainmod then + return # We just accept, so one in impls is arbitrary inherited + end + super + end +end + +# A virtual module is used to work as an implicit main module that combine unrelated modules +# Since conflict may arrise in a virtual module (the main method for instance) conflicts are disabled +class MMVirtualModule + super MMModule + init(ctx: MMContext, mods: Array[MMModule]) + do + # We need to compute the whole metamodel since there is no mmbuilder to do it + super(" main".to_symbol, mods.first.directory, ctx, new Location(null,0,0,0,0)) + ctx.add_module(self, mods) + for m in mods do + self.add_super_module(m, 1) + end + self.import_global_classes + self.import_local_classes + for c in self.local_classes do + c.compute_super_classes + end + for c in self.local_classes do + c.compute_ancestors + end + + end + redef fun require_doc(dctx) do return false end # Conditionnal part of the text content of a DocContext @@ -322,180 +364,388 @@ class MMEntity # Return a link to fun html_link(dctx: DocContext): String is abstract - # Is the entity should appear in the generaed doc - fun need_doc(dctx: DocContext): Bool is abstract - # Return a one liner description fun short_doc: String do return " " # The doc node from the AST # Return null is none fun doc: nullable ADoc do return null - - # Human redable location of the entity (module/class/property) - fun locate(dctx: DocContext): String do return "" - - # Part of the prototype before the name (kind, modifiers, qualifier) - fun prototype_head(dctx: DocContext): String is abstract - - # Part of the property after the name (signature, modifiers) - fun prototype_body(dctx: DocContext): String do return "" end redef class MMModule super MMEntity redef fun html_link(dctx) do - if dctx.mmmodule == self then - return "{self}" - else - return "{self}" - end + return "{self}" end - redef fun need_doc(dctx) do return true - redef fun prototype_head(dctx) do return "module " - var _known_owner_of_cache: Map[MMModule, MMModule] = new HashMap[MMModule, MMModule] - - # Return the owner of `module` from the point of view of `self` - fun known_owner_of(mod: MMModule): MMModule + fun require_doc(dctx: DocContext): Bool do - if _known_owner_of_cache.has_key(mod) then return _known_owner_of_cache[mod] - var res = mod - # is module is publicly imported by self? - if mhe < mod and visibility_for(mod) != 0 then - res = known_owner_of_intern(mod, self, false) - else - # Return the canonnical owner of module from the point of view of self - res = mod.owner(self) - end - _known_owner_of_cache[mod] = res - return res + if dctx.public_only and not is_toplevel then return false + return true end - # Return the most general module that own self - fun owner(from: MMModule): MMModule + # Return true if the module is a top-level owner or a top-level module + fun is_toplevel: Bool do - var res = self - var d: nullable MMDirectory = directory - while d != null and d != from.directory do - var o = d.owner - if o != null and o.mhe <= res then res = o - d = d.parent - end - return res + var pd = directory.parent + return pd == null or (pd.owner == null and directory.owner == self) end - # ??? - private fun known_owner_of_intern(mod: MMModule, from: MMModule, as_owner: Bool): MMModule - do - if mod == self then return self - var candidates = new Array[MMModule] - for m in explicit_imported_modules do - if from.visibility_for(m) == 0 then continue - if not m.mhe <= mod then continue - candidates.add(m.known_owner_of_intern(mod, from, true)) - end - # FIXME: I do not know what this does - if candidates.is_empty then return mod.owner(from) - var max = candidates.first - for m in candidates do - if max.mhe < m then max = m - end - if as_owner and max.directory.owner == self then - return self - else - return max - end - end + # Element in the module nesting tree + fun mnhe: PartialOrderElement[MMModule] do return mnhe_.as(not null) + var mnhe_: nullable PartialOrderElement[MMModule] = null -end + # Element in the top level module importation hierarchy + fun tmhe: PartialOrderElement[MMModule] do return tmhe_.as(not null) + var tmhe_: nullable PartialOrderElement[MMModule] = null -redef class MMLocalProperty - super MMEntity - # Anchor of the property description in the module html file - fun html_anchor: String - do - return "PROP_{local_class}_{cmangle(name)}" - end - - redef fun html_link(dctx) + fun toplevel_owner: MMModule do - var m = mmmodule - if not need_doc(dctx) then m = global.intro.mmmodule - m = dctx.known_owner_of(m) - if m == dctx.mmmodule then - return "{self}" - else - return "{self}" + var m = self + loop + var ds = m.mnhe.direct_smallers + if ds.length == 0 then return m + if ds.length == 1 then m = ds.first else abort end end - - # Kind of property (fun, attr, etc.) - fun kind: String is abstract - redef fun locate(dctx) + fun html_name: String do - return "in {mmmodule.html_link(dctx)}::{local_class.html_link(dctx)}" + return "{name}" end - fun known_intro_class(dctx: DocContext): MMLocalClass + fun direct_owner: nullable MMModule do - var mod = dctx.known_owner_of(global.intro.local_class.mmmodule) - var cla = mod[global.intro.local_class.global] - return cla + var d = directory + while d.owner == self do d = d.parent.as(not null) + return d.owner end - redef fun prototype_head(dctx) + # Fill the body for the page associated to the module + fun file_page_doc(dctx: DocContext) do - var res = new Buffer - var intro_class = known_intro_class(dctx) - var is_redef = local_class != intro_class + dctx.add("
\n") - if is_redef then res.append("redef ") - if global.visibility_level == 2 then - res.append("protected ") - else if global.visibility_level == 3 then - res.append("private ") + var mods = new Array[MMModule] + mods = self.mhe.greaters.to_a + dctx.sort(mods) + + dctx.open_stage + dctx.stage("\n") + dctx.close_stage + + if not dctx.public_only then + mods = self.mnhe.direct_greaters.to_a + dctx.sort(mods) + dctx.open_stage + dctx.stage("\n") + dctx.close_stage end - res.append(kind) - if is_redef then - var gp = global.intro - if intro_class.global != local_class.global then - res.append(" {mmmodule[intro_class.global].html_link(dctx)}::") - else if intro_class.mmmodule != mmmodule then - res.append(" {intro_class.mmmodule.html_link(dctx)}::") + + dctx.add("
") # metadata + + dctx.add("
\n") + dctx.add("

{name}

\n") + dctx.add("
module ") + for m in mnhe.smallers do + dctx.add("{m.html_link(dctx)}::") + end + dctx.add("{self.name}
\n") + + dctx.add("
\n") + + var doc = doc + if doc != null then + dctx.add("
\n") + dctx.add("
{doc.to_html}
\n") + dctx.add("
\n") + end + + var op = new Buffer + 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") + var ms = new Array[nullable MMModule] + do + var m0: nullable MMModule = self + while m0 != null do + m0 = m0.direct_owner + ms.add(m0) end end - return res.to_s - end + var cla = new HashSet[MMModule] + cla.add(self) + for m0 in self.mhe.greaters do + if not m0.require_doc(dctx) then continue + if self.visibility_for(m0) <= 1 then continue # private or hidden + if self.mnhe <= m0 then continue # do not want nested stuff + if m0.direct_owner != null and not m0.direct_owner.mnhe <= self then continue # not in the right nesting + cla.add(m0) + end + for m0 in self.mhe.smallers do + if not m0.require_doc(dctx) then continue + if m0.visibility_for(self) <= 1 then continue # private or hidden + if m0.direct_owner != null and not m0.direct_owner.mnhe <= self then continue # not in the right nesting + cla.add(m0) + end + for m0 in self.mnhe.smallers do + cla.add(m0) + end + ms = ms.reversed + for m0 in ms do + if m0 != null then + op.append("subgraph \"cluster_{m0.name}\"\{\n") + end + for c in cla do + if c.direct_owner != m0 then continue + if c == self then + op.append("\"{c.name}\"[shape=box,margin=0.03];\n") + else + op.append("\"{c.name}\"[URL=\"{c.html_name}.html\"];\n") + end + end + if m0 != null then + op.append("\"{m0.name}\"[URL=\"{m0.html_name}.html\"];\n") + for c in m0.mhe.direct_greaters do + if not cla.has(c) then continue + op.append("\"{m0.name}\"->\"{c.name}\";\n") + end + end + end + for m0 in ms do + # Close the nesting subgraph + if m0 != null then + op.append("\}\n") + end + end + for c in cla do + for c2 in c.tmhe.direct_greaters do + if not cla.has(c2) then continue + op.append("\"{c.name}\"->\"{c2.name}\";\n") + end + end + op.append("\}\n") + dctx.gen_dot(op.to_s, name.to_s) + dctx.add("
") + + var clas = new Array[MMLocalClass] + var props = new HashMap[MMGlobalProperty, Array[MMLocalProperty]] + var gprops = new Array[MMLocalProperty] + do + var m = self + for g in m.global_classes do + var lc = m[g] + if not lc.require_doc(dctx) then continue + var im = g.intro.mmmodule + if self.visibility_for(im) <= 1 then continue # private import or invisible import + var keep = false + for lc2 in lc.crhe.greaters_and_self do + if not lc2 isa MMSrcLocalClass then continue + if not self.mnhe <= lc2.mmmodule then continue # not introduced/redefined here/stolen + keep = true + end + if not keep then continue + clas.add(self[g]) + for gp in lc.global_properties do + if self.visibility_for(gp.intro.local_class.mmmodule) <= 1 then continue # private import or invisible import + var lp = lc[gp] + var mp = lp.local_class.mmmodule + if not self.mnhe <= mp then continue # not introduced/redefined here/stolen + lp = self[g][gp] + if not lp.require_doc(dctx) then continue + if props.has_key(lp.global) then + if not props[lp.global].has(lp) then + props[lp.global].add(lp) + end + else + props[lp.global] = [lp] + gprops.add(lp.global.intro) + end + end + end + end + dctx.add("
\n") + dctx.open_stage + dctx.stage("
\n") + dctx.stage("

Classes

\n") + dctx.sort(clas) + dctx.stage("
    \n") + for lc in clas do + if self.mnhe <= lc.global.intro.mmmodule then + dctx.add("
  • I ") + else + dctx.add("
  • R ") + end + dctx.add("{lc.html_link(dctx)}
  • \n") + end + dctx.stage("
\n") + dctx.close_stage - redef fun prototype_body(dctx) - do - var res = new Buffer - res.append(signature.to_html(dctx, true)) - var s = self - if s isa MMMethod then - if s.is_abstract then - res.append(" is abstract") - else if s.is_intern then - res.append(" is intern") + dctx.open_stage + dctx.stage("
\n") + dctx.stage("

Properties

\n") + dctx.sort(gprops) + dctx.stage("
    \n") + for lgp in gprops do + var gp = lgp.global + var lps = props[gp] + + if gp.intro isa MMAttribute then continue + + var lpi = self[gp.intro.local_class.global][gp] + + if lps.has(lpi) then + dctx.add("
  • I {lpi} ({lpi.local_class})
  • \n") + lps.remove(lpi) + else + dctx.add("
  • I {lpi}") + dctx.add(" ({lpi.local_class})
  • \n") + end + if lps.length >= 1 then + dctx.sort(lps) + for lp in lps do + dctx.add("
  • R {lp} ({lp.local_class})
  • ") + end end end - return res.to_s + dctx.stage("
\n") + dctx.close_stage + + + dctx.add("
\n") + dctx.add("\n") end - redef fun need_doc(dctx) + # Fill the body for the page associated to the full index + fun file_index_page_doc(dctx: DocContext) do - if global.visibility_level >= 3 or self isa MMAttribute then - if not dctx.intrude_mode then return false - if dctx.mmmodule.visibility_for(mmmodule) == 0 then return false + + dctx.add("

Full Index

\n") + + var clas = new Array[MMLocalClass] + var props = new HashMap[MMGlobalProperty, Array[MMLocalProperty]] + var gprops = new Array[MMLocalProperty] + var mods = new Array[MMModule] + for m in mhe.greaters_and_self do + if not m.require_doc(dctx) then continue + mods.add(m) + end + for g in global_classes do + var lc = self[g] + if not lc.require_doc(dctx) then continue + clas.add(lc) + for gp in lc.global_properties do + var lp = lc[gp] + if not lp.require_doc(dctx) then continue + if props.has_key(lp.global) then + if not props[lp.global].has(lp) then + props[lp.global].add(lp) + end + else + props[lp.global] = [lp] + gprops.add(lp.global.intro) + end + end end - if global.intro == self then - return true + dctx.open_stage + dctx.stage("
\n") + dctx.stage("

Modules

\n") + dctx.sort(mods) + dctx.stage("
    \n") + for m in mods do + dctx.add("
  • {m.html_link(dctx)}
  • ") + end + dctx.stage("
\n") + dctx.close_stage + + dctx.open_stage + dctx.stage("
\n") + dctx.stage("

Classes

\n") + dctx.sort(clas) + dctx.stage("
    \n") + for lc in clas do + dctx.add("
  • {lc.html_link(dctx)}
  • ") + end + dctx.stage("
\n") + dctx.close_stage + + dctx.open_stage + dctx.stage("
\n") + dctx.stage("

Properties

\n") + dctx.sort(gprops) + dctx.stage("
    \n") + for lgp in gprops do + var gp = lgp.global + var lps = props[gp] + + if gp.intro isa MMAttribute then continue + + var lpi = self[gp.intro.local_class.global][gp] + + lps.remove(lpi) + dctx.add("
  • I {lpi} ({lpi.local_class})
  • \n") + if lps.length >= 1 then + dctx.sort(lps) + for lp in lps do + dctx.add("
  • R {lp} ({lp.local_class})
  • \n") + end + end end - return doc != null + dctx.stage("
\n") + dctx.close_stage + end +end + +redef class MMLocalProperty + super MMEntity + # Anchor of the property description in the module html file + fun html_anchor: String + do + return "PROP_{local_class}_{cmangle(name)}" end + redef fun html_link(dctx) + do + if not require_doc(dctx) then print "not required {self}" + return "{self}" + end + + fun html_link_special(dctx: DocContext, lc: MMLocalClass): String + do + if not require_doc(dctx) then print "not required {self}" + return "{self}" + end + + # Kind of property (fun, attr, etc.) + fun kind: String is abstract + redef fun short_doc do var d = doc @@ -524,167 +774,189 @@ redef class MMLocalProperty return d end end -end -redef class MMMethod - redef fun kind do return if global.is_init then "init" else "fun" -end -redef class MMAttribute - redef fun kind do return "var" -end -redef class MMTypeProperty - redef fun kind do return "type" -end -redef class MMSrcModule - # Extract and generate html file for the module - fun extract_module_doc(dctx: DocContext) + # The most specific module in the nesting hierarchy that exports the intro of self + fun intro_module: MMModule do - dctx.info("Generating HTML for module {name}",1) - dctx.register(self) + var m = global.intro.mmmodule + var mo = m.direct_owner + while mo != null and mo.visibility_for(m) >= 2 do + m = mo + mo = m.direct_owner + end + return m + end - dctx.clear - extract_module_doc_inside(dctx) - dctx.write_to("{dctx.dir}/{name}.html") - - dctx.intrude_mode = true - dctx.clear - extract_module_doc_inside(dctx) - dctx.write_to("{dctx.dir}/{name}__.html") - dctx.intrude_mode = false - - if directory.owner == self then - dctx.inside_mode = true - dctx.clear - extract_module_doc_inside(dctx) - dctx.write_to("{dctx.dir}/{name}_.html") - dctx.inside_mode = false + # Is the intro of self exported by the top-level module ? + fun is_toplevel: Bool + do + var m = intro_module + return m == m.toplevel_owner + end + + # Return true if the global class must be documented according to the visibility configured + fun require_doc(dctx: DocContext): Bool + do + if global.visibility_level == 3 then return false # Private + if dctx.public_only then + var m = intro_module + if m != m.toplevel_owner then return false # Unexported end + return true end - fun extract_module_doc_inside(dctx: DocContext) + # Document the global property in the global class lc + fun full_documentation(dctx: DocContext, lc: MMLocalClass) do - dctx.add_header("Module {self}") - dctx.add("

Module {self}

\n
") - var s = "" - var d: nullable MMDirectory = directory - while d != null do - if d.owner != null and (d.owner != self or dctx.inside_mode or dctx.intrude_mode) then - s = "{d.owner.html_link(dctx)}::{s}" - end - d = d.parent - end - dctx.add("{s}
{prototype_head(dctx)}{self}{prototype_body(dctx)}
\n") - - var strs = new Array[String] - var intrude_modules = new Array[MMModule] - var public_modules = new Array[MMModule] - var private_modules = new Array[MMModule] - var owned_modules = dctx.owned_modules - owned_modules.clear - for m in mhe.greaters do - var v = visibility_for(m) - if not dctx.inside_mode and not dctx.intrude_mode and m.directory.owner == self then - if v >= 2 then owned_modules.add(m) - continue - end - if v == 3 then - intrude_modules.add(m) - else if v == 2 then - public_modules.add(m) - else if v == 1 then - private_modules.add(m) - end + var visibility: String + if global.visibility_level == 1 then + visibility = "public" + else if global.visibility_level == 2 then + visibility = "protected" + else if global.visibility_level == 3 then + visibility = "private" + else + abort end - if not intrude_modules.is_empty then - var mods = mhe.order.select_smallests(intrude_modules) - for i in mods do strs.add(i.html_link(dctx)) - dctx.add("
Intruded modules:
{strs.join(", ")}\n") + + var intro_class = global.intro.local_class + var is_redef = local_class.global != intro_class.global or local_class.mmmodule.toplevel_owner != intro_class.mmmodule.toplevel_owner + + dctx.add("
\n") + dctx.add("

{name}{signature.to_html(dctx, true)}

\n") + dctx.add("
\n") + #dctx.add("

LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}

") + + if is_redef then + dctx.add("redef ") + end + if not is_toplevel then + dctx.add("(unexported) ") + end + if global.visibility_level == 2 then + dctx.add("protected ") + else if global.visibility_level == 3 then + dctx.add("private ") end - if not public_modules.is_empty then - strs.clear - var mods = mhe.order.select_smallests(public_modules) - for i in mods do strs.add(i.html_link(dctx)) - dctx.add("
Imported modules:
{strs.join(", ")}\n") + dctx.add(kind) + dctx.add(" {intro_class.mmmodule.toplevel_owner.name}") + if intro_class.global == lc.global then + dctx.add("::{lc.name}") + else + dctx.add("::{mmmodule[intro_class.global].html_link(dctx)}") end - if not private_modules.is_empty then - strs.clear - var mods = mhe.order.select_smallests(private_modules) - for i in mods do strs.add(i.html_link(dctx)) - dctx.add("
Privatly imported modules:
{strs.join(", ")}\n") + if is_redef then + dctx.add("::{mmmodule[intro_class.global][global].html_link(dctx)}") + else + dctx.add("::{name}") end - dctx.add("
\n") + dctx.add("") - var doc = doc - if doc != null then dctx.add("
{doc.to_html}
\n") - - var new_classes = new Array[MMLocalClass] - for c in local_classes do - if c.need_doc(dctx) then - new_classes.add(c) - if c.global.intro == c then - dctx.register(c) - end - else - for m in owned_modules do - if m.global_classes.has(c.global) then - var mc = m[c.global] - if mc.need_doc(dctx) then - new_classes.add(c) - break - end - end - end - end + dctx.add("
") + + # Collect all refinement of the global property in the same global property + var lps = new Array[MMLocalProperty] + for l in prhe.greaters_and_self do + lps.add(l) end - if not new_classes.is_empty then - dctx.add("\n") - dctx.add("\n") - for c in new_classes do - if c.global.intro == c or owned_modules.has(c.global.intro.mmmodule) then - var add = true - for p in c.cshe.direct_greaters do - if p.global.intro.mmmodule == self or owned_modules.has(p.global.intro.mmmodule) then - add = false - end - end - if add then - dctx.add("\n") - end - else - for p in c.local_local_properties do - if p.global.is_method and p.global.intro == p then - dctx.add("\n") - end - end - end + var introdoc = false + if global.intro.doc != null then + for lp in lps do + if lp.doc == null then introdoc = true end - dctx.add("
Main Summary of {self}
Introduce {c.prototype_head(dctx)}{c.html_link(dctx)}{c.prototype_body(dctx)}
{c.short_doc}
Refine {c.html_link(dctx)} Introduce {p.prototype_head(dctx)}{p.html_link(dctx)}{p.prototype_body(dctx)}
    {p.short_doc}

\n") + end + if introdoc then + dctx.add("
{global.intro.doc.to_html}
") end - if not new_classes.is_empty then - dctx.sort(new_classes) - dctx.add("\n") - dctx.add("\n") - for c in new_classes do - dctx.add("\n") - end - dctx.add("
Class Summary of {self}
{c.prototype_head(dctx)}{c.html_link(dctx)}{c.prototype_body(dctx)}
{c.short_doc}

\n") + var tlmods = new Array[MMModule] + for lp in lps do + var bm = lp.mmmodule.toplevel_owner + var lcm = lc.global.intro.mmmodule + if lcm.mhe < lp.mmmodule then bm = lcm.toplevel_owner + if not tlmods.has(bm) then tlmods.add(bm) end - if not new_classes.is_empty then - dctx.add("\n") - dctx.add("\n") - dctx.add("
Class Detail of {self}
\n") + for tm in tlmods do + # Document the top level property for the current top level module + var tlp + if tm.global_classes.has(lc.global) then + tlp = tm[lc.global][self.global] + assert lps.has(tlp) + else if tm.global_classes.has(self.local_class.global) then + # Self is the inherited property. Process it + tlp = tm[self.local_class.global][self.global] + assert lps.has(tlp) + else + # We skip this module since the props defined by the module is + continue + end - for c in new_classes do - c.extract_class_doc(dctx) + var tlcm = lc.global.intro.mmmodule.toplevel_owner + if not tlcm.mhe <= tm then + dctx.add("

In module {tm.html_link(dctx)} :

") end - end - dctx.add("\n") + #dctx.add("

TLP: {tm} x {lc} : {tlp.full_name}

") + + var doc = tlp.doc + if doc != null and (not introdoc or global.intro.doc != doc) then + dctx.add("
{doc.to_html}
") + end + dctx.add("

") + if tlp.local_class.global != lc.global then + dctx.add("inherited from {tlp.local_class.html_link(dctx)} ") + end + if tm != tlp.mmmodule then + dctx.add("defined by the module {tlp.mmmodule.html_link(dctx)} ") + end + var n = tlp.node + if n != null then + var l = n.location + dctx.show_source(l) + end + + dctx.open_stage + dctx.stage(". previously defined by:") + for lp in lps do + var tl = lp.mmmodule.toplevel_owner + if tl != tm then continue + if lp == tlp then continue + dctx.add(" {lp.mmmodule.html_link(dctx)}") + if lp.local_class.global != lc.global then + dctx.add(" for {lp.local_class.html_link(dctx)}") + end + + n = lp.node + if n != null then + var l = n.location + dctx.show_source(l) + end + + #var doc = lp.doc + #if doc != null and (not introdoc or global.intro.doc != doc) then + # dctx.add("

{doc.to_html}
") + #end + end + dctx.close_stage + dctx.add("

") + end + dctx.add("
") + dctx.add("") end +end +redef class MMMethod + redef fun kind do return if global.is_init then "init" else "fun" +end +redef class MMAttribute + redef fun kind do return "var" +end +redef class MMTypeProperty + redef fun kind do return "type" +end +redef class MMSrcModule redef fun short_doc do var d = doc @@ -734,363 +1006,310 @@ end redef class MMLocalClass super MMEntity + # Anchor of the class description in the module html file fun html_anchor: String do return "CLASS_{self}" + fun html_name: String do return "{self}" + redef fun html_link(dctx) do - var m = mmmodule - if not need_doc(dctx) then m = global.mmmodule - m = dctx.known_owner_of(m) - if m == dctx.mmmodule then - return "{self}" - else - return "{self}" - end + if not require_doc(dctx) then print "{dctx.filename}: not required {self}" + return "{self}" end redef fun short_doc do return global.intro.short_doc redef fun doc do return global.intro.doc - redef fun need_doc(dctx) do - if mmmodule == dctx.mmmodule then - for m in dctx.owned_modules do - if m.global_classes.has(global) then - var c = m[global] - if c.need_doc(dctx) then return true - end - end + fun kind: String + do + if global.is_interface then + return "interface" + else if global.is_abstract then + return "abstract class" + else if global.is_enum then + return "enum" + else + return "class" end - return false end - redef fun locate(dctx) do return "in {mmmodule.html_link(dctx)}" - - fun known_intro(dctx: DocContext): MMLocalClass do return dctx.known_owner_of(global.intro.mmmodule)[global] - - redef fun prototype_head(dctx) + # The most specific module in the nesting hierarchy that exports the intro of self + fun intro_module: MMModule do - var res = new Buffer - var ki = known_intro(dctx) - var is_redef = ki != self - if is_redef then res.append("redef ") - if global.visibility_level == 3 then res.append("private ") - res.append("class ") - if is_redef then res.append("{ki.mmmodule.html_link(dctx)}::") - return res.to_s + var m = global.intro.mmmodule + var mo = m.direct_owner + while mo != null and mo.visibility_for(m) >= 2 do + m = mo + mo = m.direct_owner + end + return m end - redef fun prototype_body(dctx) + fun menu_link(dctx: DocContext, p: MMLocalProperty) do - var res = new Buffer - if arity > 0 then - res.append("[") - for i in [0..arity[ do - var t = get_formal(i) - res.append(t.name.to_s) - res.append(": ") - res.append(t.bound.html_link(dctx)) + if p.local_class.global != self.global then + if p.global.intro.local_class.name == "Object".to_symbol then return + if p.global.is_init or p isa MMTypeProperty then + dctx.add("
  • H {p.html_link_special(dctx, self)}
  • \n") + else + dctx.add("
  • H {p.html_link(dctx)}
  • \n") end - res.append("]") + else if p.global.intro.local_class.global == self.global then + dctx.add("
  • I {p.html_link_special(dctx, self)}
  • \n") + else + dctx.add("
  • R {p.html_link_special(dctx, self)}
  • \n") end - return res.to_s end - # Extract the doc of a class - fun extract_class_doc(dctx: DocContext) + # Return true if the global class must be documented according to the visibility configured + fun require_doc(dctx: DocContext): Bool do - dctx.add("

    {self}

    {mmmodule.html_link(dctx)}::
    {prototype_head(dctx)}{self}{prototype_body(dctx)}\n") - dctx.add("
    \n") - dctx.add("
    \n") - - var sup2 = new Array[String] - var intro_module = dctx.known_owner_of(global.mmmodule) - if intro_module != mmmodule then - dctx.add("
    Refine {self} from:
    {intro_module.html_link(dctx)}\n") - sup2.clear - var mods = new Array[MMModule] - for c in crhe.greaters do - if c.need_doc(dctx) then - var km = dctx.known_owner_of(c.mmmodule) - if km != mmmodule and km != intro_module and not mods.has(km) then - mods.add(km) - end + if global.visibility_level == 3 then return false # Private + if dctx.public_only then + var m = intro_module + if m != m.toplevel_owner then return false # Unexported + end + return true + end + + # Fill the body for the page associated to the global class + fun file_page_doc(dctx: DocContext) + do + dctx.add("
    \n") + + var props = new Array[MMLocalProperty] + var inh = new HashMap[MMLocalClass, Array[MMLocalProperty]] + var inhs = new Array[MMLocalClass] + for g in global_properties do + var p = self[g] + if not p.require_doc(dctx) then continue + if p.local_class.global == global or g.is_init_for(self) or p isa MMTypeProperty then + props.add(p) + else + var lc = mmmodule[p.local_class.global] + if inh.has_key(lc) then + inh[lc].add(p) + else + inh[lc] = [p] + inhs.add(lc) end + props.add(p) end - for c in crhe.linear_extension do - if mods.has(c.mmmodule) then sup2.add(c.mmmodule.html_link(dctx)) - end - if not sup2.is_empty then dctx.add("
    Previous refinements in:
    {sup2.join(", ")}\n") end - if not cshe.greaters.is_empty then - sup2.clear - var clas = new Array[MMLocalClass] - for c in cshe.direct_greaters do - sup2.add(c.html_link(dctx)) - end - dctx.add("
    Direct superclasses:
    {sup2.join(", ")}\n") - sup2.clear - for c in cshe.linear_extension do - if c != self then sup2.add(c.html_link(dctx)) + dctx.sort(props) + + dctx.add("\n") + + dctx.add("\n") + + dctx.add("\n") + + + dctx.add("
    \n") + dctx.add("

    {name}

    \n") + dctx.add("
    ") + if global.visibility_level == 2 then + abort + else if global.visibility_level == 3 then + dctx.add("private ") + else if self.global.intro.mmmodule.toplevel_owner.visibility_for(self.global.intro.mmmodule) <= 1 then + dctx.add("(unexported) ") end - dctx.add("
    \n") + dctx.add("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}") + dctx.add("
    \n") var doc = doc if doc != null then dctx.add("
    {doc.to_html}
    \n") end - var details = new Array[Array[MMLocalProperty]] - for i in [0..4[ do details.add(property_summary(dctx, i)) - for i in [0..4[ do property_detail(dctx, i, details[i]) - - dctx.add("

    \n") - end - - fun pass_name(pass: Int): String - do - var names = once ["Virtual Types", "Consructors", "Methods", "Attributes"] - return names[pass] - end - - fun accept_prop(p: MMLocalProperty, pass: Int): Bool - do - if pass == 0 then - return p isa MMTypeProperty - else if pass == 1 then - return p.global.is_init - else if pass == 2 then - return p isa MMMethod and not p.global.is_init - else if pass == 3 then - return p isa MMAttribute - end - abort - end - - fun property_summary(dctx: DocContext, pass: Int): Array[MMLocalProperty] - do - var passname = pass_name(pass) - dctx.open_stage - dctx.stage("\n") - dctx.stage("\n") - - var new_props = new Array[MMLocalProperty] - for g in global_properties do - if not accept_prop(g.intro, pass) then continue - if mmmodule.visibility_for(g.intro.mmmodule) < g.visibility_level then continue - var p = self[g] - if p.local_class != self or not p.need_doc(dctx) then - var cla = new Array[MMLocalClass] - for m in dctx.owned_modules do - if not m.global_classes.has(global) then continue - var c = m[global] - if not c isa MMConcreteClass then continue - if not c.has_global_property(g) then continue - var p2 = c[g] - if p2.local_class != c or not p2.need_doc(dctx) then continue - cla.add(c) - end - if cla.is_empty then continue - cla = crhe.order.select_smallests(cla) + var cla = new HashSet[MMLocalClass] + var sm = new HashSet[MMLocalClass] + var sm2 = new HashSet[MMLocalClass] + sm.add(self) + while cla.length + sm.length < 10 and sm.length > 0 do + cla.add_all(sm) + sm2.clear + for x in sm do + sm2.add_all(x.cshe.direct_smallers) end - - new_props.add(p) - if p.global.intro == p then - dctx.register(p) - end - end - dctx.sort(new_props) - for p in new_props do - dctx.add("\n") + var t = sm + sm = sm2 + sm2 = t end - dctx.stage("
    {passname} Summary of {self}
    {p.prototype_head(dctx)}{p.html_link(dctx)}{p.prototype_body(dctx)}
        {p.short_doc}

    \n") + cla.add_all(cshe.greaters_and_self) - dctx.open_stage - dctx.stage("\n") - if pass != 1 then - # skip pass 1 because constructors are not inherited - var cmap = new HashMap[MMLocalClass, Array[MMLocalProperty]] - var mmap = new HashMap[MMModule, Array[MMLocalProperty]] - for c in che.greaters do - if c isa MMSrcLocalClass then - var km = dctx.known_owner_of(c.mmmodule) - var kc = km[c.global] - if kc == self then continue - var props: Array[MMLocalProperty] - if km == mmmodule then - if cmap.has_key(kc) then - props = cmap[kc] - else - props = new Array[MMLocalProperty] - cmap[kc] = props - end - else - if mmap.has_key(km) then - props = mmap[km] - else - props = new Array[MMLocalProperty] - mmap[km] = props - end - end - for g in c.global_properties do - var p = c[g] - if p.local_class == c and p.need_doc(dctx) and accept_prop(p, pass) then - props.add(kc[g]) - end - end - end + var op = new Buffer + 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") + for c in cla do + if c == self then + op.append("\"{c.name}\"[shape=box,margin=0.03];\n") + else + op.append("\"{c.name}\"[URL=\"{c.html_name}.html\"];\n") end - dctx.open_stage - dctx.stage("\n") - for c in cshe.linear_extension do - if not cmap.has_key(c) then continue - var props = cmap[c] - if props.is_empty then continue - dctx.sort(props) - var properties = new Array[String] - for p in props do properties.add(p.html_link(dctx)) - dctx.add("\n") + for c2 in c.cshe.direct_greaters do + if not cla.has(c2) then continue + op.append("\"{c.name}\"->\"{c2.name}\";\n") end - dctx.close_stage - - dctx.open_stage - dctx.stage("\n") - for m in mmmodule.mhe.linear_extension do - if not mmap.has_key(m) then continue - var props = mmap[m] - if props.is_empty then continue - dctx.sort(props) - var properties = new Array[String] - for p in props do properties.add(p.html_link(dctx)) - dctx.add("\n") + if not c.cshe.direct_smallers.is_empty then + var others = true + for c2 in c.cshe.direct_smallers do + if cla.has(c2) then others = false + end + if others then + op.append("\"{c.name}...\"[label=\"\"];\n") + op.append("\"{c.name}...\"->\"{c.name}\"[style=dotted];\n") + end end - dctx.close_stage end + op.append("\}\n") + dctx.gen_dot(op.to_s, name.to_s) - var mmap = new HashMap[MMModule, Array[MMLocalProperty]] - for c in crhe.order do - if mmmodule.mhe <= c.mmmodule or dctx.owned_modules.has(c.mmmodule) or not c isa MMSrcLocalClass then continue - var km = dctx.known_owner_of(c.mmmodule) - if mmmodule.mhe <= km then continue - var kc = km[c.global] - var props: Array[MMLocalProperty] - if mmap.has_key(km) then - props = mmap[km] + + var mods = new Array[MMModule] + mods.add(global.intro.mmmodule.toplevel_owner) + for lc in crhe.greaters do + if not lc isa MMSrcLocalClass then continue + var m = lc.mmmodule.toplevel_owner + if not mods.has(m) then mods.add(m) + end + dctx.sort(mods) + for m in mods do + if m == global.intro.mmmodule.toplevel_owner then + dctx.add("

    Introduced by {m.html_link(dctx)}") else - props = new Array[MMLocalProperty] - mmap[km] = props + dctx.add("

    Refined by {m.html_link(dctx)}") end - for g in c.global_properties do - var p = c[g] - if p.local_class == c and p.need_doc(dctx) and accept_prop(p, pass) then - var kp = kc[g] - if not props.has(kp) then props.add(kp) + dctx.open_stage + dctx.stage(". Definition in:") + for lc in crhe.greaters do + if lc.mmmodule.toplevel_owner != m then continue + dctx.add(" {lc.mmmodule.html_link(dctx)}") + assert lc isa MMSrcLocalClass + var n = lc.node + if n != null then + dctx.show_source(n.location) end end - # c.properties_inherited_from(dctx, self, pass) + dctx.close_stage + dctx.add("

    \n") end + dctx.add("\n") + + dctx.add("\n") + dctx.open_stage - dctx.stage("\n") - for c in crhe.order do - var m = c.mmmodule - if not mmap.has_key(m) then continue - var props = mmap[m] - if props.is_empty then continue - dctx.sort(props) - var properties = new Array[String] - for p in props do properties.add(p.html_link(dctx)) - dctx.add("\n") + dctx.stage("
    \n") + dctx.stage("

    Formal and Virtual Types

    \n") + for i in [0..arity[ do + var f = get_formal(i) + f.full_documentation(dctx, self) end + for p in props do + if not p isa MMTypeProperty then continue + p.full_documentation(dctx, self) + end + dctx.stage("
    \n") dctx.close_stage - dctx.stage("
    Inherited {passname}
    from {c.html_link(dctx)}{properties.join(", ")}
    Imported {passname}
    from {m.html_link(dctx)}{properties.join(", ")}
    Added {passname} in known modules
    in {m.html_link(dctx)}{properties.join(", ")}


    \n") - dctx.close_stage - - dctx.close_stage - return new_props - end - fun property_detail(dctx: DocContext, pass: Int, new_props: Array[MMLocalProperty]) - do - var passname = pass_name(pass) dctx.open_stage - dctx.stage("\n") - dctx.stage("\n") - dctx.stage("
    {passname} Detail of {self}
    \n") + dctx.stage("
    \n") + dctx.stage("

    Constructors

    \n") + for p in props do + if not p.global.is_init_for(self) then continue + p.full_documentation(dctx, self) + end + dctx.stage("
    \n") + dctx.close_stage dctx.open_stage - for p in new_props do - dctx.add("

    {p}

    {p.mmmodule.html_link(dctx)}::{p.local_class.html_link(dctx)}::
    {p.prototype_head(dctx)} {p.name}{p.prototype_body(dctx)}

    \n") - dctx.add("
    ") - var doc = p.doc - if doc != null then - dctx.add("
    {doc.to_html}
    \n") + dctx.stage("
    \n") + dctx.stage("

    Methods

    \n") + for p in props do + if p.global.is_init then continue + if p.local_class.global != self.global then continue + if not p isa MMMethod then continue + p.full_documentation(dctx, self) + end + if not inhs.is_empty then + dctx.open_stage + dctx.stage("

    Inherited Methods

    \n") + for lc in inhs do + dctx.open_stage + dctx.stage("

    Defined in {lc.html_link(dctx)}:") + for p in inh[lc] do + if p.global.is_init then continue + if not p isa MMMethod then continue + dctx.add(" {p.html_link(dctx)}") + end + dctx.stage("

    ") + dctx.close_stage end - dctx.stage("
    \n") dctx.close_stage - - dctx.open_stage - dctx.stage("
    \n") end + dctx.add("\n") dctx.close_stage - - dctx.close_stage - end - - # Add rows for properties inheriterd to some heirs - fun properties_inherited_from(dctx: DocContext, heir: MMLocalClass, pass: Int) - do - var properties = new Array[String] - for g in global_properties do - var p = self[g] - if p.local_class == self and p.need_doc(dctx) and accept_prop(p, pass) then - properties.add(p.html_link(dctx)) - end - end - if not properties.is_empty then - var s: String - if heir.global == global then - s = mmmodule.html_link(dctx) - else - s = self.html_link(dctx) - end - dctx.add("in {s}{properties.join(", ")}\n") - end + dctx.add(" \n") end end @@ -1124,23 +1343,6 @@ redef class MMSrcLocalClass return d end end - - redef fun need_doc(dctx) - do - if global.visibility_level >= 3 then - if not dctx.intrude_mode then return false - if dctx.mmmodule.visibility_for(mmmodule) == 0 then return false - end - if global.intro == self then - return true - end - for p in src_local_properties do - if p.need_doc(dctx) then - return true - end - end - return super - end end redef class MMSignature @@ -1150,9 +1352,13 @@ redef class MMSignature var res = new Buffer if arity > 0 then res.append("(") + res.append(self.params[0].name.to_s) + res.append(": ") res.append(self[0].html_link(dctx)) for i in [1..arity[ do res.append(", ") + res.append(self.params[i].name.to_s) + res.append(": ") res.append(self[i].html_link(dctx)) end res.append(")") @@ -1200,5 +1406,33 @@ redef class MMTypeGeneric end end +redef class MMTypeFormalParameter + fun html_anchor: String + do + return "FT_{local_class}_{cmangle(name)}" + end + redef fun html_link(dctx) + do + return "{name}" + end + fun full_documentation(dctx: DocContext, lc: MMLocalClass) + do + dctx.add("
    \n") + dctx.add("

    {name}: {bound.html_link(dctx)}

    \n") + dctx.add("
    ") + dctx.add("formal generic type") + dctx.add("
    ") + dctx.add("
    ") + end +end + +redef class MMNullableType + redef fun html_link(dctx) do return "nullable " + as_notnull.html_link(dctx) +end + +redef class MMVirtualType + redef fun html_link(dctx) do return property.html_link(dctx) +end + var c = new DocContext c.exec_cmd_line diff --git a/tests/sav/nitdoc.sav b/tests/sav/nitdoc.sav index 6cc3f82..00ad0b3 100644 --- a/tests/sav/nitdoc.sav +++ b/tests/sav/nitdoc.sav @@ -10,4 +10,6 @@ usage: nitdoc [options] file... -h, -?, --help Show Help (This screen) --version Show version and exit -v, --verbose Verbose + --public Generate only the public API -d, --dir Directory where doc is generated + --source What link for source (%f for filename, %l for first line, %L for last line) diff --git a/tests/sav/nitdoc_args1.sav b/tests/sav/nitdoc_args1.sav index d01394e..c3e1c58 100644 --- a/tests/sav/nitdoc_args1.sav +++ b/tests/sav/nitdoc_args1.sav @@ -1,56 +1,653 @@ +HashMap: not required HashCollection +HashSet: not required HashCollection +AbstractArray.dot +AbstractArray.html +AbstractArray.map +AbstractArray.png +AbstractArray.s.dot +AbstractArrayRead.dot +AbstractArrayRead.html +AbstractArrayRead.map +AbstractArrayRead.png +AbstractArrayRead.s.dot +AbstractSorter.dot +AbstractSorter.html +AbstractSorter.map +AbstractSorter.png +AbstractSorter.s.dot +AbstractString.dot +AbstractString.html +AbstractString.map +AbstractString.png +AbstractString.s.dot +Array.dot +Array.html +Array.map +Array.png +Array.s.dot +ArrayCapable.dot +ArrayCapable.html +ArrayCapable.map +ArrayCapable.png +ArrayCapable.s.dot +ArrayIterator.dot +ArrayIterator.html +ArrayIterator.map +ArrayIterator.png +ArrayIterator.s.dot +ArrayMap.dot +ArrayMap.html +ArrayMap.map +ArrayMap.png +ArrayMap.s.dot +ArraySet.dot +ArraySet.html +ArraySet.map +ArraySet.png +ArraySet.s.dot +ArraySetIterator.dot +ArraySetIterator.html +ArraySetIterator.map +ArraySetIterator.png +ArraySetIterator.s.dot +BM_Pattern.dot +BM_Pattern.html +BM_Pattern.map +BM_Pattern.png +BM_Pattern.s.dot +Bool.dot +Bool.html +Bool.map +Bool.png +Bool.s.dot +Buffer.dot +Buffer.html +Buffer.map +Buffer.png +Buffer.s.dot +BufferedIStream.dot +BufferedIStream.html +BufferedIStream.map +BufferedIStream.png +BufferedIStream.s.dot +Char.dot +Char.html +Char.map +Char.png +Char.s.dot +Collection.dot +Collection.html +Collection.map +Collection.png +Collection.s.dot +Comparable.dot +Comparable.html +Comparable.map +Comparable.png +Comparable.s.dot +ComparableSorter.dot +ComparableSorter.html +ComparableSorter.map +ComparableSorter.png +ComparableSorter.s.dot +Container.dot +Container.html +Container.map +Container.png +Container.s.dot +ContainerIterator.dot +ContainerIterator.html +ContainerIterator.map +ContainerIterator.png +ContainerIterator.s.dot +Couple.dot +Couple.html +Couple.map +Couple.png +Couple.s.dot +CoupleMap.dot +CoupleMap.html +CoupleMap.map +CoupleMap.png +CoupleMap.s.dot +CoupleMapIterator.dot +CoupleMapIterator.html +CoupleMapIterator.map +CoupleMapIterator.png +CoupleMapIterator.s.dot +Discrete.dot +Discrete.html +Discrete.map +Discrete.png +Discrete.s.dot +DummyArray.dot +DummyArray.html +DummyArray.map +DummyArray.png +DummyArray.s.dot +DummyIterator.dot +DummyIterator.html +DummyIterator.map +DummyIterator.png +DummyIterator.s.dot +FDIOStream.dot +FDIOStream.html +FDIOStream.map +FDIOStream.png +FDIOStream.s.dot +FDIStream.dot +FDIStream.html +FDIStream.map +FDIStream.png +FDIStream.s.dot +FDOStream.dot +FDOStream.html +FDOStream.map +FDOStream.png +FDOStream.s.dot +FDStream.dot +FDStream.html +FDStream.map +FDStream.png +FDStream.s.dot +FStream.dot +FStream.html +FStream.map +FStream.png +FStream.s.dot +FileStat.dot +FileStat.html +FileStat.map +FileStat.png +FileStat.s.dot +FilterIStream.dot +FilterIStream.html +FilterIStream.map +FilterIStream.png +FilterIStream.s.dot +FilterOStream.dot +FilterOStream.html +FilterOStream.map +FilterOStream.png +FilterOStream.s.dot +Float.dot +Float.html +Float.map +Float.png +Float.s.dot +HashMap.dot +HashMap.html +HashMap.map +HashMap.png +HashMap.s.dot +HashMapIterator.dot +HashMapIterator.html +HashMapIterator.map +HashMapIterator.png +HashMapIterator.s.dot +HashMapNode.dot +HashMapNode.html +HashMapNode.map +HashMapNode.png +HashMapNode.s.dot +HashSet.dot +HashSet.html +HashSet.map +HashSet.png +HashSet.s.dot +HashSetIterator.dot +HashSetIterator.html +HashSetIterator.map +HashSetIterator.png +HashSetIterator.s.dot +HashSetNode.dot +HashSetNode.html +HashSetNode.map +HashSetNode.png +HashSetNode.s.dot +IFStream.dot +IFStream.html +IFStream.map +IFStream.png +IFStream.s.dot +IOProcess.dot +IOProcess.html +IOProcess.map +IOProcess.png +IOProcess.s.dot +IOS.dot +IOS.html +IOS.map +IOS.png +IOS.s.dot +IOStream.dot +IOStream.html +IOStream.map +IOStream.png +IOStream.s.dot +IProcess.dot +IProcess.html +IProcess.map +IProcess.png +IProcess.s.dot +IStream.dot +IStream.html +IStream.map +IStream.png +IStream.s.dot +IndexedIterator.dot +IndexedIterator.html +IndexedIterator.map +IndexedIterator.png +IndexedIterator.s.dot +Int.dot +Int.html +Int.map +Int.png +Int.s.dot +Iterator.dot +Iterator.html +Iterator.map +Iterator.png +Iterator.s.dot +IteratorRange.dot +IteratorRange.html +IteratorRange.map +IteratorRange.png +IteratorRange.s.dot +List.dot +List.html +List.map +List.png +List.s.dot +ListIterator.dot +ListIterator.html +ListIterator.map +ListIterator.png +ListIterator.s.dot +Map.dot +Map.html +Map.map +Map.png +Map.s.dot +MapIterator.dot +MapIterator.html +MapIterator.map +MapIterator.png +MapIterator.s.dot +MapRead.dot +MapRead.html +MapRead.map +MapRead.png +MapRead.s.dot +Match.dot +Match.html +Match.map +Match.png +Match.s.dot +NaiveCollection.dot +NaiveCollection.html +NaiveCollection.map +NaiveCollection.png +NaiveCollection.s.dot +NativeArray.dot +NativeArray.html +NativeArray.map +NativeArray.png +NativeArray.s.dot +NativeString.dot +NativeString.html +NativeString.map +NativeString.png +NativeString.s.dot +OFStream.dot +OFStream.html +OFStream.map +OFStream.png +OFStream.s.dot +OProcess.dot +OProcess.html +OProcess.map +OProcess.png +OProcess.s.dot +OStream.dot +OStream.html +OStream.map +OStream.png +OStream.s.dot +Object.dot +Object.html +Object.map +Object.png +Object.s.dot +Option.dot +Option.html +Option.map +Option.png +Option.s.dot +OptionArray.dot +OptionArray.html +OptionArray.map +OptionArray.png +OptionArray.s.dot +OptionBool.dot +OptionBool.html +OptionBool.map +OptionBool.png +OptionBool.s.dot +OptionContext.dot +OptionContext.html +OptionContext.map +OptionContext.png +OptionContext.s.dot +OptionCount.dot +OptionCount.html +OptionCount.map +OptionCount.png +OptionCount.s.dot +OptionEnum.dot +OptionEnum.html +OptionEnum.map +OptionEnum.png +OptionEnum.s.dot +OptionInt.dot +OptionInt.html +OptionInt.map +OptionInt.png +OptionInt.s.dot +OptionParameter.dot +OptionParameter.html +OptionParameter.map +OptionParameter.png +OptionParameter.s.dot +OptionString.dot +OptionString.html +OptionString.map +OptionString.png +OptionString.s.dot +OptionText.dot +OptionText.html +OptionText.map +OptionText.png +OptionText.s.dot +Pattern.dot +Pattern.html +Pattern.map +Pattern.png +Pattern.s.dot +Pointer.dot +Pointer.html +Pointer.map +Pointer.png +Pointer.s.dot +Process.dot +Process.html +Process.map +Process.png +Process.s.dot +Range.dot +Range.html +Range.map +Range.png +Range.s.dot +Rectangle.dot +Rectangle.html +Rectangle.map +Rectangle.png +Rectangle.s.dot +RemovableCollection.dot +RemovableCollection.html +RemovableCollection.map +RemovableCollection.png +RemovableCollection.s.dot +SDL_ButtonEvent.dot +SDL_ButtonEvent.html +SDL_ButtonEvent.map +SDL_ButtonEvent.png +SDL_ButtonEvent.s.dot +SDL_Event.dot +SDL_Event.html +SDL_Event.map +SDL_Event.png +SDL_Event.s.dot +SDL_EventListener.dot +SDL_EventListener.html +SDL_EventListener.map +SDL_EventListener.png +SDL_EventListener.s.dot +SDL_EventProcessor.dot +SDL_EventProcessor.html +SDL_EventProcessor.map +SDL_EventProcessor.png +SDL_EventProcessor.s.dot +SDL_KeyboardEvent.dot +SDL_KeyboardEvent.html +SDL_KeyboardEvent.map +SDL_KeyboardEvent.png +SDL_KeyboardEvent.s.dot +SDL_MouseButtonEvent.dot +SDL_MouseButtonEvent.html +SDL_MouseButtonEvent.map +SDL_MouseButtonEvent.png +SDL_MouseButtonEvent.s.dot +SDL_MouseEvent.dot +SDL_MouseEvent.html +SDL_MouseEvent.map +SDL_MouseEvent.png +SDL_MouseEvent.s.dot +SDL_MouseMotionEvent.dot +SDL_MouseMotionEvent.html +SDL_MouseMotionEvent.map +SDL_MouseMotionEvent.png +SDL_MouseMotionEvent.s.dot +SDL_Screen.dot +SDL_Screen.html +SDL_Screen.map +SDL_Screen.png +SDL_Screen.s.dot +SDL_Surface.dot +SDL_Surface.html +SDL_Surface.map +SDL_Surface.png +SDL_Surface.s.dot +Sequence.dot +Sequence.html +Sequence.map +Sequence.png +Sequence.s.dot +SequenceRead.dot +SequenceRead.html +SequenceRead.map +SequenceRead.png +SequenceRead.s.dot +Set.dot +Set.html +Set.map +Set.png +Set.s.dot +SimpleCollection.dot +SimpleCollection.html +SimpleCollection.map +SimpleCollection.png +SimpleCollection.s.dot +Sprite.dot +Sprite.html +Sprite.map +Sprite.png +Sprite.s.dot +Stderr.dot +Stderr.html +Stderr.map +Stderr.png +Stderr.s.dot +Stdin.dot +Stdin.html +Stdin.map +Stdin.png +Stdin.s.dot +Stdout.dot +Stdout.html +Stdout.map +Stdout.png +Stdout.s.dot +StreamCat.dot +StreamCat.html +StreamCat.map +StreamCat.png +StreamCat.s.dot +StreamDemux.dot +StreamDemux.html +StreamDemux.map +StreamDemux.png +StreamDemux.s.dot +String.dot +String.html +String.map +String.png +String.s.dot +StringCapable.dot +StringCapable.html +StringCapable.map +StringCapable.png +StringCapable.s.dot +Symbol.dot +Symbol.html +Symbol.map +Symbol.png +Symbol.s.dot +Sys.dot +Sys.html +Sys.map +Sys.png +Sys.s.dot +TickCounter.dot +TickCounter.html +TickCounter.map +TickCounter.png +TickCounter.s.dot +abstract_collection.dot abstract_collection.html -abstract_collection__.html -all_.module_hierarchy.dot -all_.module_hierarchy.png +abstract_collection.map +abstract_collection.png +abstract_collection.s.dot +array.dot array.html -array__.html +array.map +array.png +array.s.dot +collection.dot collection.html -collection_.html -collection__.html +collection.map +collection.png +collection.s.dot +dep.dot +dep.map +dep.png +dep.s.dot +dummy_array.dot dummy_array.html -dummy_array__.html +dummy_array.map +dummy_array.png +dummy_array.s.dot +environ.dot environ.html -environ__.html +environ.map +environ.png +environ.s.dot +exec.dot exec.html -exec__.html +exec.map +exec.png +exec.s.dot +file.dot file.html -file__.html +file.map +file.png +file.s.dot +filter_stream.dot filter_stream.html -filter_stream__.html +filter_stream.map +filter_stream.png +filter_stream.s.dot +full-index.html +game.dot game.html -game__.html +game.map +game.png +game.s.dot +hash.dot hash.html -hash__.html +hash.map +hash.png +hash.s.dot +hash_collection.dot hash_collection.html -hash_collection__.html -index-1.html +hash_collection.map +hash_collection.png +hash_collection.s.dot index.html +kernel.dot kernel.html -kernel__.html +kernel.map +kernel.png +kernel.s.dot +list.dot list.html -list__.html +list.map +list.png +list.s.dot +math.dot math.html -math__.html -menu-frame.html +math.map +math.png +math.s.dot +opts.dot opts.html -opts__.html -overview.html +opts.map +opts.png +opts.s.dot +range.dot range.html -range__.html +range.map +range.png +range.s.dot +sdl.dot sdl.html -sdl__.html +sdl.map +sdl.png +sdl.s.dot +sorter.dot sorter.html -sorter__.html +sorter.map +sorter.png +sorter.s.dot +standard.dot standard.html -standard_.html -standard__.html +standard.map +standard.png +standard.s.dot +stream.dot stream.html -stream__.html +stream.map +stream.png +stream.s.dot +string.dot string.html -string__.html +string.map +string.png +string.s.dot +string_search.dot string_search.html -string_search__.html +string_search.map +string_search.png +string_search.s.dot +symbol.dot symbol.html -symbol__.html +symbol.map +symbol.png +symbol.s.dot +time.dot time.html -time__.html +time.map +time.png +time.s.dot -- 1.7.9.5