dansanderson / picotool

Tools and Python libraries for manipulating Pico-8 game files. http://www.lexaloffle.com/pico-8.php
MIT License
376 stars 45 forks source link

Prunning unused functions and variables #91

Open tupini07 opened 3 years ago

tupini07 commented 3 years ago

First of all thanks for making such a great tool!

This is more of a feasibility question than an actual issue: I was curious about how hard would it be to have build exclude unused functions (and potentially also variables) when building.

I'm sure there are many like me that like to make a library of common functions and reuse it in different games. However, most of the time not all functions are used, which means it is necessary to do some manual cleaning for each game so that only the necessary functions are included (and tokens are saved).

Besides being really helpful to save tokens I think this feature would also enable the creation of more reusable pico8 libraries, where the library can be arbitrarily large, and users can just invoke what they need, and unused stuff will just get pruned during building.

dansanderson commented 3 years ago

Dead code elimination is my holy grail for picotool! 🌟 The intent is for the parser to be powerful enough to make changes directly to the AST, then write it back out as text, preserving as much of the original as is desired. The build step can do "token optimization:" perform data flow analysis to identify globals and constants, do build-time evaluation of constant expressions, and remove unused definitions and branches.

My original intent was to improve the parser before diving into this. The current parser is weak and difficult to maintain, more of a proof of concept than something I'd want to do dataflow analysis with. But yes it should be feasible.

Before:

-- get draw_tile() routine:
#include "tilestuff.lua"

player_x=40
player_y=50
player_sprite=7

debug_mode=false
show_debug_markers=true
function draw_debug_marker(tilenum) ... end

function _update()
  if (btn(1)) player_x += 1
  if (btn(2)) player_y += 1
  -- etc.
end

function _draw()
  for tile=1,5 do
    if debug_mode and show_debug_markers then
      draw_debug_marker(tile)
    end
    draw_tile(tile)
  end
  spr(player_sprite, player_x, player_y)
end

After token and character optimization (approximately):

function a(b) ... end
c=40
d=50
function _update()
if(btn(1))c+=1
if(btn(2))d+=1
end
function _draw()
for e=1,5 do
a(e)
end
spr(7,c,d)
end

Support for token optimized library use is the chief motivation, 100% agreed!

GiovanH commented 3 years ago

Support for constants would be HUGE. That might not even require any further analysis steps; you could just mark variables as constant with a magic comment and let the same preprocessor that deals with require substitute it out.