Created
April 21, 2016 02:04
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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