FANDOM


--<nowiki>
--| Process a Lua source file, extracting comments and function
--| prototypes.
--b Pedro Miller Rabinovitch <miller@inf.puc-rio.br>
--$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
local util = require ('Dev:Codedoc/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+([%w:._]*)'
local FUNC_LOCAL_PTRN = '^%s*local%s+(f)unction%s+([%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 )
    if not text then
        return
    end
	util.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 )
			util.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
                -- find a function declaration
				a, b, c1, c2 = string.find( line, special )
				-- On failure to find the function, try a 'local function'
				if not a and special == FUNC_PTRN then
				    a, b, c1, c2 = string.find( line, FUNC_LOCAL_PTRN )
				end
			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 )
	-- util.check_types( 'string', text )
	local functions = {}
 
	-- Get function lines
	local lines = self:scan_lines( text, FUNC_PREF, FUNC_PTRN )
	util.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, correct syntax : "--: (return type) return description"' )
			curr.returns = curr.returns or {}
			local ret = {}
			a, b, ret.type, ret.purpose =
			  string.find( v[2], RET_PTRN )
			ret.purpose = util.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, correct syntax : "--@ paramname (paramtype) paramdescription" ' )
			param.purpose = util.add_punctuation( param.purpose )
			table.insert( curr.parameters, param )
		elseif v[1] == 'f' then
			if curr then
				curr.name = v[2]
				curr.purpose = util.add_punctuation( curr.purpose )
 
				if self.options and 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 )
	util.check_types( 'string', text )
	local header = {
		authors = {},
		purpose = '',
		todo = {},
		revision = '',
	}
 
	-- Get header lines
	local lines = self:scan_lines( text, HEADER_PREF )
	util.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 {}
	util.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

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.