From c10e9c7a199d180f8673bfb73af9d1370a176bd8 Mon Sep 17 00:00:00 2001 From: Tobias Ulmer Date: Tue, 4 Sep 2012 11:54:17 +0200 Subject: [PATCH] Rewrite the strict module. Provide functions to lock tables, declare members etc. Signed-off-by: Tobias Ulmer --- generic/strict.lua | 124 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 100 insertions(+), 24 deletions(-) diff --git a/generic/strict.lua b/generic/strict.lua index 04845af..402254a 100644 --- a/generic/strict.lua +++ b/generic/strict.lua @@ -1,6 +1,7 @@ --[[ e2factory, the emlix embedded build system + Copyright (C) 2012 Tobias Ulmer , emlix GmbH Copyright (C) 2007-2009 Gordon Hecker , emlix GmbH Copyright (C) 2007-2009 Oskar Schirmer , emlix GmbH Copyright (C) 2007-2008 Felix Winkelmann, emlix GmbH @@ -25,41 +26,116 @@ along with this program. If not, see . ]] --- 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. --- +local strict = {} -local mt = getmetatable(_G) -if mt == nil then - mt = {} - setmetatable(_G, mt) +local function what() + local d = debug.getinfo(3, "S") + return d and d.what or "C" end -mt.__declared = {} +--- Lock a table against adding members explicitly or by implicit assignment. +-- @param t table to lock +function strict.lock(t) + assert(type(t) == "table") + local mt = {} + mt.__declared = {} -local function what () - local d = debug.getinfo(3, "S") - return d and d.what or "C" + if getmetatable(t) ~= nil then + error("metatable already set") + end + + mt.__newindex = function(t, k, v) + local mt = getmetatable(t) + if not mt.__declared[k] and what() ~= "C" then + error("assignment in "..tostring(t).. + " to undeclared variable '"..tostring(k).."'") + end + + -- error("assignment to "..tostring(t).."[".. + -- tostring(k).."]="..tostring(v)) + rawset(t, k, v) + end + + mt.__index = function(t, k, v) + local mt = getmetatable(t) + if not mt.__declared[k] and what() ~= "C" then + error("variable "..k.." is not declared") + end + + return rawget(t, k) + end + + setmetatable(t, mt) + + return t end -mt.__newindex = function (t, n, v) - if not mt.__declared[n] then - local w = what() - if w ~= "main" and w ~= "C" then - error("assign to undeclared variable '"..n.."'", 2) +--- Unlock a table that was protected against adding and assigning to members. +-- Not implemented yet. +-- @param t table to unlock +function strict.unlock(t) + assert(type(t) == "table") + error("strict.unlock() is not implemented yet") +end + +--- Test whether a table is locked. +-- @param t table to check +-- @return true if it's locked, false if not +function strict.islocked(t) + assert(type(t) == "table") + local mt = getmetatable(t) + + if mt and mt.__declared and mt.__newindex and mt.__index then + return true + end + + return false +end + +--- Declare new members of a table and assign them a value. +-- Note that declaring already declared members causes an error message to be +-- raised. +-- @param t table to declare members in +-- @param values table of member (key) / value pairs. +function strict.declare(t, values) + assert(type(t) == "table") + assert(type(values) == "table") + local mt = getmetatable(t) + + for k, v in pairs(values) do + if mt.__declared[k] then + error("variable '"..k.."' is already declared") end - mt.__declared[n] = true + mt.__declared[k] = true + rawset(t, k, v) end - rawset(t, n, v) + + return t end -mt.__index = function (t, n) - if not mt.__declared[n] and what() ~= "C" then - error("variable '"..n.."' is not declared", 2) +--- Remove members from a table. +-- Note that the members must be declared, otherwise a fatal error is raised. +-- Also note that values in the values table are ignored, only keys are +-- considered. +-- @param t table to remove members from +-- @param values table of members to delete. Must be in key/value form. +function strict.undeclare(t, values) + assert(type(t) == "table") + assert(type(values) == "table") + local mt = getmetatable(t) + + for k, v in pairs(values) do + if not mt.__declared[k] then + error("variable '"..k.."' was not declared in the first place") + end + + mt.__declared[k] = nil + rawset(t, k, nil) end - return rawget(t, n) + + return t end +return strict.lock(strict) + -- vim:sw=4:sts=4:et: -- 2.39.5