]> git.lizzy.rs Git - metalua.git/blob - src/lib/metalua/walk/bindings.mlua
Enable `Dots nodes to be processed as identifiers
[metalua.git] / src / lib / metalua / walk / bindings.mlua
1 require 'metalua.walk'
2 require 'metalua.walk.scope'
3
4 function bindings(ast)
5    -- binders :: ast  => name => occurences
6    -- unbound :: name => occurences
7    -- scope   :: name => ast
8
9    local binders, unbound, cfg, scope = { }, { }, { scope={ } }, scope:new()
10
11    -- * id: identifier entering in scope
12    -- * ast: statement or expr carrying this id, on of:
13    --        Local, Localrec, Forin, Fornum, Function.
14    function cfg.binder (id, ast)
15       if id.tag ~= 'Id' then return end
16       local id_name = id[1]
17       -- Reference in scope, so that the binding statement can be retrieved:
18       scope.current[id_name] = ast
19       -- Init the occurences list for this identifier:
20       if binders[ast] then binders[ast][id_name] = { }
21       else binders[ast] = { [id_name] = { } } end
22    end
23    
24    -- identifier occurence, not as a binder: reference this occurence
25    function cfg.Id (id)
26       local id_name = id[1]
27       -- ast which binds this id, might be nil:
28       local binder_ast = scope.current [id_name] 
29       -- dict id_name => occurences, might be the list of unbound occurences:
30       local occur_dict = binder_ast and binders[binder_ast] or unbound
31       -- add an occurence of `id' in the occurences list:
32       local occurences = occur_dict [id_name]
33       if occurences then table.insert (occurences, id) 
34       else occur_dict [id_name] = { id } end
35    end
36
37    function cfg.scope.down() scope:push() end
38    function cfg.scope.up()   scope:pop()  end
39
40    walk.guess (cfg, ast)
41    return binders, unbound
42 end
43