]> git.lizzy.rs Git - metalua.git/blob - src/lib/metalua/walk/scope.lua
Merge remote branch 'origin/master'
[metalua.git] / src / lib / metalua / walk / scope.lua
1 --------------------------------------------------------------------------------
2 --
3 -- Scopes: this library helps keeping track of identifier scopes,
4 -- typically in code walkers.
5 --
6 -- * scope:new() returns a new scope instance s
7 --
8 -- * s:push() bookmarks the current set of variables, so the it can be
9 --   retrieved next time a s:pop() is performed.
10 --
11 -- * s:pop() retrieves the last state saved by s:push(). Calls to
12 --   :push() and :pop() can be nested as deep as one wants.
13 --
14 -- * s:add(var_list, val) adds new variable names (stirng) into the
15 --   scope, as keys. val is the (optional) value associated with them:
16 --   it allows to attach arbitrary information to variables, e.g. the
17 --   statement or expression that created them.
18 --
19 -- * s:push(var_list, val) is a shortcut for 
20 --   s:push(); s:add(var_list, val).
21 --
22 -- * s.current is the current scope, a table with variable names as
23 --   keys and their associated value val (or 'true') as value.
24 --
25 --------------------------------------------------------------------------------
26
27 scope = { }
28 scope.__index = scope
29
30 function scope:new()
31    local ret = { current = { } }
32    ret.stack = { ret.current }
33    setmetatable (ret, self)
34    return ret
35 end
36
37 function scope:push(...)
38    table.insert (self.stack, table.shallow_copy (self.current))
39    if ... then return self:add(...) end
40 end
41
42 function scope:pop()
43    self.current = table.remove (self.stack)
44 end
45
46 function scope:add (vars, val)
47    val = val or true
48    for i, id in ipairs (vars) do
49       assert(id.tag=='Id' or id.tag=='Dots' and i==#vars)
50       if id.tag=='Id' then self.current[id[1]] = val end
51    end
52 end
53
54 return scope