1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
|
-- vim:sw=4:sts=4
---
-- Checks uses of undeclared global variables.
--
-- All global variables must be 'declared' through a regular assignment
-- (even assigning nil will do) in a main chunk before being used
-- anywhere or assigned to inside a function.
--
-- @class module
-- @name gtk.strict
--
module("gtk.strict", package.seeall)
---
-- new global variables are only allowed in main and in C functions
local function strict_newindex(t, n, v)
local d = getmetatable(t).__declared
if not d[n] then
local w = debug.getinfo(2, "S").what
if w ~= "main" and w ~= "C" then
error("assign to undeclared variable '"..n.."'", 2)
end
d[n] = true
end
rawset(t, n, v)
end
-- This function is called when an environment does not contain the
-- requested index. Typically this should not happen often.
local function strict_index(t, n)
local mt = getmetatable(t)
local d = mt.__declared
if d[n] then return rawget(t, n) end
-- "n" hasn't been assigned in this environment; try metatable
if mt.__old_index then
local v = mt.__old_index[n]
if v then return v end
end
-- not found -> error
error("variable '"..n.."' is not declared", 2)
end
---
-- Enable strict checking for the calling environment
--
function init()
local env = getfenv(2)
local mt = getmetatable(env)
if mt == nil then
mt = {}
setmetatable(env, mt)
end
if rawget(mt, "__declared") then
-- print "Strict variable checking is still on!"
return
end
-- print "Enabling strict variable checking."
mt.__declared = {}
mt.__newindex = strict_newindex
mt.__old_index = mt.__index
mt.__index = strict_index
end
---
-- When the table is locked, __newindex shouldn't be called. The only valid
-- possibility is when the variable has been assigned nil, in which case it
-- vanishes, and the next assignment will be a new one.
--
local function strict_locked(t, n, v)
local d = getmetatable(t).__declared
if not d[n] then
error("LOCKED - no new globals allowed: " .. n, 2)
end
rawset(t, n, v)
end
---
-- Prevent creation of new variables in the calling environment.
--
-- This can be used to detect unwanted usage of globals.
--
function lock()
local env = getfenv(2)
local mt = getmetatable(env)
mt.__newindex = strict_locked
end
|