modules returning a single function are supported, see tests/styles/func.lua. Parameters may have subfields, see tests/styles/subparams.lua
This commit is contained in:
parent
717eac46e5
commit
4bc48dafc3
204
ldoc/doc.lua
204
ldoc/doc.lua
|
@ -493,6 +493,8 @@ local function read_del (tags,name)
|
|||
return ret
|
||||
end
|
||||
|
||||
local build_arg_list, split_iden -- forward declaration
|
||||
|
||||
|
||||
function Item:finish()
|
||||
local tags = self.tags
|
||||
|
@ -538,74 +540,58 @@ function Item:finish()
|
|||
self.modifiers.field = self.modifiers.param
|
||||
end
|
||||
end
|
||||
local names, comments = List(), List()
|
||||
local param_names, comments = List(), List()
|
||||
if params then
|
||||
for line in params:iter() do
|
||||
local name, comment = line :match('%s*([%w_%.:]+)(.*)')
|
||||
local name, comment = line:match('%s*([%w_%.:]+)(.*)')
|
||||
if not name then
|
||||
self:error("bad param name format '"..line.."'. Are you missing a parameter name?")
|
||||
end
|
||||
names:append(name)
|
||||
param_names:append(name)
|
||||
comments:append(comment)
|
||||
end
|
||||
end
|
||||
self.modifiers['return'] = self.modifiers['return'] or List()
|
||||
self.modifiers[field] = self.modifiers[field] or List()
|
||||
-- not all arguments may be commented: we use the formal arguments
|
||||
-- if available as the authoritative list, and warn if there's an inconsistency.
|
||||
if self.formal_args then
|
||||
local fargs = self.formal_args
|
||||
if not self.ret and fargs.return_comment then
|
||||
local retc = fargs.return_comment
|
||||
local type,rest = retc:match '([^:]+):(.*)'
|
||||
if type then
|
||||
self.modifiers['return']:append{type=type}
|
||||
retc = rest
|
||||
-- we use the formal arguments (if available) as the authoritative list.
|
||||
-- If there are both params and formal args, then they must match;
|
||||
-- (A formal argument of ... may match any number of params at the end, however.)
|
||||
-- If there are formal args and no params, we see if the args have any suitable comments.
|
||||
-- Params may have subfields.
|
||||
local fargs, formal = self.formal_args
|
||||
if fargs then
|
||||
if #param_names == 0 then
|
||||
--docs may be embedded in argument comments; in either case, use formal arg names
|
||||
formal = List()
|
||||
if fargs.return_comment then
|
||||
local retc = self:parse_argument_comment(fargs.return_comment,'return')
|
||||
self.ret = List{retc}
|
||||
end
|
||||
self.ret = List{retc}
|
||||
end
|
||||
if #fargs ~= 0 then
|
||||
local pnames, pcomments = names, comments
|
||||
names, comments = List(),List()
|
||||
for i, name in ipairs(fargs) do
|
||||
formal:append(name)
|
||||
comments:append(self:parse_argument_comment(fargs.comments[name],self.parameter))
|
||||
end
|
||||
elseif #fargs > 0 then
|
||||
local varargs = fargs[#fargs] == '...'
|
||||
for i,name in ipairs(fargs) do
|
||||
if params then -- explicit set of param tags
|
||||
if pnames[i] ~= name and not varargs then
|
||||
if pnames[i] then
|
||||
self:warning("param and formal argument name mismatch: "..quote(name).." "..quote(pnames[i]))
|
||||
else
|
||||
self:warning("undocumented formal argument: "..quote(name))
|
||||
if varargs then table.remove(fargs) end
|
||||
local k = 0
|
||||
for _,pname in ipairs(param_names) do
|
||||
local _,field = split_iden(pname)
|
||||
if not field then
|
||||
k = k + 1
|
||||
if k > #fargs then
|
||||
if not varargs then
|
||||
self:warning("extra param with no formal argument: "..quote(pname))
|
||||
end
|
||||
elseif varargs then
|
||||
name = pnames[i]
|
||||
elseif pname ~= fargs[k] then
|
||||
self:warning("param and formal argument name mismatch: "..quote(pname).." "..quote(fargs[k]))
|
||||
end
|
||||
end
|
||||
names:append(name)
|
||||
local comment = pcomments[i]
|
||||
if not comment then
|
||||
-- ldoc allows comments in the formal arg list to be used, if they aren't specified with @param
|
||||
-- Further, these comments may start with a type followed by a colon, and are then equivalent
|
||||
-- to a @tparam
|
||||
comment = fargs.comments[name]
|
||||
if comment then
|
||||
comment = comment:gsub('^%-+%s*','')
|
||||
local type,rest = comment:match '([^:]+):(.*)'
|
||||
if type then
|
||||
self.modifiers[field]:append {type = type}
|
||||
comment = rest
|
||||
end
|
||||
end
|
||||
end
|
||||
comments:append (comment or '')
|
||||
end
|
||||
-- A formal argument of ... may match any number of params, however.
|
||||
if #pnames > #fargs then
|
||||
for i = #fargs+1,#pnames do
|
||||
if not varargs then
|
||||
self:warning("extra param with no formal argument: "..quote(pnames[i]))
|
||||
else
|
||||
names:append(pnames[i])
|
||||
comments:append(pcomments[i] or '')
|
||||
if k < #fargs then
|
||||
for i = k+1,#fargs do
|
||||
if fargs[i] ~= '...' then
|
||||
self:warning("undocumented formal argument: "..quote(fargs[i]))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -615,38 +601,84 @@ function Item:finish()
|
|||
-- the comments are associated with each parameter by
|
||||
-- adding name-value pairs to the params list (this is
|
||||
-- also done for any associated modifiers)
|
||||
self.params = names
|
||||
-- (At this point we patch up any subparameter references)
|
||||
local pmods = self.modifiers[field]
|
||||
for i,name in ipairs(self.params) do
|
||||
self.params[name] = comments[i]
|
||||
local params, fields = List()
|
||||
local original_names = formal and formal or param_names
|
||||
local names = List()
|
||||
self.subparams = {}
|
||||
for i,name in ipairs(original_names) do
|
||||
local pname,field = split_iden(name)
|
||||
if field then
|
||||
if not fields then
|
||||
fields = List()
|
||||
self.subparams[pname] = fields
|
||||
end
|
||||
fields:append(name)
|
||||
else
|
||||
names:append(name)
|
||||
params:append(name)
|
||||
fields = nil
|
||||
end
|
||||
|
||||
params[name] = comments[i]
|
||||
if pmods then
|
||||
pmods[name] = pmods[i]
|
||||
end
|
||||
end
|
||||
|
||||
-- build up the string representation of the argument list,
|
||||
-- using any opt and optchain modifiers if present.
|
||||
-- For instance, '(a [, b])' if b is marked as optional
|
||||
-- with @param[opt] b
|
||||
local buffer, npending = { }, 0
|
||||
local function acc(x) table.insert(buffer, x) end
|
||||
for i = 1, #names do
|
||||
local m = pmods and pmods[i]
|
||||
if m then
|
||||
if not m.optchain then
|
||||
acc ((']'):rep(npending))
|
||||
npending=0
|
||||
end
|
||||
if m.opt or m.optchain then acc(' ['); npending=npending+1 end
|
||||
end
|
||||
if i>1 then acc (', ') end
|
||||
acc(names[i])
|
||||
end
|
||||
acc ((']'):rep(npending))
|
||||
self.args = '('..table.concat(buffer)..')'
|
||||
self.params = params
|
||||
self.args = build_arg_list (names,pmods)
|
||||
end
|
||||
end
|
||||
|
||||
-- ldoc allows comments in the formal arg list to be used, if they aren't specified with @param
|
||||
-- Further, these comments may start with a type followed by a colon, and are then equivalent
|
||||
-- to a @tparam
|
||||
function Item:parse_argument_comment (comment,field)
|
||||
if comment then
|
||||
comment = comment:gsub('^%-+%s*','')
|
||||
local type,rest = comment:match '([^:]+):(.*)'
|
||||
if type then
|
||||
self.modifiers[field]:append {type = type}
|
||||
comment = rest
|
||||
end
|
||||
end
|
||||
return comment or ''
|
||||
end
|
||||
|
||||
function split_iden (name)
|
||||
if name == '...' then return name end
|
||||
local pname,field = name:match('(.-)%.(.+)')
|
||||
if not pname then
|
||||
return name
|
||||
else
|
||||
return pname,field
|
||||
end
|
||||
end
|
||||
|
||||
function build_arg_list (names,pmods)
|
||||
-- build up the string representation of the argument list,
|
||||
-- using any opt and optchain modifiers if present.
|
||||
-- For instance, '(a [, b])' if b is marked as optional
|
||||
-- with @param[opt] b
|
||||
local buffer, npending = { }, 0
|
||||
local function acc(x) table.insert(buffer, x) end
|
||||
for i = 1, #names do
|
||||
local m = pmods and pmods[i]
|
||||
if m then
|
||||
if not m.optchain then
|
||||
acc ((']'):rep(npending))
|
||||
npending=0
|
||||
end
|
||||
if m.opt or m.optchain then acc(' ['); npending=npending+1 end
|
||||
end
|
||||
if i>1 then acc (', ') end
|
||||
acc(names[i])
|
||||
end
|
||||
acc ((']'):rep(npending))
|
||||
return '('..table.concat(buffer)..')'
|
||||
end
|
||||
|
||||
function Item:type_of_param(p)
|
||||
local mods = self.modifiers[self.parameter]
|
||||
if not mods then return '' end
|
||||
|
@ -659,6 +691,23 @@ function Item:type_of_ret(idx)
|
|||
return rparam and rparam.type or ''
|
||||
end
|
||||
|
||||
function Item:subparam(p)
|
||||
if self.subparams[p] then
|
||||
return self.subparams[p],p
|
||||
else
|
||||
return {p},nil
|
||||
end
|
||||
end
|
||||
|
||||
function Item:display_name_of(p)
|
||||
local pname,field = split_iden(p)
|
||||
if field then
|
||||
return field
|
||||
else
|
||||
return pname
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Item:warning(msg)
|
||||
local file = self.file and self.file.filename
|
||||
|
@ -675,6 +724,9 @@ end
|
|||
|
||||
Module.warning, Module.error = Item.warning, Item.error
|
||||
|
||||
|
||||
-------- Resolving References -----------------
|
||||
|
||||
function Module:hunt_for_reference (packmod, modules)
|
||||
local mod_ref
|
||||
local package = self.package or ''
|
||||
|
|
|
@ -128,6 +128,10 @@ function html.generate_output(ldoc, args, project)
|
|||
end))
|
||||
end
|
||||
|
||||
function ldoc.is_list (t)
|
||||
return type(t) == 'table' and t.append
|
||||
end
|
||||
|
||||
function ldoc.typename (tp)
|
||||
if not tp or tp == '' then return '' end
|
||||
local optional
|
||||
|
@ -170,6 +174,7 @@ function html.generate_output(ldoc, args, project)
|
|||
ldoc.output = args.output
|
||||
ldoc.ipairs = ipairs
|
||||
ldoc.pairs = pairs
|
||||
ldoc.print = print
|
||||
|
||||
-- in single mode there is one module and the 'index' is the
|
||||
-- documentation for that module.
|
||||
|
|
|
@ -157,13 +157,23 @@ return [==[
|
|||
# if show_parms and item.params and #item.params > 0 then
|
||||
<h3>$(module.kinds:type_of(item).subnames):</h3>
|
||||
<ul>
|
||||
# for p in iter(item.params) do
|
||||
<li><span class="parameter">$(p)</span>
|
||||
# local tp = ldoc.typename(item:type_of_param(p))
|
||||
# if tp ~= '' then
|
||||
<span class="types">$(tp)</span>
|
||||
# for parm in iter(item.params) do
|
||||
# local param,sublist = item:subparam(parm)
|
||||
# if sublist then
|
||||
<li><span class="parameter">$(sublist)</span>$(M(item.params[sublist],item))
|
||||
<ul>
|
||||
# end
|
||||
# for p in iter(param) do
|
||||
# local name,tp = item:display_name_of(p), ldoc.typename(item:type_of_param(p))
|
||||
<li><span class="parameter">$(name)</span>
|
||||
# if tp ~= '' then
|
||||
<span class="types">$(tp)</span>
|
||||
# end
|
||||
$(M(item.params[p],item))</li>
|
||||
# end
|
||||
# if sublist then
|
||||
</li></ul>
|
||||
# end
|
||||
$(M(item.params[p],item))</li>
|
||||
# end -- for
|
||||
</ul>
|
||||
# end -- if params
|
||||
|
|
|
@ -253,8 +253,24 @@ local function parse_file(fname, lang, package, args)
|
|||
end
|
||||
if item_follows or comment:find '@' or comment:find ': ' then
|
||||
tags = extract_tags(comment,args)
|
||||
-- explicitly named @module (which is recommended)
|
||||
if doc.project_level(tags.class) then
|
||||
module_found = tags.name
|
||||
-- might be a module returning a single function!
|
||||
if tags.param or tags['return'] then
|
||||
local parms, ret, summ = tags.param, tags['return'],tags.summary
|
||||
tags.param = nil
|
||||
tags['return'] = nil
|
||||
tags.summary = nil
|
||||
add_module(tags,tags.name,false)
|
||||
tags = {
|
||||
summary = summ,
|
||||
name = 'returns...',
|
||||
class = 'function',
|
||||
['return'] = ret,
|
||||
param = parms
|
||||
}
|
||||
end
|
||||
end
|
||||
doc.expand_annotation_item(tags,current_item)
|
||||
-- if the item has an explicit name or defined meaning
|
||||
|
|
|
@ -8,11 +8,15 @@
|
|||
-- @copyright InfoReich 2013
|
||||
|
||||
--- a function with typed args.
|
||||
-- Note the the standard tparam aliases
|
||||
-- Note the the standard tparam aliases, and how the 'opt' and 'optchain'
|
||||
-- modifiers may also be used. If the Lua function has varargs, then
|
||||
-- you may document an indefinite number of extra arguments!
|
||||
-- @string name person's name
|
||||
-- @int age
|
||||
-- @string[opt] calender optional calendar
|
||||
-- @int[optchain] offset optional offset
|
||||
-- @treturn string
|
||||
function one (name,age)
|
||||
function one (name,age,...)
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
------------
|
||||
-- Get length of string.
|
||||
-- A (silly) module which returns a single function
|
||||
--
|
||||
-- @module func
|
||||
-- @string some text
|
||||
-- @param opts multibyte encoding options
|
||||
-- @string opts.charset encoding used
|
||||
-- @bool opts.strict be very pedantic
|
||||
-- @bool verbose tell the world about everything
|
||||
-- @return its length
|
||||
return function(s,opts,verbose)
|
||||
return #s
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
------------
|
||||
-- Parameters may have named subfields, if they are tables.
|
||||
--
|
||||
-- @module subparams
|
||||
module(...)
|
||||
|
||||
-------
|
||||
-- A function with subfield arguments.
|
||||
-- @param s string
|
||||
-- @param opts multibyte encoding options
|
||||
-- @param opts.charset string
|
||||
-- @param opts.strict bool
|
||||
-- @param verbose bool
|
||||
-- @return its length
|
||||
function with_options (s,opts,verbose)
|
||||
end
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
------------
|
||||
-- Classic Lua 5.1 module,
|
||||
-- Classic Lua 5.1 module.
|
||||
-- Description here
|
||||
----
|
||||
|
||||
|
|
Loading…
Reference in New Issue