]> git.lizzy.rs Git - metalua.git/commitdiff
working on H:
authorFabien Fleutot <fabien@macfabien.local>
Fri, 1 Feb 2008 08:55:06 +0000 (09:55 +0100)
committerFabien Fleutot <fabien@macfabien.local>
Fri, 1 Feb 2008 08:55:06 +0000 (09:55 +0100)
 allowed to create several hygienizers; found a serious issue with withdo hygienization.

src/lib/extension/H-runtime.mlua
src/lib/extension/H.mlua
src/lib/extension/trycatch.mlua
src/samples/withdo_test.mlua

index 954ee81c33680f527879266ea5efb90d20fef91f..9f82a944ad8e6cddc3d702dbe2b7513faa75e4fb 100644 (file)
@@ -1,8 +1,9 @@
 require 'walk.id'
 -{ extension 'log' }
 
+--------------------------------------------------------------------------------
+--
 -- H params:
-
 -- * H.alpha is the `Local{ } (or `Set{ }) statement which will
 --   receive the alpha-conversions required to restore the free
 --   variables of the transformed term. For instance, 
@@ -26,22 +27,43 @@ require 'walk.id'
 --
 -- * H:reset(field) sets a field to nil, and returns the value of that
 --   field prior to nilification.
+--------------------------------------------------------------------------------
 
-H = { } setmetatable(H, H)
+H = { } --setmetatable(H, H)
+H.__index=H
+H.template = { }
 
+--------------------------------------------------------------------------------
+--
+--------------------------------------------------------------------------------
+function H:new(x)
+   local instance = table.deep_copy(self.template)
+   if x then instance <- x end
+   setmetatable(instance, self)
+   return instance
+end
+
+--------------------------------------------------------------------------------
+--
+--------------------------------------------------------------------------------
 function H:__call (ast)
    assert (type(ast)=='table', "H expects an AST")
 
    local local_renames -- only set if inside hygienization's required
 
-   -- kind of hygienization(s) to perform
+   -----------------------------------------------------------------------------
+   -- kind of hygienization(s) to perform: h_inseide and/or h_outside
+   -----------------------------------------------------------------------------
    local h_inside, h_outside do      
       local side = self.side or 'both'
       h_inside   = side=='inside'  or side=='both'
       h_outside  = side=='outside' or side=='both'
    end
 
+   -----------------------------------------------------------------------------
+   -- Initialize self.keep:
    -- self.keep is a dictionary of free var names to be protected from capture
+   -----------------------------------------------------------------------------
    do 
       local k = self.keep
       -- If there's no self.keep, that's an empty dictionary
@@ -52,12 +74,16 @@ function H:__call (ast)
       else for i, v in ipairs(k) do k[v], k[i] = true, nil end end
    end
 
-   -- Config for the id walker
+   -----------------------------------------------------------------------------
+   -- Config skeleton for the id walker
+   -----------------------------------------------------------------------------
    local cfg = { expr = { }, stat = { }, id = { } }
 
+   -----------------------------------------------------------------------------
    -- Outside hygienization: all free variables are renamed to fresh ones,
    -- and self.alpha is updated to contain the assignments required to keep
    -- the AST's semantics.
+   -----------------------------------------------------------------------------
    if h_outside then
       local alpha = self.alpha
 
@@ -89,18 +115,26 @@ function H:__call (ast)
       end
    end
    
+   -----------------------------------------------------------------------------
+   -- Inside hygienization: rename all local variables and their ocurrences.
+   -----------------------------------------------------------------------------
    if h_inside then
 
+      ----------------------------------------------------------------
       -- Renamings can't performed on-the-spot, as it would
       -- transiently break the link between binders and bound vars,
       -- thus preventing the algo to work. They're therefore stored
       -- in local_renames, and performed after the whole tree has been
       -- walked.
+      ----------------------------------------------------------------
 
       local_renames = { }    -- `Id{ old_name } -> new_name 
       local bound_vars = { } -- binding statement -> old_name -> new_name
 
-      -- Give a new name to newly created local vars, store it in bound_vars
+      ----------------------------------------------------------------
+      -- Give a new name to newly created local vars, store it in
+      -- bound_vars
+      ----------------------------------------------------------------
       function cfg.binder (id, binder)
          if id.h_boundary then return end
          local old_name = id[1]
@@ -114,8 +148,10 @@ function H:__call (ast)
          local_renames[id] = new_name
       end
 
-      -- List a bound var for renaming.
-      -- The new name has already been chosen and put in bound_vars by cfg.binder().
+      ----------------------------------------------------------------
+      -- List a bound var for renaming.  The new name has already been
+      -- chosen and put in bound_vars by cfg.binder().
+      ----------------------------------------------------------------
       function cfg.id.bound (id, binder)
          if id.h_boundary then return end
          local old_name = id[1]
@@ -126,12 +162,16 @@ function H:__call (ast)
       end
    end
 
+   -----------------------------------------------------------------------------
    -- Don't traverse subtrees marked by '!'
+   -----------------------------------------------------------------------------
    local cut_boundaries = |x| x.h_boundary and 'break' or nil
    cfg.stat.down, cfg.expr.down = cut_boundaries, cut_boundaries
 
+   -----------------------------------------------------------------------------
    -- The walker's config is ready, let's go.
    -- After that, ids are renamed in ast, free_vars and bound_vars are set.
+   -----------------------------------------------------------------------------
    walk_id [self.kind or 'guess'] (cfg, ast)
 
    if h_inside then -- Apply local name changes
@@ -141,16 +181,20 @@ function H:__call (ast)
    return ast
 end
 
+--------------------------------------------------------------------------------
 -- Return H to allow call chainings
+--------------------------------------------------------------------------------
 function H:set(field, val) 
    local t = type(field)
    if t=='string' then self[field]=val
-   elseif t=='table' then table.override(self, field)
+   elseif t=='table' then self <- field
    else error("Can't set H, field arg can't be of type "..t) end
    return self 
 end
 
+--------------------------------------------------------------------------------
 -- Return the value before reset
+--------------------------------------------------------------------------------
 function H:reset(field) 
    if type(field) ~= 'string' then error "Can only reset H string fields" end
    local r = H[field]
@@ -158,12 +202,12 @@ function H:reset(field)
    return r
 end
 
-local function commit_locals_to_chunk(x)
-   local alpha = H:reset 'alpha'
-   --$log ('commit locals', x, alpha, 'nohash')
-   if not alpha or not alpha[1][1] then return end
-   if not x then return alpha end
-   table.insert(x, 1, alpha)
-end
+-- local function commit_locals_to_chunk(x)
+--    local alpha = H:reset 'alpha'
+--    --$log ('commit locals', x, alpha, 'nohash')
+--    if not alpha or not alpha[1][1] then return end
+--    if not x then return alpha end
+--    table.insert(x, 1, alpha)
+-- end
 
-mlp.chunk.transformers:add (commit_locals_to_chunk)
\ No newline at end of file
+-- mlp.chunk.transformers:add (commit_locals_to_chunk)
\ No newline at end of file
index a21577f6305eac8d623d62661cf335403fafa651..7bcf81f4f55c9a19fdfaf5ec3daf1bca5017b840 100644 (file)
@@ -10,7 +10,7 @@ mlp.expr.prefix:add{ '!', prec = 5,
                               v }\r
              end }\r
 \r
-mlp.stat:add{ '!', mlp.expr, builder = |x| +{stat: (-{x}).h_boundary=true } }\r
+mlp.stat:add{ '!', mlp.expr, builder = |x| +{stat: (-{x[1]}).h_boundary=true } }\r
 \r
 -- * if there's no boundary in it, is there a need to rename vars?\r
 --   ==> first pass to mark binders which contain boundaries,\r
index 5fbdf43099d3011d7c598c740cd7cf5e5432579d..ef750bba7de645d592000e656d3e5fc569e0fbfd 100644 (file)
@@ -25,6 +25,9 @@
 -- Get match parsers and builder, for catch cases handling:\r
 require 'extension.match' \r
 \r
+-{ extension 'H' }\r
+-{ extension 'log' }\r
+\r
 -- We'll need to track rogue return statements:\r
 require 'walk'\r
 \r
@@ -36,6 +39,9 @@ function trycatch_builder(x)
    local try_code, catch_cases, finally_code = unpack(x)\r
    local insert_return_catcher = false\r
 \r
+   local H = H:new{side='inside'}\r
+   !try_code; !(catch_code or { }); !(finally_code or { })\r
+\r
    --$log(try_code, catch_cases, finally_code)\r
 \r
    ----------------------------------------------------------------\r
@@ -66,13 +72,14 @@ function trycatch_builder(x)
          match x with \r
          | `Return{...} -> \r
             insert_return_catcher = true\r
-            local setvar = \r
-               +{stat:caught_return = -{ `Table{ unpack(x) } } }\r
-            x.tag = nil\r
-            x <- { setvar; `Return }\r
+-- FIXME: caught_return won't be tranformed because it's inside \r
+--        a user-bounded block\r
+            local setvar = +{stat:caught_return = -{`Table{ unpack(x) }}}\r
+            x <- { setvar; `Return }; x.tag = nil;\r
+            $log('transformed return stat:', x, 60)\r
             return 'break'\r
          | `Function{...} -> return 'break' \r
-            -- inside this, returns would be the function's, not ours.\r
+            -- inside this, returns would be the nested function's, not ours.\r
          | _ -> -- pass\r
          end\r
       end\r
@@ -85,7 +92,7 @@ function trycatch_builder(x)
 \r
    -- code handling the error catching process:\r
    local catch_result do\r
-      if catch_cases then\r
+      if #catch_cases>0 then\r
          ----------------------------------------------------------\r
          -- Protect catch code against failures: they run in a pcall(), and\r
          -- the result is kept in catch_* vars so that it can be used to\r
@@ -137,6 +144,9 @@ function trycatch_builder(x)
          if not user_success and not catch_success then error(catch_error) end \r
          -{ caught_return_rethrow }\r
       end }\r
+\r
+   H(result)\r
+\r
    return result\r
 end\r
 \r
index 3d68db9972d9ed9768b15123f33923cd75710966..dcb9283dd9508cbb80b861d502cdb6d51e931ae9 100644 (file)
@@ -1,18 +1,23 @@
 -{ extension 'withdo' }
 
 local original_close = io.close
-function io:close()
-   original_close(self)
-   print "closed a file"
+
+--[[
+function x()
+   --with f = io.open 'withdo_test.mlua' do
+   with f1, f2 = io.open 'withdo_test.mlua', io.open 'trycatch_test.mlua' do
+      local t1 = f1:read '*a'
+      local t2 = f2:read '*a'
+      return #t1, #t2
+   end
 end
+--]]
 
 function x()
    --with f = io.open 'withdo_test.mlua' do
-   with f = io.open 'withdo_test.mlua' do
-      for l in f:lines() do
-         printf("[%s]", l)
-      end
-      return '123'
+   with f1 = io.open 'withdo_test.mlua' do
+      local t1 = f1:read '*a'
+      return #t1
    end
 end