]> git.lizzy.rs Git - metalua.git/blobdiff - junk/hygienic2.lua
Fixing the previous merge :(
[metalua.git] / junk / hygienic2.lua
diff --git a/junk/hygienic2.lua b/junk/hygienic2.lua
new file mode 100644 (file)
index 0000000..d0ca8c3
--- /dev/null
@@ -0,0 +1,101 @@
+--------------------------------------------------------------------------------
+--
+-- (c) Fabien Fleutot 2007, published under the MIT license.
+--
+--
+-- API:
+-- ----
+-- * freevars.block(ast)
+-- * freevars.expr(ast)
+-- * freevars.stat(ast)
+--
+--------------------------------------------------------------------------------
+
+require 'std'
+require 'walk'
+require 'freevars'
+
+-{ extension 'match' }
+
+--------------------------------------------------------------------------------
+-- Return the string->boolean hash table of the names of all free variables
+-- in 'term'. 'kind' is the name of an entry in module 'walk', presumably
+-- one of 'expr', 'stat' or 'block'.
+--------------------------------------------------------------------------------
+local function alpha (kind, term)
+   local cfg = { expr  = { }, stat  = { }, block = { } }
+
+   -----------------------------------------------------------------------------
+   -- Monkey-patch the scope add method, so that it associates a unique name
+   -- to bound vars.
+   -----------------------------------------------------------------------------
+   local scope = scope:new()
+   function scope:add(vars)
+      for v in values(vars) do self.current[v] = mlp.gensym(v) end
+   end
+      
+   -----------------------------------------------------------------------------
+   -- Check identifiers; add functions parameters to scope
+   -----------------------------------------------------------------------------
+   function cfg.expr.down(x)
+      match x with
+      | `Splice{...} -> return 'break' -- don't touch user parts
+      | `Id{ name } ->
+         local alpha = scope.current[name]
+         if alpha then x[1] = alpha end
+      | `Function{ params, _ } -> scope:push(); scope:add (params)
+      | _ -> -- pass
+      end
+   end
+
+   -----------------------------------------------------------------------------
+   -- Close the function scope opened by 'down()'
+   -----------------------------------------------------------------------------
+   function cfg.expr.up(x)      
+      match x with `Function{...} -> scope:pop() | _ -> end
+   end
+
+   -----------------------------------------------------------------------------
+   -- Create a new scope and register loop variable[s] in it
+   -----------------------------------------------------------------------------
+   function cfg.stat.down(x)
+      match x with
+      | `Splice{...}           -> return 'break'
+      | `Forin{ vars, ... }    -> scope:push(); scope:add(vars)
+      | `Fornum{ var, ... }    -> scope:push(); scope:add{var}
+      | `Localrec{ vars, ... } -> scope:add(vars)
+      | `Repeat{ block, cond } -> -- 'cond' is in the scope of 'block'
+         scope:push()
+         for s in values (block) do walk.stat(cfg)(s) end -- no new scope
+         walk.expr(cfg)(cond)
+         scope:pop()
+         return 'break' -- No automatic walking of subparts
+      | _ -> -- pass
+      end
+   end
+
+   -----------------------------------------------------------------------------
+   -- Close the scopes opened by 'up()'
+   -----------------------------------------------------------------------------
+   function cfg.stat.up(x)
+      match x with
+      | `Forin{ ... } | `Fornum{ ... } -> scope:pop() -- `Repeat has no up().
+      | `Local{ vars, ... }            -> scope:add(vars)
+      | _ -> -- pass
+      end
+   end
+
+   -----------------------------------------------------------------------------
+   -- Create a separate scope for each block
+   -----------------------------------------------------------------------------
+   function cfg.block.down() scope:push() end
+   function cfg.block.up()   scope:pop()  end
+
+   walk[kind](cfg)(term)
+   return freevars
+end
+
+--------------------------------------------------------------------------------
+-- A wee bit of metatable hackery. Just couldn't resist, sorry.
+--------------------------------------------------------------------------------
+freevars = setmetatable ({ scope=scope }, { __index = |_, k| |t| fv(k, t) })