PoorCosmo [Lexaloffle Blog Feed]https://www.lexaloffle.com/bbs/?uid=76933 Stringify tables, including tables with tables as keys <p>This is some code I wrote to nicely stringify tables. This code started life as a <code>printh()</code> replacement that output directly to the console, but I rewrote it as seen below so it can be used in other contexts.</p> <p>The <code>strngfy()</code> function can produce either indented, multi-line code, or single-line compact output. Both scalar values and tables are supported as both keys and values.</p> <p>The <code>rptsp()</code> and <code>tcnt()</code> functions are support functions used by <code>strngfy()</code>, but they also have utility as stand-alone functions.</p> <p>The code is probably not particularly elegant, but it works for the scenarios I tested. There are some comments in the code to help users get started. All lines fit within the line-width of Pico-8's built-in editor.</p> <p>The code is 238 tokens.</p> <p>I'm new to both Pico-8 and Lua, so if I did something the hard way, or missed some tricks, or if you find bugs, let me know.</p> <p>Updates</p> <ul> <li>04/25/2023 <ul> <li>Updated function to format function types in table</li> </ul></li> <li>04/30/2023 <ul> <li>Same thing for booleans. Code is now 246 tokens.</li> <li>Shaved a few tokens by combining assignments. Code is now 238 tokens.</li> </ul></li> <li>05/02/2023 <ul> <li>Turns out nils exist. Code no longer chokes if you pass it a nil type.</li> </ul></li> </ul> <p>The code:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>-- t=table -- cm=compact output. if true, -- no newlines or indentation -- are added. -- ind=indent size -- l=indent level -- lst=last item in table? -- in practice, you only need -- to provide the first -- argument. the others are for -- tweaking output spacing -- (ind and l) and, in the case -- of lst, for internal use by -- the function . -- does not currently handle -- recursive tables, so be -- careful not to create -- infinite loops in any tables -- you send to this function. function strngfy(t,co,ind,l,lst) -- make sure ind, l, lst, and -- co have sane values. prep -- some other variables for -- use. we're shadowing ind, -- but i don't think it should -- matter under any reasonable -- set of assumptions. local ind,l,lst,co,tp,st =max(ind or 2,ind),l and l or 0,lst or false,co or false ,type(t),&quot;&quot; -------- l=co and 0 or l+1 local sp=rptsp(l*ind) if tp=='table' then local cnt=tcnt(t) st..=&quot;{&quot;..(co and &quot;&quot; or &quot;\n&quot;) -- order is not guaranteed, so -- two executions of this loop -- on the same table might -- produce two different -- orders of the keys in the -- output. -- ipairs() does guarantee -- order, but only iterates -- over consecutive numerical -- indices, and is therefore -- useless if we want to deal -- with sparsely-keyed tables, -- or tables which can have -- other tables for keys. for k,v in next,t do st..=sp..&quot;[&quot;..strngfy(k,co, ind,l,cnt&gt;1)..&quot;] =&gt; &quot;.. strngfy(v,co,ind,l,cnt&gt;1) ..(cnt&gt;1 and &quot;,&quot;..(co and &quot;&quot; or &quot;\n&quot;) or &quot;&quot;) cnt-=1 end l-=1 local sp=rptsp(l*ind) st..=(co and &quot;&quot; or &quot;\n&quot;)..sp ..&quot;}&quot;..(cnt &gt; 1 and &quot;,&quot; or &quot;&quot;) else st..=tp==&quot;function&quot; and &quot;&lt;function&gt;&quot; or tp==&quot;boolean&quot; and t==true and &quot;true&quot; or t==false and &quot;false&quot; or tp==&quot;nil&quot; and &quot;nil&quot; or t end return st end -- a special case of rptchr() -- that only produces spaces. function rptsp(c) c=c&gt;0 and c or 0 s=&quot;&quot; for i=1,c do s..=&quot; &quot; end return s end -- insanity, but as far as i can -- tell, this is the only way to -- get the number of entries in -- a table that doesn't have -- contiguous numerical keys. function tcnt(t) if type(t) ~= &quot;table&quot; then -- to remove ambiguity -- between this and a table -- with no entries. return -1 end local cnt=0 for _ in pairs(t) do cnt+=1 end return cnt end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Example usage:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>tablekey={thisisakey=&quot;asdf&quot;,thisisanotherkey=&quot;fdsa&quot;} itable={thisis=&quot;an internal table&quot;, witha=tinternaltable} tablekey[itable]={yetanother=&quot;table&quot;} tinternaltable={tintkey=&quot;tintvalue&quot;} tablekey[itable][tinternaltable] = &quot;final&quot; table={} table[tablekey]=&quot;some value&quot; table.stringkey=&quot;stringkey value&quot; omt={onemore=&quot;table&quot;,withsome=&quot;values&quot;,includingint=128,float=2.24} omtv={okthis=&quot;is the last one&quot;, i={pinky=&quot;promise&quot;}} table.stringkeyb={ stkb=&quot;a value in a table&quot;, stkc=32, stkd={}, stke={} } table.stringkeyb.stke[omt]=omtv printh(strngfy(table))</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Output:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>{ [stringkey] =&gt; stringkey value, [stringkeyb] =&gt; { [stke] =&gt; { [{ [includingint] =&gt; 128, [float] =&gt; 2.24, [onemore] =&gt; table, [withsome] =&gt; values }] =&gt; { [okthis] =&gt; is the last one, [i] =&gt; { [pinky] =&gt; promise } } }, [stkd] =&gt; { }, [stkc] =&gt; 32, [stkb] =&gt; a value in a table }, [{ [thisisanotherkey] =&gt; fdsa, [{ [thisis] =&gt; an internal table }] =&gt; { [{ [tintkey] =&gt; tintvalue }] =&gt; final, [yetanother] =&gt; table }, [thisisakey] =&gt; asdf }] =&gt; some value }</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>This code is released under the &quot;Do whatever you want with it, I don't care&quot; license, although I'd like to hear about it if you find it useful.</p> https://www.lexaloffle.com/bbs/?tid=52510 https://www.lexaloffle.com/bbs/?tid=52510 Tue, 25 Apr 2023 00:06:58 UTC