From 8f956bf444cb7e4f2c491b44bea841f4e6c96cac Mon Sep 17 00:00:00 2001 From: Jon Michael Aanes Date: Mon, 3 Apr 2017 11:55:49 +0200 Subject: [PATCH] Moved function formatting into own file. --- function.lua | 177 +++++++++++++++++++++++++++++ pretty.lua | 183 +++--------------------------- test/test_function.lua | 249 +++++++++++++++++++++++++++++++++++++++++ test/test_pretty.lua | 226 +------------------------------------ 4 files changed, 445 insertions(+), 390 deletions(-) create mode 100644 function.lua create mode 100644 test/test_function.lua diff --git a/function.lua b/function.lua new file mode 100644 index 0000000..46e6677 --- /dev/null +++ b/function.lua @@ -0,0 +1,177 @@ + +-- Import + +local LIBRARY +do + local thispath = ... and select('1', ...):match('.+%.') or '' + local was_loaded, library = pcall(require, thispath..'library') + LIBRARY = was_loaded and library or {} +end + +-- Constants + + +-------------------------------------------------------------------------------- +-- Util + +local function get_function_info (f) + -- NOTE: Works best in LuaJIT or Lua 5.2+ + + -- Regarding get-info: + -- * No need to includ 'f'. Function is already known + -- * No need to include 'L' (active lines) option. Ignored + -- * No need to include 'n' (name and namewhat). Won't work. + local info = debug.getinfo(f, 'Su') + info.params = {} + info.ups = {} + info.env = debug.getfenv and debug.getfenv(f) + info.builtin = info.source == '=[C]' + for i = 1, info.nparams or 0 do info.params[i] = debug.getlocal(f, i) end + if info.isvararg or not info.nparams then info.params[#info.params+1] = '...' end + -- Get upvalues + for i = 1, info.nups do + local k, v = debug.getupvalue(f, i) + if k == '_ENV' and not debug.getfenv then + info.env = v + else + info.ups[k] = v + end + end + + if info.source:sub(1,1) == '=' then info.defined_how = 'C' + elseif info.source:sub(1,1) == '@' then info.defined_how = 'file' + else info.defined_how = 'string' + end + + if info.builtin and LIBRARY[f] then + info.name = LIBRARY[f].name + info.params[1] = LIBRARY[f].para + info.doc = LIBRARY[f].docs + end + + return info +end + +local function get_line_index (str, line_nr) + local index = 0 + for _ = 2, line_nr do + index = str:find('\n', index, true) + if not index then return #str end + index = index + 1 + end + return index +end + +local function get_full_function_str (str, start_line, end_line) + local start_line_index = get_line_index(str, start_line) + local end_line_index = get_line_index(str, end_line + 1) + + local matched_function = str:sub(start_line_index, end_line_index):match('function.+end') + return matched_function +end + +local function width_of_strings_in_l (l, start_i, end_i) + -- FIXME: Copy of the one in pretty.lua + local width = 0 + for i = start_i or 1, (end_i or #l) do + width = width + #l[i] + end + return width +end + +-------------------------------------------------------------------------------- + +return function (value, options, depth, l, format_value) + local info = get_function_info(value) + + if info.defined_how == 'string' then + -- Function was defined as a string. + l[#l+1] = get_full_function_str(info.source, info.linedefined, info.lastlinedefined) + return; + end + + -- Include function modifier, and alignment info. + l[#l+1] = info.builtin and 'builtin ' or '' + l[#l+1] = { #l[#l], 'func_mod'} + + -- Build rest of function signature + l[#l+1] = 'function (' + local top_before = #l + for _, param in ipairs(info.params) do l[#l+1], l[#l+2] = param, ', ' end + if l[#l] == ', ' then l[#l] = nil end + l[#l+1] = ')' + l[#l+1] = { width_of_strings_in_l(l, top_before), 'func_def' } + + -- Cleanup and finish + if not options.more_function_info or depth ~= 0 then + l[#l+1] = ' ... end' + elseif options._all_function_info then + -- NOTE: This is for testing/debugging/experimentation purposes. + + local file = io.open(info.short_src, 'r') + local function_str = get_full_function_str(file:read('*all'), info.linedefined, info.lastlinedefined) + file:close() + + l[#l+1] = '\n\t--[[ Function Body\n\t' + l[#l+1] = function_str + l[#l+1] = '\n\t--]]' + + l[#l+1] = '\n\t--[[\n\tNative repr:' + l[#l+1] = tostring(value) + l[#l+1] = '\n\t' + format_value(info, options, depth + 1, l) + l[#l+1] = '--]]' + else + -- More info! -- + + -- Name + if info.name then + l[#l+1] = '\n' + l[#l+1] = options.indent + l[#l+1] = '-- ' + l[#l+1] = info.name + end + + -- Doc + if info.doc then + for doc_line in info.doc:gmatch('[^\n]+') do + l[#l+1] = '\n' + l[#l+1] = options.indent + l[#l+1] = '-- ' + + l[#l+1] = doc_line + end + end + + -- source + if not info.builtin then + l[#l+1] = '\n' + l[#l+1] = options.indent + l[#l+1] = '-- source_file: \'' + l[#l+1] = info.short_src + l[#l+1] = '\' [Line' + if info.linedefined == info.lastlinedefined then + l[#l+1] = ': ' + l[#l+1] = tostring(info.linedefined) + else + l[#l+1] = 's: ' + l[#l+1] = tostring(info.linedefined) + l[#l+1] = ' - ' + l[#l+1] = tostring(info.lastlinedefined) + end + l[#l+1] = ']' + end + + -- upvalues + if info.nups > 0 and not info.builtin then + l[#l+1] = '\n' + l[#l+1] = options.indent + l[#l+1] = '-- up_values: ' + format_value(info.ups, options, depth + 1, l) + end + + l[#l+1] = '\n\n' + l[#l+1] = options.indent + l[#l+1] = '...\nend' + end +end diff --git a/pretty.lua b/pretty.lua index 40e0a8b..0de84c6 100644 --- a/pretty.lua +++ b/pretty.lua @@ -2,18 +2,20 @@ -- Ensure loading library, if it exists, no matter where pretty.lua was loaded from. -- Load the library component -local LIBRARY, format_number, analyze_structure, TABLE_TYPE +local format_number, format_function, analyze_structure, TABLE_TYPE do local thispath = ... and select('1', ...):match('.+%.') or '' - -- Load library info - local was_loaded, library = pcall(require, thispath..'library') - LIBRARY = was_loaded and library or {} + -- Load number and function formatting + format_number = select(2, pcall(require, thispath..'number')) + format_function = select(2, pcall(require, thispath..'function')) - -- Load number formatting - was_loaded, format_number = pcall(require, thispath..'number') + -- Load other stuff + local was_loaded was_loaded, analyze_structure = pcall(require, thispath..'analyze_structure') - was_loaded, TABLE_TYPE = pcall(require, thispath..'table_type') + assert(was_loaded) + was_loaded, TABLE_TYPE = pcall(require, thispath..'table_type') + assert(was_loaded) end -- @@ -192,62 +194,6 @@ local function escape_string (str) return table.concat(l, '') end -local function get_function_info (f) - -- NOTE: Works best in LuaJIT or Lua 5.2+ - - -- Regarding get-info: - -- * No need to includ 'f'. Function is already known - -- * No need to include 'L' (active lines) option. Ignored - -- * No need to include 'n' (name and namewhat). Won't work. - local info = debug.getinfo(f, 'Su') - info.params = {} - info.ups = {} - info.env = debug.getfenv and debug.getfenv(f) - info.builtin = info.source == '=[C]' - for i = 1, info.nparams or 0 do info.params[i] = debug.getlocal(f, i) end - if info.isvararg or not info.nparams then info.params[#info.params+1] = '...' end - -- Get upvalues - for i = 1, info.nups do - local k, v = debug.getupvalue(f, i) - if k == '_ENV' and not debug.getfenv then - info.env = v - else - info.ups[k] = v - end - end - - if info.source:sub(1,1) == '=' then info.defined_how = 'C' - elseif info.source:sub(1,1) == '@' then info.defined_how = 'file' - else info.defined_how = 'string' - end - - if info.builtin and LIBRARY[f] then - info.name = LIBRARY[f].name - info.params[1] = LIBRARY[f].para - info.doc = LIBRARY[f].docs - end - - return info -end - -local function get_line_index (str, line_nr) - local index = 0 - for _ = 2, line_nr do - index = str:find('\n', index, true) - if not index then return #str end - index = index + 1 - end - return index -end - -local function get_full_function_str (str, start_line, end_line) - local start_line_index = get_line_index(str, start_line) - local end_line_index = get_line_index(str, end_line + 1) - - local matched_function = str:sub(start_line_index, end_line_index):match('function.+end') - return matched_function -end - local function width_of_strings_in_l (l, start_i, end_i) local width = 0 for i = start_i or 1, (end_i or #l) do @@ -511,13 +457,9 @@ local function format_string (str, options, depth, l) end if not format_number then - function format_number (value, options, depth, l) - local shorthand = options.math_shorthand - if value ~= value then l[#l+1] = shorthand and 'nan' or '0/0' - elseif value == 1/0 then l[#l+1] = shorthand and 'inf' or '1/0' - elseif value == -1/0 then l[#l+1] = shorthand and '-inf' or '-1/0' - else l[#l+1] = tostring(value) - end + -- Very simple number formatting, if number.lua is not available. + format_number = function (value, _, _, l) + l[#l+1] = tostring(value) end end @@ -531,101 +473,10 @@ local function format_primitive (value, options, depth, l) l[#l+1] = tostring(value) end -local function format_string_defined_function (value, options, depth, l) - local info = get_function_info(value) - l[#l+1] = get_full_function_str(info.source, info.linedefined, info.lastlinedefined) -end - -local function format_function (value, options, depth, l) - local info = get_function_info(value) - - if info.defined_how == 'string' then - return format_string_defined_function(value, options, depth, l) - end - - -- Include function modifier, and alignment info. - l[#l+1] = info.builtin and 'builtin ' or '' - l[#l+1] = { #l[#l], 'func_mod'} - - -- Build rest of function signature - l[#l+1] = 'function (' - local top_before = #l - for _, param in ipairs(info.params) do l[#l+1], l[#l+2] = param, ', ' end - if l[#l] == ', ' then l[#l] = nil end - l[#l+1] = ')' - l[#l+1] = { width_of_strings_in_l(l, top_before), 'func_def' } - - -- Cleanup and finish - if not options.more_function_info or depth ~= 0 then - l[#l+1] = ' ... end' - elseif options._all_function_info then - -- NOTE: This is for testing/debugging/experimentation purposes. - - local file = io.open(info.short_src, 'r') - local function_str = get_full_function_str(file:read('*all'), info.linedefined, info.lastlinedefined) - file:close() - - l[#l+1] = '\n\t--[[ Function Body\n\t' - l[#l+1] = function_str - l[#l+1] = '\n\t--]]' - - l[#l+1] = '\n\t--[[\n\tNative repr:' - l[#l+1] = tostring(value) - l[#l+1] = '\n\t' - format_value(info, options, depth + 1, l) - l[#l+1] = '--]]' - else - -- More info! -- - - -- Name - if info.name then - l[#l+1] = '\n' - l[#l+1] = options.indent - l[#l+1] = '-- ' - l[#l+1] = info.name - end - - -- Doc - if info.doc then - for doc_line in info.doc:gmatch('[^\n]+') do - l[#l+1] = '\n' - l[#l+1] = options.indent - l[#l+1] = '-- ' - - l[#l+1] = doc_line - end - end - - -- source - if not info.builtin then - l[#l+1] = '\n' - l[#l+1] = options.indent - l[#l+1] = '-- source_file: \'' - l[#l+1] = info.short_src - l[#l+1] = '\' [Line' - if info.linedefined == info.lastlinedefined then - l[#l+1] = ': ' - l[#l+1] = tostring(info.linedefined) - else - l[#l+1] = 's: ' - l[#l+1] = tostring(info.linedefined) - l[#l+1] = ' - ' - l[#l+1] = tostring(info.lastlinedefined) - end - l[#l+1] = ']' - end - - -- upvalues - if info.nups > 0 and not info.builtin then - l[#l+1] = '\n' - l[#l+1] = options.indent - l[#l+1] = '-- up_values: ' - format_value(info.ups, options, depth + 1, l) - end - - l[#l+1] = '\n\n' - l[#l+1] = options.indent - l[#l+1] = '...\nend' +if not format_function then + -- Very simple function formatting, if function.lua is not available. + format_function = function (value, _, _, l) + l[#l+1] = 'function (...) --[['..tostring(value):sub(11)..']] end' end end @@ -646,7 +497,7 @@ local TYPE_TO_FORMAT_FUNC = { function format_value (value, _, depth, l) local format_func = TYPE_TO_FORMAT_FUNC[type(value)] if format_func then - format_func(value, l.options, depth, l) + format_func(value, l.options, depth, l, format_value) else error(ERROR_UNKNOWN_TYPE:format(type(value), tostring(value)), 2) end diff --git a/test/test_function.lua b/test/test_function.lua new file mode 100644 index 0000000..6a6575f --- /dev/null +++ b/test/test_function.lua @@ -0,0 +1,249 @@ + +local SUITE = require('TestSuite').new('function') +SUITE:setEnviroment{ + format = require('pretty') +} + +-------------------------------------------------------------------------------- + +local HAS_ADV_GETLOCAL = not not debug.getinfo(1, 'u').nparams -- Lua 5.1 compat +if not loadstring then loadstring = load end -- Lua 5.3 compat + +local function format_test (t) + if t.longterm then return end + if t.adv_getlocal and not HAS_ADV_GETLOCAL then return end + SUITE:addTest(t.expect, function () + local input_value = t.input + local input_options = t.options + local expected_result = t.expect + local actual_result = format(input_value, input_options) + if not t.approx or type(actual_result) ~= 'string' then + assert_equal(expected_result, actual_result) + else + if not actual_result:match(expected_result) then + error(ASSERT_ERROR_APPROX:format(expected_result, actual_result)) + end + end + end) +end + +local function curline (delta) + return debug.getinfo(2).currentline + (delta or 0) +end + +-------------------------------------------------------------------------------- +-- Function printing + +format_test { + adv_getlocal = true, + input = function () end, + expect = 'function () ... end', +} + +format_test { + adv_getlocal = true, + input = function (a) end, + expect = 'function (a) ... end', +} + +format_test { + adv_getlocal = true, + input = function (a, b) end, + expect = 'function (a, b) ... end', +} + +format_test { + adv_getlocal = true, + input = function (...) end, + expect = 'function (...) ... end', +} + +format_test { + adv_getlocal = true, + input = function (a, b, ...) end, + expect = 'function (a, b, ...) ... end', +} + +do + local SOME_RANDOM_UPVALUE = false + + format_test { + adv_getlocal = true, + input = function () l = SOME_RANDOM_UPVALUE end, + expect = 'function () ... end', + } + + format_test { + adv_getlocal = true, + input = function () SOME_RANDOM_UPVALUE = true end, + expect = 'function () ... end', + } + + format_test { + -- More function info is ignored if not at depth 0. + adv_getlocal = true, + input = { a = function () SOME_RANDOM_UPVALUE = true end }, + options = { more_function_info = true }, + expect = '{\n\ta = function () ... end\n}', + } + + + local func_line = curline(2) -- Must be exactly 2 lines above function + format_test { + input = function () l = SOME_RANDOM_UPVALUE end, + adv_getlocal = true, + options = { more_function_info = true }, + expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\t-- up_values: { SOME_RANDOM_UPVALUE = false }\n\n\t...\nend' + } + + local func_line = curline(2) -- Must be exactly 2 lines above function + format_test { + input = function () SOME_RANDOM_UPVALUE = true end, + adv_getlocal = true, + options = { more_function_info = true }, + expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\t-- up_values: { SOME_RANDOM_UPVALUE = false }\n\n\t...\nend' + } +end + +do + local func_line = curline(2) -- Must be exactly 2 lines above function + format_test { + input = function () end, + adv_getlocal = true, + options = { more_function_info = true }, + expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\n\t...\nend' + } +end + +do + local index = 0 + + format_test { + input = function () index = index + 1; return index end, + adv_getlocal = true, + expect = 'function () ... end' + } + + local func_line = curline(2) -- Must be exactly 2 lines above function + format_test { + input = function () index = index + 1; return index end, + adv_getlocal = true, + options = { more_function_info = true }, + expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\t-- up_values: { index = 0 }\n\n\t...\nend' + } +end + +format_test { + adv_getlocal = true, + input = loadstring('return function () end')(), + expect = 'function () end', +} + +format_test { + adv_getlocal = true, + input = loadstring('return function () return function () end end')(), + expect = 'function () return function () end end', +} + +format_test { + adv_getlocal = true, + input = loadstring('return function () return function () end\nend')()(), + expect = 'function () end', +} + +format_test { + -- NOTE: This is HARD to fix. It's thus longerterm + adv_getlocal = true, + input = loadstring('return function () return function () end end')()(), + expect = 'function () end', +} + +format_test { + -- More function info allows one to even get the function whole, if it was defined in a string. + input = loadstring('return function (a, b) return a + b end')(), + options = { more_function_info = true }, + expect = 'function (a, b) return a + b end', +} + +format_test { + -- More function info allows one to even get the function whole, if it was defined in a string. + input = loadstring('return function (a, b)\n\treturn a + b\nend')(), + options = { more_function_info = true }, + expect = 'function (a, b)\n\treturn a + b\nend', +} + +do + local func_line = curline(2) -- Must be exactly 2 lines above function + format_test { + input = function () + -- NOTE: This function must cover 3 lines of code! + end, + adv_getlocal = true, + options = { more_function_info = true }, + expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Lines: '..func_line..' - '..(func_line+2)..']\n\n\t...\nend', + } + + local func_line = curline(2) -- Must be exactly 2 lines above function + format_test { + input = function () --[[ NOTE: This function must cover a single line of code! ]] end, + adv_getlocal = true, + options = { more_function_info = true }, + expect = 'function ()\n\t-- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\n\t...\nend', + } +end + +format_test { + input = math.abs, + expect = 'builtin function (x) ... end', +} + +format_test { + input = math.abs, + options = { more_function_info = true }, + expect = 'builtin function (x)\n\t-- math.abs\n\t-- Returns the absolute value of x.\n\n\t...\nend', +} + +format_test { + input = math.random, + expect = 'builtin function ([m [, n]) ... end', +} + +format_test { + input = math.random, + options = { more_function_info = true }, + expect = 'builtin function ([m [, n])\n\t-- math.random\n\t-- When called without arguments, returns a uniform pseudo-random real number in the range [0,1). When called with an integer number m, math.random returns a uniform pseudo-random integer in the range [1, m]. When called with two integer numbers m and n, math.random returns a uniform pseudo-random integer in the range [m, n].\n\n\t...\nend', +} + +format_test { + input = string.byte, + options = { more_function_info = true }, + expect = 'builtin function (s [, i [, j]])\n\t-- string.byte\n\t-- Returns the internal numerical codes of the characters s[i], s[i+1], ..., s[j]. The default value for i is 1; the default value for j is i.\n\t-- Note that numerical codes are not necessarily portable across platforms.\n\n\t...\nend', +} + +-- Indent functions nicely + +format_test { + -- The tail part should align, letting people focus on the important aspects. + input = { random = math.random, abs = math.abs }, + expect = '{\n\tabs = builtin function (x) ... end,\n\trandom = builtin function ([m [, n]) ... end\n}', +} + +format_test { + -- The function part should align, if some are builtin and some are not. + adv_getlocal = true, + input = { random = math.random, abs = function (x) return x < 0 and -x or x end }, + expect = '{\n\tabs = function (x) ... end,\n\trandom = builtin function ([m [, n]) ... end\n}', +} + +format_test { + -- No special indent if no special function modifier. + adv_getlocal = true, + input = { max = function(a, b) return a > b and a or b end, + abs = function (x) return x < 0 and -x or x end + }, + expect = '{\n\tabs = function (x) ... end,\n\tmax = function (a, b) ... end\n}', +} + +-------------------------------------------------------------------------------- + +return SUITE diff --git a/test/test_pretty.lua b/test/test_pretty.lua index b8293d5..a7ea451 100644 --- a/test/test_pretty.lua +++ b/test/test_pretty.lua @@ -12,15 +12,8 @@ Approximate strings not similar enough: -------------------------------------------------------------------------------- --- Lua 5.1 compat: - -local HAS_ADV_GETLOCAL = not not debug.getinfo(1, 'u').nparams - --- Lua 5.3 compat: - -if not loadstring then - loadstring = load -end +local HAS_ADV_GETLOCAL = not not debug.getinfo(1, 'u').nparams -- Lua 5.1 compat +if not loadstring then loadstring = load end -- Lua 5.3 compat local function format_test (t) if t.longterm then return end @@ -260,221 +253,6 @@ format_test { expect = 'false', } --------------------------------------------------------------------------------- --- Function printing - -format_test { - adv_getlocal = true, - input = function () end, - expect = 'function () ... end', -} - -format_test { - adv_getlocal = true, - input = function (a) end, - expect = 'function (a) ... end', -} - -format_test { - adv_getlocal = true, - input = function (a, b) end, - expect = 'function (a, b) ... end', -} - -format_test { - adv_getlocal = true, - input = function (...) end, - expect = 'function (...) ... end', -} - -format_test { - adv_getlocal = true, - input = function (a, b, ...) end, - expect = 'function (a, b, ...) ... end', -} - -do - local SOME_RANDOM_UPVALUE = false - - format_test { - adv_getlocal = true, - input = function () l = SOME_RANDOM_UPVALUE end, - expect = 'function () ... end', - } - - format_test { - adv_getlocal = true, - input = function () SOME_RANDOM_UPVALUE = true end, - expect = 'function () ... end', - } - - format_test { - -- More function info is ignored if not at depth 0. - adv_getlocal = true, - input = { a = function () SOME_RANDOM_UPVALUE = true end }, - options = { more_function_info = true }, - expect = '{\n\ta = function () ... end\n}', - } - - - local func_line = debug.getinfo(1).currentline + 2 -- Must be exactly 2 lines above function - format_test { - input = function () l = SOME_RANDOM_UPVALUE end, - adv_getlocal = true, - options = { more_function_info = true }, - expect = 'function ()\n\t-- source_file: \'./test/test_pretty.lua\' [Line: '..func_line..']\n\t-- up_values: { SOME_RANDOM_UPVALUE = false }\n\n\t...\nend' - } - - local func_line = debug.getinfo(1).currentline + 2 -- Must be exactly 2 lines above function - format_test { - input = function () SOME_RANDOM_UPVALUE = true end, - adv_getlocal = true, - options = { more_function_info = true }, - expect = 'function ()\n\t-- source_file: \'./test/test_pretty.lua\' [Line: '..func_line..']\n\t-- up_values: { SOME_RANDOM_UPVALUE = false }\n\n\t...\nend' - } -end - -do - local func_line = debug.getinfo(1).currentline + 2 -- Must be exactly 2 lines above function - format_test { - input = function () end, - adv_getlocal = true, - options = { more_function_info = true }, - expect = 'function ()\n\t-- source_file: \'./test/test_pretty.lua\' [Line: '..func_line..']\n\n\t...\nend' - } -end - -do - local index = 0 - - format_test { - input = function () index = index + 1; return index end, - adv_getlocal = true, - expect = 'function () ... end' - } - - local func_line = debug.getinfo(1).currentline + 2 -- Must be exactly 2 lines above function - format_test { - input = function () index = index + 1; return index end, - adv_getlocal = true, - options = { more_function_info = true }, - expect = 'function ()\n\t-- source_file: \'./test/test_pretty.lua\' [Line: '..func_line..']\n\t-- up_values: { index = 0 }\n\n\t...\nend' - } -end - -format_test { - adv_getlocal = true, - input = loadstring('return function () end')(), - expect = 'function () end', -} - -format_test { - adv_getlocal = true, - input = loadstring('return function () return function () end end')(), - expect = 'function () return function () end end', -} - -format_test { - longterm = true, - adv_getlocal = true, - input = loadstring('return function () return function () end\nend')()(), - expect = 'function () end', -} - -format_test { - -- NOTE: This is HARD to fix. It's thus longerterm - longterm = true, - adv_getlocal = true, - input = loadstring('return function () return function () end end')()(), - expect = 'function () end', -} - -format_test { - -- More function info allows one to even get the function whole, if it was defined in a string. - input = loadstring('return function (a, b) return a + b end')(), - options = { more_function_info = true }, - expect = 'function (a, b) return a + b end', -} - -format_test { - -- More function info allows one to even get the function whole, if it was defined in a string. - input = loadstring('return function (a, b)\n\treturn a + b\nend')(), - options = { more_function_info = true }, - expect = 'function (a, b)\n\treturn a + b\nend', -} - -do - local func_line = debug.getinfo(1).currentline + 2 -- Must be exactly 2 lines above function - format_test { - input = function () - -- NOTE: This function must cover 3 lines of code! - end, - adv_getlocal = true, - options = { more_function_info = true }, - expect = 'function ()\n\t-- source_file: \'./test/test_pretty.lua\' [Lines: '..func_line..' - '..(func_line+2)..']\n\n\t...\nend', - } - - local func_line = debug.getinfo(1).currentline + 2 -- Must be exactly 2 lines above function - format_test { - input = function () --[[ NOTE: This function must cover a single line of code! ]] end, - adv_getlocal = true, - options = { more_function_info = true }, - expect = 'function ()\n\t-- source_file: \'./test/test_pretty.lua\' [Line: '..func_line..']\n\n\t...\nend', - } -end - -format_test { - input = math.abs, - expect = 'builtin function (x) ... end', -} - -format_test { - input = math.abs, - options = { more_function_info = true }, - expect = 'builtin function (x)\n\t-- math.abs\n\t-- Returns the absolute value of x.\n\n\t...\nend', -} - -format_test { - input = math.random, - expect = 'builtin function ([m [, n]) ... end', -} - -format_test { - input = math.random, - options = { more_function_info = true }, - expect = 'builtin function ([m [, n])\n\t-- math.random\n\t-- When called without arguments, returns a uniform pseudo-random real number in the range [0,1). When called with an integer number m, math.random returns a uniform pseudo-random integer in the range [1, m]. When called with two integer numbers m and n, math.random returns a uniform pseudo-random integer in the range [m, n].\n\n\t...\nend', -} - -format_test { - input = string.byte, - options = { more_function_info = true }, - expect = 'builtin function (s [, i [, j]])\n\t-- string.byte\n\t-- Returns the internal numerical codes of the characters s[i], s[i+1], ..., s[j]. The default value for i is 1; the default value for j is i.\n\t-- Note that numerical codes are not necessarily portable across platforms.\n\n\t...\nend', -} - --- Indent functions nicely - -format_test { - -- The tail part should align, letting people focus on the important aspects. - input = { random = math.random, abs = math.abs }, - expect = '{\n\tabs = builtin function (x) ... end,\n\trandom = builtin function ([m [, n]) ... end\n}', -} - -format_test { - -- The function part should align, if some are builtin and some are not. - adv_getlocal = true, - input = { random = math.random, abs = function (x) return x < 0 and -x or x end }, - expect = '{\n\tabs = function (x) ... end,\n\trandom = builtin function ([m [, n]) ... end\n}', -} - -format_test { - -- No special indent if no special function modifier. - adv_getlocal = true, - input = { max = function(a, b) return a > b and a or b end, - abs = function (x) return x < 0 and -x or x end - }, - expect = '{\n\tabs = function (x) ... end,\n\tmax = function (a, b) ... end\n}', -} - -------------------------------------------------------------------------------- -- Userdata printing