Module:Codedoc/Procsrc

-- --| Process a Lua source file, extracting comments and function --| prototypes. --b Pedro Miller Rabinovitch  --$Id: proc_src.lua,v 1.7 2003/10/20 03:35:08 miller Exp $ --TODO: most of the work. >;) --http://lua-users.org/wiki/ExpLua require ('Dev:Util')

local ProcLua = {}

-- prefix char list local HEADER_PREF = '|b$T-' local FUNC_PREF = '%%@:Tb-' local CMT_BEGIN = '\n%s*%-%-' -- special patterns local FUNC_PTRN = { '(f)unction%s+(%a%w*)', } local FUNC_PTRN = '^%s*(f)unction%s+(%a[%w:._]*)' local PARAM_PTRN = '%s*([%w.]+)%s*%((%w+)%)%s*(.-)$' local OPTN_PARAM_PTRN = '%s*%[([%w.]+)%]%s*%((%w+)%)%s*(.-)$' local RET_PTRN = '%s*%((%w+)%)%s*(.-)$'

--% Find commentary and relevant lines --@ text (string) program code --@ prefix (string) class of characters to come after `--' --@ [special] (string) optional special patterns that should also be matched --: (table) line list function ProcLua:scan_lines( text, prefix, special ) check_types( 'string', text, prefix ) local lines = {n=0} local ptrn = CMT_BEGIN..'(['..prefix..'])%s*(.-)\n' if special == nil then text = string.gsub( text, '\n', '\n\n' ) string.gsub( '\n'..text..'\n', ptrn, function( t, str, pos )			check_types( 'string', t, str )			table.insert( lines, { t, str } )		end ) else string.gsub( text..'\n', '(.-\n)', function( line )			local a, b, c1, c2 = string.find( '\n'..line, ptrn )			if a and c1 then				if c1 == '-' then					-- concatenate to the previous line					local ll = lines[lines.n]					if ll then						ll[2] = ll[2]..' '..c2					end					a = nil				end			else				a, b, c1, c2 = string.find( line, special )			end			if a then 				table.insert( lines, { c1, c2 } )			end		end) end return lines end

--% Build function commentary structure from text --@ text (string) program code --: (table) function structure function ProcLua:get_functions( text ) -- check_types( 'string', text ) local functions = {}

-- Get function lines local lines = self:scan_lines( text, FUNC_PREF, FUNC_PTRN ) check_types( 'table', lines ) local a, b 	local curr = nil for i, v in ipairs( lines ) do		if v[1] == '%' then curr = curr or {} curr.purpose = (curr.purpose or '')..v[2]..'\n' elseif v[1] == ':' then assert( type(curr) == 'table', 'use --% before --'..v[1] ) assert( type(v[2]) == 'string', 'missing return' ) curr.returns = curr.returns or {} local ret = {} a, b, ret.type, ret.purpose = string.find( v[2], RET_PTRN ) ret.purpose = add_punctuation( ret.purpose ) table.insert( curr.returns, ret ) elseif v[1] == '@' then assert( type(curr) == 'table', 'use --% before --'..v[1] ) curr.parameters = curr.parameters or {} local param = {} a, b, param.name, param.type, param.purpose = string.find( v[2], PARAM_PTRN ) if param.purpose == nil then a, b, param.name, param.type, param.purpose = string.find( v[2], OPTN_PARAM_PTRN ) param.optional = true end assert( type(param.purpose) == 'string', 'missing param purpose' ) param.purpose = add_punctuation( param.purpose ) table.insert( curr.parameters, param ) elseif v[1] == 'f' then if curr then curr.name = v[2] curr.purpose = add_punctuation( curr.purpose ) if not self.options.proc_private then -- check if it's a pvt function (risqué) -- accept E: or Name: as public methods local _, __, class = string.find( curr.name, '(%w+)[.:]' ) if class and (class == 'E' or string.len( class) > 1) then table.insert( functions, curr ) end else table.insert( functions, curr ) end end curr = nil end end return functions end

--% Build header commentary structure from text --@ text (string) program code --: (table) header structure function ProcLua:get_header( text ) check_types( 'string', text ) local header = { authors = {}, purpose = '', todo = {}, revision = '', }

-- Get header lines local lines = self:scan_lines( text, HEADER_PREF ) check_types( 'table', lines ) for i, v in ipairs( lines ) do		if v[1] == '$' then header.revision = '$'..v[2] elseif v[1] == 'T' then table.insert( header.todo, (string.gsub( v[2], '^ODO:?%s*', '' ))) elseif v[1] == 'b' then table.insert( header.authors, v[2] ) elseif v[1] == '|' then header.purpose = header.purpose .. v[2] .. '\n' end end

return header end

--% Build comment structure from text --@ text (string) program code --@ options (table) optional options table --: (table) commentary structure function ProcLua:process( text, options ) self.options = options or {} check_types( 'string', text ) local commentary = {}

-- Get header info commentary.header = self:get_header( text )

-- Scan for function declarations

commentary.functions = self:get_functions( text )

return commentary end

return ProcLua