Skip to content

Instantly share code, notes, and snippets.

@ds84182
Created April 21, 2016 02:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ds84182/c472e48d427870f55c62d316286da6c7 to your computer and use it in GitHub Desktop.
Save ds84182/c472e48d427870f55c62d316286da6c7 to your computer and use it in GitHub Desktop.
fuckit.lua makes sure that your Lua code always runs to the end of file despite any errors that occur
do
local info = debug.getinfo(1)
local startingLine, endingLine = info.currentline
local oursource = info.source
-- This GC stuff should probably work when it should except for things that can't get collected
local bubbles = setmetatable({}, {__gc="kv"})
local bubbleContent = setmetatable({}, {__gc="kv"})
local bubbleExists = setmetatable({}, {__gc="k"})
local bubblemt = {}
-- Forward decls to prevent stack overflows :^)
local setmetatable, type, next, pairs, tablepack, print, tostring = setmetatable, type, next, pairs, table.pack, print, tostring
local tableunpack, select, pcall, xpcall = table.unpack, select, pcall, xpcall
local rawget, rawset = rawget, rawset
local stb = debug.traceback
local debuggetinfo = debug.getinfo
local debuggetlocal, debugsetlocal = debug.getlocal, debug.setlocal
local print = print
local iowrite = io.write
local bubblewrap, optionalwrap, unwrap, isbubble
local function printmod(s)
iowrite(tostring(s),'\n')
end
local function safe(func, ...)
local args = tablepack(...)
for i=1, args.n do
args[i] = unwrap(args[i])
end
local ret = tablepack(xpcall(func,stb,tableunpack(args, 1, args.n)))
if not ret[1] then --[[print(ret[2])]] return bubblewrap(nil) end
for i=2, ret.n do
ret[i] = bubblewrap(ret[i])
end
return tableunpack(ret, 2, ret.n)
end
local function safegen(func)
return function(...)
return safe(func,...)
end
end
function bubblemt:__index(index)
local v = unwrap(self)
index = unwrap(index)
return safe(function() return v[index] end)
end
function bubblemt:__newindex(index, value)
local v = unwrap(self)
index = unwrap(index)
value = unwrap(value)
safe(function() v[index] = value end)
end
function bubblemt:__call(...)
local v = unwrap(self)
return safe(function(...) return v(...) end, ...)
end
function bubblemt:__add(other)
local v = unwrap(self)
other = unwrap(other)
return safe(function() return v+other end)
end
function bubblemt:__sub(other)
local v = unwrap(self)
other = unwrap(other)
return safe(function() return v-other end)
end
function bubblemt:__mul(other)
local v = unwrap(self)
other = unwrap(other)
return safe(function() return v*other end)
end
function bubblemt:__div(other)
local v = unwrap(self)
other = unwrap(other)
return safe(function() return v/other end)
end
function bubblemt:__mod(other)
local v = unwrap(self)
other = unwrap(other)
return safe(function() return v%other end)
end
function bubblemt:__pow(other)
local v = unwrap(self)
other = unwrap(other)
return safe(function() return v^other end)
end
-- These comparison functions have to be unwrapped in order to work
function bubblemt:__eq(other)
local v = unwrap(self)
if v == nil then return true end -- nil is equal to everything
other = unwrap(other)
return unwrap(safe(function() return v == other end))
end
function bubblemt:__lt(other)
local v = unwrap(self)
if v == nil then return true end -- nil is less than everything, including nil
other = unwrap(other)
return unwrap(safe(function() return v < other end))
end
function bubblemt:__le(other)
local v = unwrap(self)
if v == nil then return true end -- nil is less than and equal to everything
other = unwrap(other)
return unwrap(safe(function() return v <= other end))
end
function bubblemt:__len()
local v = unwrap(self)
return safe(function() return #v end)
end
function bubblemt:__unm()
local v = unwrap(self)
return safe(function() return -v end)
end
function bubblemt:__concat(other)
local v = unwrap(self)
other = unwrap(other)
return safe(function() return v..other end)
end
function bubblemt:__tostring(str)
local v = unwrap(self)
return safe(function() return tostring(v) end)
end
local null = setmetatable({}, bubblemt)
bubbleExists[null] = true
function bubblewrap(v, bubl)
-- Wraps v with bubbles :)
if bubbles[v] and type(bubl) ~= "table" then
return bubbles[v]
end
if v == nil then
return null
end
-- Double bubble trouble
if isbubble(v) then
return v
end
bubbles[v] = setmetatable(type(bubl) == "table" and bubl or {}, bubblemt)
bubbleContent[bubbles[v]] = v
bubbleExists[bubbles[v]] = true
return bubbles[v]
end
function optionalwrap(v)
if bubbleExists[v] then -- If v is already a bubble, return it
return v
else
return bubblewrap(v)
end
end
function unwrap(v)
return bubbleContent[optionalwrap(v)]
end
function isbubble(v)
return bubbleExists[v]
end
local function fucktheworld(_RG)
local env = _RG or _G
-- Shallow copy and remove all env vars so __index works
local shallow = {}
for i, v in pairs(env) do shallow[i] = v env[i] = nil end
env.tostring = tostring
bubblewrap(shallow, env)
debug.sethook(function()
local info = debuggetinfo(2)
local line = info.currentline
local source = info.source
if (source == oursource and (line < startingLine or line > endingLine)) or source ~= oursource then
-- we want to wrap all the locals past the params
local cloc = info.nparams+1
while true do
local name, value = debuggetlocal(2, cloc)
if not name then break end
if not isbubble(value) then
debugsetlocal(2, cloc, bubblewrap(value))
--printmod(name.."("..tostring(value)..") is not bubble! fixd!")
end
cloc = cloc+1
end
end
end, "", 1)
end
-- TODO: Implement me
local function unfucktheworld(_RG)
local env = _RG or _G
-- unwrap all the values in the environment with bubble wrap
end
_G.fucktheworld = fucktheworld
endingLine = debug.getinfo(1).currentline
end
fucktheworld()
print(":)")
error("Test!")
local a = 5
local b = 6
local c = a+b
print("Safe "..c)
local abc = 4
print(abc+abc)
local tab = {}
tab[nil] = 5
tab = nil
print(tab[4])
print(type("test"))
("you")("what")
print(":^)")
local fourpz = 4.0
local four = 4
print(fourpz == four)
print(abc > four)
print(four < abc+abc)
print(abc < four)
local lol = "XDlol"
print(#lol)
lol = nil
print(#lol)
if lol == nil then
print("Nil checking works")
else
print("cat sanity.txt > /dev/null")
print("throw sanity;")
end
local fh = io.open("some_file.txt", "r")
print(fh:read("*a"))
fh:close()
print("I probably read a file")
if nil then
print("Major side effect: nil and false evaluate to true instead of false in if statements (when bubblewrapped)")
end
local totallyFalse = false
if totallyFalse then
print("Wow, must be true!")
end
local socket = require "socket"
-- This is great because if LuaSocket isn't installed then nothing fails!
local sock = socket.connect("localhost", 66664)
print(sock:read("*a"))
sock:close()
print("I probably just read a socket")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment