File: strict.lua

package info (click to toggle)
lua-gtk 0.9%2B20100528-2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 2,176 kB
  • ctags: 1,934
  • sloc: ansic: 9,571; sh: 373; makefile: 241
file content (93 lines) | stat: -rwxr-xr-x 2,325 bytes parent folder | download | duplicates (2)
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