Shrink elements.lua

As the tables are never modified, any values that are the same can be 
shared.
This commit is contained in:
luk3yx 2021-03-21 20:46:32 +13:00
parent 17503d543b
commit cbfddef14d
3 changed files with 130 additions and 13 deletions

File diff suppressed because one or more lines are too long

View File

@ -26,6 +26,7 @@
# IN THE SOFTWARE.
#
import collections, copy
from decimal import Decimal
def _escape_string(x):
@ -46,18 +47,18 @@ class _PartialTypeError(TypeError):
return 'Object of type ' + repr(type(self.args[0]).__name__) + \
' is not Lua serializable.'
def _dump(obj):
if isinstance(obj, set):
def _dump(obj, dump_func):
if isinstance(obj, (set, frozenset)):
obj = dict.fromkeys(obj, True)
if isinstance(obj, dict):
res = []
for k, v in obj.items():
res.append('[' + _dump(k) + '] = ' + _dump(v))
res.append('[' + dump_func(k) + '] = ' + dump_func(v))
return '{' + ', '.join(res) + '}'
if isinstance(obj, (tuple, list)):
return '{' + ', '.join(map(_dump, obj)) + '}'
return '{' + ', '.join(map(dump_func, obj)) + '}'
if isinstance(obj, bool):
return 'true' if obj else 'false'
@ -82,21 +83,88 @@ def dump(obj):
"""
try:
return _dump(obj)
return _dump(obj, _dump)
except _PartialTypeError as e:
msg = str(e)
# Clean tracebacks
raise TypeError(msg)
def _walk(obj, seen):
yield obj
if isinstance(obj, dict):
for k, v in obj.items():
# yield from _walk(k, seen)
yield from _walk(v, seen)
elif isinstance(obj, (tuple, list, set, frozenset)):
try:
if obj in seen:
return
seen.add(obj)
except TypeError:
pass
for v in obj:
yield from _walk(v, seen)
def _replace_values(obj):
if isinstance(obj, dict):
it = obj.items()
elif isinstance(obj, list):
it = enumerate(obj)
else:
return
for k, v in it:
if isinstance(v, tuple):
new_obj = list(v)
_replace_values(new_obj)
obj[k] = tuple(new_obj)
continue
_replace_values(v)
if isinstance(v, list):
obj[k] = tuple(v)
def serialize(obj):
"""
Serialize an object into valid Lua code. This will raise a TypeError if the
object cannot be serialized into lua.
"""
# Count all tuples
ref_count = collections.Counter()
obj = copy.deepcopy(obj)
_replace_values(obj)
for item in _walk(obj, set()):
if isinstance(item, (tuple, frozenset)):
try:
ref_count[item] += 1
except TypeError:
pass
# This code is heavily inspired by MT's builtin/common/serialize.lua
dumped = {}
res = []
def dump_or_ref(obj2):
try:
count = ref_count[obj2]
except TypeError:
count = 0
if count >= 2:
if obj2 not in dumped:
code = _dump(obj2, dump_or_ref)
idx = len(res) + 1
res.append('a[{}] = {}'.format(idx, code))
dumped[obj2] = idx
return 'a[{}]'.format(dumped[obj2])
return _dump(obj2, dump_or_ref)
try:
return 'return ' + _dump(obj)
res.append('return ' + _dump(obj, dump_or_ref))
if len(res) > 1:
res.insert(0, 'local a = {}')
return '\n'.join(res)
except _PartialTypeError as e:
msg = str(e)

View File

@ -288,12 +288,7 @@ def main():
with open(filename, 'w') as f:
f.write(_comment.lstrip())
f.write(lua_dump.serialize(data))
# elems = fetch_and_parse()
# for elem in sorted(elems):
# for def_ in elems[elem]:
# f.write('formspec_ast.register_element({}, {})\n'.format(
# lua_dump.dump(elem), lua_dump.dump(def_)
# ))
f.write('\n')
print('Done.')
if __name__ == '__main__':