List Dep |
|
This program outputs a list of dependencies between Lua files, such as when one Lua file calls dofile
on another Lua file. (This is a CASE tool.)
comment = [[ ListDep.lua: "List module dependencies" Version 1.0 - April, 5, 2002 This program output a list of dependencies between Lua files, such as when one Lua file calls {{dofile}} on another Lua file. The output of this program is a graph which can be viewed by the aiSee program. Download aiSee at http://www.aisee.com, available for unixes and windows To see how to use it, call "lua ListDep.lua" for the usage description. Please, send any comments to Luiz Carlos Silveira <luiz@fabricadigital.com.br> Limitations: - the "parser" don't have states, so it assumes your code behaves well. For example, comment starters inside a string confuses the parser - directories are not correctly resolved, so only the module's basename is considered. In other words, the dependencies will not be correctly listed if there are two modules with the same name. - dofile's that appear anywhere in the code are considered (except in comments), including those that are in strings. ]] MODULES = {} INFO = {} function newModule(module_label, module_title) MODULES[module_label] = {label = module_label, title = module_title, dofiles={}} end function connectModules(from, to) if (MODULES[to] == nil) then INFO.HAS_MODULE_NOT_FOUND = 1 to = "MODULE_NOT_FOUND" end if (MODULES[to].label == "UNKNOWN_REF") then INFO.HAS_UNKNOWN_REF = 1 end tinsert(MODULES[from].dofiles, MODULES[to]) end function exportGraph(out_file) local hndOUT if (out_file == "-") then hndOUT = _STDOUT else hndOUT = openfile(out_file, "w") if (hndOUT == nil) then error("Cannot write to "..out_file) end end write(hndOUT, "graph: {manhattanedges: yes\n") for i, module in MODULES do local module_label = module.label local module_title = module.title -- only show MODULE_NOT_FOUD and UNKNOWN_REF if they are connected to someone if not (((module_label == "MODULE_NOT_FOUND") and (INFO.HAS_MODULE_NOT_FOUND == nil)) or ((module_label == "UNKNOWN_REF") and (INFO.HAS_UNKNOWN_REF == nil))) then write(hndOUT, 'node: {label: "'..module_label..'" title: "'..module_title..'"}\n') end end for i, module in MODULES do for i = 1, getn(module.dofiles) do local dofile = module.dofiles[i] write(hndOUT, 'edge: {sourcename: "'..module.label..'" targetname: "'..dofile.label..'"}\n') end end write(hndOUT, "}\n") closefile(hndOUT) end -- returns the 'basename' and the 'basedir' function getBases(filename) return gsub(filename, "(.*/)(.*)", "%2") or filename, gsub(filename, "(.*/)(.*)", "%1") end -- processes the modules listed in the 'hnd' file function getReferenceForModules(hnd) local filename local modules = {} local dirname local filename local basedir local basename newModule("UNKNOWN_REF", "UNKNOWN_REF") newModule("MODULE_NOT_FOUND", "MODULE_NOT_FOUND") filename = read(hnd) while (filename) do if (filename ~= '') then basename, basedir = getBases(filename) tinsert(modules, filename) newModule(basename, basename) end filename = read(hnd) end for i = 1, getn(modules) do processFile(modules[i]) end end -- processes a module function processFile(filename) local wholefile, result local hndIN local basename, basedir = getBases(filename) local execute_function_param = function (param) local n local module_name local module_basename -- detect '' and "" strings module_name, n = gsub(param, ".*([\"'])([^%1]*)%1.*", "%2") if (n == 0) then -- detect [[]] strings module_name, n = gsub(param, ".*%[%[[^%]*]%]%].*", "%1") end if (n ~= 1) then module_basename = "UNKNOWN_REF" else module_name = gsub(module_name, "%."..CONFIG.luac_extension, ".lua") module_basename = getBases(module_name) end connectModules(%basename, module_basename) end print("processing file "..filename) hndIN = openfile(filename, "r") if (hndIN == nil) then print("** error opening file "..fname) end wholefile = read(hndIN, "*a") -- remove comments (don't work if -- is inside a string) wholefile = gsub(wholefile, "%-%-[^\n\r]*", "") -- find "dofile"s for i, execute_function in CONFIG.lua_file_execute_functions do -- for beginning of the file gsub(wholefile, "^"..execute_function.."[^0-9A-Za-z_]*(%b())", execute_function_param) -- for the middle and the end of the file gsub(wholefile, "[^0-9A-Za-z_]"..execute_function.."[^0-9A-Za-z_]*(%b())", execute_function_param) end closefile(hndIN) end -- main CONFIG = { output = "-", exclude_from_path = "", luac_extension = "luac", lua_file_execute_functions = {"dofile"}, } if (not list) then print('Usage: lua <list="luafiles.list"|"-"> [output="file"|"-"]') print(' [luac_extension="ext"]') print(' [lua_file_execute_functions="{\'func1\', ..., \'funcn\'}"]') print(' ListDeps.lua"') print() print() print(' list: A file with the list of lua files to process. One file per line.') print(' Use "-" to read from standard input') print(' example: find project/lua -name "*.lua" | lua list="-" ListDeps.lua') print() print(' output: The GDL output file, or "-" to write to the standard output.') print() print(' exclude_from_path: A gsub pattern to exclude from each lua file path') print() print(' luac_extension: The lua compiled files extension used in dofiles') print() print(' lua_file_execute_functions: a table with the functions that do files') print() print() print('Note: it only works over source code files!') exit() end if (output) then CONFIG.output = output output = nil end if (luac_extension ~= nil) then CONFIG.luac_extension = luac_extension luac_extension = nil end if (lua_file_execute_functions ~= nil) then CONFIG.lua_file_execute_functions = dostring('return '..lua_file_execute_functions) lua_file_execute_functions = nil end if (list == "-") then getReferenceForModules(_STDIN) else hnd = openfile(list, "r") if (hnd == nil) then print("File "..list.." not found!") exit() end getReferenceForModules(hnd) closefile(hnd) end exportGraph(CONFIG.output)