1 --------------------------------------------------------------------------------
3 -- (c) Fabien Fleutot 2007, published under the MIT license.
8 -- * freevars.block(ast)
9 -- * freevars.expr(ast)
10 -- * freevars.stat(ast)
12 --------------------------------------------------------------------------------
18 -{ extension
'match' }
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
= { } }
28 -----------------------------------------------------------------------------
29 -- Monkey-patch the scope add method, so that it associates a unique name
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
37 -----------------------------------------------------------------------------
38 -- Check identifiers; add functions parameters to scope
39 -----------------------------------------------------------------------------
40 function cfg
.expr
.down(x
)
42 | `Splice
{...} -> return 'break' -- don't touch user parts
44 local alpha
= scope
.current
[name
]
45 if alpha
then x
[1] = alpha
end
46 | `Function
{ params
, _
} -> scope
:push(); scope
:add (params
)
51 -----------------------------------------------------------------------------
52 -- Close the function scope opened by 'down()'
53 -----------------------------------------------------------------------------
54 function cfg
.expr
.up(x
)
55 match x with `Function
{...} -> scope
:pop() | _
-> end
58 -----------------------------------------------------------------------------
59 -- Create a new scope and register loop variable[s] in it
60 -----------------------------------------------------------------------------
61 function cfg
.stat
.down(x
)
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'
69 for s
in values (block
) do walk
.stat(cfg
)(s
) end -- no new scope
72 return 'break' -- No automatic walking of subparts
77 -----------------------------------------------------------------------------
78 -- Close the scopes opened by 'up()'
79 -----------------------------------------------------------------------------
80 function cfg
.stat
.up(x
)
82 | `Forin
{ ... } | `Fornum
{ ... } -> scope
:pop() -- `Repeat has no up().
83 | `Local
{ vars
, ... } -> scope
:add(vars
)
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
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
) })