X-Git-Url: http://nitlanguage.org diff --git a/src/nitdoc.nit b/src/nitdoc.nit index 18e1d0c..205caca 100644 --- a/src/nitdoc.nit +++ b/src/nitdoc.nit @@ -24,27 +24,27 @@ import abstracttool # Store knowledge and facilities to generate files class DocContext -special AbstractCompiler + super AbstractCompiler # Destination directory - readable writable attr _dir: String = "." + readable writable var _dir: String = "doc" # Content of a generated file - attr _stage_context: StageContext = new StageContext(null) + var _stage_context: StageContext = new StageContext(null) # Add a string in the content - meth add(s: String) do + fun add(s: String) do _stage_context.content.add(s) _stage_context.validate = true end # Add a string in the content iff some other string are added - meth stage(s: String) do _stage_context.content.add(s) + fun stage(s: String) do _stage_context.content.add(s) # Create a new stage in the content - meth open_stage do _stage_context = new StageContext(_stage_context) + fun open_stage do _stage_context = new StageContext(_stage_context) # Close the current stage in the content - meth close_stage + fun close_stage do var s = _stage_context.parent if _stage_context.validate then @@ -56,9 +56,8 @@ special AbstractCompiler end # Write the content to a new file - meth write_to(filename: String) + fun write_to(filename: String) do - print "Generate {filename}" var f = new OFStream.open(filename) for s in _stage_context.content do f.write(s) @@ -66,209 +65,330 @@ special AbstractCompiler f.close end - # Currently computed module - readable attr _module: nullable MMSrcModule + # Start a new file + fun clear + do + _stage_context = new StageContext(null) + end - # Is the current directory module computed as a simple modude ? - readable writable attr _inside_mode: Bool = false + # Sorter of entities in alphabetical order + var _sorter: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity] - # Is the current module computed as a intruded one ? - readable writable attr _intrude_mode: Bool = false + # Sort entities in the alphabetical order + fun sort(array: Array[MMEntity]) + do + _sorter.sort(array) + end - # Compued introducing entities (for the index) - attr _entities: Array[MMEntity] = new Array[MMEntity] + 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") + readable var _opt_private: OptionBool = new OptionBool("Generate the private API", "--private") + readable var _opt_nodot: OptionBool = new OptionBool("Do not generate graphes with graphviz", "--no-dot") - # Register an entity (for the index) - meth register(e: MMEntity) + fun public_only: Bool do - _entities.add(e) - if e isa MMSrcModule then - _module = e - end + if self._opt_public.value == true then return true + return false end - # Start a new file - meth clear + fun with_private: Bool do - _stage_context = new StageContext(null) + if self._opt_private.value == true then return true + return false end - # Generate common files (frames, index, overview) - meth extract_other_doc + # The current processed filename + var filename: String + + # The main virtual module + var mainmod: nullable MMVirtualModule + + redef fun perform_work(mods) do - _module = 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) + mainmod = new MMVirtualModule(self, mods) + + 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 - 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 + # 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}/menu-frame.html") + var head = "" + + "\n" + + "\n" + + "" + + var action_bar = "
\n" + + # generate the index + self.filename = "index.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") + add("") + add("{head}Index\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}
  • ") + end - add("
\n") - write_to("{dir}/index-1.html") + add("") - clear - add_header("Overview") - add("\n") - add("\n") - for m in modules do - add("\n") + 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 - add("
Overview of all Modules
{m.html_link(self)}{m.short_doc}
\n") - write_to("{dir}/overview.html") + op.append("\}\n") + self.gen_dot(op.to_s, "dep", "Modules hierarchy") + add("") + add("
") + add("") + add("\n") + write_to("{dir}/index.html") + # 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 + action_bar = "
\n" + clear + add("") + 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 + action_bar = "
\n" + clear + add("") + 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" + action_bar = "
\n" clear - add("\n\n\n\n\n") - write_to("{dir}/index.html") + add("") + add("{head}Full Index\n") + add(action_bar) + add("
") + add("
") + mainmod.file_index_page_doc(self) + add("
") + add("
") + add("\n") + write_to("{dir}/full-index.html") end - meth add_header(title: String) + + # Add a (source) link fo a given location + fun show_source(l: Location) do - add("{title}\n\n") - add("
\n") - add("Overview  Index  With Frames\n") - add("
") - add("Visibility: ") - if (not inside_mode and not intrude_mode) or module == null then - add("Public  ") - else - add("Public  ") - end - if inside_mode or module == null then - add("Inside  ") - else if module.directory.owner != module then - add("Inside  ") + var s = opt_source.value + if s == null then + add("in #{l.file.filename.simplify_path}") else - add("Inside  ") + # THIS IS JUST UGLY ! (but there is no replace yet) + var x = s.split_with("%f") + s = x.join(l.file.filename.simplify_path) + 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 - if intrude_mode or module == null then - add("Intrude  ") - else - add("Intrude  ") - end - add("
") end - # Sorter of entities in alphabetical order - attr _sorter: AlphaSorter[MMEntity] = new AlphaSorter[MMEntity] - - # Sort entities in the alphabetical order - meth sort(array: Array[MMEntity]) + # 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, alt: String) do - _sorter.sort(array) + if opt_nodot.value then return + 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("
\"{alt}\"/
") + var fmap = new IFStream.open("{self.dir}/{name}.map") + self.add(fmap.read_all) + fmap.close end - readable writable attr _owned_modules: Array[MMModule] = new Array[MMModule] + init + do + keep_ast = true + super("nitdoc") + filename = "-unset-" + option_context.add_option(opt_public) + option_context.add_option(opt_private) + option_context.add_option(opt_dir) + option_context.add_option(opt_source) + option_context.add_option(opt_nodot) + end - # Return the known_owner for current module - # if inside_mode is set, it could be a different result - meth known_owner_of(m: MMModule): MMModule + redef fun process_options do - var module = module - if module == null then return m - var res = module.known_owner_of(m) - if not inside_mode and not intrude_mode and res.directory.owner == module then - return module - else - return res + super + var d = opt_dir.value + if d != null then dir = d + + if not opt_nodot.value then + # Test if dot is runable + var res = sys.system("sh -c dot /dev/null 2>&1") + if res != 0 then + stderr.write "--no-dot implied since `dot' is not available. Try to install graphviz.\n" + opt_nodot.value = true + end end end - readable attr _opt_dir: OptionString = new OptionString("Directory where doc is generated", "-d", "--dir") + 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 - redef meth perform_work(mods) +redef class String + # Replace all occurence of pattern ith string + fun replace(p: Pattern, string: String): String do - dir.mkdir + return self.split_with(p).join(string) + end - for mod in modules do - assert mod isa MMSrcModule - mod.extract_module_doc(self) - end - self.extract_other_doc + # Escape the following characters < > & and " with their html counterpart + fun html_escape: String + do + var ret = self + if ret.has('&') then ret = ret.replace('&', "&") + if ret.has('<') then ret = ret.replace('<', "<") + if ret.has('>') then ret = ret.replace('>', ">") + if ret.has('"') then ret = ret.replace('"', """) + return ret end - init + # Remove "/./", "//" and "bla/../" + fun simplify_path: String do - super("nitdoc") - option_context.add_option(opt_dir) + var a = self.split_with("/") + var a2 = new Array[String] + for x in a do + if x == "." then continue + if x == "" and not a2.is_empty then continue + if x == ".." and not a2.is_empty then + a2.pop + continue + end + a2.push(x) + end + return a2.join("/") end +end - redef meth process_options +# 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 - super - var d = opt_dir.value - if d != null then dir = d + # 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 class StageContext # Content of the current stage - readable attr _content: Array[String] = new Array[String] + readable var _content: Array[String] = new Array[String] # Is a normal string already added? - readable writable attr _validate: Bool = false + readable writable var _validate: Bool = false # Parent stage is any - readable attr _parent: nullable StageContext = null + readable var _parent: nullable StageContext = null init(parent: nullable StageContext) do _parent = parent end @@ -276,8 +396,8 @@ end # Efficiently sort object with their to_s method class AlphaSorter[E: Object] -special AbstractSorter[E] - redef meth compare(a, b) + super AbstractSorter[E] + redef fun compare(a, b) do var sa: String var sb: String @@ -298,7 +418,7 @@ special AbstractSorter[E] end # Keep track of to_s values - attr _dico: HashMap[Object, String] = new HashMap[Object, String] + var _dico: HashMap[Object, String] = new HashMap[Object, String] init do end end @@ -306,177 +426,413 @@ end # Generalization of metamodel entities class MMEntity # Return a link to - meth html_link(dctx: DocContext): String is abstract - - # Is the entity should appear in the generaed doc - meth need_doc(dctx: DocContext): Bool is abstract + fun html_link(dctx: DocContext): String is abstract # Return a one liner description - meth short_doc: String do return " " + fun short_doc: String do return " " # The doc node from the AST # Return null is none - meth doc: nullable ADoc do return null - - # Human redable location of the entity (module/class/property) - meth locate(dctx: DocContext): String do return "" - - # Part of the prototype before the name (kind, modifiers, qualifier) - meth prototype_head(dctx: DocContext): String is abstract - - # Part of the property after the name (signature, modifiers) - meth prototype_body(dctx: DocContext): String do return "" + fun doc: nullable ADoc do return null end redef class MMModule -special MMEntity - redef meth html_link(dctx) do - if dctx.module == self then - return "{self}" - else - return "{self}" - end - end - redef meth need_doc(dctx) do return true - redef meth prototype_head(dctx) do return "module " - - attr _known_owner_of_cache: Map[MMModule, MMModule] = new HashMap[MMModule, MMModule] - meth known_owner_of(module: MMModule): MMModule - do - if _known_owner_of_cache.has_key(module) then return _known_owner_of_cache[module] - var res = module - if mhe < module and visibility_for(module) != 0 then - res = known_owner_of_intern(module, self, false) - else - res = module.owner(self) - end - _known_owner_of_cache[module] = res - return res + super MMEntity + redef fun html_link(dctx) do + return "{self}" end - # Return the most general module that own self - meth owner(from: MMModule): MMModule + fun require_doc(dctx: DocContext): 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 + if dctx.public_only and not is_toplevel then return false + return true end - private meth known_owner_of_intern(module: MMModule, from: MMModule, as_owner: Bool): MMModule + # Return true if the module is a top-level owner or a top-level module + fun is_toplevel: Bool do - if module == 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 <= module then continue - candidates.add(m.known_owner_of_intern(module, from, true)) - end - assert not candidates.is_empty - 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 + var pd = directory.parent + return pd == null or (pd.owner == null and directory.owner == self) end -end + # Element in the module nesting tree + fun mnhe: PartialOrderElement[MMModule] do return mnhe_.as(not null) + var mnhe_: nullable PartialOrderElement[MMModule] = null -redef class MMLocalProperty -special MMEntity - # Anchor of the property description in the module html file - meth html_anchor: String - do - return "PROP_{local_class}_{cmangle(name)}" - 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 meth html_link(dctx) + fun toplevel_owner: MMModule do - var m = module - if not need_doc(dctx) then m = global.intro.module - var m = dctx.known_owner_of(m) - if m == dctx.module 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 (meth, attr, etc.) - meth kind: String is abstract - redef meth locate(dctx) + fun html_name: String do - return "in {module.html_link(dctx)}::{local_class.html_link(dctx)}" + return "{name}" end - meth known_intro_class(dctx: DocContext): MMLocalClass + fun direct_owner: nullable MMModule do - var mod = dctx.known_owner_of(global.intro.local_class.module) - 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 meth 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(" {module[intro_class.global].html_link(dctx)}::") - else if intro_class.module != module then - res.append(" {intro_class.module.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 + 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, "Dependency graph for module {name}") + 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]) + lc.compute_super_classes + 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 + + 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.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})
  • \n") + lps.remove(lpi) + else + dctx.add("
  • I {lpi.html_name}") + dctx.add(" ({lpi.local_class})
  • \n") + end + if lps.length >= 1 then + dctx.sort(lps) + for lp in lps do + dctx.add("
  • R {lp.html_open_link(dctx)}{lp.html_name} ({lp.local_class})
  • ") + end + end + end + dctx.stage("
\n") + dctx.close_stage + dctx.add("
\n") + dctx.add("
\n") end - redef meth prototype_body(dctx) + # Fill the body for the page associated to the full index + fun file_index_page_doc(dctx: DocContext) do - var res = new Buffer - res.append(signature.to_html(dctx)) - var s = self - if s.node != null then - if s.node isa ADeferredMethPropdef then - res.append(" is abstract") - else if s.node isa AInternMethPropdef then - res.append(" is intern") + + 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 - return res.to_s + dctx.open_stage + dctx.stage("
\n") + dctx.stage("

Modules

\n") + dctx.sort(mods) + dctx.stage("
\n") + dctx.close_stage + + dctx.open_stage + dctx.stage("
\n") + dctx.stage("

Classes

\n") + dctx.sort(clas) + dctx.stage("
\n") + dctx.close_stage + + dctx.open_stage + dctx.stage("
\n") + dctx.stage("

Properties

\n") + dctx.sort(gprops) + 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 + + fun html_open_link(dctx: DocContext): String + do + if not require_doc(dctx) then print "not required {self}" + var title = "{html_name}{signature.to_s}" + if short_doc != " " then + title += " #{short_doc}" + end + return "" + end + + fun html_name: String + do + return self.name.to_s.html_escape end - redef meth need_doc(dctx) + redef fun html_link(dctx) do - if global.visibility_level >= 3 or self isa MMAttribute then - if not dctx.intrude_mode then return false - if dctx.module.visibility_for(module) == 0 then return false + if not require_doc(dctx) then print "not required {self}" + var title = "{html_name}{signature.to_s}" + if short_doc != " " then + title += " #{short_doc}" end - if global.intro == self then - return true + return "{html_name}" + end + + fun html_link_special(dctx: DocContext, lc: MMLocalClass): String + do + if not require_doc(dctx) then print "not required {self}" + var title = "{html_name}{signature_for(lc.get_type)}" + if short_doc != " " then + title += " #{short_doc}" end - return doc != null + return "{html_name}" end - redef meth short_doc + # Kind of property (fun, attr, etc.) + fun kind: String is abstract + + redef fun short_doc do var d = doc if d != null then @@ -488,160 +844,206 @@ special MMEntity end end - redef meth doc + redef fun doc do var n = node - if n == null or not node isa PPropdef then + if n == null or not n isa APropdef then return null end - assert n isa PPropdef var d = n.n_doc if d == null then return null end - assert d isa ADoc if d.n_comment.is_empty then return null else return d end end -end -redef class MMMethod - redef meth kind do return if global.is_init then "init" else "meth" -end -redef class MMAttribute - redef meth kind do return "attr" -end -redef class MMTypeProperty - redef meth kind do return "type" -end -redef class MMSrcModule - # Extract and generate html file for the module - meth 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.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 property must be documented according to the visibility configured + fun require_doc(dctx: DocContext): Bool + do + if global.visibility_level == 3 and not dctx.with_private 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 - meth 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 + + 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("

{html_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 + 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 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") + if is_redef then + dctx.add("::{mmmodule[intro_class.global][global].html_link(dctx)}") + else + dctx.add("::{html_name}") 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("
") + + 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 + + var introdoc = false + if global.intro.doc != null then + for lp in lps do + if lp.doc == null then introdoc = true + end 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 introdoc then + dctx.add("
{global.intro.doc.to_html}
") end - dctx.add("
\n") - 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 + 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 + + 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 - 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 + # We skip this module since the props defined by the module is + continue end - 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") + var tlcm = lc.global.intro.mmmodule.toplevel_owner + if not tlcm.mhe <= tm then + dctx.add("

In module {tm.html_link(dctx)} :

") end - dctx.add("
Class Summary of {self}
{c.prototype_head(dctx)}{c.html_link(dctx)}{c.prototype_body(dctx)}
{c.short_doc}

\n") - end - if not new_classes.is_empty then - dctx.add("\n") - dctx.add("\n") - dctx.add("
Class Detail of {self}
\n") + #dctx.add("

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

") - for c in new_classes do - c.extract_class_doc(dctx) + var doc = tlp.doc + if doc != null and (not introdoc or global.intro.doc != doc) then + dctx.add("
{doc.to_html}
") end - 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 - dctx.add("\n") + #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 meth short_doc +redef class MMSrcModule + redef fun short_doc do var d = doc if d != null then @@ -651,19 +1053,17 @@ redef class MMSrcModule end end - redef meth doc + redef fun doc do var n = node - if n.n_packagedecl == null then + if n.n_moduledecl == null then return null end - var np = n.n_packagedecl - assert np isa APackagedecl + var np = n.n_moduledecl var d = np.n_doc if d == null then return null end - assert d isa ADoc if d.n_comment.is_empty then return null else @@ -674,389 +1074,331 @@ end redef class ADoc # Html transcription of the doc - meth to_html: String + fun to_html: String do var res = new Buffer for c in n_comment do res.append(c.text.substring_from(1)) end - return res.to_s + return res.to_s.html_escape end # Oneliner transcription of the doc - meth short: String + fun short: String do - return n_comment.first.text.substring_from(1) + return n_comment.first.text.substring_from(1).html_escape end end redef class MMLocalClass -special MMEntity + super MMEntity + # Anchor of the class description in the module html file - meth html_anchor: String do return "CLASS_{self}" + fun html_anchor: String do return "CLASS_{self}" - redef meth html_link(dctx) + fun html_name: String do return "{self}" + + redef fun html_link(dctx) do - var m = module - if not need_doc(dctx) then m = global.module - var m = dctx.known_owner_of(m) - if m == dctx.module then - return "{self}" - else - return "{self}" - end + if not require_doc(dctx) then print "{dctx.filename}: not required {self}" + return "{self}" end - redef meth short_doc do return global.intro.short_doc + redef fun short_doc do return global.intro.short_doc - redef meth doc do return global.intro.doc + redef fun doc do return global.intro.doc - redef meth need_doc(dctx) do - if module == dctx.module 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 meth locate(dctx) do return "in {module.html_link(dctx)}" - - meth known_intro(dctx: DocContext): MMLocalClass do return dctx.known_owner_of(global.intro.module)[global] - - redef meth 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.module.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 meth 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 - meth 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}

    {module.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.module) - if intro_module != module 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.module) - if km != module and km != intro_module and not mods.has(km) then - mods.add(km) - end + if global.visibility_level == 3 and not dctx.with_private 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.module) then sup2.add(c.module.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 - - meth pass_name(pass: Int): String - do - var names = once ["Virtual Types", "Consructors", "Methods", "Attributes"] - return names[pass] - end - - meth 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 - - meth 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 module.visibility_for(g.intro.module) < 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) - end - - new_props.add(p) - if p.global.intro == p then - dctx.register(p) + 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 + var t = sm + sm = sm2 + sm2 = t end - dctx.sort(new_props) - for p in new_props do - dctx.add("\n") - 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]] - var props = new Array[MMLocalClass] - for c in che.greaters do - if c isa MMSrcLocalClass then - var km = dctx.known_owner_of(c.module) - var kc = km[c.global] - if kc == self then continue - var props: Array[MMLocalProperty] - if km == module 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 module.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, "Inheritance graph for class {name}") + - var mmap = new HashMap[MMModule, Array[MMLocalProperty]] - var props = new Array[MMLocalClass] - for c in crhe.order do - if module.mhe <= c.module or dctx.owned_modules.has(c.module) or not c isa MMSrcLocalClass then continue - var km = dctx.known_owner_of(c.module) - if module.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.open_stage - dctx.stage("\n") - for c in crhe.order do - var m = c.module - 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 - meth 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.module.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 - meth 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 = module.html_link(dctx) - else - s = self.html_link(dctx) - end - dctx.add("in {s}{properties.join(", ")}\n") - end + dctx.add(" \n") end end redef class MMSrcLocalClass - redef meth short_doc + redef fun short_doc do var d = doc if d != null then @@ -1069,53 +1411,38 @@ redef class MMSrcLocalClass end end - redef meth doc + redef fun doc do - var n = nodes.first - if not n isa AClassdef then + var n = node + if not n isa AStdClassdef then return null end - assert n isa AClassdef var d = n.n_doc if d == null then return null end - assert d isa ADoc if d.n_comment.is_empty then return null else return d end end - - redef meth need_doc(dctx) - do - if global.visibility_level >= 3 then - if not dctx.intrude_mode then return false - if dctx.module.visibility_for(module) == 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 # Htlm transcription of the signature (with nested links) - meth to_html(dctx: DocContext): String + fun to_html(dctx: DocContext, with_closure: Bool): String do 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(")") @@ -1124,21 +1451,31 @@ redef class MMSignature res.append(": ") res.append(return_type.html_link(dctx)) end + if with_closure then + for c in closures do + res.append(" ") + if c.is_optional then res.append("[") + if c.is_break then res.append("break ") + res.append("!{c.name}") + res.append(c.signature.to_html(dctx, false)) + if c.is_optional then res.append("]") + end + end return res.to_s end end redef class MMType # Htlm transcription of the type (with nested links) - meth html_link(dctx: DocContext): String do return to_s + fun html_link(dctx: DocContext): String do return to_s end redef class MMTypeSimpleClass - redef meth html_link(dctx) do return local_class.html_link(dctx) + redef fun html_link(dctx) do return local_class.html_link(dctx) end redef class MMTypeGeneric - redef meth html_link(dctx) + redef fun html_link(dctx) do var res = new Buffer res.append(local_class.html_link(dctx)) @@ -1153,5 +1490,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