]> git.lizzy.rs Git - metalua.git/blob - src/lib/metalua/walk/bindings.mlua
simpler bindings analysis: works on simple cases
[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       local id_name = id[1]
16       -- Reference in scope, so that the binding statement can be retrieved:
17       scope.current[id_name] = ast
18       -- Init the occurences list for this identifier:
19       if binders[ast] then binders[ast][id_name] = { }
20       else binders[ast] = { [id_name] = { } } end
21    end
22    
23    -- identifier occurence, not as a binder: reference this occurence
24    function cfg.Id (id)
25       local id_name = id[1]
26       -- ast which binds this id, might be nil:
27       local binder_ast = scope.current [id_name] 
28       -- dict id_name => occurences, might be the list of unbound occurences:
29       local occur_dict = binder_ast and binders[binder_ast] or unbound
30       -- add an occurence of `id' in the occurences list:
31       local occurences = occur_dict [id_name]
32       if occurences then table.insert (occurences, id) 
33       else occur_dict [id_name] = { id } end
34    end
35
36    function cfg.scope.down() scope:push() end
37    function cfg.scope.up()   scope:pop()  end
38
39    walk.guess (cfg, ast)
40    return binders, unbound
41 end