1
0

Updated test_function.lua to reflect the new design. The system also warns against using experimental and debug options.

This commit is contained in:
Jon Michael Aanes 2017-06-24 18:53:59 +02:00
parent 4a41111d1e
commit 3bb599e976
3 changed files with 249 additions and 248 deletions

View File

@ -123,8 +123,8 @@ local function get_function_paramlist_and_body (str, start_line, end_line)
local start_line_index = get_line_index(str, start_line) local start_line_index = get_line_index(str, start_line)
local end_line_index = get_line_index(str, end_line + 1) local end_line_index = get_line_index(str, end_line + 1)
local function_params, function_body = str:sub(start_line_index, end_line_index):match('function%s*[a-zA-Z0-9_.]*%s*(%([a-zA-Z0-9_,. \t]*%))[ \t]*(.-)[ \t]*end') local function_params, function_body = str:sub(start_line_index, end_line_index):match('.*function%s*[a-zA-Z0-9_.]*%s*(%([a-zA-Z0-9_,. \t]*%))[ \t]*(.+)[ \t]*end')
--print(function_params, function_body) function_body = function_body:match('^%s*(.-)%s*$')
assert(type(function_params) == 'string' and type(function_body) == 'string') assert(type(function_params) == 'string' and type(function_body) == 'string')
return function_params, function_body return function_params, function_body
end end
@ -160,11 +160,13 @@ local function add_indent_to_string (str, indent)
assert(type(indent) == 'string') assert(type(indent) == 'string')
local l = {} local l = {}
for line in string.gmatch(str, '\n', true) do for line in str:gmatch('[^\n]+', true) do
l[#l+1] = indent l[#l+1] = indent
l[#l+1] = line l[#l+1] = line
l[#l+1] = '\n'
end end
return table.concat(l, '\n') if l[#l] == '\n' then l[#l] = nil end
return table.concat(l, '')
end end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -204,7 +206,7 @@ return function (value, depth, l, format_value)
local info = get_function_info(value) local info = get_function_info(value)
if l.options.include_closure and not info.builtin then if l.options._include_closure and not info.builtin then
return format_function_with_closure(value, depth, l, format_value) return format_function_with_closure(value, depth, l, format_value)
end end
@ -237,7 +239,7 @@ return function (value, depth, l, format_value)
l[#l+1] = { 'align', 'func_def', width_of_strings_in_l(l, top_before) } l[#l+1] = { 'align', 'func_def', width_of_strings_in_l(l, top_before) }
-- Cleanup and finish -- Cleanup and finish
if not l.options.more_function_info or depth ~= 0 then if depth ~= 0 then
l[#l+1] = (function_body:sub(1,1) == '\n') and '' or ' ' l[#l+1] = (function_body:sub(1,1) == '\n') and '' or ' '
l[#l+1] = function_body l[#l+1] = function_body
l[#l+1] = { 'align', 'func_end', #function_body } l[#l+1] = { 'align', 'func_end', #function_body }
@ -288,16 +290,22 @@ return function (value, depth, l, format_value)
-- NOTE: This is for testing/debugging/experimentation purposes, and is -- NOTE: This is for testing/debugging/experimentation purposes, and is
-- not designed to be pretty. -- not designed to be pretty.
-- Native
l[#l+1] = indent l[#l+1] = indent
l[#l+1] = '--[[ Function Body:\n\t' l[#l+1] = '-- native_repr: '
l[#l+1] = tostring(value)
-- Function body
l[#l+1] = indent
l[#l+1] = '--[[ function_body:\n\t'
l[#l+1] = add_indent_to_string(get_function_str_from_file(info.short_src, info.linedefined, info.lastlinedefined), l.options.indent) l[#l+1] = add_indent_to_string(get_function_str_from_file(info.short_src, info.linedefined, info.lastlinedefined), l.options.indent)
l[#l+1] = indent l[#l+1] = indent
l[#l+1] = '--]]' l[#l+1] = '--]]'
-- Full info
l[#l+1] = indent l[#l+1] = indent
l[#l+1] = '--[[\n\tNative repr:' l[#l+1] = '--[[ full_info:\n'
l[#l+1] = tostring(value) info.env = nil
l[#l+1] = indent
format_value(info, depth + 1, l) format_value(info, depth + 1, l)
l[#l+1] = indent l[#l+1] = indent
l[#l+1] = '--]]' l[#l+1] = '--]]'

View File

@ -463,19 +463,19 @@ setmetatable(StringBuilder, {
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local DEBUG_OPTIONS = { _all_function_info = true, _table_addr_comment = true } local DEBUG_OPTION_USED = { }
local KNOWN_OPTIONS = { local KNOWN_OPTIONS = {
_table_addr_comment = { type = 'boolean', default = false }, _table_addr_comment = { type = 'boolean', default = false, debug = 'debug' },
_all_function_info = { type = 'boolean', default = false }, _all_function_info = { type = 'boolean', default = false, debug = 'debug' },
_include_closure = { type = 'boolean', default = false, debug = 'experimental' },
cut_strings = { type = 'boolean', default = false }, cut_strings = { type = 'boolean', default = false },
include_closure = { type = 'boolean', default = false },
indent = { type = 'string', default = ' ' }, indent = { type = 'string', default = ' ' },
max_depth = { type = 'number', default = math.huge }, max_depth = { type = 'number', default = math.huge },
embed_loaded_funcs = { type = 'boolean', default = false }, embed_loaded_funcs = { type = 'boolean', default = false }, -- TODO: Outphase this, in favor of automatically embedding "small enough" functions.
more_function_info = { type = 'boolean', default = false },
recursion = { type = 'string', default = 'ignore', accepted = {['ignore'] = true, ['marked'] = true} }, recursion = { type = 'string', default = 'ignore', accepted = {['ignore'] = true, ['marked'] = true} },
short_builtins = { type = 'boolean', default = false }, short_builtins = { type = 'boolean', default = false }, -- TODO: Outphase this. Rather automatically use the short versions in places where it would be strange to find the function, like keys, etc.
} }
local function ensure_that_all_options_are_known (options) local function ensure_that_all_options_are_known (options)
@ -488,6 +488,9 @@ local function ensure_that_all_options_are_known (options)
error(('[pretty]: Bad value given to option %s: %s (%s). Expected value of type %s'):format(option_name, option_value, type(option_value), KNOWN_OPTIONS[option_name].type), 2) error(('[pretty]: Bad value given to option %s: %s (%s). Expected value of type %s'):format(option_name, option_value, type(option_value), KNOWN_OPTIONS[option_name].type), 2)
elseif KNOWN_OPTIONS[option_name].accepted and not KNOWN_OPTIONS[option_name].accepted[option_value] then elseif KNOWN_OPTIONS[option_name].accepted and not KNOWN_OPTIONS[option_name].accepted[option_value] then
error(('[pretty]: Bad value given to option %s: %s (%s). Expected one of: %s'):format(option_name, option_value, type(option_value), table.concat(KNOWN_OPTIONS[option_name].accepted, ', ')), 2) error(('[pretty]: Bad value given to option %s: %s (%s). Expected one of: %s'):format(option_name, option_value, type(option_value), table.concat(KNOWN_OPTIONS[option_name].accepted, ', ')), 2)
elseif KNOWN_OPTIONS[option_name].debug and not DEBUG_OPTION_USED[option_name] then
DEBUG_OPTION_USED[option_name] = true
print(('[pretty]: Using %s option "%s".\n Please note that this option may change at any time. It is not stable,\n not tested, and may indeed break or be removed without warning.'):format(KNOWN_OPTIONS[option_name].debug, option_name))
end end
end end
-- Assign default values -- Assign default values

View File

@ -10,217 +10,153 @@ local HAS_ADV_GETLOCAL = not not debug.getinfo(1, 'u').nparams -- Lua 5.1 compa
if not loadstring then loadstring = load end -- Lua 5.3 compat if not loadstring then loadstring = load end -- Lua 5.3 compat
local function format_test (t) local function format_test (t)
if t.longterm then return end
if t.adv_getlocal and not HAS_ADV_GETLOCAL then return end if t.adv_getlocal and not HAS_ADV_GETLOCAL then return end
if t.single then
return SUITE:addTest(t.name or t.expect, function ()
local format = format({t.input}, t.options):gsub('^{%s+(.-)%s+}$', function(a) return '{ '..a..' }' end)
assert_equal('{ '..t.expect..' }', format)
end, { line = debug.getinfo(2).currentline })
end
SUITE:addTest(t.name or t.expect, function () SUITE:addTest(t.name or t.expect, function ()
local input_value = t.input assert_equal(t.expect, format(t.input, t.options))
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, { line = debug.getinfo(2).currentline }) end, { line = debug.getinfo(2).currentline })
end end
local function curline (delta) local function curline (delta) return debug.getinfo(2).currentline + (delta or 0) end
return debug.getinfo(2).currentline + (delta or 0)
end local TEST_UPVALUE = 42
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Function printing -- Basic inline functions
format_test { format_test {
name = 'Basic function formatting',
adv_getlocal = true, adv_getlocal = true,
single = true,
input = function () end, input = function () end,
expect = 'function () ... end', expect = 'function () ... end',
} }
format_test { format_test {
name = 'Function with a single argument',
adv_getlocal = true, adv_getlocal = true,
single = true,
input = function (a) end, input = function (a) end,
expect = 'function (a) ... end', expect = 'function (a) ... end',
} }
format_test { format_test {
name = 'Function with multiple arguments',
adv_getlocal = true, adv_getlocal = true,
single = true,
input = function (a, b) end, input = function (a, b) end,
expect = 'function (a, b) ... end', expect = 'function (a, b) ... end',
} }
format_test { format_test {
name = 'Function with vararg',
adv_getlocal = true, adv_getlocal = true,
single = true,
input = function (...) end, input = function (...) end,
expect = 'function (...) ... end', expect = 'function (...) ... end',
} }
format_test { format_test {
name = 'Function with vararg and multiple arguments',
adv_getlocal = true, adv_getlocal = true,
single = true,
input = function (a, b, ...) end, input = function (a, b, ...) end,
expect = 'function (a, b, ...) ... end', expect = 'function (a, b, ...) ... end',
} }
do format_test {
local SOME_RANDOM_UPVALUE = false name = 'Closures don\'t affect functions printed in single mode 1',
format_test {
adv_getlocal = true, adv_getlocal = true,
input = function () l = SOME_RANDOM_UPVALUE end, single = true,
input = function () l = TEST_UPVALUE end,
expect = 'function () ... end', expect = 'function () ... end',
} }
format_test { format_test {
name = 'Closures don\'t affect functions printed in single mode 2',
adv_getlocal = true, adv_getlocal = true,
input = function () SOME_RANDOM_UPVALUE = true end, single = true,
input = function () TEST_UPVALUE = true end,
expect = 'function () ... end', expect = 'function () ... end',
} }
format_test { --------------------------------------------------------------------------------
-- More function info is ignored if not at depth 0. -- Basic elaborate functions
adv_getlocal = true,
input = { a = function () SOME_RANDOM_UPVALUE = true end },
options = { more_function_info = true },
expect = '{ a = function () ... end }',
}
local func_line = curline(3)
local func_line = curline(2) -- Must be exactly 2 lines above function format_test {
format_test { name = 'Singleline elaborate function',
input = function () l = SOME_RANDOM_UPVALUE end,
adv_getlocal = true,
options = { more_function_info = true },
expect = 'function ()\n -- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n -- up_values: { SOME_RANDOM_UPVALUE = false }\n\n ...\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 -- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n -- up_values: { SOME_RANDOM_UPVALUE = false }\n\n ...\nend'
}
end
do
local func_line = curline(2) -- Must be exactly 2 lines above function
format_test {
input = function () end, input = function () end,
adv_getlocal = true,
options = { more_function_info = true },
expect = 'function ()\n -- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\n ...\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 -- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n -- up_values: { index = 0 }\n\n ...\nend'
}
end
format_test {
adv_getlocal = true,
options = { embed_loaded_funcs = true },
input = loadstring('return function () end')(),
expect = 'function () end',
}
format_test {
adv_getlocal = true,
options = { embed_loaded_funcs = true },
input = loadstring('return function () return function () end end')(),
expect = 'function () return function () end end',
}
format_test {
adv_getlocal = true,
options = { embed_loaded_funcs = 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,
options = { embed_loaded_funcs = 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 = { embed_loaded_funcs = 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 return a + b\nend')(),
options = { embed_loaded_funcs = true },
expect = 'function (a, b)\n return 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 -- source_file: \'./test/test_function.lua\' [Lines: '..func_line..' - '..(func_line+2)..']\n\n ...\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 -- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\n ...\nend', expect = 'function ()\n -- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n\n ...\nend',
} }
end
local func_line = curline(3)
format_test {
name = 'Multiline elaborate function',
input = function ()
end,
expect = 'function ()\n -- source_file: \'./test/test_function.lua\' [Lines: '..func_line..' - '..(func_line+1)..']\n\n ...\nend',
}
local func_line = curline(3) -- Must be exactly 3 lines above function
format_test {
name = 'Elaborate function with upvalue included 1',
input = function () l = TEST_UPVALUE end,
adv_getlocal = true,
expect = 'function ()\n -- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n -- up_values: { TEST_UPVALUE = 42 }\n\n ...\nend'
}
local func_line = curline(3) -- Must be exactly 3 lines above function
format_test {
name = 'Elaborate function with upvalue included 2',
input = function () TEST_UPVALUE = true end,
adv_getlocal = true,
expect = 'function ()\n -- source_file: \'./test/test_function.lua\' [Line: '..func_line..']\n -- up_values: { TEST_UPVALUE = 42 }\n\n ...\nend'
}
local func_line = curline(3)
format_test {
name = 'Elaborate function with documentation',
input = function ()
-- Hello World
if true then return false end
return true
end,
expect = 'function ()\n -- source_file: \'./test/test_function.lua\' [Lines: '..func_line..' - '..(func_line+1)..']\n -- Hello World\n\n ...\nend',
}
--------------------------------------------------------------------------------
-- Builtins
format_test { format_test {
single = true,
input = math.abs, input = math.abs,
expect = 'builtin function (x) ... end', expect = 'builtin function (x) ... end',
} }
format_test { format_test {
input = math.abs, input = math.abs,
options = { more_function_info = true },
expect = 'builtin function (x)\n -- math.abs\n -- Returns the absolute value of x.\n\n ...\nend', expect = 'builtin function (x)\n -- math.abs\n -- Returns the absolute value of x.\n\n ...\nend',
} }
format_test { format_test {
single = true,
input = math.random, input = math.random,
expect = 'builtin function ([m [, n]) ... end', expect = 'builtin function ([m [, n]) ... end',
} }
format_test { format_test {
input = math.random, input = math.random,
options = { more_function_info = true },
expect = 'builtin function ([m [, n])\n -- math.random\n -- 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 ...\nend', expect = 'builtin function ([m [, n])\n -- math.random\n -- 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 ...\nend',
} }
format_test { format_test {
input = string.byte, input = string.byte,
options = { more_function_info = true },
expect = 'builtin function (s [, i [, j]])\n -- string.byte\n -- 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 -- Note that numerical codes are not necessarily portable across platforms.\n\n ...\nend', expect = 'builtin function (s [, i [, j]])\n -- string.byte\n -- 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 -- Note that numerical codes are not necessarily portable across platforms.\n\n ...\nend',
} }
@ -228,126 +164,69 @@ format_test {
-- in a standard enviroment, return that name, instead of other complex info. -- in a standard enviroment, return that name, instead of other complex info.
format_test { format_test {
-- NOTE: These tests may be counter to intention, soon.
input = math.random, input = math.random,
options = { short_builtins = true }, options = { short_builtins = true },
expect = 'math.random', expect = 'math.random',
} }
format_test { format_test {
-- NOTE: These tests may be counter to intention, soon.
input = { math.cos, math.sin, math.abs }, input = { math.cos, math.sin, math.abs },
options = { short_builtins = true }, options = { short_builtins = true },
expect = '{ math.cos, math.sin, math.abs }', expect = '{ math.cos, math.sin, math.abs }',
} }
format_test {
name = 'Replace function with short version, if key',
input = { [math.random] = 365 },
expect = '{ [math.random] = 365 }',
}
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Closure creation -- Embedding functions loaded with loadstring
-- include_closure option: If a function uses upvalues, return code that creates
-- a closure for that function, including the function code.
-- NOTE: Without AST traversal, it's impossible to garentee that values refered
-- by multiple recursive closures are the same, because they can actually refer
-- to different variables with the same name, as the following example shows:
--
-- local val_a = 1
-- local func_a = function () return val_a end
-- local val_a = 2
-- local func_c = function () return func_a() + val_a end
do
format_test {
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = function (a, b) return (a > b) and a or b end,
expect = 'function (a, b) return (a > b) and a or b end',
}
end
do
local input_func = (function ()
local i = 0
return function (a) i = i + a; return i end
end)()
for i = 1, 10 do input_func(1) end
format_test {
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = input_func,
expect = '(function () local i = 10; return function (a) i = i + a; return i end end)()',
}
end
do
local input_func = loadstring([[
return function ()
local i = 0
return function (a) i = i + a; return i end
end]])()()
for i = 1, 10 do input_func(1) end
format_test {
name = 'Can include variables in closure',
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = input_func,
expect = '(function () local i = 10; return function (a) i = i + a; return i end end)()',
}
end
format_test { format_test {
name = 'Can include functions in closure', single = true,
adv_getlocal = true, name = 'It\'s possible to get loadstring functions whole',
options = { more_function_info = true, include_closure = true }, input = loadstring('return function (a, b) return a + b end')(),
input = (function () options = { embed_loaded_funcs = true },
local custom_max = function (a, b) return (a > b) and a or b end expect = 'function (a, b) return a + b end',
return function (a, b) return custom_max(a, b) + 2 end
end)(),
expect = '(function () local custom_max = function (a, b) return (a > b) and a or b end; return function (a, b) return custom_max(a, b) + 2 end end)()',
} }
format_test { format_test {
name = 'Can include functions defined with `function <name> () ...` style', single = true,
adv_getlocal = true, name = 'Whitespace is automatically stripped from loadstring functions',
options = { more_function_info = true, include_closure = true }, input = loadstring('return function (a, b)\n return a + b\nend')(),
input = (function () options = { embed_loaded_funcs = true },
local function custom_max (a, b) return (a > b) and a or b end expect = 'function (a, b) return a + b end',
return function (a, b) return custom_max(a, b) + 2 end
end)(),
expect = '(function () local custom_max = function (a, b) return (a > b) and a or b end; return function (a, b) return custom_max(a, b) + 2 end end)()',
} }
do format_test {
local custom_max = function (a, b) return (a > b) and a or b end single = true,
format_test {
name = 'Can include functions from outside scope into closure',
adv_getlocal = true, adv_getlocal = true,
options = { more_function_info = true, include_closure = true }, options = { embed_loaded_funcs = true },
input = (function () input = loadstring('return function () return function () end\nend')()(),
return function (a, b) return custom_max(a, b) + 2 end expect = 'function () end',
end)(), }
expect = '(function () local custom_max = function (a, b) return (a > b) and a or b end; return function (a, b) return custom_max(a, b) + 2 end end)()',
}
end
do
local a_func = function (x) return x + 2 end
local b_func = function (x) return a_func(x) * a_func(x) end
local c_func = function (x) return b_func(a_func(x)) end
format_test {
name = 'Can support recursive closures',
adv_getlocal = true,
options = { more_function_info = true, include_closure = true },
input = c_func,
expect = '(function () local b_func = (function () local a_func = function (x) return x + 2 end; return function (x) return a_func(x) * a_func(x) end end)(); local a_func = function (x) return x + 2 end; return function (x) return b_func(a_func(x)) end end)()',
}
end
format_test { format_test {
name = 'Closures do not affect builtins', name = 'When finding the correct function becomes too hard, just ignore it 1',
input = math.abs, single = true,
options = { more_function_info = true, include_closure = true }, adv_getlocal = true,
expect = 'builtin function (x)\n -- math.abs\n -- Returns the absolute value of x.\n\n ...\nend', options = { embed_loaded_funcs = true },
input = loadstring('return function () return function () end end')(),
expect = 'function () ... end',
}
format_test {
name = 'When finding the correct function becomes too hard, just ignore it 2',
single = true,
adv_getlocal = true,
options = { embed_loaded_funcs = true },
input = loadstring('return function () return function () end end')()(),
expect = 'function () ... end',
} }
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -400,13 +279,124 @@ format_test {
expect = '{\n a = function (ψ) ... end\n b = function (a) ... end\n}', expect = '{\n a = function (ψ) ... end\n b = function (a) ... end\n}',
} }
--------------------------------------------------------------------------------
-- Closure creation
-- _include_closure option: If a function uses upvalues, return code that creates
-- a closure for that function, including the function code.
-- NOTE: Without AST traversal, it's impossible to garentee that values refered
-- by multiple recursive closures are the same, because they can actually refer
-- to different variables with the same name, as the following example shows:
--
-- local val_a = 1
-- local func_a = function () return val_a end
-- local val_a = 2
-- local func_c = function () return func_a() + val_a end
-- NOTE: The following tests are all EXPERIMENTAL! All of the tests use features
-- which may change at any time.
format_test {
name = 'Closures do not affect non-upvalue function',
adv_getlocal = true,
options = { _include_closure = true },
input = function (a, b) return (a > b) and a or b end,
expect = 'function (a, b) return (a > b) and a or b end',
}
format_test {
name = 'Closures do not affect builtins',
input = math.abs,
options = { _include_closure = true },
expect = 'builtin function (x)\n -- math.abs\n -- Returns the absolute value of x.\n\n ...\nend',
}
do
local input_func = (function ()
local i = 0
return function (a) i = i + a; return i end
end)()
for i = 1, 10 do input_func(1) end
format_test {
adv_getlocal = true,
options = { _include_closure = true },
input = input_func,
expect = '(function () local i = 10; return function (a) i = i + a; return i end end)()',
}
end
do
local input_func = loadstring([[
return function ()
local i = 0
return function (a) i = i + a; return i end
end]])()()
for i = 1, 10 do input_func(1) end
format_test {
name = 'Can include variables in closure',
adv_getlocal = true,
options = { _include_closure = true },
input = input_func,
expect = '(function () local i = 10; return function (a) i = i + a; return i end end)()',
}
end
format_test {
name = 'Can include functions in closure',
adv_getlocal = true,
options = { _include_closure = true },
input = (function ()
local custom_max = function (a, b) return (a > b) and a or b end
return function (a, b) return custom_max(a, b) + 2 end
end)(),
expect = '(function () local custom_max = function (a, b) return (a > b) and a or b end; return function (a, b) return custom_max(a, b) + 2 end end)()',
}
format_test {
name = 'Can include functions defined with `function <name> () ...` style',
adv_getlocal = true,
options = { _include_closure = true },
input = (function ()
local function custom_max (a, b) return (a > b) and a or b end
return function (a, b) return custom_max(a, b) + 2 end
end)(),
expect = '(function () local custom_max = function (a, b) return (a > b) and a or b end; return function (a, b) return custom_max(a, b) + 2 end end)()',
}
do
local custom_max = function (a, b) return (a > b) and a or b end
format_test {
name = 'Can include functions from outside scope into closure',
adv_getlocal = true,
options = { _include_closure = true },
input = (function ()
return function (a, b) return custom_max(a, b) + 2 end
end)(),
expect = '(function () local custom_max = function (a, b) return (a > b) and a or b end; return function (a, b) return custom_max(a, b) + 2 end end)()',
}
end
do
local a_func = function (x) return x + 2 end
local b_func = function (x) return a_func(x) * a_func(x) end
local c_func = function (x) return b_func(a_func(x)) end
format_test {
name = 'Can support recursive closures',
adv_getlocal = true,
options = { _include_closure = true },
input = c_func,
expect = '(function () local b_func = (function () local a_func = function (x) return x + 2 end; return function (x) return a_func(x) * a_func(x) end end)(); local a_func = function (x) return x + 2 end; return function (x) return b_func(a_func(x)) end end)()',
}
end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
--[[ --[[
format_test { format_test {
adv_getlocal = true, adv_getlocal = true,
options = { more_function_info = true, _all_function_info = true, max_depth = 2 }, options = { _all_function_info = true, max_depth = 2 },
input = function() end, input = function() end,
expect = '', expect = '',
} }