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

P#64776 2019-05-27 07:03 ( Edited 2019-05-27 07:05)

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.

P#64777 2019-05-27 07:08
:: GPI
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.

P#98737 2021-10-16 10:35

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={

}
P#112655 2022-06-03 02:46 ( Edited 2022-06-03 03:19)

@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
P#115997 2022-08-18 22:03 ( Edited 2022-08-18 22:04)
:: luchak
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.

P#115999 2022-08-18 23:26 ( Edited 2022-09-21 19:17)

Does it work with multiple nested tables or only 2?

P#117760 2022-09-21 10:46

[Please log in to post a comment]

Follow Lexaloffle:        
Generated 2022-09-30 16:11:39 | 0.036s | Q:20