diff --git a/analyze_structure.lua b/analyze_structure.lua index 0d09cf1..b29b840 100644 --- a/analyze_structure.lua +++ b/analyze_structure.lua @@ -24,6 +24,14 @@ local RESERVED_LUA_WORDS = { ['goto'] = true, } +local SIMPLE_VALUE_TYPES = { + ['nil'] = true, + ['boolean'] = true, + ['number'] = true, +} + +local SHORT_STRING_MAX_LEN = 7 + -------------------------------------------------------------------------------- local function is_identifier(str) @@ -131,6 +139,34 @@ local function is_tabular (t) return true end +local is_short_table, is_simple_value + +function is_short_table (value) + -- Predicate: value is either an empty table, or one with a single simple + -- non-function element. + + assert( type(value) == 'table', '[analyze_structure]: Only tables allowed!' ) + + local first_key = next(value, nil) + if not first_key then + return true + elseif not next(value, first_key) == nil then + return false + end + + return type(value[first_key]) ~= 'table' + and is_simple_value( value[first_key] ) +end + +function is_simple_value (value) + -- Predicate: value is either nil, a boolean, a number, a short string or a + -- short table. + + return SIMPLE_VALUE_TYPES[ type(value) ] + or type(value) == 'string' and #value <= SHORT_STRING_MAX_LEN + or type(value) == 'table' and is_short_table(value) +end + -------------------------------------------------------------------------------- local function get_table_info (t) @@ -141,6 +177,7 @@ local function get_table_info (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) + info.is_short = is_short_table(t) -- Determine type of table if not info.has_seq and not info.has_map then info.type = 'empty' diff --git a/test/test_analyze_structure.lua b/test/test_analyze_structure.lua index e518c03..e636c8c 100644 --- a/test/test_analyze_structure.lua +++ b/test/test_analyze_structure.lua @@ -84,6 +84,48 @@ SUITE:addTest('Not Tabular, due to varying lengths', function () assert(table_info.is_tabular == false) end) +SUITE:addTest('Very short/empty table', function () + local input = { } + local table_info = analyze_structure(input)[input] + + assert(table_info.is_short == true) +end) + +SUITE:addTest('Very short table', function () + local input = { 1 } + local table_info = analyze_structure(input)[input] + + assert(table_info.is_short == true) +end) + +SUITE:addTest('Recursive tables are not simple', function () + local input = { {} } + local table_info = analyze_structure(input)[input] + + assert(table_info.is_short == false) +end) + +SUITE:addTest('Short strings are simple', function () + local input = { 'hello' } + local table_info = analyze_structure(input)[input] + + assert(table_info.is_short == true) +end) + +SUITE:addTest('Long strings are not', function () + local input = { 'hello world' } + local table_info = analyze_structure(input)[input] + + assert(table_info.is_short == false) +end) + +SUITE:addTest('Even maps can be simple!', function () + local input = { a = 4 } + local table_info = analyze_structure(input)[input] + + assert(table_info.is_short == true) +end) + -------------------------------------------------------------------------------- -- Corner cases.