From 017fa5a07885a1e7018dc5be2b8e81fba82bb7d6 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 30 Mar 2016 12:16:16 +0100 Subject: [PATCH 01/50] docgen: initial version of the Eolian documentation generator --- build.sh | 6 + gendoc.lua | 397 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 403 insertions(+) create mode 100755 build.sh create mode 100644 gendoc.lua diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000..3e20c64301 --- /dev/null +++ b/build.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +ROOTNS="efl" +GENPATH="dokuwiki/data/pages" +rm -rf "$GENPATH/$ROOTNS" +elua gendoc.lua -r "$GENPATH" -n "$ROOTNS" diff --git a/gendoc.lua b/gendoc.lua new file mode 100644 index 0000000000..4285e1cf4b --- /dev/null +++ b/gendoc.lua @@ -0,0 +1,397 @@ +local eolian = require("eolian") +local getopt = require("getopt") +local cutil = require("cutil") +local util = require("util") + +local doc_root +local root_nspace + +-- utils + +local make_page = function(path) + return doc_root .. "/" .. path .. ".txt" +end + +local mkdir_r = function(dirn) + local fullp = dirn and (doc_root .. "/" .. dirn) or doc_root + local prev + for x in fullp:gmatch("[^/]+") do + local p + if prev then + p = prev .. "/" .. x + else + p = x + end + prev = p + if cutil.file_exists(p) then + assert(cutil.file_is_dir(p)) + else + assert(cutil.file_mkdir(p)) + end + end +end + +local mkdir_p = function(path) + mkdir_r(path:match("(.+)/([^/]+)")) +end + +local Writer = util.Object:clone { + __ctor = function(self, path) + local subs = path:gsub(":", "/"):lower() + mkdir_p(subs) + self.file = assert(io.open(make_page(subs), "w")) + end, + + write_raw = function(self, ...) + self.file:write(...) + end, + + write_nl = function(self, n) + self:write_raw(("\n"):rep(n or 1)) + end, + + write_h = function(self, heading, level, nonl) + local s = ("="):rep(7 - level) + self:write_raw(s, " ", heading, " ", s, "\n") + if not nonl then + self:write_nl() + end + end, + + write_fmt = function(self, fmt1, fmt2, ...) + self:write_raw(fmt1, ...) + self:write_raw(fmt2) + end, + + write_b = function(self, ...) + self:write_fmt("**", "**", ...) + end, + + write_i = function(self, ...) + self:write_fmt("//", "//", ...) + end, + + write_u = function(self, ...) + self:write_fmt("__", "__", ...) + end, + + write_s = function(self, ...) + self:write_fmt("", "", ...) + end, + + write_m = function(self, ...) + self:write_fmt("''", "''", ...) + end, + + write_sub = function(self, ...) + self:write_fmt("", "", ...) + end, + + write_sup = function(self, ...) + self:write_fmt("", "", ...) + end, + + write_br = function(self, nl) + self:write_raw("\\\\", nl and "\n" or " ") + end, + + write_pre_inline = function(self, ...) + self:write_fmt("%%", "%%", ...) + end, + + write_pre = function(self, ...) + self:write_fmt("\n", "\n", ...) + end, + + write_link = function(self, target, title) + if not title then + self:write_raw("[[", target:lower(), "|", target, "]]") + return + end + target = target:lower() + if type(title) == "string" then + self:write_raw("[[", target, "|", title, "]]") + return + end + self:write_raw("[[", target, "|") + title(self) + self:write_raw("]]") + end, + + write_table = function(self, titles, tbl) + self:write_raw("^ ", table.concat(titles, " ^ "), " ^\n") + for i, v in ipairs(tbl) do + self:write_raw("| ", table.concat(v, " | "), " |\n") + end + end, + + write_list = function(self, tbl, ord) + local prec = ord and "-" or "*" + for i, v in ipairs(tbl) do + local lvl, str = 1, v + if type(v) == "table" then + lvl, str = v[1] + 1, v[2] + end + self:write_raw((" "):rep(lvl), prec, " ", str, "\n") + end + end, + + finish = function(self) + self.file:close() + end +} + +local Buffer = Writer:clone { + __ctor = function(self) + self.buf = {} + end, + + write_raw = function(self, ...) + for i, v in ipairs({ ... }) do + self.buf[#self.buf + 1] = v + end + end, + + finish = function(self) + self.result = table.concat(self.buf) + self.buf = {} + return self.result + end +} + +-- eolian to various doc elements conversions + +local get_brief_doc = function(doc) + if not doc then + return "No description supplied." + end + return doc:summary_get() +end + +local get_full_doc = function(doc) + if not doc then + return "No description supplied." + end + local sum = doc:summary_get() + local desc = doc:description_get() + if not desc then + return sum + end + return sum .. "\n\n" .. desc +end + +local gen_namespaces = function(v, subnspace, root) + local nspaces = v:namespaces_get():to_array() + for i = 1, #nspaces do + nspaces[i] = nspaces[i]:lower() + end + nspaces[#nspaces + 1] = v:name_get() + if subnspace then + table.insert(nspaces, 1, subnspace) + end + if root then + table.insert(nspaces, 1, ":" .. root_nspace) + end + return table.concat(nspaces, ":") +end + +local funct_to_str = { + [eolian.function_type.PROPERTY] = "property", + [eolian.function_type.PROP_GET] = "property", + [eolian.function_type.PROP_SET] = "property", + [eolian.function_type.METHOD] = "method" +} + +local gen_func_link = function(base, f) + local ft = funct_to_str[f:type_get()] + return base .. ":" .. ft .. ":" .. f:name_get():lower() +end + +-- builders + +local classt_to_str = { + [eolian.class_type.REGULAR] = "class", + [eolian.class_type.ABSTRACT] = "class", + [eolian.class_type.MIXIN] = "mixin", + [eolian.class_type.INTERFACE] = "interface" +} + +local build_reftable = function(f, title, ctitle, ctype, t) + if not t or #t == 0 then + return + end + f:write_h(title, 2) + local nt = {} + for i, v in ipairs(t) do + local lbuf = Buffer() + lbuf:write_link(gen_namespaces(v, ctype, true), v:full_name_get()) + nt[#nt + 1] = { + lbuf:finish(), get_brief_doc(v:documentation_get()) + } + end + table.sort(nt, function(v1, v2) return v1[1] < v2[1] end) + f:write_table({ ctitle, "Brief description" }, nt) + f:write_nl() +end + +local build_functable = function(f, title, ctitle, cl, tp) + local t = cl:functions_get(tp):to_array() + if #t == 0 then + return + end + local cns = gen_namespaces(cl, classt_to_str[cl:type_get()], true) + f:write_h(title, 2) + local nt = {} + for i, v in ipairs(t) do + local lbuf = Buffer() + local ftype = funct_to_str[v:type_get()] + lbuf:write_link(gen_func_link(cns, v), v:name_get()) + nt[#nt + 1] = { + lbuf:finish(), get_brief_doc(v:documentation_get(eolian.function_type.METHOD)) + } + end + table.sort(nt, function(v1, v2) return v1[1] < v2[1] end) + f:write_table({ ctitle, "Brief description" }, nt) + f:write_nl() +end + +local build_ref = function() + local f = Writer("reference") + f:write_h("EFL Reference", 2) + + local classes = {} + local ifaces = {} + local mixins = {} + + local clt = eolian.class_type + + for cl in eolian.all_classes_get() do + local tp = cl:type_get() + if tp == clt.REGULAR or tp == clt.ABSTRACT then + classes[#classes + 1] = cl + elseif tp == clt.MIXIN then + mixins[#mixins + 1] = cl + elseif tp == clt.INTERFACE then + ifaces[#ifaces + 1] = cl + else + error("unknown class: " .. cl:full_name_get()) + end + end + + build_reftable(f, "Classes", "Class name", "class", classes) + build_reftable(f, "Interfaces", "Interface name", "interface", ifaces) + build_reftable(f, "Mixins", "Mixin name", "mixin", mixins) + + build_reftable(f, "Aliases", "Alias name", "alias", + eolian.typedecl_all_aliases_get():to_array()) + + build_reftable(f, "Structures", "Struct name", "struct", + eolian.typedecl_all_structs_get():to_array()) + + build_reftable(f, "Enums", "Enum name", "enum", + eolian.typedecl_all_enums_get():to_array()) + + build_reftable(f, "Constants", "Constant name", "constant", + eolian.variable_all_constants_get():to_array()) + + build_reftable(f, "Globals", "Global name", "global", + eolian.variable_all_globals_get():to_array()) + + f:finish() +end + +local write_full_doc = function(f, doc) + f:write_raw(get_full_doc(doc)) + f:write_nl(2) + local since = doc and doc:since_get() or nil + if since then + f:write_i(since) + f:write_nl(2) + end +end + +local build_class = function(cl) + local f = Writer(gen_namespaces(cl, classt_to_str[cl:type_get()], false)) + + f:write_h(cl:full_name_get(), 2) + + f:write_h("Description", 3) + write_full_doc(f, cl:documentation_get()) + + f:write_h("Methods", 3) + build_functable(f, "Methods", "Method name", cl, eolian.function_type.METHOD) + + f:write_h("Properties", 3) + build_functable(f, "Properties", "Property name", + cl, eolian.function_type.PROPERTY) + + f:write_h("Events", 3) + local evs = cl:events_get():to_array() + if #evs == 0 then + f:write_raw("This class does not define any events.\n") + else + for i, ev in ipairs(evs) do + f:write_h(ev:name_get(), 4) + write_full_doc(f, ev:documentation_get()) + end + end + + f:finish() +end + +local build_classes = function() + for cl in eolian.all_classes_get() do + local ct = cl:type_get() + if not classt_to_str[ct] then + error("unknown class: " .. cl:full_name_get()) + end + build_class(cl) + end +end + +getopt.parse { + args = arg, + descs = { + { category = "General" }, + { "h", "help", nil, help = "Show this message.", metavar = "CATEGORY", + callback = getopt.help_cb(io.stdout) + }, + -- TODO: implement verbose mode + { "v", "verbose", false, help = "Be verbose." }, + + { category = "Generator" }, + { "r", "root", true, help = "Root path of the docs." }, + { "n", "namespace", true, help = "Root namespace of the docs." } + }, + error_cb = function(parser, msg) + io.stderr:write(msg, "\n") + getopt.help(parser, io.stderr) + end, + done_cb = function(parser, opts, args) + root_nspace = opts["n"] or "efl" + if not opts["r"] then + error("no documentation root supplied") + end + doc_root = opts["r"] .. "/" .. root_nspace:gsub(":", "/") + if not args[1] then + if not eolian.system_directory_scan() then + error("failed scanning system directory") + end + else + if not eolian.directory_scan(args[1]) then + error("failed scanning directory: " .. args[1]) + end + end + if not eolian.all_eot_files_parse() then + error("failed parsing eo type files") + end + if not eolian.all_eo_files_parse() then + error("failed parsing eo files") + end + mkdir_r(nil) + build_ref() + build_classes() + end +} + +return true \ No newline at end of file From ada2474acffcb377eff70475a28eee451b7cc118 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 31 Mar 2016 14:22:13 +0100 Subject: [PATCH 02/50] docgen: add inheritance hierarchy generation --- gendoc.lua | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/gendoc.lua b/gendoc.lua index 4285e1cf4b..fd257654c2 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -5,6 +5,7 @@ local util = require("util") local doc_root local root_nspace +local verbose = false -- utils @@ -310,11 +311,34 @@ local write_full_doc = function(f, doc) end end +local build_inherits +build_inherits = function(cl, t, lvl) + t = t or {} + lvl = lvl or 0 + local lbuf = Buffer() + local cltp = classt_to_str[cl:type_get()] + lbuf:write_link(gen_namespaces(cl, cltp, true), cl:full_name_get()) + lbuf:write_raw(" ") + lbuf:write_i("(" .. cltp .. ")") + t[#t + 1] = { lvl, lbuf:finish() } + for cln in cl:inherits_get() do + local acl = eolian.class_get_by_name(cln) + if not acl then + error("error retrieving inherited class " .. cln) + end + build_inherits(acl, t, lvl + 1) + end + return t +end + local build_class = function(cl) local f = Writer(gen_namespaces(cl, classt_to_str[cl:type_get()], false)) f:write_h(cl:full_name_get(), 2) + f:write_h("Inheritance hierarchy", 3) + f:write_list(build_inherits(cl)) + f:write_h("Description", 3) write_full_doc(f, cl:documentation_get()) @@ -368,6 +392,9 @@ getopt.parse { getopt.help(parser, io.stderr) end, done_cb = function(parser, opts, args) + if opts["v"] then + verbose = true + end root_nspace = opts["n"] or "efl" if not opts["r"] then error("no documentation root supplied") From e12ecb1a987e45ab3a75f811a7067581e55b8fc2 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 31 Mar 2016 14:32:34 +0100 Subject: [PATCH 03/50] docgen: add readme to doc generator --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000000..9b501ddfc2 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# docgen + +This is the upcoming documentation generator for EFL. It takes documentation +described in Eo files and turns it into a DokuWiki structure (with possibility +of adapting it to other systems later on). + +Use the supplied build.sh script to generate. By default, it assumes that a +directory called "dokuwiki" is present in the current directory, so symlink +your dokuwiki setup into it (or change the path). From a9390ccd9d1bcc01ffb893cec0f1c0ce44fa96bb Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 31 Mar 2016 14:33:50 +0100 Subject: [PATCH 04/50] docgen: pass extra arguments to the docgen script in build.sh --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 3e20c64301..b9c889a90c 100755 --- a/build.sh +++ b/build.sh @@ -3,4 +3,4 @@ ROOTNS="efl" GENPATH="dokuwiki/data/pages" rm -rf "$GENPATH/$ROOTNS" -elua gendoc.lua -r "$GENPATH" -n "$ROOTNS" +elua gendoc.lua -r "$GENPATH" -n "$ROOTNS" "$@" From 885f0131a8e62d65ec4b6102d27cbac8b3685cf6 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 31 Mar 2016 14:40:27 +0100 Subject: [PATCH 05/50] docgen: topmost line in inheritance hierarchy is bold --- gendoc.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gendoc.lua b/gendoc.lua index fd257654c2..f5da5e1379 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -320,6 +320,9 @@ build_inherits = function(cl, t, lvl) lbuf:write_link(gen_namespaces(cl, cltp, true), cl:full_name_get()) lbuf:write_raw(" ") lbuf:write_i("(" .. cltp .. ")") + if lvl == 0 then + lbuf:write_b(lbuf:finish()) + end t[#t + 1] = { lvl, lbuf:finish() } for cln in cl:inherits_get() do local acl = eolian.class_get_by_name(cln) From d3b6ab7c2d7cb6476f6441dfb4e1c358dcacf0fe Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 31 Mar 2016 15:06:13 +0100 Subject: [PATCH 06/50] docgen: do not generate unnecessary headings --- gendoc.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index f5da5e1379..331548f37f 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -241,7 +241,7 @@ local build_functable = function(f, title, ctitle, cl, tp) return end local cns = gen_namespaces(cl, classt_to_str[cl:type_get()], true) - f:write_h(title, 2) + f:write_h(title, 3) local nt = {} for i, v in ipairs(t) do local lbuf = Buffer() @@ -345,10 +345,7 @@ local build_class = function(cl) f:write_h("Description", 3) write_full_doc(f, cl:documentation_get()) - f:write_h("Methods", 3) build_functable(f, "Methods", "Method name", cl, eolian.function_type.METHOD) - - f:write_h("Properties", 3) build_functable(f, "Properties", "Property name", cl, eolian.function_type.PROPERTY) From 90ab6e07f15a182c482228c59772a707faf1b096 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 31 Mar 2016 15:43:57 +0100 Subject: [PATCH 07/50] docgen: prepare generators for function doc support --- gendoc.lua | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 331548f37f..bcc652fb3c 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -162,23 +162,39 @@ local Buffer = Writer:clone { -- eolian to various doc elements conversions -local get_brief_doc = function(doc) - if not doc then +local get_brief_doc = function(doc1, doc2) + if not doc1 and not doc2 then return "No description supplied." end - return doc:summary_get() + if not doc1 then + doc1, doc2 = doc2, doc1 + end + return doc1:summary_get() end -local get_full_doc = function(doc) - if not doc then +local get_full_doc = function(doc1, doc2) + if not doc1 and not doc2 then return "No description supplied." end - local sum = doc:summary_get() - local desc = doc:description_get() - if not desc then - return sum + if not doc1 then + doc1, doc2 = doc2, doc1 end - return sum .. "\n\n" .. desc + local sum1 = doc1:summary_get() + local desc1 = doc1:description_get() + local edoc = "" + if doc2 then + local sum2 = doc2:summary_get() + local desc2 = doc2:description_get() + if not desc2 then + if sum2 then edoc = "\n\n" .. sum2 end + else + edoc = "\n\n" .. sum2 .. "\n\n" .. desc2 + end + end + if not desc1 then + return sum1 .. edoc + end + return sum1 .. "\n\n" .. desc1 .. edoc end local gen_namespaces = function(v, subnspace, root) @@ -301,10 +317,16 @@ local build_ref = function() f:finish() end -local write_full_doc = function(f, doc) - f:write_raw(get_full_doc(doc)) +local write_full_doc = function(f, doc1, doc2) + f:write_raw(get_full_doc(doc1, doc2)) f:write_nl(2) - local since = doc and doc:since_get() or nil + local since + if doc2 then + since = doc2:since_get() + end + if not since and doc then + since = doc:since_get() + end if since then f:write_i(since) f:write_nl(2) From 90f2f0bb65fc73c3adb3e5ccbf8e0ed89fd57194 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 31 Mar 2016 15:53:57 +0100 Subject: [PATCH 08/50] docgen: properly get the secondary function type for properties --- gendoc.lua | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/gendoc.lua b/gendoc.lua index bcc652fb3c..7b144779b2 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -162,6 +162,17 @@ local Buffer = Writer:clone { -- eolian to various doc elements conversions +local get_fallback_ftype = function(f, ftype) + if not ftype then + local ft = f:get_type() + local ftt = eolian.function_type + if ft == ftt.PROP_GET or ft == ftt.PROP_SET then + return ftt + end + end + return ftype +end + local get_brief_doc = function(doc1, doc2) if not doc1 and not doc2 then return "No description supplied." @@ -172,6 +183,11 @@ local get_brief_doc = function(doc1, doc2) return doc1:summary_get() end +local get_brief_fdoc = function(f, ftype) + return get_brief_doc(f:documentation_get(eolian.function_type.METHOD), + f:documentation_get(get_fallback_ftype(ftype))) +end + local get_full_doc = function(doc1, doc2) if not doc1 and not doc2 then return "No description supplied." @@ -197,6 +213,11 @@ local get_full_doc = function(doc1, doc2) return sum1 .. "\n\n" .. desc1 .. edoc end +local get_full_fdoc = function(f, ftype) + return get_full_doc(f:documentation_get(eolian.function_type.METHOD), + f:documentation_get(get_fallback_ftype(ftype))) +end + local gen_namespaces = function(v, subnspace, root) local nspaces = v:namespaces_get():to_array() for i = 1, #nspaces do @@ -333,6 +354,11 @@ local write_full_doc = function(f, doc1, doc2) end end +local write_full_fdoc = function(f, fn, ftype) + write_full_doc(f, fn:documentation_get(eolian.function_type.METHOD), + fn:documentation_get(get_fallback_ftype(ftype))) +end + local build_inherits build_inherits = function(cl, t, lvl) t = t or {} From c57ad6e0d9d2843250a6a52469719178d649f7d6 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 31 Mar 2016 15:58:15 +0100 Subject: [PATCH 09/50] docgen: generate brief func/property descriptions correctly --- gendoc.lua | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 7b144779b2..11daa2808f 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -162,15 +162,18 @@ local Buffer = Writer:clone { -- eolian to various doc elements conversions -local get_fallback_ftype = function(f, ftype) +local get_fallback_fdoc = function(f, ftype) if not ftype then - local ft = f:get_type() + local ft = f:type_get() local ftt = eolian.function_type if ft == ftt.PROP_GET or ft == ftt.PROP_SET then - return ftt + ftype = ft end end - return ftype + if ftype then + return f:documentation_get(ftype) + end + return nil end local get_brief_doc = function(doc1, doc2) @@ -185,7 +188,7 @@ end local get_brief_fdoc = function(f, ftype) return get_brief_doc(f:documentation_get(eolian.function_type.METHOD), - f:documentation_get(get_fallback_ftype(ftype))) + get_fallback_fdoc(f, ftype)) end local get_full_doc = function(doc1, doc2) @@ -215,7 +218,7 @@ end local get_full_fdoc = function(f, ftype) return get_full_doc(f:documentation_get(eolian.function_type.METHOD), - f:documentation_get(get_fallback_ftype(ftype))) + get_fallback_fdoc(f, ftype)) end local gen_namespaces = function(v, subnspace, root) @@ -285,7 +288,7 @@ local build_functable = function(f, title, ctitle, cl, tp) local ftype = funct_to_str[v:type_get()] lbuf:write_link(gen_func_link(cns, v), v:name_get()) nt[#nt + 1] = { - lbuf:finish(), get_brief_doc(v:documentation_get(eolian.function_type.METHOD)) + lbuf:finish(), get_brief_fdoc(v) } end table.sort(nt, function(v1, v2) return v1[1] < v2[1] end) @@ -356,7 +359,7 @@ end local write_full_fdoc = function(f, fn, ftype) write_full_doc(f, fn:documentation_get(eolian.function_type.METHOD), - fn:documentation_get(get_fallback_ftype(ftype))) + get_fallback_fdoc(fn, ftype)) end local build_inherits From 53c767a5423c8b1457f919b49bb9146f30df11dc Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 6 Apr 2016 14:04:04 +0100 Subject: [PATCH 10/50] docgen: initial generation of function descriptions --- gendoc.lua | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/gendoc.lua b/gendoc.lua index 11daa2808f..f493fb1878 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -243,6 +243,12 @@ local funct_to_str = { [eolian.function_type.METHOD] = "method" } +local propt_to_type = { + [eolian.function_type.PROPERTY] = "(get, set)", + [eolian.function_type.PROP_GET] = "(get)", + [eolian.function_type.PROP_SET] = "(set)", +} + local gen_func_link = function(base, f) local ft = funct_to_str[f:type_get()] return base .. ":" .. ft .. ":" .. f:name_get():lower() @@ -257,6 +263,8 @@ local classt_to_str = { [eolian.class_type.INTERFACE] = "interface" } +local build_method, build_property + local build_reftable = function(f, title, ctitle, ctype, t) if not t or #t == 0 then return @@ -285,11 +293,20 @@ local build_functable = function(f, title, ctitle, cl, tp) local nt = {} for i, v in ipairs(t) do local lbuf = Buffer() - local ftype = funct_to_str[v:type_get()] lbuf:write_link(gen_func_link(cns, v), v:name_get()) + local pt = propt_to_type[v:type_get()] + if pt then + lbuf:write_raw(" ") + lbuf:write_i(pt) + end nt[#nt + 1] = { lbuf:finish(), get_brief_fdoc(v) } + if funct_to_str[v:type_get()] == "property" then + build_property(v, cl, linkt) + else + build_method(v, cl, linkt) + end end table.sort(nt, function(v1, v2) return v1[1] < v2[1] end) f:write_table({ ctitle, "Brief description" }, nt) @@ -424,6 +441,63 @@ local build_classes = function() end end +build_method = function(fn, cl) + local cns = gen_namespaces(cl, classt_to_str[cl:type_get()], false):lower() + .. ":method:" .. fn:name_get():lower() + local f = Writer(cns) + + f:write_h(fn:name_get(), 2) + + f:write_h("Description", 3) + write_full_doc(f, fn:documentation_get(eolian.function_type.METHOD)) + + f:finish() +end + +build_property = function(fn, cl) + local cns = gen_namespaces(cl, classt_to_str[cl:type_get()], false):lower() + .. ":property:" .. fn:name_get():lower() + local f = Writer(cns) + + local fts = eolian.function_type + local ft = fn:type_get() + local isget = (ft == fts.PROP_GET or ft == fts.PROPERTY) + local isset = (ft == fts.PROP_SET or ft == fts.PROPERTY) + + local doc = fn:documentation_get(fts.PROPERTY) + local gdoc = fn:documentation_get(fts.PROP_GET) + local sdoc = fn:documentation_get(fts.PROP_SET) + + f:write_h(fn:name_get(), 2) + + if isget and isset then + f:write_h("Description", 3) + if doc or (not gdoc and not sdoc) then + write_full_doc(f, doc) + end + end + + if isget and gdoc then + if isset then + f:write_h("Getter", 4) + else + f:write_h("Description", 3) + end + write_full_doc(f, gdoc) + end + + if isset and sdoc then + if isget then + f:write_h("Setter", 4) + else + f:write_h("Description", 3) + end + write_full_doc(f, sdoc) + end + + f:finish() +end + getopt.parse { args = arg, descs = { From 6ac7e3ee80d0b0f5bb4551497a9c8d589c4cc551 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 6 Apr 2016 14:10:21 +0100 Subject: [PATCH 11/50] docgen: allow for buffer chaining --- gendoc.lua | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index f493fb1878..c4b9a8e7ae 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -45,10 +45,12 @@ local Writer = util.Object:clone { write_raw = function(self, ...) self.file:write(...) + return self end, write_nl = function(self, n) self:write_raw(("\n"):rep(n or 1)) + return self end, write_h = function(self, heading, level, nonl) @@ -57,51 +59,63 @@ local Writer = util.Object:clone { if not nonl then self:write_nl() end + return self end, write_fmt = function(self, fmt1, fmt2, ...) self:write_raw(fmt1, ...) self:write_raw(fmt2) + return self end, write_b = function(self, ...) self:write_fmt("**", "**", ...) + return self end, write_i = function(self, ...) self:write_fmt("//", "//", ...) + return self end, write_u = function(self, ...) self:write_fmt("__", "__", ...) + return self end, write_s = function(self, ...) self:write_fmt("", "", ...) + return self end, write_m = function(self, ...) self:write_fmt("''", "''", ...) + return self end, write_sub = function(self, ...) self:write_fmt("", "", ...) + return self end, write_sup = function(self, ...) self:write_fmt("", "", ...) + return self end, write_br = function(self, nl) self:write_raw("\\\\", nl and "\n" or " ") + return self end, write_pre_inline = function(self, ...) self:write_fmt("%%", "%%", ...) + return self end, write_pre = function(self, ...) self:write_fmt("\n", "\n", ...) + return self end, write_link = function(self, target, title) @@ -112,11 +126,12 @@ local Writer = util.Object:clone { target = target:lower() if type(title) == "string" then self:write_raw("[[", target, "|", title, "]]") - return + return self end self:write_raw("[[", target, "|") title(self) self:write_raw("]]") + return self end, write_table = function(self, titles, tbl) @@ -124,6 +139,7 @@ local Writer = util.Object:clone { for i, v in ipairs(tbl) do self:write_raw("| ", table.concat(v, " | "), " |\n") end + return self end, write_list = function(self, tbl, ord) @@ -135,6 +151,7 @@ local Writer = util.Object:clone { end self:write_raw((" "):rep(lvl), prec, " ", str, "\n") end + return self end, finish = function(self) @@ -151,6 +168,7 @@ local Buffer = Writer:clone { for i, v in ipairs({ ... }) do self.buf[#self.buf + 1] = v end + return self end, finish = function(self) @@ -272,10 +290,10 @@ local build_reftable = function(f, title, ctitle, ctype, t) f:write_h(title, 2) local nt = {} for i, v in ipairs(t) do - local lbuf = Buffer() - lbuf:write_link(gen_namespaces(v, ctype, true), v:full_name_get()) nt[#nt + 1] = { - lbuf:finish(), get_brief_doc(v:documentation_get()) + Buffer():write_link(gen_namespaces(v, ctype, true), + v:full_name_get()):finish(), + get_brief_doc(v:documentation_get()) } end table.sort(nt, function(v1, v2) return v1[1] < v2[1] end) From 3f506ac167a22be768d7c27af5e8e8d2744e9dc0 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 7 Apr 2016 14:36:19 +0100 Subject: [PATCH 12/50] docgen: generation of C method/property signatures --- gendoc.lua | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/gendoc.lua b/gendoc.lua index c4b9a8e7ae..a18f474cd0 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -272,6 +272,86 @@ local gen_func_link = function(base, f) return base .. ":" .. ft .. ":" .. f:name_get():lower() end +local gen_func_sig = function(f, ftype) + ftype = ftype or eolian.function_type.METHOD +end + +local gen_cparam = function(par, out) + local part = par:type_get() + local tstr + out = out or (par:direction_get() == eolian.parameter_dir.OUT) + if part:type_get() == eolian.type_type.POINTER then + tstr = part:c_type_get() + if out then + tstr = tstr .. "*" + end + elseif out then + tstr = part:c_type_get() .. " *" + else + tstr = part:c_type_get() .. " " + end + return tstr .. par:name_get() +end + +local gen_func_csig = function(f, ftype) + ftype = ftype or eolian.function_type.METHOD + assert(ftype ~= eolian.function_type.PROPERTY) + + local cn = f:full_c_name_get(ftype) + local rtype = f:return_type_get(ftype) + + if f:type_get() == eolian.function_type.METHOD then + local pars = f:parameters_get():to_array() + local cnrt = rtype and rtype:c_type_named_get(cn) or ("void " .. cn) + for i = 1, #pars do + pars[i] = gen_cparam(pars[i]) + end + if #pars == 0 then + pars = { "void" } + end + return cnrt .. "(" .. table.concat(pars, ", ") .. ");" + end + + local keys = f:property_keys_get(ftype):to_array() + local vals = f:property_values_get(ftype):to_array() + + if ftype == eolian.function_type.PROP_SET then + local cnrt = rtype and rtype:c_type_named_get(cn) or ("void " .. cn) + local pars = {} + for i, par in ipairs(keys) do + pars[#pars + 1] = gen_cparam(par) + end + for i, par in ipairs(vals) do + pars[#pars + 1] = gen_cparam(par) + end + return cnrt .. "(" .. table.concat(pars, ", ") .. ");" + end + + -- getters + local cnrt + if not rtype then + if #vals == 1 then + cnrt = vals[1]:type_get():c_type_named_get(cn) + table.remove(vals, 1) + else + cnrt = "void " .. cn + end + else + cnrt = rtype:c_type_named_get(cn) + end + local pars = {} + for i, par in ipairs(keys) do + pars[#pars + 1] = gen_cparam(par) + end + for i, par in ipairs(vals) do + pars[#pars + 1] = gen_cparam(par, true) + end + if #pars == 0 then + pars = { "void" } + end + return cnrt .. "(" .. table.concat(pars, ", ") .. ");" +end + -- builders local classt_to_str = { @@ -466,6 +546,9 @@ build_method = function(fn, cl) f:write_h(fn:name_get(), 2) + f:write_h("C signature", 3) + f:write_raw("\n", gen_func_csig(fn), "\n\n") + f:write_h("Description", 3) write_full_doc(f, fn:documentation_get(eolian.function_type.METHOD)) @@ -488,6 +571,16 @@ build_property = function(fn, cl) f:write_h(fn:name_get(), 2) + f:write_h("C signature", 3) + f:write_raw("\n") + if isget then + f:write_raw(gen_func_csig(fn, fts.PROP_GET), "\n") + end + if isset then + f:write_raw(gen_func_csig(fn, fts.PROP_SET), "\n") + end + f:write_raw("\n") + if isget and isset then f:write_h("Description", 3) if doc or (not gdoc and not sdoc) then From c8a25492c30af967bbfef5f078a8424698df2375 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 7 Apr 2016 14:41:27 +0100 Subject: [PATCH 13/50] docgen: cleaner code block generation --- gendoc.lua | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index a18f474cd0..51cfa41dc9 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -118,6 +118,11 @@ local Writer = util.Object:clone { return self end, + write_code = function(self, str, lang) + lang = lang and (" " .. lang) or "" + self:write_raw("\n", str, "\n") + end, + write_link = function(self, target, title) if not title then self:write_raw("[[", target:lower(), "|", target, "]]") @@ -547,7 +552,7 @@ build_method = function(fn, cl) f:write_h(fn:name_get(), 2) f:write_h("C signature", 3) - f:write_raw("\n", gen_func_csig(fn), "\n\n") + f:write_code(gen_func_csig(fn), "c") f:write_h("Description", 3) write_full_doc(f, fn:documentation_get(eolian.function_type.METHOD)) @@ -572,14 +577,14 @@ build_property = function(fn, cl) f:write_h(fn:name_get(), 2) f:write_h("C signature", 3) - f:write_raw("\n") + local codes = {} if isget then - f:write_raw(gen_func_csig(fn, fts.PROP_GET), "\n") + codes[#codes + 1] = gen_func_csig(fn, fts.PROP_GET) end if isset then - f:write_raw(gen_func_csig(fn, fts.PROP_SET), "\n") + codes[#codes + 1] = gen_func_csig(fn, fts.PROP_SET) end - f:write_raw("\n") + f:write_code(table.concat(codes, "\n"), "c") if isget and isset then f:write_h("Description", 3) From 891646261f67f4a0a00716db927e0a5c08b454c0 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Tue, 12 Apr 2016 14:38:50 +0100 Subject: [PATCH 14/50] docgen: prepare for markup parsing and add support for notes --- gendoc.lua | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 51cfa41dc9..c7fa5fd61c 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -120,7 +120,7 @@ local Writer = util.Object:clone { write_code = function(self, str, lang) lang = lang and (" " .. lang) or "" - self:write_raw("\n", str, "\n") + self:write_raw("\n", str, "\n\n") end, write_link = function(self, target, title) @@ -185,6 +185,59 @@ local Buffer = Writer:clone { -- eolian to various doc elements conversions +local str_split = function(str, delim) + if not str then + return nil + end + local s, e = str:find(delim, 1, true) + if not s then + return { str } + end + local t = {} + while s do + t[#t + 1] = str:sub(1, s - 1) + str = str:sub(e + 1) + s, e = str:find(delim, 1, true) + if not s then + t[#t + 1] = str + end + end + return t +end + +local notetypes = { + ["Note: "] = "\n", + ["Warning: "] = "\n", + ["Remark: "] = "\n", + ["TODO: "] = "\n**TODO:** " +} + +local gen_doc_par = function(str) + local tag + for k, v in pairs(notetypes) do + if str:match("^" .. k) then + tag = v + str = str:sub(#k + 1) + break + end + end + if tag then + return tag .. str .. "\n" + end + return str +end + +local gen_doc_refd = function(str) + if not str then + return nil + end + local pars = str_split(str, "\n\n") + for i = 1, #pars do + pars[i] = gen_doc_par(pars[i]) + end + return table.concat(pars, "\n\n") +end + local get_fallback_fdoc = function(f, ftype) if not ftype then local ft = f:type_get() @@ -206,7 +259,7 @@ local get_brief_doc = function(doc1, doc2) if not doc1 then doc1, doc2 = doc2, doc1 end - return doc1:summary_get() + return gen_doc_refd(doc1:summary_get()) end local get_brief_fdoc = function(f, ftype) @@ -234,9 +287,9 @@ local get_full_doc = function(doc1, doc2) end end if not desc1 then - return sum1 .. edoc + return gen_doc_refd(sum1 .. edoc) end - return sum1 .. "\n\n" .. desc1 .. edoc + return gen_doc_refd(sum1 .. "\n\n" .. desc1 .. edoc) end local get_full_fdoc = function(f, ftype) @@ -553,6 +606,7 @@ build_method = function(fn, cl) f:write_h("C signature", 3) f:write_code(gen_func_csig(fn), "c") + f:write_nl() f:write_h("Description", 3) write_full_doc(f, fn:documentation_get(eolian.function_type.METHOD)) @@ -585,6 +639,7 @@ build_property = function(fn, cl) codes[#codes + 1] = gen_func_csig(fn, fts.PROP_SET) end f:write_code(table.concat(codes, "\n"), "c") + f:write_nl() if isget and isset then f:write_h("Description", 3) From 7eac3275e41339fadd118a0968bd890436a40db4 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Tue, 12 Apr 2016 15:23:47 +0100 Subject: [PATCH 15/50] docgen: add support for monospace markup highlights --- gendoc.lua | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index c7fa5fd61c..d9a31dbfc0 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -212,6 +212,39 @@ local notetypes = { ["TODO: "] = "\n**TODO:** " } +local gen_doc_markup = function(str) + local f = str:gmatch(".") + local c = f() + local buf = {} + while c do + if c == "\\" then + c = f() + if c ~= "@" and c ~= "$" then + buf[#buf + 1] = "\\" + end + buf[#buf + 1] = c + c = f() + elseif c == "$" then + c = f() + if c and c:match("[a-zA-Z_]") then + local wbuf = { c } + c = f() + while c and c:match("[a-zA-Z0-9_]") do + wbuf[#wbuf + 1] = c + c = f() + end + buf[#buf + 1] = "''" .. table.concat(wbuf) .. "''" + else + buf[#buf + 1] = "$" + end + else + buf[#buf + 1] = c + c = f() + end + end + return table.concat(buf) +end + local gen_doc_par = function(str) local tag for k, v in pairs(notetypes) do @@ -222,9 +255,9 @@ local gen_doc_par = function(str) end end if tag then - return tag .. str .. "\n" + return tag .. gen_doc_markup(str) .. "\n" end - return str + return gen_doc_markup(str) end local gen_doc_refd = function(str) From 0b8dd67e0b9800a06ca5a0dabd3637a71963411c Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Tue, 12 Apr 2016 16:54:25 +0100 Subject: [PATCH 16/50] docgen: correctly resolve references in docs --- gendoc.lua | 140 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 126 insertions(+), 14 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index d9a31dbfc0..a5b643a8d2 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -185,6 +185,20 @@ local Buffer = Writer:clone { -- eolian to various doc elements conversions +local classt_to_str = { + [eolian.class_type.REGULAR] = "class", + [eolian.class_type.ABSTRACT] = "class", + [eolian.class_type.MIXIN] = "mixin", + [eolian.class_type.INTERFACE] = "interface" +} + +local funct_to_str = { + [eolian.function_type.PROPERTY] = "property", + [eolian.function_type.PROP_GET] = "property", + [eolian.function_type.PROP_SET] = "property", + [eolian.function_type.METHOD] = "method" +} + local str_split = function(str, delim) if not str then return nil @@ -212,6 +226,95 @@ local notetypes = { ["TODO: "] = "\n**TODO:** " } +local get_decl_nspace = function(decl) + local dt = eolian.declaration_type + local tp = decl:type_get() + if tp == dt.ALIAS then + return "alias" + elseif tp == dt.STRUCT then + return "struct" + elseif tp == dt.ENUM then + return "enum" + elseif tp == dt.VAR then + return "var" + elseif tp == dt.CLASS then + local ret = classt_to_str[decl:class_get():type_get()] + if not ret then + error("unknown class type for class '" .. decl:name_get() .. "'") + end + return ret + else + error("unknown declaration type for declaration '" + .. decl:name_get() .. "'") + end +end + +local gen_ref_link +gen_ref_link = function(str) + local decl = eolian.declaration_get_by_name(str) + if decl then + return table.concat { + ":", root_nspace, ":", get_decl_nspace(decl), ":", + str:gsub("%.", ":"):lower() + } + end + + -- field or func + local bstr = str:match("(.+)%.[^.]+") + if not bstr then + error("invalid reference '" .. str .. "'") + end + + local sfx = str:sub(#bstr + 1) + + decl = eolian.declaration_get_by_name(bstr) + if decl then + local dt = eolian.declaration_type + local tp = decl:type_get() + if tp == dt.STRUCT or tp == dt.ENUM then + -- TODO: point to the actual item + return gen_ref_link(bstr) + end + end + + local ftp = eolian.function_type + + local cl = eolian.class_get_by_name(bstr) + local fn + local ftype = ftp.UNRESOLVED + if not cl then + if sfx == ".get" then + ftype = ftp.PROP_GET + elseif sfx == ".set" then + ftype = ftp.PROP_SET + end + local mname + if ftype ~= ftp.UNRESOLVED then + mname = bstr:match(".+%.([^.]+)") + if not mname then + error("invalid reference '" .. str .. "'") + end + bstr = bstr:match("(.+)%.[^.]+") + cl = eolian.class_get_by_name(bstr) + if cl then + fn = cl:function_get_by_name(mname, ftype) + end + end + else + fn = cl:function_get_by_name(sfx:sub(2), ftype) + if fn then ftype = fn:type_get() end + end + + if not fn or not funct_to_str[ftype] then + error("invalid reference '" .. str .. "'") + end + + return table.concat { + gen_ref_link(bstr), ":", funct_to_str[ftype], ":", + fn:name_get():lower() + } +end + local gen_doc_markup = function(str) local f = str:gmatch(".") local c = f() @@ -237,6 +340,29 @@ local gen_doc_markup = function(str) else buf[#buf + 1] = "$" end + elseif c == "@" then + c = f() + if c and c:match("[a-zA-Z_]") then + local rbuf = { c } + c = f() + while c and c:match("[a-zA-Z0-9_.]") do + rbuf[#rbuf + 1] = c + c = f() + end + local ldot = false + if rbuf[#rbuf] == "." then + ldot = true + rbuf[#rbuf] = nil + end + local title = table.concat(rbuf) + buf[#buf + 1] = Buffer():write_link(gen_ref_link(title), + title):finish() + if ldot then + buf[#buf + 1] = "." + end + else + buf[#buf + 1] = "@" + end else buf[#buf + 1] = c c = f() @@ -345,13 +471,6 @@ local gen_namespaces = function(v, subnspace, root) return table.concat(nspaces, ":") end -local funct_to_str = { - [eolian.function_type.PROPERTY] = "property", - [eolian.function_type.PROP_GET] = "property", - [eolian.function_type.PROP_SET] = "property", - [eolian.function_type.METHOD] = "method" -} - local propt_to_type = { [eolian.function_type.PROPERTY] = "(get, set)", [eolian.function_type.PROP_GET] = "(get)", @@ -445,13 +564,6 @@ end -- builders -local classt_to_str = { - [eolian.class_type.REGULAR] = "class", - [eolian.class_type.ABSTRACT] = "class", - [eolian.class_type.MIXIN] = "mixin", - [eolian.class_type.INTERFACE] = "interface" -} - local build_method, build_property local build_reftable = function(f, title, ctitle, ctype, t) From abb4e758d6057b2047d5f89d59e6accae7f4b823 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 13 Apr 2016 13:21:53 +0100 Subject: [PATCH 17/50] docgen: don't let EFL docs affect dokuwiki markup --- gendoc.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index a5b643a8d2..86219dc911 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -336,7 +336,7 @@ local gen_doc_markup = function(str) wbuf[#wbuf + 1] = c c = f() end - buf[#buf + 1] = "''" .. table.concat(wbuf) .. "''" + buf[#buf + 1] = "%%''" .. table.concat(wbuf) .. "''%%" else buf[#buf + 1] = "$" end @@ -355,20 +355,30 @@ local gen_doc_markup = function(str) rbuf[#rbuf] = nil end local title = table.concat(rbuf) + buf[#buf + 1] = "%%" buf[#buf + 1] = Buffer():write_link(gen_ref_link(title), title):finish() + buf[#buf + 1] = "%%" if ldot then buf[#buf + 1] = "." end else buf[#buf + 1] = "@" end + elseif c == "%" then + c = f() + if c == "%" then + c = f() + buf[#buf + 1] = "%%%%%%" + else + buf[#buf + 1] = "%" + end else buf[#buf + 1] = c c = f() end end - return table.concat(buf) + return "%%" .. table.concat(buf) .. "%%" end local gen_doc_par = function(str) From c2338a6bdfe883c09ed79edb9863925cbfaf7768 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 13 Apr 2016 14:29:47 +0100 Subject: [PATCH 18/50] docgen: refactor for integration of paragraphs into writer --- gendoc.lua | 133 +++++++++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 86219dc911..ed3dcf9ba6 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -36,6 +36,67 @@ local mkdir_p = function(path) mkdir_r(path:match("(.+)/([^/]+)")) end +local str_split = function(str, delim) + if not str then + return nil + end + local s, e = str:find(delim, 1, true) + if not s then + return { str } + end + local t = {} + while s do + t[#t + 1] = str:sub(1, s - 1) + str = str:sub(e + 1) + s, e = str:find(delim, 1, true) + if not s then + t[#t + 1] = str + end + end + return t +end + +-- translation tables and funcs + +local classt_to_str = { + [eolian.class_type.REGULAR] = "class", + [eolian.class_type.ABSTRACT] = "class", + [eolian.class_type.MIXIN] = "mixin", + [eolian.class_type.INTERFACE] = "interface" +} + +local funct_to_str = { + [eolian.function_type.PROPERTY] = "property", + [eolian.function_type.PROP_GET] = "property", + [eolian.function_type.PROP_SET] = "property", + [eolian.function_type.METHOD] = "method" +} + +local decl_to_nspace = function(decl) + local dt = eolian.declaration_type + local decltypes = { + [dt.ALIAS] = "alias", + [dt.STRUCT] = "struct", + [dt.ENUM] = "enum", + [dt.VAR] = "var" + } + local ns = decltypes[decl:type_get()] + if ns then + return ns + elseif decl:type_get() == dt.CLASS then + local ret = classt_to_str[decl:class_get():type_get()] + if not ret then + error("unknown class type for class '" .. decl:name_get() .. "'") + end + return ret + else + error("unknown declaration type for declaration '" + .. decl:name_get() .. "'") + end +end + +-- generator + local Writer = util.Object:clone { __ctor = function(self, path) local subs = path:gsub(":", "/"):lower() @@ -185,76 +246,12 @@ local Buffer = Writer:clone { -- eolian to various doc elements conversions -local classt_to_str = { - [eolian.class_type.REGULAR] = "class", - [eolian.class_type.ABSTRACT] = "class", - [eolian.class_type.MIXIN] = "mixin", - [eolian.class_type.INTERFACE] = "interface" -} - -local funct_to_str = { - [eolian.function_type.PROPERTY] = "property", - [eolian.function_type.PROP_GET] = "property", - [eolian.function_type.PROP_SET] = "property", - [eolian.function_type.METHOD] = "method" -} - -local str_split = function(str, delim) - if not str then - return nil - end - local s, e = str:find(delim, 1, true) - if not s then - return { str } - end - local t = {} - while s do - t[#t + 1] = str:sub(1, s - 1) - str = str:sub(e + 1) - s, e = str:find(delim, 1, true) - if not s then - t[#t + 1] = str - end - end - return t -end - -local notetypes = { - ["Note: "] = "\n", - ["Warning: "] = "\n", - ["Remark: "] = "\n", - ["TODO: "] = "\n**TODO:** " -} - -local get_decl_nspace = function(decl) - local dt = eolian.declaration_type - local tp = decl:type_get() - if tp == dt.ALIAS then - return "alias" - elseif tp == dt.STRUCT then - return "struct" - elseif tp == dt.ENUM then - return "enum" - elseif tp == dt.VAR then - return "var" - elseif tp == dt.CLASS then - local ret = classt_to_str[decl:class_get():type_get()] - if not ret then - error("unknown class type for class '" .. decl:name_get() .. "'") - end - return ret - else - error("unknown declaration type for declaration '" - .. decl:name_get() .. "'") - end -end - local gen_ref_link gen_ref_link = function(str) local decl = eolian.declaration_get_by_name(str) if decl then return table.concat { - ":", root_nspace, ":", get_decl_nspace(decl), ":", + ":", root_nspace, ":", decl_to_nspace(decl), ":", str:gsub("%.", ":"):lower() } end @@ -382,6 +379,12 @@ local gen_doc_markup = function(str) end local gen_doc_par = function(str) + local notetypes = { + ["Note: "] = "\n", + ["Warning: "] = "\n", + ["Remark: "] = "\n", + ["TODO: "] = "\n**TODO:** " + } local tag for k, v in pairs(notetypes) do if str:match("^" .. k) then From afa5a4dc05da1632eb81f75c47a88eeb1e4952f9 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 13 Apr 2016 16:02:42 +0100 Subject: [PATCH 19/50] docgen: refactor link generation system to be less dokuwiki-centric --- gendoc.lua | 104 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index ed3dcf9ba6..fc3e4c4895 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -95,11 +95,51 @@ local decl_to_nspace = function(decl) end end +local gen_nsp_eo = function(eobj, subn, root) + local tbl = eobj:namespaces_get():to_array() + for i = 1, #tbl do + tbl[i] = tbl[i]:lower() + end + table.insert(tbl, 1, subn) + tbl[#tbl + 1] = eobj:name_get():lower() + if root then + tbl[#tbl + 1] = true + end + return tbl +end + +local gen_nsp_class = function(cl, root) + return gen_nsp_eo(cl, classt_to_str[cl:type_get()], root) +end + +local gen_nsp_func = function(fn, cl, root) + local tbl = gen_nsp_class(cl) + tbl[#tbl + 1] = funct_to_str[fn:type_get()] + tbl[#tbl + 1] = fn:name_get():lower() + if root then + tbl[#tbl + 1] = true + end + return tbl +end + +local gen_link_target = function(tbl, root) + if tbl[#tbl] == true or root then + if not root then tbl[#tbl] = nil end + return ":" .. root_nspace .. ":" .. table.concat(tbl, ":") + end + return table.concat(tbl, ":") +end + -- generator local Writer = util.Object:clone { __ctor = function(self, path) - local subs = path:gsub(":", "/"):lower() + local subs + if type(path) == "table" then + subs = table.concat(path, "/") + else + subs = path:gsub(":", "/"):lower() + end mkdir_p(subs) self.file = assert(io.open(make_page(subs), "w")) end, @@ -185,6 +225,9 @@ local Writer = util.Object:clone { end, write_link = function(self, target, title) + if type(target) == "table" then + target = gen_link_target(target) + end if not title then self:write_raw("[[", target:lower(), "|", target, "]]") return @@ -250,10 +293,12 @@ local gen_ref_link gen_ref_link = function(str) local decl = eolian.declaration_get_by_name(str) if decl then - return table.concat { - ":", root_nspace, ":", decl_to_nspace(decl), ":", - str:gsub("%.", ":"):lower() - } + local t = { decl_to_nspace(decl) } + for tok in str:gmatch("[^%.]+") do + t[#t + 1] = tok:lower() + end + t[#t + 1] = true + return t end -- field or func @@ -306,10 +351,11 @@ gen_ref_link = function(str) error("invalid reference '" .. str .. "'") end - return table.concat { - gen_ref_link(bstr), ":", funct_to_str[ftype], ":", - fn:name_get():lower() - } + local ret = gen_ref_link(bstr) + ret[#ret] = funct_to_str[ftype] + ret[#ret + 1] = fn:name_get():lower() + ret[#ret + 1] = true + return ret end local gen_doc_markup = function(str) @@ -469,32 +515,12 @@ local get_full_fdoc = function(f, ftype) get_fallback_fdoc(f, ftype)) end -local gen_namespaces = function(v, subnspace, root) - local nspaces = v:namespaces_get():to_array() - for i = 1, #nspaces do - nspaces[i] = nspaces[i]:lower() - end - nspaces[#nspaces + 1] = v:name_get() - if subnspace then - table.insert(nspaces, 1, subnspace) - end - if root then - table.insert(nspaces, 1, ":" .. root_nspace) - end - return table.concat(nspaces, ":") -end - local propt_to_type = { [eolian.function_type.PROPERTY] = "(get, set)", [eolian.function_type.PROP_GET] = "(get)", [eolian.function_type.PROP_SET] = "(set)", } -local gen_func_link = function(base, f) - local ft = funct_to_str[f:type_get()] - return base .. ":" .. ft .. ":" .. f:name_get():lower() -end - local gen_func_sig = function(f, ftype) ftype = ftype or eolian.function_type.METHOD end @@ -587,7 +613,7 @@ local build_reftable = function(f, title, ctitle, ctype, t) local nt = {} for i, v in ipairs(t) do nt[#nt + 1] = { - Buffer():write_link(gen_namespaces(v, ctype, true), + Buffer():write_link(gen_nsp_eo(v, ctype, true), v:full_name_get()):finish(), get_brief_doc(v:documentation_get()) } @@ -602,12 +628,11 @@ local build_functable = function(f, title, ctitle, cl, tp) if #t == 0 then return end - local cns = gen_namespaces(cl, classt_to_str[cl:type_get()], true) f:write_h(title, 3) local nt = {} for i, v in ipairs(t) do local lbuf = Buffer() - lbuf:write_link(gen_func_link(cns, v), v:name_get()) + lbuf:write_link(gen_nsp_func(v, cl, true), v:name_get()) local pt = propt_to_type[v:type_get()] if pt then lbuf:write_raw(" ") @@ -698,10 +723,9 @@ build_inherits = function(cl, t, lvl) t = t or {} lvl = lvl or 0 local lbuf = Buffer() - local cltp = classt_to_str[cl:type_get()] - lbuf:write_link(gen_namespaces(cl, cltp, true), cl:full_name_get()) + lbuf:write_link(gen_nsp_class(cl, true), cl:full_name_get()) lbuf:write_raw(" ") - lbuf:write_i("(" .. cltp .. ")") + lbuf:write_i("(" .. classt_to_str[cl:type_get()] .. ")") if lvl == 0 then lbuf:write_b(lbuf:finish()) end @@ -717,7 +741,7 @@ build_inherits = function(cl, t, lvl) end local build_class = function(cl) - local f = Writer(gen_namespaces(cl, classt_to_str[cl:type_get()], false)) + local f = Writer(gen_nsp_class(cl)) f:write_h(cl:full_name_get(), 2) @@ -756,9 +780,7 @@ local build_classes = function() end build_method = function(fn, cl) - local cns = gen_namespaces(cl, classt_to_str[cl:type_get()], false):lower() - .. ":method:" .. fn:name_get():lower() - local f = Writer(cns) + local f = Writer(gen_nsp_func(fn, cl)) f:write_h(fn:name_get(), 2) @@ -773,9 +795,7 @@ build_method = function(fn, cl) end build_property = function(fn, cl) - local cns = gen_namespaces(cl, classt_to_str[cl:type_get()], false):lower() - .. ":property:" .. fn:name_get():lower() - local f = Writer(cns) + local f = Writer(gen_nsp_func(fn, cl)) local fts = eolian.function_type local ft = fn:type_get() From 8ce5781e64f1ec9ba27c23194f99eef328988600 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 13 Apr 2016 16:19:18 +0100 Subject: [PATCH 20/50] docgen: integrate dokuwiki markup handling into Writer --- gendoc.lua | 327 +++++++++++++++++++++++++++-------------------------- 1 file changed, 164 insertions(+), 163 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index fc3e4c4895..3016f7f211 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -122,12 +122,73 @@ local gen_nsp_func = function(fn, cl, root) return tbl end -local gen_link_target = function(tbl, root) - if tbl[#tbl] == true or root then - if not root then tbl[#tbl] = nil end - return ":" .. root_nspace .. ":" .. table.concat(tbl, ":") +local gen_nsp_ref +gen_nsp_ref = function(str, root) + local decl = eolian.declaration_get_by_name(str) + if decl then + local t = { decl_to_nspace(decl) } + for tok in str:gmatch("[^%.]+") do + t[#t + 1] = tok:lower() + end + if root then t[#t + 1] = true end + return t end - return table.concat(tbl, ":") + + -- field or func + local bstr = str:match("(.+)%.[^.]+") + if not bstr then + error("invalid reference '" .. str .. "'") + end + + local sfx = str:sub(#bstr + 1) + + decl = eolian.declaration_get_by_name(bstr) + if decl then + local dt = eolian.declaration_type + local tp = decl:type_get() + if tp == dt.STRUCT or tp == dt.ENUM then + -- TODO: point to the actual item + return gen_nsp_ref(bstr, root) + end + end + + local ftp = eolian.function_type + + local cl = eolian.class_get_by_name(bstr) + local fn + local ftype = ftp.UNRESOLVED + if not cl then + if sfx == ".get" then + ftype = ftp.PROP_GET + elseif sfx == ".set" then + ftype = ftp.PROP_SET + end + local mname + if ftype ~= ftp.UNRESOLVED then + mname = bstr:match(".+%.([^.]+)") + if not mname then + error("invalid reference '" .. str .. "'") + end + bstr = bstr:match("(.+)%.[^.]+") + cl = eolian.class_get_by_name(bstr) + if cl then + fn = cl:function_get_by_name(mname, ftype) + end + end + else + fn = cl:function_get_by_name(sfx:sub(2), ftype) + if fn then ftype = fn:type_get() end + end + + if not fn or not funct_to_str[ftype] then + error("invalid reference '" .. str .. "'") + end + + local ret = gen_nsp_ref(bstr) + ret[#ret + 1] = funct_to_str[ftype] + ret[#ret + 1] = fn:name_get():lower() + if root then ret[#ret + 1] = true end + return ret end -- generator @@ -226,7 +287,12 @@ local Writer = util.Object:clone { write_link = function(self, target, title) if type(target) == "table" then - target = gen_link_target(target) + if target[#target] == true then + target[#target] = nil + target = ":" .. root_nspace .. ":" .. table.concat(target, ":") + else + target = table.concat(target, ":") + end end if not title then self:write_raw("[[", target:lower(), "|", target, "]]") @@ -263,6 +329,97 @@ local Writer = util.Object:clone { return self end, + write_par_markup = function(self, str) + self:write_raw("%%") + local f = str:gmatch(".") + local c = f() + while c do + if c == "\\" then + c = f() + if c ~= "@" and c ~= "$" then + self:write_raw("\\") + end + self:write_raw(c) + c = f() + elseif c == "$" then + c = f() + if c and c:match("[a-zA-Z_]") then + local wbuf = { c } + c = f() + while c and c:match("[a-zA-Z0-9_]") do + wbuf[#wbuf + 1] = c + c = f() + end + self:write_raw("%%''" .. table.concat(wbuf) .. "''%%") + else + self:write_raw("$") + end + elseif c == "@" then + c = f() + if c and c:match("[a-zA-Z_]") then + local rbuf = { c } + c = f() + while c and c:match("[a-zA-Z0-9_.]") do + rbuf[#rbuf + 1] = c + c = f() + end + local ldot = false + if rbuf[#rbuf] == "." then + ldot = true + rbuf[#rbuf] = nil + end + local title = table.concat(rbuf) + self:write_raw("%%") + self:write_link(gen_nsp_ref(title, true), title) + self:write_raw("%%") + if ldot then + self:write_raw(".") + end + else + self:write_raw("@") + end + elseif c == "%" then + c = f() + if c == "%" then + c = f() + self:write_raw("%%%%%%") + else + self:write_raw("%") + end + else + self:write_raw(c) + c = f() + end + end + self:write_raw("%%") + return self + end, + + write_par = function(self, str) + local notetypes = { + ["Note: "] = "\n", + ["Warning: "] = "\n", + ["Remark: "] = "\n", + ["TODO: "] = "\n**TODO:** " + } + local tag + for k, v in pairs(notetypes) do + if str:match("^" .. k) then + tag = v + str = str:sub(#k + 1) + break + end + end + if tag then + self:write_raw(tag) + self:write_par_markup(str) + self:write_raw("\n") + else + self:write_par_markup(str) + end + return self + end, + finish = function(self) self.file:close() end @@ -289,169 +446,13 @@ local Buffer = Writer:clone { -- eolian to various doc elements conversions -local gen_ref_link -gen_ref_link = function(str) - local decl = eolian.declaration_get_by_name(str) - if decl then - local t = { decl_to_nspace(decl) } - for tok in str:gmatch("[^%.]+") do - t[#t + 1] = tok:lower() - end - t[#t + 1] = true - return t - end - - -- field or func - local bstr = str:match("(.+)%.[^.]+") - if not bstr then - error("invalid reference '" .. str .. "'") - end - - local sfx = str:sub(#bstr + 1) - - decl = eolian.declaration_get_by_name(bstr) - if decl then - local dt = eolian.declaration_type - local tp = decl:type_get() - if tp == dt.STRUCT or tp == dt.ENUM then - -- TODO: point to the actual item - return gen_ref_link(bstr) - end - end - - local ftp = eolian.function_type - - local cl = eolian.class_get_by_name(bstr) - local fn - local ftype = ftp.UNRESOLVED - if not cl then - if sfx == ".get" then - ftype = ftp.PROP_GET - elseif sfx == ".set" then - ftype = ftp.PROP_SET - end - local mname - if ftype ~= ftp.UNRESOLVED then - mname = bstr:match(".+%.([^.]+)") - if not mname then - error("invalid reference '" .. str .. "'") - end - bstr = bstr:match("(.+)%.[^.]+") - cl = eolian.class_get_by_name(bstr) - if cl then - fn = cl:function_get_by_name(mname, ftype) - end - end - else - fn = cl:function_get_by_name(sfx:sub(2), ftype) - if fn then ftype = fn:type_get() end - end - - if not fn or not funct_to_str[ftype] then - error("invalid reference '" .. str .. "'") - end - - local ret = gen_ref_link(bstr) - ret[#ret] = funct_to_str[ftype] - ret[#ret + 1] = fn:name_get():lower() - ret[#ret + 1] = true - return ret -end - -local gen_doc_markup = function(str) - local f = str:gmatch(".") - local c = f() - local buf = {} - while c do - if c == "\\" then - c = f() - if c ~= "@" and c ~= "$" then - buf[#buf + 1] = "\\" - end - buf[#buf + 1] = c - c = f() - elseif c == "$" then - c = f() - if c and c:match("[a-zA-Z_]") then - local wbuf = { c } - c = f() - while c and c:match("[a-zA-Z0-9_]") do - wbuf[#wbuf + 1] = c - c = f() - end - buf[#buf + 1] = "%%''" .. table.concat(wbuf) .. "''%%" - else - buf[#buf + 1] = "$" - end - elseif c == "@" then - c = f() - if c and c:match("[a-zA-Z_]") then - local rbuf = { c } - c = f() - while c and c:match("[a-zA-Z0-9_.]") do - rbuf[#rbuf + 1] = c - c = f() - end - local ldot = false - if rbuf[#rbuf] == "." then - ldot = true - rbuf[#rbuf] = nil - end - local title = table.concat(rbuf) - buf[#buf + 1] = "%%" - buf[#buf + 1] = Buffer():write_link(gen_ref_link(title), - title):finish() - buf[#buf + 1] = "%%" - if ldot then - buf[#buf + 1] = "." - end - else - buf[#buf + 1] = "@" - end - elseif c == "%" then - c = f() - if c == "%" then - c = f() - buf[#buf + 1] = "%%%%%%" - else - buf[#buf + 1] = "%" - end - else - buf[#buf + 1] = c - c = f() - end - end - return "%%" .. table.concat(buf) .. "%%" -end - -local gen_doc_par = function(str) - local notetypes = { - ["Note: "] = "\n", - ["Warning: "] = "\n", - ["Remark: "] = "\n", - ["TODO: "] = "\n**TODO:** " - } - local tag - for k, v in pairs(notetypes) do - if str:match("^" .. k) then - tag = v - str = str:sub(#k + 1) - break - end - end - if tag then - return tag .. gen_doc_markup(str) .. "\n" - end - return gen_doc_markup(str) -end - local gen_doc_refd = function(str) if not str then return nil end local pars = str_split(str, "\n\n") for i = 1, #pars do - pars[i] = gen_doc_par(pars[i]) + pars[i] = Buffer():write_par(pars[i]):finish() end return table.concat(pars, "\n\n") end From c338ff0fcaf3984e130913c36d4be3d98a532490 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 14 Apr 2016 13:12:56 +0100 Subject: [PATCH 21/50] docgen: fix C func signatures --- gendoc.lua | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 3016f7f211..513e39d7fc 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -556,9 +556,7 @@ local gen_func_csig = function(f, ftype) for i = 1, #pars do pars[i] = gen_cparam(pars[i]) end - if #pars == 0 then - pars = { "void" } - end + table.insert(pars, 1, "Eo *obj"); return cnrt .. "(" .. table.concat(pars, ", ") .. ");" end @@ -574,6 +572,7 @@ local gen_func_csig = function(f, ftype) for i, par in ipairs(vals) do pars[#pars + 1] = gen_cparam(par) end + table.insert(pars, 1, "Eo *obj"); return cnrt .. "(" .. table.concat(pars, ", ") .. ");" end @@ -596,9 +595,7 @@ local gen_func_csig = function(f, ftype) for i, par in ipairs(vals) do pars[#pars + 1] = gen_cparam(par, true) end - if #pars == 0 then - pars = { "void" } - end + table.insert(pars, 1, "Eo *obj"); return cnrt .. "(" .. table.concat(pars, ", ") .. ");" end From 2d48278c49594a97c6c06cb5b7eeff4ed326bbe4 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 14 Apr 2016 13:22:35 +0100 Subject: [PATCH 22/50] docgen: properly const the first argument in C sig where needed --- gendoc.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 513e39d7fc..7ead430e7e 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -550,13 +550,18 @@ local gen_func_csig = function(f, ftype) local cn = f:full_c_name_get(ftype) local rtype = f:return_type_get(ftype) + local fparam = "Eo *obj" + if f:is_const() or f:is_class() or ftype == eolian.function_type.PROP_GET then + fparam = "const Eo *obj" + end + if f:type_get() == eolian.function_type.METHOD then local pars = f:parameters_get():to_array() local cnrt = rtype and rtype:c_type_named_get(cn) or ("void " .. cn) for i = 1, #pars do pars[i] = gen_cparam(pars[i]) end - table.insert(pars, 1, "Eo *obj"); + table.insert(pars, 1, fparam); return cnrt .. "(" .. table.concat(pars, ", ") .. ");" end @@ -572,7 +577,7 @@ local gen_func_csig = function(f, ftype) for i, par in ipairs(vals) do pars[#pars + 1] = gen_cparam(par) end - table.insert(pars, 1, "Eo *obj"); + table.insert(pars, 1, fparam); return cnrt .. "(" .. table.concat(pars, ", ") .. ");" end @@ -595,7 +600,7 @@ local gen_func_csig = function(f, ftype) for i, par in ipairs(vals) do pars[#pars + 1] = gen_cparam(par, true) end - table.insert(pars, 1, "Eo *obj"); + table.insert(pars, 1, fparam); return cnrt .. "(" .. table.concat(pars, ", ") .. ");" end From d83c4bc0e7f07d6545fc31af1f2505398cb0d192 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 14 Apr 2016 13:44:07 +0100 Subject: [PATCH 23/50] docgen: initial support for params and property keys/values --- gendoc.lua | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/gendoc.lua b/gendoc.lua index 7ead430e7e..08afd0b759 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -324,7 +324,14 @@ local Writer = util.Object:clone { if type(v) == "table" then lvl, str = v[1] + 1, v[2] end + local pbeg, pend = str:match("([^\n]+)\n(.+)") + if not pbeg then + pbeg = str + end self:write_raw((" "):rep(lvl), prec, " ", str, "\n") + if pend then + self:write_raw(pend, "\n") + end end return self end, @@ -782,6 +789,27 @@ local build_classes = function() end end +local pdir_to_str = { + [eolian.parameter_dir.IN] = "(in)", + [eolian.parameter_dir.OUT] = "(out)", + [eolian.parameter_dir.INOUT] = "(inout)" +} + +local build_parlist = function(f, pl, nodir) + local params = {} + for i, p in ipairs(pl) do + local buf = Buffer() + buf:write_b(p:name_get()) + if not nodir then + buf:write_raw(" ") + buf:write_i(pdir_to_str[p:direction_get()]) + end + buf:write_raw(" - ", get_full_doc(p:documentation_get())) + params[#params + 1] = buf:finish() + end + f:write_list(params) +end + build_method = function(fn, cl) local f = Writer(gen_nsp_func(fn, cl)) @@ -791,6 +819,9 @@ build_method = function(fn, cl) f:write_code(gen_func_csig(fn), "c") f:write_nl() + f:write_h("Parameters", 3) + build_parlist(f, fn:parameters_get():to_array()) + f:write_h("Description", 3) write_full_doc(f, fn:documentation_get(eolian.function_type.METHOD)) @@ -822,6 +853,43 @@ build_property = function(fn, cl) f:write_code(table.concat(codes, "\n"), "c") f:write_nl() + local pgkeys = isget and fn:property_keys_get(fts.PROP_GET):to_array() or {} + local pskeys = isset and fn:property_keys_get(fts.PROP_SET):to_array() or {} + local pgvals = isget and fn:property_values_get(fts.PROP_GET):to_array() or {} + local psvals = isset and fn:property_values_get(fts.PROP_SET):to_array() or {} + + if #pgkeys > 0 or #pskeys > 0 then + f:write_h("Keys", 3) + if #pgkeys > 0 then + if #pskeys > 0 then + f:write_h("Getter", 4) + end + build_parlist(f, pgkeys, true) + end + if #pskeys > 0 then + if #pgkeys > 0 then + f:write_h("Setter", 4) + end + build_parlist(f, pskeys, true) + end + end + + if #pgvals > 0 or #psvals > 0 then + f:write_h("Values", 3) + if #pgvals > 0 then + if #psvals > 0 then + f:write_h("Getter", 4) + end + build_parlist(f, pgvals, true) + end + if #psvals > 0 then + if #pgvals > 0 then + f:write_h("Setter", 4) + end + build_parlist(f, psvals, true) + end + end + if isget and isset then f:write_h("Description", 3) if doc or (not gdoc and not sdoc) then From 3a8318c83ea8d2ef82713235daec6b3264fa3b52 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 14 Apr 2016 13:52:34 +0100 Subject: [PATCH 24/50] docgen: do not separate duplicate keys/vals --- gendoc.lua | 63 +++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 08afd0b759..0d74cb0be5 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -810,6 +810,34 @@ local build_parlist = function(f, pl, nodir) f:write_list(params) end +local build_vallist = function(f, pg, ps, title) + if #pg == #ps then + local same = true + for i = 1, #pg do + if pg[i] ~= ps[i] then + same = false + break + end + end + if same then ps = {} end + end + if #pg > 0 or #ps > 0 then + f:write_h(title, 3) + if #pg > 0 then + if #ps > 0 then + f:write_h("Getter", 4) + end + build_parlist(f, pg, true) + end + if #ps > 0 then + if #pg > 0 then + f:write_h("Setter", 4) + end + build_parlist(f, ps, true) + end + end +end + build_method = function(fn, cl) local f = Writer(gen_nsp_func(fn, cl)) @@ -855,40 +883,11 @@ build_property = function(fn, cl) local pgkeys = isget and fn:property_keys_get(fts.PROP_GET):to_array() or {} local pskeys = isset and fn:property_keys_get(fts.PROP_SET):to_array() or {} + build_vallist(f, pgkeys, pskeys, "Keys") + local pgvals = isget and fn:property_values_get(fts.PROP_GET):to_array() or {} local psvals = isset and fn:property_values_get(fts.PROP_SET):to_array() or {} - - if #pgkeys > 0 or #pskeys > 0 then - f:write_h("Keys", 3) - if #pgkeys > 0 then - if #pskeys > 0 then - f:write_h("Getter", 4) - end - build_parlist(f, pgkeys, true) - end - if #pskeys > 0 then - if #pgkeys > 0 then - f:write_h("Setter", 4) - end - build_parlist(f, pskeys, true) - end - end - - if #pgvals > 0 or #psvals > 0 then - f:write_h("Values", 3) - if #pgvals > 0 then - if #psvals > 0 then - f:write_h("Getter", 4) - end - build_parlist(f, pgvals, true) - end - if #psvals > 0 then - if #pgvals > 0 then - f:write_h("Setter", 4) - end - build_parlist(f, psvals, true) - end - end + build_vallist(f, pgvals, psvals, "Values") if isget and isset then f:write_h("Description", 3) From 1b26751c43b8a8b7a7b7b52f847394704f75628b Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 14 Apr 2016 15:10:49 +0100 Subject: [PATCH 25/50] docgen: better headings for properties and methods --- gendoc.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 0d74cb0be5..77032cb376 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -841,7 +841,7 @@ end build_method = function(fn, cl) local f = Writer(gen_nsp_func(fn, cl)) - f:write_h(fn:name_get(), 2) + f:write_h(cl:full_name_get() .. "." .. fn:name_get(), 2) f:write_h("C signature", 3) f:write_code(gen_func_csig(fn), "c") @@ -868,7 +868,7 @@ build_property = function(fn, cl) local gdoc = fn:documentation_get(fts.PROP_GET) local sdoc = fn:documentation_get(fts.PROP_SET) - f:write_h(fn:name_get(), 2) + f:write_h(cl:full_name_get() .. "." .. fn:name_get(), 2) f:write_h("C signature", 3) local codes = {} From bc086ab3325292796f6d8a8cc2d38aa03a166fd0 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 14 Apr 2016 17:17:48 +0100 Subject: [PATCH 26/50] docgen: add statistics + verbose printing with -v switch --- gendoc.lua | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) diff --git a/gendoc.lua b/gendoc.lua index 77032cb376..3f0e0bbf67 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -191,6 +191,285 @@ gen_nsp_ref = function(str, root) return ret end +-- statistics + +local stats = { + class = 0, + class_undoc = 0, + interface = 0, + interface_undoc = 0, + mixin = 0, + mixin_undoc = 0, + method = 0, + method_undoc = 0, + param = 0, + param_undoc = 0, + mret = 0, + mret_undoc = 0, + getter = 0, + getter_undoc = 0, + gret = 0, + gret_undoc = 0, + gkey = 0, + gkey_undoc = 0, + gvalue = 0, + gvalue_undoc = 0, + setter = 0, + setter_undoc = 0, + sret = 0, + sret_undoc = 0, + skey = 0, + skey_undoc = 0, + svalue = 0, + svalue_undoc = 0, + event = 0, + event_undoc = 0, + alias = 0, + alias_undoc = 0, + struct = 0, + struct_undoc = 0, + sfield = 0, + sfield_undoc = 0, + enum = 0, + enum_undoc = 0, + efield = 0, + efield_undoc = 0, + constant = 0, + constant_undoc = 0, + global = 0, + global_undoc = 0 +} + +local stats_pd = function(n) + local ret = 0 + if n == 0 then + return 1 + end + while (n ~= 0) do + n = math.floor(n / 10) + ret = ret + 1 + end + return ret +end + +local fcol = 30 +local ncol = 0 + +local print_stat = function(printname, statname, sub) + local sv = stats[statname] + local svu = stats[statname .. "_undoc"] + local percent = (sv == 0) and 100 or math.floor(((sv - svu) / sv) * 100 + 0.5) + local tb = (" "):rep(math.max(0, fcol - #printname - 1) + ncol - stats_pd(sv)) + local dtb = (" "):rep(ncol - stats_pd(sv - svu)) + print(("%s:%s%d (documented: %s%d or %d%%)") + :format(printname, tb, sv, dtb, sv - svu, percent)) +end + +local print_stats = function() + for k, v in pairs(stats) do + ncol = math.max(ncol, stats_pd(v)) + end + + print("=== CLASS SECTION ===\n") + print_stat("Classes", "class") + print_stat("Interfaces", "interface") + print_stat("Mixins", "mixin") + print_stat("Events", "event") + + print("\n=== FUNCTION SECTION ===\n") + print_stat("Methods", "method") + print_stat(" Method params", "param") + print_stat(" Method returns", "mret") + print_stat("Getters", "getter") + print_stat(" Getter returns", "gret") + print_stat(" Getter keys", "gkey") + print_stat(" Getter values", "gvalue") + print_stat("Setters", "setter") + print_stat(" Setter returns", "sret") + print_stat(" Setter keys", "skey") + print_stat(" Setter values", "svalue") + + print("\n=== TYPE SECTION ===\n") + print_stat("Aliases", "alias") + print_stat("Structs", "struct") + print_stat("Struct fields", "sfield") + print_stat("Enums", "enum") + print_stat("Enum fields", "efield") + + print("\n=== VARIABLE SECTION ===\n") + print_stat("Constants", "constant") + print_stat("Globals", "global") +end + +local stat_incr = function(name, missing) + stats[name] = stats[name] + 1 + if missing then + stats[name .. "_undoc"] = stats[name .. "_undoc"] + 1 + end +end + +local print_missing = function(name, tp) + if not verbose then + return + end + print(tp .. " '" .. name .. "'" .. " missing documentation") +end + +local check_class = function(cl) + local ct = classt_to_str[cl:type_get()] + if not ct then + return + end + if not cl:documentation_get() then + print_missing(cl:full_name_get(), ct) + stat_incr(ct, true) + else + stat_incr(ct, false) + end + + for ev in cl:events_get() do + if not ev:documentation_get() then + print_missing(cl:full_name_get() .. "." .. ev:name_get(), "event") + stat_incr("event", true) + else + stat_incr("event", false) + end + end +end + +local check_method = function(fn, cl) + local fts = eolian.function_type + local fulln = cl:full_name_get() .. "." .. fn:name_get() + if fn:return_type_get(fts.METHOD) then + if not fn:return_documentation_get(fts.METHOD) then + print_missing(fulln, "method return") + stat_incr("mret", true) + else + stat_incr("mret", false) + end + end + if not fn:documentation_get(fts.METHOD) then + print_missing(fulln, "method") + stat_incr("method", true) + else + stat_incr("method", false) + end + for p in fn:parameters_get() do + if not p:documentation_get() then + print_missing(fulln .. "." .. p:name_get(), "method parameter") + stat_incr("param", true) + else + stat_incr("param", false) + end + end +end + +local check_property = function(fn, cl, ft) + local fts = eolian.function_type + + local pfxs = { + [fts.PROP_GET] = "g", + [fts.PROP_SET] = "s", + } + local pfx = pfxs[ft] + + local fulln = cl:full_name_get() .. "." .. fn:name_get() + if fn:return_type_get(ft) then + if not fn:return_documentation_get(ft) then + print_missing(fulln, pfx .. "etter return") + stat_incr(pfx .. "ret", true) + else + stat_incr(pfx .. "ret", false) + end + end + + if not fn:documentation_get(fts.PROPERTY) and not fn:documentation_get(ft) then + print_missing(fulln, pfx .. "etter") + stat_incr(pfx .. "etter", true) + else + stat_incr(pfx .. "etter", false) + end + + for p in fn:property_keys_get(ft) do + if not p:documentation_get() then + print_missing(fulln .. "." .. p:name_get(), pfx .. "etter key") + stat_incr(pfx .. "key", true) + else + stat_incr(pfx .. "key", false) + end + end + + for p in fn:property_values_get(ft) do + if not p:documentation_get() then + print_missing(fulln .. "." .. p:name_get(), pfx .. "etter value") + stat_incr(pfx .. "value", true) + else + stat_incr(pfx .. "value", false) + end + end +end + +local check_alias = function(v) + if not v:documentation_get() then + print_missing(v:full_name_get(), "alias") + stat_incr("alias", true) + else + stat_incr("alias", false) + end +end + +local check_struct = function(v) + if not v:documentation_get() then + print_missing(v:full_name_get(), "struct") + stat_incr("struct", true) + else + stat_incr("struct", false) + end + for fl in v:struct_fields_get() do + if not fl:documentation_get() then + print_missing(v:full_name_get() .. "." .. fl:name_get(), "struct field") + stat_incr("sfield", true) + else + stat_incr("sfield", false) + end + end +end + +local check_enum = function(v) + if not v:documentation_get() then + print_missing(v:full_name_get(), "enum") + stat_incr("enum", true) + else + stat_incr("enum", false) + end + for fl in v:enum_fields_get() do + if not fl:documentation_get() then + print_missing(v:full_name_get() .. "." .. fl:name_get(), "enum field") + stat_incr("efield", true) + else + stat_incr("efield", false) + end + end +end + +local check_constant = function(v) + if not v:documentation_get() then + print_missing(v:full_name_get(), "constant") + stat_incr("constant", true) + else + stat_incr("constant", false) + end +end + +local check_global = function(v) + if not v:documentation_get() then + print_missing(v:full_name_get(), "global") + stat_incr("global", true) + else + stat_incr("global", false) + end +end + -- generator local Writer = util.Object:clone { @@ -615,13 +894,23 @@ end local build_method, build_property +local reft_checks = { + ["alias"] = check_alias, + ["struct"] = check_struct, + ["enum"] = check_enum, + ["constant"] = check_constant, + ["global"] = check_global +} + local build_reftable = function(f, title, ctitle, ctype, t) if not t or #t == 0 then return end f:write_h(title, 2) local nt = {} + local cfunc = reft_checks[ctype] for i, v in ipairs(t) do + if cfunc then cfunc(v) end nt[#nt + 1] = { Buffer():write_link(gen_nsp_eo(v, ctype, true), v:full_name_get()):finish(), @@ -752,6 +1041,7 @@ end local build_class = function(cl) local f = Writer(gen_nsp_class(cl)) + check_class(cl) f:write_h(cl:full_name_get(), 2) @@ -840,6 +1130,7 @@ end build_method = function(fn, cl) local f = Writer(gen_nsp_func(fn, cl)) + check_method(fn, cl) f:write_h(cl:full_name_get() .. "." .. fn:name_get(), 2) @@ -864,6 +1155,9 @@ build_property = function(fn, cl) local isget = (ft == fts.PROP_GET or ft == fts.PROPERTY) local isset = (ft == fts.PROP_SET or ft == fts.PROPERTY) + if isget then check_property(fn, cl, fts.PROP_GET) end + if isset then check_property(fn, cl, fts.PROP_SET) end + local doc = fn:documentation_get(fts.PROPERTY) local gdoc = fn:documentation_get(fts.PROP_GET) local sdoc = fn:documentation_get(fts.PROP_SET) @@ -962,6 +1256,7 @@ getopt.parse { mkdir_r(nil) build_ref() build_classes() + print_stats() end } From e9899fcf70c46aef29f026d2504f55567a70fb0f Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 14 Apr 2016 17:20:49 +0100 Subject: [PATCH 27/50] docgen: align percentages in stats --- gendoc.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 3f0e0bbf67..bf93db40ce 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -261,8 +261,9 @@ local print_stat = function(printname, statname, sub) local percent = (sv == 0) and 100 or math.floor(((sv - svu) / sv) * 100 + 0.5) local tb = (" "):rep(math.max(0, fcol - #printname - 1) + ncol - stats_pd(sv)) local dtb = (" "):rep(ncol - stats_pd(sv - svu)) - print(("%s:%s%d (documented: %s%d or %d%%)") - :format(printname, tb, sv, dtb, sv - svu, percent)) + local ptb = (" "):rep(3 - stats_pd(percent)) + print(("%s:%s%d (documented: %s%d or %s%d%%)") + :format(printname, tb, sv, dtb, sv - svu, ptb, percent)) end local print_stats = function() From d199a270003c916a0f868afd89990e556d19bf9a Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Fri, 15 Apr 2016 14:08:34 +0100 Subject: [PATCH 28/50] docgen: move all path handling stuff to a single location --- gendoc.lua | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index bf93db40ce..e839234f81 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -9,17 +9,31 @@ local verbose = false -- utils +local path_sep = "/" + +local path_join = function(...) + return table.concat({ ... }, path_sep) +end + +local path_to_nspace = function(p) + return p:gsub(path_sep, ":"):lower() +end + +local nspace_to_path = function(ns) + return ns:gsub(":", path_sep):lower() +end + local make_page = function(path) - return doc_root .. "/" .. path .. ".txt" + return path_join(doc_root, path .. ".txt") end local mkdir_r = function(dirn) - local fullp = dirn and (doc_root .. "/" .. dirn) or doc_root + local fullp = dirn and path_join(doc_root, dirn) or doc_root local prev - for x in fullp:gmatch("[^/]+") do + for x in fullp:gmatch("[^" .. path_sep .. "]+") do local p if prev then - p = prev .. "/" .. x + p = path_join(prev, x) else p = x end @@ -33,7 +47,7 @@ local mkdir_r = function(dirn) end local mkdir_p = function(path) - mkdir_r(path:match("(.+)/([^/]+)")) + mkdir_r(path:match("(.+)" .. path_sep .. "([^" .. path_sep .. "]+)")) end local str_split = function(str, delim) @@ -477,9 +491,9 @@ local Writer = util.Object:clone { __ctor = function(self, path) local subs if type(path) == "table" then - subs = table.concat(path, "/") + subs = path_join(unpack(path)) else - subs = path:gsub(":", "/"):lower() + subs = nspace_to_path(path) end mkdir_p(subs) self.file = assert(io.open(make_page(subs), "w")) @@ -1238,7 +1252,7 @@ getopt.parse { if not opts["r"] then error("no documentation root supplied") end - doc_root = opts["r"] .. "/" .. root_nspace:gsub(":", "/") + doc_root = path_join(opts["r"], nspace_to_path(root_nspace)) if not args[1] then if not eolian.system_directory_scan() then error("failed scanning system directory") From a2e8f950151ff7dcab1ea0c8c693a60fa163dee1 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Sat, 16 Apr 2016 18:26:54 +0100 Subject: [PATCH 29/50] docgen: simplify build.sh (move some of it into the main script) --- build.sh | 9 ++++----- gendoc.lua | 20 +++----------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/build.sh b/build.sh index b9c889a90c..ac25748092 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,5 @@ #!/bin/sh - -ROOTNS="efl" -GENPATH="dokuwiki/data/pages" -rm -rf "$GENPATH/$ROOTNS" -elua gendoc.lua -r "$GENPATH" -n "$ROOTNS" "$@" +if [ -z "$EFL_DOC_ROOT" ]; then + export EFL_DOC_ROOT="dokuwiki/data/pages" +fi +elua gendoc.lua -r "$EFL_DOC_ROOT" "$@" diff --git a/gendoc.lua b/gendoc.lua index e839234f81..800d6f31cd 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -28,22 +28,7 @@ local make_page = function(path) end local mkdir_r = function(dirn) - local fullp = dirn and path_join(doc_root, dirn) or doc_root - local prev - for x in fullp:gmatch("[^" .. path_sep .. "]+") do - local p - if prev then - p = path_join(prev, x) - else - p = x - end - prev = p - if cutil.file_exists(p) then - assert(cutil.file_is_dir(p)) - else - assert(cutil.file_mkdir(p)) - end - end + assert(cutil.file_mkpath(dirn and path_join(doc_root, dirn) or doc_root)) end local mkdir_p = function(path) @@ -1249,7 +1234,7 @@ getopt.parse { verbose = true end root_nspace = opts["n"] or "efl" - if not opts["r"] then + if not opts["r"] or opts["r"] == "" then error("no documentation root supplied") end doc_root = path_join(opts["r"], nspace_to_path(root_nspace)) @@ -1268,6 +1253,7 @@ getopt.parse { if not eolian.all_eo_files_parse() then error("failed parsing eo files") end + cutil.file_rmrf(path_join(doc_root)) mkdir_r(nil) build_ref() build_classes() From e8e89db97f2713ec0de2916f2fbe89a02477f92a Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Sun, 17 Apr 2016 16:18:37 +0100 Subject: [PATCH 30/50] docgen: remove now unnecessary build.sh script --- build.sh | 5 ----- gendoc.lua | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) delete mode 100755 build.sh diff --git a/build.sh b/build.sh deleted file mode 100755 index ac25748092..0000000000 --- a/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -if [ -z "$EFL_DOC_ROOT" ]; then - export EFL_DOC_ROOT="dokuwiki/data/pages" -fi -elua gendoc.lua -r "$EFL_DOC_ROOT" "$@" diff --git a/gendoc.lua b/gendoc.lua index 800d6f31cd..07e3478790 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -1233,9 +1233,9 @@ getopt.parse { if opts["v"] then verbose = true end - root_nspace = opts["n"] or "efl" + root_nspace = (not opts["n"] or opts["n"] == "") and "efl" or opts["n"] if not opts["r"] or opts["r"] == "" then - error("no documentation root supplied") + opts["r"] = "dokuwiki/data/pages" end doc_root = path_join(opts["r"], nspace_to_path(root_nspace)) if not args[1] then From 16b8d21692874045e9d7b446ab524f34154d5040 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Mon, 18 Apr 2016 21:08:17 +0100 Subject: [PATCH 31/50] docgen: initial support for generic method signatures --- gendoc.lua | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/gendoc.lua b/gendoc.lua index 07e3478790..960ec19c87 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -732,6 +732,20 @@ local Buffer = Writer:clone { -- eolian to various doc elements conversions +local get_type_str +get_type_str = function(tp) + local tps = eolian.type_type + local tpt = tp:type_get() + if tpt == tps.VOID then + return "void" + end + if tpt == tps.REGULAR then + return tp:full_name_get() + end + -- TODO + return tp:full_name_get() +end + local gen_doc_refd = function(str) if not str then return nil @@ -890,6 +904,85 @@ local gen_func_csig = function(f, ftype) return cnrt .. "(" .. table.concat(pars, ", ") .. ");" end +local get_func_namesig = function(fn, cl, buf) + if fn:type_get() ~= eolian.function_type.METHOD then + buf[#buf + 1] = "@property " + end + buf[#buf + 1] = cl:full_name_get() + buf[#buf + 1] = "." + buf[#buf + 1] = fn:name_get() + buf[#buf + 1] = " " + if fn:scope_get() == eolian.object_scope.PROTECTED then + buf[#buf + 1] = "@protected " + end + if fn:is_class() then + buf[#buf + 1] = "@class " + end + if fn:is_const() then + buf[#buf + 1] = "@const " + end + if fn:is_c_only() then + buf[#buf + 1] = "@c_only " + end +end + +local gen_func_param = function(fp, buf) + -- TODO: default value + buf[#buf + 1] = " " + local dirs = { + [eolian.parameter_dir.IN] = "@in ", + [eolian.parameter_dir.OUT] = "@out ", + [eolian.parameter_dir.INOUT] = "@inout ", + } + buf[#buf + 1] = dirs[fp:direction_get()] + buf[#buf + 1] = fp:name_get() + buf[#buf + 1] = ": " + buf[#buf + 1] = get_type_str(fp:type_get()) + if fp:is_nonull() then + buf[#buf + 1] = " @nonull" + end + if fp:is_nullable() then + buf[#buf + 1] = " @nullable" + end + if fp:is_optional() then + buf[#buf + 1] = " @optional" + end + buf[#buf + 1] = ";\n" +end + +local get_method_sig = function(fn, cl) + local buf = {} + get_func_namesig(fn, cl, buf) + if fn:is_virtual_pure(eolian.function_type.METHOD) then + buf[#buf + 1] = "@virtual_pure " + end + buf[#buf + 1] = "{" + local params = fn:parameters_get():to_array() + local rtp = fn:return_type_get(eolian.function_type.METHOD) + if #params == 0 and not rtp then + buf[#buf + 1] = "}" + return table.concat(buf) + end + buf[#buf + 1] = "\n" + if #params > 0 then + buf[#buf + 1] = " params {\n" + for i, fp in ipairs(params) do + gen_func_param(fp, buf) + end + buf[#buf + 1] = " }" + end + buf[#buf + 1] = "}" + return table.concat(buf) +end + +local get_property_sig = function(fn, cl) + local buf = {} + get_func_namesig(fn, cl, buf) + buf[#buf + 1] = "{" + buf[#buf + 1] = "}" + return table.concat(buf) +end + -- builders local build_method, build_property @@ -1134,6 +1227,10 @@ build_method = function(fn, cl) f:write_h(cl:full_name_get() .. "." .. fn:name_get(), 2) + f:write_h("Signature", 3) + f:write_code(get_method_sig(fn, cl)) + f:write_nl() + f:write_h("C signature", 3) f:write_code(gen_func_csig(fn), "c") f:write_nl() @@ -1164,6 +1261,10 @@ build_property = function(fn, cl) f:write_h(cl:full_name_get() .. "." .. fn:name_get(), 2) + f:write_h("Signature", 3) + f:write_code(get_method_sig(fn, cl)) + f:write_nl() + f:write_h("C signature", 3) local codes = {} if isget then @@ -1218,7 +1319,6 @@ getopt.parse { { "h", "help", nil, help = "Show this message.", metavar = "CATEGORY", callback = getopt.help_cb(io.stdout) }, - -- TODO: implement verbose mode { "v", "verbose", false, help = "Be verbose." }, { category = "Generator" }, From 6723b8d071ea38e839e6e4a66431163b2e82d8f7 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Tue, 19 Apr 2016 21:09:10 +0100 Subject: [PATCH 32/50] docgen: support windows path sep and sanitize on all platforms --- gendoc.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 960ec19c87..cb0483f8c2 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -2,6 +2,7 @@ local eolian = require("eolian") local getopt = require("getopt") local cutil = require("cutil") local util = require("util") +local ffi = require("ffi") local doc_root local root_nspace @@ -9,18 +10,21 @@ local verbose = false -- utils -local path_sep = "/" +local path_sep, rep_sep = "/", "\\" +if ffi.os == "Windows" then + path_sep, rep_sep = rep_sep, path_sep +end local path_join = function(...) - return table.concat({ ... }, path_sep) + return table.concat({ ... }, path_sep):gsub(rep_sep, path_sep) end local path_to_nspace = function(p) - return p:gsub(path_sep, ":"):lower() + return p:gsub(rep_sep, ":"):gsub(path_sep, ":"):lower() end local nspace_to_path = function(ns) - return ns:gsub(":", path_sep):lower() + return ns:gsub(":", path_sep):gsub(rep_sep, path_sep):lower() end local make_page = function(path) From 4e404addc1666d301ca5aa4e7fff087f31e5b77b Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 20 Apr 2016 12:49:51 +0100 Subject: [PATCH 33/50] docgen: fix doc since tag retrieval --- gendoc.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index cb0483f8c2..b5a7292eee 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -1100,8 +1100,8 @@ local write_full_doc = function(f, doc1, doc2) if doc2 then since = doc2:since_get() end - if not since and doc then - since = doc:since_get() + if not since and doc1 then + since = doc1:since_get() end if since then f:write_i(since) From 050310b535ec2e93287438bba6bf69b95bab99e9 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 20 Apr 2016 12:51:09 +0100 Subject: [PATCH 34/50] docgen: clearer since documentation --- gendoc.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gendoc.lua b/gendoc.lua index b5a7292eee..6661421842 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -1104,7 +1104,7 @@ local write_full_doc = function(f, doc1, doc2) since = doc1:since_get() end if since then - f:write_i(since) + f:write_i("Since " .. since) f:write_nl(2) end end From 4bbc956079cf5371136774de175f8e13063c7872 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 21 Apr 2016 17:14:11 +0100 Subject: [PATCH 35/50] docgen: add a type serializer and use it for signature params --- gendoc.lua | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 6661421842..2fba9d7b5c 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -736,18 +736,48 @@ local Buffer = Writer:clone { -- eolian to various doc elements conversions +local wrap_type_attrs = function(tp, str) + if tp:is_const() then + str = "const(" .. str .. ")" + end + if tp:is_own() then + str = "own(" .. str .. ")" + end + local ffunc = tp:free_func_get() + if ffunc then + str = "free(" .. str .. ", " .. ffunc .. ")" + end + return str +end + local get_type_str get_type_str = function(tp) local tps = eolian.type_type local tpt = tp:type_get() - if tpt == tps.VOID then - return "void" + if tpt == tps.UNKNOWN then + error("unknown type: " .. tp:full_name_get()) + elseif tpt == tps.VOID then + return wrap_type_attrs(tp, "void") + elseif tpt == tps.UNDEFINED then + return wrap_type_attrs(tp, "__undefined_type") + elseif tpt == tps.REGULAR or tpt == tps.CLASS then + return wrap_type_attrs(tp, tp:full_name_get()) + elseif tpt == tps.COMPLEX then + local stypes = {} + for stp in tp:subtypes_get() do + stypes[#stypes + 1] = get_type_str(stp) + end + return wrap_type_attrs(tp, tp:full_name_get() .. "<" + .. table.concat(stypes, ", ") .. ">") + elseif tpt == tps.POINTER then + local btp = tp:base_type_get() + local suffix = " *" + if btp:type_get() == tps.POINTER then + suffix = "*" + end + return wrap_type_attrs(tp, get_type_str(btp) .. suffix) end - if tpt == tps.REGULAR then - return tp:full_name_get() - end - -- TODO - return tp:full_name_get() + error("unhandled type type: " .. tpt) end local gen_doc_refd = function(str) @@ -973,7 +1003,7 @@ local get_method_sig = function(fn, cl) for i, fp in ipairs(params) do gen_func_param(fp, buf) end - buf[#buf + 1] = " }" + buf[#buf + 1] = " }\n" end buf[#buf + 1] = "}" return table.concat(buf) From 8ce185d8a6c03cfd4b43bd979d7e00fa55435a12 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Fri, 22 Apr 2016 13:54:33 +0100 Subject: [PATCH 36/50] docgen: complete generic signatures for methods --- gendoc.lua | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 2fba9d7b5c..5d23816822 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -960,7 +960,7 @@ local get_func_namesig = function(fn, cl, buf) end end -local gen_func_param = function(fp, buf) +local gen_func_param = function(fp, buf, nodir) -- TODO: default value buf[#buf + 1] = " " local dirs = { @@ -968,10 +968,16 @@ local gen_func_param = function(fp, buf) [eolian.parameter_dir.OUT] = "@out ", [eolian.parameter_dir.INOUT] = "@inout ", } - buf[#buf + 1] = dirs[fp:direction_get()] + if not nodir then buf[#buf + 1] = dirs[fp:direction_get()] end buf[#buf + 1] = fp:name_get() buf[#buf + 1] = ": " buf[#buf + 1] = get_type_str(fp:type_get()) + local dval = fp:default_value_get() + if dval then + buf[#buf + 1] = " (" + buf[#buf + 1] = dval:serialize() + buf[#buf + 1] = ")" + end if fp:is_nonull() then buf[#buf + 1] = " @nonull" end @@ -1005,6 +1011,21 @@ local get_method_sig = function(fn, cl) end buf[#buf + 1] = " }\n" end + local rett = fn:return_type_get(eolian.function_type.METHOD) + if rett then + buf[#buf + 1] = " return: " + buf[#buf + 1] = get_type_str(rett) + local dval = fn:return_default_value_get(eolian.function_type.METHOD) + if dval then + buf[#buf + 1] = " (" + buf[#buf + 1] = dval:serialize() + buf[#buf + 1] = ")" + end + if fn:return_is_warn_unused(eolian.function_type.METHOD) then + buf[#buf + 1] = " @warn_unused" + end + buf[#buf + 1] = ";\n" + end buf[#buf + 1] = "}" return table.concat(buf) end From 96d9572df62d9cd427f87d98e4c6fc831169b369 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Fri, 22 Apr 2016 15:32:19 +0100 Subject: [PATCH 37/50] docgen: generation of property signatures --- gendoc.lua | 136 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 116 insertions(+), 20 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 5d23816822..4c6c5fea48 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -938,7 +938,7 @@ local gen_func_csig = function(f, ftype) return cnrt .. "(" .. table.concat(pars, ", ") .. ");" end -local get_func_namesig = function(fn, cl, buf) +local gen_func_namesig = function(fn, cl, buf) if fn:type_get() ~= eolian.function_type.METHOD then buf[#buf + 1] = "@property " end @@ -990,9 +990,29 @@ local gen_func_param = function(fp, buf, nodir) buf[#buf + 1] = ";\n" end -local get_method_sig = function(fn, cl) +local gen_func_return = function(fp, ftype, buf, indent) + local rett = fp:return_type_get(ftype) + if not rett then + return + end + buf[#buf + 1] = indent and (" "):rep(indent) or " " + buf[#buf + 1] = "return: " + buf[#buf + 1] = get_type_str(rett) + local dval = fp:return_default_value_get(ftype) + if dval then + buf[#buf + 1] = " (" + buf[#buf + 1] = dval:serialize() + buf[#buf + 1] = ")" + end + if fp:return_is_warn_unused(ftype) then + buf[#buf + 1] = " @warn_unused" + end + buf[#buf + 1] = ";\n" +end + +local gen_method_sig = function(fn, cl) local buf = {} - get_func_namesig(fn, cl, buf) + gen_func_namesig(fn, cl, buf) if fn:is_virtual_pure(eolian.function_type.METHOD) then buf[#buf + 1] = "@virtual_pure " end @@ -1011,28 +1031,104 @@ local get_method_sig = function(fn, cl) end buf[#buf + 1] = " }\n" end - local rett = fn:return_type_get(eolian.function_type.METHOD) - if rett then - buf[#buf + 1] = " return: " - buf[#buf + 1] = get_type_str(rett) - local dval = fn:return_default_value_get(eolian.function_type.METHOD) - if dval then - buf[#buf + 1] = " (" - buf[#buf + 1] = dval:serialize() - buf[#buf + 1] = ")" - end - if fn:return_is_warn_unused(eolian.function_type.METHOD) then - buf[#buf + 1] = " @warn_unused" - end - buf[#buf + 1] = ";\n" + gen_func_return(fn, eolian.function_type.METHOD, buf) + buf[#buf + 1] = "}" + return table.concat(buf) +end + +local eovals_check_same = function(a1, a2) + if #a1 ~= #a2 then return false end + for i, v in ipairs(a1) do + if v ~= a2[i] then return false end end + return true +end + +local gen_prop_keyvals = function(tbl, kword, buf, indent) + local ind = indent and (" "):rep(indent) or " " + if #tbl == 0 then return end + buf[#buf + 1] = " " + buf[#buf + 1] = ind + buf[#buf + 1] = kword + buf[#buf + 1] = " {\n" + for i, v in ipairs(tbl) do + buf[#buf + 1] = ind + gen_func_param(v, buf, true) + end + buf[#buf + 1] = " " + buf[#buf + 1] = ind + buf[#buf + 1] = "}\n" +end + +local gen_prop_sig = function(fn, cl) + local buf = {} + gen_func_namesig(fn, cl, buf) + local fnt = fn:type_get() + local ftt = eolian.function_type + local isget = (fnt == ftt.PROPERTY or fnt == ftt.PROP_GET) + local isset = (fnt == ftt.PROPERTY or fnt == ftt.PROP_SET) + + local gvirt = fn:is_virtual_pure(ftt.PROP_GET) + local svirt = fn:is_virtual_pure(ftt.PROP_SET) + + if (not isget or gvirt) and (not isset or svirt) then + buf[#buf + 1] = "@virtual_pure " + end + + local gkeys = isget and fn:property_keys_get(ftt.PROP_GET):to_array() or {} + local skeys = isset and fn:property_keys_get(ftt.PROP_SET):to_array() or {} + local gvals = isget and fn:property_values_get(ftt.PROP_GET):to_array() or {} + local svals = isget and fn:property_values_get(ftt.PROP_SET):to_array() or {} + local grtt = isget and fn:return_type_get(ftt.PROP_GET) or nil + local srtt = isset and fn:return_type_get(ftt.PROP_SET) or nil + + local keys_same = eovals_check_same(gkeys, skeys) + local vals_same = eovals_check_same(gvals, svals) + + buf[#buf + 1] = "{\n" + + if isget then + buf[#buf + 1] = " get {" + if (#gkeys == 0 or keys_same) and (#gvals == 0 or vals_same) and + (not grtt or grtt == srtt) then + buf[#buf + 1] = "}\n" + else + buf[#buf + 1] = "\n" + if not keys_same then gen_prop_keyvals(gkeys, "keys", buf) end + if not vals_same then gen_prop_keyvals(gvals, "values", buf) end + if grtt ~= srtt then + gen_func_return(fn, ftt.PROP_GET, buf, 2) + end + buf[#buf + 1] = " }\n" + end + end + + if isset then + buf[#buf + 1] = " set {" + if (#skeys == 0 or keys_same) and (#svals == 0 or vals_same) and + (not srtt or grtt == srtt) then + buf[#buf + 1] = "}\n" + else + buf[#buf + 1] = "\n" + if not keys_same then gen_prop_keyvals(skeys, "keys", buf) end + if not vals_same then gen_prop_keyvals(svals, "values", buf) end + if grtt ~= srtt then + gen_func_return(fn, ftt.PROP_SET, buf, 2) + end + buf[#buf + 1] = " }\n" + end + end + + if keys_same then gen_prop_keyvals(gkeys, "keys", buf, 0) end + if vals_same then gen_prop_keyvals(gvals, "values", buf, 0) end + buf[#buf + 1] = "}" return table.concat(buf) end local get_property_sig = function(fn, cl) local buf = {} - get_func_namesig(fn, cl, buf) + gen_func_namesig(fn, cl, buf) buf[#buf + 1] = "{" buf[#buf + 1] = "}" return table.concat(buf) @@ -1283,7 +1379,7 @@ build_method = function(fn, cl) f:write_h(cl:full_name_get() .. "." .. fn:name_get(), 2) f:write_h("Signature", 3) - f:write_code(get_method_sig(fn, cl)) + f:write_code(gen_method_sig(fn, cl)) f:write_nl() f:write_h("C signature", 3) @@ -1317,7 +1413,7 @@ build_property = function(fn, cl) f:write_h(cl:full_name_get() .. "." .. fn:name_get(), 2) f:write_h("Signature", 3) - f:write_code(get_method_sig(fn, cl)) + f:write_code(gen_prop_sig(fn, cl)) f:write_nl() f:write_h("C signature", 3) From 5eb3ddf8527142af95c633778ba2e778e32da25a Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Sat, 23 Apr 2016 18:37:49 +0100 Subject: [PATCH 38/50] docgen: remove the unnecessary initializers for stats --- gendoc.lua | 54 ++++++------------------------------------------------ 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 4c6c5fea48..6bbd179263 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -196,52 +196,7 @@ end -- statistics -local stats = { - class = 0, - class_undoc = 0, - interface = 0, - interface_undoc = 0, - mixin = 0, - mixin_undoc = 0, - method = 0, - method_undoc = 0, - param = 0, - param_undoc = 0, - mret = 0, - mret_undoc = 0, - getter = 0, - getter_undoc = 0, - gret = 0, - gret_undoc = 0, - gkey = 0, - gkey_undoc = 0, - gvalue = 0, - gvalue_undoc = 0, - setter = 0, - setter_undoc = 0, - sret = 0, - sret_undoc = 0, - skey = 0, - skey_undoc = 0, - svalue = 0, - svalue_undoc = 0, - event = 0, - event_undoc = 0, - alias = 0, - alias_undoc = 0, - struct = 0, - struct_undoc = 0, - sfield = 0, - sfield_undoc = 0, - enum = 0, - enum_undoc = 0, - efield = 0, - efield_undoc = 0, - constant = 0, - constant_undoc = 0, - global = 0, - global_undoc = 0 -} +local stats = {} local stats_pd = function(n) local ret = 0 @@ -259,8 +214,8 @@ local fcol = 30 local ncol = 0 local print_stat = function(printname, statname, sub) - local sv = stats[statname] - local svu = stats[statname .. "_undoc"] + local sv = stats[statname] or 0 + local svu = stats[statname .. "_undoc"] or 0 local percent = (sv == 0) and 100 or math.floor(((sv - svu) / sv) * 100 + 0.5) local tb = (" "):rep(math.max(0, fcol - #printname - 1) + ncol - stats_pd(sv)) local dtb = (" "):rep(ncol - stats_pd(sv - svu)) @@ -306,6 +261,9 @@ local print_stats = function() end local stat_incr = function(name, missing) + if not stats[name] then + stats[name], stats[name .. "_undoc"] = 0, 0 + end stats[name] = stats[name] + 1 if missing then stats[name .. "_undoc"] = stats[name .. "_undoc"] + 1 From c566ab91136002ef4accc889d6368c0da880b1dd Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Sun, 24 Apr 2016 17:18:40 +0100 Subject: [PATCH 39/50] docgen: put global settings into a single table --- gendoc.lua | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 6bbd179263..4153008384 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -4,9 +4,7 @@ local cutil = require("cutil") local util = require("util") local ffi = require("ffi") -local doc_root -local root_nspace -local verbose = false +local global_opts = {} -- utils @@ -28,11 +26,12 @@ local nspace_to_path = function(ns) end local make_page = function(path) - return path_join(doc_root, path .. ".txt") + return path_join(global_opts.doc_root, path .. ".txt") end local mkdir_r = function(dirn) - assert(cutil.file_mkpath(dirn and path_join(doc_root, dirn) or doc_root)) + local dr = global_opts.doc_root + assert(cutil.file_mkpath(dirn and path_join(dr, dirn) or dr)) end local mkdir_p = function(path) @@ -271,7 +270,7 @@ local stat_incr = function(name, missing) end local print_missing = function(name, tp) - if not verbose then + if not global_opts.verbose then return end print(tp .. " '" .. name .. "'" .. " missing documentation") @@ -530,7 +529,8 @@ local Writer = util.Object:clone { if type(target) == "table" then if target[#target] == true then target[#target] = nil - target = ":" .. root_nspace .. ":" .. table.concat(target, ":") + target = ":" .. global_opts.root_nspace .. ":" + .. table.concat(target, ":") else target = table.concat(target, ":") end @@ -1440,13 +1440,15 @@ getopt.parse { end, done_cb = function(parser, opts, args) if opts["v"] then - verbose = true + global_opts.verbose = true end - root_nspace = (not opts["n"] or opts["n"] == "") and "efl" or opts["n"] + global_opts.root_nspace = (not opts["n"] or opts["n"] == "") + and "efl" or opts["n"] if not opts["r"] or opts["r"] == "" then opts["r"] = "dokuwiki/data/pages" end - doc_root = path_join(opts["r"], nspace_to_path(root_nspace)) + global_opts.doc_root = path_join(opts["r"], + nspace_to_path(global_opts.root_nspace)) if not args[1] then if not eolian.system_directory_scan() then error("failed scanning system directory") @@ -1462,7 +1464,7 @@ getopt.parse { if not eolian.all_eo_files_parse() then error("failed parsing eo files") end - cutil.file_rmrf(path_join(doc_root)) + cutil.file_rmrf(path_join(global_opts.doc_root)) mkdir_r(nil) build_ref() build_classes() From 14ca210f2d30f7bcecc4b5f02dfc9a61e46adc92 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Mon, 25 Apr 2016 18:06:36 +0100 Subject: [PATCH 40/50] docgen: better newline handling in generated docs --- gendoc.lua | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 4153008384..7de53ccb30 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -1200,7 +1200,6 @@ end local write_full_doc = function(f, doc1, doc2) f:write_raw(get_full_doc(doc1, doc2)) - f:write_nl(2) local since if doc2 then since = doc2:since_get() @@ -1209,8 +1208,8 @@ local write_full_doc = function(f, doc1, doc2) since = doc1:since_get() end if since then - f:write_i("Since " .. since) f:write_nl(2) + f:write_i("Since " .. since) end end @@ -1252,6 +1251,7 @@ local build_class = function(cl) f:write_h("Description", 3) write_full_doc(f, cl:documentation_get()) + f:write_nl(2) build_functable(f, "Methods", "Method name", cl, eolian.function_type.METHOD) build_functable(f, "Properties", "Property name", @@ -1262,9 +1262,14 @@ local build_class = function(cl) if #evs == 0 then f:write_raw("This class does not define any events.\n") else + local first = true for i, ev in ipairs(evs) do + if not first then + f:write_nl(2) + end f:write_h(ev:name_get(), 4) write_full_doc(f, ev:documentation_get()) + first = false end end @@ -1349,6 +1354,7 @@ build_method = function(fn, cl) f:write_h("Description", 3) write_full_doc(f, fn:documentation_get(eolian.function_type.METHOD)) + f:write_nl() f:finish() end @@ -1398,6 +1404,9 @@ build_property = function(fn, cl) if doc or (not gdoc and not sdoc) then write_full_doc(f, doc) end + if (isget and gdoc) or (isset and sdoc) then + f:write_nl(2) + end end if isget and gdoc then @@ -1407,6 +1416,9 @@ build_property = function(fn, cl) f:write_h("Description", 3) end write_full_doc(f, gdoc) + if isset and sdoc then + f:write_nl(2) + end end if isset and sdoc then @@ -1418,6 +1430,7 @@ build_property = function(fn, cl) write_full_doc(f, sdoc) end + f:write_nl() f:finish() end From de66784dba4f13001c202033bd5149f544fc006a Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Tue, 26 Apr 2016 14:37:47 +0100 Subject: [PATCH 41/50] docgen: only generate params for methods when they exist --- gendoc.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 7de53ccb30..c59b50de0b 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -1349,8 +1349,12 @@ build_method = function(fn, cl) f:write_code(gen_func_csig(fn), "c") f:write_nl() - f:write_h("Parameters", 3) - build_parlist(f, fn:parameters_get():to_array()) + local pars = fn:parameters_get():to_array() + if #pars > 0 then + f:write_h("Parameters", 3) + build_parlist(f, pars) + f:write_nl() + end f:write_h("Description", 3) write_full_doc(f, fn:documentation_get(eolian.function_type.METHOD)) From c85e79b32f76c742bd7af407d9dfdcdb89d94548 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 27 Apr 2016 15:49:13 +0100 Subject: [PATCH 42/50] docgen: add support for inheritance graphs via graphviz --- gendoc.lua | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/gendoc.lua b/gendoc.lua index c59b50de0b..43dc3da799 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -1240,6 +1240,72 @@ build_inherits = function(cl, t, lvl) return t end + +local class_to_color = function(cl) + local classt_to_color = { + [eolian.class_type.REGULAR] = { "black", "gray" }, + [eolian.class_type.ABSTRACT] = { "black", "gray" }, + [eolian.class_type.MIXIN] = { "blue", "skyblue" }, + [eolian.class_type.INTERFACE] = { "cornflowerblue", "azure" } + } + return classt_to_color[cl:type_get()] +end + +local class_to_node = function(cl, main) + local cn = cl:full_name_get() + local sn = cn:lower():gsub("%.", "_") + local attrs = { "label = \"" .. cn .. "\"" } + local clr = class_to_color(cl) + if main then + attrs[#attrs + 1] = "style = filled" + attrs[#attrs + 1] = "fillcolor = " .. clr[2] + end + attrs[#attrs + 1] = "color = " .. clr[1] + + -- FIXME: need a dokuwiki graphviz plugin with proper URL support + -- the existing one only supports raw URLs (no dokuwikí namespaces) + --local url = ":" .. global_opts.root_nspace .. ":" + -- .. table.concat(gen_nsp_class(cl), ":") + --attrs[#attrs + 1] = "URL=\"" .. url .. "\"" + + return sn .. " [" .. table.concat(attrs, ", ") .. "]" +end + +local build_igraph_r +build_igraph_r = function(cl, nbuf, ibuf) + local sn = cl:full_name_get():lower():gsub("%.", "_") + for cln in cl:inherits_get() do + local acl = eolian.class_get_by_name(cln) + if not acl then + error("error retrieving inherited class " .. cln) + end + nbuf[#nbuf + 1] = class_to_node(acl) + ibuf[#ibuf + 1] = sn .. " -> " .. cln:lower():gsub("%.", "_") + build_igraph_r(acl, nbuf, ibuf) + end +end + +local build_igraph = function(cl) + local buf = { "\n" } + buf[#buf + 1] = "digraph hierarchy {\n" + buf[#buf + 1] = "rankdir = TB\n" + buf[#buf + 1] = "size = \"6\"\n" + buf[#buf + 1] = "node [shape = box]\n\n" + + local nbuf = {} + local ibuf = {} + nbuf[#nbuf + 1] = class_to_node(cl, true) + build_igraph_r(cl, nbuf, ibuf) + + buf[#buf + 1] = table.concat(nbuf, "\n") + buf[#buf + 1] = "\n\n" + + buf[#buf + 1] = table.concat(ibuf, "\n") + buf[#buf + 1] = "\n}\n" + + return table.concat(buf) +end + local build_class = function(cl) local f = Writer(gen_nsp_class(cl)) check_class(cl) @@ -1248,6 +1314,9 @@ local build_class = function(cl) f:write_h("Inheritance hierarchy", 3) f:write_list(build_inherits(cl)) + f:write_nl() + f:write_raw(build_igraph(cl)) + f:write_nl(2) f:write_h("Description", 3) write_full_doc(f, cl:documentation_get()) From 66322c0940116100154e3abb5a317124b2cbf93a Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 27 Apr 2016 15:56:59 +0100 Subject: [PATCH 43/50] docgen: transparency for inheritance graph background --- gendoc.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 43dc3da799..e3b118d142 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -1256,11 +1256,13 @@ local class_to_node = function(cl, main) local sn = cn:lower():gsub("%.", "_") local attrs = { "label = \"" .. cn .. "\"" } local clr = class_to_color(cl) - if main then - attrs[#attrs + 1] = "style = filled" - attrs[#attrs + 1] = "fillcolor = " .. clr[2] - end + attrs[#attrs + 1] = "style = filled" attrs[#attrs + 1] = "color = " .. clr[1] + if main then + attrs[#attrs + 1] = "fillcolor = " .. clr[2] + else + attrs[#attrs + 1] = "fillcolor = white" + end -- FIXME: need a dokuwiki graphviz plugin with proper URL support -- the existing one only supports raw URLs (no dokuwikí namespaces) @@ -1290,6 +1292,7 @@ local build_igraph = function(cl) buf[#buf + 1] = "digraph hierarchy {\n" buf[#buf + 1] = "rankdir = TB\n" buf[#buf + 1] = "size = \"6\"\n" + buf[#buf + 1] = "bgcolor = \"transparent\"\n" buf[#buf + 1] = "node [shape = box]\n\n" local nbuf = {} From ff57eec82ef474314663fddef183725250570c56 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 28 Apr 2016 13:59:39 +0100 Subject: [PATCH 44/50] docgen: generalized graph writer --- gendoc.lua | 110 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 28 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index e3b118d142..6ca9c3f619 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -550,6 +550,63 @@ local Writer = util.Object:clone { return self end, + write_graph = function(self, tbl) + self:write_raw("\n") + self:write_raw("digraph ", tbl.type, " {\n") + + for k, v in pairs(tbl.attrs or {}) do + self:write_raw(" ", k, " = \"", v, "\"\n") + end + + local write_node = function(nname, attrs) + self:write_raw(" ", nname, " [") + local first = true + for k, v in pairs(attrs) do + if not first then + self:write_raw(", ") + end + self:write_raw(k, " = \"", v, "\"") + first = false + end + self:write_raw("]\n") + end + + if tbl.node then + self:write_nl() + write_node("node", tbl.node) + end + if tbl.edge then + if not tbl.node then self:write_nl() end + write_node("edge", tbl.edge) + end + + self:write_nl() + for i, v in ipairs(tbl.nodes) do + local nname = v.name + v.name = nil + write_node(nname, v) + end + + self:write_nl() + for i, v in ipairs(tbl.connections) do + local from, to, sep = v[1], v[2], (v[3] or "->") + if type(from) == "table" then + self:write_raw(" {", table.concat(from, ", "), "}") + else + self:write_raw(" ", from) + end + self:write_raw(" ", sep, " ") + if type(to) == "table" then + self:write_raw("{", table.concat(to, ", "), "}") + else + self:write_raw(to) + end + self:write_nl() + end + + self:write_raw("}\n") + end, + write_table = function(self, titles, tbl) self:write_raw("^ ", table.concat(titles, " ^ "), " ^\n") for i, v in ipairs(tbl) do @@ -1252,25 +1309,22 @@ local class_to_color = function(cl) end local class_to_node = function(cl, main) - local cn = cl:full_name_get() - local sn = cn:lower():gsub("%.", "_") - local attrs = { "label = \"" .. cn .. "\"" } + local ret = {} + + ret.label = cl:full_name_get() + ret.name = ret.label:lower():gsub("%.", "_") + local clr = class_to_color(cl) - attrs[#attrs + 1] = "style = filled" - attrs[#attrs + 1] = "color = " .. clr[1] - if main then - attrs[#attrs + 1] = "fillcolor = " .. clr[2] - else - attrs[#attrs + 1] = "fillcolor = white" - end + ret.style = "filled" + ret.color = clr[1] + ret.fillcolor = main and clr[2] or "white" -- FIXME: need a dokuwiki graphviz plugin with proper URL support -- the existing one only supports raw URLs (no dokuwikí namespaces) - --local url = ":" .. global_opts.root_nspace .. ":" - -- .. table.concat(gen_nsp_class(cl), ":") - --attrs[#attrs + 1] = "URL=\"" .. url .. "\"" + --ret.URL = ":" .. global_opts.root_nspace .. ":" + -- .. table.concat(gen_nsp_class(cl), ":") - return sn .. " [" .. table.concat(attrs, ", ") .. "]" + return ret end local build_igraph_r @@ -1282,31 +1336,31 @@ build_igraph_r = function(cl, nbuf, ibuf) error("error retrieving inherited class " .. cln) end nbuf[#nbuf + 1] = class_to_node(acl) - ibuf[#ibuf + 1] = sn .. " -> " .. cln:lower():gsub("%.", "_") + ibuf[#ibuf + 1] = { sn, (cln:lower():gsub("%.", "_")) } build_igraph_r(acl, nbuf, ibuf) end end local build_igraph = function(cl) - local buf = { "\n" } - buf[#buf + 1] = "digraph hierarchy {\n" - buf[#buf + 1] = "rankdir = TB\n" - buf[#buf + 1] = "size = \"6\"\n" - buf[#buf + 1] = "bgcolor = \"transparent\"\n" - buf[#buf + 1] = "node [shape = box]\n\n" + local graph = { + type = "hierarchy", + attrs = { + rankdir = "TB", + size = "6", + bgcolor = "transparent" + }, + node = { shape = "box" } + } local nbuf = {} local ibuf = {} nbuf[#nbuf + 1] = class_to_node(cl, true) build_igraph_r(cl, nbuf, ibuf) - buf[#buf + 1] = table.concat(nbuf, "\n") - buf[#buf + 1] = "\n\n" + graph.nodes = nbuf + graph.connections = ibuf - buf[#buf + 1] = table.concat(ibuf, "\n") - buf[#buf + 1] = "\n}\n" - - return table.concat(buf) + return graph end local build_class = function(cl) @@ -1318,7 +1372,7 @@ local build_class = function(cl) f:write_h("Inheritance hierarchy", 3) f:write_list(build_inherits(cl)) f:write_nl() - f:write_raw(build_igraph(cl)) + f:write_graph(build_igraph(cl)) f:write_nl(2) f:write_h("Description", 3) From 18542180eaa889c734d720cd088266ec4aeca758 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 28 Apr 2016 16:20:27 +0100 Subject: [PATCH 45/50] docgen: add params to disable usage of graphviz and notes plugins --- gendoc.lua | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 6ca9c3f619..c774767a56 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -701,12 +701,12 @@ local Writer = util.Object:clone { end, write_par = function(self, str) - local notetypes = { + local notetypes = global_opts.use_notes and { ["Note: "] = "\n", ["Warning: "] = "\n", ["Remark: "] = "\n", ["TODO: "] = "\n**TODO:** " - } + } or {} local tag for k, v in pairs(notetypes) do if str:match("^" .. k) then @@ -1372,8 +1372,10 @@ local build_class = function(cl) f:write_h("Inheritance hierarchy", 3) f:write_list(build_inherits(cl)) f:write_nl() - f:write_graph(build_igraph(cl)) - f:write_nl(2) + if global_opts.use_dot then + f:write_graph(build_igraph(cl)) + f:write_nl(2) + end f:write_h("Description", 3) write_full_doc(f, cl:documentation_get()) @@ -1575,16 +1577,18 @@ getopt.parse { { category = "Generator" }, { "r", "root", true, help = "Root path of the docs." }, - { "n", "namespace", true, help = "Root namespace of the docs." } + { "n", "namespace", true, help = "Root namespace of the docs." }, + { nil, "disable-graphviz", false, help = "Disable graphviz usage." }, + { nil, "disable-notes", false, help = "Disable notes plugin usage." } }, error_cb = function(parser, msg) io.stderr:write(msg, "\n") getopt.help(parser, io.stderr) end, done_cb = function(parser, opts, args) - if opts["v"] then - global_opts.verbose = true - end + global_opts.verbose = not not opts["v"] + global_opts.use_dot = not opts["disable-graphviz"] + global_opts.use_notes = not opts["disable-notes"] global_opts.root_nspace = (not opts["n"] or opts["n"] == "") and "efl" or opts["n"] if not opts["r"] or opts["r"] == "" then From 180af88ad7bfd74554951edcd8efed3e0883cece Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 28 Apr 2016 16:21:29 +0100 Subject: [PATCH 46/50] docgen: don't generate docs when help option is given --- gendoc.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gendoc.lua b/gendoc.lua index c774767a56..cbeae4bdc1 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -1586,6 +1586,9 @@ getopt.parse { getopt.help(parser, io.stderr) end, done_cb = function(parser, opts, args) + if opts["h"] then + return + end global_opts.verbose = not not opts["v"] global_opts.use_dot = not opts["disable-graphviz"] global_opts.use_notes = not opts["disable-notes"] From a7297cef42daf8bef47ac69a64b3bede36f12790 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 5 May 2016 11:59:52 +0100 Subject: [PATCH 47/50] docgen: add type declaration serializer for type docs --- gendoc.lua | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/gendoc.lua b/gendoc.lua index cbeae4bdc1..18d5b61382 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -795,6 +795,81 @@ get_type_str = function(tp) error("unhandled type type: " .. tpt) end +local add_typedecl_attrs = function(tp, buf) + if tp:is_extern() then + buf[#buf + 1] = "@extern " + end + local ffunc = tp:free_func_get() + if ffunc then + buf[#buf + 1] = "@free(" + buf[#buf + 1] = ffunc + buf[#buf + 1] = ") " + end +end + +local get_typedecl_str = function(tp) + local tps = eolian.typedecl_type + local tpt = tp:type_get() + if tpt == tps.UNKNOWN then + error("unknown typedecl: " .. tp:full_name_get()) + elseif tpt == tps.STRUCT or tpt == tps.STURCT_OPAQUE then + local buf = { "struct " } + add_typedecl_attrs(tp, buf) + buf[#buf + 1] = tp:full_name_get() + if tpt == tps.STRUCT_OPAQUE then + buf[#buf + 1] = ";" + return table.concat(buf) + end + local fields = tp:struct_fields_get():to_array() + if #fields == 0 then + buf[#buf + 1] = " {}" + return table.concat(buf) + end + buf[#buf + 1] = " {\n" + for i, fld in ipairs(fields) do + buf[#buf + 1] = " " + buf[#buf + 1] = fld:name_get() + buf[#buf + 1] = ": " + buf[#buf + 1] = get_type_str(fld:type_get()) + buf[#buf + 1] = ";\n" + end + buf[#buf + 1] = "}" + return table.concat(buf) + elseif tpt == tps.ENUM then + local buf = { "enum " } + add_typedecl_attrs(tp, buf) + buf[#buf + 1] = tp:full_name_get() + local fields = tp:enum_fields_get():to_array() + if #fields == 0 then + buf[#buf + 1] = " {}" + return table.concat(buf) + end + buf[#buf + 1] = " {\n" + for i, fld in ipairs(fields) do + buf[#buf + 1] = " " + buf[#buf + 1] = fld:name_get() + buf[#buf + 1] = ": " + buf[#buf + 1] = fld:value_get():serialize() + if i == #fields then + buf[#buf + 1] = "\n" + else + buf[#buf + 1] = ",\n" + end + end + buf[#buf + 1] = "}" + return table.concat(buf) + elseif tpt == tps.ALIAS then + local buf = { "type " } + add_typedecl_attrs(tp, buf) + buf[#buf + 1] = tp:full_name_get() + buf[#buf + 1] = ": " + buf[#buf + 1] = get_type_str(tp:base_type_get()) + buf[#buf + 1] = ";" + return table.concat(buf) + end + error("unhandled typedecl type: " .. tpt) +end + local gen_doc_refd = function(str) if not str then return nil @@ -1414,6 +1489,40 @@ local build_classes = function() end end +local build_alias = function(tp) +end + +local build_struct = function(tp) +end + +local build_enum = function(tp) +end + +local build_variable = function(v, constant) +end + +local build_typedecls = function() + for tp in eolian.typedecl_all_aliases_get() do + build_alias(tp) + end + + for tp in eolian.typedecl_all_structs_get() do + build_struct(tp) + end + + for tp in eolian.typedecl_all_enums_get() do + build_enum(tp) + end + + for v in eolian.variable_all_constants_get() do + build_variable(v, true) + end + + for v in eolian.variable_all_globals_get() do + build_variable(v, false) + end +end + local pdir_to_str = { [eolian.parameter_dir.IN] = "(in)", [eolian.parameter_dir.OUT] = "(out)", @@ -1618,6 +1727,7 @@ getopt.parse { mkdir_r(nil) build_ref() build_classes() + build_typedecls() print_stats() end } From d46ae0205c056103697196b94a6ffe745e3d0033 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 5 May 2016 14:29:14 +0100 Subject: [PATCH 48/50] docgen: generate pages for different types --- gendoc.lua | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 18d5b61382..db201e8720 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -1228,23 +1228,13 @@ end local build_method, build_property -local reft_checks = { - ["alias"] = check_alias, - ["struct"] = check_struct, - ["enum"] = check_enum, - ["constant"] = check_constant, - ["global"] = check_global -} - local build_reftable = function(f, title, ctitle, ctype, t) if not t or #t == 0 then return end f:write_h(title, 2) local nt = {} - local cfunc = reft_checks[ctype] for i, v in ipairs(t) do - if cfunc then cfunc(v) end nt[#nt + 1] = { Buffer():write_link(gen_nsp_eo(v, ctype, true), v:full_name_get()):finish(), @@ -1490,15 +1480,35 @@ local build_classes = function() end local build_alias = function(tp) + local f = Writer(gen_nsp_eo(tp, "alias")) + check_alias(tp) + + f:finish() end local build_struct = function(tp) + local f = Writer(gen_nsp_eo(tp, "struct")) + check_struct(tp) + + f:finish() end local build_enum = function(tp) + local f = Writer(gen_nsp_eo(tp, "enum")) + check_enum(tp) + + f:finish() end local build_variable = function(v, constant) + local f = Writer(gen_nsp_eo(v, constant and "constant" or "global")) + if constant then + check_constant(v) + else + check_global(v) + end + + f:finish() end local build_typedecls = function() @@ -1513,7 +1523,9 @@ local build_typedecls = function() for tp in eolian.typedecl_all_enums_get() do build_enum(tp) end +end +local build_variables = function() for v in eolian.variable_all_constants_get() do build_variable(v, true) end @@ -1728,6 +1740,7 @@ getopt.parse { build_ref() build_classes() build_typedecls() + build_variables() print_stats() end } From aaa1e2b0ec58370d9ffaef0002e5f68c65185e30 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Tue, 10 May 2016 18:11:24 +0100 Subject: [PATCH 49/50] docgen: basic doc generation for types --- gendoc.lua | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index db201e8720..4abb298fee 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -812,7 +812,7 @@ local get_typedecl_str = function(tp) local tpt = tp:type_get() if tpt == tps.UNKNOWN then error("unknown typedecl: " .. tp:full_name_get()) - elseif tpt == tps.STRUCT or tpt == tps.STURCT_OPAQUE then + elseif tpt == tps.STRUCT or tpt == tps.STRUCT_OPAQUE then local buf = { "struct " } add_typedecl_attrs(tp, buf) buf[#buf + 1] = tp:full_name_get() @@ -848,8 +848,11 @@ local get_typedecl_str = function(tp) for i, fld in ipairs(fields) do buf[#buf + 1] = " " buf[#buf + 1] = fld:name_get() - buf[#buf + 1] = ": " - buf[#buf + 1] = fld:value_get():serialize() + local val = fld:value_get() + if val then + buf[#buf + 1] = ": " + buf[#buf + 1] = val:serialize() + end if i == #fields then buf[#buf + 1] = "\n" else @@ -1479,10 +1482,24 @@ local build_classes = function() end end +local write_tsigs = function(f, tp) + f:write_h(tp:full_name_get(), 2) + + f:write_h("Signature", 3) + f:write_code(get_typedecl_str(tp)) + f:write_nl() + + f:write_h("C signature", 3) + f:write_code(tp:c_type_get() .. ";") + f:write_nl() +end + local build_alias = function(tp) local f = Writer(gen_nsp_eo(tp, "alias")) check_alias(tp) + write_tsigs(f, tp) + f:finish() end @@ -1490,6 +1507,8 @@ local build_struct = function(tp) local f = Writer(gen_nsp_eo(tp, "struct")) check_struct(tp) + write_tsigs(f, tp) + f:finish() end @@ -1497,6 +1516,8 @@ local build_enum = function(tp) local f = Writer(gen_nsp_eo(tp, "enum")) check_enum(tp) + write_tsigs(f, tp) + f:finish() end From 57ca910dbceb22c414902e9bd3d409f1668f1463 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Wed, 11 May 2016 12:30:37 +0100 Subject: [PATCH 50/50] docgen: allow multiple paths to be scanned when provided --- gendoc.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gendoc.lua b/gendoc.lua index 4abb298fee..8b8b710f75 100644 --- a/gendoc.lua +++ b/gendoc.lua @@ -1741,13 +1741,15 @@ getopt.parse { end global_opts.doc_root = path_join(opts["r"], nspace_to_path(global_opts.root_nspace)) - if not args[1] then + if #args == 0 then if not eolian.system_directory_scan() then error("failed scanning system directory") end else - if not eolian.directory_scan(args[1]) then - error("failed scanning directory: " .. args[1]) + for i, p in ipairs(args) do + if not eolian.directory_scan(p) then + error("failed scanning directory: " .. p) + end end end if not eolian.all_eot_files_parse() then