102 lines
2.9 KiB
Lua
102 lines
2.9 KiB
Lua
|
|
inspect = require("inspect")
|
|
|
|
|
|
-- If t is a table, return it. If not, return a blank table.
|
|
function forcetable(t)
|
|
if type(t) == "table" then
|
|
return t
|
|
else
|
|
return {}
|
|
end
|
|
end
|
|
|
|
-- Clear the table out. Deletes all keys, removes any metatable.
|
|
-- TODO: this doesn't work on tables that have __metatable metamethod.
|
|
function rawclear(t)
|
|
for k in pairs(t) do
|
|
rawset(t, k, nil)
|
|
end
|
|
setmetatable(t, nil)
|
|
return t
|
|
end
|
|
|
|
-- given a class database, removes all the functions that have
|
|
-- been inserted into it, but keeps the class and action tables.
|
|
function reset_class_db(db)
|
|
for name,maybeclass in pairs(db) do
|
|
local class = forcetable(maybeclass)
|
|
local action = forcetable(rawget(class, "action"))
|
|
rawclear(class)
|
|
rawclear(action)
|
|
rawset(db, name, class)
|
|
class.action = action
|
|
class.__index = class
|
|
class.__class = name
|
|
end
|
|
end
|
|
|
|
-- Given a class_db, makes an accessor that fetches classes
|
|
-- from that class db.
|
|
function make_class_accessor(db)
|
|
return function(name)
|
|
local class = rawget(db, name)
|
|
if type(class) ~= "table" then
|
|
class = {}
|
|
rawset(db, name, class)
|
|
class.action = {}
|
|
class.__index = class
|
|
class.__class = name
|
|
end
|
|
return class
|
|
end
|
|
end
|
|
|
|
-- given a global_db, makes an accessor that fetches named
|
|
-- tables from that global_db.
|
|
function make_global_accessor(db)
|
|
return function(name)
|
|
local global = rawget(db, name)
|
|
if type(global) ~= "table" then
|
|
global = {}
|
|
rawset(db, name, global)
|
|
end
|
|
return global
|
|
end
|
|
end
|
|
|
|
-- The sandbox list - a list of the builtin functions that gets imported
|
|
-- into world models. This is a very weak form of sandboxing, a world
|
|
-- model can still easily use functions that are not on this list. If you
|
|
-- want stronger sandboxing, you need to not link in certain builtins at all.
|
|
--
|
|
-- Omitted from this list: "debug", "dofile", "getfenv", "io", "jit",
|
|
-- "load", "loadfile", "loadstring", "module", "newproxy", "os", "package",
|
|
-- "pcall", "require", "xpcall"
|
|
--
|
|
local sandbox_list = { "assert", "bit", "error", "getmetatable", "inspect",
|
|
"ipairs", "math", "next", "pairs", "print", "rawequal", "rawget", "rawset",
|
|
"select", "setmetatable", "tonumber", "tostring", "type", "unpack" }
|
|
|
|
-- Make a world model.
|
|
--
|
|
function make_world_model()
|
|
genv = {}
|
|
genv._G = genv
|
|
meta = {}
|
|
meta.class_db = {}
|
|
meta.global_db = {}
|
|
meta.source_db = {}
|
|
meta.tangible_db = {}
|
|
meta.__newindex = function() error("Global environment is read-only") end
|
|
-- meta.__metatable = false
|
|
genv.class = make_class_accessor(meta.class_db)
|
|
genv.global = make_global_accessor(meta.global_db)
|
|
for i,name in ipairs(sandbox_list) do
|
|
genv[name] = _G[name]
|
|
end
|
|
setmetatable(genv, meta)
|
|
return genv
|
|
end
|
|
|