├── .gitignore ├── .luarocks └── config-5.3.lua ├── LICENSE ├── README.md ├── luarocks ├── pico8-to-lua-0.1.0-1.rockspec └── pico8-to-lua.lua /.gitignore: -------------------------------------------------------------------------------- 1 | /lua 2 | /lua_modules 3 | -------------------------------------------------------------------------------- /.luarocks/config-5.3.lua: -------------------------------------------------------------------------------- 1 | -- LuaRocks configuration for use with Lua 5.3 2 | lua_interpreter = "lua5.3" 3 | variables = { 4 | LUA_DIR = "/usr", 5 | LUA_INCDIR = "/usr/include/lua5.3", 6 | LUA_LIBDIR = "/usr/lib/x86_64-linux-gnu", 7 | LUA_BINDIR = "/usr/bin", 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Jez Kabanov 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgement in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pico8-to-lua 2 | 3 | A command-line utility written in Lua that converts the [PICO-8](https://www.lexaloffle.com/pico-8.php) variety of extended Lua syntax to standard Lua syntax. 4 | 5 | It's a thin wrapper around the internal syntax converter from [PICOLOVE](https://github.com/picolove/picolove). 6 | 7 | Reasons you might find this useful: 8 | - You want to run a tool built for Lua on your code, and the tool won't recognize it because you're using special PICO-8 syntax 9 | - You want better syntax highlighting support in your text editor 10 | - You want to extract a function you wrote for PICO-8 and use it in a different Lua program 11 | 12 | ### You might also try... 13 | 14 | While I was working on this project, [picotool](https://github.com/dansanderson/picotool) was updated to support a `--pure-lua` argument to its `listlua` command, which will do roughly the same thing as this! 15 | 16 | ## Installation 17 | 18 | 1. Install [Lua](https://www.lua.org/start.html) for your operating system. This doesn't come with PICO-8, which has its own Lua compiler, so you'll need to install Lua separately. 19 | 2. You can either: 20 | 21 | a. Install with [LuaRocks](https://luarocks.org/): 22 | ```console 23 | $ luarocks install pico8-to-lua 24 | ``` 25 | 26 | b. Clone the repository from GitHub and enter the project directory: 27 | ```console 28 | $ git clone https://github.com/benwiley4000/pico8-to-lua.git 29 | $ cd pico-to-lua/ 30 | ``` 31 | 32 | ## Usage 33 | 34 | > ***NOTE:*** All the examples assume you have installed `pico-to-lua` globally, but if you're using it from inside the cloned directory, you can replace all instances of `pico8-to-lua` with `./pico8-to-lua.lua` (or `lua pico8-to-lua.lua` for non-UNIX environments) in the commands that you run. 35 | 36 | Assuming you have an input Lua file that looks like this: 37 | 38 | ```lua 39 | -- input.lua 40 | function next_even_number(num) 41 | if (num % 2 != 0) num += 1 42 | return num 43 | end 44 | ``` 45 | 46 | You can generate a standard Lua version with the command: 47 | 48 | ```console 49 | $ pico8-to-lua input.lua 50 | ``` 51 | 52 | You should see this output: 53 | 54 | ```lua 55 | function next_even_number(num) 56 | if num % 2 ~= 0 then num = num + 1 end 57 | return num 58 | end 59 | ``` 60 | 61 | You can also use a `.p8` file as input... 62 | 63 | ```lua 64 | pico-8 cartridge // http://www.pico-8.com 65 | version 16 66 | __lua__ 67 | function _init() 68 | local num = 0b10 69 | if (num+1==0b11) print('yes!') 70 | end 71 | ``` 72 | 73 | ```console 74 | $ pico8-to-lua input.p8 75 | ``` 76 | 77 | ...which will output transformed p8 file contents: 78 | 79 | ```lua 80 | pico-8 cartridge // http://www.pico-8.com 81 | version 16 82 | __lua__ 83 | function _init() 84 | local num = 0x2 85 | if num+1==0x3 then print('yes!') end 86 | end 87 | ``` 88 | 89 | If you only want the lua output, you can pass the `--lua-only` flag when the input is a p8 file: 90 | 91 | ```console 92 | $ pico8-to-lua input.p8 --lua-only 93 | ``` 94 | 95 | ```lua 96 | function _init() 97 | local num = 0x2 98 | if num+1==0x3 then print('yes!') end 99 | end 100 | ``` 101 | 102 | If you're in a UNIX environment, you can pipe the output directly to a file: 103 | 104 | ```console 105 | $ pico8-to-lua input.lua > output.lua 106 | ``` 107 | 108 | ``` 109 | $ pico8-to-lua input.p8 > output.p8 110 | ``` 111 | 112 | Or you can pipe into another program: 113 | 114 | ```console 115 | $ pico8-to-lua input.p8 --lua-only | luacheck - 116 | ``` 117 | 118 | You can even pipe output from another program into this one by passing `-` as the filename argument: 119 | 120 | ```console 121 | $ cat input.lua | pico8-to-lua - > output.lua 122 | ``` 123 | 124 | ```console 125 | $ curl https://someurl.com/mycart.p8 | pico8-to-lua - --lua-only | luacheck - 126 | ``` 127 | -------------------------------------------------------------------------------- /luarocks: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | LUAROCKS_SYSCONFDIR='/usr/local/etc/luarocks' LUA_INIT='package.path="/usr/local/share/lua/5.3/?.lua;/usr/local/share/lua/5.3/?/init.lua;/usr/local/lib/lua/5.3/?.lua;/usr/local/lib/lua/5.3/?/init.lua;/usr/share/lua/5.3/?.lua;/usr/share/lua/5.3/?/init.lua;./?.lua;./?/init.lua;/home/ben/.luarocks/share/lua/5.3/?.lua;/home/ben/.luarocks/share/lua/5.3/?/init.lua";package.cpath="/usr/local/lib/lua/5.3/?.so;/usr/lib/x86_64-linux-gnu/lua/5.3/?.so;/usr/lib/lua/5.3/?.so;/usr/local/lib/lua/5.3/loadall.so;./?.so;/home/ben/.luarocks/lib/lua/5.3/?.so"' exec '/usr/bin/lua5.3' '/usr/local/lib/luarocks/rocks-5.3/luarocks/3.0.4-1/bin/luarocks' --project-tree /home/ben/Documents/Code/pico8-to-lua/lua_modules "$@" 4 | -------------------------------------------------------------------------------- /pico8-to-lua-0.1.0-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "pico8-to-lua" 2 | version = "0.1.0-2" 3 | source = { 4 | url = "git://github.com/benwiley4000/pico8-to-lua.git", 5 | tag = "v0.1.0" 6 | } 7 | description = { 8 | detailed = "A command-line utility written in Lua that converts the PICO-8 variety of extended Lua syntax to standard Lua syntax.", 9 | homepage = "https://github.com/benwiley4000/pico8-to-lua", 10 | license = "Zlib" 11 | } 12 | build = { 13 | type = "builtin", 14 | modules = { 15 | ["pico8-to-lua"] = "pico8-to-lua.lua" 16 | }, 17 | install = { 18 | bin = { 19 | ["pico8-to-lua"] = "pico8-to-lua.lua" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pico8-to-lua.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | -- FUNCTIONS 4 | -- (all functions are borrowed from other projects; see citations above each) 5 | 6 | -- Got this function from picolove! 7 | -- https://github.com/picolove/picolove/blob/d5a65fd6dd322532d90ea612893a00a28096804a/main.lua#L820 8 | -- PICOLOVE is licensed under the Zlib license: 9 | 10 | -- Copyright (c) 2015 Jez Kabanov 11 | 12 | -- This software is provided 'as-is', without any express or implied 13 | -- warranty. In no event will the authors be held liable for any damages 14 | -- arising from the use of this software. 15 | 16 | -- Permission is granted to anyone to use this software for any purpose, 17 | -- including commercial applications, and to alter it and redistribute it 18 | -- freely, subject to the following restrictions: 19 | 20 | -- 1. The origin of this software must not be misrepresented; you must not 21 | -- claim that you wrote the original software. If you use this software 22 | -- in a product, an acknowledgement in the product documentation would be 23 | -- appreciated but is not required. 24 | -- 2. Altered source versions must be plainly marked as such, and must not be 25 | -- misrepresented as being the original software. 26 | -- 3. This notice may not be removed or altered from any source distribution. 27 | function patch_lua(lua) 28 | -- patch lua code 29 | lua = lua:gsub("!=","~=") 30 | lua = lua:gsub("//","--") 31 | -- rewrite shorthand if statements eg. if (not b) i=1 j=2 32 | lua = lua:gsub("if%s*(%b())%s*([^\n]*)\n",function(a,b) 33 | local nl = a:find('\n',nil,true) 34 | local th = b:find('%f[%w]then%f[%W]') 35 | local an = b:find('%f[%w]and%f[%W]') 36 | local o = b:find('%f[%w]or%f[%W]') 37 | local ce = b:find('--',nil,true) 38 | if not (nl or th or an or o) then 39 | if ce then 40 | local c,t = b:match("(.-)(%s-%-%-.*)") 41 | return "if "..a:sub(2,-2).." then "..c.." end"..t.."\n" 42 | else 43 | return "if "..a:sub(2,-2).." then "..b.." end\n" 44 | end 45 | end 46 | end) 47 | -- rewrite assignment operators 48 | lua = lua:gsub("(%S+)%s*([%+-%*/%%])=","%1 = %1 %2 ") 49 | -- rewrite inspect operator "?" 50 | lua = lua:gsub("^(%s*)?([^\n\r]*)","%1print(%2)") 51 | -- convert binary literals to hex literals 52 | lua = lua:gsub("([^%w_])0[bB]([01.]+)", function(a, b) 53 | local p1, p2 = b, "" 54 | if b:find(".", nil, true) then 55 | p1, p2 = b:match("(.-)%.(.*)") 56 | end 57 | -- pad to 4 characters 58 | p2 = p2 .. string.rep("0", 3 - ((#p2 - 1) % 4)) 59 | p1, p2 = tonumber(p1, 2), tonumber(p2, 2) 60 | if p1 then 61 | if p2 then 62 | return string.format("%s0x%x.%x", a, p1, p2) 63 | else 64 | return string.format("%s0x%x", a, p1) 65 | end 66 | end 67 | end) 68 | 69 | return lua 70 | end 71 | 72 | -- thanks to https://helloacm.com/split-a-string-in-lua/ 73 | function split(s, delimiter) 74 | result = {} 75 | for match in (s..delimiter):gmatch("(.-)"..delimiter) do 76 | table.insert(result, match) 77 | end 78 | return result 79 | end 80 | 81 | -- PROCEDURE 82 | 83 | before_delimiter = "__lua__\n" 84 | after_delimiter = "__gfx__" 85 | 86 | filename = arg[1] 87 | output_lua_only = arg[2] == "--lua-only" 88 | 89 | if not filename then 90 | error("ERROR: Must provide filename argument") 91 | elseif filename == '-' then 92 | f = io.input() 93 | else 94 | f = io.open(filename) 95 | if not f then 96 | error("ERROR: File "..filename.." not found") 97 | end 98 | end 99 | input_contents = f:read('*all') 100 | f:close() 101 | 102 | pico8_lua = input_contents 103 | before_lua = "" 104 | after_lua = "" 105 | is_p8_file = pico8_lua:sub(1,16) == "pico-8 cartridge" 106 | if is_p8_file then 107 | local t1 = split(pico8_lua, before_delimiter) 108 | local t2 = split(t1[2], after_delimiter) 109 | pico8_lua = t2[1] 110 | before_lua = t1[1] 111 | after_lua = t2[2] 112 | end 113 | 114 | plain_lua = patch_lua(pico8_lua) 115 | 116 | out_str = plain_lua 117 | if is_p8_file and not output_lua_only then 118 | out_str = before_lua..before_delimiter..out_str 119 | if after_lua then 120 | out_str = out_str..after_delimiter..after_lua 121 | end 122 | end 123 | 124 | -- we'll get an extra newline when 125 | -- we print so remove the newline at 126 | -- the end if there is one 127 | if out_str:sub(-1) == '\n' then 128 | out_str = out_str:sub(0, -2) 129 | end 130 | 131 | print(out_str) 132 | --------------------------------------------------------------------------------