Advertisement
Guest User

CodeMetrics 1.1

a guest
Aug 4th, 2016
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.89 KB | None | 0 0
  1. --[[
  2.  
  3.   CodeMetrics 1.1
  4.   Written by George Thomas (GeorgeEpicGen)
  5.  
  6.   Changelog:
  7.   1.1   Renamed 'script#get_coroutine_count' tok
  8.         'script#get_subroutine_count' to avoid confusion
  9.         with Lua's 'coroutine' API.
  10.  
  11.   Look, I know the code is not the neatest you've ever seen,
  12.   but it works, and it works well. If you seriously hate the
  13.   code, feel free to modify and redistribute it as you wish,
  14.   but make sure you give me at least SOME credit for, you know,
  15.   actually writing the damn thing!
  16.  
  17.   In all seriousness, please, modify and redistribute this
  18.   file as much as you want. I would really appreciate it if
  19.   you be decent enough as to give me a little credit for
  20.   the base code, but make sure you credit yourself, too!
  21.  
  22. --]]
  23.  
  24. VERSION = 1.1
  25.  
  26. local CMD_HELP = "\n [ CodeMetrics "..VERSION.." ]\n\n"
  27.   .. "CodeMetrics is a lightweight API used to calculate\n"
  28.   .. "Lua script properties such as line count and code \n"
  29.   .. "complexity.                                       \n"
  30.   .. "                                                  \n"
  31.   .. "To use CodeMetrics from the command line, simply  \n"
  32.   .. "execute                                           \n"
  33.   .. "                                                  \n"
  34.   .. "\t\tCodeMetrics [\"path_to_script\"]              \n"
  35.   .. "                                                  \n"
  36.   .. "and the script's properties will be printed to the\n"
  37.   .. "shell.                                            \n"
  38.   .. "                                                  \n"
  39.   .. "To use CodeMetrics from another script, write     \n"
  40.   .. "                                                  \n"
  41.   .. "\t\tos.loadAPI(\"CodeMetrics\")                   \n"
  42.   .. "\t\tmy_script = CodeMetrics.new(path)             \n"
  43.   .. "                                                  \n"
  44.   .. "and then invoke the desired functions:            \n"
  45.   .. "                                                  \n"
  46.   .. "\t\tmy_script:get_character_count()               \n"
  47.   .. "\t\tmy_script:get_subroutine_count()               \n"
  48.   .. "\t\tmy_script:get_cyclo_complexity()              \n"
  49.   .. "\t\tmy_script:get_function_count()                \n"
  50.   .. "\t\tmy_script:get_line_count()                    \n"
  51.  
  52. function new(path)  
  53.   self = setmetatable({
  54.    
  55.     get_character_count = function(self)
  56.       return self["chars"]
  57.     end,
  58.    
  59.     get_subroutine_count = function(self)
  60.       local tokens = self["tokens"]
  61.       local subroutineCount = 0
  62.       for k,v in pairs(tokens) do
  63.         if (v == "do"
  64.          or v == "else"
  65.          or v == "function"
  66.          or v == "repeat"
  67.          or v == "then") then
  68.           subroutineCount = subroutineCount + 1
  69.         end
  70.       end
  71.       return subroutineCount
  72.     end,
  73.    
  74.     get_count = function(self, token)
  75.       return self["tokens"]:get_occurences(token)
  76.     end,
  77.    
  78.     get_cyclo_complexity = function(self)
  79.       local tokens = self["tokens"]
  80.       local complexity = 1
  81.       local depth = 0
  82.       for i=1, #tokens do
  83.         local ppv = tokens[i-2]
  84.         local pv = tokens[i-1]
  85.         local v = tokens[i]
  86.         local nv = tokens[i+1]
  87.         if (v == "do"
  88.          or v == "function"
  89.          or v == "repeat"
  90.          or v == "then") then
  91.           depth = depth + 1
  92.           complexity = complexity + (depth*2)
  93.         elseif (v == "}"
  94.          or v == "return"
  95.          or v == "until") then
  96.           depth = depth - 1
  97.         end
  98.       end
  99.       return complexity
  100.     end,
  101.    
  102.     get_function_count = function(self)
  103.       return self["funcs"]
  104.     end,
  105.    
  106.     get_line_count = function(self)
  107.       return self["lines"]
  108.     end,
  109.    
  110.     r = function(self)
  111.       local p = self["path"]
  112.      
  113.       if ((not fs.exists(p))
  114.        or (fs.isDir(p))) then
  115.         error("File '" .. p .. "' is a "
  116.          .. "directory or does not exist!")
  117.       end
  118.      
  119.       local f = fs.open(p, "r")
  120.       local cont = f.readAll()
  121.       f.close()
  122.      
  123.       self["cont"] = cont
  124.       self:parse()
  125.       return cont
  126.     end,
  127.    
  128.     parse = function(self)
  129.       local parsed = {
  130.         set_tokens = function(self, tokens)
  131.           self["tokens"] = tokens
  132.         end,
  133.        
  134.         get_tokens = function(self)
  135.           return self["tokens"]
  136.         end,
  137.       }
  138.      
  139.       local cont = self:get_contents()
  140.       local chars, subts, funcs, lns = 0,0,0,1
  141.      
  142.       cont = cont:gsub("%-%-.\n", "")
  143.       cont = cont:gsub("--%[%[.--]]", "")
  144.       cont = cont:gsub("\".\"", "")
  145.       chars = #cont
  146.      
  147.       cont = cont:gsub("elseif", "elif")
  148.      
  149.       local tokens = {
  150.           add = function(self, tok)
  151.               self[#self + 1] = tok
  152.             end,
  153.          
  154.           get_occurences = function(self, token)
  155.               local occr = 0
  156.               for i=1,#self do
  157.                 if (self[i] == token) then
  158.                   occr = occr + 1
  159.                 end
  160.               end
  161.              
  162.               return occr
  163.             end
  164.         }
  165.      
  166.       local token = ""
  167.       for i=1, #cont do
  168.         local c = cont:sub(i, i)
  169.         if (token == "do"
  170.          or token == "else"
  171.          or token == "repeat"
  172.          or token == "then") then
  173.           subts = subts + 1
  174.           tokens:add(token)
  175.           token = ""
  176.         elseif (token == "function") then
  177.           subts = subts + 1
  178.           funcs = funcs + 1
  179.           tokens:add(token)
  180.           token = ""
  181.         elseif (token == "elif") then
  182.           tokens:add("elseif")
  183.           token = ""
  184.         elseif (token == "and"
  185.          or token == "break"
  186.          or token == "else"
  187.          or token == "end"
  188.          or token == "false"
  189.          or token == "for"
  190.          or token == "if"
  191.          or token == "in"
  192.          or token == "local"
  193.          or token == "nil"
  194.          or token == "not"
  195.          or token == "or"
  196.          or token == "return"
  197.          or token == "true"
  198.          or token == "while") then
  199.           tokens:add(token)
  200.           token = ""
  201.         else
  202.           if (c == "{" or c == "}"
  203.            or c == "(" or c == ")"
  204.            or c == "[" or c == "]") then
  205.             tokens:add(c)
  206.             token = ""
  207.           elseif (c == "\f"
  208.            or c == "\n"
  209.            or c == "\v") then
  210.            lns = lns + 1
  211.            token = ""
  212.           elseif (c == "\f"
  213.            or c == "\t"
  214.            or c == " ") then
  215.             token = ""
  216.           else
  217.             token = token .. c
  218.           end
  219.         end
  220.       end
  221.      
  222.       cont = cont:gsub("elif", "elseif")
  223.      
  224.       self["chars"] = chars
  225.       self["subts"] = subts
  226.       self["funcs"] = funcs
  227.       self["lines"] = lns
  228.       self["tokens"] = tokens
  229.      
  230.       tokens.add = nil
  231.       parsed:set_tokens(tokens)
  232.       return parsed
  233.     end,
  234.    
  235.     get_contents = function(self)
  236.       return self["cont"]
  237.     end,
  238.    
  239.     get_path = function(self)
  240.       return self["path"]
  241.     end,
  242.    
  243.   }, {
  244.    
  245.     __tostring = function(self)
  246.       local path = self:get_path()
  247.      
  248.       local chars = self:get_character_count()
  249.       local subts = self:get_subroutine_count()
  250.       local cyclo = self:get_cyclo_complexity()
  251.       local funcs = self:get_function_count()
  252.       local lns = self:get_line_count()
  253.      
  254.       return "Script '" .. path .. "'\n"
  255.         .. "\tCharacters: " .. chars .. "\n"
  256.         .. "\tSubroutines: " .. subts .. "\n"
  257.         .. "\tFunctions: " .. funcs .. "\n"
  258.         .. "\tLines: " .. lns .. "\n"
  259.         .. "\tComplexity: " .. cyclo .. "\n"
  260.     end
  261.    
  262.   })
  263.  
  264.   self["path"] = path
  265.   self:r()
  266.   return self
  267. end
  268.  
  269. function main(args)
  270.   if (args == nil
  271.    or #args == 0) then
  272.     return
  273.   end
  274.  
  275.   local scr = new(args[1])
  276.   if (#args == 1) then
  277.     if (args[1] == "-help") then
  278.       textutils.pagedPrint(CMD_HELP)
  279.     else
  280.       print(scr)
  281.     end
  282.   end
  283. end
  284.  
  285. main({...})
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement