From 5bee4a73781bf2b9cb674fa1aa84b5bec90f5403 Mon Sep 17 00:00:00 2001 From: Jon Michael Aanes Date: Fri, 14 Apr 2017 10:56:38 +0200 Subject: [PATCH] Small holes in sequences will now be filled with `nil`, rather than triggering a reclassification to PURE_MAP. --- analyze_structure.lua | 15 ++++++++++++++- pretty.lua | 32 +++++++++++++++++++++++++------- test/test_analyze_structure.lua | 20 ++++++++++++++++++++ 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/analyze_structure.lua b/analyze_structure.lua index 34643c1..89707a9 100644 --- a/analyze_structure.lua +++ b/analyze_structure.lua @@ -112,6 +112,19 @@ 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) @@ -182,7 +195,7 @@ local function get_table_info (t) local key_types = get_key_types(t) local info = {} - info.has_seq = (#t > 0) + 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.is_tabular = is_tabular(t) diff --git a/pretty.lua b/pretty.lua index a514ea5..ff72157 100644 --- a/pretty.lua +++ b/pretty.lua @@ -161,6 +161,16 @@ local function get_key_value_pairs_in_proper_order (t) return key_value_pairs end +local function fill_holes_in_key_value_pairs (key_value_pairs) + -- NOTE: Assumes that all keys are numbers + for i = 2, #key_value_pairs do + for j = key_value_pairs[i-1][1] + 1, key_value_pairs[i][1] - 1 do + key_value_pairs[#key_value_pairs+1] = { j, nil } + end + end + table.sort(key_value_pairs, compare_key_value_pairs) +end + local function nr_elements_in_map (t) local k, count = nil, -1 repeat @@ -355,10 +365,12 @@ local function format_key_and_value_sequence (l, key, value, options, depth) end local TABLE_TYPE_TO_PAIR_FORMAT = { + [TABLE_TYPE.EMPTY] = format_key_and_value_sequence, [TABLE_TYPE.SEQUENCE] = format_key_and_value_sequence, + [TABLE_TYPE.SET] = format_key_and_value_arbitr_map, + [TABLE_TYPE.MIXED] = format_key_and_value_arbitr_map, [TABLE_TYPE.STRING_MAP] = format_key_and_value_string_map, [TABLE_TYPE.PURE_MAP] = format_key_and_value_arbitr_map, - [TABLE_TYPE.MIXED] = format_key_and_value_arbitr_map, } -- Formatting tables @@ -366,8 +378,11 @@ local TABLE_TYPE_TO_PAIR_FORMAT = { local function format_single_line_map (t, options, 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 key_value_pairs = get_key_value_pairs_in_proper_order(t) - local table_type = get_table_type(t) + if table_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] l[#l+1] = '{ ' @@ -388,8 +403,11 @@ end local function format_map (t, options, depth, l) -- TODO: l. + local table_type = l.info[t] and l.info[t].type or get_table_type(t) -- FIXME: This is a temp fix local key_value_pairs = get_key_value_pairs_in_proper_order(t) - local table_type = get_table_type(t) + if table_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] l[#l+1] = '{\n' @@ -427,7 +445,7 @@ function format_table (t, options, depth, l) l.visited[t] = true -- Single line? - if is_single_line_table(t) then format_single_line_map(t, options, l); return end + if is_single_line_table(t) then return format_single_line_map(t, options, l) end if depth == 'max' then l[#l+1] = '{...}'; return end @@ -514,9 +532,9 @@ 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_value) + local formatting = TYPE_TO_FORMAT_FUNC[type(value)] + if formatting then + formatting(value, l.options, depth, l, format_value) else error(ERROR_UNKNOWN_TYPE:format(type(value), tostring(value)), 2) end diff --git a/test/test_analyze_structure.lua b/test/test_analyze_structure.lua index 7b35dd3..82d321e 100644 --- a/test/test_analyze_structure.lua +++ b/test/test_analyze_structure.lua @@ -26,6 +26,26 @@ SUITE:addTest('Sequence', function () assert(table_info.has_map == false) end) +SUITE:addTest('Sequence with holes', function () + local input = { 1, nil, 3 } + local table_info = analyze_structure(input)[input] + + assert(table_info.type == TABLE_TYPE.SEQUENCE, 'Returned bad type: '..table_info.type) + assert(table_info.has_seq == true) + assert(table_info.has_map == false) + assert(table_info.has_holes == true) +end) + +SUITE:addTest('Sequence with hole on start', function () + local input = { nil, 2, 3 } + local table_info = analyze_structure(input)[input] + + assert(table_info.type == TABLE_TYPE.SEQUENCE, 'Returned bad type: '..table_info.type) + assert(table_info.has_seq == true) + assert(table_info.has_map == false) + assert(table_info.has_holes == true) +end) + SUITE:addTest('Pure Map', function () local input = { a = 1, [true] = 2, c = 3 } local table_info = analyze_structure(input)[input]