Log In  


I wrote this library to cut down on the number of tokens taken up by large tables with string data, e.g. for dialogue text/translations/etc. Most helpful if those tokens are using a lot of your tokens (i.e. more than 150), since the library itself takes up 139 tokens. But all your table declarations can be reduced to 5 tokens each!

Here's an example of what your code can look like.

Before:

my_table = {
  hello='world',
  nested={
    some='data\'s nested',
    inside_of='here'
  },
  'and',
  'indexed',
  'data',
  { as='well' }
}

After:

function table_from_string(str)
  local tab, is_key = {}, true
  local key,val,is_on_key
  local function reset()
    key,val,is_on_key = '','',true
  end
  reset()
  local i, len = 1, #str
  while i <= len do
    local char = sub(str, i, i)
    -- token separator
    if char == '\31' then
      if is_on_key then
        is_on_key = false
      else
        tab[tonum(key) or key] = val
        reset()
      end
    -- subtable start
    elseif char == '\29' then
      local j,c = i,''
      -- checking for subtable end character
      while (c ~= '\30') do
        j = j + 1
        c = sub(str, j, j)
      end
      tab[tonum(key) or key] = table_from_string(sub(str,i+1,j-1))
      reset()
      i = j
    else
      if is_on_key then
        key = key..char
      else
        val = val..char
      end
    end
    i = i + 1
  end
  return tab
end

my_table=
table_from_string(
 '1�and�2�indexed�3�data�4�as�well��hello�world�nested�inside_of�here�some�data\'s nested��'
)

Clearly it's more helpful if your data table is much larger than this. In my case, my data tables took up almost 200 tokens, and I saved about 50 using this technique. If I go to add more translations in the future, it will save even more.

https://github.com/benwiley4000/pico8-table-string

4


And no I wouldn't suggest keeping this compressed version as your only record of your data table, of course! For my own workflow, I am setting up an automated script to take my data table from a separate Lua file and periodically update the contents of the p8 file with the stringified version.


2
-- print out a table - for debug
function tableout(t,deep)
 deep=deep or 0
 local str=sub("    ",1,deep)
 print(str.."table size: "..#t) 
 for k,v in pairs(t) do
   if type(v)=="table" then
     print(str..tostr(k).."[]")
     tableout(v,deep+1)
   else
     print(str..tostr(k).." = "..tostr(v))
   end
 end
end

-- convert a string to a table
function str2table(str)
 local out,s={}
 add(out,{})
 for l in all(split(str,"\n")) do
  while ord(l)==9 or ord(l)==32 do
    l=sub(l,2)
  end  
  if l~="" then
   s=split(l,"=")
   if (#s==1) s[1]=#out[#out]+1 s[2]=l
   if (s[2]=="{") s[2]={}
   if s[2]=="}" then
     deli(out)
   else
    out[#out][s[1]]=s[2]
    if (type(s[2])=="table") add(out,s[2])
   end
  end
 end
 return out[1]
end

table2=str2table([[
hello=world
something

{
	a=10
	b=20
	c=30
	doda
	{
		doublenest
	}
}

and
indexed
nestedkey={
  something
}
]])
cls()
tableout(table2)
print("---")

My Variant :)
It use a multi-line-String and a more lua-like syntax. So it is easier change- and readable. Disadvantage is, that it don't allow escape-sequenzes like \n \r.


Can the functionality of these things be expanded to cover cases:

var=true
function add_enemy(x,y)
  obj={r=rnd(100),x=x or 100, y=var and 11 or 63, apples={}}
end

So we have extraneous local var (upvalue) x, global variable var, and/or, function call rnd().
apples is covered it 'has to' be formatted like this is my understanding? can I make it just like apples={} ?

apples={

}

@GPI you can save another token by swapping from for-loop to foreach().

function str2table(str)
 local out,s={}
 add(out,{})

foreach(split(str,"\n"), function(l)

 -- for l in all(split(str,"\n")) do
  while ord(l)==9 or ord(l)==32 do
    l=sub(l,2)
  end  
  if l~="" then
   s=split(l,"=")
   if (#s==1) s[1]=#out[#out]+1 s[2]=l
   if (s[2]=="{") s[2]={}
   if s[2]=="}" then
     deli(out)
   else
    out[#out][s[1]]=s[2]
    if (type(s[2])=="table") add(out,s[2])
   end
  end
 -- end
		end) 

 return out[1]
end
--127

1

@Cerb043_4 yup, you can absolutely do stuff like that, but it'll take a lot more than 139 tokens to set up. I've got a project that has some stuff that looks like this:

eval[[
(set rep (fn (n x)
 (let a (pack))
 (for 1 $n (fn () (add $a $x)))
 $a
))

(set pat_param_idx (' {b0=11,b1=27,dr=43}))

(set syn_pat_template (' {
 nt=`(rep 16 19)
 dt=`(rep 16 64)
 st=`(rep 16 64)
 l=16
}))
]]

You can take a look at the implementation in https://github.com/luchak/rp8/blob/main/src/utils.lua . There's some weirdness / edge cases, particularly with nil and multivalues, but it mostly works as you'd expect.

There's also https://www.lexaloffle.com/bbs/?tid=47403 which implements something similar (with two different interpreters for different speed/token tradeoffs!), but it hasn't had as many bugfixes as the actually-in-use code I linked above, and also mishandles nested scopes in some unfortunate ways. I'll probably want to reconcile all of these implementations at some point.


Does it work with multiple nested tables or only 2?



[Please log in to post a comment]