Merge remote-tracking branch 'origin/v0.7.2'
diff --git a/README-parser.md b/README-parser.md
index d5edacc..98e34ee 100644
--- a/README-parser.md
+++ b/README-parser.md
@@ -85,7 +85,7 @@
       `Nil  |  `Dots  |  `True  |  `False
     | `Number{ <number> }
     | `String{ <string> }
-    | `Function{ { `Id{ <string> }* `Dots? } block }
+    | `Function{ { ident* `Dots? } block }
     | `Table{ ( `Pair{ expr expr } | expr )* }
     | `Op{ opid expr expr? }
     | `Paren{ expr }       -- significant to cut multiple values returns
@@ -96,7 +96,9 @@
       `Call{ expr expr* }
     | `Invoke{ expr `String{ <string> } expr* }
 
-    lhs: `Id{ <string> } | `Index{ expr expr }
+    ident: `Id{ <string> }
+
+    lhs: ident | `Index{ expr expr }
 
     opid: 'add'   | 'sub'   | 'mul'   | 'div'
         | 'mod'   | 'pow'   | 'concat'| 'eq'
diff --git a/metalua.lua b/bin/metalua
similarity index 94%
rename from metalua.lua
rename to bin/metalua
index eee8e6e..77e0b65 100644
--- a/metalua.lua
+++ b/bin/metalua
@@ -1,5 +1,7 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
+#!/usr/bin/env lua51
+--*-lua-*----------------------------------------------------------------------
+--
+-- Copyright (c) 2006-2014 Fabien Fleutot and others.
 --
 -- All rights reserved.
 --
@@ -88,8 +90,6 @@
     local argv = {...}
     local opts, optind, optarg =
         alt_getopt.get_ordered_opts({...}, alt_getopt_options, long_opts)
-    --pp.printf("argv=%s; opts=%s, ending at %i, with optarg=%s",
-    --          argv, opts, optind, optarg)
     local s2l = { } -- short to long option names conversion table
     for long, short in pairs(long_opts) do s2l[short]=long end
     local cfg = { chunks = { } }
@@ -108,7 +108,6 @@
 
    -------------------------------------------------------------------
    -- Print messages if in verbose mode
-   -------------------------------------------------------------------
    local function verb_print (fmt, ...)
       if cfg.verbose then
          return pp.printf ("[ "..fmt.." ]", ...)
@@ -125,7 +124,7 @@
    if not next(cfg.chunks) and next(cfg.params) then
       local the_file = table.remove(cfg.params, 1)
       verb_print("Param %q considered as a source file", the_file)
-      cfg.file={ the_file }
+      cfg.chunks={ { tag='file', the_file } }
    end
 
    -------------------------------------------------------------------
@@ -135,7 +134,6 @@
       cfg.interactive=true
    end
 
-
    -------------------------------------------------------------------
    -- Run if asked to, or if no --output has been given
    -- if cfg.run==false it's been *forced* to false, don't override.
@@ -182,8 +180,8 @@
    end
    -- The last file returns the whole chunk's result
    if last_file_idx then
-       -- transform  +{ (function(...) -{ast} end)(...) }
-       -- into   +{ return (function(...) -{ast} end)(...) }
+       -- transform  `+{ (function(...) -{ast} end)(...) }`
+       -- into       `+{ return (function(...) -{ast} end)(...) }`
        local prv_ast = code[last_file_idx]
        local new_ast = { tag='Return', prv_ast }
        code[last_file_idx] = new_ast
diff --git a/metalua/compiler/ast_to_src.mlua b/metalua/compiler/ast_to_src.mlua
index 9054088..ca80a12 100644
--- a/metalua/compiler/ast_to_src.mlua
+++ b/metalua/compiler/ast_to_src.mlua
@@ -21,6 +21,7 @@
 
 local M = { }
 M.__index = M
+M.__call = |self, ...| self:run(...)
 
 local pp=require 'metalua.pprint'
 
@@ -160,24 +161,34 @@
 --------------------------------------------------------------------------------
 function M:node (node)
    assert (self~=M and self._acc)
-   if node==nil then self:acc'<<error>>'; return end
-   if not node.tag then -- tagless block.
-      self:list (node, self.nl)
-   else
-      local f = M[node.tag]
-      if type (f) == "function" then -- Delegate to tag method.
-         f (self, node, unpack (node))
-      elseif type (f) == "string" then -- tag string.
-         self:acc (f)
-      else -- No appropriate method, fall back to splice dumping.
-           -- This cannot happen in a plain Lua AST.
-         self:acc " -{ "
-         self:acc (pp.tostring (node, {metalua_tag=1, hide_hash=1}), 80)
-         self:acc " }"
+   if node==nil then self:acc'<<error>>'
+   elseif not self.custom_printer or not self.custom_printer (self, node) then
+       if not node.tag then -- tagless (henceunindented) block.
+           self:list (node, self.nl)
+       else
+          local f = M[node.tag]
+          if type (f) == "function" then -- Delegate to tag method.
+              f (self, node, unpack (node))
+          elseif type (f) == "string" then -- tag string.
+              self:acc (f)
+          else -- No appropriate method, fall back to splice dumping.
+              -- This cannot happen in a plain Lua AST.
+              self:acc " -{ "
+              self:acc (pp.tostring (node, {metalua_tag=1, hide_hash=1}), 80)
+              self:acc " }"
+          end
       end
    end
 end
 
+function M:block(body)
+    if not self.custom_printer or not self.custom_printer (self, body) then
+        self:nlindent ()
+        self:list     (body, self.nl)
+        self:nldedent ()
+    end
+end
+
 --------------------------------------------------------------------------------
 -- Convert every node in the AST list `list' passed as 1st arg.
 -- `sep' is an optional separator to be accumulated between each list element,
@@ -225,9 +236,7 @@
 
 function M:Do (node)
    self:acc      "do"
-   self:nlindent ()
-   self:list     (node, self.nl)
-   self:nldedent ()
+   self:block    (node)
    self:acc      "end"
 end
 
@@ -244,9 +253,7 @@
       self:acc      " ("
       self:list     (params, ", ", 2)
       self:acc      ")"
-      self:nlindent ()
-      self:list     (body, self.nl)
-      self:nldedent ()
+      self:block    (body)
       self:acc      "end"
 
    | `Set{ { lhs }, { `Function{ params, body } } } if is_idx_stack (lhs) ->
@@ -256,9 +263,7 @@
       self:acc      " ("
       self:list     (params, ", ")
       self:acc      ")"
-      self:nlindent ()
-      self:list    (body, self.nl)
-      self:nldedent ()
+      self:block    (body)
       self:acc      "end"
 
    | `Set{ { `Id{ lhs1name } == lhs1, ... } == lhs, rhs }
@@ -303,17 +308,13 @@
    self:acc      "while "
    self:node     (cond)
    self:acc      " do"
-   self:nlindent ()
-   self:list     (body, self.nl)
-   self:nldedent ()
+   self:block    (body)
    self:acc      "end"
 end
 
 function M:Repeat (node, body, cond)
    self:acc      "repeat"
-   self:nlindent ()
-   self:list     (body, self.nl)
-   self:nldedent ()
+   self:block    (body)
    self:acc      "until "
    self:node     (cond)
 end
@@ -325,16 +326,12 @@
       self:acc      (i==1 and "if " or "elseif ")
       self:node     (cond)
       self:acc      " then"
-      self:nlindent ()
-      self:list     (body, self.nl)
-      self:nldedent ()
+      self:block    (body)
    end
    -- odd number of children --> last one is an `else' clause --
    if #node%2 == 1 then
       self:acc      "else"
-      self:nlindent ()
-      self:list     (node[#node], self.nl)
-      self:nldedent ()
+      self:block    (node[#node])
    end
    self:acc "end"
 end
@@ -352,9 +349,7 @@
       self:node  (node[4])
    end
    self:acc      " do"
-   self:nlindent ()
-   self:list     (body, self.nl)
-   self:nldedent ()
+   self:block    (body)
    self:acc      "end"
 end
 
@@ -364,9 +359,7 @@
    self:acc      " in "
    self:list     (generators, ", ")
    self:acc      " do"
-   self:nlindent ()
-   self:list     (body, self.nl)
-   self:nldedent ()
+   self:block    (body)
    self:acc      "end"
 end
 
@@ -406,9 +399,7 @@
       self:acc      " ("
       self:list     (params, ", ")
       self:acc      ")"
-      self:nlindent ()
-      self:list     (body, self.nl)
-      self:nldedent ()
+      self:block    (body)
       self:acc      "end"
 
    | _ ->
@@ -488,9 +479,7 @@
         self:list (params, ", ")
     end
     self:acc      ")"
-    self:nlindent ()
-    self:list     (body, self.nl)
-    self:nldedent ()
+    self:block    (body)
     self:acc      "end"
 end
 
@@ -690,4 +679,4 @@
     end
 end
 
-return (|x| M.run(x))
+return M
diff --git a/metalua/loader.lua b/metalua/loader.lua
index 9c4754f..e535fef 100644
--- a/metalua/loader.lua
+++ b/metalua/loader.lua
@@ -52,9 +52,9 @@
       --printf('path = %s, rpath_mark=%s, name=%s', path, resc(path_mark), name)
       local filename = path:gsub (resc (path_mark), name)
       --printf('filename = %s', filename)
-      local file = io.open (filename, 'r')
+      local file = io.open (filename, 'rb')
       if file then return file, filename end
-      table.insert(errors, string.format("\tno lua file %q", filename))
+      table.insert(errors, string.format("\tno file %q", filename))
    end
    return false, '\n'..table.concat(errors, "\n")..'\n'
 end
@@ -80,7 +80,7 @@
     local bytecode, file, msg
     if delta <= 0 then
        --print ("(need to recompile "..src_filename.." into "..dst_filename..")")
-       bytecode = mlc :src_to_bytecode (src, name)
+       bytecode = mlc :src_to_bytecode (src, '@'..src_filename)
        for x in dst_filename :gmatch('()'..dir_sep) do
           lfs.mkdir(dst_filename:sub(1,x))
        end
@@ -94,7 +94,7 @@
        bytecode = file :read '*a'
        file :close()
     end
-    return mlc :bytecode_to_function (bytecode)
+    return mlc :bytecode_to_function (bytecode, '@'..src_filename)
 end
 
 ----------------------------------------------------------------------
@@ -107,7 +107,7 @@
    file:close()
    if M.mcache and pcall(require, 'lfs') then
       return metalua_cache_loader(name, filename_or_msg, luastring)
-   else return require 'metalua.compiler'.new() :src_to_function (luastring, name) end
+   else return require 'metalua.compiler'.new() :src_to_function (luastring, '@'..filename_or_msg) end
 end
 
 
diff --git a/metalua/treequery.mlua b/metalua/treequery.mlua
index f5b09d2..e369b99 100755
--- a/metalua/treequery.mlua
+++ b/metalua/treequery.mlua
@@ -299,7 +299,7 @@
     local tag = node.tag
     if not tag then return false
     elseif STAT_TAGS[tag] then return true
-    elseif tag=='Call' or tag=='Invoke' then return parent.tag==nil
+    elseif tag=='Call' or tag=='Invoke' then return parent and parent.tag==nil
     else return false end
 end
 
@@ -435,6 +435,27 @@
     end
 end
 
+--- Returns a list of the direct children of AST node `ast`.
+--  Children are only expressions, statements and blocks,
+--  not intermediates such as `Pair` nodes or internal lists
+--  in `Local` or `Set` nodes.
+--  Children are returned in parsing order, which isn't necessarily
+--  the same as source code order. For instance, the right-hand-side
+--  of a `Local` node is listed before the left-hand-side, because
+--  semantically the right is evaluated before the variables on the
+--  left enter scope.
+--
+--  @param ast the node whose children are needed
+--  @return a list of the direct children of `ast`
+function M.children(ast)
+    local acc = { }
+    local cfg = { }
+    function cfg.down(x)
+        if x~=ast then table.insert(acc, x); return 'break' end
+    end
+    walk.guess(cfg, ast)
+    return acc
+end
 
 -- -----------------------------------------------------------------------------
 -- -----------------------------------------------------------------------------
diff --git a/metalua/treequery/walk.mlua b/metalua/treequery/walk.mlua
index 67dacfd..94fc5d6 100755
--- a/metalua/treequery/walk.mlua
+++ b/metalua/treequery/walk.mlua
@@ -18,35 +18,35 @@
 -------------------------------------------------------------------------------
 
 -- Low level AST traversal library.
--- This library is a helper for the higher-level treequery library.
+--
+-- This library is a helper for the higher-level `treequery` library.
 -- It walks through every node of an AST, depth-first, and executes
--- some callbacks contained in its cfg config table:
+-- some callbacks contained in its `cfg` config table:
 --
--- * cfg.down(...) is called when it walks down a node, and receive as
+-- * `cfg.down(...)` is called when it walks down a node, and receive as
 --   parameters the node just entered, followed by its parent, grand-parent
 --   etc. until the root node.
 --
--- * cfg.up(...) is called when it walks back up a node, and receive as
+-- * `cfg.up(...)` is called when it walks back up a node, and receive as
 --   parameters the node just entered, followed by its parent, grand-parent
 --   etc. until the root node.
 --
--- * cfg.occurrence(binder, id_node, ...) is called when it visits an `Id{ }
---   node which isn't a local variable creator. binder is a reference to its
---   binder with its context. The binder is the `Id{ } node which created 
---   this local variable. By "binder and its context", we mean a list starting
---   with the `Id{ }, and followed by every ancestor of the binder node, up until
---   the common root node.
---   binder is nil if the variable is global.
---   id_node is followed by its ancestor, up until the root node.
+-- * `cfg.occurrence(binder, id_node, ...)` is called when it visits
+--   an `` `Id{ }`` node which isn't a local variable creator. binder
+--   is a reference to its binder with its context. The binder is the
+--   `` `Id{ }`` node which created this local variable. By "binder
+--   and its context", we mean a list starting with the `` `Id{ }``,
+--   and followed by every ancestor of the binder node, up until the
+--   common root node.  `binder` is nil if the variable is global.
+--   `id_node` is followed by its ancestor, up until the root node.
 --
--- cfg.scope is maintained during the traversal, associating a
+-- `cfg.scope` is maintained during the traversal, associating a
 -- variable name to the binder which creates it in the context of the
 -- node currently visited.
 --
--- walk.traverse.xxx functions are in charge of the recursive descent into
--- children nodes. They're private helpers.
---
--- corresponding walk.xxx functions also take care of calling cfg callbacks.
+-- `walk.traverse.xxx` functions are in charge of the recursive
+-- descent into children nodes. They're private helpers. They are also
+-- in charge of calling appropriate `cfg.xxx` callbacks.
 
 -{ extension ("match", ...) }
 
@@ -74,6 +74,7 @@
 -- These [M.traverse.xxx()] functions are in charge of actually going through
 -- ASTs. At each node, they make sure to call the appropriate walker.
 --------------------------------------------------------------------------------
+
 function M.traverse.stat (cfg, x, ...)
    if M.debug then pp.printf("traverse stat %s", x) end
    local ancestors = {...}
@@ -180,10 +181,15 @@
     local f = cfg.binder
     local ferror = cfg.error or cfg.malformed or cfg.unknown
     for i, id_node in ipairs(id_list) do
+      local down, up = cfg.down, cfg.up
       if id_node.tag == 'Id' then
          cfg.scope :set (id_node[1], { id_node, ... })
+         if down then down(id_node, ...) end
          if f then f(id_node, ...) end
+         if up then up(id_node, ...) end
       elseif i==#id_list and id_node.tag=='Dots' then
+         if down then down(id_node, ...) end
+         if up then up(id_node, ...) end
          -- Do nothing, those are valid `Dots
       elseif ferror then
          -- Traverse error handling function
@@ -213,7 +219,10 @@
 end
 
 ----------------------------------------------------------------------
--- Declare [M.stat], [M.expr], [M.block] and [M.expr_list]
+-- Declare [M.stat], [M.expr], [M.block].
+-- `M.binder_list` is not here, because `cfg.up` and `cfg.down` must
+-- be called on individual binders, not on the list itself.
+-- It's therefore handled in `traverse.binder_list()`
 ----------------------------------------------------------------------
 for _, w in ipairs{ "stat", "expr", "block" } do --, "malformed", "unknown" } do
    M[w] = walker_builder (w, M.traverse[w])