From: Petr Špaček Date: Fri, 17 Jul 2020 07:58:54 +0000 (+0200) Subject: krprint: reuse serialization infrastructure for pretty-printer X-Git-Tag: v5.2.0~4^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb312263e9e8f9623d1ebc36c907263ef3fe9836;p=thirdparty%2Fknot-resolver.git krprint: reuse serialization infrastructure for pretty-printer At the moment it does not handle functions and other non-serializable types. --- diff --git a/daemon/lua/krprint.lua b/daemon/lua/krprint.lua index 2ae9f4ec0..0f9cfc803 100644 --- a/daemon/lua/krprint.lua +++ b/daemon/lua/krprint.lua @@ -1,13 +1,10 @@ -- SPDX-License-Identifier: GPL-3.0-or-later - -local serializer_class = { - __inst_mt = {} +local base_class = { + cur_indent = 0, } --- class instances with following metatable inherit all class members -serializer_class.__inst_mt.__index = serializer_class --- constructor -function serializer_class.new(on_unrepresentable) +-- shared constructor: use as serializer_class:new() +function base_class.new(class, on_unrepresentable) on_unrepresentable = on_unrepresentable or 'comment' if not (on_unrepresentable == 'comment' or on_unrepresentable == 'error') then @@ -16,12 +13,12 @@ function serializer_class.new(on_unrepresentable) local inst = {} inst.on_unrepresentable = on_unrepresentable inst.done = {} - setmetatable(inst, serializer_class.__inst_mt) + setmetatable(inst, class.__inst_mt) return inst end -- format comment with leading/ending whitespace if needed -local function format_note(note, ws_prefix, ws_suffix) +function base_class.format_note(self, note, ws_prefix, ws_suffix) if note == nil then return '' else @@ -30,13 +27,19 @@ local function format_note(note, ws_prefix, ws_suffix) end end -local function static_serializer(val, on_unrepresentable) - local inst = serializer_class.new(on_unrepresentable) - local expr, note = inst:val2expr(val) - return string.format('%s%s', format_note(note, nil, ' '), expr) +function base_class.indent_head(self) + return string.rep(' ', self.cur_indent) end -function serializer_class.val2expr(self, val) +function base_class.indent_inc(self) + self.cur_indent = self.cur_indent + self.indent_step +end + +function base_class.indent_dec(self) + self.cur_indent = self.cur_indent - self.indent_step +end + +function base_class.val2expr(self, val) local val_type = type(val) local val_repr = self[val_type] if val_repr then @@ -50,12 +53,14 @@ function serializer_class.val2expr(self, val) end end -serializer_class['nil'] = function(_, val) +-- "nil" is a Lua keyword so assignment below is workaround to create +-- function base_class.nil(self, val) +base_class['nil'] = function(_, val) assert(type(val) == 'nil') return 'nil' end -function serializer_class.number(_, val) +function base_class.number(_, val) assert(type(val) == 'number') if val == math.huge then return 'math.huge' @@ -68,7 +73,7 @@ function serializer_class.number(_, val) end end -function serializer_class.string(_, val) +function base_class.string(_, val) assert(type(val) == 'string') val = tostring(val) local chars = {'\''} @@ -86,12 +91,12 @@ function serializer_class.string(_, val) return table.concat(chars) end -function serializer_class.boolean(_, val) +function base_class.boolean(_, val) assert(type(val) == 'boolean') return tostring(val) end -function serializer_class.table(self, tab) +function base_class.table(self, tab) assert(type(tab) == 'table') if self.done[tab] then error('cyclic reference', 0) @@ -100,6 +105,7 @@ function serializer_class.table(self, tab) local items = {'{'} local previdx = 0 + self:indent_inc() for idx, val in pairs(tab) do local errors, valok, valexpr, valnote, idxok, idxexpr, idxnote errors = {} @@ -127,14 +133,15 @@ function serializer_class.table(self, tab) end end + local item = '' if #errors == 0 then -- finally serialize one [key=]?value expression + local indent = self:indent_head() if addidx then - table.insert(items, - string.format('%s[%s]', format_note(idxnote, nil, ' '), idxexpr)) - table.insert(items, '=') + item = string.format('%s%s[%s]%s=%s', indent, self:format_note(idxnote, nil, self.key_val_sep), idxexpr, self.key_val_sep, self.key_val_sep) + indent = '' end - table.insert(items, string.format('%s%s,', format_note(valnote, nil, ' '), valexpr)) + item = item .. string.format('%s%s%s,', indent, self:format_note(valnote, nil, self.item_sep), valexpr) else local errmsg = string.format('%s = %s (%s)', tostring(idx), @@ -144,12 +151,44 @@ function serializer_class.table(self, tab) error(errmsg, 0) else errmsg = string.format('--[[ missing %s ]]', errmsg) - table.insert(items, errmsg) + item = errmsg end end + table.insert(items, item) end -- one key+value - table.insert(items, '}') - return table.concat(items, ' '), string.format('%s follows', tab) + self:indent_dec() + table.insert(items, self:indent_head() .. '}') + return table.concat(items, self.item_sep), string.format('%s follows', tab) +end + +local serializer_class = { + indent_step = 0, + item_sep = ' ', + key_val_sep = ' ', + __inst_mt = {} +} +-- inhertance form base class (for :new()) +setmetatable(serializer_class, { __index = base_class }) +-- class instances with following metatable inherit all class members +serializer_class.__inst_mt.__index = serializer_class + +local function static_serializer(val, on_unrepresentable) + local inst = serializer_class:new(on_unrepresentable) + local expr, note = inst:val2expr(val) + return string.format('%s%s', inst:format_note(note, nil, inst.item_sep), expr) + end + +local pprinter_class = { + indent_step = 4, + item_sep = '\n', + key_val_sep = ' ', + __inst_mt = {}, + format_note = function() return '' end, +} + +-- default tostring method is better suited for human-intended output +function pprinter_class.number(_, number) + return tostring(number) end local function deserialize_lua(serial) @@ -161,9 +200,19 @@ local function deserialize_lua(serial) return deserial_func() end +setmetatable(pprinter_class, { __index = base_class }) +pprinter_class.__inst_mt.__index = pprinter_class + +local function static_pprint(val, on_unrepresentable) + local inst = pprinter_class:new(on_unrepresentable) + local expr, note = inst:val2expr(val) + return string.format('%s%s', inst:format_note(note, nil, inst.item_sep), expr) +end + local M = { serialize_lua = static_serializer, - deserialize_lua = deserialize_lua + deserialize_lua = deserialize_lua, + pprint = static_pprint } return M