Files lua-5.1.3/src/liblua.a and lua-5.1.3-tablescope/src/liblua.a differ diff -urN lua-5.1.3/src/ltm.c lua-5.1.3-tablescope/src/ltm.c --- lua-5.1.3/src/ltm.c 2007-12-27 08:02:26.000000000 -0500 +++ lua-5.1.3-tablescope/src/ltm.c 2008-02-02 01:57:54.000000000 -0500 @@ -33,7 +33,7 @@ "__gc", "__mode", "__eq", "__add", "__sub", "__mul", "__div", "__mod", "__pow", "__unm", "__len", "__lt", "__le", - "__concat", "__call" + "__concat", "__call", "__scope" /* PATCH - TABLESCOPE */ }; int i; for (i=0; i= cl->p->code + cl->p->sizecode) break; + if (GET_OPCODE(*pi) == OP_CALL && + (GET_OPCODE(*(pi-1)) == OP_SETLIST || + GET_OPCODE(*(pi-1)) == OP_SETTABLE) ) + { + /* Determine whether this "o {....}" contains the GETGLOBAL by + searching for start of this "o {....}", which is implied + by condition RA(NEWTABLE) == RA(SETLIST or SETTABLE). + */ + const Instruction * pi2; + int is_containing; + for (pi2 = pi; ; pi2--) { + lua_assert(pi2 >= cl->p->code); + if (GET_OPCODE(*pi2) == OP_NEWTABLE && + RA(*pi2) == RA(*(pi-1))) + { + is_containing = (pi2 < pc); + break; + } + } + /* Search complete if o has __scope metamethod (tm). */ + if (is_containing && + ! ttisnil(tm = luaT_gettmbyobj(L, RA(*(pi)), TM_SCOPE))) + { + break; + } + } + } /* pi */ + + /* Lookup key first in __scope (if available). Found if non-nil. */ + if (tm && !ttisnil(tm)) { + Protect(luaV_gettable(L, tm, rb, ra)); + if (! ttisnil(ra)) { *pbase = base; return 1; } + } + *pbase = base; + return 0; +} + void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; @@ -430,6 +483,10 @@ TValue *rb = KBx(i); sethvalue(L, &g, cl->env); lua_assert(ttisstring(rb)); + + /* PATCH - TABLESCOPE */ + if (gettablescope(L, ra, rb, pc, cl, &base)) continue; + Protect(luaV_gettable(L, &g, rb, ra)); continue; } diff -urN lua-5.1.3/test/tablescope.lua lua-5.1.3-tablescope/test/tablescope.lua --- lua-5.1.3/test/tablescope.lua 1969-12-31 19:00:00.000000000 -0500 +++ lua-5.1.3-tablescope/test/tablescope.lua 2008-02-02 10:07:56.000000000 -0500 @@ -0,0 +1,145 @@ +-- Test suite for table scoping patch. [PATCH - TABLESCOPE] +-- +-- The table scope patch is described in +-- http://lua-users.org/wiki/TableScope . +-- +-- David Manura, 2008-02. Licensed under the same terms as Lua itself. + +-- Helper function to stringify object (supports nested tables). +local function format(t) + if type(t) == 'table' then + local found = {} + local ts = {} + for i,v in ipairs(t) do ts[i] = format(v); found[i] = true end + for k,v in pairs(t) do if not found[k] then + ts[#ts+1] = format(k) .. '=' .. format(v) + end end + return '[' .. table.concat(ts, ",") .. ']' + else + return tostring(t) + end +end + +-- Helper function to check assertions in test suite. +local ops = {} +ops['=='] = function(a,b) return a == b end +local function check(op, a, b) + if not ops[op](a, b) then + error("FAIL: " .. format(a) .. " == " .. format(b), 2) + end +end + +-- Creates some ficticious object with the given name. +-- This object contains a __scope metamethod pointing to itself. +local function make(name) + local obj = {name = name} + local mt = { + __scope = obj, + __call = function(self, t) return self.name .. format(t) end + } + return setmetatable(obj, mt) +end + +-- Some functions and objects. +qux = "QUX" +quux = "QUUX" +baz = "BAZ" +thud = "THUD" +function identity(o) return o end +local foo = make 'foo' + foo.quux = "quux" + foo.baz = "baz" + foo.bar = function(name) return 'bar[' .. name .. ']' end +local goo = make 'goo' + goo.quux = "QuuX" + goo.thud = "thud" + goo.bar = function(name) return 'BaR[' .. name ..']' end + +local function test_scope() + -- basic example + check('==', format {baz, foo {baz,[baz]=baz}, baz}, + "[BAZ,foo[baz,baz=baz],BAZ]") + + -- nested scoped with different __scope. + check('==', format {baz, foo {baz, goo {baz}, {baz}}, baz}, + "[BAZ,foo[baz,goo[BAZ],[baz]],BAZ]") + check('==', baz, "BAZ") + + -- obj lacking __scope + check('==', identity {baz} [1], "BAZ") + + -- fallthrough to parent if child lacks __scope. + check('==', foo { identity {baz} [1] }, "foo[baz]") + + -- in parent but not in child + check('==', foo {goo {baz}}, "foo[goo[BAZ]]") + + -- in child but not in parent + check('==', foo {goo {thud}}, "foo[goo[thud]]") + + -- in neither child nor parent + check('==', foo {goo {qux}, qux}, "foo[goo[QUX],QUX]") + + -- in both child and parent + check('==', foo {goo {quux}, quux}, "foo[goo[QuuX],quux]") + + -- nested table + check('==', foo { { baz } }, "foo[[baz]]") + + -- locals override globals + do + local baz = "BaZ" + check('==', foo {baz}, "foo[BaZ]") + end + + -- complex scoping example + local o = + foo { + bar "bar"; + baz; + goo { + thud; + bar(quux); + baz + } + } + check('==', o, "foo[bar[bar],baz,goo[thud,BaR[QuuX],BAZ]]") +end +test_scope() + +local function test_table_structure() + -- vararg in table + (function(...) + check('==', format(foo {baz, ...}), "foo[baz,2,3]") end)(2,3) + + -- empty table + check('==', format {baz, foo {}, baz}, "[BAZ,foo[],BAZ]") + + -- hash only + check('==', foo {x=baz}, "foo[x=baz]") + + -- numeric only + check('==', foo {baz}, "foo[baz]") + + -- hash and numeric + check('==', foo {baz,x=baz}, "foo[baz,x=baz]") + + -- key + check('==', foo {[baz]=baz}, "foo[baz=baz]") + + -- expression in table + local obj = foo { bar "bar" .. bar "bar" } + check('==', obj, 'foo[bar[bar]bar[bar]]') + + -- more complex + local obj = foo { bar "bar"; {baz}; qux; {{{}}}, [baz]=baz } + check('==', obj, 'foo[bar[bar],[baz],QUX,[[[]]],baz=baz]') +end +test_table_structure() + +print 'DONE' + + + + +