]> git.e2factory.org Git - e2factory.git/commitdiff
Rewrite the strict module.
authorTobias Ulmer <tu@emlix.com>
Tue, 4 Sep 2012 09:54:17 +0000 (11:54 +0200)
committerTobias Ulmer <tu@emlix.com>
Tue, 26 Feb 2013 18:07:09 +0000 (19:07 +0100)
Provide functions to lock tables, declare members etc.

Signed-off-by: Tobias Ulmer <tu@emlix.com>
generic/strict.lua

index 04845af0833a58fcf65e3458e33c30fd7b9ee392..402254a0a4a9e4c2f0301b9ca4db948befa61de2 100644 (file)
@@ -1,6 +1,7 @@
 --[[
    e2factory, the emlix embedded build system
 
+   Copyright (C) 2012 Tobias Ulmer <tu@emlix.com>, emlix GmbH
    Copyright (C) 2007-2009 Gordon Hecker <gh@emlix.com>, emlix GmbH
    Copyright (C) 2007-2009 Oskar Schirmer <os@emlix.com>, emlix GmbH
    Copyright (C) 2007-2008 Felix Winkelmann, emlix GmbH
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ]]
 
--- 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: