starting to track local functions. A module without a starting doc comment is considered an error. A problem with tag warnings crashing ldoc was sorted out. A table or function comment at the end of file could cause a crash.

This commit is contained in:
steve donovan 2011-06-13 15:42:42 +02:00
parent d2d7d6ac38
commit 74b52dacd1
2 changed files with 51 additions and 28 deletions

21
doc.lua
View File

@ -18,7 +18,8 @@ local known_tags = {
param = 'M', see = 'M', usage = 'M', ['return'] = 'M', field = 'M', author='M'; param = 'M', see = 'M', usage = 'M', ['return'] = 'M', field = 'M', author='M';
class = 'id', name = 'id', pragma = 'id', alias = 'id'; class = 'id', name = 'id', pragma = 'id', alias = 'id';
copyright = 'S', summary = 'S', description = 'S', release = 'S', license = 'S'; copyright = 'S', summary = 'S', description = 'S', release = 'S', license = 'S';
module = 'T', script = 'T',['function'] = 'T', table = 'T', section = 'T', type = 'T'; module = 'T', script = 'T',['function'] = 'T', lfunction = 'T',
table = 'T', section = 'T', type = 'T';
} }
known_tags._alias = {} known_tags._alias = {}
known_tags._project_level = { known_tags._project_level = {
@ -78,10 +79,8 @@ function File:_init(filename)
end end
function File:new_item(tags,line) function File:new_item(tags,line)
local item = Item(tags) local item = Item(tags,self,line)
self.items:append(item) self.items:append(item)
item.file = self
item.lineno = line
return item return item
end end
@ -92,6 +91,7 @@ function File:finish()
item:finish() item:finish()
if doc.project_level(item.type) then if doc.project_level(item.type) then
this_mod = item this_mod = item
-- if name is 'package.mod', then mod_name is 'mod' -- if name is 'package.mod', then mod_name is 'mod'
local package,mname = split_dotted_name(this_mod.name) local package,mname = split_dotted_name(this_mod.name)
if not package then if not package then
@ -168,7 +168,9 @@ function File:finish()
end end
end end
function Item:_init(tags) function Item:_init(tags,file,line)
self.file = file
self.lineno = line
self.summary = tags.summary self.summary = tags.summary
self.description = tags.description self.description = tags.description
tags.summary = nil tags.summary = nil
@ -186,14 +188,14 @@ function Item:_init(tags)
elseif ttype == TAG_ID then elseif ttype == TAG_ID then
if type(value) ~= 'string' then if type(value) ~= 'string' then
-- such tags are _not_ multiple, e.g. name -- such tags are _not_ multiple, e.g. name
self:error(tag..' cannot have multiple values') self:error("'"..tag.."' cannot have multiple values")
else else
self.tags[tag] = tools.extract_identifier(value) self.tags[tag] = tools.extract_identifier(value)
end end
elseif ttype == TAG_SINGLE then elseif ttype == TAG_SINGLE then
self.tags[tag] = value self.tags[tag] = value
else else
self:warning ('unknown tag: '..tag) self:warning ("unknown tag: '"..tag.."'")
end end
end end
end end
@ -272,6 +274,11 @@ function Item:warning(msg)
io.stderr:write(name,':',self.lineno or '?',' ',msg,'\n') io.stderr:write(name,':',self.lineno or '?',' ',msg,'\n')
end end
function Item:error(msg)
self:warning(msg)
os.exit(1)
end
-- resolving @see references. A word may be either a function in this module, -- resolving @see references. A word may be either a function in this module,
-- or a module in this package. A MOD.NAME reference is within this package. -- or a module in this package. A MOD.NAME reference is within this package.
-- Otherwise, the full qualified name must be used. -- Otherwise, the full qualified name must be used.

View File

@ -47,6 +47,7 @@ end
ModuleMap:add_kind('function','Functions','Parameters') ModuleMap:add_kind('function','Functions','Parameters')
ModuleMap:add_kind('table','Tables','Fields') ModuleMap:add_kind('table','Tables','Fields')
ModuleMap:add_kind('field','Fields') ModuleMap:add_kind('field','Fields')
ModuleMap:add_kind('lfunction','Local Functions','Parameters')
class.ProjectMap(KindMap) class.ProjectMap(KindMap)
@ -244,8 +245,10 @@ function Lua:find_module(tok,t,v)
end end
end end
function Lua:function_follows(t,v) function Lua:function_follows(t,v,tok)
return t == 'keyword' and v == 'function' local is_local = t == 'keyword' and v == 'local'
if is_local then t,v = tnext(tok) end
return t == 'keyword' and v == 'function', is_local
end end
function Lua:parse_function_header (tags,tok,toks) function Lua:parse_function_header (tags,tok,toks)
@ -256,7 +259,11 @@ end
function Lua:parse_extra (tags,tok,toks) function Lua:parse_extra (tags,tok,toks)
if tags.class == 'table' and not tags.fields then if tags.class == 'table' and not tags.fields then
local res,t,v = self:search_for_token(tok,'{','{',tok()) local res
local stat,t,v = pcall(tok)
if not stat then return nil end
print('tok',t,v)
res,t,v = self:search_for_token(tok,'{','{',tok())
if not res then return nil,t,v end if not res then return nil,t,v end
tags.formal_args = tools.get_parameters(toks,'}',function(s) tags.formal_args = tools.get_parameters(toks,'}',function(s)
return s == ',' or s == ';' return s == ',' or s == ';'
@ -303,7 +310,13 @@ local function parse_file(fname,lang)
local tok,f = lang.lexer(fname) local tok,f = lang.lexer(fname)
local toks = tools.space_skip_getter(tok) local toks = tools.space_skip_getter(tok)
function lineno () return lexer.lineno(tok) end function lineno ()
while true do
local res = lexer.lineno(tok)
if type(res) == 'number' then return res end
if res == nil then return nil end
end
end
function filename () return fname end function filename () return fname end
function F:warning (msg,kind) function F:warning (msg,kind)
@ -350,24 +363,20 @@ local function parse_file(fname,lang)
if t == 'space' then t,v = tnext(tok) end if t == 'space' then t,v = tnext(tok) end
local fun_follows,tags local fun_follows, tags, is_local
if ldoc_comment or first_comment then if ldoc_comment or first_comment then
comment = table.concat(comment) comment = table.concat(comment)
fun_follows = lang:function_follows(t,v) if not ldoc_comment and first_comment then
if fun_follows or comment:find '@' or first_comment then F:error("first comment must be a doc comment!")
end
first_comment = false
fun_follows, is_local = lang:function_follows(t,v,tok)
if fun_follows or comment:find '@'then
tags = extract_tags(comment) tags = extract_tags(comment)
-- handle the special case where the initial module comment was not
-- an ldoc style comment
if not ldoc_comment and first_comment and not tags.class then
tags.class = 'module'
ldoc_comment = true
F:warning 'Module doc comment assumed'
end
if doc.project_level(tags.class) then if doc.project_level(tags.class) then
module_found = tags.name module_found = tags.name
end end
end end
first_comment = false
end end
-- some hackery necessary to find the module() call -- some hackery necessary to find the module() call
if not module_found and ldoc_comment then if not module_found and ldoc_comment then
@ -388,14 +397,21 @@ local function parse_file(fname,lang)
-- end of a block of document comments -- end of a block of document comments
if ldoc_comment and tags then if ldoc_comment and tags then
if fun_follows then -- parse the function definition local line = t ~= nil and lineno() or 666
lang:parse_function_header(tags,tok,toks) if t ~= nil then
else if fun_follows then -- parse the function definition
lang:parse_extra(tags,tok,toks) lang:parse_function_header(tags,tok,toks)
else
lang:parse_extra(tags,tok,toks)
end
end
if tags.class == 'function' and is_local then
tags.class = 'lfunction'
end end
if tags.name then if tags.name then
F:new_item(tags,lineno()).inferred = fun_follows F:new_item(tags,line).inferred = fun_follows
end end
if not t then break end
end end
end end
if t ~= 'comment' then t,v = tok() end if t ~= 'comment' then t,v = tok() end
@ -606,7 +622,7 @@ local ldoc_dir = arg[0]:gsub('[^/\\]+$','')
if args.style == '!' then args.style = ldoc_dir end if args.style == '!' then args.style = ldoc_dir end
if args.template == '!' then args.template = ldoc_dir end if args.template == '!' then args.template = ldoc_dir end
local module_template,err = utils.readfile (path.join(args.style,templ)) local module_template,err = utils.readfile (path.join(args.template,templ))
if not module_template then quit(err) end if not module_template then quit(err) end