]> git.lizzy.rs Git - metalua.git/blob - junk/hygienic2.lua
Merge remote branch 'origin/master'
[metalua.git] / junk / hygienic2.lua
1 --------------------------------------------------------------------------------
2 --
3 -- (c) Fabien Fleutot 2007, published under the MIT license.
4 --
5 --
6 -- API:
7 -- ----
8 -- * freevars.block(ast)
9 -- * freevars.expr(ast)
10 -- * freevars.stat(ast)
11 --
12 --------------------------------------------------------------------------------
13
14 require 'std'
15 require 'walk'
16 require 'freevars'
17
18 -{ extension 'match' }
19
20 --------------------------------------------------------------------------------
21 -- Return the string->boolean hash table of the names of all free variables
22 -- in 'term'. 'kind' is the name of an entry in module 'walk', presumably
23 -- one of 'expr', 'stat' or 'block'.
24 --------------------------------------------------------------------------------
25 local function alpha (kind, term)
26    local cfg = { expr  = { }, stat  = { }, block = { } }
27
28    -----------------------------------------------------------------------------
29    -- Monkey-patch the scope add method, so that it associates a unique name
30    -- to bound vars.
31    -----------------------------------------------------------------------------
32    local scope = scope:new()
33    function scope:add(vars)
34       for v in values(vars) do self.current[v] = mlp.gensym(v) end
35    end
36       
37    -----------------------------------------------------------------------------
38    -- Check identifiers; add functions parameters to scope
39    -----------------------------------------------------------------------------
40    function cfg.expr.down(x)
41       match x with
42       | `Splice{...} -> return 'break' -- don't touch user parts
43       | `Id{ name } ->
44          local alpha = scope.current[name]
45          if alpha then x[1] = alpha end
46       | `Function{ params, _ } -> scope:push(); scope:add (params)
47       | _ -> -- pass
48       end
49    end
50
51    -----------------------------------------------------------------------------
52    -- Close the function scope opened by 'down()'
53    -----------------------------------------------------------------------------
54    function cfg.expr.up(x)      
55       match x with `Function{...} -> scope:pop() | _ -> end
56    end
57
58    -----------------------------------------------------------------------------
59    -- Create a new scope and register loop variable[s] in it
60    -----------------------------------------------------------------------------
61    function cfg.stat.down(x)
62       match x with
63       | `Splice{...}           -> return 'break'
64       | `Forin{ vars, ... }    -> scope:push(); scope:add(vars)
65       | `Fornum{ var, ... }    -> scope:push(); scope:add{var}
66       | `Localrec{ vars, ... } -> scope:add(vars)
67       | `Repeat{ block, cond } -> -- 'cond' is in the scope of 'block'
68          scope:push()
69          for s in values (block) do walk.stat(cfg)(s) end -- no new scope
70          walk.expr(cfg)(cond)
71          scope:pop()
72          return 'break' -- No automatic walking of subparts
73       | _ -> -- pass
74       end
75    end
76
77    -----------------------------------------------------------------------------
78    -- Close the scopes opened by 'up()'
79    -----------------------------------------------------------------------------
80    function cfg.stat.up(x)
81       match x with
82       | `Forin{ ... } | `Fornum{ ... } -> scope:pop() -- `Repeat has no up().
83       | `Local{ vars, ... }            -> scope:add(vars)
84       | _ -> -- pass
85       end
86    end
87
88    -----------------------------------------------------------------------------
89    -- Create a separate scope for each block
90    -----------------------------------------------------------------------------
91    function cfg.block.down() scope:push() end
92    function cfg.block.up()   scope:pop()  end
93
94    walk[kind](cfg)(term)
95    return freevars
96 end
97
98 --------------------------------------------------------------------------------
99 -- A wee bit of metatable hackery. Just couldn't resist, sorry.
100 --------------------------------------------------------------------------------
101 freevars = setmetatable ({ scope=scope }, { __index = |_, k| |t| fv(k, t) })