From 87b12e15b21076742aa3de5e55967cb3b596ee23 Mon Sep 17 00:00:00 2001 From: Jon Michael Aanes Date: Fri, 14 Apr 2017 13:06:43 +0200 Subject: [PATCH] =?UTF-8?q?Fixed=20issues=20with=20`anal=C3=BDse=5Fstructu?= =?UTF-8?q?re.lua`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The most significant was a misclassification of tables with number exclusive keys, with huge jumps between each one. Example: { 1, [300] = 300 } This was caused by logic faults in `get_table_info`, which has been fixed. When solving above issue, a two new issues appeared: 1. Due to a logic fault, the count of number of elements in a table was wrong, leading to issues with tables with boolean keys. This was fixed with simple logic changes. 2. Some very small tables (1 element) would be classified as sets, and thus rendered wrongly. This was fixed by adding a MINIMUM_NUMBER_OF_SET_ELEMENTS constant. --- analyze_structure.lua | 45 ++++++++++++++++++--------------- pretty.lua | 10 ++++---- test/test_analyze_structure.lua | 20 ++++++++++++++- test/test_pretty.lua | 12 ++++----- 4 files changed, 54 insertions(+), 33 deletions(-) diff --git a/analyze_structure.lua b/analyze_structure.lua index 93bbcb4..b891941 100644 --- a/analyze_structure.lua +++ b/analyze_structure.lua @@ -38,6 +38,7 @@ local SIMPLE_VALUE_TYPES = { } local SHORT_STRING_MAX_LEN = 7 +local MINIMUM_NUMBER_OF_SET_ELEMENTS = 2 -------------------------------------------------------------------------------- @@ -83,14 +84,27 @@ local function largest_number_index (t) return max_index end -local function nr_elements_in_map (t) +local function nr_elements_in_table (t) local k, count = nil, -1 repeat k, count = next(t, k), count + 1 - until not k + until k == nil return count end +local function nr_elements_in_seq (t) + local i, last_elem_i, nr_elems, has_holes = 0, 0, 0, false + while i <= last_elem_i + 2 do + i = i + 1 + if t[i] ~= nil then + last_elem_i, nr_elems = i, nr_elems + 1 + else + has_holes = true + end + end + return nr_elems, has_holes +end + -------------------------------------------------------------------------------- local function contains_only_nice_string_keys (t) @@ -119,19 +133,6 @@ local function contains_only_nice_number_indexes (t) return #t > 0 end -local function has_seq (t) - if not contains_only_nice_number_indexes(t) then return false end - -- Contain list of keys - local keys = {[0] = 0} - for i, _ in pairs(t) do keys[#keys+1] = i end - table.sort(keys) - -- Check to see that no indice jumps more than 2 - for indice_i = 1, #keys do - if keys[indice_i - 1] < keys[indice_i] - 2 then return false end - end - return true, (#keys ~= keys[#keys]) -end - local function is_set (t) -- Predicate: Does t contain only boolean values. local value_types = get_value_types(t) @@ -202,12 +203,14 @@ local function get_table_info (t) local key_types = get_key_types(t) local info = {} - info.has_seq, info.has_holes = has_seq(t) - info.has_map = key_types.nr_types > (key_types.number and 1 or 0) - info.is_set = is_set(t) + info.nr_elems = nr_elements_in_table(t) + info.seq_elems, info.has_holes = nr_elements_in_seq(t) + info.map_elems = info.nr_elems - info.seq_elems + info.has_seq = info.seq_elems > 0 + info.has_map = info.map_elems > 0 + info.is_set = is_set(t) and info.nr_elems >= MINIMUM_NUMBER_OF_SET_ELEMENTS info.is_tabular = is_tabular(t) - info.is_short = is_short_table(t) - info.nr_elems = nr_elements_in_map(t) -- TODO: Use this for something. + info.is_short = is_short_table(t) -- TODO: Remove this. It's not used for anything. -- Determine type of table if not info.has_seq and not info.has_map then info.type = TABLE_TYPE.EMPTY @@ -251,4 +254,4 @@ end -------------------------------------------------------------------------------- -return analyze_structure +return { analyze_structure, get_table_info } diff --git a/pretty.lua b/pretty.lua index 0238616..1beefbc 100644 --- a/pretty.lua +++ b/pretty.lua @@ -2,7 +2,7 @@ -- Ensure loading library, if it exists, no matter where pretty.lua was loaded from. -- Load the library component -local format_number, format_function, analyze_structure, TABLE_TYPE +local format_number, format_function, analyze_structure, get_table_info, TABLE_TYPE do local thispath = ... and select('1', ...):match('.+%.') or '' @@ -13,7 +13,7 @@ do -- Load other stuff local was_loaded was_loaded, analyze_structure = pcall(require, thispath..'analyze_structure') - print(was_loaded, analyze_structure) + analyze_structure, get_table_info = analyze_structure[1], analyze_structure[2] assert(was_loaded, '[pretty]: Could not load vital library: analyze_structure') was_loaded, TABLE_TYPE = pcall(require, thispath..'table_type') assert(was_loaded, '[pretty]: Could not load vital library: table_type') @@ -333,12 +333,12 @@ local TABLE_TYPE_TO_PAIR_FORMAT = { local function format_map (t, options, depth, l) -- NOTE: Assumes that the input table was pre-checked with `is_single_line_table()` - local table_type = l.info[t] and l.info[t].type or get_table_type(t) -- FIXME: This is a temp fix + local table_info = l.info[t] or get_table_info(t) local key_value_pairs = get_key_value_pairs_in_proper_order(t) - if table_type == TABLE_TYPE.SEQUENCE and l.info[t].has_holes then + if table_info.type == TABLE_TYPE.SEQUENCE and l.info[t].has_holes then fill_holes_in_key_value_pairs(key_value_pairs) end - local pair_format_func = TABLE_TYPE_TO_PAIR_FORMAT[table_type] + local pair_format_func = TABLE_TYPE_TO_PAIR_FORMAT[table_info.type] local start_of_table_i = #l + 1 l[#l+1] = '{' diff --git a/test/test_analyze_structure.lua b/test/test_analyze_structure.lua index 82d321e..7fb98c6 100644 --- a/test/test_analyze_structure.lua +++ b/test/test_analyze_structure.lua @@ -1,7 +1,7 @@ local SUITE = require('TestSuite').new('analyze_structure') SUITE:setEnviroment { - analyze_structure = require('analyze_structure'), + analyze_structure = require('analyze_structure')[1], TABLE_TYPE = require('table_type') } @@ -55,6 +55,24 @@ SUITE:addTest('Pure Map', function () assert(table_info.has_map == true) end) +SUITE:addTest('Boolean set', function () + local input = { [true] = true, [false] = false } + local table_info = analyze_structure(input)[input] + + assert(table_info.type == TABLE_TYPE.SET, 'Returned bad type: '..table_info.type) + assert(table_info.has_seq == false) + assert(table_info.has_map == true) +end) + +SUITE:addTest('A Mixed table', function () + local input = { 300, [300] = 1 } + local table_info = analyze_structure(input)[input] + + assert(table_info.has_seq == true) + assert(table_info.has_map == true) + assert(table_info.type == TABLE_TYPE.MIXED, 'Returned bad type: '..table_info.type) +end) + SUITE:addTest('String Map', function () local input = { a = 1, b = 2, c = 3 } local table_info = analyze_structure(input)[input] diff --git a/test/test_pretty.lua b/test/test_pretty.lua index f513cc5..4ae1db1 100644 --- a/test/test_pretty.lua +++ b/test/test_pretty.lua @@ -192,11 +192,6 @@ format_test { expect = '{ [false] = false, [true] = true }', } -format_test { - input = { [100] = 'Hi', [300] = 'Hello' }, - expect = '{ [100] = \'Hi\', [300] = \'Hello\' }', -} - format_test { -- Order does not matter input = { b = 1, a = 2 }, expect = '{ a = 2, b = 1 }', @@ -225,9 +220,14 @@ format_test { expect = '{\n\ta = { 1, 2, 3 },\n\tb = { 4, 5, 6 }\n}', } +format_test { + input = { [100] = 'Hi', [300] = 'Hello' }, + expect = '{ [100] = \'Hi\', [300] = \'Hello\' }', +} + format_test { input = { 'Hi', [300] = 'Hello' }, - expect = '{\n\t[1] = \'Hi\',\n\t[300] = \'Hello\'\n}', + expect = '{ [1] = \'Hi\', [300] = \'Hello\' }', } format_test {