diff --git a/src/lua/extra.cc b/src/lua/extra.cc index 5c4a1bb3..f9bd0e69 100644 --- a/src/lua/extra.cc +++ b/src/lua/extra.cc @@ -38,9 +38,12 @@ void PCSX::LuaFFI::open_extra(Lua L) { luaopen_pb_unsafe(L.getState()); L.setfield("pb.unsafe"); - static int lualoader = 6; + static int lualoader = 7; static const char* pprint = ( #include "pprint.lua/pprint.lua" + ); + static const char* pprint_internals = ( +#include "pprint.lua/pprint-internals.lua" ); static const char* reflectFFI = ( #include "ffi-reflect/reflect.lua" @@ -58,6 +61,7 @@ void PCSX::LuaFFI::open_extra(Lua L) { #include "lua-protobuf/protoc.lua" ); L.load(pprint, "internal:pprinter.lua/pprint.lua"); + L.load(pprint_internals, "internal:pprinter.lua/pprint-internals.lua"); L.load(reflectFFI, "internal:ffi-reflect/reflect.lua"); L.load(protobufLexer, "internal:lua-protobuf/lexer.lua"); diff --git a/third_party/pprint.lua/pprint-internals.lua b/third_party/pprint.lua/pprint-internals.lua new file mode 100644 index 00000000..b84acc60 --- /dev/null +++ b/third_party/pprint.lua/pprint-internals.lua @@ -0,0 +1,127 @@ +--lualoader, R"EOF(-- + +-- seems this is the only way to escape these, as lua don't know how to map char '\a' to 'a' +local ESCAPE_MAP = { + ['\a'] = '\\a', ['\b'] = '\\b', ['\f'] = '\\f', ['\n'] = '\\n', ['\r'] = '\\r', + ['\t'] = '\\t', ['\v'] = '\\v', ['\\'] = '\\\\', +} + +-- generic utilities +pprint._internals.tokenize_string = function(s) + local t = {} + for i = 1, #s do + local c = s:sub(i, i) + local b = c:byte() + local e = ESCAPE_MAP[c] + if (b >= 0x20 and b < 0x80) or e then + local s = e or c + t[i] = { char = s, len = #s } + else + t[i] = { char = string.format('\\x%02x', b), len = 4 } + end + if c == '"' then + t.has_double_quote = true + elseif c == "'" then + t.has_single_quote = true + end + end + return t +end +pprint._internals.tokenize_utf8_string = tokenize_string + +local has_lpeg, lpeg = pcall(require, 'lpeg') + +if has_lpeg then + local function utf8_valid_char(c) + return { char = c, len = 1 } + end + + local function utf8_invalid_char(c) + local b = c:byte() + local e = ESCAPE_MAP[c] + if (b >= 0x20 and b < 0x80) or e then + local s = e or c + return { char = s, len = #s } + else + return { char = string.format('\\x%02x', b), len = 4 } + end + end + + local cont = lpeg.R('\x80\xbf') + local utf8_char = + lpeg.R('\x20\x7f') + + lpeg.R('\xc0\xdf') * cont + + lpeg.R('\xe0\xef') * cont * cont + + lpeg.R('\xf0\xf7') * cont * cont * cont + + local utf8_capture = (((utf8_char / utf8_valid_char) + (lpeg.P(1) / utf8_invalid_char)) ^ 0) * -1 + + pprint._internals.tokenize_utf8_string = function(s) + local dq = s:find('"') + local sq = s:find("'") + local t = table.pack(utf8_capture:match(s)) + t.has_double_quote = not not dq + t.has_single_quote = not not sq + return t + end +end + +local CACHE_TYPES = { + ['table'] = true, ['function'] = true, ['thread'] = true, + ['userdata'] = true, ['cdata'] = true, +} + +-- cache would be populated to be like: +-- { +-- function = { `fun1` = 1, _cnt = 1 }, -- object id +-- table = { `table1` = 1, `table2` = 2, _cnt = 2 }, +-- visited_tables = { `table1` = 7, `table2` = 8 }, -- visit count +-- } +-- use weakrefs to avoid accidentall adding refcount +pprint._internals.cache_apperance = function(obj, cache, option) + if not cache.visited_tables then + cache.visited_tables = setmetatable({}, {__mode = 'k'}) + end + local t = type(obj) + + -- TODO can't test filter_function here as we don't have the ix and key, + -- might cause different results? + -- respect show_xxx and filter_function to be consistent with print results + if (not pprint._internals.TYPES[t] and not option.show_table) + or (pprint._internals.TYPES[t] and not option['show_'..t]) then + return + end + + if CACHE_TYPES[t] or pprint._internals.TYPES[t] == nil then + if not cache[t] then + cache[t] = setmetatable({}, {__mode = 'k'}) + cache[t]._cnt = 0 + end + if not cache[t][obj] then + cache[t]._cnt = cache[t]._cnt + 1 + cache[t][obj] = cache[t]._cnt + end + end + if t == 'table' or pprint._internals.TYPES[t] == nil then + if cache.visited_tables[obj] == false then + -- already printed, no need to mark this and its children anymore + return + elseif cache.visited_tables[obj] == nil then + cache.visited_tables[obj] = 1 + else + -- visited already, increment and continue + cache.visited_tables[obj] = cache.visited_tables[obj] + 1 + return + end + for k, v in pairs(obj) do + pprint._internals.cache_apperance(k, cache, option) + pprint._internals.cache_apperance(v, cache, option) + end + local mt = getmetatable(obj) + if mt and option.show_metatable then + pprint._internals.cache_apperance(mt, cache, option) + end + end +end + +-- )EOF" diff --git a/third_party/pprint.lua/pprint.lua b/third_party/pprint.lua/pprint.lua index 82466051..f5820c43 100644 --- a/third_party/pprint.lua/pprint.lua +++ b/third_party/pprint.lua/pprint.lua @@ -4,6 +4,8 @@ pprint = { VERSION = '0.1' } local depth = 1 +pprint._internals = {} + pprint.defaults = { -- If set to number N, then limit table recursion to N deep. depth_limit = false, @@ -34,140 +36,16 @@ pprint.defaults = { sort_keys = true, -- sort table keys } -local TYPES = { +pprint._internals.TYPES = { ['nil'] = 1, ['boolean'] = 2, ['number'] = 3, ['string'] = 4, ['table'] = 5, ['function'] = 6, ['thread'] = 7, ['userdata'] = 8, ['cdata'] = 9, } --- seems this is the only way to escape these, as lua don't know how to map char '\a' to 'a' -local ESCAPE_MAP = { - ['\a'] = '\\a', ['\b'] = '\\b', ['\f'] = '\\f', ['\n'] = '\\n', ['\r'] = '\\r', - ['\t'] = '\\t', ['\v'] = '\\v', ['\\'] = '\\\\', -} - --- generic utilities -local tokenize_string = function(s) - local t = {} - for i = 1, #s do - local c = s:sub(i, i) - local b = c:byte() - local e = ESCAPE_MAP[c] - if (b >= 0x20 and b < 0x80) or e then - local s = e or c - t[i] = { char = s, len = #s } - else - t[i] = { char = string.format('\\x%02x', b), len = 4 } - end - if c == '"' then - t.has_double_quote = true - elseif c == "'" then - t.has_single_quote = true - end - end - return t -end -local tokenize_utf8_string = tokenize_string - -local has_lpeg, lpeg = pcall(require, 'lpeg') - -if has_lpeg then - local function utf8_valid_char(c) - return { char = c, len = 1 } - end - - local function utf8_invalid_char(c) - local b = c:byte() - local e = ESCAPE_MAP[c] - if (b >= 0x20 and b < 0x80) or e then - local s = e or c - return { char = s, len = #s } - else - return { char = string.format('\\x%02x', b), len = 4 } - end - end - - local cont = lpeg.R('\x80\xbf') - local utf8_char = - lpeg.R('\x20\x7f') + - lpeg.R('\xc0\xdf') * cont + - lpeg.R('\xe0\xef') * cont * cont + - lpeg.R('\xf0\xf7') * cont * cont * cont - - local utf8_capture = (((utf8_char / utf8_valid_char) + (lpeg.P(1) / utf8_invalid_char)) ^ 0) * -1 - - tokenize_utf8_string = function(s) - local dq = s:find('"') - local sq = s:find("'") - local t = table.pack(utf8_capture:match(s)) - t.has_double_quote = not not dq - t.has_single_quote = not not sq - return t - end -end - local function is_plain_key(key) return type(key) == 'string' and key:match('^[%a_][%a%d_]*$') end -local CACHE_TYPES = { - ['table'] = true, ['function'] = true, ['thread'] = true, - ['userdata'] = true, ['cdata'] = true, -} - --- cache would be populated to be like: --- { --- function = { `fun1` = 1, _cnt = 1 }, -- object id --- table = { `table1` = 1, `table2` = 2, _cnt = 2 }, --- visited_tables = { `table1` = 7, `table2` = 8 }, -- visit count --- } --- use weakrefs to avoid accidentall adding refcount -local function cache_apperance(obj, cache, option) - if not cache.visited_tables then - cache.visited_tables = setmetatable({}, {__mode = 'k'}) - end - local t = type(obj) - - -- TODO can't test filter_function here as we don't have the ix and key, - -- might cause different results? - -- respect show_xxx and filter_function to be consistent with print results - if (not TYPES[t] and not option.show_table) - or (TYPES[t] and not option['show_'..t]) then - return - end - - if CACHE_TYPES[t] or TYPES[t] == nil then - if not cache[t] then - cache[t] = setmetatable({}, {__mode = 'k'}) - cache[t]._cnt = 0 - end - if not cache[t][obj] then - cache[t]._cnt = cache[t]._cnt + 1 - cache[t][obj] = cache[t]._cnt - end - end - if t == 'table' or TYPES[t] == nil then - if cache.visited_tables[obj] == false then - -- already printed, no need to mark this and its children anymore - return - elseif cache.visited_tables[obj] == nil then - cache.visited_tables[obj] = 1 - else - -- visited already, increment and continue - cache.visited_tables[obj] = cache.visited_tables[obj] + 1 - return - end - for k, v in pairs(obj) do - cache_apperance(k, cache, option) - cache_apperance(v, cache, option) - end - local mt = getmetatable(obj) - if mt and option.show_metatable then - cache_apperance(mt, cache, option) - end - end -end - -- makes 'foo2' < 'foo100000'. string.sub makes substring anyway, no need to use index based method local function str_natural_cmp(lhs, rhs) while #lhs > 0 and #rhs > 0 do @@ -201,8 +79,8 @@ local function cmp(lhs, rhs) if tleft == tright then return str_natural_cmp(tostring(lhs), tostring(rhs)) end -- allow custom types - local oleft = TYPES[tleft] or 10 - local oright = TYPES[tright] or 10 + local oleft = pprint._internals.TYPES[tleft] or 10 + local oright = pprint._internals.TYPES[tright] or 10 return oleft < oright end @@ -216,7 +94,7 @@ local function make_option(option) option[k] = v end if option.show_all then - for t, _ in pairs(TYPES) do + for t, _ in pairs(pprint._internals.TYPES) do option['show_'..t] = true end option.show_metatable = true @@ -324,7 +202,7 @@ function pprint.pformat(obj, option, printer) end local function string_formatter(s, force_long_quote) - local tokens = option.string_is_utf8 and tokenize_utf8_string(s) or tokenize_string(s) + local tokens = option.string_is_utf8 and pprint._internals.tokenize_utf8_string(s) or pprint._internals.tokenize_string(s) local string_len = 0 local escape_quotes = tokens.has_double_quote and tokens.has_single_quote for _, token in ipairs(tokens) do @@ -555,7 +433,7 @@ function pprint.pformat(obj, option, printer) if option.object_cache then -- needs to visit the table before start printing - cache_apperance(obj, cache, option) + pprint._internals.cache_apperance(obj, cache, option) end _p(format(obj)) diff --git a/vsprojects/Lua/Lua.vcxproj b/vsprojects/Lua/Lua.vcxproj index c4a219da..4b1a5d1b 100644 --- a/vsprojects/Lua/Lua.vcxproj +++ b/vsprojects/Lua/Lua.vcxproj @@ -68,6 +68,7 @@ + diff --git a/vsprojects/Lua/Lua.vcxproj.filters b/vsprojects/Lua/Lua.vcxproj.filters index d723befa..ae9386e2 100644 --- a/vsprojects/Lua/Lua.vcxproj.filters +++ b/vsprojects/Lua/Lua.vcxproj.filters @@ -56,7 +56,7 @@ Header Files - + Header Files @@ -113,5 +113,8 @@ Source Files + + Source Files + \ No newline at end of file