- var d = opt_dir.value
- if d != null then dir = d
- end
-end
-
-# Conditionnal part of the text content of a DocContext
-class StageContext
- # Content of the current stage
- readable var _content: Array[String] = new Array[String]
-
- # Is a normal string already added?
- readable writable var _validate: Bool = false
-
- # Parent stage is any
- readable var _parent: nullable StageContext = null
-
- init(parent: nullable StageContext) do _parent = parent
-end
-
-
-# Efficiently sort object with their to_s method
-class AlphaSorter[E: Object]
-special AbstractSorter[E]
- redef fun compare(a, b)
- do
- var sa: String
- var sb: String
- var d = _dico
- if d.has_key(a) then
- sa = d[a]
- else
- sa = a.to_s
- d[a] = sa
- end
- if d.has_key(b) then
- sb = d[b]
- else
- sb = b.to_s
- d[b] = sb
- end
- return sa <=> sb
- end
-
- # Keep track of to_s values
- var _dico: HashMap[Object, String] = new HashMap[Object, String]
-
- init do end
-end
-
-# Generalization of metamodel entities
-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
-special MMEntity
- redef fun html_link(dctx) do
- if dctx.module == self then
- return "{self}"
- else
- return "<a href=\"{self}.html\">{self}</a>"
- end
- 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]
- fun 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
- end
-
- # Return the most general module that own self
- fun owner(from: MMModule): MMModule
- 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
- end
-
- private fun known_owner_of_intern(module: MMModule, from: MMModule, as_owner: Bool): MMModule
- 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
- end
-
-end
-
-redef class MMLocalProperty
-special 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
- 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 "<a href=\"#{html_anchor}\">{self}</a>"
- else
- return "<a href=\"{m}.html#{html_anchor}\">{self}</a>"
- end
- end
-
- # Kind of property (fun, attr, etc.)
- fun kind: String is abstract
-
- redef fun locate(dctx)
- do
- return "in {module.html_link(dctx)}::{local_class.html_link(dctx)}"
- end
-
- fun known_intro_class(dctx: DocContext): MMLocalClass
- do
- var mod = dctx.known_owner_of(global.intro.local_class.module)
- var cla = mod[global.intro.local_class.global]
- return cla
- end
-
- redef fun prototype_head(dctx)
- do
- var res = new Buffer
- var intro_class = known_intro_class(dctx)
- var is_redef = local_class != intro_class
-
- 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 ")
- 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)}::")
- end
- end
- return res.to_s
- end
-
- redef fun prototype_body(dctx)
- do
- var res = new Buffer
- res.append(signature.to_html(dctx))
- 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")
- end
- end
- return res.to_s
- end
-
- redef fun need_doc(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
- end
- if global.intro == self then
- return true
- end
- return doc != null
- end
-
- redef fun short_doc
- do
- var d = doc
- if d != null then
- return d.short
- else if global.intro == self then
- return " "
- else
- return global.intro.short_doc
- end
- end
-
- redef fun doc
- do
- var n = node
- if n == null or not n isa APropdef then
- return null
- end
- var d = n.n_doc
- if d == null then
- return null
- end
- if d.n_comment.is_empty then
- return null
- else
- 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)
- do
- dctx.info("Generating HTML for module {name}",1)
- dctx.register(self)
-
- 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
- end
- end
-
- fun extract_module_doc_inside(dctx: DocContext)
- do
- dctx.add_header("Module {self}")
- dctx.add("<h1>Module {self}</h1>\n<dl>")
- 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}<br/>{prototype_head(dctx)}<b>{self}</b>{prototype_body(dctx)}<br/>\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
- 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("<dt>Intruded modules: <dd>{strs.join(", ")}\n")
- 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("<dt>Imported modules: <dd>{strs.join(", ")}\n")
- 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("<dt>Privatly imported modules: <dd>{strs.join(", ")}\n")
- end
- dctx.add("</dl>\n")
-
- var doc = doc
- if doc != null then dctx.add("<pre>{doc.to_html}</pre>\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
- end
-
- if not new_classes.is_empty then
- dctx.sort(new_classes)
- dctx.add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
- dctx.add("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\"><big>Class Summary of {self}</big></th><tr>\n")
- for c in new_classes do
- dctx.add("<tr><td width=\"20%\" align=\"right\">{c.prototype_head(dctx)}</td><td><b>{c.html_link(dctx)}</b>{c.prototype_body(dctx)}<br/>{c.short_doc}</td><tr>\n")
- end
- dctx.add("</table><br/>\n")
- end
-
- if not new_classes.is_empty then
- dctx.add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
- dctx.add("<tr bgcolor=\"#CCCCFF\"><th><big>Class Detail of {self}</big></th><tr>\n")
- dctx.add("</table>\n")
-
- for c in new_classes do
- c.extract_class_doc(dctx)
- end
- end
-
- dctx.add("</body></html>\n")
- end
-
- redef fun short_doc
- do
- var d = doc
- if d != null then
- return d.short
- else
- return " "
- end
- end
-
- redef fun doc
- do
- var n = node
- if n.n_packagedecl == null then
- return null
- end
- var np = n.n_packagedecl
- var d = np.n_doc
- if d == null then
- return null
- end
- if d.n_comment.is_empty then
- return null
- else
- return d
- end