Licensing
diff --git a/checks.lua b/checks.lua
new file mode 100644
index 0000000..c0c99ac
--- /dev/null
+++ b/checks.lua
@@ -0,0 +1,59 @@
+--------------------------------------------------------------------------------
+-- Copyright (c) 2006-2013 Fabien Fleutot and others.
+--
+-- All rights reserved.
+--
+-- This program and the accompanying materials are made available
+-- under the terms of the Eclipse Public License v1.0 which
+-- accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- This program and the accompanying materials are also made available
+-- under the terms of the MIT public license which accompanies this
+-- distribution, and is available at http://www.lua.org/license.html
+--
+-- Contributors:
+--     Fabien Fleutot - API and implementation
+--
+--------------------------------------------------------------------------------
+
+-- Alternative implementation of checks() in Lua. Slower than
+-- the C counterpart, but no compilation/porting concerns.
+
+checkers = { }
+
+local function check_one(expected, val)
+    if type(val)==expected then return true end
+    local mt = getmetatable(val)
+    if mt and mt.__type==expected then return true end
+    local f = checkers[expected]
+    if f and f(val) then return true end
+    return false
+end
+
+local function check_many(name, expected, val)
+    if expected=='?' then return true
+    elseif expected=='!' then return (val~=nil)
+    elseif type(expected) ~= 'string' then
+        error 'strings expected by checks()'
+    elseif val==nil and expected :sub(1,1) == '?' then return true end
+    for one in expected :gmatch "[^|?]+" do
+        if check_one(one, val) then return true end
+    end
+    return false
+end
+
+function checks(...)
+    for i, arg in ipairs{...} do
+        local name, val = debug.getlocal(2, i)
+        local success = check_many(name, arg, val)
+        if not success then
+            local fname = debug.getinfo(2, 'n').name
+            local fmt = "bad argument #%d to '%s' (%s expected, got %s)"
+            local msg = string.format(fmt, i, fname or "?", arg, type(val))
+            error(msg, 3)
+        end
+    end
+end
+
+return checks
diff --git a/compiler/Makefile b/compiler/Makefile
deleted file mode 100644
index 2d9d88c..0000000
--- a/compiler/Makefile
+++ /dev/null
@@ -1,67 +0,0 @@
-include ../config
-
-all: $(LIBRARIES) install metalua
-
-$(PLATFORM): all
-
-LUA_RUN     = ../$(LUA_VM_DIR)/$(RUN)
-LUA_COMPILE = ../$(LUA_VM_DIR)/$(COMPILE)
-
-LIBRARIES =       \
-	bytecode.luac \
-	mlp.luac      \
-	mlc.luac      
-
-# Library which compiles an AST into a bytecode string.
-BYTECODE_LUA =      \
-      lopcodes.lua  \
-      lcode.lua     \
-      ldump.lua     \
-      compile.lua   
-
-# Library which compiles source strings into AST
-MLP_LUA =           \
-      lexer.lua     \
-      gg.lua        \
-      mlp_lexer.lua \
-      mlp_misc.lua  \
-      mlp_table.lua \
-      mlp_meta.lua  \
-      mlp_expr.lua  \
-      mlp_stat.lua  \
-      mlp_ext.lua 
-
-metalua.luac: mlc.luac
-
-bytecode.luac: $(BYTECODE_LUA)
-	$(LUA_COMPILE) -o $@ $^
-
-mlp.luac: $(MLP_LUA)
-	$(LUA_COMPILE) -o $@ $^
-
-# Plain lua files compilation
-%.luac: %.mlua bootstrap.lua mlp.luac bytecode.luac
-	$(LUA_RUN) bootstrap.lua $<
-
-# FIXME what's this?! some old stuff from when metalua files hadn't their own
-# extensions?
-# Metalua files compilation through the bootstrap compiler
-%.luac: %.lua
-	$(LUA_COMPILE) -o $@ bootstrap $<
-
-# Compiler/interpreter
-metalua: metalua.luac install-lib
-	$(LUA_RUN) metalua.luac --verbose --sharpbang '#!$(TARGET_BIN_PATH)/lua' --output metalua --file metalua.mlua
-
-install-lib: $(LIBRARIES)
-	mkdir -p $(TARGET_LUA_PATH)/metalua
-	cp $(LIBRARIES) $(TARGET_LUA_PATH)/metalua/
-
-install: install-lib metalua
-	mkdir -p $(TARGET_BIN_PATH)
-	cp metalua $(TARGET_BIN_PATH)/
-
-.PHONY: all install
-
-clean:
-	-rm *.luac metalua 
diff --git a/compiler/mlc.mlua b/compiler/mlc.mlua
deleted file mode 100644
index 86a64df..0000000
--- a/compiler/mlc.mlua
+++ /dev/null
@@ -1,248 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--------------------------------------------------------------------------------
--- This module is written in a more hackish way than necessary, just
--- because I can.  Its core feature is to dynamically generate a
--- function that converts from a source format to a destination
--- format; these formats are the various ways to represent a piece of
--- program, from the source file to the executable function. Legal
--- formats are:
---
--- * luafile:    the name of a file containing sources.
--- * luastring:  these sources as a single string.
--- * lexstream:  a stream of lexemes.
--- * ast:        an abstract syntax tree.
--- * proto:      a (Yueliang) struture containing a high level
---               representation of bytecode. Largely based on the
---               Proto structure in Lua's VM.
--- * luacstring: a string dump of the function, as taken by
---               loadstring() and produced by string.dump().
--- * function:   an executable lua function in RAM.
---
--------------------------------------------------------------------------------
-
-require 'metalua.bytecode'
-require 'metalua.mlp'
-
-mlc = { }
-setmetatable(mlc, mlc)
-mlc.metabugs = false
-
---------------------------------------------------------------------------------
--- Order of the transformations. if 'a' is on the left of 'b', then a 'a' can
--- be transformed into a 'b' (but not the other way around).
--- mlc.sequence goes for numbers to format names, mlc.order goes from format
--- names to numbers.
---------------------------------------------------------------------------------
-mlc.sequence = {
-   'luafile',  'luastring', 'lexstream', 'ast', 'proto', 
-   'luacstring', 'function' }
-mlc.order = table.transpose(mlc.sequence)
-
--- Check whether a structure of nested tables is a valid AST.
--- Currently thows an error if it isn't.
--- @return true When no error is found in given ast
--- @return false, error string
--- @return false, error string, positions Provide position of error in
---  given ast as a table. The position contains the following keys
---    * column: number
---    * line  : number
---    * offset: number
--- TODO: build a detailed error location, with the lineinfo of every nested node.
-local function check_ast(kind, ast)
-    if not ast then return check_ast('block', kind) end
-    assert(type(ast)=='table', "wrong AST type")
-    local cfg = {}
-    local function error2ast(error_node, ...)
-        if not error_node.stuffing then
-            if error_node.tag=='Error' then
-                cfg.errorfound = true
-                cfg.errormsg = error_node[1]
-
-                -- Try to extract error position in source
-                local li = error_node.lineinfo and error_node.lineinfo.first
-
-                -- Fill positions if undefined or not narrow enough
-                if li and ( not cfg.positions or cfg.positions.offset < li.offset ) then
-                    cfg.positions = {
-                        column = li.column,
-                        line   = li.line,
-                        offset = li.offset
-                    }
-                end
-            else
-                -- This block is for dealing with errors which are not error
-                -- nodes. It would be soooo nice to get rid of it.
-                -- TODO: Try to remove this bug when issue #20 is fixed
-                local li
-                for _, n in ipairs{ error_node, ... } do
-                    if n.lineinfo then
-                        li = n.lineinfo
-                        cfg.errorfound = true
-                        break
-                    end
-                end
-                local posmsg
-                if li then
-                    local column = li.first.column
-                    local line   = li.first.line
-                    local offset = li.first.offset
-                    posmsg = string.format("line %d, char %d, offset %d",
-                                          line, column, offset)
-                    cfg.positions = {
-                        column = column,
-                        line   = line,
-                        offset = offset
-                    }
-                else
-                    posmsg = "unknown source position"     
-                end
-                local msg = "Invalid node "..
-                    (error_node.tag and "tag "..tostring(error_node.tag) or "without tag")..
-                    (posmsg and " at "..posmsg or "")
-                cfg.errormsg = msg
-            end
-        end
-    end
-    local f = require 'metalua.treequery.walk' [kind]
-    cfg.malformed=error2ast
-    cfg.unknown=  error2ast
-    cfg.error=    error2ast
-    f(cfg, ast)
-    return cfg.errorfound == nil, cfg.errormsg, cfg.positions
-end
-
-mlc.check_ast = check_ast
-
-function mlc.luafile_to_luastring(x, name)
-    name = name or '@'..x
-    local f, msg = io.open (x, 'rb')
-    if not f then return f, msg end
-    local r = f :read '*a'
-    f :close()
-    return r, name
-end
-
-function mlc.luastring_to_lexstream(src, name)
-    local r = mlp.lexer :newstream (src, name)
-    return r, name
-end
-
-function mlc.lexstream_to_ast(lx, name)
-    if PRINT_PARSED_STAT then
-        print("About to parse a lexstream, starting with "..tostring(lx:peek()))
-    end
-    local r = mlp.chunk(lx)    
-    r.source = name
-    return r, name
-end
-
-function mlc.ast_to_proto(ast, name)
-    name = name or ast.source
-    return bytecode.metalua_compile(ast, name), name
-end
-
-function mlc.proto_to_luacstring(proto, name)
-    return bytecode.dump_string(proto), name
-end
-
-function mlc.luacstring_to_function(bc, name)
-    return string.undump(bc, name)
-end
-
--- Create all sensible combinations
-for i=1,#mlc.sequence do
-    for j=i+2, #mlc.sequence do
-        local dst_name = mlc.sequence[i].."_to_"..mlc.sequence[j]
-        local functions = { }
-        --local n = { }
-        for k=i, j-1 do
-            local name =  mlc.sequence[k].."_to_"..mlc.sequence[k+1]
-            local f = assert(mlc[name])
-            table.insert (functions, f)
-            --table.insert(n, name)
-        end
-        mlc[dst_name] = function(a, b)
-            for _, f in ipairs(functions) do
-                a, b = f(a, b)
-            end
-            return a, b
-        end
-        --printf("Created mlc.%s out of %s", dst_name, table.concat(n, ', '))
-    end
-end
-
-
---------------------------------------------------------------------------------
--- This case isn't handled by the __index method, as it goes "in the wrong direction"
---------------------------------------------------------------------------------
-mlc.function_to_luacstring = string.dump
-
---------------------------------------------------------------------------------
--- These are drop-in replacement for loadfile() and loadstring(). The
--- C functions will call them instead of the original versions if
--- they're referenced in the registry.
---------------------------------------------------------------------------------
-
-lua_loadstring = loadstring
-local lua_loadstring = loadstring
-lua_loadfile = loadfile
-local lua_loadfile = loadfile
-
-function loadstring(str, name)
-   if type(str) ~= 'string' then error 'string expected' end
-   if str:match '^\027LuaQ' then return lua_loadstring(str) end
-   local n = str:match '^#![^\n]*\n()'
-   if n then str=str:sub(n, -1) end
-   -- FIXME: handle erroneous returns (return nil + error msg)
-   local success, f = pcall (mlc.luastring_to_function, str, name)
-   if success then return f else return nil, f end
-end
-
-function loadfile(filename)
-   local f, err_msg = io.open(filename, 'rb')
-   if not f then return nil, err_msg end
-   local success, src = pcall( f.read, f, '*a')
-   pcall(f.close, f)
-   if success then return loadstring (src, '@'..filename)
-   else return nil, src end
-end
-
-function load(f, name)
-   while true do
-      local x = f()
-      if not x then break end
-      assert(type(x)=='string', "function passed to load() must return strings")
-      table.insert(acc, x)
-   end
-   return loadstring(table.concat(x))
-end
-
-function dostring(src)
-   local f, msg = loadstring(src)
-   if not f then error(msg) end
-   return f()
-end
-
-function dofile(name)
-   local f, msg = loadfile(name)
-   if not f then error(msg) end
-   return f()
-end
diff --git a/compiler/mlp_expr.lua b/compiler/mlp_expr.lua
deleted file mode 100644
index 0c7949c..0000000
--- a/compiler/mlp_expr.lua
+++ /dev/null
@@ -1,194 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
---------------------------------------------------------------------------------
---
--- Exported API:
--- * [mlp.expr()]
--- * [mlp.expr_list()]
--- * [mlp.func_val()]
---
---------------------------------------------------------------------------------
-
---require "gg"
---require "mlp_misc"
---require "mlp_table"
---require "mlp_meta"
-
---------------------------------------------------------------------------------
--- These function wrappers (eta-expansions actually) are just here to break
--- some circular dependencies between mlp_xxx.lua files.
---------------------------------------------------------------------------------
-local function _expr (lx) return  mlp.expr (lx) end
-local function block (lx) return mlp.block (lx) end
-local function stat  (lx) return mlp.stat (lx)  end
-
-local function _table_content (lx) return mlp.table_content (lx) end
-
-module ("mlp", package.seeall)
-
---------------------------------------------------------------------------------
--- Non-empty expression list. Actually, this isn't used here, but that's
--- handy to give to users.
---------------------------------------------------------------------------------
-expr_list = gg.list{ _expr, separators = "," }
-
---------------------------------------------------------------------------------
--- Helpers for function applications / method applications
---------------------------------------------------------------------------------
-func_args_content = gg.list { 
-   name = "function arguments",
-   _expr, separators = ",", terminators = ")" } 
-
--- Used to parse methods
-method_args = gg.multisequence{
-   name = "function argument(s)",
-   { "{", table_content, "}" },
-   { "(", func_args_content, ")", builder = fget(1) },
-   { "+{", quote_content, "}" }, 
-   function(lx) local r = opt_string(lx); return r and {r} or { } end }
-
---------------------------------------------------------------------------------
--- [func_val] parses a function, from opening parameters parenthese to
--- "end" keyword included. Used for anonymous functions as well as
--- function declaration statements (both local and global).
---
--- It's wrapped in a [_func_val] eta expansion, so that when expr
--- parser uses the latter, they will notice updates of [func_val]
--- definitions.
---------------------------------------------------------------------------------
-func_params_content = gg.list{ name="function parameters",
-   gg.multisequence{ { "...", builder = "Dots" }, id },
-   separators  = ",", terminators = {")", "|"} } 
-
-local _func_params_content = function (lx) return func_params_content(lx) end
-
-func_val = gg.sequence { name="function body",
-   "(", func_params_content, ")", block, "end", builder = "Function" }
-
-local _func_val = function (lx) return func_val(lx) end
-
---------------------------------------------------------------------------------
--- Default parser for primary expressions
---------------------------------------------------------------------------------
-function id_or_literal (lx)
-   local a = lx:next()
-   if a.tag~="Id" and a.tag~="String" and a.tag~="Number" then
-      local msg
-      if a.tag=='Eof' then
-         msg = "End of file reached when an expression was expected"
-      elseif a.tag=='Keyword' then
-         msg = "An expression was expected, and `"..a[1]..
-            "' can't start an expression"
-      else
-         msg = "Unexpected expr token " .. _G.table.tostring (a, 'nohash')
-      end
-      return gg.parse_error (lx, msg)
-   end
-   return a
-end
-
-
---------------------------------------------------------------------------------
--- Builder generator for operators. Wouldn't be worth it if "|x|" notation
--- were allowed, but then lua 5.1 wouldn't compile it 
---------------------------------------------------------------------------------
-
--- opf1 = |op| |_,a| `Op{ op, a }
-local function opf1 (op) return 
-   function (_,a) return { tag="Op", op, a } end end
-
--- opf2 = |op| |a,_,b| `Op{ op, a, b }
-local function opf2 (op) return 
-   function (a,_,b) return { tag="Op", op, a, b } end end
-
--- opf2r = |op| |a,_,b| `Op{ op, b, a } -- (args reversed)
-local function opf2r (op) return 
-   function (a,_,b) return { tag="Op", op, b, a } end end
-
-local function op_ne(a, _, b) 
-   -- The first version guarantees to return the same code as Lua,
-   -- but it relies on the non-standard 'ne' operator, which has been
-   -- suppressed from the official AST grammar (although still supported
-   -- in practice by the compiler).
-   -- return { tag="Op", "ne", a, b }
-   return { tag="Op", "not", { tag="Op", "eq", a, b, lineinfo= {
-            first = a.lineinfo.first, last = b.lineinfo.last } } }
-end
-   
-
---------------------------------------------------------------------------------
---
--- complete expression
---
---------------------------------------------------------------------------------
-
--- FIXME: set line number. In [expr] transformers probably
-
-expr = gg.expr { name = "expression",
-
-   primary = gg.multisequence{ name="expr primary",
-      { "(", _expr, ")",           builder = "Paren" },
-      { "function", _func_val,     builder = fget(1) },
-      { "-{", splice_content, "}", builder = fget(1) },
-      { "+{", quote_content, "}",  builder = fget(1) }, 
-      { "nil",                     builder = "Nil" },
-      { "true",                    builder = "True" },
-      { "false",                   builder = "False" },
-      { "...",                     builder = "Dots" },
-      table,
-      id_or_literal },
-
-   infix = { name="expr infix op",
-      { "+",  prec = 60, builder = opf2 "add"  },
-      { "-",  prec = 60, builder = opf2 "sub"  },
-      { "*",  prec = 70, builder = opf2 "mul"  },
-      { "/",  prec = 70, builder = opf2 "div"  },
-      { "%",  prec = 70, builder = opf2 "mod"  },
-      { "^",  prec = 90, builder = opf2 "pow",    assoc = "right" },
-      { "..", prec = 40, builder = opf2 "concat", assoc = "right" },
-      { "==", prec = 30, builder = opf2 "eq"  },
-      { "~=", prec = 30, builder = op_ne  },
-      { "<",  prec = 30, builder = opf2 "lt"  },
-      { "<=", prec = 30, builder = opf2 "le"  },
-      { ">",  prec = 30, builder = opf2r "lt"  },
-      { ">=", prec = 30, builder = opf2r "le"  },
-      { "and",prec = 20, builder = opf2 "and" },
-      { "or", prec = 10, builder = opf2 "or"  } },
-
-   prefix = { name="expr prefix op",
-      { "not", prec = 80, builder = opf1 "not" },
-      { "#",   prec = 80, builder = opf1 "len" },
-      { "-",   prec = 80, builder = opf1 "unm" } },
-
-   suffix = { name="expr suffix op",
-      { "[", _expr, "]", builder = function (tab, idx) 
-         return {tag="Index", tab, idx[1]} end},
-      { ".", id, builder = function (tab, field) 
-         return {tag="Index", tab, id2string(field[1])} end },
-      { "(", func_args_content, ")", builder = function(f, args) 
-         return {tag="Call", f, unpack(args[1])} end },
-      { "{", _table_content, "}", builder = function (f, arg)
-         return {tag="Call", f, arg[1]} end},
-      { ":", id, method_args, builder = function (obj, post)
-         return {tag="Invoke", obj, id2string(post[1]), unpack(post[2])} end},
-      { "+{", quote_content, "}", builder = function (f, arg) 
-         return {tag="Call", f,  arg[1] } end },
-      default = { name="opt_string_arg", parse = mlp.opt_string, builder = function(f, arg) 
-         return {tag="Call", f, arg } end } } }
diff --git a/lib/errnode.lua b/lib/errnode.lua
deleted file mode 100644
index 1680c48..0000000
--- a/lib/errnode.lua
+++ /dev/null
@@ -1,38 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Sierra Wireless and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Kevin Kin-Foo - API and implementation
---
--------------------------------------------------------------------------------
-
-require 'metalua.compiler'
---
--- Ecapsulates funcion mlc.luastring_to_ast in order to protect call and parse
--- error string when an error occurs.
---
--- @param src string containg Lua code to evaluate
--- @return AST of table type, as returned by mlc.luastring_to_ast. Contains an
---	error when AST generation fails
---
-function getast(src)
-   local status, result = pcall(mlc.luastring_to_ast, src)
-   if status then return result else
-      local line, column, offset = result:match '%(l.(%d+), c.(%d+), k.(%d+)%)'
-      local filename = result :match '^([^:]+)'
-      local msg = result :match 'line %d+, char %d+: (.-)\n'
-      local li = {line, column, offset, filename}
-      return {tag='Error', lineinfo={first=li, last=li}, msg}
-   end
-end
diff --git a/lib/metalua/compiler.lua b/lib/metalua/compiler.lua
deleted file mode 100644
index 030b79b..0000000
--- a/lib/metalua/compiler.lua
+++ /dev/null
@@ -1,22 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-require 'metalua.runtime'
-require 'metalua.mlc'
-require 'metalua.package2'
diff --git a/lib/metalua/dollar.mlua b/lib/metalua/dollar.mlua
deleted file mode 100644
index c4f324e..0000000
--- a/lib/metalua/dollar.mlua
+++ /dev/null
@@ -1,43 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--- TODO: support modules as macros?
---       does it make sense to store a constant AST as a macro?
-
--{ extension 'match' }
-
-dollar = rawget(getfenv(), 'dollar') or { }
-
-local function dollar_builder(call)
-   match call with
-   | `Call{ `Id{name}, ... } -> return dollar[name](select(2, unpack(call)))
-   | `Id{name} -> 
-      local m = dollar[name]
-      match type(m) with
-      | 'function' -> return m()
-      | 'table'    -> return m
-      | 'nil'      -> error "No such macro registered"
-      | t          -> error ("Invalid macro type "..t)
-      end
-   | _ -> error "Invalid $macro, '$' should be followed by an identifier or function call"
-   end
-end   
-
-mlp.expr.prefix:add{ '$', prec = 100, builder = |_, x| dollar_builder(x) }
-mlp.stat:add{ '$', mlp.expr, builder = |x| dollar_builder(x[1]) }
diff --git a/lib/metalua/extension/H-runtime.mlua b/lib/metalua/extension/H-runtime.mlua
deleted file mode 100644
index 63ac784..0000000
--- a/lib/metalua/extension/H-runtime.mlua
+++ /dev/null
@@ -1,235 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-require 'metalua.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,
---   H+{print(1)} will be transformed into +{.1.X.print(1)},
---   and alpha will contain +{local -{`Id '.1.X.print} = print }.
---   alpha is reused and augmented by successive calls to H().
---
--- * H.side contains 'inside', 'outside', 'both' or nil (equivalent to
---   'both'). It indicates the kind of hygienization that's to be
---   performed.
---
--- * H.keep contain a set of free variable names which must not be
---   renamed.
---
--- * H.kind is the kind of walker that must be used ('expr', 'stat',
---   'block'...) and defaults to 'guess'.
---
--- * H:set (field, val) sets a field in H and returns H, so that calls
---   can be chained, e.g.:
---   > H:set(keep, {'print'}):set('side', outside)+{print(x)}
---
--- * H:reset(field) sets a field to nil, and returns the value of that
---   field prior to nilification.
---------------------------------------------------------------------------------
-
-H = { } --setmetatable(H, H)
-H.__index=H
-H.template = { alpha = { } }
-
---------------------------------------------------------------------------------
---
---------------------------------------------------------------------------------
-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: 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
-      if not k then k = { }; self.keep = k
-      -- If it's a string, consider it as a single-element dictionary
-      elseif type(k)=='string' then k = { [k] = true }; self.keep=k
-      -- If there's a list-part in self.keep, transpose it:
-      else for i, v in ipairs(k) do k[v], k[i] = true, nil end end
-   end
-
-   -----------------------------------------------------------------------------
-   -- 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
-
-      -- free_vars is an old_name -> new_name dictionary computed from alpha:
-      -- self.alpha is not an efficient representation for searching.
-      if not alpha then alpha = { }; self.alpha = alpha end
-      -- FIXME: alpha should only be overridden when there actually are some
-      -- globals renamed.
-      if #alpha==0 then alpha <- `Local{ { }, { } } end
-      local new, old = unpack(alpha)
-      local free_vars  = { }
-
-      assert (#new==#old, "Invalid alpha list")
-      for i = 1, #new do
-         assert (old[i].tag=='Id' and #old[i]==1, "Invalid lhs in alpha list")
-         assert (new[i].tag=='Id' and #new[i]==1, "Invalid rhs in alpha list")
-         free_vars[old[i][1]] = new[i][1]
-      end
-
-      -- Rename free variables that are not supposed to be captured.
-      function cfg.id.free (id)
-         local old_name = id[1]
-         if self.keep[old_name] then return end
-         local new_name = free_vars[old_name]
-         if not new_name then
-            new_name = mlp.gensym('X.'..old_name)[1]
-            free_vars[old_name] = new_name
-            table.insert(alpha[1], `Id{new_name})
-            table.insert(alpha[2], `Id{old_name})
-         end
-         id[1] = new_name
-      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
-      ----------------------------------------------------------------
-      function cfg.binder (id, binder)
-         if id.h_boundary then return end
-         local old_name = id[1]
-         local binder_table = bound_vars[binder]
-         if not binder_table then
-            binder_table = { }
-            bound_vars[binder] = binder_table
-         end
-         local new_name = mlp.gensym('L.'..old_name)[1]
-         binder_table[old_name] = new_name
-         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().
-      ----------------------------------------------------------------
-      function cfg.id.bound (id, binder)
-         if id.h_boundary then return end
-         local old_name = id[1]
-         local new_name = bound_vars[binder][old_name]
-         --.log(bound_vars[binder])
-         assert(new_name, "no alpha conversion for a bound var?!")
-         local_renames[id] = new_name
-      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
-      for id, new_name in pairs(local_renames) do id[1] = new_name end
-   end
-
-   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 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]
-   H[field] = nil
-   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
-
--- mlp.chunk.transformers:add (commit_locals_to_chunk)
diff --git a/lib/metalua/extension/H.mlua b/lib/metalua/extension/H.mlua
deleted file mode 100644
index 0a63f6e..0000000
--- a/lib/metalua/extension/H.mlua
+++ /dev/null
@@ -1,41 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-require 'metalua.walk.id'
--{ extension 'log' }
-
-mlp.expr.prefix:add{ '!', prec = 5,
-   builder = function(_,x)
-                local v = mlp.gensym()
-                return `Stat{ +{ block:
-                                 local -{v} = -{x};
-                                 (-{v}).h_boundary=true },
-                              v }
-             end }
-
-mlp.stat:add{ '!', mlp.expr, builder = |x| +{stat: (-{x[1]}).h_boundary=true } }
-
--- * if there's no boundary in it, is there a need to rename vars?
---   ==> first pass to mark binders which contain boundaries,
---       then 2nd pass only touched those which have a splice
---       in them.
-
-return +{ require (-{ `String{ package.metalua_extension_prefix .. 'H-runtime' } }) }
-
-
diff --git a/lib/metalua/extension/anaphoric.mlua b/lib/metalua/extension/anaphoric.mlua
deleted file mode 100644
index aacb0d4..0000000
--- a/lib/metalua/extension/anaphoric.mlua
+++ /dev/null
@@ -1,73 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
---------------------------------------------------------------------------------
---
--- Anaphoric macros.
---
--- This extension turns 'it' into a special variable, that's bound to
--- an often used value:
---
--- * in an 'if' statement, 'it' is bound, in a block, to the condition
---   that triggered the block's execution:
---   > if 1234 then y=it end; assert (y == 1234)
---
--- * in a while loop, it's bound to the test:
---   > while file:read "*a" do table.insert (lines, it) end
---
--- 'it' is bound the the most closely surrounding structure. If you wanted to
--- use its content at a deeper position in the AST, you would have to save it
--- in a temporary variable. But what you should really do in such a case is
--- avoiding to use anaphoric macros: they're fine for one-liner, but they
--- reduce readability for bigger functions.
---------------------------------------------------------------------------------
-
--- TODO: 'and' operator could, and maybe should, be anaphoric as well
--- TODO: anaphoric functions would be cool for recursive functions, but
---       recursive calls are always in an 'if' statement, so the pronoun
---       used for functions must not be the same as for 'if'.
-
-require 'freevars'
-
-local function anaphoric_if(ast)
-   local it_found = false
-   for i=2, #ast do 
-      if freevars.block(ast[i])['it'] then
-         it_found = true
-         break
-      end
-   end
-   if it_found then
-      local cond = ast[1]
-      ast[1] = +{it}
-      return +{stat: do local it = -{cond}; -{ast} end }
-   end
-end
-
-local function anaphoric_while(ast)
-   local it_found = false
-   if freevars.block(ast[2])['it'] then
-      local cond = ast[1]
-      ast[1] = +{it}
-      return +{stat: do local it = -{cond}; -{ast} end }
-   end
-end
-
-mlp.stat:get'if'.transformers:add(anaphoric_if)
-mlp.stat:get'while'.transformers:add(anaphoric_while)
\ No newline at end of file
diff --git a/lib/metalua/extension/continue.mlua b/lib/metalua/extension/continue.mlua
deleted file mode 100644
index fbd0f87..0000000
--- a/lib/metalua/extension/continue.mlua
+++ /dev/null
@@ -1,72 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-require "metalua.walk"
-
-----------------------------------------------------------------------
--- * [loop_tags] are the tags of statements which support continue.
--- * [loop_keywords] are the initial keywords which trigger the parsing
---   of these statements: they're indeed indexed by keyword in [mlp.stat].
-----------------------------------------------------------------------
-
-local loop_tags = table.transpose{ "Forin", "Fornum", "While", "Repeat" }
-local loop_keywords = { "for", "while", "repeat" }
-
-----------------------------------------------------------------------
--- This function takes the AST of a continue-enabled loop, parse
--- its body to find all instances of [`Continue]. If any of them
--- is found ([label~=nil]), they're transformed in [`Goto{...}], and
--- the corresponding label is added at the end of the loop's body.
---
--- Caveat: if a [continue] appears in the non-body part of a loop
--- (and therefore is relative to some enclosing loop), it isn't
--- handled, and therefore causes a compilation error. This could
--- only happen due in a [`Stat{ }], however, since [`Function{ }]
--- cuts the search for [`Continue].
-----------------------------------------------------------------------
-local function loop_transformer (ast)
-   local label
-   local cfg = { stat = { }; expr = { } }
-
-   function cfg.stat.down (x)
-      if loop_tags[x.tag] then return 'break'
-      elseif x.tag=='Continue' then
-         if not label then label = mlp.gensym 'continue' end
-         x <- `Goto{ label }
-      end
-   end
-
-   function cfg.expr.down (x)
-      return x.tag=='Function' and 'break'
-   end
-
-   local loop_body = ast.tag=="Repeat" and ast[1] or ast[#ast]
-   walk.block (cfg, loop_body)
-   if label then table.insert (loop_body, `Label{ label }) end
-end
-
-----------------------------------------------------------------------
--- Register the transformer for each kind of loop:
-----------------------------------------------------------------------
-for keyword in values (loop_keywords) do
-   mlp.stat:get(keyword).transformers:add (loop_transformer)
-end
-
-mlp.lexer:add "continue"
-mlp.stat:add{ "continue", builder = ||`Continue }
diff --git a/lib/metalua/extension/localin.mlua b/lib/metalua/extension/localin.mlua
deleted file mode 100644
index 8599a32..0000000
--- a/lib/metalua/extension/localin.mlua
+++ /dev/null
@@ -1,21 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-mlp.expr:add{ "local", mlp.id, "=", mlp.expr, "in", mlp.expr,
-   builder=|x| `Stat{ { `Local{ { x[1] }, { x[2] } } }, x[3] } }
\ No newline at end of file
diff --git a/lib/metalua/extension/ternary.mlua b/lib/metalua/extension/ternary.mlua
deleted file mode 100644
index 42cf767..0000000
--- a/lib/metalua/extension/ternary.mlua
+++ /dev/null
@@ -1,29 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-local function b(x, suffix)
-   local v, ontrue, onfalse = mlp.gensym "test", unpack (suffix)
-   return `Stat{ 
-      +{ block:
-         local -{v}
-         if -{x} then (-{v}) = -{ontrue} else (-{v}) = -{onfalse or `Nil} end },
-      v }
-end
-
-mlp.expr.suffix:add{ "?", mlp.expr, gg.onkeyword{ ",", mlp.expr }, prec=5, builder=b }
diff --git a/lib/metalua/extension/trycatch.mlua b/lib/metalua/extension/trycatch.mlua
deleted file mode 100644
index 3f190d5..0000000
--- a/lib/metalua/extension/trycatch.mlua
+++ /dev/null
@@ -1,208 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{ extension 'match' }
-
---------------------------------------------------------------------------------
---
--- TODO:
---
--- * Hygienize calls to pcall()
---
---------------------------------------------------------------------------------
-
--{ extension 'H' }
--{ extension 'log' }
-
--- Get match parsers and builder, for catch cases handling:
-local match_alpha = require 'metalua.extension.match'
-local H = H:new{side='inside', alpha = match_alpha }
-
--- We'll need to track rogue return statements:
-require 'metalua.walk'
-
--- Put a block AST into a pcall():
-local mkpcall = |block| +{pcall(function() -{block} end)}
-
--- The statement builder:
-function trycatch_builder(x)
-   --$log ("trycatch_builder", x, 'nohash', 60)
-   local try_code, catch_cases, finally_code = unpack(x)
-   local insert_return_catcher = false
-
-   -- Can't be hygienize automatically by the current version of H, as
-   -- it must bridge from inside user code (hacjed return statements)
-   -- to outside macro code.
-   local caught_return = !mlp.gensym 'caught_return'
-   local saved_args
-
-   !try_code; !(finally_code or { })
-   -- FIXME: Am I sure there's no need to hygienize inside?
-   --[[if catch_cases then
-      for case in ivalues(catch_cases) do
-         --$log(case,'nohash')
-         local patterns, guard, block = unpack(case)
-         ! block
-      end
-   end]]
-
-
-   ----------------------------------------------------------------
-   -- Returns in the try-block must be transformed:
-   -- from the user's PoV, the code in the try-block isn't
-   -- a function, therefore a return in it must not merely
-   -- end the execution of the try block, but:
-   --  * not cause any error to be caught;
-   --  * let the finally-block be executed;
-   --  * only then, let the enclosing function return with the
-   --    appropraite values.
-   -- The way to handle that is that any returned value is stored
-   -- into the runtime variable caught_return, then a return with
-   -- no value is sent, to stop the execution of the try-code.
-   --
-   -- Similarly, a return in a catch case code must not prevent
-   -- the finally-code from being run.
-   --
-   -- This walker catches return statements and perform the relevant
-   -- transformation into caught_return setting + empty return.
-   --
-   -- There is an insert_return_catcher compile-time flag, which
-   -- allows to avoid inserting return-handling code in the result
-   -- when not needed.
-   ----------------------------------------------------------------
-   local replace_returns_and_dots do
-      local function f(x)
-         match x with
-         | `Return{...} ->
-            insert_return_catcher = true
-            -- Setvar's 'caught_return' code can't be hygienize by H currently.
-            local setvar = `Set{ {caught_return}, { `Table{ unpack(x) } } }
-            x <- { setvar; `Return }; x.tag = nil;
-            --$log('transformed return stat:', x, 60)
-            return 'break'
-         | `Function{...} -> return 'break'
-            -- inside this, returns would be the nested function's, not ours.
-         | `Dots ->
-            if not saved_args then saved_args = mlp.gensym 'args' end
-            x <- `Call{ `Id 'unpack', saved_args }
-         | _ -> -- pass
-         end
-      end
-      local cfg = { stat = {down=f}, expr = {down=f} }
-      replace_returns_and_dots = |x| walk.block(cfg, x)
-   end
-
-   -- parse returns in the try-block:
-   replace_returns_and_dots (try_code)
-
-   -- code handling the error catching process:
-   local catch_result do
-      if catch_cases and #catch_cases>0 then
-         ----------------------------------------------------------
-         -- Protect catch code against failures: they run in a pcall(), and
-         -- the result is kept in catch_* vars so that it can be used to
-         -- relaunch the error after the finally code has been executed.
-         ----------------------------------------------------------
-         for x in ivalues (catch_cases) do
-            local case_code = x[3]
-            -- handle rogue returns:
-            replace_returns_and_dots (case_code)
-            -- in case of error in the catch, we still need to run "finally":
-            x[3] = +{block: catch_success, catch_error = -{mkpcall(case_code)}}
-         end
-         ----------------------------------------------------------
-         -- Uncaught exceptions must not cause a mismatch,
-         -- so we introduce a catch-all do-nothing last case:
-         ----------------------------------------------------------
-         table.insert (catch_cases, { { { `Id '_' } }, false, { } })
-         catch_result = spmatch.match_builder{ {+{user_error}}, catch_cases }
-      else
-         catch_result = { }
-      end
-   end
-
-   ----------------------------------------------------------------
-   -- Build the bits of code that will handle return statements
-   -- in the user code (try-block and catch-blocks).
-   ----------------------------------------------------------------
-   local caught_return_init, caught_return_rethrow do
-      if insert_return_catcher then
-         caught_return_init    = `Local{{caught_return}}
-         caught_return_rethrow =
-            +{stat: if -{caught_return} then return unpack(-{caught_return}) end}
-      else
-         caught_return_init, caught_return_rethrow = { }, { }
-      end
-   end
-
-   local saved_args_init =
-      saved_args and `Local{ {saved_args}, { `Table{`Dots} } } or { }
-
-   -- The finally code, to execute no matter what:
-   local finally_result = finally_code or { }
-
-   -- And the whole statement, gluing all taht together:
-   local result = +{stat:
-      do
-         -{ saved_args_init }
-         -{ caught_return_init }
-         local user_success,  user_error  = -{mkpcall(try_code)}
-         local catch_success, catch_error = false, user_error
-         if not user_success then -{catch_result} end
-         -{finally_result}
-         if not user_success and not catch_success then error(catch_error) end
-         -{ caught_return_rethrow }
-      end }
-
-   H(result)
-
-   return result
-end
-
-function catch_case_builder(x)
-   --$log ("catch_case_builder", x, 'nohash', 60)
-   local patterns, guard, _, code = unpack(x)
-   -- patterns ought to be a pattern_group, but each expression must
-   -- be converted into a single-element pattern_seq.
-   for i = 1, #patterns do patterns[i] = {patterns[i]} end
-   return { patterns, guard, code }
-end
-
-mlp.lexer:add{ 'try', 'catch', 'finally', '->' }
-mlp.block.terminators:add{ 'catch', 'finally' }
-
-mlp.stat:add{
-   'try',
-   mlp.block,
-   gg.onkeyword{ 'catch',
-      gg.list{
-         gg.sequence{
-            mlp.expr_list,
-            gg.onkeyword{ 'if', mlp.expr },
-            gg.optkeyword 'then',
-            mlp.block,
-            builder = catch_case_builder },
-         separators = 'catch' } },
-   gg.onkeyword{ 'finally', mlp.block },
-   'end',
-   builder = trycatch_builder }
-
-return H.alpha
-
-
diff --git a/lib/metalua/extension/types-runtime.mlua b/lib/metalua/extension/types-runtime.mlua
deleted file mode 100644
index 1f3e582..0000000
--- a/lib/metalua/extension/types-runtime.mlua
+++ /dev/null
@@ -1,178 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
---------------------------------------------------------------------------------
--- Initialize the types table. It has an __index metatable entry,
--- so that if a symbol is not found in it, it is looked for in the current
--- environment. It allows to write things like [ n=3; x :: vector(n) ].
---------------------------------------------------------------------------------
-types = { }
-setmetatable (types, { __index = getfenv(0)})
-
-function types.error (fmt, ...)
-   error(string.format("Runtime type-checking failure: "..fmt, ...))
-end
-
---------------------------------------------------------------------------------
--- Add a prefix to an error message, if an error occurs.
--- Useful for type checkers that call sub-type-checkers.
---------------------------------------------------------------------------------
-local function nest_error (prefix, ...)
-   local status, msg = pcall(...)
-   if not status then types.error("%s:\n%s", prefix, msg) end
-end
-
---------------------------------------------------------------------------------
--- Built-in types
---------------------------------------------------------------------------------
-for typename in values{ "number", "string", "boolean", "function", "thread" } do
-   types[typename] = 
-      function (val)           
-         if type(val) ~= typename then types.error ("%s expected", typename) end
-      end
-end
-
-function types.integer(val)
-   if type(val)~='number' or val%1~=0 then types.error 'integer expected' end
-end
-
---------------------------------------------------------------------------------
--- table(foo) checks
--- table(foo, bar) checks
--- table(i) where i is an integer checks
--- table(i, j) where i and j are integers checks
--- Integers and key/value types can be combined
---------------------------------------------------------------------------------
-function types.table (...)
-
-   local key_type, val_type, range_from, range_to
-   -- arguments parsing
-   for x in values{...} do
-      if type(x) == "number" then
-         if range2    then types.error "Invalid type: too many numbers in table type"
-         elseif range1 then range2 = x
-         else   range1 = x end
-      else
-         if     type_key  then types.error "Invalid type: too many types"
-         elseif type_val  then type_key, type_val = type_val, x
-         else   type_val = x end
-      end
-   end
-   if not range2 then range2=range1 end
-   if not type_key then type_key = types.integer end
-   return function (val)
-      if type(val) ~= "table" then types.error "table expected" end
-      local s = #val
-      if range2 and range2 > s then types.error "Not enough table elements" end
-      if range1 and range1 < s then types.error "Too many elements table elements" end
-      for k,v in pairs(val) do 
-         nest_error ("in table key",   type_key, k)
-         nest_error ("in table value", type_val, v)
-      end
-   end
-end
-
---------------------------------------------------------------------------------
--- [list (subtype)] checks that the term is a table, and all of its 
--- integer-indexed elements are of type [subtype].
---------------------------------------------------------------------------------
-types.list = |...| types.table (types.integer, ...)
-
---------------------------------------------------------------------------------
--- Check that [x] is an integral number
---------------------------------------------------------------------------------
-function types.int (x)
-   if type(x)~="number" or x%1~=0 then types.error "Integer number expected" end
-end
-
---------------------------------------------------------------------------------
--- [range(a,b)] checks that number [val] is between [a] and [b]. [a] and [b]
--- can be omitted.
---------------------------------------------------------------------------------
-function types.range (a,b)
-   return function (val)
-      if type(val)~="number" or a and val<a or b and val>b then 
-         types.error ("Number between %s and %s expected",
-                      a and tostring(a) or "-infty",
-                      b and tostring(b) or "+infty")
-      end
-   end
-end
-
---------------------------------------------------------------------------------
--- [inter (x, y)] checks that the term has both types [x] and [y].
---------------------------------------------------------------------------------
-function types.inter (...)
-   local args={...}
-   return function(val)
-      for t in values(args) do nest_error ("in inter type", t, args) end
-   end
-end      
-
---------------------------------------------------------------------------------
--- [inter (x, y)] checks that the term has type either [x] or [y].
---------------------------------------------------------------------------------
-function types.union (...)
-   local args={...}
-   return function(val)
-      for t in values(args) do if pcall(t, val) then return end end
-      types.error "None of the types in the union fits"
-   end
-end      
-
---------------------------------------------------------------------------------
--- [optional(t)] accepts values of types [t] or [nil].
---------------------------------------------------------------------------------
-function types.optional(t)
-   return function(val) 
-             if val~=nil then nest_error("In optional type", t, val) end 
-   end
-end  
-
---------------------------------------------------------------------------------
--- A call to this is done on litteral tables passed as types, i.e.
--- type {1,2,3} is transformed into types.__table{1,2,3}.
---------------------------------------------------------------------------------
-function types.__table(s_type)
-   return function (s_val)
-      if type(s_val) ~= "table" then types.error "Struct table expected" end
-      for k, field_type in pairs (s_type) do
-         nest_error ("in struct field "..k, field_type, s_val[k])
-      end
-   end
-end
-
---------------------------------------------------------------------------------
--- Same as __table, except that it's called on literal strings.
---------------------------------------------------------------------------------
-function types.__string(s_type)
-   return function (s_val)
-      if s_val ~= s_type then
-         types.error("String %q expected", s_type)
-      end
-   end
-end
-
---------------------------------------------------------------------------------
--- Top and Bottom:
---------------------------------------------------------------------------------
-function types.any() end
-function types.none() types.error "Empty type" end
-types.__or  = types.union
-types.__and = types.inter
\ No newline at end of file
diff --git a/lib/metalua/extension/types.mlua b/lib/metalua/extension/types.mlua
deleted file mode 100644
index a8e30c8..0000000
--- a/lib/metalua/extension/types.mlua
+++ /dev/null
@@ -1,371 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--- This extension inserts type-checking code at approriate place in the code,
--- thanks to annotations based on "::" keyword:
---
--- * function declarations can be annotated with a returned type. When they
---   are, type-checking code is inserted in each of their return statements,
---   to make sure they return the expected type.
---
--- * function parameters can also be annotated. If they are, type-checking
---   code is inserted in the function body, which checks the arguments' types
---   and cause an explicit error upon incorrect calls. Moreover, if a new value
---   is assigned to the parameter in the function's body, the new value's type
---   is checked before the assignment is performed.
---
--- * Local variables can also be annotated. If they are, type-checking
---   code is inserted before any value assignment or re-assignment is
---   performed on them.
---
--- Type checking can be disabled with:
---
--- -{stat: types.enabled = false }
---
--- Code transformation is performed at the chunk level, i.e. file by
--- file.  Therefore, it the value of compile-time variable
--- [types.enabled] changes in the file, the only value that counts is
--- its value once the file is entirely parsed.
---
--- Syntax
--- ======
---
--- Syntax annotations consist of "::" followed by a type
--- specifier. They can appear after a function parameter name, after
--- the closing parameter parenthese of a function, or after a local
--- variable name in the declaration. See example in samples.
---
--- Type specifiers are expressions, in which identifiers are taken
--- from table types. For instance, [number] is transformed into
--- [types.number]. These [types.xxx] fields must contain functions,
--- which generate an error when they receive an argument which doesn't
--- belong to the type they represent. It is perfectly acceptible for a
--- type-checking function to return another type-checking function,
--- thus defining parametric/generic types. Parameters can be
--- identifiers (they're then considered as indexes in table [types])
--- or literals.
---
--- Design hints
--- ============
---
--- This extension uses the code walking library [walk] to globally
--- transform the chunk AST. See [chunk_transformer()] for details
--- about the walker.
---
--- During parsing, type informations are stored in string-indexed
--- fields, in the AST nodes of tags `Local and `Function. They are
--- used by the walker to generate code only if [types.enabled] is
--- true.
---
--- TODO
--- ====
---
--- It's easy to add global vars type-checking, by declaring :: as an
--- assignment operator.  It's easy to add arbitrary expr
--- type-checking, by declaring :: as an infix operator. How to make
--- both cohabit?
-
---------------------------------------------------------------------------------
---
--- Function chunk_transformer()
---
---------------------------------------------------------------------------------
---
--- Takes a block annotated with extra fields, describing typing
--- constraints, and returns a normal AST where these constraints have
--- been turned into type-checking instructions.
---
--- It relies on the following annotations:
---
---  * [`Local{ }] statements may have a [types] field, which contains a
---    id name ==> type name map.
---
---  * [Function{ }] expressions may have an [param_types] field, also a
---    id name ==> type name map. They may also have a [ret_type] field
---    containing the type of the returned value.
---
--- Design hints:
--- =============
---
--- It relies on the code walking library, and two states:
---
---  * [return_types] is a stack of the expected return values types for
---    the functions currently in scope, the most deeply nested one
---    having the biggest index.
---
---  * [scopes] is a stack of id name ==> type name scopes, one per
---    currently active variables scope.
---
--- What's performed by the walker:
---
---  * Assignments to a typed variable involve a type checking of the
---    new value;
---
---  * Local declarations are checked for additional type declarations.
---
---  * Blocks create and destroy variable scopes in [scopes]
---
---  * Functions create an additional scope (around its body block's scope)
---    which retains its argument type associations, and stacks another
---    return type (or [false] if no type constraint is given)
---
---  * Return statements get the additional type checking statement if
---    applicable.
---
---------------------------------------------------------------------------------
-
--- TODO: unify scopes handling with free variables detector
--- FIXME: scopes are currently incorrect anyway, only functions currently define a scope.
-
-require "metalua.walk"
-
--{ extension 'match' }
-
-module("types", package.seeall)
-
-enabled = true
-
-local function chunk_transformer (block)
-   if not enabled then return end
-   local return_types, scopes = { }, { }
-   local cfg = { block = { }; stat = { }; expr = { } }
-
-   function cfg.stat.down (x)
-      match x with
-      | `Local{ lhs, rhs, types = x_types } ->
-         -- Add new types declared by lhs in current scope.
-         local myscope = scopes [#scopes]
-         for var, type in pairs (x_types) do
-            myscope [var] = process_type (type)
-         end
-         -- Type-check each rhs value with the type of the
-         -- corresponding lhs declaration, if any.  Check backward, in
-         -- case a local var name is used more than once.
-         for i = 1, max (#lhs, #rhs) do
-            local type, new_val = myscope[lhs[i][1]], rhs[i]
-            if type and new_val then
-               rhs[i] = checktype_builder (type, new_val, 'expr')
-            end
-         end
-      | `Set{ lhs, rhs } ->
-         for i=1, #lhs do
-            match lhs[i] with
-            | `Id{ v } ->
-               -- Retrieve the type associated with the variable, if any:
-               local  j, type = #scopes, nil
-               repeat j, type = j-1, scopes[j][v] until type or j==0
-               -- If a type constraint is found, apply it:
-               if type then rhs[i] = checktype_builder(type, rhs[i] or `Nil, 'expr') end
-            | _ -> -- assignment to a non-variable, pass
-            end
-         end
-      | `Return{ r_val } ->
-         local r_type = return_types[#return_types]
-         if r_type then
-            x <- `Return{ checktype_builder (r_type, r_val, 'expr') }
-         end
-      | _ -> -- pass
-      end
-   end
-
-   function cfg.expr.down (x)
-      if x.tag ~= 'Function' then return end
-      local new_scope = { }
-      table.insert (scopes, new_scope)
-      for var, type in pairs (x.param_types or { }) do
-         new_scope[var] = process_type (type)
-      end
-      local r_type = x.ret_type and process_type (x.ret_type) or false
-      table.insert (return_types, r_type)
-   end
-
-   -------------------------------------------------------------------
-   -- Unregister the returned type and the variable scope in which
-   -- arguments are registered;
-   -- then, adds the parameters type checking instructions at the
-   -- beginning of the function, if applicable.
-   -------------------------------------------------------------------
-   function cfg.expr.up (x)
-      if x.tag ~= 'Function' then return end
-      -- Unregister stuff going out of scope:
-      table.remove (return_types)
-      table.remove (scopes)
-      -- Add initial type checking:
-      for v, t in pairs(x.param_types or { }) do
-         table.insert(x[2], 1, checktype_builder(t, `Id{v}, 'stat'))
-      end
-   end
-
-   cfg.block.down = || table.insert (scopes, { })
-   cfg.block.up   = || table.remove (scopes)
-
-   walk.block(cfg, block)
-end
-
---------------------------------------------------------------------------
--- Perform required transformations to change a raw type expression into
--- a callable function:
---
---  * identifiers are changed into indexes in [types], unless they're
---    allready indexed, or into parentheses;
---
---  * literal tables are embedded into a call to types.__table
---
--- This transformation is not performed when type checking is disabled:
--- types are stored under their raw form in the AST; the transformation is
--- only performed when they're put in the stacks (scopes and return_types)
--- of the main walker.
---------------------------------------------------------------------------
-function process_type (type_term)
-   -- Transform the type:
-   cfg = { expr = { } }
-
-   function cfg.expr.down(x)
-      match x with
-      | `Index{...} | `Paren{...} -> return 'break'
-      | _ -> -- pass
-      end
-   end
-   function cfg.expr.up (x)
-      match x with
-      | `Id{i} -> x <- `Index{ `Id "types", `String{ i } }
-      | `Table{...} | `String{...} | `Op{...} ->
-         local xcopy, name = table.shallow_copy(x)
-         match x.tag with
-         | 'Table'  -> name = '__table'
-         | 'String' -> name = '__string'
-         | 'Op'     -> name = '__'..x[1]
-         end
-         x <- `Call{ `Index{ `Id "types", `String{ name } }, xcopy }
-      | `Function{ params, { results } } if results.tag=='Return' ->
-         results.tag = nil
-         x <- `Call{ +{types.__function}, params, results }
-      | `Function{...} -> error "malformed function type"
-      | _ -> -- pass
-      end
-   end
-   walk.expr(cfg, type_term)
-   return type_term
-end
-
---------------------------------------------------------------------------
--- Insert a type-checking function call on [term] before returning
--- [term]'s value. Only legal in an expression context.
---------------------------------------------------------------------------
-local non_const_tags = table.transpose
-   { 'Dots', 'Op', 'Index', 'Call', 'Invoke', 'Table' }
-function checktype_builder(type, term, kind)
-   -- Shove type-checking code into the term to check:
-   match kind with
-   | 'expr' if non_const_tags [term.tag] ->
-      local  v = mlp.gensym()
-      return `Stat{ { `Local{ {v}, {term} }; `Call{ type, v } }, v }
-   | 'expr' ->
-      return `Stat{ { `Call{ type, term } }, term }
-   | 'stat' ->
-      return `Call{ type, term }
-   end
-end
-
---------------------------------------------------------------------------
--- Parse the typechecking tests in a function definition, and adds the
--- corresponding tests at the beginning of the function's body.
---------------------------------------------------------------------------
-local function func_val_builder (x)
-   local typed_params, ret_type, body = unpack(x)
-   local e = `Function{ { }, body; param_types = { }; ret_type = ret_type }
-
-   -- Build [untyped_params] list, and [e.param_types] dictionary.
-   for i, y in ipairs (typed_params) do
-      if y.tag=="Dots" then
-         assert(i==#typed_params, "`...' must be the last parameter")
-         break
-      end
-      local param, type = unpack(y)
-      e[1][i] = param
-      if type then e.param_types[param[1]] = type end
-   end
-   return e
-end
-
---------------------------------------------------------------------------
--- Parse ":: type" annotation if next token is "::", or return false.
--- Called by function parameters parser
---------------------------------------------------------------------------
-local opt_type = gg.onkeyword{ "::", mlp.expr }
-
---------------------------------------------------------------------------
--- Updated function definition parser, which accepts typed vars as
--- parameters.
---------------------------------------------------------------------------
-
--- Parameters parsing:
-local id_or_dots = gg.multisequence{ { "...", builder = "Dots" }, default = mlp.id }
-
--- Function parsing:
-mlp.func_val = gg.sequence{
-   "(", gg.list{
-      gg.sequence{ id_or_dots, opt_type }, terminators = ")", separators  = "," },
-   ")",  opt_type, mlp.block, "end",
-   builder = func_val_builder }
-
-mlp.lexer:add { "::", "newtype" }
-mlp.chunk.transformers:add (chunk_transformer)
-
--- Local declarations parsing:
-local local_decl_parser = mlp.stat:get "local" [2].default
-
-local_decl_parser[1].primary = gg.sequence{ mlp.id, opt_type }
-
-function local_decl_parser.builder(x)
-   local lhs, rhs = unpack(x)
-   local s, stypes = `Local{ { }, rhs or { } }, { }
-   for i = 1, #lhs do
-      local id, type = unpack(lhs[i])
-      s[1][i] = id
-      if type then stypes[id[1]]=type end
-   end
-   if next(stypes) then s.types = stypes end
-   return s
-end
-
-function newtype_builder(x)
-   local lhs, rhs = unpack(x)
-   match lhs with
-   | `Id{ x } -> t = process_type (rhs)
-   | `Call{ `Id{ x }, ... } ->
-      t = `Function{ { }, rhs }
-      for i = 2, #lhs do
-         if lhs[i].tag ~= "Id" then error "Invalid newtype parameter" end
-         t[1][i-1] = lhs[i]
-      end
-   | _ -> error "Invalid newtype definition"
-   end
-   return `Let{ { `Index{ `Id "types", `String{ x } } }, { t } }
-end
-
-mlp.stat:add{ "newtype", mlp.expr, "=", mlp.expr, builder = newtype_builder }
-
-
---------------------------------------------------------------------------
--- Register as an operator
---------------------------------------------------------------------------
---mlp.expr.infix:add{ "::", prec=100, builder = |a, _, b| insert_test(a,b) }
-
-return +{ require (-{ `String{ package.metalua_extension_prefix .. 'types-runtime' } }) }
diff --git a/lib/metalua/extension/withdo.mlua b/lib/metalua/extension/withdo.mlua
deleted file mode 100644
index b361482..0000000
--- a/lib/metalua/extension/withdo.mlua
+++ /dev/null
@@ -1,49 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--- RAII in metalua.
---
--- Write:
--- with var_1, var_2... = val_1, val_2... do
---    ...
--- end
---
--- will assign val_n to var_n foreach n, and guaranty that var_n:close() will be called,
--- no matter what, even if the body causes an error, even if it returns, even
--- if another :close() call causes an error, etc. No. Matter. What.
-
-require 'metalua.extension.trycatch'
-
-function withdo_builder (x)
-   local names, vals, body = unpack(x)
-   for i = #names, 1, -1 do
-      local name, val = names[i], vals[i]
-      body = trycatch_builder{ { `Set{ {name}, {val} }, body }, -- try-block
-                               { }, -- catch-block
-                               { +{ print ("closing "..-{`String{name[1]}}) },
-                                 `Invoke{ name, `String "close" } } }
-   end
-   table.insert(body, 1, `Local{ names })
-   return body
-end
-
-mlp.lexer:add 'with'
-mlp.stat:add{
-   'with', mlp.id_list, '=', mlp.expr_list, 'do', mlp.block, 'end',
-   builder = withdo_builder }
diff --git a/lib/metalua/extension/xglobal-runtime.lua b/lib/metalua/extension/xglobal-runtime.lua
deleted file mode 100644
index b863fed..0000000
--- a/lib/metalua/extension/xglobal-runtime.lua
+++ /dev/null
@@ -1,60 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-local _G = getfenv()
-local _G_mt = getmetatable(_G)
-
-
--- Set the __globals metafield in the global environment's metatable,
--- if not already there.
-if _G_mt then
-   if _G_mt.__globals then return else
-      print( "Warning: _G already has a metatable,"..
-            " which might interfere with xglobals")
-      _G_mt.__globals = { } 
-   end
-else 
-   _G_mt = { __globals = { } }
-   setmetatable(_G, _G_mt)
-end
-
--- add a series of variable names to the list of declared globals
-function _G_mt.__newglobal(...)
-   local g = _G_mt.__globals
-   for v in ivalues{...} do g[v]=true end
-end
-
--- Try to set a global that's not in _G:
--- if it isn't declared, fail
-function _G_mt.__newindex(_G, var, val)
-   if not _G_mt.__globals[var] then
-      error ("Setting undeclared global variable "..var)
-   end
-   rawset(_G, var, val)
-end
-
--- Try to read a global that's not in _G:
--- if it isn't declared, fail
-function _G_mt.__index(_G, var)
-   if not _G_mt.__globals[var] then 
-      error ("Reading undeclared global variable "..var) 
-   end
-   return nil
-end
-
diff --git a/lib/metalua/extension/xglobal.mlua b/lib/metalua/extension/xglobal.mlua
deleted file mode 100644
index 3859e98..0000000
--- a/lib/metalua/extension/xglobal.mlua
+++ /dev/null
@@ -1,39 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--- WARNING, this is undertested, especially in cases where mutliple
--- modules have their own fenvs. Use at your own risks.
-
-require 'strict'
-
-local function decl_builder(x)
-   local ids, vals = unpack(x)
-   local ids_as_strings = table.imap(|x| `String{x[1]}, ids)
-   local decl = `Call{ +{getmetatable(getfenv()).__newglobal},
-                       unpack(ids_as_strings) }
-   if vals then return { decl, `Set{ ids, vals } }
-   else return decl end
-end
-
-mlp.lexer:add 'global'
-mlp.stat:add{ 
-   'global', mlp.id_list, gg.onkeyword{ '=', mlp.expr_list },
-   builder = decl_builder }
-
-return +{ require (-{ `String{ package.metalua_extension_prefix .. 'xglobal-runtime' } }) }
diff --git a/lib/metalua/mlc_xcall.lua b/lib/metalua/mlc_xcall.lua
deleted file mode 100644
index 7875874..0000000
--- a/lib/metalua/mlc_xcall.lua
+++ /dev/null
@@ -1,142 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
---------------------------------------------------------------------------------
--- Execute an `mlc.*_to_ast()' in a separate lua process.
--- Communication between processes goes through temporary files,
--- for the sake of portability.
---------------------------------------------------------------------------------
-
-mlc_xcall = { }
-
---------------------------------------------------------------------------------
--- Number of lines to remove at the end of a traceback, should it be
--- dumped due to a compilation error in metabugs mode.
---------------------------------------------------------------------------------
-local STACK_LINES_TO_CUT = 7
-
---------------------------------------------------------------------------------
--- (Not intended to be called directly by users)
---
--- This is the back-end function, called in a separate lua process
--- by `mlc_xcall.client_*()' through `os.execute()'.
---  * inputs:
---     * the name of a lua source file to compile in a separate process
---     * the name of a writable file where the resulting ast is dumped
---       with `serialize()'.
---     * metabugs: if true and an error occurs during compilation,
---       the compiler's stacktrace is printed, allowing meta-programs
---       debugging.
---  * results:
---     * an exit status of 0 or -1, depending on whethet compilation
---       succeeded;
---     * the ast file filled will either the serialized ast, or the
---       error message.
---------------------------------------------------------------------------------
-function mlc_xcall.server (luafilename, astfilename, metabugs)
-
-   -- We don't want these to be loaded when people only do client-side business
-   require 'metalua.compiler'
-   require 'serialize'
-
-   mlc.metabugs = metabugs
-
-   -- compile the content of luafile name in an AST, serialized in astfilename
-   --local status, ast = pcall (mlc.luafile_to_ast, luafilename)
-   local status, ast
-   local function compile() return mlc.luafile_to_ast (luafilename) end
-   if mlc.metabugs then 
-      --print 'mlc_xcall.server/metabugs'
-      --status, ast = xpcall (compile, debug.traceback)
-      --status, ast = xpcall (compile, debug.traceback)
-      local function tb(msg)
-         local r = debug.traceback(msg)
-
-         -- Cut superfluous end lines
-         local line_re = '\n[^\n]*'
-         local re =  "^(.-)" .. (line_re) :rep (STACK_LINES_TO_CUT) .. "$"
-         return r :strmatch (re) or r
-      end
-      --status, ast = xpcall (compile, debug.traceback)
-      status, ast = xpcall (compile, tb)
-   else status, ast = pcall (compile) end
-   if status then 
-      local check_status, check_msg = pcall (mlc.check_ast, 'block', ast)
-      if not check_status then status, ast = false, check_msg end
-   end
-   local out = io.open (astfilename, 'w')
-   if status then -- success
-      out:write (serialize (ast))
-      out:close ()
-      os.exit (0)
-   else -- failure, `ast' is actually the error message
-      out:write (ast)
-      out:close ()
-      os.exit (-1)
-   end      
-end
-
---------------------------------------------------------------------------------
--- Compile the file whose name is passed as argument, in a separate process,
--- communicating through a temporary file.
--- returns:
---  * true or false, indicating whether the compilation succeeded
---  * the ast, or the error message.
---------------------------------------------------------------------------------
-function mlc_xcall.client_file (luafile)
-
-   -- printf("\n\nmlc_xcall.client_file(%q)\n\n", luafile)
-
-   local tmpfilename = os.tmpname()
-   local cmd = string.format (
-      [=[lua -l metalua.mlc_xcall -e "mlc_xcall.server([[%s]], [[%s]], %s)"]=], 
-      luafile, tmpfilename, mlc.metabugs and "true" or "false")
-
-   -- printf("os.execute [[%s]]\n\n", cmd)
-
-   local status = (0 == os.execute (cmd))
-   local result -- ast or error msg
-   if status then 
-      result = (lua_loadfile or loadfile) (tmpfilename) ()
-   else
-      local f = io.open (tmpfilename)
-      result = f :read '*a'
-      f :close()
-   end
-   os.remove(tmpfilename)
-   return status, result
-end
-
---------------------------------------------------------------------------------
--- Compile a source string into an ast, by dumping it in a tmp
--- file then calling `mlc_xcall.client_file()'.
--- returns: the same as `mlc_xcall.client_file()'.
---------------------------------------------------------------------------------
-function mlc_xcall.client_literal (luasrc)
-   local srcfilename = os.tmpname()
-   local srcfile, msg = io.open (srcfilename, 'w')
-   if not srcfile then print(msg) end
-   srcfile :write (luasrc)
-   srcfile :close ()
-   local status, ast = mlc_xcall.client_file (srcfilename)
-   os.remove(srcfilename)
-   return status, ast
-end
-
-return mlc_xcall
\ No newline at end of file
diff --git a/lib/metalua/runtime.lua b/lib/metalua/runtime.lua
deleted file mode 100644
index cacf3d1..0000000
--- a/lib/metalua/runtime.lua
+++ /dev/null
@@ -1,22 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-require 'metalua.base'
-require 'metalua.table2'
-require 'metalua.string2'
diff --git a/lib/metalua/walk/bindings.mlua b/lib/metalua/walk/bindings.mlua
deleted file mode 100644
index b072f9f..0000000
--- a/lib/metalua/walk/bindings.mlua
+++ /dev/null
@@ -1,65 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-require 'metalua.walk'
-require 'metalua.walk.scope'
-
-function bindings(ast)
-   -- binders :: ast  => name => occurences
-   -- unbound :: name => occurences
-   -- scope   :: name => ast
-
-   local binders, unbound, cfg, scope = { }, { }, { scope={ } }, scope:new()
-
-   -- * id: identifier entering in scope
-   -- * ast: statement or expr carrying this id, on of:
-   --        Local, Localrec, Forin, Fornum, Function.
-   function cfg.binder (id, ast)
-      if id.tag ~= 'Id' then return end
-      local id_name = id[1]
-      -- Reference in scope, so that the binding statement can be retrieved:
-      scope.current[id_name] = ast
-      -- Init the occurences list for this identifier:
-      if binders[ast] then binders[ast][id_name] = { }
-      else binders[ast] = { [id_name] = { } } end
-   end
-   
-   -- identifier occurence, not as a binder: reference this occurence
-   function cfg.Id (id)
-      local id_name = id[1]
-      -- ast which binds this id, might be nil:
-      local binder_ast = scope.current [id_name] 
-      -- dict id_name => occurences, might be the list of unbound occurences:
-      local occur_dict = binder_ast and binders[binder_ast] or unbound
-      -- add an occurence of `id' in the occurences list:
-      local occurences = occur_dict [id_name]
-      if occurences then table.insert (occurences, id) 
-      else occur_dict [id_name] = { id } end
-   end
-
-   --Do not choke on partial ASTs which contain `Error{} nodes
-   function cfg.error(x) end
-
-   function cfg.scope.down() scope:push() end
-   function cfg.scope.up()   scope:pop()  end
-
-   walk.guess (cfg, ast)
-   return binders, unbound
-end
-
diff --git a/lib/serialize.lua b/lib/serialize.lua
deleted file mode 100644
index 4e5c8a7..0000000
--- a/lib/serialize.lua
+++ /dev/null
@@ -1,202 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
---------------------------------------------------------------------------------
---
--- Serialize an object into a source code string. This string, when passed as
--- an argument to loadstring()(), returns an object structurally identical
--- to the original one. 
---
--- The following are supported:
---
--- * strings, numbers, booleans, nil
---
--- * functions without upvalues
---
--- * tables thereof. There is no restriction on keys; recursive and shared
---   sub-tables are handled correctly.
---
--- Caveat: metatables and environments aren't saved; this might or might not
---         be what you want.
---------------------------------------------------------------------------------
-
-local no_identity = { number=1, boolean=1, string=1, ['nil']=1 }
-
-function serialize (x)
-   
-   local gensym_max =  0  -- index of the gensym() symbol generator
-   local seen_once  = { } -- element->true set of elements seen exactly once in the table
-   local multiple   = { } -- element->varname set of elements seen more than once
-   local nested     = { } -- transient, set of elements currently being traversed
-   local nest_points  = { }
-   local nest_patches = { }
-   
-   -- Generate fresh indexes to store new sub-tables:
-   local function gensym()
-      gensym_max = gensym_max + 1 ;  return gensym_max
-   end
-   
-   -----------------------------------------------------------------------------
-   -- `nest_points' are places where a (recursive) table appears within
-   -- itself, directly or not.  for instance, all of these chunks
-   -- create nest points in table `x':
-   --
-   -- "x = { }; x[x] = 1"
-   -- "x = { }; x[1] = x"
-   -- "x = { }; x[1] = { y = { x } }".
-   --
-   -- To handle those, two tables are created by `mark_nest_point()':
-   --
-   -- * `nest_points [parent]' associates all keys and values in table
-   --   parent which create a nest_point with boolean `true'
-   --
-   -- * `nest_patches' contains a list of `{ parent, key, value }'
-   --   tuples creating a nest point. They're all dumped after all the
-   --   other table operations have been performed.
-   --
-   -- `mark_nest_point (p, k, v)' fills tables `nest_points' and
-   -- `nest_patches' with informations required to remember that
-   -- key/value `(k,v)' creates a nest point in parent table `p'. It
-   -- also marks `p' as occuring multiple times, since several
-   -- references to it will be required in order to patch the nest
-   -- points.
-   -----------------------------------------------------------------------------
-   local function mark_nest_point (parent, k, v)
-      local nk, nv = nested[k], nested[v]
-      assert (not nk or seen_once[k] or multiple[k])
-      assert (not nv or seen_once[v] or multiple[v])
-      local mode = (nk and nv and "kv") or (nk and "k") or ("v")
-      local parent_np = nest_points [parent]
-      local pair = { k, v }
-      if not parent_np then parent_np = { }; nest_points [parent] = parent_np end
-      parent_np [k], parent_np [v] = nk, nv
-      table.insert (nest_patches, { parent, k, v })
-      seen_once [parent], multiple [parent]  = nil, true
-   end
-   
-   -----------------------------------------------------------------------------
-   -- 1st pass, list the tables and functions which appear more than once in `x'
-   -----------------------------------------------------------------------------
-   local function mark_multiple_occurences (x)
-      if no_identity [type(x)] then return end
-      if     seen_once [x]     then seen_once [x], multiple [x] = nil, true
-      elseif multiple  [x]     then -- pass
-      else   seen_once [x] = true end
-      
-      if type (x) == 'table' then
-         nested [x] = true
-         for k, v in pairs (x) do
-            if nested[k] or nested[v] then mark_nest_point (x, k, v) else
-               mark_multiple_occurences (k)
-               mark_multiple_occurences (v)
-            end
-         end
-         nested [x] = nil
-      end
-   end
-
-   local dumped    = { } -- multiply occuring values already dumped in localdefs
-   local localdefs = { } -- already dumped local definitions as source code lines
-
-
-   -- mutually recursive functions:
-   local dump_val, dump_or_ref_val
-
-   ------------------------------------------------------------------------------
-   -- if `x' occurs multiple times, dump the local var rather than the
-   -- value. If it's the first time it's dumped, also dump the content
-   -- in localdefs.
-   ------------------------------------------------------------------------------            
-   function dump_or_ref_val (x)
-      if nested[x] then return 'false' end -- placeholder for recursive reference
-      if not multiple[x] then return dump_val (x) end
-      local var = dumped [x]
-      if var then return "_[" .. var .. "]" end -- already referenced
-      local val = dump_val(x) -- first occurence, create and register reference
-      var = gensym()
-      table.insert(localdefs, "_["..var.."]="..val)
-      dumped [x] = var
-      return "_[" .. var .. "]"
-   end
-
-   -----------------------------------------------------------------------------
-   -- 2nd pass, dump the object; subparts occuring multiple times are dumped
-   -- in local variables, which can then be referenced multiple times;
-   -- care is taken to dump local vars in an order which repect dependencies.
-   -----------------------------------------------------------------------------
-   function dump_val(x)
-      local  t = type(x)
-      if     x==nil        then return 'nil'
-      elseif t=="number"   then return tostring(x)
-      elseif t=="string"   then return string.format("%q", x)
-      elseif t=="boolean"  then return x and "true" or "false"
-      elseif t=="function" then
-         return string.format ("loadstring(%q,'@serialized')", string.dump (x))
-      elseif t=="table" then
-
-         local acc        = { }
-         local idx_dumped = { }
-         local np         = nest_points [x]
-         for i, v in ipairs(x) do
-            if np and np[v] then
-               table.insert (acc, 'false') -- placeholder
-            else
-               table.insert (acc, dump_or_ref_val(v))
-            end
-            idx_dumped[i] = true
-         end
-         for k, v in pairs(x) do
-            if np and (np[k] or np[v]) then
-               --check_multiple(k); check_multiple(v) -- force dumps in localdefs
-            elseif not idx_dumped[k] then
-               table.insert (acc, "[" .. dump_or_ref_val(k) .. "] = " .. dump_or_ref_val(v))
-            end
-         end
-         return "{ "..table.concat(acc,", ").." }"
-      else
-         error ("Can't serialize data of type "..t)
-      end
-   end
-          
-   -- Patch the recursive table entries:
-   local function dump_nest_patches()
-      for _, entry in ipairs(nest_patches) do
-         local p, k, v = unpack (entry)
-         assert (multiple[p])
-         local set = dump_or_ref_val (p) .. "[" .. dump_or_ref_val (k) .. "] = " .. 
-            dump_or_ref_val (v) .. " -- rec "
-         table.insert (localdefs, set)
-      end
-   end
-   
-   mark_multiple_occurences (x)
-   local toplevel = dump_or_ref_val (x)
-   dump_nest_patches()
-
-   if next (localdefs) then
-      -- Dump local vars containing shared or recursive parts,
-      -- then the main table using them.
-      return "local _={ }\n" ..
-         table.concat (localdefs, "\n") .. 
-         "\nreturn " .. toplevel
-   else
-      -- No shared part, straightforward dump:
-      return "return " .. toplevel
-   end
-end
diff --git a/make.bat b/make.bat
deleted file mode 100644
index d4e9ca6..0000000
--- a/make.bat
+++ /dev/null
@@ -1,58 +0,0 @@
-@CLS
-
-@REM *** Settings ***
-
-@REM BASE        = root directory of metalua sources
-@REM DISTRIB_BIN = metalua executables target directory
-@REM DISTRIB_LIB = metalua libraries target directory, can be an existing path referenced in LUA_PATH
-@REM LUA, LUAC   = Lua executables, provided by metalua by default.
-
-@REM --- BEGINNING OF USER-EDITABLE PART ---
-
-@set BASE=%CD%
-@set DISTRIB=%BASE%\..\distrib
-@set DISTRIB_BIN=%DISTRIB%\bin
-@set DISTRIB_LIB=%DISTRIB%\lib
-@set LUA=%DISTRIB_BIN%\lua
-@set LUAC=%DISTRIB_BIN%\luac
-
-@REM --- END OF USER-EDITABLE PART ---
-
-
-@REM *** Create the distribution directories, populate them with lib sources ***
-
-@set LUA_PATH=?.luac;?.lua;%DISTRIB_LIB%\?.luac;%DISTRIB_LIB%\?.lua
-@set LUA_MPATH=?.mlua;%DISTRIB_LIB%\?.mlua
-
-mkdir %DISTRIB%
-mkdir %DISTRIB_BIN%
-mkdir %DISTRIB_LIB%
-xcopy /y /s lib %DISTRIB_LIB%
-xcopy /y /s bin %DISTRIB_BIN%
-
-@REM *** Generate a callable batch metalua.bat script ***
-
-echo @set LUA_PATH=?.luac;?.lua;%DISTRIB_LIB%\?.luac;%DISTRIB_LIB%\?.lua > %DISTRIB_BIN%\metalua.bat
-echo @set LUA_MPATH=?.mlua;%DISTRIB_LIB%\?.mlua >> %DISTRIB_BIN%\metalua.bat
-echo @%LUA% %DISTRIB_LIB%\metalua.luac %%* >> %DISTRIB_BIN%\metalua.bat
-
-
-@REM *** Compiling the parts of the compiler written in plain Lua ***
-
-cd compiler
-%LUAC% -o %DISTRIB_LIB%\metalua\bytecode.luac lopcodes.lua lcode.lua ldump.lua compile.lua
-%LUAC% -o %DISTRIB_LIB%\metalua\mlp.luac lexer.lua gg.lua mlp_lexer.lua mlp_misc.lua mlp_table.lua mlp_meta.lua mlp_expr.lua mlp_stat.lua mlp_ext.lua
-cd ..
-
-@REM *** Bootstrap the parts of the compiler written in metalua ***
-
-%LUA% %BASE%\build-utils\bootstrap.lua %BASE%\compiler\mlc.mlua output=%DISTRIB_LIB%\metalua\mlc.luac
-%LUA% %BASE%\build-utils\bootstrap.lua %BASE%\compiler\metalua.mlua output=%DISTRIB_LIB%\metalua.luac
-
-@REM *** Finish the bootstrap: recompile the metalua parts of the compiler with itself ***
-
-call %DISTRIB_BIN%\metalua -vb -f compiler\mlc.mlua     -o %DISTRIB_LIB%\metalua\mlc.luac
-call %DISTRIB_BIN%\metalua -vb -f compiler\metalua.mlua -o %DISTRIB_LIB%\metalua.luac
-
-@REM *** Precompile metalua libraries ***
-%LUA% %BASE%\build-utils\precompile.lua directory=%DISTRIB_LIB% command=%DISTRIB_BIN%\metalua
diff --git a/make.sh b/make.sh
deleted file mode 100644
index fc890e9..0000000
--- a/make.sh
+++ /dev/null
@@ -1,135 +0,0 @@
-#! /bin/sh
-
-# --- BEGINNING OF USER-EDITABLE PART ---
-
-# Metalua sources
-BASE=${PWD}
-
-# Temporary building location.
-# Upon installation, everything will be moved to ${INSTALL_LIB} and ${INSTALL_BIN}
-
-if [ -z "${BUILD}" ]; then
-  BUILD=$(mkdir -p ../build; cd ../build; pwd)
-fi
-
-if [ -z "${BUILD_BIN}" ]; then
-  BUILD_BIN=${BUILD}/bin
-fi
-
-if [ -z "${BUILD_LIB}" ]; then
-  BUILD_LIB=${BUILD}/lib
-fi
-
-# Where to place the final results
-# DESTDIR=
-# INSTALL_BIN=/usr/local/bin
-# INSTALL_LIB=/usr/local/lib/lua/5.1
-if [ -z "${INSTALL_BIN}" ]; then
-  INSTALL_BIN=~/local/bin
-fi
-
-if [ -z "${INSTALL_LIB}" ]; then
-  INSTALL_LIB=~/local/lib/lua
-fi
-
-# Where to find Lua executables.
-# On many Debian-based systems, those can be installed with "sudo apt-get install lua5.1"
-LUA=$(which lua)
-LUAC=$(which luac)
-
-# --- END OF USER-EDITABLE PART ---
-
-if [ -z ${LUA}  ] ; then echo "Error: no lua interpreter found"; exit 1; fi
-if [ -z ${LUAC} ] ; then echo "Error: no lua compiler found"; exit 1; fi
-
-if [ -f ~/.metaluabuildrc ] ; then . ~/.metaluabuildrc; fi
-
-if [ -z "$LINEREADER" ] ; then LINEREADER=$(which rlwrap); fi
-
-if [ -z "$LINEREADER" ] ; then
-    echo "Warning, rlwrap not found, no line editor support for interactive mode"
-    echo "Consider performing the equivalent of 'sudo apt-get install rlwrap'."
-fi
-
-echo '*** Lua paths setup ***'
-
-export LUA_PATH="?.luac;?.lua;${BUILD_LIB}/?.luac;${BUILD_LIB}/?.lua"
-export LUA_MPATH="?.mlua;${BUILD_LIB}/?.mlua"
-
-echo '*** Create the distribution directories, populate them with lib sources ***'
-
-mkdir -p ${BUILD_BIN}
-mkdir -p ${BUILD_LIB}
-cp -Rp lib/* ${BUILD_LIB}/
-# cp -Rp bin/* ${BUILD_BIN}/ # No binaries provided for unix (for now)
-
-echo '*** Generating a callable metalua shell script ***'
-
-cat > ${BUILD_BIN}/metalua <<EOF
-#!/bin/sh
-export LUA_PATH='?.luac;?.lua;${BUILD_LIB}/?.luac;${BUILD_LIB}/?.lua'
-export LUA_MPATH='?.mlua;${BUILD_LIB}/?.mlua'
-exec ${LINEREADER} ${LUA} ${BUILD_LIB}/metalua.luac \$*
-EOF
-chmod a+x ${BUILD_BIN}/metalua
-
-echo '*** Compiling the parts of the compiler written in plain Lua ***'
-
-cd compiler
-${LUAC} -o ${BUILD_LIB}/metalua/bytecode.luac lopcodes.lua lcode.lua ldump.lua compile.lua || exit 1
-${LUAC} -o ${BUILD_LIB}/metalua/mlp.luac lexer.lua gg.lua mlp_lexer.lua mlp_misc.lua mlp_table.lua mlp_meta.lua mlp_expr.lua mlp_stat.lua mlp_ext.lua || exit 1
-cd ..
-
-echo '*** Bootstrap the parts of the compiler written in metalua ***'
-
-${LUA} ${BASE}/build-utils/bootstrap.lua ${BASE}/compiler/mlc.mlua output=${BUILD_LIB}/metalua/mlc.luac
-${LUA} ${BASE}/build-utils/bootstrap.lua ${BASE}/compiler/metalua.mlua output=${BUILD_LIB}/metalua.luac
-${LUA} ${BASE}/build-utils/bootstrap.lua ${BASE}/lib/metalua/treequery/walk.mlua output=${BUILD_LIB}/metalua/treequery/walk.luac
-
-echo '*** Finish the bootstrap: recompile the metalua parts of the compiler with itself ***'
-
-${BUILD_BIN}/metalua -vb -f compiler/mlc.mlua     -o ${BUILD_LIB}/metalua/mlc.luac
-${BUILD_BIN}/metalua -vb -f compiler/metalua.mlua -o ${BUILD_LIB}/metalua.luac
-${BUILD_BIN}/metalua -vb -f lib/metalua/treequery/walk.mlua -o ${BUILD_LIB}/metalua/treequery/walk.luac
-
-echo '*** Precompile metalua libraries ***'
-for SRC in $(find ${BUILD_LIB} -name '*.mlua'); do
-    DST=$(dirname $SRC)/$(basename $SRC .mlua).luac
-    if [ $DST -nt $SRC ]; then
-        echo "+ $DST already up-to-date"
-    else
-        echo "- $DST generated from $SRC"
-        ${BUILD_BIN}/metalua $SRC -o $DST
-    fi
-done
-
-echo '*** Generate make-install.sh script ***'
-
-cat > make-install.sh <<EOF2
-#!/bin/sh
-mkdir -p ${INSTALL_BIN}
-mkdir -p ${INSTALL_LIB}
-if [ -n "${DESTDIR}" ]; then
-    mkdir -p ${DESTDIR}${INSTALL_BIN}
-    mkdir -p ${DESTDIR}${INSTALL_LIB}
-fi
-cat > ${DESTDIR}${INSTALL_BIN}/metalua <<EOF
-#!/bin/sh
-METALUA_LIB=${INSTALL_LIB}
-export LUA_PATH="?.luac;?.lua;\\\${METALUA_LIB}/?.luac;\\\${METALUA_LIB}/?.lua"
-export LUA_MPATH="?.mlua;\\\${METALUA_LIB}/?.mlua"
-exec ${LINEREADER} ${LUA} \\\${METALUA_LIB}/metalua.luac "\\\$@"
-EOF
-
-chmod a+x ${DESTDIR}${INSTALL_BIN}/metalua
-
-cp -pR ${BUILD_LIB}/* ${DESTDIR}${INSTALL_LIB}/
-
-echo "metalua libs installed in ${INSTALL_LIB};"
-echo "metalua executable in ${INSTALL_BIN}."
-EOF2
-chmod a+x make-install.sh
-
-echo
-echo "Build completed, proceed to installation with './make-install.sh' or 'sudo ./make-install.sh'"
-echo
diff --git a/compiler/metalua.mlua b/metalua.lua
similarity index 71%
rename from compiler/metalua.mlua
rename to metalua.lua
index 4526243..7c97af3 100644
--- a/compiler/metalua.mlua
+++ b/metalua.lua
@@ -17,24 +17,29 @@
 --
 -------------------------------------------------------------------------------
 
---require 'verbose_require'
+-- Main file for the metalua executable
+require 'metalua.base'
+require 'metalua.compiler.globals' -- metalua-aware loadstring, dofile etc.
 
-require 'metalua.compiler'
-require 'metalua.clopts'
-require 'metalua.mlc_xcall'
+local mlc    = require 'metalua.compiler'
+local clopts = require 'metalua.clopts'
 
-AST_COMPILE_ERROR_NUMBER        = -1
-RUNTIME_ERROR_NUMBER            = -3
-BYTECODE_SYNTHESE_ERROR_NUMBER  = -100
+local M = { }
 
--{ extension 'match' }
+local AST_COMPILE_ERROR_NUMBER        = -1
+local RUNTIME_ERROR_NUMBER            = -3
+local BYTECODE_SYNTHESE_ERROR_NUMBER  = -100
 
 local chunks  = { }
 local runargs = { }
 
-local acc_chunk = |kind| |arg| table.insert (chunks, { tag=kind, arg })
+local function acc_chunk(kind)
+    return function(x)
+        table.insert (chunks, { tag=kind, x })
+    end
+end
 
-parser = clopts {
+M.cmdline_parser = clopts {
    -- Chunk loading
    {  short = 'f', long = 'file', type = 'string', action = acc_chunk 'File',
       usage = 'load a file to compile and/or run'
@@ -74,13 +79,14 @@
    {  short = 's', long = 'sharpbang', type = 'string',
       usage = 'set a first line to add to compiled file, typically "#!/bin/env mlr"'
    },
-   {  long  = 'no-runtime', type = 'boolean',
-      usage = "prevent the automatic requirement of metalua runtime"
+   {  long  = 'no-base-lib', type = 'boolean',
+      usage = "prevent the automatic requirement of metalua base lib"
    },
    {  long  = '', short = 'p', type = '*',
       action= function (newargs) runargs=table.icat(runargs, newargs) end,
       usage = "pass all remaining arguments to the program"
    },
+
 usage=[[
 
 Compile and/or execute metalua programs. Parameters passed to the
@@ -102,9 +108,9 @@
   forbids it.
 ]]}
 
-local function main (...)
+function M.main (...)
 
-   local cfg = parser(...)
+   local cfg = M.cmdline_parser(...)
 
    -------------------------------------------------------------------
    -- Print messages if in verbose mode
@@ -125,7 +131,7 @@
    if #chunks==0 and cfg.params then
       local the_file = table.remove(cfg.params, 1)
       verb_print("Param %q considered as a source file", the_file)
-      chunks = { `File{ the_file } }
+      chunks = { {tag='File', the_file } }
    end
 
    -------------------------------------------------------------------
@@ -148,25 +154,32 @@
 
    -------------------------------------------------------------------
    -- Get ASTs from sources
-   mlc.metabugs = cfg.metabugs
+
    local last_file
-   for x in values(chunks) do
+   for _, x in pairs(chunks) do
+      local compiler = mlc.new()
+      local tag, val = x.tag, x[1]
       verb_print("Compiling %s", table.tostring(x))
       local st, ast
-      match x with
-      | `Library{ l } -> st, ast = true, `Call{ `Id 'require', `String{ l } }
-      | `Literal{ e } -> st, ast = mlc_xcall.client_literal (e)
-      | `File{ f } ->
-         st, ast = mlc_xcall.client_file (f)
-          -- Isolate each file in a separate fenv
-         if st then
-            ast = +{ function (...) -{ast} end (...)  }
-            ast.source  = '@'..f -- TODO [EVE]
-            code.source = '@'..f -- TODO [EVE]
-            last_file = ast
-         end
+      if tag=='Library' then
+          ast = { tag='Call',
+                  {tag='Id', "require" },
+                  {tag='String', val } }
+      elseif tag=='Literal' then ast = compiler :src_to_ast(val)
+      elseif tag=='File' then
+         ast = compiler :srcfile_to_ast(val)
+         -- Isolate each file in a separate fenv
+         ast = { tag='Call', 
+                 { tag='Function', { { tag='Dots'} }, ast }, 
+                 { tag='Dots' } }
+         ast.source  = '@'..val -- TODO [EVE]
+         code.source = '@'..val -- TODO [EVE]
+         last_file = ast
+      else
+          error ("Bad option "..tag)
       end
-      if not st then
+      local valid = true -- TODO: check AST's correctness
+      if not valid then
          printf ("Cannot compile %s:\n%s", table.tostring(x), ast or "no msg")
          os.exit (AST_COMPILE_ERROR_NUMBER)
       end
@@ -175,15 +188,21 @@
    end
    -- The last file returns the whole chunk's result
    if last_file then
-      local c = table.shallow_copy(last_file)
-      last_file <- `Return{ source = c.source, c }
+       local c = table.shallow_copy(last_file)
+       table.override(last_file, {tag='Return', source = c.source, c })
    end
 
+   -- Further uses of compiler won't involve AST transformations:
+   -- they can share the same instance.
+   -- TODO: reuse last instance if possible.
+   local compiler = mlc.new()
+
+
    -------------------------------------------------------------------
    -- AST printing
    if cfg['print-ast'] or cfg['print-ast-lineinfo'] then
       verb_print "Resulting AST:"
-      for x in ivalues(code) do
+      for _, x in ipairs(code) do
          printf("--- AST From %s: ---", table.tostring(x.source, 'nohash'))
          if x.origin and x.origin.tag=='File' then x=x[1][1][2][1] end
          if cfg['print-ast-lineinfo'] then table.print(x, 80, "indent1")
@@ -195,25 +214,27 @@
    -- Source printing
    if cfg['print-src'] then
       verb_print "Resulting sources:"
-      require 'metalua.ast_to_string'
-      for x in ivalues(code) do
+      for _, x in ipairs(code) do
          printf("--- Source From %s: ---", table.tostring(x.source, 'nohash'))
-         if x.origin and x.origin.tag=='File' then x=x[1][1][2][1] end
-         print (ast_to_string (x))
+         if x.origin and x.origin.tag=='File' then x=x[1][1][2] end
+         print (compiler :ast2string (x))
       end
    end
 
-   -- FIXME: canonize/check AST
+   -- TODO: canonize/check AST
 
    -------------------------------------------------------------------
-   -- Insert runtime loader
-   if cfg['no-runtime'] then
-      verb_print "Prevent insertion of command \"require 'metalua.runtime'\""
+   -- Insert base lib loader
+   if cfg['no-base-lib'] then
+      verb_print "Prevent insertion of command \"require 'metalua.base'\""
    else
-      table.insert(code, 1, +{require'metalua.runtime'})
+       local req_runtime = { tag='Call',
+                             {tag='Id', "require"},
+                             {tag='String', "metalua.base"} }
+       table.insert(code, 1, req_runtime)
    end
 
-   local bytecode = mlc.ast_to_luacstring (code)
+   local bytecode = compiler :ast_to_bytecode (code)
    code = nil
 
    -------------------------------------------------------------------
@@ -221,8 +242,8 @@
    if cfg.sharpbang then
       local shbang = cfg.sharpbang
       verb_print ("Adding sharp-bang directive %q", shbang)
-      if not shbang :strmatch'^#!' then shbang = '#!' .. shbang end
-      if not shbang :strmatch'\n$' then shbang = shbang .. '\n' end
+      if not shbang :match'^#!' then shbang = '#!' .. shbang end
+      if not shbang :match'\n$' then shbang = shbang .. '\n' end
       bytecode = shbang .. bytecode
    end
 
@@ -244,16 +265,16 @@
    -- Run compiled code
    if cfg.run then
       verb_print "Running"
-      local f = mlc.luacstring_to_function (bytecode)
+      local f = compiler :bytecode_to_function (bytecode)
       bytecode = nil
       -- FIXME: isolate execution in a ring
       -- FIXME: check for failures
-
       runargs = table.icat(cfg.params or { }, runargs)
       local function print_traceback (errmsg)
          return errmsg .. '\n' .. debug.traceback ('',2) .. '\n'
       end
-      local st, msg = xpcall(|| f(unpack (runargs)), print_traceback)
+      local function g() return f(unpack (runargs)) end
+      local st, msg = xpcall(g, print_traceback)
       if not st then
          io.stderr:write(msg)
          os.exit(RUNTIME_ERROR_NUMBER)
@@ -264,12 +285,16 @@
    -- Run REPL loop
    if cfg.interactive then
       verb_print "Starting REPL loop"
-      require 'metalua.metaloop'
-      metaloop.run()
+      require 'metalua.repl' .run()
    end
 
    verb_print "Done"
 
 end
 
-main(...)
+-- If the lib is being loaded, the sentinel token is currently
+-- put as a placeholder in its package.loaded entry.
+local called_as_a_lib = type(package.loaded.metalua)=='userdata'
+
+if not called_as_a_lib then M.main(...)
+else return M end
\ No newline at end of file
diff --git a/lib/metalua/base.lua b/metalua/base.lua
similarity index 63%
rename from lib/metalua/base.lua
rename to metalua/base.lua
index 08be242..b0f0e36 100644
--- a/lib/metalua/base.lua
+++ b/metalua/base.lua
@@ -1,4 +1,4 @@
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 -- Copyright (c) 2006-2013 Fabien Fleutot and others.
 --
 -- All rights reserved.
@@ -15,7 +15,7 @@
 -- Contributors:
 --     Fabien Fleutot - API and implementation
 --
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
@@ -25,53 +25,7 @@
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
-if not metalua then rawset(getfenv(), 'metalua', { }) end
-metalua.version             = "v-0.5"
-
-if not rawpairs then
-   rawpairs, rawipairs, rawtype = pairs, ipairs, type
-end
-
-function pairs(x)
-   assert(type(x)=='table', 'pairs() expects a table')
-   local mt = getmetatable(x)
-   if mt then
-      local mtp = mt.__pairs
-      if mtp then return mtp(x) end
-   end
-   return rawpairs(x)
-end
-
-function ipairs(x)
-   assert(type(x)=='table', 'ipairs() expects a table')
-   local mt = getmetatable(x)
-   if mt then
-      local mti = mt.__ipairs
-      if mti then return mti(x) end
-   end
-   return rawipairs(x)
-end
-
---[[
-function type(x)
-   local mt = getmetatable(x)
-   if mt then
-      local mtt = mt.__type
-      if mtt then return mtt end
-   end
-   return rawtype(x)
-end
-]]
-
-function min (a, ...)
-   for n in values{...} do if n<a then a=n end end
-   return a
-end
-
-function max (a, ...)
-   for n in values{...} do if n>a then a=n end end
-   return a
-end
+require 'checks'
 
 function o (...)
    local args = {...}
@@ -92,7 +46,7 @@
 end
 
 function ivalues (x)
-   assert(type(x)=='table', 'ivalues() expects a table')
+   checks('table')
    local i = 1
    local function iterator ()
       local r = x[i]; i=i+1; return r
@@ -102,7 +56,7 @@
 
 
 function values (x)
-   assert(type(x)=='table', 'values() expects a table')
+   checks('table')
    local function iterator (state)
       local it
       state.content, it = next(state.list, state.content)
@@ -112,7 +66,7 @@
 end
 
 function keys (x)
-   assert(type(x)=='table', 'keys() expects a table')
+   checks('table')
    local function iterator (state)
       local it = next(state.list, state.content)
       state.content = it
@@ -121,3 +75,6 @@
    return iterator, { list = x }
 end
 
+require 'metalua.table'
+require 'metalua.string'
+require 'metalua.package'
\ No newline at end of file
diff --git a/lib/metalua/clopts.mlua b/metalua/clopts.mlua
similarity index 98%
rename from lib/metalua/clopts.mlua
rename to metalua/clopts.mlua
index 28d19c3..7ea6c4f 100644
--- a/lib/metalua/clopts.mlua
+++ b/metalua/clopts.mlua
@@ -38,9 +38,9 @@
 -- * add a ++ long counterpart to +
 --
 
--{ extension 'match' }
+-{ extension ('match',...) }
 
-function clopts(cfg)
+local function clopts(cfg)
    local short, long, param_func = { }, { }
    local legal_types = table.transpose{ 
       'boolean','string','number','string*','number*','nil', '*' }
@@ -48,7 +48,7 @@
    -----------------------------------------------------------------------------
    -- Fill short and long name indexes, and check its validity
    -----------------------------------------------------------------------------
-   for x in ivalues(cfg) do
+   for _, x in ipairs(cfg) do
       local xtype = type(x)
       if xtype=='table' then
          if not x.type then x.type='nil' end
@@ -73,7 +73,7 @@
    local function print_usage(msg)
       if msg then print(msg,'\n') end
       print(cfg.usage or "Options:\n")
-      for x in values(cfg) do
+      for _, x in pairs(cfg) do
          if type(x) == 'table' then
             local opts = { }
             if x.type=='boolean' then 
@@ -220,4 +220,4 @@
    return parse
 end
 
-
+return clopts
diff --git a/metalua/compiler.lua b/metalua/compiler.lua
new file mode 100644
index 0000000..96c4e3d
--- /dev/null
+++ b/metalua/compiler.lua
@@ -0,0 +1,239 @@
+--------------------------------------------------------------------------------
+-- Copyright (c) 2006-2013 Fabien Fleutot and others.
+--
+-- All rights reserved.
+--
+-- This program and the accompanying materials are made available
+-- under the terms of the Eclipse Public License v1.0 which
+-- accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- This program and the accompanying materials are also made available
+-- under the terms of the MIT public license which accompanies this
+-- distribution, and is available at http://www.lua.org/license.html
+--
+-- Contributors:
+--     Fabien Fleutot - API and implementation
+--
+--------------------------------------------------------------------------------
+
+--*-lua-*-----------------------------------------------------------------------
+--
+-- Convert between various code representation formats. Some atomic
+-- converters are written in extenso, others are composed automatically
+-- by chaining the atomic ones together in a closure.
+--
+-- Supported formats are:
+--
+-- * luafile:    the name of a file containing sources.
+-- * luastring:  these sources as a single string.
+-- * lexstream:  a stream of lexemes.
+-- * ast:        an abstract syntax tree.
+-- * proto:      a (Yueliang) struture containing a high level 
+--               representation of bytecode. Largely based on the 
+--               Proto structure in Lua's VM
+-- * luacstring: a string dump of the function, as taken by 
+--               loadstring() and produced by string.dump().
+-- * function:   an executable lua function in RAM.
+--
+--------------------------------------------------------------------------------
+
+require 'checks'
+require 'metalua.table'
+
+local M  = { }
+
+--------------------------------------------------------------------------------
+-- Order of the transformations. if 'a' is on the left of 'b', then a 'a' can
+-- be transformed into a 'b' (but not the other way around).
+-- M.sequence goes for numbers to format names, M.order goes from format
+-- names to numbers.
+--------------------------------------------------------------------------------
+M.sequence = {
+	'srcfile',  'src', 'lexstream', 'ast', 'proto', 'bytecode', 'function' }
+
+local arg_types = {
+	srcfile    = { 'string', '?string' },
+	src        = { 'string', '?string' },
+	lexstream  = { 'lexer.stream', '?string' },
+	ast        = { 'table', '?string' },
+	proto      = { 'table', '?string' },
+	bytecode   = { 'string', '?string' },
+}
+
+M.order = table.transpose(M.sequence)
+
+local function check_ast(kind, ast)
+	if not ast then return check_ast('block', kind) end
+	assert(type(ast)=='table', "wrong AST type")
+	local cfg = {}
+	local function error2ast(error_node, ...)
+		if not error_node.earlier then
+			if error_node.tag=='Error' then
+				cfg.errorfound = true
+				cfg.errormsg = error_node[1]
+
+				-- Try to extract error position in source
+				local li = error_node.lineinfo and error_node.lineinfo.first
+
+				-- Fill positions if undefined or not narrow enough
+				if li and ( not cfg.positions or cfg.positions.offset < li.offset ) then
+					cfg.positions = {
+						column = li.column,
+						line   = li.line,
+						offset = li.offset
+					}
+				end
+			else
+				-- This block is for dealing with errors which are not error
+				-- nodes. It would be soooo nice to get rid of it.
+				-- TODO: Try to remove this bug when issue #20 is fixed
+				local li
+				for _, n in ipairs{ error_node, ... } do
+					if n.lineinfo then
+						li = n.lineinfo
+						cfg.errorfound = true
+						break
+					end
+				end
+				local posmsg
+				if li then
+					local column = li.first.column
+					local line   = li.first.line
+					local offset = li.first.offset
+					posmsg = string.format("line %d, char %d, offset %d",
+					line, column, offset)
+					cfg.positions = {
+						column = column,
+						line   = line,
+						offset = offset
+					}
+				else
+					posmsg = "unknown source position"     
+				end
+				local msg = "Invalid node "..
+				(error_node.tag and "tag "..tostring(error_node.tag) or "without tag")..
+				(posmsg and " at "..posmsg or "")
+				cfg.errormsg = msg
+			end
+		end
+	end
+	local f = require 'metalua.treequery.walk' [kind]
+	cfg.malformed=error2ast
+	cfg.unknown=  error2ast
+	cfg.error=    error2ast
+	f(cfg, ast)
+	return cfg.errorfound == nil, cfg.errormsg, cfg.positions
+end
+
+M.check_ast = check_ast
+
+local function find_error(ast, nested)
+	checks('table', '?table')
+	nested = nested or { }
+	if nested[ast] then return "Cyclic AST" end
+	nested[ast]=true
+	if ast.tag=='Error' then
+		local pos = tostring(ast.lineinfo.first)
+		return pos..": "..ast[1]
+	end
+	for _, item in ipairs(ast) do
+		if type(item)=='table' then
+			local err=find_error(item)
+			if err then return err end
+		end
+	end
+	nested[ast]=nil
+	return nil
+end
+
+local CONV = { } -- conversion metatable __index
+
+function CONV :srcfile_to_src(x, name)
+	checks('metalua.compiler', 'string', '?string')
+	name = name or '@'..x
+	local f, msg = io.open (x, 'rb')
+	if not f then error(msg) end
+	local r, msg = f :read '*a'
+	if not r then error("Cannot read file '"..x.."': "..msg) end
+	f :close()
+	return r, name
+end
+
+function CONV :src_to_lexstream(src, name)
+	checks('metalua.compiler', 'string', '?string')
+	local r = self.parser.lexer :newstream (src, name)
+	return r, name
+end
+
+function CONV :lexstream_to_ast(lx, name)
+	checks('metalua.compiler', 'lexer.stream', '?string')
+	local r = self.parser.chunk(lx)
+	r.source = name
+	return r, name
+end
+
+function CONV :ast_to_proto(ast, name)
+	checks('metalua.compiler', 'table', '?string')
+	--table.print(ast, 'nohash', 1) io.flush()
+	local err = find_error(ast)
+	if err then  error(err) end
+	local f = require 'metalua.compiler.bytecode.compile'.ast_to_proto
+	return f(ast, name), name
+end
+
+function CONV :proto_to_bytecode(proto, name)
+	local bc = require 'metalua.compiler.bytecode'
+	return bc.proto_to_bytecode(proto), name
+end
+
+function CONV :bytecode_to_function(bc, name)
+	checks('metalua.compiler', 'string', '?string')
+	return loadstring(bc, name)
+end
+
+-- Create all sensible combinations
+for i=1,#M.sequence do
+	local src = M.sequence[i]
+	for j=i+2, #M.sequence do
+		local dst = M.sequence[j]
+		local dst_name = src.."_to_"..dst
+		local my_arg_types = arg_types[src]
+		local functions = { }
+		for k=i, j-1 do
+			local name =  M.sequence[k].."_to_"..M.sequence[k+1]
+			local f = assert(CONV[name], name)
+			table.insert (functions, f)
+		end
+		CONV[dst_name] = function(self, a, b)
+			checks('metalua.compiler', unpack(my_arg_types))
+			for _, f in ipairs(functions) do
+				a, b = f(self, a, b)
+			end
+			return a, b
+		end
+		--printf("Created M.%s out of %s", dst_name, table.concat(n, ', '))
+	end
+end
+
+
+--------------------------------------------------------------------------------
+-- This one goes in the "wrong" direction, cannot be composed.
+--------------------------------------------------------------------------------
+function CONV :function_to_bytecode(...) return string.dump(...) end
+
+function CONV :ast_to_src(...)
+	require 'metalua.package' -- ast_to_string isn't written in plain lua
+	return require 'metalua.compiler.ast_to_src' (...)
+end
+
+local MT = { __index=CONV, __type='metalua.compiler' }
+
+function M.new() 
+	local parser = require 'metalua.compiler.parser' .new()
+	local self = { parser = parser }
+	setmetatable(self, MT)
+	return self
+end
+
+return M
\ No newline at end of file
diff --git a/lib/metalua/ast_to_string.mlua b/metalua/compiler/ast_to_src.mlua
similarity index 83%
rename from lib/metalua/ast_to_string.mlua
rename to metalua/compiler/ast_to_src.mlua
index 33091c6..3eec4a5 100644
--- a/lib/metalua/ast_to_string.mlua
+++ b/metalua/compiler/ast_to_src.mlua
@@ -17,13 +17,11 @@
 --
 -------------------------------------------------------------------------------
 
--{ extension 'match' }
+-{ extension ('match', ...) }
 
 local M = { }
 M.__index = M
 
-ast_to_string = |x| M.run(x)
-
 --------------------------------------------------------------------------------
 -- Instanciate a new AST->source synthetizer
 --------------------------------------------------------------------------------
@@ -134,7 +132,7 @@
 local op_prec = { }
 
 for prec, ops in ipairs (op_preprec) do
-   for op in ivalues (ops) do
+   for _, op in ipairs (ops) do
       op_prec[op] = prec
    end
 end
@@ -158,6 +156,7 @@
 --------------------------------------------------------------------------------
 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
@@ -187,7 +186,7 @@
    for i = start or 1, # list do
       self:node (list[i])
       if list[i + 1] then
-         if not sep then            
+         if not sep then 
          elseif type (sep) == "function" then sep (self)
          elseif type (sep) == "string"   then self:acc (sep)
          else   error "Invalid list separator" end
@@ -279,6 +278,20 @@
       self:list  (lhs, ", ")
       self:acc   " = "
       self:list  (rhs, ", ")
+   | `Set{ lhs, rhs, annot } ->
+      -- ``... = ...'', no syntax sugar, annotation --
+      local n = #lhs
+      for i=1,n do
+          local ell, a = lhs[i], annot[i]
+          self:node (ell)
+          if a then 
+              self:acc ' #'
+              self:node(a)
+          end
+          if i~=n then self:acc ', ' end
+      end
+      self:acc   " = "
+      self:list  (rhs, ", ")
    end
 end
 
@@ -353,17 +366,30 @@
    self:acc      "end"
 end
 
-function M:Local (node, lhs, rhs)
-   if next (lhs) then
-      self:acc     "local "
-      self:list    (lhs, ", ")
-      if rhs[1] then
-         self:acc  " = "
-         self:list (rhs, ", ")
-      end
-   else -- Can't create a local statement with 0 variables in plain Lua
-      self:acc (table.tostring (node, 'nohash', 80))
-   end
+function M:Local (node, lhs, rhs, annots)
+    if next (lhs) then
+        self:acc     "local "
+        if annots then
+            local n = #lhs
+            for i=1, n do
+                self:node (lhs)
+                local a = annots[i]
+                if a then
+                    self:acc ' #'
+                    self:node (a)
+                end
+                if i~=n then self:acc ', ' end
+            end
+        else
+            self:list    (lhs, ", ")
+        end
+        if rhs[1] then
+            self:acc  " = "
+            self:list (rhs, ", ")
+        end
+    else -- Can't create a local statement with 0 variables in plain Lua
+        self:acc (table.tostring (node, 'nohash', 80))
+    end
 end
 
 function M:Localrec (node, lhs, rhs)
@@ -441,14 +467,27 @@
    self:acc (string.format ("%q", str):gsub ("\\\n", "\\n"))
 end
 
-function M:Function (node, params, body)
-   self:acc      "function ("
-   self:list     (params, ", ")
-   self:acc      ")"
-   self:nlindent ()
-   self:list     (body, self.nl)
-   self:nldedent ()
-   self:acc      "end"
+function M:Function (node, params, body, annots)
+    self:acc      "function ("
+    if annots then
+        local n = #params
+        for i=1,n do
+            local p, a = params[i], annots[i]
+            self:node(p)
+            if annots then
+                self:acc " #"
+                self:node(a)
+            end
+            if i~=n then self:acc ', ' end
+        end
+    else
+        self:list (params, ", ")
+    end
+    self:acc      ")"
+    self:nlindent ()
+    self:list     (body, self.nl)
+    self:nldedent ()
+    self:acc      "end"
 end
 
 function M:Table (node)
@@ -515,7 +554,7 @@
       self:node (b)
       self:acc  (right_paren and ")")
 
-   else -- unary operator.     
+   else -- unary operator.
       local paren
       match a with
       | `Op{ op_a, ... } if op_prec[op] >= op_prec[op_a] -> paren = true
@@ -570,3 +609,81 @@
    end 
 end
 
+
+M.TDyn    = '*'
+M.TDynbar = '**'
+M.TPass   = 'pass'
+M.TField  = 'field'
+M.TIdbar  = M.TId
+M.TReturn = M.Return
+
+
+function M:TId (node, name) self:acc(name) end
+
+
+function M:TCatbar(node, te, tebar)
+    self:acc'('
+    self:node(te)
+    self:acc'|'
+    self:tebar(tebar)
+    self:acc')'
+end
+
+function M:TFunction(node, p, r)
+    self:tebar(p)
+    self:acc '->'
+    self:tebar(r)
+end
+
+function M:TTable (node, default, pairs)
+    self:acc '['
+    self:list (pairs, ', ')
+    if default.tag~='TField' then
+        self:acc '|'
+        self:node (default)
+    end
+    self:acc ']'
+end
+
+function M:TPair (node, k, v)
+    self:node (k)
+    self:acc '='
+    self:node (v)
+end
+
+function M:TIdbar (node, name)
+    self :acc (name)
+end
+
+function M:TCatbar (node, a, b)
+    self:node(a)
+    self:acc ' ++ '
+    self:node(b)
+end
+
+function M:tebar(node)
+    if node.tag then self:node(node) else
+        self:acc '('
+        self:list(node, ', ')
+        self:acc ')'
+    end
+end
+
+function M:TUnkbar(node, name)
+    self:acc '~~'
+    self:acc (name)
+end
+
+function M:TUnk(node, name)
+    self:acc '~'
+    self:acc (name)
+end
+
+for name, tag in pairs{ const='TConst', var='TVar', currently='TCurrently', just='TJust' } do
+    M[tag] = function(self, node, te)
+        self:acc (name..' ')
+        self:node(te)
+    end
+end
+
+return (|x| M.run(x))
diff --git a/lib/verbose_require.lua b/metalua/compiler/bytecode.lua
similarity index 70%
copy from lib/verbose_require.lua
copy to metalua/compiler/bytecode.lua
index 0e07650..b3afbdb 100644
--- a/lib/verbose_require.lua
+++ b/metalua/compiler/bytecode.lua
@@ -1,4 +1,4 @@
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 -- Copyright (c) 2006-2013 Fabien Fleutot and others.
 --
 -- All rights reserved.
@@ -15,17 +15,15 @@
 -- Contributors:
 --     Fabien Fleutot - API and implementation
 --
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 
+local compile = require 'metalua.compiler.bytecode.compile'
+local ldump   = require 'metalua.compiler.bytecode.ldump'
 
-do
-   local xrequire, n, ind = require, 0, "| "
-   function require (x)
-      print(ind:rep(n).."/ require: "..x)
-      n=n+1
-      local y = xrequire(x)
-      n=n-1
-      print(ind:rep(n).."\\_")
-      return y
-   end
-end
+local M = { }
+
+M.ast_to_proto      = compile.ast_to_proto
+M.proto_to_bytecode = ldump.dump_string
+M.proto_to_file     = ldump.dump_file
+
+return M
\ No newline at end of file
diff --git a/compiler/compile.lua b/metalua/compiler/bytecode/compile.lua
similarity index 93%
rename from compiler/compile.lua
rename to metalua/compiler/bytecode/compile.lua
index fc12ea5..1e2c972 100644
--- a/compiler/compile.lua
+++ b/metalua/compiler/bytecode/compile.lua
@@ -17,10 +17,29 @@
 --     Fabien Fleutot - Port to Lua 5.1, integration with Metalua
 --
 -------------------------------------------------------------------------------
+
+----------------------------------------------------------------------
+--
+-- WARNING! You're entering a hackish area, proceed at your own risks!
+--
+-- This code partly results from the borrowing, then ruthless abuse, of
+-- Yueliang's implementation of Lua 5.0 compiler. I claim
+-- responsibility for all of the ugly, dirty stuff that you might spot
+-- in it.
+--
+-- Eventually, this code will be rewritten, either in Lua or more
+-- probably in C. Meanwhile, if you're interested into digging
+-- metalua's sources, this is not the best part to invest your time
+-- on.
+--
+-- End of warning.
+--
+----------------------------------------------------------------------
+
 ----------------------------------------------------------------------
 -- Metalua.
 --
--- Summary: Compile ASTs to Lua 5.1 VM function prototype.
+-- Summary: Compile ASTs to Lua 5.1 VM function prototype. 
 -- Largely based on:
 --
 -- * Yueliang (http://luaforge.net/projects/yueliang),
@@ -29,8 +48,16 @@
 -- * Lua 5.1 sources (http://www.lua.org), src/lparser.c
 --
 ----------------------------------------------------------------------
+--
+-- Copyright (c) 2006-2008, Fabien Fleutot <metalua@gmail.com>.
+--
+-- This software is released under the MIT Licence, see licence.txt
+-- for details.
+--
+----------------------------------------------------------------------
 
-module ("bytecode", package.seeall)
+local luaK = require 'metalua.compiler.bytecode.lcode'
+local luaP = require 'metalua.compiler.bytecode.lopcodes'
 
 local debugf = function() end
 --local debugf=printf
@@ -38,16 +65,18 @@
 local stat = { }
 local expr = { }
 
-MAX_INT            = 2147483645 -- INT_MAX-2 for 32-bit systems (llimits.h)
-MAXVARS            = 200        -- (llimits.h)
-MAXUPVALUES        = 32         -- (llimits.h)
-MAXPARAMS          = 100        -- (llimits.h)
-LUA_MAXPARSERLEVEL = 200        -- (llimits.h)
+local M = { }
+
+M.MAX_INT            = 2147483645 -- INT_MAX-2 for 32-bit systems (llimits.h)
+M.MAXVARS            = 200        -- (llimits.h)
+M.MAXUPVALUES        = 32         -- (llimits.h)
+M.MAXPARAMS          = 100        -- (llimits.h)
+M.LUA_MAXPARSERLEVEL = 200        -- (llimits.h)
 
 -- from lobject.h
-VARARG_HASARG   = 1
-VARARG_ISVARARG = 2
-VARARG_NEEDSARG = 4
+M.VARARG_HASARG   = 1
+M.VARARG_ISVARARG = 2
+M.VARARG_NEEDSARG = 4
 
 local function hasmultret (k) 
    return k=="VCALL" or k=="VVARARG"
@@ -100,7 +129,7 @@
 -- since [fs.nactvar] and [fs.freereg] aren't updated.
 -----------------------------------------------------------------------
 local function registerlocalvar (fs, varname)
-   debugf("[locvar: %s = reg %i]", varname, fs.nlocvars)
+   --debugf("[locvar: %s = reg %i]", varname, fs.nlocvars)
    local f = fs.f
    f.locvars[fs.nlocvars] = { } -- LocVar
    f.locvars[fs.nlocvars].varname = varname
@@ -280,7 +309,7 @@
 ------------------------------------------------------------------------
 -- FIXME: is there a need for f=fs.f? if yes, why not always using it? 
 ------------------------------------------------------------------------
-function indexupvalue(fs, name, v)
+local function indexupvalue(fs, name, v)
    local f = fs.f
    for i = 0, f.nups - 1 do
       if fs.upvalues[i].k == v.k and fs.upvalues[i].info == v.info then
@@ -471,7 +500,7 @@
 ------------------------------------------------------------------------
 local function new_localvar (fs, name, n)
   assert (type (name) == "string")
-  if fs.nactvar + n > MAXVARS then error ("too many local vars") end
+  if fs.nactvar + n > M.MAXVARS then error ("too many local vars") end
   fs.actvar[fs.nactvar + n] = registerlocalvar (fs, name)
   --printf("[NEW_LOCVAR] %i = %s", fs.nactvar+n, name)
 end
@@ -487,9 +516,9 @@
       new_localvar (fs, ast_params[i][1], i-1)
    end
    -- from [code_param]:
-   --checklimit (fs, fs.nactvar, self.MAXPARAMS, "parameters")
+   --checklimit (fs, fs.nactvar, self.M.MAXPARAMS, "parameters")
    fs.f.numparams = fs.nactvar
-   fs.f.is_vararg = dots and VARARG_ISVARARG or 0 
+   fs.f.is_vararg = dots and M.VARARG_ISVARARG or 0 
    adjustlocalvars (fs, nparams)
    fs.f.numparams = fs.nactvar --FIXME vararg must be taken in account
    luaK:reserveregs (fs, fs.nactvar)  -- reserve register for parameters
@@ -524,7 +553,7 @@
 ------------------------------------------------------------------------
 local function enterlevel (fs)
    fs.nestlevel = fs.nestlevel + 1
-   assert (fs.nestlevel <= LUA_MAXPARSERLEVEL, "too many syntax levels")
+   assert (fs.nestlevel <= M.LUA_MAXPARSERLEVEL, "too many syntax levels")
 end
 
 ------------------------------------------------------------------------
@@ -668,7 +697,7 @@
 
 function stat.stat (fs, ast)
    if ast.lineinfo then fs.lastline = ast.lineinfo.last.line end
-   -- debugf (" - Statement %s", disp.ast (ast) )
+   --debugf (" - Statement %s", table.tostring (ast) )
 
    if not ast.tag then chunk (fs, ast) else
 
@@ -677,8 +706,7 @@
          error ("A statement cannot have tag `"..ast.tag) end
       parser (fs, ast)
    end
-   --debugf (" - /Statement `%s", ast.tag or "<nil>")
-   debugf (" - /Statement `%s", ast.tag)
+   --debugf (" - /Statement `%s", ast.tag)
 end
 
 ------------------------------------------------------------------------
@@ -719,10 +747,10 @@
          end
          first = fs.nactvar
          nret = luaK.LUA_MULTRET  -- return all values
-      elseif nret == 1 then 
-         --printf("[RETURN] 1 val: e=%s", tostringv(e))
-         first = luaK:exp2anyreg(fs, e)
-         --printf("[RETURN] 1 val in reg %i", first)
+      elseif nret == 1 then
+         if ast[1].tag ~= "Error" then
+            first = luaK:exp2anyreg(fs, e)
+         end
       else
          --printf("* Return multiple vals in nextreg %i", fs.freereg)
          luaK:exp2nextreg(fs, e)  -- values must go to the 'stack'
@@ -1041,14 +1069,14 @@
 
    if ast.lineinfo then fs.lastline = ast.lineinfo.last.line end
 
-   --debugf (" - Expression %s", tostringv (ast))
+   --debugf (" - Expression %s", table.tostring (ast))
    local parser = expr[ast.tag]
    if parser then parser (fs, ast, v)
    elseif not ast.tag then 
       error ("No tag in expression "..table.tostring(ast, 'nohash', 80))
    else 
       error ("No parser for node `"..ast.tag) end
-   debugf (" - /`%s", ast.tag)
+   --debugf (" - /Expression `%s", ast.tag)
 end
 
 ------------------------------------------------------------------------
@@ -1071,8 +1099,8 @@
    assert (fs.f.is_vararg ~= 0, "No vararg in this function")
    -- NEEDSARG flag is set if and only if the function is a vararg,
    -- but no vararg has been used yet in its code.
-   if fs.f.is_vararg < VARARG_NEEDSARG then 
-      fs.f.is_varag = fs.f.is_vararg - VARARG_NEEDSARG end
+   if fs.f.is_vararg < M.VARARG_NEEDSARG then 
+      fs.f.is_varag = fs.f.is_vararg - M.VARARG_NEEDSARG end
    init_exp (v, "VVARARG", luaK:codeABC (fs, "OP_VARARG", 0, 1, 0))
 end
 
@@ -1205,7 +1233,7 @@
    -- "local foo = -{`Stat{...}}", variable foo will be messed up by
    -- the compilation of `Stat.
    -- FIX: save the active variables at indices >= nactvar in
-   -- save_actvar, and restore them after `Stat has been computer.
+   -- save_actvar, and restore them after `Stat has been computed.
    --
    -- I use a while rather than for loops and length operators because
    -- fs.actvar is a 0-based array...
@@ -1247,19 +1275,30 @@
    --printf(" * End of Stat")
 end
 
-
+function expr.Error() end
 
 ------------------------------------------------------------------------
 -- Main function: ast --> proto
 ------------------------------------------------------------------------
-function metalua_compile (ast, source)
+function M.ast_to_proto (ast, source)
   local fs = open_func (nil)
-  fs.f.is_vararg = VARARG_ISVARARG
+  fs.f.is_vararg = M.VARARG_ISVARARG
   chunk (fs, ast)
   close_func (fs)
   assert (fs.prev == nil)
   assert (fs.f.nups == 0)
   assert (fs.nestlevel == 0)
   if source then fs.f.source = source end
-  return fs.f
+  return fs.f, source
 end
+
+local function Error (fs, ast, v)
+    local msg = string.format ("Error node in AST at position %s: %s",
+                               tostring(ast.lineinfo),
+                               table.tostring(ast, nohash))
+    error(msg)
+end
+
+expr.Error, stat.Error = Error, Error
+
+return M
\ No newline at end of file
diff --git a/compiler/lcode.lua b/metalua/compiler/bytecode/lcode.lua
similarity index 97%
rename from compiler/lcode.lua
rename to metalua/compiler/bytecode/lcode.lua
index d6de77e..adabbb3 100644
--- a/compiler/lcode.lua
+++ b/metalua/compiler/bytecode/lcode.lua
@@ -18,8 +18,28 @@
 --
 -------------------------------------------------------------------------------
 
+----------------------------------------------------------------------
+--
+-- WARNING! You're entering a hackish area, proceed at your own risks!
+--
+-- This code results from the borrowing, then ruthless abuse, of
+-- Yueliang's implementation of Lua 5.0 compiler. I claim
+-- responsibility for all of the ugly, dirty stuff that you might spot
+-- in it.
+--
+-- Eventually, this code will be rewritten, either in Lua or more
+-- probably in C. Meanwhile, if you're interested into digging
+-- metalua's sources, this is not the best part to invest your time
+-- on.
+--
+-- End of warning.
+--
+----------------------------------------------------------------------
+
 --[[--------------------------------------------------------------------
 
+  $Id$
+
   lcode.lua
   Lua 5 code generator in Lua
   This file is part of Yueliang.
@@ -52,11 +72,11 @@
 --   luaK:sethvalue(o) (from lobject.h)
 ----------------------------------------------------------------------]]
 
-module("bytecode", package.seeall)
+local luaP = require 'metalua.compiler.bytecode.lopcodes'
 
 local function debugf() end
 
-luaK = {}
+local luaK = { }
 
 luaK.MAXSTACK    = 250        -- (llimits.h, used in lcode.lua)
 luaK.LUA_MULTRET = -1         -- (lua.h)
@@ -1032,3 +1052,5 @@
    end
    fs.freereg = base + 1
 end
+
+return luaK
\ No newline at end of file
diff --git a/compiler/ldump.lua b/metalua/compiler/bytecode/ldump.lua
similarity index 95%
rename from compiler/ldump.lua
rename to metalua/compiler/bytecode/ldump.lua
index 05ace5c..01d1b97 100644
--- a/compiler/ldump.lua
+++ b/metalua/compiler/bytecode/ldump.lua
@@ -18,6 +18,13 @@
 --
 -------------------------------------------------------------------------------
 
+----------------------------------------------------------------------
+--
+-- This code results from the borrowing, then ruthless abuse, of
+-- Yueliang's implementation of Lua 5.0 compiler.
+--
+----------------------------------------------------------------------
+
 --[[--------------------------------------------------------------------
 
   ldump.lua
@@ -56,9 +63,11 @@
 --   luaU:ttype(o) (from lobject.h)
 ----------------------------------------------------------------------]]
 
-module("bytecode", package.seeall)
+local luaP = require 'metalua.compiler.bytecode.lopcodes'
 
-format = { }
+local M = { }
+
+local format = { }
 format.header = string.dump(function()end):sub(1, 12)
 format.little_endian, format.int_size, 
 format.size_t_size,   format.instr_size, 
@@ -70,7 +79,10 @@
 assert(format.little_endian, "Big endian architectures not supported by dumper")
 
 --requires luaP
-luaU = {}
+local luaU = { }
+M.luaU = luaU
+
+luaU.format = format
 
 -- constants used by dumper
 luaU.LUA_TNIL     = 0
@@ -229,21 +241,21 @@
 end
 
 ------------------------------------------------------------------------
--- dumps a 32-bit signed integer (for int)
+-- dumps a signed integer of size `format.int_size` (for int)
 ------------------------------------------------------------------------
 function luaU:DumpInt(x, D)
   self:DumpBlock(self:from_int(x, format.int_size), D)
 end
 
 ------------------------------------------------------------------------
--- dumps a 32-bit unsigned integer (for size_t)
+-- dumps an unsigned integer of size `format.size_t_size` (for size_t)
 ------------------------------------------------------------------------
 function luaU:DumpSize(x, D)
   self:DumpBlock(self:from_int(x, format.size_t_size), D)
 end
 
 ------------------------------------------------------------------------
--- dumps a LUA_NUMBER (hard-coded as a double)
+-- dumps a LUA_NUMBER; can be an int or double depending on the VM.
 ------------------------------------------------------------------------
 function luaU:DumpNumber(x, D)
    if format.integral then
@@ -423,7 +435,7 @@
 end
 
 -- FIXME: ugly concat-base generation in [make_setS], bufferize properly! 
-function dump_string (proto)
+function M.dump_string (proto)
    local writer, buff = luaU:make_setS()
    luaU:dump (proto, writer, buff)
    return buff.data
@@ -431,11 +443,13 @@
 
 -- FIXME: [make_setS] sucks, perform synchronous file writing
 -- Now unused
-function dump_file (proto, filename)
+function M.dump_file (proto, filename)
    local writer, buff = luaU:make_setS()
    luaU:dump (proto, writer, buff)
    local file = io.open (filename, "wb")
    file:write (buff.data)
    io.close(file)
    if UNIX_SHARPBANG then os.execute ("chmod a+x "..filename) end
-end
\ No newline at end of file
+end
+
+return M
diff --git a/compiler/lopcodes.lua b/metalua/compiler/bytecode/lopcodes.lua
similarity index 95%
rename from compiler/lopcodes.lua
rename to metalua/compiler/bytecode/lopcodes.lua
index 15d97f7..66ac329 100644
--- a/compiler/lopcodes.lua
+++ b/metalua/compiler/bytecode/lopcodes.lua
@@ -18,8 +18,28 @@
 --
 -------------------------------------------------------------------------------
 
+----------------------------------------------------------------------
+--
+-- WARNING! You're entering a hackish area, proceed at your own risks!
+--
+-- This code results from the borrowing, then ruthless abuse, of
+-- Yueliang's implementation of Lua 5.0 compiler. I claim
+-- responsibility for all of the ugly, dirty stuff that you might spot
+-- in it.
+--
+-- Eventually, this code will be rewritten, either in Lua or more
+-- probably in C. Meanwhile, if you're interested into digging
+-- metalua's sources, this is not the best part to invest your time
+-- on.
+--
+-- End of warning.
+--
+----------------------------------------------------------------------
+
 --[[--------------------------------------------------------------------
 
+  $Id$
+
   lopcodes.lua
   Lua 5 virtual machine opcodes in Lua
   This file is part of Yueliang.
@@ -47,11 +67,9 @@
 --   endian form and field size and positions are hard-coded
 ----------------------------------------------------------------------]]
 
-module("bytecode", package.seeall)
-
 local function debugf() end
 
-luaP = { }
+local luaP = { }
 
 --[[
 ===========================================================================
@@ -438,3 +456,5 @@
   "0000102", -- OP_CLOSURE
   "0000101"  -- OP_VARARG
 }
+
+return luaP
\ No newline at end of file
diff --git a/metalua/compiler/globals.lua b/metalua/compiler/globals.lua
new file mode 100644
index 0000000..e10b6cb
--- /dev/null
+++ b/metalua/compiler/globals.lua
@@ -0,0 +1,85 @@
+--------------------------------------------------------------------------------
+-- Copyright (c) 2006-2013 Fabien Fleutot and others.
+--
+-- All rights reserved.
+--
+-- This program and the accompanying materials are made available
+-- under the terms of the Eclipse Public License v1.0 which
+-- accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- This program and the accompanying materials are also made available
+-- under the terms of the MIT public license which accompanies this
+-- distribution, and is available at http://www.lua.org/license.html
+--
+-- Contributors:
+--     Fabien Fleutot - API and implementation
+--
+--------------------------------------------------------------------------------
+
+--*-lua-*-----------------------------------------------------------------------
+-- Override Lua's default compilation functions, so that they support Metalua
+-- rather than only plain Lua
+--------------------------------------------------------------------------------
+
+local mlc = require 'metalua.compiler'
+
+local M = { }
+
+-- Original versions
+local original_lua_versions = {
+    load       = load,
+    loadfile   = loadfile,
+    loadstring = loadstring,
+    dofile     = dofile }
+
+local lua_loadstring = loadstring
+local lua_loadfile = loadfile
+
+function M.loadstring(str, name)
+   if type(str) ~= 'string' then error 'string expected' end
+   if str:match '^\027LuaQ' then return lua_loadstring(str) end
+   local n = str:match '^#![^\n]*\n()'
+   if n then str=str:sub(n, -1) end
+   -- FIXME: handle erroneous returns (return nil + error msg)
+   return mlc.new():src_to_function(str, name)
+end
+
+function M.loadfile(filename)
+   local f, err_msg = io.open(filename, 'rb')
+   if not f then return nil, err_msg end
+   local success, src = pcall( f.read, f, '*a')
+   pcall(f.close, f)
+   if success then return M.loadstring (src, '@'..filename)
+   else return nil, src end
+end
+
+function M.load(f, name)
+   while true do
+      local x = f()
+      if not x then break end
+      assert(type(x)=='string', "function passed to load() must return strings")
+      table.insert(acc, x)
+   end
+   return M.loadstring(table.concat(x))
+end
+
+function M.dostring(src)
+   local f, msg = M.loadstring(src)
+   if not f then error(msg) end
+   return f()
+end
+
+function M.dofile(name)
+   local f, msg = M.loadfile(name)
+   if not f then error(msg) end
+   return f()
+end
+
+-- Export replacement functions as globals
+for name, f in pairs(M) do _G[name] = f end
+
+-- To be done *after* exportation
+M.lua = original_lua_versions
+
+return M
\ No newline at end of file
diff --git a/metalua/compiler/indent.lua b/metalua/compiler/indent.lua
new file mode 100644
index 0000000..2b961de
--- /dev/null
+++ b/metalua/compiler/indent.lua
@@ -0,0 +1,255 @@
+--------------------------------------------------------------------------------
+-- Copyright (c) 2006-2013 Fabien Fleutot and others.
+--
+-- All rights reserved.
+--
+-- This program and the accompanying materials are made available
+-- under the terms of the Eclipse Public License v1.0 which
+-- accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- This program and the accompanying materials are also made available
+-- under the terms of the MIT public license which accompanies this
+-- distribution, and is available at http://www.lua.org/license.html
+--
+-- Contributors:
+--     Fabien Fleutot - API and implementation
+--
+--------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- Copyright (c) 2011, 2012 Sierra Wireless and others.
+-- All rights reserved. This program and the accompanying materials
+-- are made available under the terms of the Eclipse Public License v1.0
+-- which accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- Contributors:
+--     Sierra Wireless - initial API and implementation
+-------------------------------------------------------------------------------
+
+---
+-- Uses Metalua capabilities to indent code and provide source code offset
+-- semantic depth
+--
+-- @module luaformatter
+local M = {}
+local mlc = require 'metalua.compiler'
+local math = require 'math'
+local walk = require 'metalua.walk'
+
+---
+--  calculate all ident level
+-- @param Source code to analyze
+-- @return #table {linenumber = identationlevel}
+-- @usage local depth = format.indentLevel("local var")
+local function getindentlevel(source,indenttable)
+
+	local function getfirstline(node)
+		-- Regular node
+		local offsets = node[1].lineinfo
+		local first
+		local offset
+		-- Consider previous comments as part of current chunk
+		-- WARNING: This is NOT the default in Metalua
+		if offsets.first.comments then
+			first = offsets.first.comments.lineinfo.first.line
+			offset = offsets.first.comments.lineinfo.first.offset
+		else
+			first = offsets.first.line
+			offset = offsets.first.offset
+		end
+		return first, offset
+	end
+
+	local function getlastline(node)
+		-- Regular node
+		local offsets = node[#node].lineinfo
+		local last
+		-- Same for block end comments
+		if offsets.last.comments then
+			last = offsets.last.comments.lineinfo.last.line
+		else
+			last = offsets.last.line
+		end
+		return last
+	end
+
+	--
+	-- Define AST walker
+	--
+	local linetodepth = { 0 }
+	local walker = {
+		block = { },
+		expr  = { },
+		depth = 0,     -- Current depth while walking
+	}
+
+	function walker.block.down(node, parent,...)
+		--ignore empty node
+		if #node == 0 then
+			return end
+		-- get first line of the block
+		local startline,startoffset = getfirstline(node)
+		local endline = getlastline(node)
+		-- If the block doesn't start with a new line, don't indent the first line
+		if not source:sub(1,startoffset-1):find("[\r\n]%s*$") then
+			startline = startline + 1
+		end
+		for i=startline, endline do
+			linetodepth[i]=walker.depth
+		end
+		walker.depth = walker.depth + 1
+	end
+
+	function walker.block.up(node, ...)
+		if #node == 0 then
+			return end
+		walker.depth = walker.depth - 1
+	end
+
+	function walker.expr.down(node, parent, ...)
+		if indenttable and node.tag == 'Table' then
+			if #node == 0 then
+				return end
+			local startline,startoffset = getfirstline(node)
+			local endline = getlastline(node)
+			if source:sub(1,startoffset-1):find("[\r\n]%s*$") then
+				for i=startline, endline do
+					linetodepth[i]=walker.depth
+				end
+			else
+				for i=startline+1, endline do
+					linetodepth[i]=walker.depth
+				end
+			end
+			walker.depth = walker.depth + 1
+		elseif node.tag =='String' then
+			local firstline = node.lineinfo.first.line
+			local lastline = node.lineinfo.last.line
+			for i=firstline+1, lastline do
+				linetodepth[i]=false
+			end
+		end
+	end
+
+	function walker.expr.up(node, parent, ...)
+		if indenttable and node.tag == 'Table' then
+			if #node == 0 then
+				return end
+			walker.depth = walker.depth - 1
+		end
+	end
+
+	-- Walk through AST to build linetodepth
+	local ast = mlc.src_to_ast(source)
+	mlc.check_ast(ast)
+    walk.block(walker, ast)
+	return linetodepth
+end
+
+---
+-- Trim white spaces before and after given string
+--
+-- @usage local trimmedstr = trim('          foo')
+-- @param #string string to trim
+-- @return #string string trimmed
+local function trim(string)
+	local pattern = "^(%s*)(.*)"
+	local _, strip =  string:match(pattern)
+	if not strip then return string end
+	local restrip
+	_, restrip = strip:reverse():match(pattern)
+	return restrip and restrip:reverse() or strip
+end
+
+---
+-- Indent Lua Source Code.
+-- @function [parent=#luaformatter] indentCode
+-- @param source source code to format
+-- @param delimiter line delimiter to use, usually '\n' or '\r\n'
+-- @param indentTable boolean: whether table content must be indented
+-- @param tab either a string representing a number of indentation, or the number
+--   of spaces taken by a tab (often 8 or 4)
+-- @param indentationSize if given, an indentation of depth `n` shifts the code
+--   `indentationSize * n` chars to the right, with a mix of chars and spaces.
+--   `tab` must then be a number
+-- @return #string formatted code
+-- @usage indentCode('local var', '\n', true, '\t')
+-- @usage indentCode('local var', '\n', true, --[[tabulationSize]]4, --[[indentationSize]]2)
+function M.indentcode(source, delimiter, indenttable, tab, indentationSize)
+    checks('string', 'string', '?', 'number|string', '?numer')
+
+    -- function: generates a string which moves `depth` indentation levels from the left.
+	local tabulation
+    if indentationSize then
+        local tabSize = assert(tonumber(tab))
+		-- When tabulation size and indentation size are given,
+        -- tabulate with a mix of tabs and spaces
+		tabulation = function(depth)
+			local range      = depth * indentationSize
+			local tabCount   = math.floor(range / tabSize)
+			local spaceCount = range % tabSize
+			return string.rep('\t', tabCount) .. string.rep(' ', spaceCount)
+		end
+    else
+        if type(tab)=='number' then tab = string.rep(' ', tab) end
+		tabulation = function (depth) return tab :rep (depth) end
+	end
+
+	-- Delimiter position table: positions[x] is the offset of the first character
+    -- of the n-th delimiter in the source
+	local positions = { 1-#delimiter }
+	local a, b = nil, 0
+	repeat
+        a, b = source :find (delimiter, b+1, true)
+        if a then table.insert (positions, a) end
+    until not a
+
+	-- Don't try to indent a single line!
+	if #positions < 2 then return source end
+
+	-- calculate the line number -> indentation correspondence table
+	local linetodepth = getindentlevel(source,indenttable)
+
+	-- Concatenate string with right identation
+	local indented = { }
+	for  position=1, #positions do
+		-- Extract source code line
+		local offset = positions[position]
+		-- Get the interval between two positions
+		local rawline
+		if positions[position + 1] then
+			rawline = source:sub(offset + delimiterLength, positions[position + 1] -1)
+		else
+			-- From current prosition to end of line
+			rawline = source:sub(offset + delimiterLength)
+		end
+
+		-- Trim white spaces
+		local indentcount = linetodepth[position]
+		if not indentcount then
+			indented[#indented+1] = rawline
+		else
+			local line = trim(rawline)
+			-- Append right indentation
+			-- Indent only when there is code on the line
+			if line:len() > 0 then
+				-- Compute next real depth related offset
+				-- As is offset is pointing a white space before first statement of block,
+				-- We will work with parent node depth
+				indented[#indented+1] = tabulation( indentcount)
+				-- Append timmed source code
+				indented[#indented+1] = line
+			end
+		end
+		-- Append carriage return
+		-- While on last character append carriage return only if at end of original source
+		if position < #positions or source:sub(source:len()-delimiterLength, source:len()) == delimiter then
+			indented[#indented+1] = delimiter
+		end
+	end
+	return table.concat(indented)
+end
+
+return M
diff --git a/metalua/compiler/parser.lua b/metalua/compiler/parser.lua
new file mode 100644
index 0000000..3809c25
--- /dev/null
+++ b/metalua/compiler/parser.lua
@@ -0,0 +1,62 @@
+--------------------------------------------------------------------------------
+-- Copyright (c) 2006-2013 Fabien Fleutot and others.
+--
+-- All rights reserved.
+--
+-- This program and the accompanying materials are made available
+-- under the terms of the Eclipse Public License v1.0 which
+-- accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- This program and the accompanying materials are also made available
+-- under the terms of the MIT public license which accompanies this
+-- distribution, and is available at http://www.lua.org/license.html
+--
+-- Contributors:
+--     Fabien Fleutot - API and implementation
+--
+--------------------------------------------------------------------------------
+
+-- Export all public APIs from sub-modules, squashed into a flat spacename
+
+local MT = { __type='metalua.compiler.parser' }
+
+local function new()
+    local mod_names = { "common", "expr", "lexer", "meta", "misc", "stat", "table", "ext", "annot" }
+
+    for name, _ in pairs(package.loaded) do
+        local x = name :match '^metalua.compiler.parser.(.*)'
+        if x then
+            local found = false
+            for _, y in pairs(mod_names) do
+                if x==y then found=true; break end
+            end
+            --if found then print (">> found "..x)
+            --else print(">> not found: "..x) end
+        end
+    end
+
+    -- Unload parser modules
+    for _, mod_name in ipairs(mod_names) do
+        package.loaded["metalua.compiler.parser."..mod_name] = nil
+    end
+
+    local M = require 'metalua.compiler.parser.common'
+
+    for _, mod_name in ipairs(mod_names) do
+        -- TODO: expose sub-modules as nested tables? 
+        -- Not sure: it might be confusing, will clash with API names, e.g. for expr
+        local mod = require ("metalua.compiler.parser."..mod_name)
+        assert (type (mod) == 'table')
+        for api_name, val in pairs(mod) do
+            assert(not M[api_name])
+            M[api_name] = val
+        end
+    end
+
+    -- TODO: remove or make somehow optional the 'ext' module
+
+    return setmetatable(M, MT)
+end
+
+return { new = new }
diff --git a/metalua/compiler/parser/annot.lua b/metalua/compiler/parser/annot.lua
new file mode 100644
index 0000000..ab2fa59
--- /dev/null
+++ b/metalua/compiler/parser/annot.lua
@@ -0,0 +1,138 @@
+--------------------------------------------------------------------------------
+-- Copyright (c) 2006-2013 Fabien Fleutot and others.
+--
+-- All rights reserved.
+--
+-- This program and the accompanying materials are made available
+-- under the terms of the Eclipse Public License v1.0 which
+-- accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- This program and the accompanying materials are also made available
+-- under the terms of the MIT public license which accompanies this
+-- distribution, and is available at http://www.lua.org/license.html
+--
+-- Contributors:
+--     Fabien Fleutot - API and implementation
+--
+--------------------------------------------------------------------------------
+
+local gg    = require 'metalua.grammar.generator'
+local misc  = require 'metalua.compiler.parser.misc'
+local mlp   = require 'metalua.compiler.parser.common'
+local lexer = require 'metalua.compiler.parser.lexer'
+local M     = { }
+
+lexer.lexer :add '->'
+
+function M.tid(lx)
+    local w = lx :next()
+    local t = w.tag
+    if t=='Keyword' and w[1] :match '^[%a_][%w_]*$' or w.tag=='Id' then
+        return {tag='TId'; lineinfo=w.lineinfo; w[1]}
+    else return gg.parse_error (lx, 'tid expected') end
+end
+
+local function expr(...) return mlp.expr(...) end
+
+local function te(...) return M.te(...) end
+
+local field_types = { var='TVar'; const='TConst';
+                      currently='TCurrently'; field='TField' }
+
+function M.tf(lx)
+    local tk = lx:next()
+    local w = tk[1]
+    local tag = field_types[w]
+    if not tag then error ('Invalid field type '..w)
+    elseif tag=='TField' then return {tag='TField'} else
+        local te = M.te(lx)
+        return {tag=tag; te}
+    end
+end
+
+local tebar_content = gg.list{
+    name        = 'tebar content',
+    primary     = te,
+    separators  = { ",", ";" },
+    terminators = ")" }
+
+M.tebar = gg.multisequence{ 
+    name = 'annot.tebar',
+    --{ '*', builder = 'TDynbar' }, -- maybe not user-available
+    { '(', tebar_content, ')', 
+      builder = function(x) return x[1] end },
+    { te }
+}
+
+M.te = gg.multisequence{
+    name = 'annot.te',
+    { M.tid, builder=function(x) return x[1] end },
+    { '*', builder = 'TDyn' },
+    { "[",
+      gg.list{
+          primary = gg.sequence{
+              expr, "=", M.tf,
+              builder = 'TPair'
+          },
+          separators  = { ",", ";" },
+          terminators = { "]", "|" } },
+      gg.onkeyword{ "|", M.tf },
+      "]",
+      builder = function(x)
+                    local fields, other = unpack(x)
+                    return { tag='TTable', other or {tag='TField'}, fields }
+                end
+    }, -- "[ ... ]"
+    { '(', tebar_content, ')', '->', '(', tebar_content, ')',
+      builder = function(x)
+                    local p, r = unpack(x)
+                    return {tag='TFunction', p, r }
+                end } }
+
+
+M.ts = gg.multisequence{
+    name = 'annot.ts',
+    { 'return', tebar_content, builder='TReturn' },
+    { M.tid, builder = function(x)
+                           if x[1][1]=='pass' then return {tag='TPass'}
+                           else error "Bad statement type" end
+                       end } }
+
+
+-- TODO: add parsers for statements:
+-- #return tebar
+-- #alias = te
+-- #ell = tf
+
+M.stat_annot = gg.sequence{
+    gg.list{ primary=M.tid, separators='.' },
+    '=',
+    M.annot,
+    builder = 'Annot' }
+
+function M.opt(primary, a_type)
+    checks('table|function', 'string')
+    return gg.sequence{
+        primary,
+        gg.onkeyword{ "#", assert(M[a_type]) },
+        builder = function(x)
+                      local t, annot = unpack(x)
+                      return annot and { tag='Annot', t, annot } or t
+                  end }
+end
+
+-- split a list of "foo" and "`Annot{foo, annot}" into a list of "foo"
+-- and a list of "annot".
+-- No annot list is returned if none of the elements were annotated.
+function M.split(lst)
+    local x, a, some = { }, { }, false
+    for i, p in ipairs(lst) do
+        if p.tag=='Annot' then
+            some, x[i], a[i] = true, unpack(p)
+        else x[i] = p end
+    end
+    if some then return x, a else return lst end
+end
+
+return M
\ No newline at end of file
diff --git a/lib/verbose_require.lua b/metalua/compiler/parser/common.lua
similarity index 64%
copy from lib/verbose_require.lua
copy to metalua/compiler/parser/common.lua
index 0e07650..1d6290e 100644
--- a/lib/verbose_require.lua
+++ b/metalua/compiler/parser/common.lua
@@ -1,4 +1,4 @@
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 -- Copyright (c) 2006-2013 Fabien Fleutot and others.
 --
 -- All rights reserved.
@@ -15,17 +15,13 @@
 -- Contributors:
 --     Fabien Fleutot - API and implementation
 --
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 
+-- Shared common parser table. It will be filled by parser.init(),
+-- and every other module will be able to call its elements at runtime.
+--
+-- If the table was directly created in parser.init, a circular
+-- dependency would be created: parser.init depends on other modules to fill the table,
+-- so other modules can't simultaneously depend on it.
 
-do
-   local xrequire, n, ind = require, 0, "| "
-   function require (x)
-      print(ind:rep(n).."/ require: "..x)
-      n=n+1
-      local y = xrequire(x)
-      n=n-1
-      print(ind:rep(n).."\\_")
-      return y
-   end
-end
+return { }
\ No newline at end of file
diff --git a/metalua/compiler/parser/expr.lua b/metalua/compiler/parser/expr.lua
new file mode 100644
index 0000000..935d2c9
--- /dev/null
+++ b/metalua/compiler/parser/expr.lua
@@ -0,0 +1,208 @@
+-------------------------------------------------------------------------------
+-- Copyright (c) 2006-2013 Fabien Fleutot and others.
+--
+-- All rights reserved.
+--
+-- This program and the accompanying materials are made available
+-- under the terms of the Eclipse Public License v1.0 which
+-- accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- This program and the accompanying materials are also made available
+-- under the terms of the MIT public license which accompanies this
+-- distribution, and is available at http://www.lua.org/license.html
+--
+-- Contributors:
+--     Fabien Fleutot - API and implementation
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+--
+-- Exported API:
+-- * [mlp.expr()]
+-- * [mlp.expr_list()]
+-- * [mlp.func_val()]
+--
+-------------------------------------------------------------------------------
+
+local gg  = require 'metalua.grammar.generator'
+local mlp = require 'metalua.compiler.parser.common'
+local M   = { }
+
+local mlp_table = require 'metalua.compiler.parser.table'
+local mlp_meta  = require 'metalua.compiler.parser.meta'
+local mlp_misc  = require 'metalua.compiler.parser.misc'
+local annot     = require 'metalua.compiler.parser.annot'
+
+-- Delayed dependencies toward externally-defined parsers
+local function block (lx) return mlp.block (lx) end
+local function stat (lx) return mlp.stat (lx)  end
+
+-- For recursive definitions
+local function expr (lx) return M.expr (lx) end
+
+local id = mlp_misc.id
+
+
+--------------------------------------------------------------------------------
+-- Non-empty expression list. Actually, this isn't used here, but that's
+-- handy to give to users.
+--------------------------------------------------------------------------------
+M.expr_list = gg.list{ primary=expr, separators="," }
+
+--------------------------------------------------------------------------------
+-- Helpers for function applications / method applications
+--------------------------------------------------------------------------------
+M.func_args_content = gg.list{
+    name        = "function arguments",
+    primary     = expr,
+    separators  = ",",
+    terminators = ")" }
+
+-- Used to parse methods
+M.method_args = gg.multisequence{
+   name = "function argument(s)",
+   { "{",  mlp_table.content, "}" },
+   { "(",  M.func_args_content, ")", builder = unpack },
+   { "+{", mlp_meta.quote_content, "}" },
+   function(lx) local r = mlp.opt_string(lx); return r and {r} or { } end }
+
+--------------------------------------------------------------------------------
+-- [func_val] parses a function, from opening parameters parenthese to
+-- "end" keyword included. Used for anonymous functions as well as
+-- function declaration statements (both local and global).
+--
+-- It's wrapped in a [_func_val] eta expansion, so that when expr
+-- parser uses the latter, they will notice updates of [func_val]
+-- definitions.
+--------------------------------------------------------------------------------
+M.func_params_content = gg.list{ name="function parameters",
+   gg.multisequence{ { "...", builder = "Dots" }, annot.opt(id, 'te') },
+   separators  = ",", terminators = {")", "|"} }
+
+M.func_val = gg.sequence{ name="function body",
+   "(", M.func_params_content, ")", block, "end",
+   builder = function(x)
+       local params, body = unpack(x)
+       local annots, some = { }, false
+       for i, p in ipairs(params) do
+           if p.tag=='Annot' then
+               params[i], annots[i], some = p[1], p[2], true
+           else annots[i] = false end
+       end
+       if some then return { tag='Function', params, body, annots }
+       else  return { tag='Function', params, body } end
+   end }
+
+local func_val = function(lx) return M.func_val(lx) end
+
+--------------------------------------------------------------------------------
+-- Default parser for primary expressions
+--------------------------------------------------------------------------------
+function M.id_or_literal (lx)
+   local a = lx:next()
+   if a.tag~="Id" and a.tag~="String" and a.tag~="Number" then
+      local msg
+      if a.tag=='Eof' then
+         msg = "End of file reached when an expression was expected"
+      elseif a.tag=='Keyword' then
+         msg = "An expression was expected, and `"..a[1]..
+            "' can't start an expression"
+      else
+         msg = "Unexpected expr token " .. table.tostring (a, 'nohash')
+      end
+      return gg.parse_error (lx, msg)
+   end
+   return a
+end
+
+
+--------------------------------------------------------------------------------
+-- Builder generator for operators. Wouldn't be worth it if "|x|" notation
+-- were allowed, but then lua 5.1 wouldn't compile it 
+--------------------------------------------------------------------------------
+
+-- opf1 = |op| |_,a| `Op{ op, a }
+local function opf1 (op) return 
+   function (_,a) return { tag="Op", op, a } end end
+
+-- opf2 = |op| |a,_,b| `Op{ op, a, b }
+local function opf2 (op) return 
+   function (a,_,b) return { tag="Op", op, a, b } end end
+
+-- opf2r = |op| |a,_,b| `Op{ op, b, a } -- (args reversed)
+local function opf2r (op) return 
+   function (a,_,b) return { tag="Op", op, b, a } end end
+
+local function op_ne(a, _, b)
+    -- This version allows to remove the "ne" operator from the AST definition.
+    -- However, it doesn't always produce the exact same bytecode as Lua 5.1.
+    return { tag="Op", "not", 
+             { tag="Op", "eq", a, b, lineinfo= {
+                   first = a.lineinfo.first, last = b.lineinfo.last } } }
+end
+   
+
+--------------------------------------------------------------------------------
+--
+-- complete expression
+--
+--------------------------------------------------------------------------------
+
+-- FIXME: set line number. In [expr] transformers probably
+
+M.expr = gg.expr { name = "expression",
+
+   primary = gg.multisequence{ name="expr primary",
+      { "(", expr, ")",                     builder = "Paren" },
+      { "function", func_val,               builder = unpack },
+      { "-{", mlp_meta.splice_content, "}", builder = unpack },
+      { "+{", mlp_meta.quote_content, "}",  builder = unpack },
+      { "nil",                              builder = "Nil" },
+      { "true",                             builder = "True" },
+      { "false",                            builder = "False" },
+      { "...",                              builder = "Dots" },
+      mlp_table.table,
+      M.id_or_literal },
+
+   infix = { name="expr infix op",
+      { "+",  prec = 60, builder = opf2 "add"  },
+      { "-",  prec = 60, builder = opf2 "sub"  },
+      { "*",  prec = 70, builder = opf2 "mul"  },
+      { "/",  prec = 70, builder = opf2 "div"  },
+      { "%",  prec = 70, builder = opf2 "mod"  },
+      { "^",  prec = 90, builder = opf2 "pow",    assoc = "right" },
+      { "..", prec = 40, builder = opf2 "concat", assoc = "right" },
+      { "==", prec = 30, builder = opf2 "eq"  },
+      { "~=", prec = 30, builder = op_ne  },
+      { "<",  prec = 30, builder = opf2 "lt"  },
+      { "<=", prec = 30, builder = opf2 "le"  },
+      { ">",  prec = 30, builder = opf2r "lt"  },
+      { ">=", prec = 30, builder = opf2r "le"  },
+      { "and",prec = 20, builder = opf2 "and" },
+      { "or", prec = 10, builder = opf2 "or"  } },
+
+   prefix = { name="expr prefix op",
+      { "not", prec = 80, builder = opf1 "not" },
+      { "#",   prec = 80, builder = opf1 "len" },
+      { "-",   prec = 80, builder = opf1 "unm" } },
+
+   suffix = { name="expr suffix op",
+      { "[", expr, "]", builder = function (tab, idx)
+         return {tag="Index", tab, idx[1]} end},
+      { ".", id, builder = function (tab, field)
+         return {tag="Index", tab, mlp_misc.id2string(field[1])} end },
+      { "(", M.func_args_content, ")", builder = function(f, args)
+         return {tag="Call", f, unpack(args[1])} end },
+      { "{", mlp_table.content, "}", builder = function (f, arg)
+         return {tag="Call", f, arg[1]} end},
+      { ":", id, M.method_args, builder = function (obj, post)
+         local m_name, args = unpack(post)
+         return {tag="Invoke", obj, mlp_misc.id2string(m_name), unpack(args)} end},
+      { "+{", mlp_meta.quote_content, "}", builder = function (f, arg)
+         return {tag="Call", f,  arg[1] } end },
+      default = { name="opt_string_arg", parse = mlp_misc.opt_string, builder = function(f, arg) 
+         return {tag="Call", f, arg } end } } }
+
+return M
\ No newline at end of file
diff --git a/compiler/mlp_ext.lua b/metalua/compiler/parser/ext.lua
similarity index 65%
rename from compiler/mlp_ext.lua
rename to metalua/compiler/parser/ext.lua
index 021a72f..294fb8a 100644
--- a/compiler/mlp_ext.lua
+++ b/metalua/compiler/parser/ext.lua
@@ -23,57 +23,69 @@
 --
 --------------------------------------------------------------------------------
 
-module ("mlp", package.seeall)
+local gg        = require 'metalua.grammar.generator'
+local mlp       = require 'metalua.compiler.parser.common'
+local mlp_lexer = require 'metalua.compiler.parser.lexer'
+local mlp_expr  = require 'metalua.compiler.parser.expr'
+local mlp_stat  = require 'metalua.compiler.parser.stat'
+local mlp_misc  = require 'metalua.compiler.parser.misc'
+
+local expr = mlp_expr.expr
+
+local M = { }
 
 --------------------------------------------------------------------------------
 -- Alebraic Datatypes
 --------------------------------------------------------------------------------
 local function adt (lx)
-   local tagval = id (lx) [1]
+   local node = mlp_misc.id (lx)
+   local tagval = node[1]
    local tagkey = {tag="Pair", {tag="String", "tag"}, {tag="String", tagval} }
    if lx:peek().tag == "String" or lx:peek().tag == "Number" then
       return { tag="Table", tagkey, lx:next() }
    elseif lx:is_keyword (lx:peek(), "{") then
-      local x = table (lx)
-      _G.table.insert (x, 1, tagkey)
+      local x = mlp.table (lx)
+      table.insert (x, 1, tagkey)
       return x
    else return { tag="Table", tagkey } end
 end
 
-expr:add{ "`", adt, builder = fget(1) }
+M.adt = gg.sequence{ "`", adt, builder = unpack }
+
+expr.primary :add(M.adt)
 
 --------------------------------------------------------------------------------
 -- Anonymous lambda
 --------------------------------------------------------------------------------
-local lambda_expr = gg.sequence{ 
-   "|", func_params_content, "|", expr,
-   builder= function (x) 
+M.lambda_expr = gg.sequence{
+   "|", mlp_expr.func_params_content, "|", expr,
+   builder = function (x)
       local li = x[2].lineinfo
-      return { tag="Function", x[1], 
+      return { tag="Function", x[1],
                { {tag="Return", x[2], lineinfo=li }, lineinfo=li } }
    end }
 
 -- In an earlier version, lambda_expr took an expr_list rather than an expr
 -- after the 2nd bar. However, it happened to be much more of a burden than an
--- help, So finally I disabled it. If you want to return several results, 
+-- help, So finally I disabled it. If you want to return several results,
 -- use the long syntax.
 --------------------------------------------------------------------------------
--- local lambda_expr = gg.sequence{ 
+-- local lambda_expr = gg.sequence{
 --    "|", func_params_content, "|", expr_list,
---    builder= function (x) 
+--    builder= function (x)
 --       return {tag="Function", x[1], { {tag="Return", unpack(x[2]) } } } end }
 
-expr:add (lambda_expr)
+expr.primary :add (M.lambda_expr)
 
 --------------------------------------------------------------------------------
 -- Allows to write "a `f` b" instead of "f(a, b)". Taken from Haskell.
 -- This is not part of Lua 5.1 syntax, so it's added to the expression
 -- afterwards, so that it's easier to disable.
 --------------------------------------------------------------------------------
-local function expr_in_backquotes (lx) return expr(lx, 35) end
+function M.expr_in_backquotes (lx) return expr(lx, 35) end
 
-expr.infix:add{ name = "infix function", 
-   "`", expr_in_backquotes, "`", prec = 35, assoc="left", 
+expr.infix :add{ name = "infix function",
+   "`", M.expr_in_backquotes, "`", prec = 35, assoc="left",
    builder = function(a, op, b) return {tag="Call", op[1], a, b} end }
 
 
@@ -81,28 +93,34 @@
 -- table.override assignment
 --------------------------------------------------------------------------------
 
-mlp.lexer:add "<-"
-stat.assignments["<-"] = function (a, b)
-   assert( #a==1 and #b==1, "No multi-args for '<-'")                         
+mlp_lexer.lexer:add "<-"
+mlp_stat.stat.assignments["<-"] = function (a, b)
+   assert( #a==1 and #b==1, "No multi-args for '<-'")
    return { tag="Call", { tag="Index", { tag="Id", "table" },
                                        { tag="String", "override" } },
-                        a[1], b[1]} 
+                        a[1], b[1]}
 end
 
 --------------------------------------------------------------------------------
 -- C-style op+assignments
+-- TODO: no protection against side-effects in LHS vars.
 --------------------------------------------------------------------------------
-local function op_assign(kw, op) 
+local function op_assign(kw, op)
    local function rhs(a, b)
-      return { tag="Op", op, a, b } 
+      return { tag="Op", op, a, b }
    end
-   local function f(a,b) 
-      return { tag="Set", a, _G.table.imap(rhs, a, b) }
+   local function f(a,b)
+       if #a ~= #b then return gg.parse_error "assymetric operator+assignment" end
+       local right = { }
+       local r = { tag="Set", a, right }
+       for i=1, #a do right[i] = { tag="Op", op, a[i], b[i] } end
+       return r
    end
    mlp.lexer:add (kw)
    mlp.stat.assignments[kw] = f
 end
 
-_G.table.iforeach (op_assign, 
-                {"+=", "-=", "*=", "/="},
-                {"add", "sub", "mul", "div"})
\ No newline at end of file
+local ops = { add='+='; sub='-='; mul='*='; div='/=' }
+for ast_op_name, keyword in pairs(ops) do op_assign(keyword, ast_op_name) end
+
+return M
\ No newline at end of file
diff --git a/compiler/mlp_lexer.lua b/metalua/compiler/parser/lexer.lua
similarity index 70%
rename from compiler/mlp_lexer.lua
rename to metalua/compiler/parser/lexer.lua
index 70ad94c..7f93f8a 100644
--- a/compiler/mlp_lexer.lua
+++ b/metalua/compiler/parser/lexer.lua
@@ -1,4 +1,4 @@
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 -- Copyright (c) 2006-2013 Fabien Fleutot and others.
 --
 -- All rights reserved.
@@ -15,20 +15,23 @@
 -- Contributors:
 --     Fabien Fleutot - API and implementation
 --
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 
 ----------------------------------------------------------------------
+-- (Meta)lua-specific lexer, derived from the generic lexer.
+----------------------------------------------------------------------
 --
--- Summary: Source file lexer. ~~Currently only works on strings.
--- Some API refactoring is needed.
+-- Copyright (c) 2006-2012, Fabien Fleutot <metalua@gmail.com>.
+--
+-- This software is released under the MIT Licence, see licence.txt
+-- for details.
 --
 ----------------------------------------------------------------------
 
-module ("mlp", package.seeall)
+local generic_lexer = require 'metalua.grammar.lexer'
+local M = { }
 
-require "lexer"
-
-local mlp_lexer = lexer.lexer:clone()
+M.lexer = generic_lexer.lexer :clone()
 
 local keywords = {
     "and", "break", "do", "else", "elseif",
@@ -41,6 +44,6 @@
     "::", -- Lua5,2
     "+{", "-{" }
  
-for w in values(keywords) do mlp_lexer:add(w) end
+for _, w in ipairs(keywords) do M.lexer :add (w) end
 
-_M.lexer = mlp_lexer
+return M
diff --git a/compiler/mlp_meta.lua b/metalua/compiler/parser/meta.lua
similarity index 74%
rename from compiler/mlp_meta.lua
rename to metalua/compiler/parser/meta.lua
index 578dfd5..396df85 100644
--- a/compiler/mlp_meta.lua
+++ b/metalua/compiler/parser/meta.lua
@@ -17,11 +17,11 @@
 --
 -------------------------------------------------------------------------------
 
-----------------------------------------------------------------------
+-------------------------------------------------------------------------------
 --
 -- Summary: Meta-operations: AST quasi-quoting and splicing
 --
-----------------------------------------------------------------------
+-------------------------------------------------------------------------------
 
 --------------------------------------------------------------------------------
 --
@@ -31,7 +31,9 @@
 --
 --------------------------------------------------------------------------------
 
-module ("mlp", package.seeall)
+local gg       = require 'metalua.grammar.generator'
+local mlp      = require 'metalua.compiler.parser.common'
+local M        = { }
 
 --------------------------------------------------------------------------------
 -- External splicing: compile an AST into a chunk, load and evaluate
@@ -39,37 +41,41 @@
 -- an AST).
 --------------------------------------------------------------------------------
 
-function splice (ast)
-   local f = mlc.ast_to_function(ast, '=splice')
-   local result=f()
-   return result
+function M.splice (ast)
+    -- TODO: should there be one mlc per splice, or per parser instance?
+    local mlc = require 'metalua.compiler'.new()
+    local f = mlc :ast_to_function(ast, '=splice')
+    local result=f(mlp)
+    return result
 end
 
 --------------------------------------------------------------------------------
 -- Going from an AST to an AST representing that AST
 -- the only key being lifted in this version is ["tag"]
 --------------------------------------------------------------------------------
-function quote (t)
-   --print("QUOTING:", _G.table.tostring(t, 60))
+function M.quote (t)
+   --print("QUOTING:", table.tostring(t, 60,'nohash'))
    local cases = { }
    function cases.table (t)
       local mt = { tag = "Table" }
-      --_G.table.insert (mt, { tag = "Pair", quote "quote", { tag = "True" } })
+      --table.insert (mt, { tag = "Pair", quote "quote", { tag = "True" } })
       if t.tag == "Splice" then
          assert (#t==1, "Invalid splice")
          local sp = t[1]
          return sp
       elseif t.tag then
-         _G.table.insert (mt, { tag = "Pair", quote "tag", quote (t.tag) })
+         table.insert (mt, { tag="Pair", M.quote "tag", M.quote(t.tag) })
       end
       for _, v in ipairs (t) do
-         _G.table.insert (mt, quote(v))
+         table.insert (mt, M.quote(v))
       end
       return mt
    end
    function cases.number (t) return { tag = "Number", t, quote = true } end
    function cases.string (t) return { tag = "String", t, quote = true } end
-   return cases [ type (t) ] (t)
+   function cases.boolean (t) return { tag = t and "True" or "False", t, quote = true } end
+   local f = cases [type(t)]
+   if f then return f(t) else error ("Cannot quote an AST containing "..tostring(t)) end
 end
 
 --------------------------------------------------------------------------------
@@ -78,21 +84,22 @@
 -- parsing data inside a quasiquote), [-{foo}] is replaced by
 -- [`Splice{foo}], which will be unpacked by [quote()].
 --------------------------------------------------------------------------------
-in_a_quote = false
+M.in_a_quote = false
 
 --------------------------------------------------------------------------------
 -- Parse the inside of a "-{ ... }"
 --------------------------------------------------------------------------------
-function splice_content (lx)
+function M.splice_content (lx)
    local parser_name = "expr"
    if lx:is_keyword (lx:peek(2), ":") then
       local a = lx:next()
       lx:next() -- skip ":"
       assert (a.tag=="Id", "Invalid splice parser name")
       parser_name = a[1]
-   end
-   local ast = mlp[parser_name](lx)
-   if in_a_quote then
+  end
+  local parser = require 'metalua.compiler.parser'.new()
+  local ast = parser [parser_name](lx)
+   if M.in_a_quote then
       --printf("SPLICE_IN_QUOTE:\n%s", _G.table.tostring(ast, "nohash", 60))
       return { tag="Splice", ast }
    else
@@ -101,28 +108,29 @@
       elseif parser_name ~= "block" then
          error ("splice content must be an expr, stat or block") end
       --printf("EXEC THIS SPLICE:\n%s", _G.table.tostring(ast, "nohash", 60))
-      return splice (ast)
+      return M.splice (ast)
    end
 end
 
 --------------------------------------------------------------------------------
 -- Parse the inside of a "+{ ... }"
 --------------------------------------------------------------------------------
-function quote_content (lx)
-   local parser 
+function M.quote_content (lx)
+   local parser
    if lx:is_keyword (lx:peek(2), ":") then -- +{parser: content }
-      parser = mlp[id(lx)[1]]
+      parser = mlp[mlp.id(lx)[1]]
       lx:next()
    else -- +{ content }
       parser = mlp.expr
    end
 
-   local prev_iq = in_a_quote
-   in_a_quote = true
+   local prev_iq = M.in_a_quote
+   M.in_a_quote = true
    --print("IN_A_QUOTE")
    local content = parser (lx)
-   local q_content = quote (content)
-   in_a_quote = prev_iq
+   local q_content = M.quote (content)
+   M.in_a_quote = prev_iq
    return q_content
 end
 
+return M
diff --git a/compiler/mlp_misc.lua b/metalua/compiler/parser/misc.lua
similarity index 72%
rename from compiler/mlp_misc.lua
rename to metalua/compiler/parser/misc.lua
index dcde657..04c4f98 100644
--- a/compiler/mlp_misc.lua
+++ b/metalua/compiler/parser/misc.lua
@@ -17,11 +17,11 @@
 --
 -------------------------------------------------------------------------------
 
----------------------------------------------------------------------
+-------------------------------------------------------------------------------
 --
 -- Summary: metalua parser, miscellaneous utility functions.
 --
-----------------------------------------------------------------------
+-------------------------------------------------------------------------------
 
 --------------------------------------------------------------------------------
 --
@@ -30,17 +30,19 @@
 -- * [mlp.id()]
 -- * [mlp.opt_id()]
 -- * [mlp.id_list()]
--- * [mlp.gensym()]
 -- * [mlp.string()]
 -- * [mlp.opt_string()]
 -- * [mlp.id2string()]
 --
 --------------------------------------------------------------------------------
 
---require "gg"
---require "mll"
+local gg       = require 'metalua.grammar.generator'
+local mlp      = require 'metalua.compiler.parser.common'
+local mlp_meta = require 'metalua.compiler.parser.meta'
+local M        = { }
 
-module ("mlp", package.seeall)
+
+local splice = gg.sequence{ "-{", mlp_meta.splice_content, "}", builder=unpack }
 
 --------------------------------------------------------------------------------
 -- returns a function that takes the [n]th element of a table.
@@ -53,7 +55,7 @@
 -- a lightweight syntax.
 --------------------------------------------------------------------------------
 
-function fget (n, tag) 
+function M.fget (n, tag) 
    assert (type (n) == "number")
    if tag then
       assert (type (tag) == "string")
@@ -70,14 +72,14 @@
 -- Try to read an identifier (possibly as a splice), or return [false] if no
 -- id is found.
 --------------------------------------------------------------------------------
-function opt_id (lx)
+function M.opt_id (lx)
    local a = lx:peek();
    if lx:is_keyword (a, "-{") then
-      local v = gg.sequence{ "-{", splice_content, "}" } (lx) [1]
-      if v.tag ~= "Id" and v.tag ~= "Splice" then
-         return gg.parse_error(lx, "Bad id splice")
-      end
-      return v
+       local v = splice(lx)
+       if v.tag ~= "Id" and v.tag ~= "Splice" then
+           return gg.parse_error(lx, "Bad id splice")
+       end
+       return v
    elseif a.tag == "Id" then return lx:next()
    else return false end
 end
@@ -85,38 +87,24 @@
 --------------------------------------------------------------------------------
 -- Mandatory reading of an id: causes an error if it can't read one.
 --------------------------------------------------------------------------------
-function id (lx)
-   return opt_id (lx) or gg.parse_error(lx,"Identifier expected")
+function M.id (lx)
+   return M.opt_id (lx) or gg.parse_error(lx,"Identifier expected")
 end
 
 --------------------------------------------------------------------------------
 -- Common helper function
 --------------------------------------------------------------------------------
-id_list = gg.list { primary = mlp.id, separators = "," }
-
---------------------------------------------------------------------------------
--- Symbol generator: [gensym()] returns a guaranteed-to-be-unique identifier.
--- The main purpose is to avoid variable capture in macros.
---
--- If a string is passed as an argument, theis string will be part of the
--- id name (helpful for macro debugging)
---------------------------------------------------------------------------------
-local gensymidx = 0
-
-function gensym (arg)
-   gensymidx = gensymidx + 1
-   return { tag="Id", _G.string.format(".%i.%s", gensymidx, arg or "")}
-end
+M.id_list = gg.list { primary = M.id, separators = "," }
 
 --------------------------------------------------------------------------------
 -- Converts an identifier into a string. Hopefully one day it'll handle
 -- splices gracefully, but that proves quite tricky.
 --------------------------------------------------------------------------------
-function id2string (id)
+function M.id2string (id)
    --print("id2string:", disp.ast(id))
    if id.tag == "Id" then id.tag = "String"; return id
    elseif id.tag == "Splice" then
-      assert (in_a_quote, "can't do id2string on an outermost splice")
+      assert (mlp_meta.in_a_quote, "can't do id2string on an outermost splice")
       error ("id2string on splice not implemented")
       -- Evaluating id[1] will produce `Id{ xxx },
       -- and we want it to produce `String{ xxx }
@@ -126,17 +114,17 @@
       return {tag="String",  {tag="Index", {tag="Splice", id[1] }, 
                                            {tag="Number", 1 } } }
    elseif id.tag == 'Error' then return id
-   else error ("Identifier expected: ".._G.table.tostring(id, 'nohash')) end
+   else error ("Identifier expected: "..table.tostring(id, 'nohash')) end
 end
 
 --------------------------------------------------------------------------------
 -- Read a string, possibly spliced, or return an error if it can't
 --------------------------------------------------------------------------------
-function string (lx)
+function M.string (lx)
    local a = lx:peek()
    if lx:is_keyword (a, "-{") then
-      local v = gg.sequence{ "-{", splice_content, "}" } (lx) [1]
-      if v.tag ~= "" and v.tag ~= "Splice" then
+      local v = splice(lx)
+      if v.tag ~= "String" and v.tag ~= "Splice" then
          return gg.parse_error(lx,"Bad string splice")
       end
       return v
@@ -147,36 +135,39 @@
 --------------------------------------------------------------------------------
 -- Try to read a string, or return false if it can't. No splice allowed.
 --------------------------------------------------------------------------------
-function opt_string (lx)
+function M.opt_string (lx)
    return lx:peek().tag == "String" and lx:next()
 end
    
 --------------------------------------------------------------------------------
 -- Chunk reader: block + Eof
 --------------------------------------------------------------------------------
-function skip_initial_sharp_comment (lx)
+function M.skip_initial_sharp_comment (lx)
    -- Dirty hack: I'm happily fondling lexer's private parts
    -- FIXME: redundant with lexer:newstream()
    lx :sync()
    local i = lx.src:match ("^#.-\n()", lx.i)
-   if i then lx.i, lx.column_offset, lx.line = i, i, lx.line+1 end
+   if i then
+      lx.i = i
+      lx.column_offset = i
+      lx.line = lx.line and lx.line + 1 or 1
+   end
 end
 
-local function _chunk (lx)
-   if PRINT_PARSED_STAT then print "HI"; printf("about to chunk on %s", tostring(lx:peek())) end
+local function chunk (lx)
    if lx:peek().tag == 'Eof' then
-       if PRINT_PARSED_STAT then print "at EOF" end
        return { } -- handle empty files
    else 
-      skip_initial_sharp_comment (lx)
-      if PRINT_PARSED_STAT then printf("after skipping, at %s", tostring(lx:peek())) end
-      local chunk = block (lx)
+      M.skip_initial_sharp_comment (lx)
+      local chunk = mlp.block (lx)
       if lx:peek().tag ~= "Eof" then 
-          _G.table.insert(chunk, gg.parse_error(lx, "End-of-file expected"))
+          table.insert(chunk, gg.parse_error(lx, "End-of-file expected"))
       end
       return chunk
    end
 end
 
 -- chunk is wrapped in a sequence so that it has a "transformer" field.
-chunk = gg.sequence { _chunk, builder = unpack }
+M.chunk = gg.sequence { chunk, builder = unpack }
+
+return M
\ No newline at end of file
diff --git a/compiler/mlp_stat.lua b/metalua/compiler/parser/stat.lua
similarity index 66%
rename from compiler/mlp_stat.lua
rename to metalua/compiler/parser/stat.lua
index c5aa8c1..fc9a064 100644
--- a/compiler/mlp_stat.lua
+++ b/metalua/compiler/parser/stat.lua
@@ -17,21 +17,28 @@
 --
 -------------------------------------------------------------------------------
 
-----------------------------------------------------------------------
+-------------------------------------------------------------------------------
 --
--- Summary: metalua parser, statement/block parser. This is part of
---   the definition of module [mlp].
+-- Summary: metalua parser, statement/block parser. This is part of the
+-- definition of module [mlp].
 --
-----------------------------------------------------------------------
+-------------------------------------------------------------------------------
 
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
 --
 -- Exports API:
 -- * [mlp.stat()]
 -- * [mlp.block()]
 -- * [mlp.for_header()]
 --
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
+
+local mlp      = require 'metalua.compiler.parser.common'
+local mlp_misc = require 'metalua.compiler.parser.misc'
+local mlp_meta = require 'metalua.compiler.parser.meta'
+local annot    = require 'metalua.compiler.parser.annot'
+local gg       = require 'metalua.grammar.generator'
+local M        = { }
 
 --------------------------------------------------------------------------------
 -- eta-expansions to break circular dependency
@@ -40,31 +47,29 @@
 local func_val  = function (lx) return mlp.func_val (lx) end
 local expr_list = function (lx) return mlp.expr_list(lx) end
 
-module ("mlp", package.seeall)
-
 --------------------------------------------------------------------------------
 -- List of all keywords that indicate the end of a statement block. Users are
 -- likely to extend this list when designing extensions.
 --------------------------------------------------------------------------------
 
 
-local block_terminators = { "else", "elseif", "end", "until", ")", "}", "]" }
+M.block_terminators = { "else", "elseif", "end", "until", ")", "}", "]" }
 
 -- FIXME: this must be handled from within GG!!!
-function block_terminators:add(x) 
-   if type (x) == "table" then for _, y in ipairs(x) do self:add (y) end
-   else _G.table.insert (self, x) end
+function M.block_terminators :add(x) 
+   if type (x) == "table" then for _, y in ipairs(x) do self :add (y) end
+   else table.insert (self, x) end
 end
 
 --------------------------------------------------------------------------------
 -- list of statements, possibly followed by semicolons
 --------------------------------------------------------------------------------
-block = gg.list {
+M.block = gg.list {
    name        = "statements block",
-   terminators = block_terminators,
+   terminators = M.block_terminators,
    primary     = function (lx)
       -- FIXME use gg.optkeyword()
-      local x = stat (lx)
+      local x = mlp.stat (lx)
       if lx:is_keyword (lx:peek(), ";") then lx:next() end
       return x
    end }
@@ -73,7 +78,7 @@
 -- Helper function for "return <expr_list>" parsing.
 -- Called when parsing return statements.
 -- The specific test for initial ";" is because it's not a block terminator,
--- so without itgg.list would choke on "return ;" statements.
+-- so without it gg.list would choke on "return ;" statements.
 -- We don't make a modified copy of block_terminators because this list
 -- is sometimes modified at runtime, and the return parser would get out of
 -- sync if it was relying on a copy.
@@ -81,20 +86,27 @@
 local return_expr_list_parser = gg.multisequence{
    { ";" , builder = function() return { } end }, 
    default = gg.list { 
-      expr, separators = ",", terminators = block_terminators } }
+      expr, separators = ",", terminators = M.block_terminators } }
+
+
+local for_vars_list = gg.list{
+    name        = "for variables list",
+    primary     = mlp_misc.id,
+    separators  = ",", 
+    terminators = "in" }
 
 --------------------------------------------------------------------------------
 -- for header, between [for] and [do] (exclusive).
 -- Return the `Forxxx{...} AST, without the body element (the last one).
 --------------------------------------------------------------------------------
-function for_header (lx)
+function M.for_header (lx)
     local vars = mlp.id_list(lx)
     if lx :is_keyword (lx:peek(), "=") then       
         if #vars ~= 1 then 
             return gg.parse_error (lx, "numeric for only accepts one variable")
         end
         lx:next() -- skip "="
-        local exprs = expr_list (lx)
+        local exprs = mlp.expr_list (lx)
         if #exprs < 2 or #exprs > 3 then
             return gg.parse_error (lx, "numeric for requires 2 or 3 boundaries")
         end
@@ -103,7 +115,7 @@
         if not lx :is_keyword (lx :next(), "in") then
             return gg.parse_error (lx, '"=" or "in" expected in for loop')
         end
-        local exprs = expr_list (lx)
+        local exprs = mlp.expr_list (lx)
         return { tag="Forin", vars, exprs }
     end
 end
@@ -113,16 +125,16 @@
 --------------------------------------------------------------------------------
 local function fn_builder (list)
    local r = list[1]
-   for i = 2, #list do r = { tag="Index", r, id2string(list[i]) } end
+   for i = 2, #list do r = { tag="Index", r, mlp.id2string(list[i]) } end
    return r
 end
-local func_name = gg.list{ id, separators = ".", builder = fn_builder }
+local func_name = gg.list{ mlp_misc.id, separators = ".", builder = fn_builder }
 
 --------------------------------------------------------------------------------
 -- Function def parser helper: ( : id )?
 --------------------------------------------------------------------------------
-local method_name = gg.onkeyword{ name = "method invocation", ":", id, 
-   transformers = { function(x) return x and x.tag=='Id' and id2string(x) end } }
+local method_name = gg.onkeyword{ name = "method invocation", ":", mlp_misc.id, 
+   transformers = { function(x) return x and x.tag=='Id' and mlp_misc.id2string(x) end } }
 
 --------------------------------------------------------------------------------
 -- Function def builder
@@ -138,7 +150,7 @@
       name = { tag="Index", name, method, lineinfo = {
          first = name.lineinfo.first,
          last  = method.lineinfo.last } }
-      _G.table.insert (func[1], 1, {tag="Id", "self"}) 
+      table.insert (func[1], 1, {tag="Id", "self"}) 
    end
    local r = { tag="Set", {name}, {func} } 
    r[1].lineinfo = name.lineinfo
@@ -152,13 +164,13 @@
 --------------------------------------------------------------------------------
 local function if_builder (x)
    local cb_pairs, else_block, r = x[1], x[2], {tag="If"}
-   if cb_pairs.tag=='Error' then return cb_pairs end -- propagate errors 
+   if cb_pairs.tag=='Error' then return cb_pairs end -- propagate errors
    local n_pairs = #cb_pairs
    for i = 1, n_pairs do
        local cond, block = unpack(cb_pairs[i])
        r[2*i-1], r[2*i] = cond, block
    end
-   if else_block then r[#r+1] = else_block end
+   if else_block then table.insert(r, #r+1, else_block) end
    return r
 end 
 
@@ -166,32 +178,48 @@
 -- produce a list of (expr,block) pairs
 --------------------------------------------------------------------------------
 local elseifs_parser = gg.list {
-   gg.sequence { expr, "then", block, name='if/then block' },
+   gg.sequence { expr, "then", M.block , name='elseif parser' },
    separators  = "elseif",
-   terminators = { "else", "end" } }
+   terminators = { "else", "end" }
+}
+
+local annot_expr = gg.sequence {
+    expr,
+    gg.onkeyword{ "#", annot.tf },
+    builder = function(x) 
+                  local e, a = unpack(x)
+                  if a then return { tag='Annot', e, a }
+                  else return e end
+              end }
+
+local annot_expr_list = gg.list {
+    primary = annot.opt(expr, 'tf'), separators = ',' }
 
 --------------------------------------------------------------------------------
 -- assignments and calls: statements that don't start with a keyword
 --------------------------------------------------------------------------------
 local function assign_or_call_stat_parser (lx)
-   local e = expr_list (lx)
+   local e = annot_expr_list (lx)
    local a = lx:is_keyword(lx:peek())
-   local op = a and stat.assignments[a]
+   local op = a and mlp.stat.assignments[a]
+   -- TODO: refactor annotations
    if op then
       --FIXME: check that [e] is a LHS
-      lx:next()
-      local v = expr_list (lx)
-      if type(op)=="string" then return { tag=op, e, v }
+      lx :next()
+      local annots
+      e, annots = annot.split(e)
+      local v = mlp.expr_list (lx)
+      if type(op)=="string" then return { tag=op, e, v, annots }
       else return op (e, v) end
-   else 
+   else
       assert (#e > 0)
-      if #e > 1 then 
-         return gg.parse_error (lx, 
+      if #e > 1 then
+         return gg.parse_error (lx,
             "comma is not a valid statement separator; statement can be "..
             "separated by semicolons, or not separated at all") end
       if e[1].tag ~= "Call" and e[1].tag ~= "Invoke" then
          local typename
-         if e[1].tag == 'Id' then 
+         if e[1].tag == 'Id' then
             typename = '("'..e[1][1]..'") is an identifier'
          elseif e[1].tag == 'Op' then 
             typename = "is an arithmetic operation"
@@ -205,40 +233,51 @@
    end
 end
 
-local_stat_parser = gg.multisequence{
-   -- local function <name> <func_val>
-   { "function", id, func_val, builder = 
+M.local_stat_parser = gg.multisequence{
+    -- local function <name> <func_val>
+    { "function", mlp_misc.id, func_val, builder = 
       function(x) 
-         local vars = { x[1], lineinfo = x[1].lineinfo }
-         local vals = { x[2], lineinfo = x[2].lineinfo }
-         return { tag="Localrec", vars, vals } 
+          local vars = { x[1], lineinfo = x[1].lineinfo }
+          local vals = { x[2], lineinfo = x[2].lineinfo }
+          return { tag="Localrec", vars, vals } 
       end },
-   -- local <id_list> ( = <expr_list> )?
-   default = gg.sequence{ id_list, gg.onkeyword{ "=", expr_list },
-      builder = function(x) return {tag="Local", x[1], x[2] or { } } end } }
+    -- local <id_list> ( = <expr_list> )?
+    default = gg.sequence{ 
+        gg.list{
+            primary = annot.opt(mlp_misc.id, 'tf'),
+            separators = ',' },
+        gg.onkeyword{ "=", expr_list },
+        builder = function(x)
+            local annotated_left, right = unpack(x)
+            local left, annotations = annot.split(annotated_left)
+            return {tag="Local", left, right or { }, annotations }
+        end } }
 
 --------------------------------------------------------------------------------
 -- statement
 --------------------------------------------------------------------------------
-stat = gg.multisequence { 
-   name="statement",
-   { "do", block, "end", builder = 
+M.stat = gg.multisequence { 
+   name = "statement",
+   { "do", M.block, "end", builder = 
       function (x) return { tag="Do", unpack (x[1]) } end },
-   { "for", for_header, "do", block, "end", builder = 
+   { "for", M.for_header, "do", M.block, "end", builder = 
       function (x) x[1][#x[1]+1] = x[2]; return x[1] end },
    { "function", func_name, method_name, func_val, builder=funcdef_builder },
-   { "while", expr, "do", block, "end", builder = "While" },
-   { "repeat", block, "until", expr, builder = "Repeat" },
-   { "local", local_stat_parser, builder = fget (1) },
-   { "return", return_expr_list_parser, builder = fget (1, "Return") },
+   { "while", expr, "do", M.block, "end", builder = "While" },
+   { "repeat", M.block, "until", expr, builder = "Repeat" },
+   { "local", M.local_stat_parser, builder = unpack },
+   { "return", return_expr_list_parser, builder = 
+     function(x) x[1].tag='Return'; return x[1] end },
    { "break", builder = function() return { tag="Break" } end },
-   { "-{", splice_content, "}", builder = fget(1) },
-   { "if", gg.nonempty(elseifs_parser), gg.onkeyword{ "else", block }, "end", 
+   { "-{", mlp_meta.splice_content, "}", builder = unpack },
+   { "if", gg.nonempty(elseifs_parser), gg.onkeyword{ "else", M.block }, "end",
      builder = if_builder },
    default = assign_or_call_stat_parser }
 
-stat.assignments = {
-   ["="] = "Set" }
+M.stat.assignments = {
+   ["="] = "Set"
+}
 
-stat.dontfail = true
-function stat.assignments:add(k, v) self[k] = v end
+function M.stat.assignments:add(k, v) self[k] = v end
+
+return M
\ No newline at end of file
diff --git a/compiler/mlp_table.lua b/metalua/compiler/parser/table.lua
similarity index 62%
rename from compiler/mlp_table.lua
rename to metalua/compiler/parser/table.lua
index cfc26a2..ccffb2e 100644
--- a/compiler/mlp_table.lua
+++ b/metalua/compiler/parser/table.lua
@@ -1,4 +1,4 @@
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 -- Copyright (c) 2006-2013 Fabien Fleutot and others.
 --
 -- All rights reserved.
@@ -15,53 +15,54 @@
 -- Contributors:
 --     Fabien Fleutot - API and implementation
 --
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 
-----------------------------------------------------------------------
+--------------------------------------------------------------------------------
 --
--- Summary: metalua parser, table constructor parser. This is part
---   of thedefinition of module [mlp].
+-- Copyright (c) 2006-2012, Fabien Fleutot <metalua@gmail.com>.
 --
-----------------------------------------------------------------------
+-- This software is released under the MIT Licence, see licence.txt
+-- for details.
+--
+--------------------------------------------------------------------------------
 
 --------------------------------------------------------------------------------
 --
 -- Exported API:
--- * [mlp.table_field()]
--- * [mlp.table_content()]
--- * [mlp.table()]
+-- * [M.bracket_field()]
+-- * [M.field()]
+-- * [M.content()]
+-- * [M.table()]
 --
 -- KNOWN BUG: doesn't handle final ";" or "," before final "}"
 --
 --------------------------------------------------------------------------------
 
---require "gg"
---require "mll"
---require "mlp_misc"
-local tableinsert = table.insert
+local gg  = require 'metalua.grammar.generator'
+local mlp = require 'metalua.compiler.parser.common'
 
-module ("mlp", package.seeall)
+local M = { }
 
 --------------------------------------------------------------------------------
 -- eta expansion to break circular dependencies:
 --------------------------------------------------------------------------------
-local function _expr (lx) return expr(lx) end
+local function _expr (lx) return mlp.expr(lx) end
 
 --------------------------------------------------------------------------------
 -- [[key] = value] table field definition
 --------------------------------------------------------------------------------
-local bracket_field = gg.sequence{ "[", _expr, "]", "=", _expr, builder = "Pair" }
+M.bracket_field = gg.sequence{ "[", _expr, "]", "=", _expr, builder = "Pair" }
 
 --------------------------------------------------------------------------------
 -- [id = value] or [value] table field definition;
 -- [[key]=val] are delegated to [bracket_field()]
 --------------------------------------------------------------------------------
-function table_field (lx)
-   if lx:is_keyword (lx:peek(), "[") then return bracket_field (lx) end
+function M.field (lx)
+   if lx :is_keyword (lx :peek(), "[") then return M.bracket_field (lx) end
    local e = _expr (lx)
-   if lx:is_keyword (lx:peek(), "=") then 
-      lx:next(); -- skip the "="
-      local key = id2string(e)
+   if lx :is_keyword (lx :peek(), "=") then 
+      lx :next(); -- skip the "="
+      local key = mlp.id2string(e)
       local val = _expr(lx)
       local r = { tag="Pair", key, val } 
       r.lineinfo = { first = key.lineinfo.first, last = val.lineinfo.last }
@@ -69,35 +70,18 @@
    else return e end
 end
 
-local function _table_field(lx) return table_field(lx) end
-
 --------------------------------------------------------------------------------
 -- table constructor, without enclosing braces; returns a full table object
 --------------------------------------------------------------------------------
-function table_content(lx)
-    local items = {tag = "Table"}
-    while not lx:is_keyword(lx:peek(), '}') do
-        -- Seek for table values
-        local tablevalue = _table_field (lx)
-        if tablevalue then
-            tableinsert(items, tablevalue)
-        else 
-            return gg.parse_error(lx, '`Pair of value expected.')
-        end
-
-        -- Seek for values separators
-        if lx:is_keyword(lx:peek(), ',', ';') then
-            lx:next()
-        elseif not lx:is_keyword(lx:peek(), '}') then
-            return gg.parse_error(lx, '} expected.')
-        end
-    end
-    return items
-end
-
-local function _table_content(lx) return table_content(lx) end
+M.content  = gg.list { 
+   primary     =  function(...) return M.field(...) end, 
+   separators  = { ",", ";" }, 
+   terminators = "}",
+   builder     = "Table" }
 
 --------------------------------------------------------------------------------
 -- complete table constructor including [{...}]
 --------------------------------------------------------------------------------
-table = gg.sequence{ "{", _table_content, "}", builder = fget(1) }
+M.table = gg.sequence{ "{", function(...) return M.content(...) end, "}", builder = unpack }
+
+return M
diff --git a/lib/metalua/extension/clist.mlua b/metalua/extension/clist.mlua
similarity index 86%
rename from lib/metalua/extension/clist.mlua
rename to metalua/extension/clist.mlua
index ae28e84..14cfde8 100644
--- a/lib/metalua/extension/clist.mlua
+++ b/metalua/extension/clist.mlua
@@ -16,15 +16,23 @@
 --     Fabien Fleutot - API and implementation
 --
 -------------------------------------------------------------------------------
-
---------------------------------------------------------------------------------
 --
 -- This extension implements list comprehensions, similar to Haskell and
 -- Python syntax, to easily describe lists.
 --
---------------------------------------------------------------------------------
+-- * x[a ... b] is the list { x[a], x[a+1], ..., x[b] }
+-- * { f()..., b } contains all the elements returned by f(), then b
+--   (allows to expand list fields other than the last one)
+-- * list comprehensions a la python, with "for" and "if" suffixes:
+--   {i+10*j for i=1,3 for j=1,3 if i~=j} is { 21, 31, 12, 32, 13, 23 }
+--
+-------------------------------------------------------------------------------
 
--{ extension "match" }
+-{ extension ("match", ...) }
+
+local gg  = require 'metalua.grammar.generator'
+local mlp = require 'metalua.compiler.parser'
+local mlp_table = require 'metalua.compiler.parser.table'
 
 local function dots_builder (x) return `Dots{ x } end
 
@@ -43,7 +51,7 @@
    |  _              -> return `Comp{ x, p[1] }
    end
 end
-   
+
 local function comp_builder(core, list, no_unpack)
    -- [ti] = temp var holding table.insert
    -- [v]  = variable holding the table being built
@@ -57,7 +65,7 @@
    match core with
    | `Dots{ x } -> 
       local w = mlp.gensym()
-      r = +{stat: for -{w} in values( -{x} ) do -{ `Call{ ti, v, w } } end }
+      r = +{stat: for _, -{w} in pairs( -{x} ) do -{ `Call{ ti, v, w } } end }
    | `Pair{ k, w } ->
       r = `Set{ { `Index{ v, k } }, { w } }
    |  _ -> r = `Call{ ti, v, core }
@@ -88,7 +96,7 @@
       local tables = { `Table }
       local ctable = tables[1]
       local function flush() ctable=`Table; table.insert(tables, ctable) end
-      for x in values(list) do
+      for _, x in pairs(list) do
          match x with
          | `Comp{ y, acc } -> table.insert(ctable, comp_builder(y, acc)); flush()
          | `Dots{ y }      -> table.insert(ctable, y); flush()
@@ -104,14 +112,14 @@
    end
 end
 
-mlp.table_field = gg.expr{ name="table cell",
-   primary = mlp.table_field,
+mlp_table.field = gg.expr{ name="table cell",
+   primary = mlp_table.field,
    suffix  = { name="table cell suffix",
       { "...",                 builder = dots_builder },
       { "for", mlp.for_header, builder = for_builder  },
       { "if",  mlp.expr,       builder = if_builder   } } }
 
-mlp.table_content.builder = table_content_builder
+mlp_table.content.builder = table_content_builder
 
 --[[
 mlp.stat:add{ "for", gg.expr {
@@ -133,7 +141,7 @@
    | ranges ->
       local r = `Call{ +{table.isub}, a }
       local function acc (x,y) table.insert (r,x); table.insert (r,y) end
-      for seq in ivalues (ranges) do
+      for _, seq in ipairs (ranges) do
          match seq with
          | { e, false } -> acc(e,e)
          | { e, f }     -> acc(e,f)
diff --git a/lib/metalua/extension/log.mlua b/metalua/extension/log.mlua
similarity index 96%
rename from lib/metalua/extension/log.mlua
rename to metalua/extension/log.mlua
index 5f048c1..c9323a9 100644
--- a/lib/metalua/extension/log.mlua
+++ b/metalua/extension/log.mlua
@@ -19,7 +19,7 @@
 
 require 'metalua.dollar'
 
--{ extension 'match' }
+-{ extension ('match', ...) }
 
 function dollar.log(...)
    local args   = {...}
@@ -56,3 +56,5 @@
    end
    return code
 end
+
+return function() end
diff --git a/lib/metalua/extension/match.mlua b/metalua/extension/match.mlua
similarity index 83%
rename from lib/metalua/extension/match.mlua
rename to metalua/extension/match.mlua
index eab9f8f..d7c7762 100644
--- a/lib/metalua/extension/match.mlua
+++ b/metalua/extension/match.mlua
@@ -17,7 +17,7 @@
 --
 -------------------------------------------------------------------------------
 
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
 --
 -- Glossary:
 --
@@ -28,11 +28,11 @@
 -- * pattern_group: several pattern seqs, one of them might match
 --                  the term seq.
 -- * case: pattern_group * guard option * block
--- * match_statement: tested term_seq * case list 
+-- * match_statement: tested term_seq * case list
 --
 -- Hence a complete match statement is a:
 --
--- { list(expr),  list{ list(list(expr)), expr or false, block } } 
+-- { list(expr),  list{ list(list(expr)), expr or false, block } }
 --
 -- Implementation hints
 -- ====================
@@ -64,15 +64,15 @@
 -- Code generation is performed by acc_xxx() functions, which accumulate
 -- code in cfg.code:
 --
--- * acc_test(test, cfg) will generate a jump to cfg.on_failure 
+-- * acc_test(test, cfg) will generate a jump to cfg.on_failure
 --   *when the test returns TRUE*
 --
 -- * acc_stat accumulates a statement
--- 
--- * acc_assign accumulate an assignment statement, and makes sure that 
+--
+-- * acc_assign accumulate an assignment statement, and makes sure that
 --   the LHS variable the registered as local in cfg.locals.
---   
-----------------------------------------------------------------------
+--
+-------------------------------------------------------------------------------
 
 -- TODO: hygiene wrt type()
 -- TODO: cfg.ntmp isn't reset as often as it could. I'm not even sure
@@ -80,6 +80,8 @@
 
 module ('spmatch', package.seeall)
 
+local gg  = require 'metalua.grammar.generator'
+
 ----------------------------------------------------------------------
 -- This would have been best done through library 'metalua.walk',
 -- but walk depends on match, so we have to break the dependency.
@@ -87,23 +89,24 @@
 -- it appears in a function.
 ----------------------------------------------------------------------
 function replace_dots (ast, term)
-   local function rec (x)
-      if type(x) == 'table' then
-         if x.tag=='Dots' then 
-            if term=='ambiguous' then
-               error ("You can't use `...' on the right of a match case when it appears "..
-                      "more than once on the left")
-            else 
-               x <- term
-            end
-         elseif x.tag=='Function' then return
-         else for y in ivalues (x) do rec (y) end end
-      end
-   end
-   return rec (ast)
+    local function rec (x)
+        if type(x) == 'table' then
+            if x.tag=='Dots' then
+                if term=='ambiguous' then
+                    error ("You can't use `...' on the right of a match case when it appears "..
+                           "more than once on the left")
+                else
+                    x <- term
+                end
+            elseif x.tag=='Function' then return nil
+            else for _, y in ipairs (x) do rec (y) end end
+        end
+    end
+    return rec (ast)
 end
 
-tmpvar_base = mlp.gensym 'submatch.' [1]
+tmpvar_base = gg.gensym 'submatch.' [1]
+
 function next_tmpvar(cfg)
    assert (cfg.ntmp, "No cfg.ntmp imbrication level in the match compiler")
    cfg.ntmp = cfg.ntmp+1
@@ -127,15 +130,15 @@
 -- term    :: expr
 function id_pattern_element_builder (pattern, term, cfg)
    assert (pattern.tag == "Id")
-   if pattern[1] == "_" then 
+   if pattern[1] == "_" then
       -- "_" is used as a dummy var ==> no assignment, no == checking
       cfg.locals._ = true
-   elseif cfg.locals[pattern[1]] then 
+   elseif cfg.locals[pattern[1]] then
       -- This var is already bound ==> test for equality
       acc_test (+{ -{term} ~= -{pattern} }, cfg)
    else
       -- Free var ==> bind it, and remember it for latter linearity checking
-      acc_assign (pattern, term, cfg) 
+      acc_assign (pattern, term, cfg)
       cfg.locals[pattern[1]] = true
    end
 end
@@ -150,7 +153,7 @@
 function pattern_element_builder (pattern, term, cfg)
    if literal_tags[pattern.tag] then
       acc_test (+{ -{term} ~= -{pattern} }, cfg)
-   elseif "Id" == pattern.tag then 
+   elseif "Id" == pattern.tag then
       id_pattern_element_builder (pattern, term, cfg)
    elseif "Op" == pattern.tag and "div" == pattern[1] then
       regexp_pattern_element_builder (pattern, term, cfg)
@@ -158,7 +161,7 @@
       eq_pattern_element_builder (pattern, term, cfg)
    elseif "Table" == pattern.tag then
       table_pattern_element_builder (pattern, term, cfg)
-   else 
+   else
       error ("Invalid pattern: "..table.tostring(pattern, "nohash"))
    end
 end
@@ -178,11 +181,11 @@
 
    -- Sanity checks --
    assert (op=='div', "Don't know what to do with that op in a pattern")
-   assert (regexp.tag=="String", 
+   assert (regexp.tag=="String",
            "Left hand side operand for '/' in a pattern must be "..
            "a literal string representing a regular expression")
    if sub_pattern.tag=="Table" then
-      for x in ivalues(sub_pattern) do
+      for _, x in ipairs(sub_pattern) do
 	 assert (x.tag=="Id" or x.tag=='Dots',
 		 "Right hand side operand for '/' in a pattern must be "..
 		 "a list of identifiers")
@@ -218,15 +221,15 @@
       else -- Implicit key
          len, key, sub_pattern = len+1, `Number{ len+1 }, pattern[i]
       end
-      
+
       -- '...' can only appear in final position
       -- Could be fixed actually...
       assert (not seen_dots, "Wrongly placed `...' ")
 
-      if sub_pattern.tag == "Id" then 
+      if sub_pattern.tag == "Id" then
          -- Optimization: save a useless [ v(n+1)=v(n).key ]
          id_pattern_element_builder (sub_pattern, `Index{ term, key }, cfg)
-         if sub_pattern[1] ~= "_" then 
+         if sub_pattern[1] ~= "_" then
             acc_test (+{ -{sub_pattern} == nil }, cfg)
          end
       elseif sub_pattern.tag == "Dots" then
@@ -241,7 +244,7 @@
       end
    end
    if seen_dots then -- remember how to retrieve `...'
-      -- FIXME: check, but there might be cases where the variable -{term} 
+      -- FIXME: check, but there might be cases where the variable -{term}
       -- will be overridden in contrieved tables.
       -- ==> save it now, and clean the setting statement if unused
       if cfg.dots_replacement then cfg.dots_replacement = 'ambiguous'
@@ -274,10 +277,10 @@
 --------------------------------------------------
 function case_builder (case, term_seq, cfg)
    local patterns_group, guard, block = unpack(case)
-   local on_success = mlp.gensym 'on_success' [1]
+   local on_success = gg.gensym 'on_success' [1]
    for i = 1, #patterns_group do
       local pattern_seq = patterns_group[i]
-      cfg.on_failure = mlp.gensym 'match_fail' [1]
+      cfg.on_failure = gg.gensym 'match_fail' [1]
       cfg.dots_replacement = false
       pattern_seq_builder (pattern_seq, term_seq, cfg)
       if i<#patterns_group then
@@ -298,9 +301,9 @@
 
 function match_builder (x)
    local term_seq, cases = unpack(x)
-   local cfg = { 
+   local cfg = {
       code          = `Do{ },
-      after_success = mlp.gensym "_after_success" }
+      after_success = gg.gensym "_after_success" }
 
 
    -- Some sharing issues occur when modifying term_seq,
@@ -319,7 +322,7 @@
       -- Temporary workaround: suppress the condition, so that
       -- all external variables are copied into unique names.
       --if t.tag ~= 'Id' and not literal_tags[t.tag] then
-         local v = mlp.gensym 'v'
+         local v = gg.gensym 'v'
          if not match_locals then match_locals = `Local{ {v}, {t} } else
             table.insert(match_locals[1], v)
             table.insert(match_locals[2], t)
@@ -328,11 +331,11 @@
       --end
    end
    term_seq = new_term_seq
-   
+
    if match_locals then acc_stat(match_locals, cfg) end
 
    for i=1, #cases do
-      local case_cfg = { 
+      local case_cfg = {
          after_success    = cfg.after_success,
          code             = `Do{ }
          -- locals    = { } -- unnecessary, done by pattern_seq_builder
@@ -341,7 +344,7 @@
       if next (case_cfg.locals) then
          local case_locals = { }
          table.insert (case_cfg.code, 1, `Local{ case_locals, { } })
-         for v in keys (case_cfg.locals) do
+         for v, _ in pairs (case_cfg.locals) do
             table.insert (case_locals, `Id{ v })
          end
       end
@@ -356,26 +359,30 @@
 -- Syntactical front-end
 ----------------------------------------------------------------------
 
-mlp.lexer:add{ "match", "with", "->" }
-mlp.block.terminators:add "|"
+local function extend(mlp)
+    checks('metalua.compiler.parser')
+    mlp.lexer:add{ "match", "with", "->" }
+    mlp.block.terminators:add "|"
 
-match_cases_list_parser = gg.list{ name = "match cases list",
-   gg.sequence{ name = "match case",
-      gg.list{ name  = "match case patterns list",
-         primary     = mlp.expr_list,
-         separators  = "|",
-         terminators = { "->", "if" } },
-      gg.onkeyword{ "if", mlp.expr, consume = true },
-      "->",
-      mlp.block },
-   separators  = "|",
-   terminators = "end" }
+    match_cases_list_parser = gg.list{ name = "match cases list",
+        gg.sequence{ name = "match case",
+                     gg.list{ name  = "match case patterns list",
+                              primary     = mlp.expr_list,
+                              separators  = "|",
+                              terminators = { "->", "if" } },
+                     gg.onkeyword{ "if", mlp.expr, consume = true },
+                     "->",
+                     mlp.block },
+        separators  = "|",
+        terminators = "end" }
 
-mlp.stat:add{ name = "match statement",
-   "match", 
-   mlp.expr_list, 
-   "with", gg.optkeyword "|",
-   match_cases_list_parser,
-   "end",
-   builder = |x| match_builder{ x[1], x[3] } }
+    mlp.stat:add{ name = "match statement",
+                  "match",
+                  mlp.expr_list,
+                  "with", gg.optkeyword "|",
+                  match_cases_list_parser,
+                  "end",
+                  builder = |x| match_builder{ x[1], x[3] } }
+end
 
+return extend
\ No newline at end of file
diff --git a/lib/metalua/extension/xloop.mlua b/metalua/extension/xloop.mlua
similarity index 80%
rename from lib/metalua/extension/xloop.mlua
rename to metalua/extension/xloop.mlua
index f4b365f..b5aaed9 100644
--- a/lib/metalua/extension/xloop.mlua
+++ b/metalua/extension/xloop.mlua
@@ -16,12 +16,38 @@
 --     Fabien Fleutot - API and implementation
 --
 -------------------------------------------------------------------------------
+-- Loop control syntax extensions
+--
+-- * Allows to compound loop headers together, e.g. write:
+--      for i=1,10 for j=1,10 do f(i,j) end
+--   instead of:
+--      for i=1,10 do for j=1,10 do f(i,j) end end
+--   loop headers are "for/=" and "for/in"
+--
+-- * while <condition> in a loop header will break the loop(s)
+--   as soon as condition stops being satisfied.
+--
+-- * until <condition> in a loop header will break the loop(s)
+--   as soon as condition is satisfied.
+--
+-- * if <condition> in a loop header will skip an iteration
+--   if the condition is not satisfied.
+--
+-- * unless <condition> in a loop header will skip an iteration
+--   if the condition is satisfied.
+--
+-- TODO: document ordering matters, e.g. how 
+-- "for i in x() if cond(i) for j in y()" is parsed.
+--
+-------------------------------------------------------------------------------
 
--{ extension 'match' }
--{ extension 'log' }
+-{ extension ('match', ...) }
 
 require 'metalua.walk'
 
+local gg  = require 'metalua.grammar.generator'
+local mlp = require 'metalua.compiler.parser'
+
 ----------------------------------------------------------------------
 -- Back-end:
 ----------------------------------------------------------------------
@@ -113,7 +139,3 @@
 mlp.stat:add{
    'while', mlp.expr, loop_element_list, 'do', mlp.block, 'end',
    builder = |x| xloop_builder{ `While{x[1]}, x[2], x[3] } }
-
-mlp.stat:add{
-   'unless', mlp.expr, 'then', mlp.block, 'end',
-   builder = |x| +{stat: if not -{x[1]} then -{x[2]} end} }
diff --git a/lib/metalua/extension/xmatch.mlua b/metalua/extension/xmatch.mlua
similarity index 97%
rename from lib/metalua/extension/xmatch.mlua
rename to metalua/extension/xmatch.mlua
index 1936bda..71fd0b0 100644
--- a/lib/metalua/extension/xmatch.mlua
+++ b/metalua/extension/xmatch.mlua
@@ -23,8 +23,6 @@
 
 require 'metalua.walk.id'
 
--{extension 'log'}
-
 ----------------------------------------------------------------------
 -- Back-end for statements
 -- "match function ..." and "local match function...".
@@ -119,7 +117,7 @@
             local tested_term_seq, _, cases = unpack(x)
             local v = mlp.gensym 'match_expr'
             -- Replace expressions with blocks
-            for case in ivalues (cases) do
+            for _, case in ipairs (cases) do
                local body = case[3]
                case[3] = { `Set{ {v}, {body} } }
             end
@@ -173,7 +171,7 @@
    -------------------------------------------------------------------
    local vars_not_in_pattern do
       vars_not_in_pattern = { }
-      for k in keys(vars) do
+      for k, _ in pairs(vars) do
          if not vars_in_pattern[k] then
             vars_not_in_pattern[k] = true
          end
@@ -185,7 +183,7 @@
    -------------------------------------------------------------------
    if next(vars_not_in_pattern) then
       local loc = { }
-      for k in keys (vars_not_in_pattern) do
+      for k, _ in pairs(vars_not_in_pattern) do
          table.insert (loc, `Id{k})
       end
       table.insert (code, 1, `Local{ loc, { } })
@@ -196,7 +194,7 @@
    -------------------------------------------------------------------
    local decl_list do
       decl_list = { }
-      for k in keys (vars_in_pattern) do
+      for k, _ in pairs(vars_in_pattern) do
          table.insert (decl_list, `Id{k})
       end
    end
diff --git a/compiler/gg.lua b/metalua/grammar/generator.lua
similarity index 84%
rename from compiler/gg.lua
rename to metalua/grammar/generator.lua
index c4c6019..15dddf8 100644
--- a/compiler/gg.lua
+++ b/metalua/grammar/generator.lua
@@ -1,4 +1,4 @@
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 -- Copyright (c) 2006-2013 Fabien Fleutot and others.
 --
 -- All rights reserved.
@@ -15,15 +15,15 @@
 -- Contributors:
 --     Fabien Fleutot - API and implementation
 --
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 
----------------------------------------------------------------------
+--------------------------------------------------------------------------------
 --
 -- Summary: parser generator. Collection of higher order functors,
 --   which allow to build and combine parsers. Relies on a lexer
 --   that supports the same API as the one exposed in mll.lua.
 --
-----------------------------------------------------------------------
+--------------------------------------------------------------------------------
 
 --------------------------------------------------------------------------------
 --
@@ -37,14 +37,31 @@
 -- * [gg.onkeyword()]
 -- * [gg.optkeyword()]
 --
--- Other functions:
+-- Other functions: 
 -- * [gg.parse_error()]
 -- * [gg.make_parser()]
 -- * [gg.is_parser()]
 --
 --------------------------------------------------------------------------------
 
-module("gg", package.seeall)
+local M = { }
+
+local lexer = require 'metalua.grammar.lexer'
+
+--------------------------------------------------------------------------------
+-- Symbol generator: [gensym()] returns a guaranteed-to-be-unique identifier.
+-- The main purpose is to avoid variable capture in macros.
+--
+-- If a string is passed as an argument, theis string will be part of the
+-- id name (helpful for macro debugging)
+--------------------------------------------------------------------------------
+local gensymidx = 0
+
+function M.gensym (arg)
+   gensymidx = gensymidx + 1
+   return { tag="Id", string.format(".%i.%s", gensymidx, arg or "")}
+end
+
 
 -------------------------------------------------------------------------------
 -- parser metatable, which maps __call to method parse, and adds some
@@ -58,16 +75,22 @@
 -------------------------------------------------------------------------------
 local parser_metatable = { }
 
-function parser_metatable :__call (...) 
-    local r = self :parse(...) 
+function parser_metatable :__call (lx, ...)
+    --return self :parse(lx, ...)
+    local r = self :parse (lx, ...)
+    if r and type(r) ~= 'table' then
+        printf("Grammar generator: parser %s returned non-table %s at %s",
+               table.tostring(self.name),
+               table.tostring(r),
+               table.tostring((...):peek()))
+    end
     return r
-    --return self :parse(...) 
 end
 
 -------------------------------------------------------------------------------
 -- Turn a table into a parser, mainly by setting the metatable.
 -------------------------------------------------------------------------------
-function make_parser(kind, p)
+function M.make_parser(kind, p)
    p.kind = kind
    if not p.transformers then p.transformers = { } end
    function p.transformers:add (x)
@@ -81,7 +104,7 @@
 -- Return true iff [x] is a parser.
 -- If it's a gg-generated parser, return the name of its kind.
 -------------------------------------------------------------------------------
-function is_parser (x)
+function M.is_parser (x)
    return type(x)=="function" or getmetatable(x)==parser_metatable and x.kind
 end
 
@@ -98,21 +121,25 @@
    local r = { }
    local failed = false
    for i=1, #p do
-      e=p[i]
+      local e=p[i]
       if failed then
-         if type(e)=="string" then table.insert(r, earlier_error(lx)) end
+         if type(e)=="string" then table.insert(r, M.earlier_error(lx)) end
       elseif type(e) == "string" then
-         if not lx :is_keyword (lx :next(), e) then
-            table.insert(r, {tag='Error', "A keyword was expected, probably `"..e.."'."})
+         local kw = lx :next()
+         if not lx :is_keyword (kw, e) then
+            table.insert(r, {
+                tag = 'Error',
+                lineinfo = kw.lineinfo,
+                "A keyword was expected, probably `"..e.."'."})
             failed=true
          end
-      elseif is_parser (e) then
+      elseif M.is_parser (e) then
          local x = e(lx)
          if type(x)=='table' and x.tag=='Error' then failed=true end
          table.insert (r, x)
       else -- Invalid parser definition, this is not a parsing error, it must fail.
-         return gg.parse_error (lx,"Sequence `%s': element #%i is neither a string "..
-                         "nor a parser: %s", p.name, i, table.tostring(e))
+         return M.parse_error (lx,"Sequence `%s': element #%i is neither a string "..
+             "nor a parser: %s", p.name, i, table.tostring(e))
       end
    end
    return r
@@ -136,7 +163,7 @@
    if parser.transformers then
       for _, t in ipairs (parser.transformers) do ast = t(ast) or ast end
    end
-   if type(ast) == 'table'then
+   if type(ast) == 'table' then
       local ali = ast.lineinfo
       if not ali or ali.first~=fli or ali.last~=lli then
          ast.lineinfo = lexer.new_lineinfo(fli, lli)
@@ -146,13 +173,13 @@
 end
 
 -------------------------------------------------------------------------------
--- Generate a tracable parsing error
+-- Generate a tracable parsing error (not implemented yet)
 -------------------------------------------------------------------------------
-function parse_error(lx, fmt, ...)
+function M.parse_error(lx, fmt, ...)
    local li = lx:lineinfo_left()
    local line, column, offset
    if li then line, column, offset = li.line, li.column, li.offset
-   else line, column, offset, src_name = -1, -1, -1 end
+   else line, column, offset = -1, -1, -1 end
 
    local msg  = string.format("line %i, char %i: "..fmt, line, column, ...)   
    local src = lx.src
@@ -165,24 +192,22 @@
       msg = string.format("%s\n>>> %s\n>>> %s", msg, srcline, idx)
    end
    lx :kill()
-   assert (lx :peek().tag=='Eof')
-   --printf ("gg.parse_error(%q)", msg)
-   return { tag='Error', msg, error=true }
+   return { tag='Error', msg }
 end
 
-function wrap_error(lx, nchildren, tag, ...)
+function M.wrap_error(lx, nchildren, tag, ...)
     local li = lx :peek() .lineinfo
-    local r = { tag=tag or 'Error', lineinfo=li, error=true }
+    local r = { tag=tag or 'Error', lineinfo=li }
     local children = {...}
     for i=1, nchildren do
-        r[i] = children[i] or earlier_error(lx)
+        r[i] = children[i] or M.earlier_error(lx)
     end
     return r
 end
 
-function earlier_error(lx)
+function M.earlier_error(lx)
     local li = lx and lx :peek().lineinfo
-    return { tag='Error', "earlier error", lineinfo=li, error=true, stuffing = true }
+    return { tag='Error', "earlier error", lineinfo=li, error=true, earlier=true }
 end
    
 -------------------------------------------------------------------------------
@@ -212,8 +237,8 @@
 -- * [name] is set, if it wasn't in the input.
 --
 -------------------------------------------------------------------------------
-function sequence (p)
-   make_parser ("sequence", p)
+function M.sequence (p)
+   M.make_parser ("sequence", p)
 
    -------------------------------------------------------------------
    -- Parsing method
@@ -293,24 +318,25 @@
 -- * [kind] == "multisequence"
 --
 -------------------------------------------------------------------------------
-function multisequence (p)   
-   make_parser ("multisequence", p)
+function M.multisequence (p)   
+   M.make_parser ("multisequence", p)
 
    -------------------------------------------------------------------
    -- Add a sequence (might be just a config table for [gg.sequence])
    -------------------------------------------------------------------
-   function p:add (s)
+   function p :add (s)
       -- compile if necessary:
       local keyword = type(s)=='table' and s[1]
-      if type(s)=='table' and not is_parser(s) then sequence(s) end
-      if is_parser(s)~='sequence' or type(keyword)~='string' then 
+      if type(s)=='table' and not M.is_parser(s) then M.sequence(s) end
+      if M.is_parser(s)~='sequence' or type(keyword)~='string' then 
          if self.default then -- two defaults
             error ("In a multisequence parser, all but one sequences "..
                    "must start with a keyword")
          else self.default = s end -- first default
       elseif self.sequences[keyword] then -- duplicate keyword
-         eprintf (" *** Warning: keyword %q overloaded in multisequence ***",
-                  keyword)
+         print (string.format(
+	    " *** Warning: keyword %q overloaded in multisequence ***",
+            keyword))
          self.sequences[keyword] = s
       else -- newly caught keyword
          self.sequences[keyword] = s
@@ -320,12 +346,12 @@
    -------------------------------------------------------------------
    -- Get the sequence starting with this keyword. [kw :: string]
    -------------------------------------------------------------------
-   function p:get (kw) return self.sequences [kw] end
+   function p :get (kw) return self.sequences [kw] end
 
    -------------------------------------------------------------------
    -- Remove the sequence starting with keyword [kw :: string]
    -------------------------------------------------------------------
-   function p:del (kw) 
+   function p :del (kw) 
       if not self.sequences[kw] then 
          eprintf("*** Warning: trying to delete sequence starting "..
                  "with %q from a multisequence having no such "..
@@ -338,7 +364,7 @@
    -------------------------------------------------------------------
    -- Parsing method
    -------------------------------------------------------------------
-   function p:parse (lx)
+   function p :parse (lx)
       local fli = lx:lineinfo_right()
       local x = raw_parse_multisequence (lx, self.sequences, self.default)
       local lli = lx:lineinfo_left()
@@ -352,7 +378,7 @@
    -- from the array part of the parser to the hash part of field
    -- [sequences]
    p.sequences = { }
-   for i=1, #p do p:add (p[i]); p[i] = nil end
+   for i=1, #p do p :add (p[i]); p[i] = nil end
 
    -- FIXME: why is this commented out?
    --if p.default and not is_parser(p.default) then sequence(p.default) end
@@ -379,7 +405,7 @@
 --     and the prefixed expression
 --   - for [infix], it takes the left-hand-side expression, the results 
 --     of the infix sequence parser, and the right-hand-side expression.
---   - for [suffix], it takes the suffixed expression, and theresult 
+--   - for [suffix], it takes the suffixed expression, and the result 
 --     of the suffix sequence parser.
 --
 -- * the default field is a list, with parameters:
@@ -405,8 +431,8 @@
 --   [add] method
 --
 -------------------------------------------------------------------------------
-function expr (p)
-   make_parser ("expr", p)
+function M.expr (p)
+   M.make_parser ("expr", p)
 
    -------------------------------------------------------------------
    -- parser method.
@@ -414,7 +440,7 @@
    -- it won't read expressions whose precedence is lower or equal
    -- to [prec].
    -------------------------------------------------------------------
-   function p:parse (lx, prec)
+   function p :parse (lx, prec)
       prec = prec or 0
 
       ------------------------------------------------------
@@ -423,7 +449,7 @@
       -- Options include prec, assoc, transformers.
       ------------------------------------------------------
       local function get_parser_info (tab)
-         local p2 = tab:get (lx:is_keyword (lx:peek()))
+         local p2 = tab :get (lx :is_keyword (lx :peek()))
          if p2 then -- keyword-based sequence found
             local function parser(lx) return raw_parse_sequence(lx, p2) end
             return parser, p2
@@ -441,17 +467,17 @@
       -- expr, and one for the one with the prefix op.
       ------------------------------------------------------
       local function handle_prefix ()
-         local fli = lx:lineinfo_right()
+         local fli = lx :lineinfo_right()
          local p2_func, p2 = get_parser_info (self.prefix)
          local op = p2_func and p2_func (lx)
          if op then -- Keyword-based sequence found
-            local ili = lx:lineinfo_right() -- Intermediate LineInfo
-            local e = p2.builder (op, self:parse (lx, p2.prec))
-            local lli = lx:lineinfo_left()
+            local ili = lx :lineinfo_right() -- Intermediate LineInfo
+            local e = p2.builder (op, self :parse (lx, p2.prec))
+            local lli = lx :lineinfo_left()
             return transform (transform (e, p2, ili, lli), self, fli, lli)
          else -- No prefix found, get a primary expression         
             local e = self.primary(lx)
-            local lli = lx:lineinfo_left()
+            local lli = lx :lineinfo_left()
             return transform (e, self, fli, lli)
          end
       end --</expr.parse.handle_prefix>
@@ -504,7 +530,7 @@
          -- Check for non-associative operators, and complain if applicable. 
          -----------------------------------------
          elseif p2.assoc=="none" and p2.prec==prec then
-            return parse_error (lx, "non-associative operator!")
+            return M.parse_error (lx, "non-associative operator!")
 
          -----------------------------------------
          -- No infix operator suitable at that precedence
@@ -556,7 +582,7 @@
    if not p.primary then p.primary=p[1]; p[1]=nil end
    for _, t in ipairs{ "primary", "prefix", "infix", "suffix" } do
       if not p[t] then p[t] = { } end
-      if not is_parser(p[t]) then multisequence(p[t]) end
+      if not M.is_parser(p[t]) then M.multisequence(p[t]) end
    end
    function p:add(...) return self.primary:add(...) end
    return p
@@ -588,21 +614,18 @@
 --   is the same as [{"do"}]. If [terminators] is empty/nil, then
 --   [separators] has to be non-empty.
 --
--- * [nonempty]: if true, empty lists are rejected by the parser whatever
---   the [terminators] and [separators] values are.
---
 -- After creation, the following fields are added:
 -- * [parse] the parsing function lexer->AST
 -- * [kind] == "list"
 --
 -------------------------------------------------------------------------------
-function list (p)
-   make_parser ("list", p)
+function M.list (p)
+   M.make_parser ("list", p)
 
    -------------------------------------------------------------------
    -- Parsing method
    -------------------------------------------------------------------
-   function p:parse (lx)
+   function p :parse (lx)
 
       ------------------------------------------------------
       -- Used to quickly check whether there's a terminator 
@@ -612,26 +635,23 @@
          return keywords and lx:is_keyword(lx:peek(), unpack(keywords)) end
 
       local x = { }
-      local fli = lx:lineinfo_right()
+      local fli = lx :lineinfo_right()
 
       -- if there's a terminator to start with, don't bother trying
-      if not peek_is_in (self.terminators) then
-
-          while true do
-              
-              local item = self.primary(lx)
-              table.insert(x, item)
-
-              -- loop exit conditions
-              if type(item)=='table' and item.tag=='Error' then break -- error in last item
-              elseif self.separators then -- either a separator is consumed or an error is raised
-                  if peek_is_in (self.separators) then lx :next() else break end
-              elseif peek_is_in (self.terminators) then break  -- end on terminator detection
-              elseif lx :peek().tag == 'Eof' then break end -- Eof is always a terminator
-          end
-      end
-      if self.nonempty and not next(x) then
-          return gg.parse_error (lx,"List `%s' must not be empty", p.name)
+      if not peek_is_in (self.terminators) then 
+         repeat
+             local item = self.primary(lx)
+             table.insert (x, item) -- read one element
+         until
+            -- Don't go on after an error
+            type(item)=='table' and item.tag=='Error' or
+            -- There's a separator list specified, and next token isn't in it.
+            -- Otherwise, consume it with [lx:next()]
+            self.separators and not(peek_is_in (self.separators) and lx:next()) or
+            -- Terminator token ahead
+            peek_is_in (self.terminators) or
+            -- Last reason: end of file reached
+            lx:peek().tag=="Eof"
       end
 
       local lli = lx:lineinfo_left()
@@ -653,11 +673,9 @@
    -------------------------------------------------------------------
    -- Construction
    -------------------------------------------------------------------
-   if not p.primary then p.primary, p[1] = p[1], nil end
-
+   if not p.primary then p.primary = p[1]; p[1] = nil end
    if type(p.terminators) == "string" then p.terminators = { p.terminators }
    elseif p.terminators and #p.terminators == 0 then p.terminators = nil end
-
    if type(p.separators) == "string" then p.separators = { p.separators }
    elseif p.separators and #p.separators == 0 then p.separators = nil end
 
@@ -667,7 +685,7 @@
 
 -------------------------------------------------------------------------------
 --
--- Keyword-conditionned parser generator
+-- Keyword-conditioned parser generator
 --
 -------------------------------------------------------------------------------
 -- 
@@ -686,7 +704,7 @@
 --
 -- * [transformers]: as usual
 --
--- * [peek]: if non-nil, the conditionning keyword is left in the lexeme
+-- * [peek]: if non-nil, the conditioning keyword is left in the lexeme
 --   stream instead of being consumed.
 --
 -- * [primary]: the subparser. 
@@ -704,14 +722,14 @@
 -- * [keywords]
 --
 -------------------------------------------------------------------------------
-function onkeyword (p)
-   make_parser ("onkeyword", p)
+function M.onkeyword (p)
+   M.make_parser ("onkeyword", p)
 
    -------------------------------------------------------------------
    -- Parsing method
    -------------------------------------------------------------------
-   function p:parse(lx)
-      if lx:is_keyword (lx:peek(), unpack(self.keywords)) then
+   function p :parse (lx)
+      if lx :is_keyword (lx:peek(), unpack(self.keywords)) then
          local fli = lx:lineinfo_right()
          if not self.peek then lx:next() end
          local content = self.primary (lx)
@@ -728,7 +746,7 @@
    if not p.keywords then p.keywords = { } end
    for _, x in ipairs(p) do
       if type(x)=="string" then table.insert (p.keywords, x)
-      else assert (not p.primary and is_parser (x)); p.primary = x end
+      else assert (not p.primary and M.is_parser (x)); p.primary = x end
    end
    if not next (p.keywords) then 
       eprintf("Warning, no keyword to trigger gg.onkeyword") end
@@ -750,7 +768,7 @@
 -- Notice that tokens returned by lexer already carry lineinfo, therefore
 -- there's no need to add them, as done usually through transform() calls.
 -------------------------------------------------------------------------------
-function optkeyword (...)
+function M.optkeyword (...)
    local args = {...}
    if type (args[1]) == "table" then 
       assert (#args == 1)
@@ -777,7 +795,7 @@
 -- The resulting parser returns whatever the argument parser does.
 --
 -------------------------------------------------------------------------------
-function with_lexer(new_lexer, parser)
+function M.with_lexer(new_lexer, parser)
 
    -------------------------------------------------------------------
    -- Most gg functions take their parameters in a table, so it's 
@@ -785,7 +803,7 @@
    -- its arguments in a list:
    -------------------------------------------------------------------
    if not parser and #new_lexer==2 and type(new_lexer[1])=='table' then
-      return with_lexer(unpack(new_lexer))
+      return M.with_lexer(unpack(new_lexer))
    end
 
    -------------------------------------------------------------------
@@ -803,8 +821,13 @@
    end
 end
 
-function nonempty(primary)
-    local p = make_parser('non-empty list', { primary = primary, name=primary.name })
+--------------------------------------------------------------------------------
+--
+-- Make sure a parser is used and returns successfully.
+--
+--------------------------------------------------------------------------------
+function M.nonempty(primary)
+    local p = M.make_parser('non-empty list', { primary = primary, name=primary.name })
     function p :parse (lx)
          local fli = lx:lineinfo_right()
          local content = self.primary (lx)
@@ -812,10 +835,12 @@
          local li = content.lineinfo or { }
          fli, lli = li.first or fli, li.last or lli
          if #content == 0 then
-           return gg.parse_error (lx, "`%s' must not be empty", self.name or "list")
+           return gg.parse_error (lx, "`%s' must not be empty.", self.name or "list")
        else
            return transform (content, self, fli, lli)
        end
     end
     return p
 end
+
+return M
diff --git a/compiler/lexer.lua b/metalua/grammar/lexer.lua
similarity index 87%
rename from compiler/lexer.lua
rename to metalua/grammar/lexer.lua
index 15c1ad8..bfd0247 100644
--- a/compiler/lexer.lua
+++ b/metalua/grammar/lexer.lua
@@ -17,11 +17,16 @@
 --
 -------------------------------------------------------------------------------
 
-module ("lexer", package.seeall)
+require 'checks'
 
+local M = { }
 
-lexer = { alpha={ }, sym={ } }
+local lexer = { alpha={ }, sym={ } }
 lexer.__index=lexer
+lexer.__type='lexer.stream'
+
+M.lexer = lexer
+
 
 local debugf = function() end
 -- local debugf=printf
@@ -29,44 +34,40 @@
 ----------------------------------------------------------------------
 -- Some locale settings produce bad results, e.g. French locale
 -- expect float numbers to use commas instead of periods.
+-- TODO: change number parser into something loclae-independent,
+-- locales are nasty.
 ----------------------------------------------------------------------
 os.setlocale('C')
 
+local MT = { }
 
-
-----------------------------------------------------------------------
--- Some locale settings produce bad results, e.g. French locale
--- expects float numbers to use commas instead of periods.
-----------------------------------------------------------------------
-os.setlocale('C')
+M.metatables=MT
 
 ----------------------------------------------------------------------
 -- Create a new metatable, for a new class of objects.
 ----------------------------------------------------------------------
 local function new_metatable(name) 
-    local mt = { __type = 'metalua::lexer::'..name }; 
-    mt.__index = mt; return mt
+    local mt = { __type = 'lexer.'..name }; 
+    mt.__index = mt
+    MT[name] = mt
 end
 
 
-
 ----------------------------------------------------------------------
 -- Position: represent a point in a source file.
 ----------------------------------------------------------------------
-position_metatable = new_metatable 'position'
+new_metatable 'position'
 
 local position_idx=1
 
-function new_position(line, column, offset, source)
-    -- assert(type(line)=='number')
-    -- assert(type(column)=='number')
-    -- assert(type(offset)=='number')
-    -- assert(type(source)=='string')
+function M.new_position(line, column, offset, source)
+    checks('number', 'number', 'number', 'string')
     local id = position_idx; position_idx = position_idx+1
-    return setmetatable({line=line, column=column, offset=offset, source=source, id=id}, position_metatable)
+    return setmetatable({line=line, column=column, offset=offset,
+                         source=source, id=id}, MT.position)
 end
 
-function position_metatable :__tostring()
+function MT.position :__tostring()
     return string.format("<%s%s|L%d|C%d|K%d>", 
         self.comments and "C|" or "",
         self.source, self.line, self.column, self.offset)
@@ -77,9 +78,9 @@
 ----------------------------------------------------------------------
 -- Position factory: convert offsets into line/column/offset positions.
 ----------------------------------------------------------------------
-position_factory_metatable = new_metatable 'position_factory'
+new_metatable 'position_factory'
 
-function new_position_factory(src, src_name)
+function M.new_position_factory(src, src_name)
     -- assert(type(src)=='string')
     -- assert(type(src_name)=='string')
     local lines = { 1 }
@@ -87,10 +88,10 @@
     local max = #src+1
     table.insert(lines, max+1) -- +1 includes Eof
     return setmetatable({ src_name=src_name, line2offset=lines, max=max }, 
-        position_factory_metatable)
+        MT.position_factory)
 end
 
-function position_factory_metatable :get_position (offset)
+function MT.position_factory :get_position (offset)
     -- assert(type(offset)=='number')
     assert(offset<=self.max)
     local line2offset = self.line2offset
@@ -115,7 +116,7 @@
     local line = left
     local column = offset - line2offset[line] + 1
     self.last_left = left
-    return new_position(line, column, offset, self.src_name)
+    return M.new_position(line, column, offset, self.src_name)
 end
 
 
@@ -124,15 +125,14 @@
 -- Lineinfo: represent a node's range in a source file;
 -- embed information about prefix and suffix comments.
 ----------------------------------------------------------------------
-lineinfo_metatable = new_metatable 'lineinfo'
+new_metatable 'lineinfo'
 
-function new_lineinfo(first, last)
-    assert(first.__type=='metalua::lexer::position')
-    assert(last.__type=='metalua::lexer::position')
-    return setmetatable({first=first, last=last}, lineinfo_metatable)
+function M.new_lineinfo(first, last)
+    checks('lexer.position', 'lexer.position')
+    return setmetatable({first=first, last=last}, MT.lineinfo)
 end
 
-function lineinfo_metatable :__tostring()
+function MT.lineinfo :__tostring()
     local fli, lli = self.first, self.last
     local line   = fli.line;   if line~=lli.line     then line  =line  ..'-'..lli.line   end
     local column = fli.column; if column~=lli.column then column=column..'-'..lli.column end
@@ -143,21 +143,19 @@
                          lli.comments and "|C" or "")
 end
 
-
-
 ----------------------------------------------------------------------
 -- Token: atomic Lua language element, with a category, a content,
 -- and some lineinfo relating it to its original source.
 ----------------------------------------------------------------------
-token_metatable = new_metatable 'token'
+new_metatable 'token'
 
-function new_token(tag, content, lineinfo)
+function M.new_token(tag, content, lineinfo)
     --printf("TOKEN `%s{ %q, lineinfo = %s} boundaries %d, %d", 
     --       tag, content, tostring(lineinfo), lineinfo.first.id, lineinfo.last.id) 
-    return setmetatable({tag=tag, lineinfo=lineinfo, content}, token_metatable)
+    return setmetatable({tag=tag, lineinfo=lineinfo, content}, MT.token)
 end
 
-function token_metatable :__tostring()    
+function MT.token :__tostring()    
     --return string.format("`%s{ %q, %s }", self.tag, self[1], tostring(self.lineinfo))
     return string.format("`%s %q", self.tag, self[1])
 end
@@ -167,16 +165,16 @@
 -- Comment: series of comment blocks with associated lineinfo.
 -- To be attached to the tokens just before and just after them.
 ----------------------------------------------------------------------
-comment_metatable = new_metatable 'comment'
+new_metatable 'comment'
 
-function new_comment(lines)
+function M.new_comment(lines)
     local first = lines[1].lineinfo.first
     local last  = lines[#lines].lineinfo.last
-    local lineinfo = new_lineinfo(first, last)
-    return setmetatable({lineinfo=lineinfo, unpack(lines)}, comment_metatable)
+    local lineinfo = M.new_lineinfo(first, last)
+    return setmetatable({lineinfo=lineinfo, unpack(lines)}, MT.comment)
 end
 
-function comment_metatable :text()
+function MT.comment :text()
     local last_line = self[1].lineinfo.last.line
     local acc = { }
     for i, line in ipairs(self) do
@@ -187,10 +185,8 @@
     return table.concat(acc)
 end
 
-function new_comment_line(text, lineinfo, nequals)
-    assert(type(text)=='string')
-    assert(lineinfo.__type=='metalua::lexer::lineinfo')
-    assert(nequals==nil or type(nequals)=='number')
+function M.new_comment_line(text, lineinfo, nequals)
+    checks('string', 'lexer.lineinfo', '?number')
     return { lineinfo = lineinfo, text, nequals }
 end
 
@@ -233,7 +229,7 @@
          backslashes = backslashes :sub (1,-2)
       end
       local k, j, i = digits :reverse() :byte(1, 3)
-      local z = _G.string.byte "0"
+      local z = string.byte "0"
       local code = (k or z) + 10*(j or z) + 100*(i or z) - 111*z
       if code > 255 then 
          error ("Illegal escape sequence '\\"..digits..
@@ -272,7 +268,7 @@
          a = "\a", b = "\b", f = "\f",
          n = "\n", r = "\r", t = "\t", v = "\v",
          ["\\"] = "\\", ["'"] = "'", ['"'] = '"', ["\n"] = "\n" }
-      return t[x] or error([[Unknown escape sequence '\]]..x..[[']])
+      return t[x] or x
    end
 
    s = s: gsub ("(\\+)(z%s*)", unesc_z)  -- Lua 5.2
@@ -297,14 +293,13 @@
 ----------------------------------------------------------------------
 function lexer :extract ()
    local attached_comments = { }
-   -- generate a non-comment token, attach comments to its lineinfo.
-   local function gen_token(...) 
-      local token = new_token(...)
+   local function gen_token(...)
+      local token = M.new_token(...)
       if #attached_comments>0 then -- attach previous comments to token
-         local comments = new_comment(attached_comments)
+         local comments = M.new_comment(attached_comments)
          token.lineinfo.first.comments = comments
          if self.lineinfo_last_extracted then
-            self.lineinfo_last_extracted.comments = comments 
+            self.lineinfo_last_extracted.comments = comments
          end
          attached_comments = { }
       end
@@ -317,10 +312,10 @@
 
        -- skip whitespaces
        self.i = self.src:match (self.patterns.spaces, self.i)
-       if self.i>#self.src then -- handle EOF
+       if self.i>#self.src then
          local fli = self.posfact :get_position (#self.src+1)
          local lli = self.posfact :get_position (#self.src+1) -- ok?
-         local tok = gen_token("Eof", "eof", new_lineinfo(fli, lli))
+         local tok = gen_token("Eof", "eof", M.new_lineinfo(fli, lli))
          tok.lineinfo.last.facing = lli
          return tok
        end
@@ -332,7 +327,7 @@
            if tag then
                local fli = self.posfact :get_position (i_first)
                local lli = self.posfact :get_position (self.i-1)
-               local lineinfo = new_lineinfo(fli, lli)
+               local lineinfo = M.new_lineinfo(fli, lli)
                if tag=='Comment' then
                    local prev_comment = attached_comments[#attached_comments]
                    if not xtra -- new comment is short
@@ -342,7 +337,7 @@
                        prev_comment[1] = prev_comment[1].."\n"..content -- TODO quadratic, BAD!
                        prev_comment.lineinfo.last = lli
                    else -- accumulate comment
-                       local comment = new_comment_line(content, lineinfo, xtra)
+                       local comment = M.new_comment_line(content, lineinfo, xtra)
                        table.insert(attached_comments, comment)
                    end
                    break -- back to skipping spaces
@@ -379,7 +374,7 @@
 ----------------------------------------------------------------------
 function lexer :extract_short_string()
    local k = self.src :sub (self.i,self.i)   -- first char
-   if k~=[[']] and k~=[["]] then return end  -- no match '
+   if k~=[[']] and k~=[["]] then return end  -- no match'
    local i = self.i + 1
    local j = i
    while true do
@@ -481,14 +476,14 @@
          local k = w:sub(1,1)
          local list = self.sym [k]
          if not list then list = { }; self.sym [k] = list end
-         _G.table.insert (list, w)
+         table.insert (list, w)
       elseif w:match "^%p$" then return
       else error "Invalid keyword" end
    end
 end
 
 ----------------------------------------------------------------------
--- Return the [n]th next token, without consumming it.
+-- Return the [n]th next token, without consuming it.
 -- [n] defaults to 1. If it goes pass the end of the stream, an EOF
 -- token is returned.
 ----------------------------------------------------------------------
@@ -512,11 +507,11 @@
    self :peek (n)
    local a
    for i=1,n do
-      a = _G.table.remove (self.peeked, 1) 
+      a = table.remove (self.peeked, 1) 
       -- TODO: is this used anywhere? I think not.  a.lineinfo.last may be nil.
       --self.lastline = a.lineinfo.last.line
    end
-   self.lineinfo_last = a.lineinfo.last
+   self.lineinfo_last_consumed = a.lineinfo.last
    return a
 end
 
@@ -524,7 +519,10 @@
 -- Returns an object which saves the stream's current state.
 ----------------------------------------------------------------------
 -- FIXME there are more fields than that to save
-function lexer :save () return { self.i; _G.table.cat(self.peeked) } end
+-- TODO  remove metalua.table dependency, used here to make a shallow copy
+-- of self.peeked, hash-part included. The hash-part seems unused,
+-- so { unpack(x) } should work OK.
+function lexer :save () return { self.i; table.cat(self.peeked) } end
 
 ----------------------------------------------------------------------
 -- Restore the stream's state, as saved by method [save].
@@ -576,7 +574,7 @@
 end
 
 function lexer :lineinfo_left()
-   return self.lineinfo_last
+   return self.lineinfo_last_consumed
 end
 
 ----------------------------------------------------------------------
@@ -588,16 +586,16 @@
       return setmetatable ({ }, self) :takeover (src_or_stream)
    elseif type(src_or_stream)=='string' then -- it's a source string
       local src = src_or_stream
-      local first_position = new_position(1, 1, 1, name) 
+      local pos1 = M.new_position(1, 1, 1, name)
       local stream = { 
          src_name      = name;   -- Name of the file
          src           = src;    -- The source, as a single string
          peeked        = { };    -- Already peeked, but not discarded yet, tokens
          i             = 1;      -- Character offset in src
          attached_comments = { },-- comments accumulator
-         lineinfo_last = first_position,           -- right boundary of last consummed token
-         lineinfo_last_extracted = first_position, -- right boundary of last extracted token
-         posfact       = new_position_factory (src_or_stream, name)
+         lineinfo_last_extracted = pos1,
+         lineinfo_last_consumed  = pos1,
+         posfact       = M.new_position_factory (src_or_stream, name)
       }
       setmetatable (stream, self)
 
@@ -638,7 +636,7 @@
    local function err ()
       error ("Got " .. tostring (a) .. 
              ", expected one of these keywords : '" ..
-             _G.table.concat (words,"', '") .. "'") end
+             table.concat (words,"', '") .. "'") end
           
    if not a or a.tag ~= "Keyword" then err () end
    if #words == 0 then return a[1] end
@@ -652,8 +650,9 @@
 -- 
 ----------------------------------------------------------------------
 function lexer :clone()
-   require 'metalua.runtime'
+   require 'metalua.table'
    local clone = {
+      -- TODO: remove metalua.table dependency
       alpha = table.deep_copy(self.alpha),
       sym   = table.deep_copy(self.sym) }
    setmetatable(clone, self)
@@ -671,3 +670,5 @@
     self.attached_comments = { }
     self.lineinfo_last = self.posfact :get_position (#self.src+1)
 end
+
+return M
\ No newline at end of file
diff --git a/lib/metalua/package2.lua b/metalua/package.lua
similarity index 63%
rename from lib/metalua/package2.lua
rename to metalua/package.lua
index d39f6c3..3bba351 100644
--- a/lib/metalua/package2.lua
+++ b/metalua/package.lua
@@ -1,4 +1,4 @@
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 -- Copyright (c) 2006-2013 Fabien Fleutot and others.
 --
 -- All rights reserved.
@@ -15,15 +15,16 @@
 -- Contributors:
 --     Fabien Fleutot - API and implementation
 --
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 
 local package = package
 
-require 'metalua.mlc'
+require 'metalua.table'
+require 'metalua.string'
 
 package.metalua_extension_prefix = 'metalua.extension.'
 
-package.mpath = os.getenv 'LUA_MPATH' or
+package.mpath = package.mpath or os.getenv 'LUA_MPATH' or
    './?.mlua;/usr/local/share/lua/5.1/?.mlua;'..
    '/usr/local/share/lua/5.1/?/init.mlua;'..
    '/usr/local/lib/lua/5.1/?.mlua;'..
@@ -59,29 +60,7 @@
       if file then return file, filename end
       table.insert(errors, string.format("\tno lua file %q", filename))
    end
-   return false, table.concat(errors, "\n")..'\n'
-end
-
-----------------------------------------------------------------------
--- Execute a metalua module sources compilation in a separate process
--- Sending back the bytecode directly is difficult, as some shells
--- (at least MS-Windows') interpret some characters. So rather than
--- base64-encoding the bytecode, AST is returned from the child
--- process, and converted to bytecode then function in the calling
--- process.
-----------------------------------------------------------------------
-local function spring_load(filename)
-   -- FIXME: handle compilation errors
-   local pattern = 
-      [=[lua -l metalua.compiler -l serialize -e ]=]..
-      [=["print(serialize(mlc.luafile_to_ast[[%s]]))"]=]
-   local cmd = string.format (pattern, filename)
-   --print ("running command: ``" .. cmd .. "''")
-   local fd = io.popen (cmd)
-   local ast_src = fd:read '*a'
-   fd:close()
-   local ast = lua_loadstring (ast_src) () -- much faster than loadstring()
-   return mlc.ast_to_function(ast, filename)
+   return false, '\n'..table.concat(errors, "\n")..'\n'
 end
 
 ----------------------------------------------------------------------
@@ -90,16 +69,10 @@
 function package.metalua_loader (name)
    local file, filename_or_msg = package.findfile (name, package.mpath)
    if not file then return filename_or_msg end
-   if package.metalua_nopopen then
-      local luastring = file:read '*a'
-      file:close()
-      return mlc.luastring_to_function (luastring, name)
-   else      
-      file:close()
-      require 'metalua.mlc_xcall'
-      local status, ast = mlc_xcall.client_file (filename_or_msg)
-      return mlc.ast_to_function(ast)
-   end
+   local luastring = file:read '*a'
+   file:close()
+   local mlc = require 'metalua.compiler'.new()
+   return mlc :src_to_function (luastring, name)
 end
 
 ----------------------------------------------------------------------
@@ -111,15 +84,12 @@
 ----------------------------------------------------------------------
 -- Load an extension.
 ----------------------------------------------------------------------
-function extension (name, noruntime)
-   local complete_name = package.metalua_extension_prefix..name
-   local x = require (complete_name)
-   if x==true then return
-   elseif type(x) ~= 'table' then
-      error ("extension returned %s instead of an AST", type(x))
-   else
-      return x
-   end
+function extension (name, mlp)
+    local complete_name = package.metalua_extension_prefix..name
+    -- TODO: pass mlp around
+    local extend_func = require (complete_name)
+    local ast =extend_func(mlp)
+    return ast
 end
 
 return package
diff --git a/lib/metalua/metaloop.mlua b/metalua/repl.mlua
similarity index 83%
rename from lib/metalua/metaloop.mlua
rename to metalua/repl.mlua
index 5e42f30..204482e 100644
--- a/lib/metalua/metaloop.mlua
+++ b/metalua/repl.mlua
@@ -17,20 +17,21 @@
 --
 -------------------------------------------------------------------------------
 
-require 'metalua.compiler'
-
-module ('metaloop', package.seeall)
-
+-- Keep these global:
 PRINT_AST  = true
 LINE_WIDTH = 60
 PROMPT     = "M> "
 PROMPT2    = ">> "
 
+local M = { }
+
+local readline
+
 do -- set readline() to a line reader, either editline otr a default
    local status, _ = pcall(require, 'editline')
    if status then
       local rl_handle = editline.init 'metalua'
-      readline = |p| rl_handle:read(p) 
+      readline = |p| rl_handle:read(p)
    else
       function readline (p)
          io.write (p)
@@ -40,14 +41,14 @@
    end
 end
 
-function reached_eof(lx, msg)
+local function reached_eof(lx, msg)
    return lx:peek().tag=='Eof' or msg:find "token `Eof"
 end
 
-printf ("Metalua, interactive REPLoop.\n"..
-        "(c) 2006-2011 <metalua@gmail.com>")
 
-function run()
+function M.run()
+    printf ("Metalua, interactive REPLoop.\n"..
+            "(c) 2006-2013 <metalua@gmail.com>")
    local lines = { }
    while true do
       local src, lx, ast, f, results, success
@@ -60,17 +61,17 @@
          table.insert(lines, line)
          src = table.concat (lines, "\n")
       until #line>0
-      
-      lx  = mlc.luastring_to_lexstream(src) 
-      success, ast = pcall(mlc.lexstream_to_ast, lx)
+
+      lx  = mlc :src_to_lexstream(src)
+      success, ast = pcall(mlc.lexstream_to_ast, mlc, lx)
       if success then
-         local check_status, check_msg = pcall(mlc.check_ast, ast)
+         local check_status, check_msg = pcall(check_ast, ast)
          if not check_status then
              print "Invalid AST:"
              print (check_msg)
              lines = { }
          else
-             success, f = pcall(mlc.ast_to_function, ast, '=stdin')
+             success, f = pcall(mlc.ast_to_function, mlc, ast, '=stdin')
              if success then
                  results = { xpcall(f, debug.traceback) }
                  success = table.remove (results, 1)
@@ -95,8 +96,10 @@
          if not reached_eof(lx, ast) then
             print "Can't compile source into AST:"
             print (ast)
-            lines = { } 
+            lines = { }
          end
       end
    end
-end
\ No newline at end of file
+end
+
+return M
\ No newline at end of file
diff --git a/lib/metalua/string2.lua b/metalua/string.lua
similarity index 100%
rename from lib/metalua/string2.lua
rename to metalua/string.lua
diff --git a/lib/metalua/table2.lua b/metalua/table.lua
similarity index 98%
rename from lib/metalua/table2.lua
rename to metalua/table.lua
index 653fd68..565f832 100644
--- a/lib/metalua/table2.lua
+++ b/metalua/table.lua
@@ -104,8 +104,8 @@
 
 function table.icat(...)
    local result = { }
-   for t in values {...} do
-      for x in values (t) do
+   for _, t in ipairs {...} do
+      for _, x in pairs (t) do
          table.insert (result, x)
       end
    end
@@ -152,7 +152,7 @@
 -- the fact the [next()] enumerates the array-part before the hash-part.
 function table.cat(...)
    local y={ }
-   for x in values{...} do
+   for _, x in ipairs{...} do
       -- cat array-part
       for _, v in ipairs(x) do table.insert(y,v) end
       -- cat hash-part
@@ -184,7 +184,6 @@
    return dst
 end
 
-
 function table.range(a,b,c)
    if not b then assert(not(c)); b=a; a=1
    elseif not c then c = (b>=a) and 1 or -1 end
@@ -193,7 +192,6 @@
    return result
 end
 
-
 -- FIXME: new_indent seems to be always nil?!
 -- FIXME: accumulator function should be configurable,
 -- so that print() doesn't need to bufferize the whole string
diff --git a/lib/metalua/treequery.mlua b/metalua/treequery.mlua
old mode 100644
new mode 100755
similarity index 92%
rename from lib/metalua/treequery.mlua
rename to metalua/treequery.mlua
index 5925471..c1f9f84
--- a/lib/metalua/treequery.mlua
+++ b/metalua/treequery.mlua
@@ -74,7 +74,7 @@
         from_up     = { },

         up_f        = false,

         down_f      = false,

-        filters     = { }

+        filters     = { },

     }, Q)

 end

 

@@ -265,10 +265,11 @@
     if #args==1 then

         local tag = ...

         return (|node| node.tag==tag)

+        --return function(self, node) printf("node %s has_tag %s?", table.tostring(node), tag); return node.tag==tag end

     else

         local tags = { }

         for _, tag in ipairs(args) do tags[tag]=true end

-        return function(node)

+        return function(self, node)

             local node_tag = node.tag

             return node_tag and tags[node_tag]

         end

@@ -287,7 +288,7 @@
 --- Predicate to test whether a node represents a statement.

 --  It is context-aware, i.e. it recognizes `Call and `Invoke nodes

 --  used in a statement context as such.

-function M.is_stat(node, parent)

+function M.is_stat(self, node, parent)

     local tag = node.tag

     if not tag then return false

     elseif STAT_TAGS[tag] then return true

@@ -296,7 +297,7 @@
 end

 

 --- Predicate to test whether a node represents a statements block.

-function M.is_block(node) return node.tag==nil end

+function M.is_block(self, node) return node.tag==nil end

 

 -- -----------------------------------------------------------------------------

 -- -----------------------------------------------------------------------------

@@ -322,11 +323,7 @@
    return false

 end

 

---- Retrieve the binder associated to an occurrence within root.
---
--- Each call to this function might cause a traversal of the whole
--- `root` tree. For use inside a query method, prefer `treequery.get_binder`.
---

+--- Retrieve the binder associated to an occurrence within root.

 --  @param occurrence an Id node representing an occurrence in `root`.

 --  @param root the tree in which `node` and its binder occur.

 --  @return the binder node, and its ancestors up to root if found.

@@ -341,12 +338,25 @@
     return unpack(result)

 end

 

+--- Predicate to filter occurrences of a given binder.

+--  Warning: it relies on internal scope book-keeping,

+--  and for this reason, it only works as query method argument.

+--  It won't work outside of a query.

+--  @param binder the binder whose occurrences must be kept by predicate

+--  @return a predicate

 

---- Return a predicate testing whether a node is an occurrence of the 

---  given binder.

---

--- Caveat: only works in a treequery method.

---

+-- function M.is_occurrence_of(binder)

+--     return function(node, ...)

+--         if node.tag ~= 'Id' then return nil end

+--         if M.is_binder(node, ...) then return nil end

+--         local scope = ACTIVE_SCOPE[node]

+--         if not scope then return nil end

+--         local result = scope :get (node[1]) or { }

+--         if result[1] ~= binder then return nil end

+--         return unpack(result)

+--     end

+-- end

+

 function M.is_occurrence_of(binder)

     return function(node, ...)

         local b = M.get_binder(node)

@@ -354,12 +364,6 @@
     end

 end

 

---- Return the binder which captures this occurence of a variable if applicable;

---  return `nil` if the variable is a binder or a free variable

---

---  Caveat: this only works in arguments of query methods.

---  Out of a query, use `treequery.binder()`.

---

 function M.get_binder(occurrence, ...)

     if occurrence.tag ~= 'Id' then return nil end

     if M.is_binder(occurrence, ...) then return nil end

@@ -381,7 +385,7 @@
     if type(a)~='number' then n, pred = 2, n end

     if type(pred)=='string' then pred = M.has_tag(pred, ...) end

     return function(self, ...)

-        return select(n, ...) and pred(select(n, ...))

+        return select(n, ...) and pred(self, select(n, ...))

     end

 end

 

@@ -414,7 +418,7 @@
 --  @return a predicate

 function M.is_nth(a, b)

     b = b or a

-    return function(node, parent)

+    return function(self, node, parent)

         if not parent then return false end

         local nchildren = #parent

         local a = a<=0 and nchildren+a+1 or a

diff --git a/lib/metalua/treequery/walk.mlua b/metalua/treequery/walk.mlua
old mode 100644
new mode 100755
similarity index 96%
rename from lib/metalua/treequery/walk.mlua
rename to metalua/treequery/walk.mlua
index 9d35e46..2e10956
--- a/lib/metalua/treequery/walk.mlua
+++ b/metalua/treequery/walk.mlua
@@ -48,7 +48,7 @@
 --

 -- corresponding walk.xxx functions also take care of calling cfg callbacks.

 

--{ extension "match" }

+-{ extension ("match",...) }

 

 local M = { traverse = { }; tags = { }; debug = false }

 

@@ -80,7 +80,7 @@
    local CS = || cfg.scope :restore()                          -- Close scope

 

    match x with

-   | {...} if x.tag == nil -> for y in ivalues(x) do M.stat(cfg, y, ...) end

+   | {...} if x.tag == nil -> for _, y in ipairs(x) do M.stat(cfg, y, ...) end

                           -- no tag --> node not inserted in the history ancestors

    | `Do{...}                    -> OS(x); for _, y in ipairs(x) do S(y) end; CS(x) 

    | `Set{ lhs, rhs }            -> EL(lhs); EL(rhs)

@@ -139,16 +139,16 @@
 end

 

 function M.traverse.block (cfg, x, ...)

-   assert(type(x)=='table', "traverse.block() expects a table")

+   assert(type(x)=='table', "traverse.block() expects a table")
    if x.tag then M.malformed(cfg, x, ...)

-   else for y in ivalues(x) do M.stat(cfg, y, x, ...) end

+   else for _, y in ipairs(x) do M.stat(cfg, y, x, ...) end
    end

 end

 

 function M.traverse.expr_list (cfg, x, ...)

    assert(type(x)=='table', "traverse.expr_list() expects a table")

    -- x doesn't appear in the ancestors

-   for y in ivalues(x) do M.expr(cfg, y, ...) end

+   for _, y in ipairs(x) do M.expr(cfg, y, ...) end

 end

 

 function M.malformed(cfg, x, ...)

@@ -169,7 +169,7 @@
     if cfg.occurrence then cfg.occurrence(cfg.scope :get(x[1]),  x, ...) end

 end

 

--- TODO: Is it useful to call each error handling function

+-- TODO: Is it useful to call each error handling function?

 function M.binder_list (cfg, id_list, ...)

     local f = cfg.binder

     local ferror = cfg.error or cfg.malformed or cfg.unknown

@@ -209,7 +209,7 @@
 ----------------------------------------------------------------------

 -- Declare [M.stat], [M.expr], [M.block] and [M.expr_list]

 ----------------------------------------------------------------------

-for w in values{ "stat", "expr", "block" } do --, "malformed", "unknown" } do

+for _, w in ipairs{ "stat", "expr", "block" } do --, "malformed", "unknown" } do

    M[w] = walker_builder (w, M.traverse[w])

 end

 

@@ -246,4 +246,4 @@
 function S :get (var_name) return self.current[var_name] end

 function S :set (key, val) self.current[key] = val end

 

-return M

+return M
diff --git a/lib/metalua/walk.mlua b/metalua/walk.mlua
similarity index 91%
rename from lib/metalua/walk.mlua
rename to metalua/walk.mlua
index 6c13fb9..139474f 100644
--- a/lib/metalua/walk.mlua
+++ b/metalua/walk.mlua
@@ -17,7 +17,9 @@
 --
 -------------------------------------------------------------------------------
 
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
+-- Code walkers
+--
 -- This library offers a generic way to write AST transforming
 -- functions. Macros can take bits of AST as parameters and generate a
 -- more complex AST with them; but modifying an AST a posteriori is
@@ -163,16 +165,16 @@
 -- { stat = f1, expr = { up = f1 } }
 --
 --
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
 
--{ extension "match" }
+-{ extension ('match', ...) }
 
 walk = { traverse = { }; tags = { }; debug = false }
 
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
 -- Standard tags: can be used to guess the type of an AST, or to check
 -- that the type of an AST is respected.
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
 walk.tags.stat = table.transpose{ 
    'Do', 'Set', 'While', 'Repeat', 'Local', 'Localrec', 'Return',
    'Fornum', 'Forin', 'If', 'Break', 'Goto', 'Label',
@@ -193,14 +195,14 @@
 function walk.traverse.stat (cfg, x, ...)
    if walk.debug then printf("traverse stat %s", table.tostring(x)) end
    local log = {...}
-   local B    = |y| walk.block       (cfg, y, x, unpack(log))
-   local S    = |y| walk.stat        (cfg, y, x, unpack(log))
-   local E    = |y| walk.expr        (cfg, y, x, unpack(log))
-   local EL   = |y| walk.expr_list   (cfg, y, x, unpack(log))
-   local I    = |y| walk.binder_list (cfg, y, x, unpack(log))
-   local DOWN = || scope(cfg, 'down')
-   local UP   = || scope(cfg, 'up')
-   local function BS(y) DOWN(); B(y); UP() end
+   local B  = |y| walk.block       (cfg, y, x, unpack(log))
+   local S  = |y| walk.stat        (cfg, y, x, unpack(log))
+   local E  = |y| walk.expr        (cfg, y, x, unpack(log))
+   local EL = |y| walk.expr_list   (cfg, y, x, unpack(log))
+   local I  = |y| walk.binder_list (cfg, y, x, unpack(log))
+   local function BS(y)
+      scope (cfg, 'down'); B(y); scope (cfg, 'up')
+   end
 
    match x with
    | {...} if x.tag == nil -> for y in ivalues(x) do walk.stat(cfg, y, ...) end
@@ -208,13 +210,13 @@
    | `Do{...}                    -> BS(x)
    | `Set{ lhs, rhs }            -> EL(lhs); EL(rhs)
    | `While{ cond, body }        -> E(cond); BS(body)
-   | `Repeat{ body, cond }       -> DOWN(); B(body); E(cond); UP()
+   | `Repeat{ body, cond }       -> scope(cfg, 'down'); B(body); E(cond); scope(cfg, 'up')
    | `Local{ lhs }               -> I(lhs)
    | `Local{ lhs, rhs }          -> EL(rhs); I(lhs)
    | `Localrec{ lhs, rhs }       -> I(lhs); EL(rhs)
-   | `Fornum{ i, a, b, body }    -> E(a); E(b); DOWN(); I{i}; B(body); UP()
+   | `Fornum{ i, a, b, body }    -> E(a); E(b); I{i}; BS(body)
    | `Fornum{ i, a, b, c, body } -> E(a); E(b); E(c); I{i}; BS(body)
-   | `Forin{ i, rhs, body }      -> EL(rhs); DOWN(); I(i); B(body); UP()
+   | `Forin{ i, rhs, body }      -> EL(rhs); I(i); BS(body)
    | `If{...}                    -> for i=1, #x-1, 2 do E(x[i]); BS(x[i+1]) end
                                     if #x%2 == 1 then BS(x[#x]) end
    | `Call{...}|`Invoke{...}|`Return{...} -> EL(x)
@@ -234,15 +236,13 @@
    local E  = |y| walk.expr        (cfg, y, x, unpack(log))
    local EL = |y| walk.expr_list   (cfg, y, x, unpack(log)) 
    local I  = |y| walk.binder_list (cfg, y, x, unpack(log))
-   local DOWN = || scope(cfg, 'down')
-   local UP   = || scope(cfg, 'up')
    match x with
    | `Paren{ e }               -> E(e)
    | `Call{...} | `Invoke{...} -> EL(x)
    | `Index{ a, b }            -> E(a); E(b)
    | `Op{ opid, ... }          -> E(x[2]); if #x==3 then E(x[3]) end
-   | `Function{ params, body } -> DOWN(); I(params); B(body); UP()
-   | `Stat{ b, e }             -> DOWN(); B(b); E(e); UP()
+   | `Function{ params, body } -> I(params); scope(cfg, 'down'); B(body); scope (cfg, 'in')
+   | `Stat{ b, e }             -> scope(cfg, 'down'); B(b); E(e); scope (cfg, 'in')
    | `Table{ ... }             ->
       for i = 1, #x do match x[i] with
          | `Pair{ k, v } -> E(k); E(v)
@@ -258,13 +258,13 @@
 
 function walk.traverse.block (cfg, x, ...)
    assert(type(x)=='table', "traverse.block() expects a table")
-   for y in ivalues(x) do walk.stat(cfg, y, x, ...) end
+   for _, y in ipairs(x) do walk.stat(cfg, y, x, ...) end
 end
 
 function walk.traverse.expr_list (cfg, x, ...)
    assert(type(x)=='table', "traverse.expr_list() expects a table")
    -- x doesn't appear in the log
-   for y in ivalues(x) do walk.expr(cfg, y, ...) end
+   for _, y in ipairs(x) do walk.expr(cfg, y, ...) end
 end
 
 
@@ -312,7 +312,7 @@
 ----------------------------------------------------------------------
 -- Declare [walk.stat], [walk.expr], [walk.block] and [walk.expr_list]
 ----------------------------------------------------------------------
-for w in values{ "stat", "expr", "block", "expr_list" } do
+for _, w in ipairs{ "stat", "expr", "block", "expr_list" } do
    walk[w] = walker_builder (w, walk.traverse[w])
 end
 
@@ -321,7 +321,7 @@
 ----------------------------------------------------------------------
 function walk.binder_list (cfg, x, ...)
    local f = cfg.binder 
-   if f then for v in ivalues(x) do f(v, ...) end end
+   if f then for _, v in ipairs(x) do f(v, ...) end end
 end
 
 ----------------------------------------------------------------------
@@ -334,3 +334,5 @@
    if not x.tag             then return walk.block(cfg, x, ...) end
    error ("Can't guess the AST type from tag "..(x.tag or '<none>')) 
 end
+
+return walk
diff --git a/metalua/walk/bindings.lua b/metalua/walk/bindings.lua
new file mode 100644
index 0000000..33ae4e1
--- /dev/null
+++ b/metalua/walk/bindings.lua
@@ -0,0 +1,55 @@
+--------------------------------------------------------------------------------
+-- Copyright (c) 2006-2013 Fabien Fleutot and others.
+--
+-- All rights reserved.
+--
+-- This program and the accompanying materials are made available
+-- under the terms of the Eclipse Public License v1.0 which
+-- accompanies this distribution, and is available at
+-- http://www.eclipse.org/legal/epl-v10.html
+--
+-- This program and the accompanying materials are also made available
+-- under the terms of the MIT public license which accompanies this
+-- distribution, and is available at http://www.lua.org/license.html
+--
+-- Contributors:
+--     Fabien Fleutot - API and implementation
+--
+--------------------------------------------------------------------------------
+
+local W = require 'metalua.treequery.walk'
+
+local function bindings(ast)
+	local cfg     = { }
+	local locals  = { }
+	local globals = { }
+
+	function cfg.occurrence(binding_ctx, id_occ, ...)
+		if binding_ctx then
+			local binder = binding_ctx[2]
+			local id_name = id_occ[1]
+			if not locals[binder][id_name] then
+				locals[binder][id_name] = {}
+			end
+			table.insert(locals[binder][id_name], id_occ)
+		else
+			local occ_name = id_occ[1]
+			local t = globals[occ_name]
+			if t then table.insert(t, id_occ) else globals[occ_name]={ id_occ } end
+		end	
+	end
+
+	function cfg.binder(id, stat, ...)
+		local id_name = id[1]
+		if not locals[stat] then
+			locals[stat] = {}
+		end
+		if not locals[stat][id_name] then
+			locals[stat][id_name] = {}
+		end
+	end
+	W.guess(cfg, ast)
+	return locals, globals
+end
+
+return bindings
diff --git a/lib/metalua/walk/id.mlua b/metalua/walk/id.mlua
similarity index 96%
rename from lib/metalua/walk/id.mlua
rename to metalua/walk/id.mlua
index 9ad40c4..52eabe5 100644
--- a/lib/metalua/walk/id.mlua
+++ b/metalua/walk/id.mlua
@@ -17,7 +17,7 @@
 --
 -------------------------------------------------------------------------------
 
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
 --
 -- This library walks AST to gather information about the identifiers
 -- in it. It classifies them between free variables and bound
@@ -60,10 +60,10 @@
 -- * `Splice must stop the walking, so that user code won't be
 --   converted
 --
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
 
--{ extension 'match' }
--{ extension 'log' }
+-{ extension ('match', ...) }
+-- -{ extension ('log', ...) }
 
 require 'metalua.walk'
 require 'metalua.walk.scope'
@@ -124,7 +124,7 @@
          -- by returning 'break'.
          -------------------------------------------------------------
          scope:push()
-         for stat in values (block) do walk.stat(cfg, stat, x, ...) end 
+         for _, stat in ipairs (block) do walk.stat(cfg, stat, x, ...) end 
          walk.expr(cfg, expr, x, unpack(parents))
          scope:pop()
          return 'break'
@@ -162,7 +162,7 @@
          -- by returning 'break'.
          -------------------------------------------------------------
          scope:push() 
-         for stat in values (block) do walk.stat(cfg, stat, x, ...) end 
+         for _, stat in ipairs (block) do walk.stat(cfg, stat, x, ...) end 
          walk.expr(cfg, expr, x, ...)
          scope:pop()
          return 'break'
diff --git a/lib/metalua/walk/scope.lua b/metalua/walk/scope.lua
similarity index 98%
rename from lib/metalua/walk/scope.lua
rename to metalua/walk/scope.lua
index 856917b..29d9402 100644
--- a/lib/metalua/walk/scope.lua
+++ b/metalua/walk/scope.lua
@@ -17,7 +17,7 @@
 --
 -------------------------------------------------------------------------------
 
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
 --
 -- Scopes: this library helps keeping track of identifier scopes,
 -- typically in code walkers.
@@ -41,7 +41,7 @@
 -- * s.current is the current scope, a table with variable names as
 --   keys and their associated value val (or 'true') as value.
 --
---------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
 
 scope = { }
 scope.__index = scope
diff --git a/samples/clist_test.mlua b/samples/clist_test.mlua
deleted file mode 100644
index 804b786..0000000
--- a/samples/clist_test.mlua
+++ /dev/null
@@ -1,39 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{extension "clist"}
-
--- integers from 2 to 50, by steps of 2:
-x = { i for i = 2, 50, 2 }
-
--- the same, obtained by filtering over all integers <= 50:
-y = { i for i = 1, 50 if i%2==0 }
-
--- prime numbers, implemented in an inefficient way:
-local sieve, n = { i for i=2, 100 }, 1
-while n < #sieve do
-   sieve = { 
-      i for i in values(sieve[1 ... n]);
-      i for i in values(sieve[n+1 ... #sieve]) if i%sieve[n] ~= 0 }
-   n += 1
-end
-
-print "Prime numbers < 100, computed with lists by comprehension:"
-table.print(sieve)
-
diff --git a/samples/h_test.mlua b/samples/h_test.mlua
deleted file mode 100644
index 7923884..0000000
--- a/samples/h_test.mlua
+++ /dev/null
@@ -1,79 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{ extension 'log' }
--{ extension  'H'  }
-
-require 'metalua.compiler'
-
-TEST_CASES = { 
-
-   {  "everything should be renamed",
-      +{ block: 
-         local x = 3
-         print(x) },
-      { } }, 
-
-  {  "don't get confused between global and local x",
-     +{ block: 
-        print(x)
-        local x = 3
-        print(x) },
-     { alpha = { } } },
-
-  {  "don't rename keepme",
-     +{ block:
-        keepme()
-        dont_keep_me() },
-     { keep = 'keepme' , alpha = `Local{ { }, { } } } },
- 
-  {  "print shouldn't be renamed the 2nd and 3rd time",
-     +{ block:
-        print(i)
-        -{!`Call{`Id 'print', `String 'hi' } } 
-        -{!+{print 'hi'}} },
-     { } },
- 
-  {  "print shouldn't be renamed at all",
-     +{ block: 
-        print(i)
-        -{`Call{`Id 'print', `String 'hi' } }
-        -{+{print 'hi'}} },
-     { keep = 'print' } },
- 
-  {  "Rename print with a pre-specified name, rename x freely, not y",
-     +{ block: 
-        print (x, y) },
-     {  alpha = +{stat: local RENAMED_PRINT = print}, 
-        keep  = {y = true} } } } 
-
-for case in ivalues(TEST_CASES) do
-   local comment, ast, cfg = unpack(case)
-   print ('\n'..'-':rep(70))
-   print (comment)
-   local H = H:new(cfg)
-   print ("\nBEFORE PARSING:")
-   $log (ast, H, 50)
-   H(ast)
-   print ("\nAFTER PARSING:")
-   $log (ast, H, 50)
-end
-
-print ('\n'..'=':rep(70))
-$log(TEST_CASES,40)
\ No newline at end of file
diff --git a/samples/h_test2.mlua b/samples/h_test2.mlua
deleted file mode 100644
index ee9f64d..0000000
--- a/samples/h_test2.mlua
+++ /dev/null
@@ -1,44 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{ block:
-   -{ extension 'log' }
-   -{ extension 'H' }
-
-   require 'metalua.dollar'
-
-   local H = H:new()
-   print("initial H.alpha", H.alpha)
-
-
-   function dollar.Q(cond, iftrue, iffalse)
-      local b = +{ block: 
-                   local v 
-                   if -{!cond} then v = -{!iftrue}
-                   else v = -{!iffalse} end }
-      local r = `Stat{ b, +{v} }
-      H(r)
-      return r
-   end 
-
-   $log(H)
-   return H.alpha }
-
-x=1 ; y=$Q(x==1, 'one', 'two') ; print(y)
-x=2 ; y=$Q(x==1, 'one', 'two') ; print(y)
\ No newline at end of file
diff --git a/samples/hello_world.mlua b/samples/hello_world.mlua
deleted file mode 100644
index 48cb7eb..0000000
--- a/samples/hello_world.mlua
+++ /dev/null
@@ -1,26 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--- The message numbered (1) will display at compilation, i.e. before
--- (2) is displayed (supposing that compilation and execution are
--- both requested)
-
-print "(2) This is a runtime message: Hello world!"
--{ print "(1) This is a compile-time message: Hello world!" }
-
diff --git a/samples/ifexpr.mlua b/samples/ifexpr.mlua
deleted file mode 100644
index c6ca15a..0000000
--- a/samples/ifexpr.mlua
+++ /dev/null
@@ -1,161 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-----------------------------------------------------------------------------------
--- This samples walks you through the writing of a simple extension.
---
--- Lua makes a difference between statements and expressions, and it's sometimes
--- cumbersome to put a statement where an expression is expected. Among others,
--- if-then-else constructs are statements, so you cannot write:
---
--- > local foo = if bar then 1 else 2
---
--- Indeed, an expression is expected at the right of the equal, and "if ..." is
--- a statement, which expects nested statements as "then" and "else" clauses.
--- The example above must therefore be written:
---
--- > local foo
--- > if bar then foo=1 else foo=2 end
---
---
--- Let's allow if-then-[elseif*]-[else] constructs to be used in an expression's
--- context. In such a context, 'then' and 'else' are expected to be followed by
--- expressions, not statement blocks.
---
--- Stuff you probably need to understand, at least summarily, to follow this
--- code:
--- * Lua syntax
--- * the fact that -{ ... } switches metalua into compile time mode
--- * mlp, the dynamically extensible metalua parser, which will be extended with
---   the new construct at compile time.
--- * gg, the grammar generator that allows to build and extend parsers, and with
---   which mlp is implemented.
--- * the fact that code can be interchangeably represented as abstract syntax
---   trees with `Foo{ bar } notations (easy to manipulate) or as quotes inside a
---   +{ ... } (easy to read).
---
-----------------------------------------------------------------------------------
-
-
-----------------------------------------------------------------------------------
--- How to turn this file in a proper syntax extension.
--- ===================================================
---
--- To turn this example's metalevel 0 code into a regular extension:
--- * Put everything inside the -{block: ... } in a separate .mlua file;
--- * save it in a directory called 'extension', which is itself
---   in your $LUA_MPATH. For instance, if your $LUA_MPATH contains
---   '~/local/metalua/?.mlua', you can save it as 
---   '~/local/metalua/extension-compiler/ifexpr.mlua'
--- * Load the extension with "-{ extension 'ifexpr' }", whenever you want to
---   use it.
-----------------------------------------------------------------------------------
-
--{ block: -- Enter metalevel 0, where we'll start hacking the parser.
-
-   -------------------------------------------------------------------------------
-   -- Most extension implementations are cut in two parts: a front-end which
-   -- parses the syntax into some custom tree, and a back-end which turns that
-   -- tree into a compilable AST. Since the front-end calls the back-end, the
-   -- later has to be declared first.
-   -------------------------------------------------------------------------------
-
-   -------------------------------------------------------------------------------
-   -- Back-end:
-   -- =========
-   -- This is the builder that turns the parser's result into an expression AST.
-   -- Local vars:
-   -- -----------
-   -- elseifthen_list : list of { condition, expression_if_true } pairs,
-   -- opt_else:         either the expression in the 'else' final clause if any,
-   --                   or false if there's no else clause.
-   -- v:                the variable in which the result will be stored.
-   -- ifstat:           the if-then-else statement that will be generated from
-   --                   then if-then-else expression, then embedded in a `Stat{}
-   --
-   -- The builder simply turns all expressions into blocks, so that they fit in
-   -- a regular if-then-else statement. Then the resulting if-then-else is
-   -- embedded in a `Stat{ } node, so that it can be placed where an expression
-   -- is expected.
-   --
-   -- The variable in which the result is stored has its name generated by
-   -- mlp.gensym(). This way we're sure there will be no variable capture.
-   -- When macro hygiene problems are more complex, it's generally a good
-   -- idea to give a look at the extension 'H'.
-   -------------------------------------------------------------------------------
-   local function builder (x)
-      local elseifthen_list, opt_else = unpack (x)
-
-      local v = mlp.gensym 'ife' -- the selected expr will be stored in this var.
-      local ifstat = `If{ }
-      for y in ivalues (elseifthen_list) do
-         local cond, val = unpack (y)
-         table.insert (ifstat, cond)
-         table.insert (ifstat, { `Set{ {v}, {val} } }) -- change expr into stat.
-      end
-      if opt_else then -- the same for else clause, except that there's no cond.
-         table.insert (ifstat, { `Set{ {v}, {opt_else} } })
-      end
-      return `Stat{ +{block: local -{v}; -{ifstat}}, v }
-   end
-
-   -------------------------------------------------------------------------------
-   -- Front-end:
-   -- ==========
-   -- This is mostly the same as the regular if-then-else parser, except that:
-   -- * it's added to the expression parser, not the statement parser;
-   -- * blocks after conditions are replaced by exprs;
-   --
-   -- In Lua, 'end' traditionally terminates a block, not an
-   -- expression. Should there be a 'end' to respect if-then-else
-   -- usual syntax, or should there be none, to respect usual implicit
-   -- expression ending? I chose not to put an 'end' here, but other people
-   -- might have other tastes...
-   -------------------------------------------------------------------------------
-   mlp.expr:add{ name = 'if-expression',
-      'if',
-      gg.list { gg.sequence{mlp.expr, "then", mlp.expr}, separators="elseif" },
-      gg.onkeyword{ 'else', mlp.expr }, 
-      builder = builder } 
-
-} -- Back to metalevel 1, with the new feature enabled
-
-local foo, bar
-
-------------------------------------------------------------
--- The parser will read this as:
---    { { { `Id 'foo', `Number 1 }, 
---        { `Id 'bar', `Number 2 } }, 
---      `Number 3 },
--- then feed it to 'builder', which will turn it into an AST
-------------------------------------------------------------
-
-local x = if false then 1 elseif bar then 2 else 3
-
-------------------------------------------------------------
--- The result after builder will be:
---    `Stat{ +{block: local $v$
---                    if     foo then $v$ = 1
---                    elseif bar then $v$ = 2
---                    else            $v$ = 3
---                    end }, `Id "$v$" }
-------------------------------------------------------------
-
-assert (x == 3)
-print "It seems to work..."
\ No newline at end of file
diff --git a/samples/lex_switch_test.mlua b/samples/lex_switch_test.mlua
deleted file mode 100644
index 4c79709..0000000
--- a/samples/lex_switch_test.mlua
+++ /dev/null
@@ -1,59 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--- This is a simple and somewhat stupid example of how to switch
--- lexers dynamically. Behind a V, X and Y are the only reserved
--- keywords. In normal conditions, X and Y aren't keywords and can be
--- used as variables.
-
--{ block:
-   require 'lexer'
-   local my_lexer = lexer.lexer:clone() -- no keywords
-   my_lexer:add{"X", "Y"}
-   mlp.lexer:add "V"
-
-   function num(lx)
-      local a = lx:next()
-      assert(a.tag=='Number')
-      return a
-   end
-      
-   my_parser = gg.list{
-      gg.multisequence{
-         { "X", num, builder = |x| `Table{ x[1], +{0} } },
-         { "Y", num, builder = |y| `Table{ +{0}, y[1] } },
-         default = gg.sequence{ mlp.id, builder = |x| `Pair{ `String{x[1][1]},`True } } },
-      separators = { ',', ';' },
-      builder = function(l) l.tag='Table'; return l end }
-
-   mlp.expr:add{ "V", gg.with_lexer(my_lexer, my_parser), builder = unpack } }
-
--- Use the special lexer:
-foo = V X 1, Y 2, X 3, 
-      for, foo, in, tag, function -- check that these aren't keywords in my_lexer
-
--- Use X and Y as Id, in the unpolluted lexer:
-print "Vector:"
-X = table.tostring(foo, 60)
-print (X)
-
-print "Sum:" -- Ready for a functional one-liner? :)
-Y = |v| table.ifold (|a,b| table.imap (|c,d| c+d, a, b), {0,0}, v) 
-table.print (Y(foo))
-
diff --git a/samples/match_test.mlua b/samples/match_test.mlua
deleted file mode 100644
index 4eff225..0000000
--- a/samples/match_test.mlua
+++ /dev/null
@@ -1,105 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{extension 'match'}
-
-WIDTH = 50
-function p(msg)
-   io.write(msg, ' ':rep(WIDTH-#msg))
-   io.flush()
-end
-
-p "Basic match"
-match 1 with 1 -> print 'ok' end
-
-p "Sequence match"
-match 3, 4 with 
-| 1, 2 -> print 'KO'
-| 3, 4 -> print 'ok' 
-end
-
-p "Id binding"
-match 3, 4 with 
-| 1, 2 -> print 'KO'
-| x, y -> print 'ok' 
-end
-
-p "Table destructuring & non-litteral tested term"
-match {1, 2} with
-|{a, 2} -> assert(a==1); print 'ok'
-end
-
-p "Pattern group"
-match {'?'} with
-|1|2|3 -> print 'KO'
-|{...} -> print 'ok'
-end
-
-p "Multi-level destructuring"
-match {{1000}} with
-|{{2000}} -> print 'KO'
-|{{3000}} -> print 'KO'
-|{{1000}} -> print 'ok'
-end
-
-p "Guard"
-match 1 with
-| 1 if false -> print 'KO'
-| 1 -> print 'ok'
-end
-
-p "Guard with bound var"
-match 1 with
-| a if a ~= 1 -> print 'KO'
-| a if a == 1 -> print 'ok'
-end
-
-p "Non linear var & destructuring"
-match {1, {2}} with
-| {a, {a}} -> print 'KO'
-| {a, {b}} -> print 'ok'
-end
-
-p "Non-linear vars on a sequence"
-match 1, 2 with
-| a, a -> print 'KO'
-| a, b -> print 'ok'
-end
-
-p "Multiple _ wildcards"
-match 1, 2 with
-| _, _ -> print 'ok'
-| a, b -> print 'KO'
-end
-
-p "Regexp & non-linear vars"
-match 'toto' with
-| 't(.)t(.)' / { a, a } -> print (a..'k')
-end
-
-p "Nested match & ..."
-match { { 'o', 'k', '!' } } with
-| { t } -> match t with
-   | { a, b }      -> print 'KO'
-   | { a, b, ... } -> print (a..b)
-   | _             -> print 'KO'
-   end
-| _ -> print 'KO'
-end
-
diff --git a/samples/synth.mlua b/samples/synth.mlua
deleted file mode 100644
index 880fc3a..0000000
--- a/samples/synth.mlua
+++ /dev/null
@@ -1,579 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-require 'strict'
-
--{ extension 'match' }
-
-synth = { }
-synth.__index = synth
-
---------------------------------------------------------------------------------
--- Instanciate a new AST->source synthetizer
---------------------------------------------------------------------------------
-function synth.new ()
-   local self = {
-      _acc           = { },  -- Accumulates pieces of source as strings
-      current_indent = 0,    -- Current level of line indentation
-      indent_step    = "   " -- Indentation symbol, normally spaces or '\t'
-   }
-   return setmetatable (self, synth)
-end
-
---------------------------------------------------------------------------------
--- Run a synthetizer on the `ast' arg and return the source as a string.
--- Can also be used as a static method `synth.run (ast)'; in this case,
--- a temporary synthetizer is instanciated on the fly.
---------------------------------------------------------------------------------
-function synth:run (ast)
-   if not ast then
-      self, ast = synth.new(), self
-   end
-   self._acc = { }
-   self:node (ast)
-   return table.concat (self._acc)
-end
-
---------------------------------------------------------------------------------
--- Accumulate a piece of source file in the synthetizer.
---------------------------------------------------------------------------------
-function synth:acc (x)
-   if x then table.insert (self._acc, x) end
-end
-
---------------------------------------------------------------------------------
--- Accumulate an indented newline.
--- Jumps an extra line if indentation is 0, so that
--- toplevel definitions are separated by an extra empty line.
---------------------------------------------------------------------------------
-function synth:nl ()
-   if self.current_indent == 0 then self:acc "\n"  end
-   self:acc ("\n" .. self.indent_step:rep (self.current_indent))
-end
-
---------------------------------------------------------------------------------
--- Increase indentation and accumulate a new line.
---------------------------------------------------------------------------------
-function synth:nlindent ()
-   self.current_indent = self.current_indent + 1
-   self:nl ()
-end
-
---------------------------------------------------------------------------------
--- Decrease indentation and accumulate a new line.
---------------------------------------------------------------------------------
-function synth:nldedent ()
-   self.current_indent = self.current_indent - 1
-   self:acc ("\n" .. self.indent_step:rep (self.current_indent))
-end
-
---------------------------------------------------------------------------------
--- Keywords, which are illegal as identifiers.
---------------------------------------------------------------------------------
-local keywords = table.transpose {
-   "and",    "break",   "do",    "else",   "elseif",
-   "end",    "false",   "for",   "function", "if",
-   "in",     "local",   "nil",   "not",    "or",
-   "repeat", "return",  "then",  "true",   "until",
-   "while" }
-
---------------------------------------------------------------------------------
--- Return true iff string `id' is a legal identifier name.
---------------------------------------------------------------------------------
-local function is_ident (id)
-   return id:strmatch "^[%a_][%w_]*$" and not keywords[id]
-end
-
---------------------------------------------------------------------------------
--- Return true iff ast represents a legal function name for
--- syntax sugar ``function foo.bar.gnat() ... end'':
--- a series of nested string indexes, with an identifier as
--- the innermost node.
---------------------------------------------------------------------------------
-local function is_idx_stack (ast)
-   match ast with
-   | `Id{ _ }                     -> return true
-   | `Index{ left, `String{ _ } } -> return is_idx_stack (left)
-   | _                            -> return false
-   end
-end
-
---------------------------------------------------------------------------------
--- Operator precedences, in increasing order.
--- This is not directly used, it's used to generate op_prec below.
---------------------------------------------------------------------------------
-local op_preprec = {
-   { "or", "and" },
-   { "lt", "le", "eq", "ne" },
-   { "concat" }, 
-   { "add", "sub" },
-   { "mul", "div", "mod" },
-   { "unary", "not", "len" },
-   { "pow" },
-   { "index" } }
-
---------------------------------------------------------------------------------
--- operator --> precedence table, generated from op_preprec.
---------------------------------------------------------------------------------
-local op_prec = { }
-
-for prec, ops in ipairs (op_preprec) do
-   for op in ivalues (ops) do
-      op_prec[op] = prec
-   end
-end
-
---------------------------------------------------------------------------------
--- operator --> source representation.
---------------------------------------------------------------------------------
-local op_symbol = {
-   add    = " + ",   sub     = " - ",   mul     = " * ",
-   div    = " / ",   mod     = " % ",   pow     = " ^ ",
-   concat = " .. ",  eq      = " == ",  ne      = " ~= ",
-   lt     = " < ",   le      = " <= ",  ["and"] = " and ",
-   ["or"] = " or ",  ["not"] = "not ",  len     = "# " }
-
---------------------------------------------------------------------------------
--- Accumulate the source representation of AST `node' in
--- the synthetizer. Most of the work is done by delegating to
--- the method having the name of the AST tag.
--- If something can't be converted to normal sources, it's
--- instead dumped as a `-{ ... }' splice in the source accumulator.
---------------------------------------------------------------------------------
-function synth:node (node)
-   assert (self~=synth and self._acc)
-   if not node.tag then -- tagless block.
-      self:list (node, self.nl)
-   else
-      local f = synth[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 (table.tostring (node, "nohash"), 80)
-         self:acc " }"
-      end
-   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,
--- it can be a string or a synth method.
--- `start' is an optional number (default == 1), indicating which is the
--- first element of list to be converted, so that we can skip the begining
--- of a list. 
---------------------------------------------------------------------------------
-function synth:list (list, sep, start)
-   for i = start or 1, # list do
-      self:node (list[i])
-      if list[i + 1] then
-         if not sep then            
-         elseif type (sep) == "function" then sep (self)
-         elseif type (sep) == "string"   then self:acc (sep)
-         else   error "Invalid list separator" end
-      end
-   end
-end
-
---------------------------------------------------------------------------------
---
--- Tag methods.
--- ------------
---
--- Specific AST node dumping methods, associated to their node kinds
--- by their name, which is the corresponding AST tag.
--- synth:node() is in charge of delegating a node's treatment to the
--- appropriate tag method.
---
--- Such tag methods are called with the AST node as 1st arg.
--- As a convenience, the n node's children are passed as args #2 ... n+1.
---
--- There are several things that could be refactored into common subroutines
--- here: statement blocks dumping, function dumping...
--- However, given their small size and linear execution
--- (they basically perform series of :acc(), :node(), :list(), 
--- :nl(), :nlindent() and :nldedent() calls), it seems more readable
--- to avoid multiplication of such tiny functions.
---
--- To make sense out of these, you need to know metalua's AST syntax, as
--- found in the reference manual or in metalua/doc/ast.txt.
---
---------------------------------------------------------------------------------
-
-function synth:Do (node)
-   self:acc      "do"
-   self:nlindent ()
-   self:list     (node, self.nl)
-   self:nldedent ()
-   self:acc      "end"
-end
-
-function synth:Set (node)
-   match node with
-   | `Set{ { `Index{ lhs, `String{ method } } }, 
-           { `Function{ { `Id "self", ... } == params, body } } } 
-         if is_idx_stack (lhs) and is_ident (method) ->
-      -- ``function foo:bar(...) ... end'' --
-      self:acc      "function "
-      self:node     (lhs)
-      self:acc      ":"
-      self:acc      (method)
-      self:acc      " ("
-      self:list     (params, ", ", 2)
-      self:acc      ")"
-      self:nlindent ()
-      self:list     (body, self.nl)
-      self:nldedent ()
-      self:acc      "end"
-
-   | `Set{ { lhs }, { `Function{ params, body } } } if is_idx_stack (lhs) ->
-      -- ``function foo(...) ... end'' --
-      self:acc      "function "
-      self:node     (lhs)
-      self:acc      " ("
-      self:list     (params, ", ")
-      self:acc      ")"
-      self:nlindent ()
-      self:list    (body, self.nl)
-      self:nldedent ()
-      self:acc      "end"
-
-   | `Set{ { `Id{ lhs1name } == lhs1, ... } == lhs, rhs } 
-         if not is_ident (lhs1name) ->
-      -- ``foo, ... = ...'' when foo is *not* a valid identifier.
-      -- In that case, the spliced 1st variable must get parentheses,
-      -- to be distinguished from a statement splice.
-      -- This cannot happen in a plain Lua AST.
-      self:acc      "("
-      self:node     (lhs1)
-      self:acc      ")"
-      if lhs[2] then -- more than one lhs variable
-         self:acc   ", "
-         self:list  (lhs, ", ", 2)
-      end
-      self:acc      " = "
-      self:list     (rhs, ", ")
-
-   | `Set{ lhs, rhs } ->
-      -- ``... = ...'', no syntax sugar --
-      self:list  (lhs, ", ")
-      self:acc   " = "
-      self:list  (rhs, ", ")
-   end
-end
-
-function synth:While (node, cond, body)
-   self:acc      "while "
-   self:node     (cond)
-   self:acc      " do"
-   self:nlindent ()
-   self:list     (body, self.nl)
-   self:nldedent ()
-   self:acc      "end"
-end
-
-function synth:Repeat (node, body, cond)
-   self:acc      "repeat"
-   self:nlindent ()
-   self:list     (body, self.nl)
-   self:nldedent ()
-   self:acc      "until "
-   self:node     (cond)
-end
-
-function synth:If (node)
-   for i = 1, #node-1, 2 do
-      -- for each ``if/then'' and ``elseif/then'' pair --
-      local cond, body = node[i], node[i+1]
-      self:acc      (i==1 and "if " or "elseif ")
-      self:node     (cond)
-      self:acc      " then"
-      self:nlindent ()
-      self:list     (body, self.nl)
-      self:nldedent ()
-   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 ()
-   end
-   self:acc "end"
-end
-
-function synth:Fornum (node, var, first, last)
-   local body = node[#node]
-   self:acc      "for "
-   self:node     (var)
-   self:acc      " = "
-   self:node     (first)
-   self:acc      ", "
-   self:node     (last)
-   if #node==5 then -- 5 children --> child #4 is a step increment.
-      self:acc   ", "
-      self:node  (node[4])
-   end
-   self:acc      " do"
-   self:nlindent ()
-   self:list     (body, self.nl)
-   self:nldedent ()
-   self:acc      "end"
-end
-
-function synth:Forin (node, vars, generators, body)
-   self:acc      "for "
-   self:list     (vars, ", ")
-   self:acc      " in "
-   self:list     (generators, ", ")
-   self:acc      " do"
-   self:nlindent ()
-   self:list     (body, self.nl)
-   self:nldedent ()
-   self:acc      "end"
-end
-
-function synth:Local (node, lhs, rhs)
-   self:acc     "local "
-   self:list    (lhs, ", ")
-   if rhs[1] then
-      self:acc  " = "
-      self:list (rhs, ", ")
-   end
-end
-
-function synth:Localrec (node, lhs, rhs)
-   match node with
-   | `Localrec{ { `Id{name} }, { `Function{ params, body } } }
-         if is_ident (name) ->
-      -- ``local function name() ... end'' --
-      self:acc      "local function "
-      self:acc      (name)
-      self:acc      " ("
-      self:list     (params, ", ")
-      self:acc      ")"
-      self:nlindent ()
-      self:list     (body, self.nl)
-      self:nldedent ()
-      self:acc      "end"
-
-   | _ -> 
-      -- Other localrec are unprintable ==> splice them --
-          -- This cannot happen in a plain Lua AST. --
-      self:acc "-{ "
-      self:acc (table.tostring (node, 'nohash', 80))
-      self:acc " }"
-   end
-end
-
-function synth:Call (node, f)
-   -- single string or table literal arg ==> no need for parentheses. --
-   local parens
-   match node with
-   | `Call{ _, `String{_} }
-   | `Call{ _, `Table{...}} -> parens = false
-   | _ -> parens = true
-   end
-   self:node (f)
-   self:acc  (parens and " (" or  " ")
-   self:list (node, ", ", 2) -- skip `f'.
-   self:acc  (parens and ")")
-end
-
-function synth:Invoke (node, f, method)
-   -- single string or table literal arg ==> no need for parentheses. --
-   local parens
-   match node with
-   | `Invoke{ _, _, `String{_} }
-   | `Invoke{ _, _, `Table{...}} -> parens = false
-   | _ -> parens = true
-   end
-   self:node   (f)
-   self:acc    ":"
-   self:acc    (method[1])
-   self:acc    (parens and " (" or  " ")
-   self:list   (node, ", ", 3) -- Skip args #1 and #2, object and method name.
-   self:acc    (parens and ")")
-end
-
-function synth:Return (node)
-   self:acc  "return "
-   self:list (node, ", ")
-end
-
-synth.Break = "break"
-synth.Nil   = "nil"
-synth.False = "false"
-synth.True  = "true"
-synth.Dots  = "..."
-
-function synth:Number (node, n)
-   self:acc (tostring (n))
-end
-
-function synth:String (node, str)
-   -- format "%q" prints '\n' in an umpractical way IMO,
-   -- so this is fixed with the :gsub( ) call.
-   self:acc (string.format ("%q", str):gsub ("\\\n", "\\n"))
-end
-
-function synth:Function (node, params, body)
-   self:acc      "function "
-   self:acc      " ("
-   self:list     (params, ", ")
-   self:acc      ")"
-   self:nlindent ()
-   self:list     (body, self.nl)
-   self:nldedent ()
-   self:acc      "end"
-end
-
-function synth:Table (node)
-   if not node[1] then self:acc "{ }" else
-      self:acc "{"
-      self:nlindent ()
-      for i, elem in ipairs (node) do
-         match elem with
-         | `Pair{ `String{ key }, value } if is_ident (key) ->
-            -- ``key = value''. --
-            self:acc  (key)
-            self:acc  " = "
-            self:node (value)
-
-         | `Pair{ key, value } ->
-            -- ``[key] = value''. --
-            self:acc  "["
-            self:node (key)
-            self:acc  "] = "
-            self:node (value)
-
-         | _ -> 
-            -- ``value''. --
-            self:node (elem)
-         end
-         if node [i+1] then
-            self:acc ","
-            self:nl  ()
-         end
-      end
-      self:nldedent  ()
-      self:acc       "}"
-   end
-end
-
-function synth:Op (node, op, a, b)
-   -- Transform ``not (a == b)'' into ``a ~= b''. --
-   match node with
-   | `Op{ "not", `Op{ "eq", _a, _b } }
-   | `Op{ "not", `Paren{ `Op{ "eq", _a, _b } } } ->  
-      op, a, b = "ne", _a, _b
-   | _ ->
-   end
-
-   if b then -- binary operator.
-      local left_paren, right_paren
-      match a with
-      | `Op{ op_a, ...} if op_prec[op] >= op_prec[op_a] -> left_paren = true
-      | _ -> left_paren = false
-      end
-
-      match b with -- FIXME: might not work with right assoc operators ^ and ..
-      | `Op{ op_b, ...} if op_prec[op] >= op_prec[op_b] -> right_paren = true
-      | _ -> right_paren = false
-      end
-
-      self:acc  (left_paren and "(")
-      self:node (a)
-      self:acc  (left_paren and ")")
-
-      self:acc  (op_symbol [op])
-
-      self:acc  (right_paren and "(")
-      self:node (b)
-      self:acc  (right_paren and ")")
-
-   else -- unary operator.     
-      local paren
-      match a with
-      | `Op{ op_a, ... } if op_prec[op] >= op_prec[op_a] -> paren = true
-      | _ -> paren = false
-      end
-      self:acc  (op_symbol[op])
-      self:acc  (paren and "(")
-      self:node (a)
-      self:acc  (paren and ")")
-   end
-end
-
-function synth:Paren (node, content)
-   self:acc  "("
-   self:node (content)
-   self:acc  ")"
-end
-
-function synth:Index (node, table, key)
-   local paren_table
-   -- Check precedence, see if parens are needed around the table --
-   match table with
-   | `Op{ op, ... } if op_prec[op] < op_prec.index -> paren_table = true
-   | _ -> paren_table = false
-   end
-
-   self:acc  (paren_table and "(")
-   self:node (table)
-   self:acc  (paren_table and ")")
-
-   match key with
-   | `String{ field } if is_ident (field) -> 
-      -- ``table.key''. --
-      self:acc "."
-      self:acc (field)
-   | _ -> 
-      -- ``table [key]''. --
-      self:acc   "["
-      self:node (key)
-      self:acc   "]"
-   end
-end
-
-function synth:Id (node, name)
-   if is_ident (name) then
-      self:acc (name)
-   else -- Unprintable identifier, fall back to splice representation.
-        -- This cannot happen in a plain Lua AST.
-      self:acc    "-{`Id "
-      self:String (node, name)
-      self:acc    "}"
-   end 
-end
-
-
---------------------------------------------------------------------------------
--- Read a file, get its AST, use synth to regenerate sources
--- from that AST
---------------------------------------------------------------------------------
-require 'metalua.compiler'
-local filename = (arg[2] or arg[1]) or arg[0]
-local ast = mlc.luafile_to_ast (filename)
-
-print(synth.run(ast))
diff --git a/samples/trycatch_test.mlua b/samples/trycatch_test.mlua
deleted file mode 100644
index 80e4124..0000000
--- a/samples/trycatch_test.mlua
+++ /dev/null
@@ -1,126 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{ extension 'trycatch' }
-
-
-----------------------------------------------------------------------
-print "1) no error"
-try
-   print("   Hi")
-end
-
-
-----------------------------------------------------------------------
-print "2) caught error"
-try
-   error "some_error"
-catch x then
-   printf("   Successfully caught %q", x)
-end
-
-
--- [[
-----------------------------------------------------------------------
-print "3) no error, with a finally"
-try
-   print "   Hi"
-finally
-   print "   Finally OK"
-end
-
-
-----------------------------------------------------------------------
-print "4) error, with a finally"
-try
-   print "   Hi"
-   error "bang"
-catch "bang"/{_} then
-   print "   Bang caught"
-finally
-   print "   Finally OK"
-end
-
-
-----------------------------------------------------------------------
-print "5) nested catchers"
-try
-   try
-      error "some_error"
-   catch "some_other_error" then
-      assert (false, "mismatch, this must not happen")
-   end
-   catch "some_error"/{x} then
-   printf("   Successfully caught %q across a try that didn't catch", x)
-catch x then
-   assert (false, "We shouldn't reach this catch-all")
-end
-
-
-----------------------------------------------------------------------
-print "6) nested catchers, with a 'finally in the inner one"
-try
-   try
-      error "some_error"
-   catch "some_other_error" then
-      assert (false, "mismatch, this must not happen")
-   finally
-      print "   Leaving the inner try-catch"
-   end
-catch "some_error"/{x} then
-   printf("   Successfully caught %q across a try that didn't catch", x)
-catch x then
-   assert (false, "We shouldn't reach this catch-all")
-end
-
-
-----------------------------------------------------------------------
-print "7) 'finally' intercepts a return from a function"
-function f()
-   try
-      print "   into f:"
-      return "F_RESULT"
-      assert (false, "I'll never go there")
-   catch _ then
-      assert (false, "No exception should be thrown")
-   finally
-      print "   I do the finally before leaving f()"
-   end
-end
-local fr = f()
-printf("   f returned %q", fr)
-
-
-----------------------------------------------------------------------
-print "8) don't be fooled by nested functions"
-function f()
-   try
-      local function g() return "from g" end
-      printf("   g() returns %q", g())
-      return "from f"
-   catch _ then
-      assert (false, "No exception should be thrown")
-   end
-end
-local fr = f()
-printf("   f returned %q", fr)
-
-----------------------------------------------------------------------
-print "*) done."
-
diff --git a/samples/types_test.mlua b/samples/types_test.mlua
deleted file mode 100644
index aeb3945..0000000
--- a/samples/types_test.mlua
+++ /dev/null
@@ -1,38 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{ extension "types" }
--{ extension "clist" }
-
--- Uncomment this to turn typechecking code generation off:
--- -{stat: types.enabled=false}
-
-function sum (x :: table(number)) :: number
-   local acc :: number = 0
-   for i=1, #x do
-      acc = acc + x[i] -- .. 'x' -- converts to string
-   end
-   --acc='bug' -- put a string in a number variable
-   return acc
-end
-
-x       = { i for i=1,100 }
---x[23] = 'toto' -- string in a number list, sum() will complain
-y       = sum (x)
-printf ("sum 1 .. %i = %i", #x, y)
\ No newline at end of file
diff --git a/samples/walk_id_test.mlua b/samples/walk_id_test.mlua
deleted file mode 100644
index 5dfff6c..0000000
--- a/samples/walk_id_test.mlua
+++ /dev/null
@@ -1,45 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{ extension 'match' }
-
-require 'metalua.walk.id'
-
-ast = +{ block:
-         y = type(1)
-         function foo(x)
-            local type = 'number'
-            assert(x==type or not x)
-         end
-         foo(x) }
-
-disp = |msg,ast| printf("\n%s:\n%s", msg, table.tostring(ast, 80, 'nohash'))
-disp('initial term', ast)
-
-do -- Make globals explicit:
-   local ast = table.deep_copy(ast)
-   local cfg = { id = { } }
-   function cfg.id.free(i) 
-      i <- `Index{ `Id '_G', `String{i[1]} } 
-      return 'break'
-   end   
-   walk_id.block(cfg, ast)
-   disp('Globals made explicit', ast)
-end
-
diff --git a/samples/weaver.mlua b/samples/weaver.mlua
deleted file mode 100644
index 3a7507f..0000000
--- a/samples/weaver.mlua
+++ /dev/null
@@ -1,139 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-require 'metalua.mlc'
-require 'metalua.walk'
-
-function weave_ast (src, ast, name)
-
-   -------------------------------------------------------------------
-   -- translation: associate an AST node to its recomposed source
-   -- ast_children: associate an AST node to the list of its children
-   -- ast_parent: associate an AST node to the list of its parent
-   -- weavable: whether an AST node supports weaving of its children
-   -- node: common walker config for exprs, stats & blocks
-   -------------------------------------------------------------------
-   local translation, ast_children, ast_parent, weaveable, node =
-      { }, { }, { }, { }, { }
-
-   -------------------------------------------------------------------
-   -- Build up the parent/children relationships. This is not the same
-   -- as inclusion between tables: the relation we're building only
-   -- relates blocks, expressions and statements; in the AST, some
-   -- tables don't represent any of these node kinds.
-   -- For instance in `Local{ { `Id "x" }, { } }, `Id"x" is a child of
-   -- the `Local{ } node, although it's not directly included in it.
-   -------------------------------------------------------------------
-   function node.down(ast, parent)
-      ----------------------------------------------------
-      -- `Do{ } blocks are processed twice:
-      --  * once as a statement
-      --  * once as a block, child of itself
-      -- This prevents them from becoming their own child.
-      ----------------------------------------------------
-      if ast==parent then return end
-
-      if not ast.lineinfo then 
-         weaveable [ast] = false, false
-         if parent then weaveable [parent] = false end
-      else
-         weaveable [ast] = true
-         
-         -- normalize lineinfo
-         -- TODO: FIXME
-         if ast.lineinfo.first[3] > ast.lineinfo.last[3] then
-           ast.lineinfo.first, ast.lineinfo.last = ast.lineinfo.last, ast.lineinfo.first
-         end
-      end
-      ast_children [ast] = { }
-      ast_parent [ast] = parent
-      if parent then table.insert (ast_children [parent], ast) end
-   end
-
-   -------------------------------------------------------------------
-   -- Visit up, from leaves to upper-level nodes, and weave leaves
-   -- back into the text of their parent node, recursively.  Since the
-   -- visitor is imperative, we can't easily make it return a value
-   -- (the resulting recomposed source, here). Therefore we
-   -- imperatively store results in the association table
-   -- `translation'.
-   -------------------------------------------------------------------
-   function node.up(ast)
-      local _acc = { }
-      local function acc(x) table.insert (_acc, x) end
-      
-      if not next(ast) then -- shadow node, remove from ast_children
-         local x = ast_children[ast_parent[ast]]
-         for i,a in ipairs (x) do if a==ast then table.remove (x, i); break end end
-         return "" -- no need to continue, we know that the node is empty!
-      end
-      
-      -- ast Can't be weaved normally, try something else --
-      local function synthetize (ast)
-         acc "-{expr: "
-         acc (table.tostring (ast, 'nohash', 80, 8))
-         acc " }"
-      end
-
-      -- regular weaving of chidren in the parent's sources --
-      local function weave (ast)
-         -- sort children in appearence order
-         local comp = |a,b| a.lineinfo.first[3] < b.lineinfo.first[3]
-         table.sort (ast_children [ast], comp)
- 
-         local li = ast.lineinfo
-         if not li then return synthetize (ast) end
-         local a, d = li.first[3], li.last[3]
-         for child in ivalues (ast_children [ast]) do
-            local li = child.lineinfo
-            local b, c = li.first[3], li.last[3]
-            acc (src:sub (a, b - 1))
-            acc (translation [child])
-            a = c + 1
-         end
-         acc (src:sub (a, d))
-      end
-
-      -- compute the translation from the children's ones --
-      if not translation [ast] then
-         if weaveable [ast] then weave (ast) else synthetize (ast) end
-         translation [ast] = table.concat (_acc)
-      end
-   end
-
-   local cfg = { expr=node; stat=node; block=node }
-   walk.block (cfg, ast)
-
-   return translation [ast]
-end
-
--- Get the source. If none is given, use itself as an example. --
-local filename = arg[2] or arg[1] or arg[0]
-local f = assert (io.open (filename, 'r'))
-local src = f:read '*a'
-f:close()
-
-local ast = mlc.luastring_to_ast (src, name)
-if not next(ast) then
-   io.write (src) -- Empty ast, probably empty file, or comments only
-else
-   local before = src:sub (1, ast.lineinfo.first[3]-1)
-   local after  = src:sub (ast.lineinfo.last[3]+1, -1)
-   io.write (before .. weave_ast (src, ast) .. after)
-end
diff --git a/samples/withdo_test.mlua b/samples/withdo_test.mlua
deleted file mode 100644
index 9feb487..0000000
--- a/samples/withdo_test.mlua
+++ /dev/null
@@ -1,32 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{ extension 'withdo' }
-
-local original_close = io.close
-
-function x()
-   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
-
-print(x())
\ No newline at end of file
diff --git a/samples/xglobals_test.mlua b/samples/xglobals_test.mlua
deleted file mode 100644
index 7a46488..0000000
--- a/samples/xglobals_test.mlua
+++ /dev/null
@@ -1,59 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{ extension 'xglobal' }
-
-----------------------------------------------------------------------
-print "1) declare unassigned globals"
-global a, b
-
-----------------------------------------------------------------------
-print "2) declare-and-assign global"
-global c = 3
-
-----------------------------------------------------------------------
-print "3) assign to pre-declared globals"
-a, b = 1, 2
-
-----------------------------------------------------------------------
-print "4) fail when setting an undeclared global"
-local st1, msg1 = pcall(function()
-   a = 4
-   d = 5 -- failure, assignment to undeclared global
-end)
-assert(not st1)
-printf ("   -> This error was expected: %s", msg1)
-
-----------------------------------------------------------------------
-print "5) fail when reading an undeclared global"
-local st2, msg2 = pcall(function()
-   b = c -- OK
-   local _ = d -- failure, try to read undeclared global
-end)
-assert(not st2)
-printf ("   -> This error was expected: %s", msg2)
-
-----------------------------------------------------------------------
-print "6) check the globals' values"
-assert(a==4)
-assert(b==3)
-assert(c==3)
-
-----------------------------------------------------------------------
-print "*) done."
diff --git a/samples/xloop_test.mlua b/samples/xloop_test.mlua
deleted file mode 100644
index e87993a..0000000
--- a/samples/xloop_test.mlua
+++ /dev/null
@@ -1,23 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{ extension 'xloop' }
-for i=1,9 for j=10,90,10 if i~=3 while i<8 do
-   io.write(i+j, ' ')
-end
\ No newline at end of file
diff --git a/samples/xmatch_test.mlua b/samples/xmatch_test.mlua
deleted file mode 100644
index f651db4..0000000
--- a/samples/xmatch_test.mlua
+++ /dev/null
@@ -1,73 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--{ extension 'xmatch' }
-
-WIDTH=60
-function p(msg) io.write(msg..' ':rep(WIDTH-#msg)) end
-
-----------------------------------------------------------------------
-p "match as an expression"
-print(match 1 with 1 -> 'ok' | 2 -> 'KO')
-
-----------------------------------------------------------------------
-p "global match function"
-match function g
-| x if x<10 -> return 'o'
-| _         -> return 'k'
-end
-print(g(1)..g(11))
-
-----------------------------------------------------------------------
-p "global match function, multi-args"
-match function cmp
-| x, y if x<y -> return 'increasing'
-| _, _        -> return 'decreasing'
-      end
-
-if cmp(1,2)=='increasing' and cmp(2,1)=='decreasing' then
-   print "ok" else print "KO"
-end
-
-----------------------------------------------------------------------
-p "local match function"
-do
-   local match function x
-   | 1 -> print 'ok'
-   end
-   x(1)
-end
-assert(not x)
-
-----------------------------------------------------------------------
-p "global bind assignment"
-bind {a, b} = {'o', 'k'}
-print(a..b)
-
-----------------------------------------------------------------------
-p "local bind assignment"
-c, d = 'k', 'o'
-do
-   local bind {c, {d}} = {'o', {'k'}}
-   print(c..d)
-end
-
-----------------------------------------------------------------------
-p "local bind assignment scope"
-print(d..c)
diff --git a/lib/strict.lua b/strict.lua
similarity index 85%
rename from lib/strict.lua
rename to strict.lua
index e35e22d..19213a8 100644
--- a/lib/strict.lua
+++ b/strict.lua
@@ -12,6 +12,14 @@
 --
 -------------------------------------------------------------------------------
 
+--
+-- strict.lua
+-- checks uses of undeclared global variables
+-- All global variables must be 'declared' through a regular assignment
+-- (even assigning nil will do) in a main chunk before being used
+-- anywhere or assigned to inside a function.
+--
+
 local getinfo, error, rawset, rawget = debug.getinfo, error, rawset, rawget
 
 local mt = getmetatable(_G)
diff --git a/tests/lexer.lua b/tests/lexer.lua
deleted file mode 100644
index 6eb430a..0000000
--- a/tests/lexer.lua
+++ /dev/null
@@ -1,149 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 David Manura and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     David Manura - API and implementation
---
--------------------------------------------------------------------------------
-
--- tests of lexer (preliminary)
---
--- D.Manura.  Copyright (c) 2011, Fabien Fleutot <metalua@gmail.com>.
---
--- This software is released under the MIT Licence, see Metalua licence.txt
--- for details.
-
-
-package.path = 'src/compiler/?.lua;src/lib/?.lua'
-
-require 'mlp_lexer'
-local LX = mlp.lexer
-
--- equality check.
-local function checkeq(a, b)
-  if a ~= b then
-    error('not equal:\n' .. tostring(a) .. '\n' .. tostring(b), 2)
-  end
-end
-
-local function checkmatch(a, b)
-  if not a:match(b) then
-    error('not match:\n' .. tostring(a) .. '\n' .. tostring(b), 2)
-  end
-end
-
--- reads file to string (with limited error handling)
-local function readfile(filename)
-  local fh = assert(io.open(filename, 'rb'))
-  local text = fh:read'*a'
-  fh:close()
-  return text
-end
-
--- formats token succinctly.
-local function tokfmt(tok)
-  local function fmt(o)
-    return (type(o) == 'string') and ("%q"):format(o):sub(2,-2) or tostring(o)
-  end
-  return [[`]] .. tok.tag .. tostring(tok.lineinfo):gsub('%|L[^%|]*%|C[^%|]*', '') .. '{' .. fmt(tok[1]) .. '}'
-end
-
--- utility function to lex code
-local function lex(code)
-  local sm = LX:newstream(code)
-  local toks = {}
-  while 1 do
-    local tok = sm:next()
-    toks[#toks+1] = tokfmt(tok)
-    if tok.tag == 'Eof' then
-      break
-    end
-  end
-  return table.concat(toks)
-end
-local function tlex(code)
-  local sm = LX:newstream(code)
-  local toks = {}
-  while 1 do
-    local tok = sm:next()
-    toks[#toks+1] = tok
-    if tok.tag == 'Eof' then break end
-  end
-return toks
-end
-local function plex(code)
-  return pcall(lex, code)
-end
-
---FIX checkeq(nil, plex '====')
-
--- trivial tests
-checkeq(lex[[]], [[`Eof<?|K1>{eof}]])
-checkeq(lex'\t', [[`Eof<?|K2>{eof}]])
-checkeq(lex'\n', [[`Eof<?|K2>{eof}]])
-checkeq(lex'--', [[`Eof<C|?|K3>{eof}]])
-checkeq(lex'\n -- \n--\n ', [[`Eof<C|?|K11>{eof}]])
-checkeq(lex[[return]], [[`Keyword<?|K1-6>{return}`Eof<?|K7>{eof}]])
-
--- string tests
-checkeq(lex[["\092b"]],  [[`String<?|K1-7>{\\b}`Eof<?|K8>{eof}]]) -- was bug
-checkeq(lex[["\x5Cb"]],  [[`String<?|K1-7>{\\b}`Eof<?|K8>{eof}]]) -- [5.2]
-checkeq(lex[["\0\t\090\100\\\1004"]],  [[`String<?|K1-21>{\000	Zd\\d4}`Eof<?|K22>{eof}]]) -- decimal/escape
-
--- number tests, hex (including Lua 5.2)
-local t = tlex[[0xa 0xB 0xfF -0xFf 0x1.8 0x1.8P1 0x1.8p+01 0x.8p-1]]
-checkeq(t[1][1], 0xa)
-checkeq(t[2][1], 0xB)
-checkeq(t[3][1], 0xfF)
-checkeq(t[4][1], '-')
-checkeq(t[5][1], 0xFf)
--- 5.2 hex floats
-checkeq(t[6][1], 1.5) -- 0x1.8
-checkeq(t[7][1], 3) -- 0x1.8P1
-checkeq(t[8][1], 3) -- 0x1.8p+01
-checkeq(t[9][1], 0.25) -- 0x0.8p-1
-checkeq(t[10][1], 'eof')
-
-
--- Lua 5.2
-checkeq(lex'"a\\z \n ."', [[`String<?|K1-9>{a.}`Eof<?|K10>{eof}]])  -- \z
-checkeq(lex'"\\z"', [[`String<?|K1-4>{}`Eof<?|K5>{eof}]])  -- \z
-checkeq(lex[["\x00\\\xfF\\xAB"]], [[`String<?|K1-17>{\000\\]]..'\255'..[[\\xAB}`Eof<?|K18>{eof}]])
-
--- Lua 5.2 goto and ::
-checkeq(lex'goto a1 ::a1 ::', [[`Keyword<?|K1-4>{goto}`Id<?|K6-7>{a1}]]..
-   [[`Keyword<?|K9-10>{::}`Id<?|K11-12>{a1}`Keyword<?|K14-15>{::}`Eof<?|K16>{eof}]])
-
-
-assert(lex(readfile(arg[0]))) -- lex self
-
--- checks of unescape_string
-local p = function(s) local ok, o = pcall(tlex, s); return ok and o[1][1] or o end
-checkmatch(p[['\']], 'Unterminated')
-checkeq(p[['\\a\\\t']], [[\a\]]..'\t')
-checkeq(p[['\\116']], [[\116]])
-checkeq(p[['\\\116']], [[\t]])
-checkeq(p[['\092\116']], [[\t]]) -- was bug
-checkeq(p[['\x5c\x74']], [[\t]]) -- 5.2 hex
--- Lua 5.2
-checkeq(p[['\z\z \
-a\z  ']], [[
-
-a]])
-checkeq(p[['\\z']], [[\z]])  -- was bug
-checkmatch(p[['\xaz']], 'Unknown escape')
-checkmatch(p[['\999']], 'must be in.*255')
-checkeq(p[['\z\32']], ' ') -- was bug
-
-print 'DONE'
diff --git a/tests/locals-and-stats.mlua b/tests/locals-and-stats.mlua
deleted file mode 100644
index 6e24fa5..0000000
--- a/tests/locals-and-stats.mlua
+++ /dev/null
@@ -1,34 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
-local foo
-
-x = -{ `Stat{ { `Local{ { `Id "B" },
-                        { `Stat{ { `Local{ { `Id "A" },
-                                           { `Number 4 } },
-                                   `Set{ { `Id "y" },
-                                         { `Id "A" } } },
-                                 `Id "A" } } },
-                `Set{ { `Id "x" },
-                      { `Id "B" } } },
-              `Id "B" } }
-
-assert(x==4)
-print "Test passed."
-
diff --git a/tests/reweave.mlua b/tests/reweave.mlua
deleted file mode 100644
index 3a891a4..0000000
--- a/tests/reweave.mlua
+++ /dev/null
@@ -1,43 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
--{ extension 'xloop' }
-
-ls = io.popen ( (os.getenv("OS") or "") :match "^Windows" and "dir /b reweave" or "ls reweave")
-this_script = arg[1]
-
-local errors = {}
-
-for filename in ls :lines() if filename :strmatch  "%.m?lua$" do
-   printf ("--- weaver check %s ---", filename)
-   local ret = os.execute ("metalua ../samples/weaver.mlua reweave/"..filename.." | diff -q reweave/"..filename.." -")
-   if ret ~= 0 then
-      print("================================================================================") 
-      print("Reweaved source does not match original:") 
-      print("================================================================================") 
-      os.execute ("metalua ../samples/weaver.mlua reweave/"..filename.." | diff reweave/"..filename.." -")
-      errors[#errors + 1] = "Reweaving of "..filename.." failed, returned "..ret
-   end
-end
-
-ls :close()
-
-if #errors > 0 then
-   print("================================================================================") 
-   error("REWEAVING ERRORS DETECTED:\n * " .. table.concat(errors, "\n * ")) 
-end
diff --git a/tests/reweave/comment.lua b/tests/reweave/comment.lua
deleted file mode 100644
index 587d620..0000000
--- a/tests/reweave/comment.lua
+++ /dev/null
@@ -1,3 +0,0 @@
---[[
-comment
---]]
diff --git a/tests/reweave/comment2.lua b/tests/reweave/comment2.lua
deleted file mode 100644
index 6222fb6..0000000
--- a/tests/reweave/comment2.lua
+++ /dev/null
@@ -1,2 +0,0 @@
---[[comment]]
-local code = 5
diff --git a/tests/reweave/comment_dup.lua b/tests/reweave/comment_dup.lua
deleted file mode 100644
index 17afdfd..0000000
--- a/tests/reweave/comment_dup.lua
+++ /dev/null
@@ -1,8 +0,0 @@
-if true then
-  -- comment
-end
-
-if true then
-  -- comment
-  print("something else after")
-end
diff --git a/tests/reweave/comments.lua b/tests/reweave/comments.lua
deleted file mode 100644
index 05e8762..0000000
--- a/tests/reweave/comments.lua
+++ /dev/null
@@ -1,8 +0,0 @@
-# it eats
---[[ all ]]
---[===[ my ]===]
-comments() -- foo
---[[ bar
-baz ]] qqq()
--- even
-one() -- liners
diff --git a/tests/reweave/dup.lua b/tests/reweave/dup.lua
deleted file mode 100644
index e6428ab..0000000
--- a/tests/reweave/dup.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-f(a > b)
-f(c >= d)
diff --git a/tests/reweave/empty.lua b/tests/reweave/empty.lua
deleted file mode 100644
index e69de29..0000000
--- a/tests/reweave/empty.lua
+++ /dev/null
diff --git a/tests/reweave/extra_whitespace.lua b/tests/reweave/extra_whitespace.lua
deleted file mode 100644
index 7358189..0000000
--- a/tests/reweave/extra_whitespace.lua
+++ /dev/null
@@ -1,16 +0,0 @@
-t = {}
-
-t = { }
-
-t {}
-
-t { }
-
-assert(count(function () end) == 1)
-
-for k,v,w in a do end
-
-repeat until 1; repeat until true;
-while false do end; while nil do end;
-
-foo(1) { };
diff --git a/tests/reweave/function-index-decl.lua b/tests/reweave/function-index-decl.lua
deleted file mode 100644
index a7c77ac..0000000
--- a/tests/reweave/function-index-decl.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-function a.b.c.f1 (x) return x+1 end
-function a.b.c:f2 (x,y) self[x] = y end
diff --git a/tests/reweave/if.lua b/tests/reweave/if.lua
deleted file mode 100644
index 32ddd19..0000000
--- a/tests/reweave/if.lua
+++ /dev/null
@@ -1 +0,0 @@
-f(5 > 7)
diff --git a/tests/reweave/index_index.lua b/tests/reweave/index_index.lua
deleted file mode 100644
index 6aa0028..0000000
--- a/tests/reweave/index_index.lua
+++ /dev/null
@@ -1 +0,0 @@
-function a.b.c (x) end
diff --git a/tests/reweave/schema.lua b/tests/reweave/schema.lua
deleted file mode 100644
index c5275ba..0000000
--- a/tests/reweave/schema.lua
+++ /dev/null
@@ -1,1286 +0,0 @@
-local print, verb, dbg, errr, print_table, printt = make_module_loggers("schema", "SCM")
-
-local CT, GMF,
-      game_const
-      = import 'game/const.lua'
-      {
-        'chipTypes',
-        'gameModeFlags'
-      }
-
-local MTF,
-      cast_type
-      = import (game_const.abilities)
-      {
-        'manualTargetFlags',
-        'castType'
-      }
-
-local AP, abiprob_mapping = import (game_const.abilities.property)
-      {
-        'mappingInv', -- Note order (inverted goes first)
-        'mapping'
-      }
-
-local PO, CM, CST, SO,
-      abie_const
-      = import 'abie/const.lua'
-      {
-        'propObjects',
-        'customMessages',
-        'clientStat',
-        'storeObjects'
-      }
-
-local non_empty_list,
-      no_check,
-      not_implemented,
-      get_children,
-      get_children_concat_newline,
-      get_children_concat_str,
-      get_children_concat_table,
-      get_value,
-      get_value_quoted,
-      get_value_tonumber,
-      check_mapping_tonumber,
-      get_value_mapped_tonumber_quoted,
-      node_children_placeholders_filler,
-      check_tonumber
-      = import 'jsle/schema/util.lua'
-      {
-        'non_empty_list',
-        'no_check',
-        'not_implemented',
-        'get_children',
-        'get_children_concat_newline',
-        'get_children_concat_str',
-        'get_children_concat_table',
-        'get_value',
-        'get_value_quoted',
-        'get_value_tonumber',
-        'check_mapping_tonumber',
-        'get_value_mapped_tonumber_quoted',
-        'node_children_placeholders_filler',
-        'check_tonumber'
-      }
-
-local declare_common = import 'jsle/schema/common.lua' { 'declare_common' }
-
--- Optional TODOs:
-
--- TODO: Must be able to fetch back data from lang file to this schema.
--- TODO: Write effect validation with human readable answers. Make it available via jobman's job.
--- TODO: Write auto-conversion function for old abilities (v.1.01->current)
--- TODO: Embed limitations on number of simultanious identical active OT effects
--- TODO: Write checkers for numeric fields
--- TODO: Adapt game/ctrl.lua to abie
-
-local define_schema = function(jsle)
-  assert_is_table(jsle)
-
--- WARNING: Return nil on error from handlers, do not return false -- it is a legitimate value.
--- WARNING: Reordering of schema elements would result in INCOMPATIBLE format change!
-
-  local propwrite_values =
-  {
-    { ["health"] = [[жизнь]] };
-    { ["health_max"] = [[здоровье]] };
-    { ["mana1"] = [[красную ману]] };
-    { ["mana2"] = [[зелёную ману]] };
-    { ["mana3"] = [[синюю ману]] };
-    -- Note mana4 is reserved for health
-    { ["mana5"] = [[ману 5]] };
-    { ["mana6"] = [[ману 6]] };
-    { ["mana7"] = [[ману 7]] };
-    { ["mana8"] = [[ману 8]] };
-    { ["armor"] = [[броню]] };
-    { ["fury"] = [[ярость]] };
-    { ["block"] = [[блок]] };
-    { ["fortune"] = [[удачу]] };
-    { ["stun"] = [[оглушение]] };
-    { ["armour_piercing"] = [[бронебойность]] };
-    { ["agility"] = [[ловкость]] };
-    { ["counterattack"] = [[контрудар]] };
-    { ["damage"] = [[базовый урон]] };
-    { ["damage_min"] = [[минимальный урон]] };
-    { ["damage_max"] = [[максимальный урон]] };
-    { ["damage_mult"] = [[множитель урона]] };
-    { ["vampiric"] = [[вампиризм]] };
-    { ["stun_count"] = [[оглушённость]] };
-  }
-
-  local propread_values = tiappend(
-      tclone(propwrite_values),
-      {
-        { ["race_id"] = [[расу]] },
-        { ["level"] = [[уровень]] },
-        { ["grade"] = [[степень]] }, -- TODO: clan_rank?!
-        { ["rank"] = [[ранг]] },
-        { ["glory"] = [[доблесть]] },
-        { ["scalps"] = [[скальпы]] },
-        { ["kills"] = [[убийства]] },
-      }
-    )
-
-  -- TODO: Be more specific. Should be at least "abie-1.03".
-  jsle:version("1.03") -- WARNING: Do an ordering cleanup when this changes
-
-  jsle:record "ROOT"
-  {
-    children =
-    {
-      [1] = "TARGET_LIST";
-      [2] = "IMMEDIATE_EFFECT_LIST";
-      [3] = "OVERTIME_EFFECT";
-      [4] = { "BOOLEAN", default = 0 }; -- Warning! Do not use BOOLOP_VARIANT, nothing of it would work at this point.
-      [5] = { "CUSTOM_OVERTIME_EFFECTS", default = empty_table };
-    };
-    html = [[<h2>Цели</h2>%C(1)%<h2>Мгновенные эффекты</h2><b>Игнорировать активацию в статистике:</b>%C(4)%<br><br><b>Действия:</b>%C(2)%<h2>Овертайм-эффекты</h2>%C(3)%<hr>%C(5)%]];
-    checker = no_check;
-    handler = function(self, node)
-      return self:effect_from_string(
-        node.value[1], -- Target list
-        node.value[4], -- Ignore usage stats flag
-        self:fill_placeholders(
-            node.value,
-[[
-function(self)
-  self:set_custom_ot_effects($(5))
-
-  do
-    $(2)
-  end
-
-  do
-    $(3)
-  end
-end
-]]
-          )
-       )
-    end;
-  }
-
-  jsle:list "TARGET_LIST"
-  {
-    type = "TARGET_VALUE";
-    html = [[%LIST(", ")%]];
-    checker = non_empty_list;
-    handler = function(self, node)
-      local result = 0
-      for i, v in ipairs(node.value) do
-        result = result + v
-      end
-      return result
-    end;
-  }
-
-  jsle:enum "TARGET_VALUE"
-  {
-    values =
-    {
-      { [MTF.AUTO_ONLY]       = [[неинтерактивно]] };
-      { [MTF.SELF_HUMAN]      = [[на себя]] };
-      { [MTF.SELF_TEAM_HUMAN] = [[на человека в своей команде]] };
-      { [MTF.OPP_HUMAN]       = [[на противника]] };
-      { [MTF.OPP_TEAM_HUMAN]  = [[на человека в команде противника]] };
-      { [MTF.FIELD_CHIP]      = [[на фишку]] };
-    };
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value_tonumber;
-    numeric_keys = true;
-  }
-
-  jsle:list "IMMEDIATE_EFFECT_LIST"
-  {
-    type = "ACTION_VARIANT";
-    html = [[%LE("<i>Нет</i>")%%LNE("<ol><li>")%%LIST("<li>")%%LNE("</ol>")%]];
-    checker = no_check;
-    handler = get_children_concat_newline;
-  }
-
-  jsle:record "OVERTIME_EFFECT"
-  {
-    children =
-    {
-      [1] = "OT_EFFECT_TARGET";
-      [2] = "NUMOP_VARIANT";
-      [3] = "NUMOP_VARIANT";
-      [4] = "BOOLOP_VARIANT";
-      [5] = "OVERTIME_EFFECT_LIST";
-      [6] = "OVERTIME_EFFECT_LIST";
-      [7] = "OVERTIME_EFFECT_LIST";
-      [8] = "OT_MODIFIER_LIST";
-      [9] = "NUMOP_VARIANT"; -- TODO: Must be higher in the list. Straighten numbers on next version change (do not forget to fix texts)
-      [10] = "NUMOP_VARIANT"; -- TODO: Must be higher in the list. Straighten numbers on next version change (do not forget to fix texts)
-      [11] = { "GAME_MODES", default = GMF.ALL }; -- TODO: Must be higher in the list. Straighten numbers on next version change (do not forget to fix texts)
-      [12] = { "BOOLEAN", default = 0 };
-    };
-    html = [[<br><b>Цель:</b> %C(1)%<br><b>Время жизни:</b> %C(2)% <i>(&ge;255 &mdash; бессрочно)</i><br><b>Период:</b> %C(3)%<br><b>Изначальный кулдаун:</b> %C(10)%<br><b>Сброс в конце боя:</b> %C(4)%<br><b>Остается при снятии всех эффектов вручную:</b> %C(12)%<br><b>Максимальное число одновременно активных эффектов:</b> %C(9)% <i>(0 &mdash; не ограничено)</i><br><b>Игровые режимы:</b> %C(11)%<h3>При изменении набора характеристик</h3>%C(5)%<h3>В конце хода цели</h3>%C(7)%<h3>Временные модификаторы <i>(кроме жизни)</i></h3>%C(8)%]];
-    checker = no_check;
-    handler = function(self, node)
-      if
-        node.value[5] ~= "" or
-        node.value[6] ~= "" or
-        node.value[7] ~= "" or
-        node.value[8] ~= "{}"
-      then
-        -- Spawning OT effect only if have any actions in it.
-        return node_children_placeholders_filler
-          [[
-            self:spawn_overtime_effect(
-                $(1),
-                $(2),
-                $(3),
-                $(10),
-                $(4),
-                $(9),
-                function(self)
-                  $(5)
-                end,
-                function(self)
-                  $(6)
-                end,
-                function(self)
-                  $(7)
-                end,
-                $(8),
-                $(11),
-                $(12)
-              )
-          ]] (self, node)
-      else
-        return [[-- No OT effects]]
-      end
-   end;
-  }
-
-  jsle:list "OT_MODIFIER_LIST"
-  {
-    type = "OT_MODIFIER_VARIANT";
-    html = [[%LE("<i>Нет</i>")%%LNE("<ol><li>")%%LIST("<li>")%%LNE("</ol>")%]];
-    checker = no_check;
-    handler = get_children_concat_table;
-  }
-
-  jsle:variant "OT_MODIFIER_VARIANT"
-  {
-    values =
-    {
-      { ["MOD_SET"]  = [[Установить]] };
-      { ["MOD_INC"]  = [[Увеличить]] };
-      { ["MOD_DEC"]  = [[Уменьшить]] };
-      { ["MOD_MULT"] = [[Умножить]] };
-    };
-    label = [["<i title=\"Модификатор\">M</i>"]];
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value;
-  }
-
-  jsle:record "MOD_SET"
-  {
-    children =
-    {
-      [1] = "PROPWRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Установить %C(1)% цели в %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[{ name = $(1), fn = function(self, value) return ($(2)) end; }]];
-  }
-
-  jsle:record "MOD_INC"
-  {
-    children =
-    {
-      [1] = "PROPWRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Увеличить %C(1)% цели на %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[{ name = $(1), fn = function(self, value) return value + ($(2)) end; }]];
-  }
-
-  jsle:record "MOD_DEC"
-  {
-    children =
-    {
-      [1] = "PROPWRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Уменьшить %C(1)% цели на %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[{ name = $(1), fn = function(self, value) return value - ($(2)) end; }]];
-  }
-
-  jsle:record "MOD_MULT"
-  {
-    children =
-    {
-      [1] = "PROPWRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Умножить %C(1)% цели на %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[{ name = $(1), fn = function(self, value) return value * ($(2)) end; }]];
-  }
-
-  jsle:list "OVERTIME_EFFECT_LIST"
-  {
-    type = "ACTION_VARIANT";
-    html = [[%LE("<i>Нет</i>")%%LNE("<ol><li>")%%LIST("<li>")%%LNE("</ol>")%]];
-    checker = no_check;
-    handler = get_children_concat_newline;
-  }
-
-  jsle:list "ACTION_LIST"
-  {
-    type = "ACTION_VARIANT";
-    html = [[<ol><li>%LIST("<li>")%</ol>]];
-    checker = non_empty_list;
-    handler = get_children_concat_newline;
-  }
-
-  jsle:variant "ACTION_VARIANT"
-  {
-    values =
-    {
-      { ["ACT_SET"]               = [[Установить]] };
-      { ["ACT_INC"]               = [[Увеличить]] };
-      { ["ACT_DEC"]               = [[Уменьшить]] };
-      { ["ACT_MULT"]              = [[Умножить]] };
-      { ["ACT_DIRECTSET"]         = [[Установить напрямую]] };
-      { ["ACT_DIRECTINC"]         = [[Увеличить напрямую]] };
-      { ["ACT_DIRECTDEC"]         = [[Уменьшить напрямую]] };
-      { ["ACT_DIRECTMULT"]        = [[Умножить напрямую]] };
-      { ["ACT_FLDEXPLODE"]        = [[Взорвать фишки]] };
-      { ["ACT_FLDLEVELDELTA"]     = [[Поднять уровень фишек]] };
-      { ["ACT_FLDCOLLECT_COORDS"] = [[Собрать фишки по координатам]] };
-      { ["ACT_FLDREPLACE_COORDS"] = [[Заменить фишки по координатам]] };
-      { ["ACT_ONEMOREACTION"]     = [[Дать ещё одно действие]] };
-      { ["ACT_KEEPTIMEOUT"]       = [[Не сбрасывать таймер]] };
-      { ["ACT_SETVAR"]            = [[Запомнить]] };
-      { ["ACT_SETOBJVAR_LOCAL"]   = [[Запомнить в объекте локально]] };
-      { ["ACT_SETOBJVAR_GLOBAL"]  = [[Запомнить в объекте глобально]] };
-      { ["ACT_SETOBJVAR_OT"]      = [[Запомнить в текущем овертайме]] };
-      { ["ACT_DOIF"]              = [[Если]] };
-      { ["ACT_DOIFELSE"]          = [[Если ... иначе]] };
-      { ["ACT_PLAYABIANIM"]       = [[Играть эффект абилки]] };
-      { ["ACT_SENDCUSTOMMSG"]     = [[Отправить данные клиентам]] };
-      { ["ACT_INCSTAT"]           = [[Увеличить статистику клиента]] };
-      { ["ACT_ACTIVATEOT"]        = [[Активировать ОТ-эффект]] };
-      { ["ACT_REMOVE_OVERTIMES"]  = [[Снять ОТ-эффекты]] };
-      -- Keep these below --
-      { ["ACT_FLDREPLACE"]        = [[Заменить фишки <b><i>(устарело)</i></b>]] };
-      { ["ACT_CRASH_GAME"]        = [[УРОНИТЬ игру <b><i>(только для тестов)</i></b>]] };
-      -- { ["PLAINLUA"]           = [[Lua]] };
-    };
-    label = [["<i title=\"Действие\">A</i>"]];
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value;
-  }
-
-  declare_common(jsle, "ACT_DOIF", "ACT_DOIFELSE")
-
-  jsle:record "ACT_SET"
-  {
-    children =
-    {
-      [1] = "PROPPATH_WRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Установить %C(1)% в %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:propset($(1), $(2))]];
-  }
-
-  jsle:record "ACT_INC"
-  {
-    children =
-    {
-      [1] = "PROPPATH_WRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Увеличить %C(1)% на %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:propinc($(1), $(2))]];
-  }
-
-  jsle:record "ACT_DEC"
-  {
-    children =
-    {
-      [1] = "PROPPATH_WRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Уменьшить %C(1)% на %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:propdec($(1), $(2))]];
-  }
-
-  jsle:record "ACT_MULT"
-  {
-    children =
-    {
-      [1] = "PROPPATH_WRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Умножить %C(1)% на %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:propmult($(1), $(2))]];
-  }
-
-  jsle:record "ACT_DIRECTSET"
-  {
-    children =
-    {
-      [1] = "PROPPATH_WRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Установить напрямую %C(1)% в %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:propset_direct($(1), $(2))]];
-  }
-
-  jsle:record "ACT_DIRECTINC"
-  {
-    children =
-    {
-      [1] = "PROPPATH_WRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Увеличить напрямую %C(1)% на %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:propinc_direct($(1), $(2))]];
-  }
-
-  jsle:record "ACT_DIRECTDEC"
-  {
-    children =
-    {
-      [1] = "PROPPATH_WRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Уменьшить напрямую %C(1)% на %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:propdec_direct($(1), $(2))]];
-  }
-
-  jsle:record "ACT_DIRECTMULT"
-  {
-    children =
-    {
-      [1] = "PROPPATH_WRITE";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Умножить напрямую %C(1)% на %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:propmult_direct($(1), $(2))]];
-  }
-
-  jsle:record "ACT_FLDEXPLODE"
-  {
-    children =
-    {
-      [1] = "NUMOP_VARIANT";
-      [2] = "CHIPCOORD";
-    };
-    html = [[Взорвать бомбу радиусом %C(1)% в координатах %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:fld_explode($(1), $(2))]];
-  }
-
-  jsle:record "ACT_FLDREPLACE"
-  {
-    children =
-    {
-      [1] = "CHIPTYPE";
-      [2] = "NUMOP_VARIANT";
-      [3] = "CHIPTYPE";
-      [4] = "NUMOP_VARIANT";
-    };
-    html = [[Заменить %C(1)% уровня %C(2)% на %C(3)% уровня %C(4)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:fld_replace($(1), $(2), $(3), $(4))]];
-    doc = [[Deprecated, use other replace actions]];
-  }
-
-  jsle:record "ACT_FLDLEVELDELTA"
-  {
-    children =
-    {
-      [1] = "NUMOP_VARIANT";
-      [2] = "CHIPTYPE";
-      [3] = "NUMOP_VARIANT";
-      [4] = "NUMOP_VARIANT";
-    };
-    html = [[Поднять уровень %C(2)% на %C(1)% в диапазоне от %C(3)% до %C(4)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:fld_level_delta($(1), $(2), $(3), $(4))]];
-  }
-
-  jsle:record "ACT_FLDCOLLECT_COORDS"
-  {
-    children =
-    {
-      [1] = "COORDLISTOP_VARIANT";
-    };
-    html = [[Собрать %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:fld_collect_coords($(1))]];
-  }
-
-  jsle:record "ACT_FLDREPLACE_COORDS"
-  {
-    children =
-    {
-      [1] = "COORDLISTOP_VARIANT";
-      [2] = "CHIPTYPE_LIST";
-      [3] = "NUMOP_VARIANT";
-    };
-    html = [[Заменить %C(1)% на %C(2)% уровня %C(3)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:fld_replace_coords($(1),$(2),$(3))]];
-  }
-
-  jsle:literal "ACT_ONEMOREACTION"
-  {
-    html = [[Дать ещё одно действие <i>(только мгновенный эффект)</i>]];
-    checker = no_check;
-    handler = invariant [[self:one_more_action()]];
-  }
-
-  jsle:literal "ACT_KEEPTIMEOUT"
-  {
-    html = [[Не сбрасывать таймер <i>(только мгновенный эффект)</i>]];
-    checker = no_check;
-    handler = invariant [[self:keep_timeout()]];
-  }
-
-  jsle:record "ACT_SETVAR"
-  {
-    children =
-    {
-      [1] = "NUMOP_VARIANT";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Запомнить в №%C(1)% значение %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:setvar($(1), $(2))]];
-  }
-
-  jsle:enum "OT_EFFECT_TARGET"
-  {
-    values =
-    {
-      { [PO.SELF] = [[на себя]] };
-      { [PO.OPP] = [[на противника]] };
-      { [PO.TARGET] = [[на цель]] };
-    };
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value_quoted;
-  }
-
-  jsle:variant "BOOLOP_VARIANT"
-  {
-    values =
-    {
-      { ["BOOLEAN"] = [[Логическое значение]] };
-      { ["BOOLOP_LT"] = [[&lt;]] };
-      { ["BOOLOP_LTE"] = [[&le;]] };
-      { ["BOOLOP_GT"] = [[&gt;]] };
-      { ["BOOLOP_GTE"] = [[&ge;]] };
-      { ["BOOLOP_EQ"] = [[==]] };
-      { ["BOOLOP_NEQ"] = [[!=]] };
-      { ["BOOLOP_AND_MANY"] = [[И (Список)]] };
-      { ["BOOLOP_OR_MANY"] = [[ИЛИ (Список)]] };
-      { ["BOOLOP_NOT"] = [[НЕ]] };
-      { ["BOOLOP_HAVEMEDAL"] = [[МЕДАЛЬ]] };
-      { ["BOOLOP_ISACTIVE"] = [[Изменения инициированы целью овертайм-эффекта]] };
-      { ["BOOLOP_IS_GAME_IN_MODE"] = [[Текущий игровой режим]] };
-      -- Deprecated, keep below --
-      { ["BOOLOP_AND"] = [[И]] };
-      { ["BOOLOP_OR"] = [[ИЛИ]] };
-      --{ ["PLAINLUA"] = [[Lua]] };
-    };
-    label = [["<i title=\"Логическая операция\">B</i>"]];
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value;
-  }
-
-  jsle:record "BOOLOP_HAVEMEDAL"
-  {
-    children =
-    {
-      [1] = "PROPOBJECT";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[есть медаль №%C(2)% %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:have_medal($(1), $(2))]];
-  }
-
-  jsle:literal "BOOLOP_ISACTIVE"
-  {
-    html = [[изменения инициированы целью овертайм-эффекта]];
-    checker = no_check; -- Only for on_changeset event.
-    handler = invariant [[self:is_overtime_target_active()]];
-  }
-
-  declare_common(
-      jsle,
-      "BOOLOP_LT",
-      "BOOLOP_LTE",
-      "BOOLOP_GT",
-      "BOOLOP_GTE",
-      "BOOLOP_EQ",
-      "BOOLOP_NEQ",
-      "BOOLOP_AND",
-      "BOOLOP_OR",
-      "BOOLOP_NOT"
-    )
-
-  jsle:variant "NUMOP_VARIANT"
-  {
-    values =
-    {
-      { ["NUMBER"] = [[Число]] };
-      { ["NUMOP_ADD_MANY"] = [[+ (Список)]] };
-      { ["NUMOP_DEC_MANY"] = [[- (Список)]] };
-      { ["NUMOP_MUL_MANY"] = [[* (Список)]] };
-      { ["NUMOP_DIV_MANY"] = [[/ (Список)]] };
-      { ["NUMOP_POV"] = [[POW]] }; -- TODO: POW, not POV! Fix by search and replace
-      { ["NUMOP_MOD"] = [[MOD]] };
-      { ["NUMOP_MIN"] = [[MIN]] };
-      { ["NUMOP_MAX"] = [[MAX]] };
-      { ["NUMOP_UNM"] = [[Знак]] };
-      { ["NUMOP_GET"] = [[Характеристика]] };
-      { ["NUMOP_GET_RAW"] = [[Базовое значение характеристики]] };
-      { ["NUMOP_GET_ABIPROP"] = [[Характеристика абилки]] };
-      { ["NUMOP_PERCENT_ROLL"] = [[Cлучайный процент]] };
-      { ["NUMOP_TEAMSIZE"] = [[Размер команды]] };
-      { ["NUMOP_GETVAR"] = [[Вспомнить]] };
-      { ["NUMOP_GETOBJVAR_LOCAL"]  = [[Вспомнить из объекта локально]] };
-      { ["NUMOP_GETOBJVAR_GLOBAL"] = [[Вспомнить из объекта глобально]] };
-      { ["NUMOP_GETOBJVAR_OT"]     = [[Вспомнить из текущего овертайма]] };
-      { ["NUMOP_OTLIFETIMELEFT"] = [[Оставшееся время жизни]] };
-      { ["NUMOP_OTLIFETIMETOTAL"] = [[Общее время жизни]] };
-      { ["NUMOP_FLDGETQUANTITYOFCHIPS"] = [[Число фишек по цвету и уровню]] };
-      { ["NUMOP_TARGETX"] = [[Координата X выбранной фишки]] };
-      { ["NUMOP_TARGETY"] = [[Координата Y выбранной фишки]] };
-      { ["NUMOP_OTEFFECTCOUNT"] = [[Число активных овертайм-эффектов]] };
-      { ["NUMOP_IFF"] = [[Если]] };
-      { ["NUMOP_GETUID"] = [[Идентификатор игрока]] };
-      -- Keep these below --
-      { ["NUMOP_FLDCOUNTCHIPS"] = [[Число фишек на поле <b><i>(устарело)</i></b>]] };
-      { ["NUMOP_ADD"] = [[+]] };
-      { ["NUMOP_DEC"] = [[-]] };
-      { ["NUMOP_MUL"] = [[*]] };
-      { ["NUMOP_DIV"] = [[/]] };
-      { ["NUMOP_CRASH_GAME"] = [[УРОНИТЬ игру <b><i>(только для тестов)</i></b>]] };
-      --{ ["PLAINLUA"] = [[Lua]] };
-    };
-    label = [["<i title=\"Численная операция\">I</i>"]];
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value;
-  }
-
-  declare_common(
-      jsle,
-      "NUMOP_ADD",
-      "NUMOP_DEC",
-      "NUMOP_MUL",
-      "NUMOP_DIV",
-      "NUMOP_POV",
-      "NUMOP_MOD",
-      "NUMOP_MIN",
-      "NUMOP_MAX",
-      "NUMOP_UNM"
-    )
-
-  jsle:record "NUMOP_GET"
-  {
-    children =
-    {
-      [1] = "PROPPATH_READ";
-    };
-    html = [[%C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:propget($(1), false)]];
-  }
-
-  declare_common(jsle, "NUMOP_PERCENT_ROLL")
-
-  jsle:record "NUMOP_FLDCOUNTCHIPS"
-  {
-    children =
-    {
-      [1] = "CHIPTYPE";
-      [2] = "BOOLOP_VARIANT";
-    };
-    html = [[число %C(1)% на поле (учитывая уровни: %C(2)%)]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:fld_count_chips($(1), $(2))]];
-    doc = [[Deprecated, use other chip count operations]];
-  }
-
-  jsle:record "NUMOP_TEAMSIZE"
-  {
-    children =
-    {
-      [1] = "PROPOBJECT";
-    };
-    html = [[размер команды %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:team_size($(1))]];
-  }
-
-  jsle:record "NUMOP_GETVAR"
-  {
-    children =
-    {
-      [1] = "NUMOP_VARIANT";
-    };
-    html = [[вспомнить из №%C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:getvar($(1))]];
-  }
-
-  jsle:literal "NUMOP_OTLIFETIMELEFT"
-  {
-    html = [[оставшееся время жизни]];
-    checker = no_check;
-    handler = invariant [[self:ot_lifetime_left()]];
-  }
-
-  jsle:literal "NUMOP_OTLIFETIMETOTAL"
-  {
-    html = [[общее время жизни]];
-    checker = no_check;
-    handler = invariant [[self:ot_lifetime_total()]];
-  }
-
-  jsle:literal "NUMOP_TARGETX"
-  {
-    html = [[X выбранной фишки]];
-    checker = no_check;
-    handler = invariant [[self:target_x()]];
-  }
-
-  jsle:literal "NUMOP_TARGETY"
-  {
-    html = [[Y выбранной фишки]];
-    checker = no_check;
-    handler = invariant [[self:target_y()]];
-  }
-
-  jsle:record "PROPPATH_WRITE"
-  {
-    children =
-    {
-      [1] = "PROPOBJECT";
-      [2] = "PROPWRITE";
-    };
-    html = [[%C(2)% %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:make_proppath($(1), $(2))]];
-  }
-
-  jsle:record "PROPPATH_READ"
-  {
-    children =
-    {
-      [1] = "PROPOBJECT";
-      [2] = "PROPREAD";
-    };
-    html = [[%C(2)% %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:make_proppath($(1), $(2))]];
-  }
-
-  jsle:enum "PROPOBJECT"
-  {
-    values =
-    {
-      { [PO.SELF] = [[у себя]] };
-      { [PO.OPP] = [[у противника]] };
-      { [PO.TARGET] = [[у цели]] };
-      { [PO.OWN_CHANGESET] = [[в своём наборе изменений]] };
-      { [PO.OPP_CHANGESET] = [[в наборе изменений противника]] };
-    };
-    html = [[%VALUE()%]];
-    checker = no_check; -- Check value is valid for current action list subtype
-    handler = get_value_quoted;
-  }
-
-  jsle:enum "PROPWRITE"
-  {
-    values = propwrite_values;
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value_quoted;
-  }
-
-  jsle:enum "PROPREAD"
-  {
-    values = propread_values;
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value_quoted;
-  }
-
-  jsle:enum "CHIPTYPE"
-  {
-    values =
-    {
-      { [CT.EMERALD] = [[зелёных фишек]] };
-      { [CT.RUBY] = [[красных фишек]] };
-      { [CT.AQUA] = [[синих фишек]] };
-      { [CT.DMG] = [[черепов]] };
-      { [CT.CHIP5] = [[фишек-5]] };
-      { [CT.CHIP6] = [[фишек-6]] };
-      { [CT.CHIP7] = [[фишек-7]] };
-      { [CT.CHIP8] = [[фишек-8]] };
-      { [CT.EMPTY] = [[пустых фишек]] };
-    };
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value_tonumber;
-    numeric_keys = true;
-  }
-
-  jsle:edit "NUMBER"
-  {
-    size = 4;
-    numeric = true;
-    checker = check_tonumber;
-    handler = get_value_tonumber;
-  }
-
-  declare_common(
-      jsle,
-      "BOOLEAN",
-      "PLAINLUA"
-    )
-
-  jsle:list "COORDLISTOP_STD"
-  {
-    type = "CHIPCOORD";
-    html = [[фишки с координатами %LIST(", ")%]];
-    checker = non_empty_list;
-    handler = get_children_concat_table;
-  }
-
-  jsle:record "CHIPCOORD"
-  {
-    children =
-    {
-      [1] = "NUMOP_VARIANT";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[(x: %C(1)%, y: %C(2)%)]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[{x=$(1), y=$(2)}]];
-  }
-
-  -- TODO: UNUSED. Remove or use.
-  jsle:record "BOOLOP_SELECTEDTARGET"
-  {
-    children =
-    {
-      [1] = "TARGET_VALUE";
-    };
-    html = [[выбрана цель %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:is_target_selected($(1))]];
-    doc = [[Currently not used]];
-  }
-
-  jsle:record "NUMOP_OTEFFECTCOUNT"
-  {
-    children =
-    {
-      [1] = "PROPOBJECT";
-      [2] = "NUMOP_VARIANT";
-      [3] = "NUMOP_VARIANT";
-    };
-    html = [[число овертайм-эффектов абилки ID %C(2)% <i>(0 &mdash; этот эффект)</i> № эффекта %C(3)% <i>(0 &mdash; по умолчанию)</i>, активных %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:active_ot_effect_count($(1), $(2), $(3))]];
-  }
-
-  declare_common(jsle, "NUMOP_IFF")
-
-  jsle:record "NUMOP_GET_RAW"
-  {
-    children =
-    {
-      [1] = "PROPPATH_READ";
-    };
-    html = [[базовое значение %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:propget($(1), true)]];
-  }
-
-  -- TODO: Get rid of non-list versions!
-
-  declare_common(
-      jsle,
-      "NUMOP_ADD_MANY",
-      "NUMOP_DEC_MANY",
-      "NUMOP_MUL_MANY",
-      "NUMOP_DIV_MANY"
-    )
-
-  declare_common(
-      jsle,
-      "BOOLOP_AND_MANY",
-      "BOOLOP_OR_MANY"
-    )
-
-  jsle:list "CHIPTYPE_LIST"
-  {
-    type = "CHIPTYPE";
-    html = [[%LIST(", ")%]];
-    checker = non_empty_list;
-    handler = get_children_concat_table;
-  }
-
-  jsle:record "NUMOP_GET_ABIPROP"
-  {
-    children =
-    {
-      [1] = "ABIPROP_NAME";
-    };
-    html = [[%C(1)% абилки]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:abipropget($(1))]];
-  }
-
-  jsle:enum "ABIPROP_NAME"
-  {
-    values =
-    {
-      { [AP.prob] = [[вероятность активации]] };
-    };
-    html = [[%VALUE()%]];
-    checker = check_mapping_tonumber;
-    handler = get_value_mapped_tonumber_quoted(abiprob_mapping);
-  }
-
-  jsle:record "ACT_SENDCUSTOMMSG"
-  {
-    children =
-    {
-      [1] = "NUMOP_LIST";
-    };
-    html = [[Отправить участникам боя данные: %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:send_custom_msg($(1))]];
-  }
-
-  declare_common(jsle, "NUMOP_LIST")
-
-  jsle:record "ACT_PLAYABIANIM"
-  {
-    children =
-    {
-      [1] = "NUMOP_VARIANT";
-    };
-    html = [[Играть эффект абилки ID: %C(1)%]];
-    checker = no_check;
-    -- Hack. Should format be hardcoded here or below?
-    handler = node_children_placeholders_filler(
-        [[self:send_custom_msg({]]..assert_is_number(CM.PLAYABIANIM)
-        ..[[, $(1), self:get_uid("]]..PO.SELF..[[")})]]
-      );
-  }
-
-  jsle:variant "COORDLISTOP_VARIANT"
-  {
-    values =
-    {
-      { ["COORDLISTOP_STD"] = [[Обычный список коордтнат]] };
-      { ["COORDLISTOP_GETLEVEL"] = [[Фишки цвета <i>цв1</i> с уровнями от <i>ур1</i> до <i>ур2</i>]] };
-    };
-    label = [["<i title=\"Список координат\">C</i>"]];
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value;
-  }
-
-  jsle:record "COORDLISTOP_GETLEVEL"
-  {
-    children =
-    {
-      [1] = "CHIPTYPE";
-      [2] = "NUMOP_VARIANT";
-      [3] = "NUMOP_VARIANT";
-    };
-    html = [[%C(1)% с уровнями от %C(2)% до %C(3)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:fld_get_coordlist_from_levels_and_type($(1), $(2), $(3))]];
-  }
-
-  jsle:record "NUMOP_FLDGETQUANTITYOFCHIPS"
-  {
-    children =
-    {
-      [1] = "CHIPTYPE";
-      [2] = "NUMOP_VARIANT";
-      [3] = "NUMOP_VARIANT";
-      [4] = "BOOLOP_VARIANT";
-    };
-    html = [[число %C(1)% на поле уровней с %C(2)% до %C(3)% (учитывая уровень в счетчике: %C(4)%)]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:fld_get_quantity_of_chips($(1), $(2), $(3), $(4))]];
-  }
-
-  jsle:enum "CLIENTSTAT"
-  {
-    values =
-    {
-      -- TODO: Support commented out variants?
-      { [CST.SPELL_USE]        = [[исп. спеллов]] };
-      --{ [CST.SPELL_FRAG]       = [[фраги от спеллов]] };
-      { [CST.CONSUMABLE_USE]   = [[исп. расходников]] };
-      --{ [CST.CONSUMABLE_FRAG]  = [[фраги от расходников]] };
-      { [CST.AUTOABILITY_USE]  = [[исп. автоабилок]] };
-      --{ [CST.AUTOABILITY_FRAG] = [[фраги от автоабилок]] };
-      --{ [CST.RATING]           = [[рейтинг]] };
-      --{ [CST.CUSTOM]           = [[пользовательская]] };
-    };
-    html = [[%VALUE()%]];
-    checker = check_mapping_tonumber;
-    handler = get_value_tonumber;
-  }
-
-  jsle:record "ACT_INCSTAT"
-  {
-    children =
-    {
-      [1] = "PROPOBJECT";
-      [2] = "CLIENTSTAT";
-      [3] = "NUMOP_VARIANT";
-      [4] = "NUMOP_VARIANT";
-    };
-    html = [[Увеличить %C(1)% статистику &laquo;%C(2)%&raquo; эффекта №%C(3)% <i>(0 &mdash; текущий)</i> на %C(4)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:inc_client_stat($(1), $(2), $(3), $(4))]];
-  }
-
-  jsle:record "ACT_ACTIVATEOT"
-  {
-    children =
-    {
-      [1] = "NUMOP_VARIANT";
-      [2] = { "KEYVALUE_LIST", default = empty_table };
-    };
-    html = [[Активировать ОТ-эффект №%C(1)%, передав %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:activate_custom_ot_effect($(1),$(2))]];
-  }
-
-  jsle:list "CUSTOM_OVERTIME_EFFECTS"
-  {
-    type = "OVERTIME_EFFECT";
-    html = [[%LE("<i>(Нет дополнительных ОТ-эффектов)</i>")%%LNE("<ol><li><h2>Дополнительный OT-эффект</h2>")%%LIST("<hr><li><h2>Дополнительный OT-эффект</h2>")%%LNE("</ol>")%]];
-    checker = no_check;
-    handler = function(self, node)
-      local buf = {[[{]]}
-      local _ = function(v) buf[#buf + 1] = tostring(v) end
-      for i, child in ipairs(node.value) do
-        _ [[
-[]] _(i) _[[] = function(self)
-]] _(child) _ [[
-end;
-]]
-      end
-      _ [[}]]
-      return table.concat(buf)
-    end;
-  }
-
-  jsle:record "NUMOP_GETUID"
-  {
-    children =
-    {
-      [1] = "PROPOBJECT";
-    };
-    html = [[идентификатор игрока %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:get_uid($(1))]];
-  }
-
-  jsle:enum "STORE_OBJ"
-  {
-    values =
-    {
-      { [SO.CLIENT_SELF]   = [[на себе]] };
-      { [SO.CLIENT_OPP]    = [[на противнике]] };
-      { [SO.CLIENT_TARGET] = [[на цели]] };
-      { [SO.FIGHT]         = [[на бою]] };
-      { [SO.GAME]          = [[на игре]] };
-    };
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value_tonumber;
-  }
-
-  jsle:record "ACT_SETOBJVAR_LOCAL"
-  {
-    children =
-    {
-      [1] = "STORE_OBJ";
-      [2] = "NUMOP_VARIANT";
-      [3] = "NUMOP_VARIANT";
-    };
-    html = [[Запомнить в объекте &laquo;%C(1)%&raquo; в слот №%C(2)% <b>приватное</b> значение %C(3)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:setobjvar_local($(1), $(2), $(3))]];
-  }
-
-  jsle:record "NUMOP_GETOBJVAR_LOCAL"
-  {
-    children =
-    {
-      [1] = "STORE_OBJ";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[вспомнить из объекта &laquo;%C(1)%&raquo; из слота №%C(2)% <b>приватное</b> значение]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:getobjvar_local($(1), $(2))]];
-  }
-
-  jsle:record "ACT_SETOBJVAR_GLOBAL"
-  {
-    children =
-    {
-      [1] = "STORE_OBJ";
-      [2] = "NUMOP_VARIANT";
-      [3] = "NUMOP_VARIANT";
-    };
-    html = [[Запомнить в объекте %C(1)% в слот №%C(2)% <b>публичное</b> значение %C(3)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:setobjvar_global($(1), $(2), $(3))]];
-  }
-
-  jsle:record "NUMOP_GETOBJVAR_GLOBAL"
-  {
-    children =
-    {
-      [1] = "STORE_OBJ";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[вспомнить из объекта %C(1)% из слота №%C(2)% <b>публичное</b> значение]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:getobjvar_global($(1), $(2))]];
-  }
-
-  jsle:record "ACT_REMOVE_OVERTIMES"
-  {
-    children =
-    {
-      [1] = "OT_EFFECT_TARGET";
-    };
-    html = [[Снять все эффекты, наложенные %C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:remove_overtime_effects($(1))]];
-  }
-
-  jsle:enum "GAME_MODES"
-  {
-    values =
-    {
-      { [GMF.ALL] = [[любой]] };
-      { [GMF.DUEL] = [[дуэль]] };
-      { [GMF.SINGLE] = [[одиночная игра]] };
-    };
-    html = [[%VALUE()%]];
-    checker = no_check;
-    handler = get_value_tonumber;
-  }
-
-  jsle:record "BOOLOP_IS_GAME_IN_MODE"
-  {
-    children =
-    {
-      [1] = "GAME_MODES";
-    };
-    html = [[игровой режим &laquo;%C(1)%&raquo; включён]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:is_game_in_mode($(1))]];
-  }
-
-  jsle:record "ACT_SETOBJVAR_OT"
-  {
-    children =
-    {
-      [1] = "NUMOP_VARIANT";
-      [2] = "NUMOP_VARIANT";
-    };
-    html = [[Запомнить в текущем овертайме в слот №%C(1)% значение %C(2)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:setobjvar_ot($(1), $(2))]];
-  }
-
-  jsle:record "NUMOP_GETOBJVAR_OT"
-  {
-    children =
-    {
-      [1] = "NUMOP_VARIANT";
-    };
-    html = [[Вспомнить из текущего овертайма из слота №%C(1)%]];
-    checker = no_check;
-    handler = node_children_placeholders_filler [[self:getobjvar_ot($(1))]];
-  }
-
-  declare_common(
-      jsle,
-      "KEYVALUE_LIST",
-      "KEYVALUE"
-    )
-
-  jsle:literal "ACT_CRASH_GAME"
-  {
-    html = [[<span style="color:red"><b>УРОНИТЬ</b> игру (только для теста)<span>]];
-    checker = function(self, node)
-      if common_get_config().crashers_enabled == true then
-        errr("WARNING: ACT_CRASH_GAME CRASHER IS ON")
-        return true
-      end
-
-      errr("DETECTED ATTEMPT TO UPLOAD CRASHERS (SCHEMA)")
-      return false, "crashers are disabled in config"
-    end;
-    handler = invariant [[self:crash_game()]];
-  }
-
-  jsle:literal "NUMOP_CRASH_GAME"
-  {
-    html = [[<span style="color:red"><b>УРОНИТЬ</b> игру (только для теста)<span>]];
-    checker = function(self, node)
-      if common_get_config().crashers_enabled == true then
-        errr("WARNING: NUMOP_CRASH_GAME CRASHER IS ON")
-        return true
-      end
-
-      errr("DETECTED ATTEMPT TO UPLOAD CRASHERS (SCHEMA)")
-      return false, "crashers are disabled in config"
-    end;
-    handler = invariant [[(self:crash_game() or 0)]];
-  }
-
-  return jsle
-end
-
-return
-{
-  define_schema = define_schema;
-}
diff --git a/tests/reweave/scope.lua b/tests/reweave/scope.lua
deleted file mode 100644
index f871746..0000000
--- a/tests/reweave/scope.lua
+++ /dev/null
@@ -1,3 +0,0 @@
-do
-  print("scope")
-end
diff --git a/tests/reweave/str.lua b/tests/reweave/str.lua
deleted file mode 100644
index bf63ff3..0000000
--- a/tests/reweave/str.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-sample=[==========[perl -e 'print "<IMG SRC=javascript:alert(\"XSS\")>";' > out]==========]
-sample=[==========[perl -e 'print "<IMG SRC=javascript:alert(\"XSS\")>";' > out]==========]
diff --git a/tests/reweave/ws_simple.lua b/tests/reweave/ws_simple.lua
deleted file mode 100644
index 044284a..0000000
--- a/tests/reweave/ws_simple.lua
+++ /dev/null
@@ -1 +0,0 @@
-repeat until true
diff --git a/tests/run.mlua b/tests/run.mlua
deleted file mode 100644
index f9f9896..0000000
--- a/tests/run.mlua
+++ /dev/null
@@ -1,56 +0,0 @@
--------------------------------------------------------------------------------
--- Copyright (c) 2006-2013 Fabien Fleutot and others.
---
--- All rights reserved.
---
--- This program and the accompanying materials are made available
--- under the terms of the Eclipse Public License v1.0 which
--- accompanies this distribution, and is available at
--- http://www.eclipse.org/legal/epl-v10.html
---
--- This program and the accompanying materials are also made available
--- under the terms of the MIT public license which accompanies this
--- distribution, and is available at http://www.lua.org/license.html
---
--- Contributors:
---     Fabien Fleutot - API and implementation
---
--------------------------------------------------------------------------------
-
--- Run all *.lua and *.mlua files in this directory.
--- This makes it easy to run all tests in the directory, 
-
--{ extension 'xloop' }
-
-LS_COMMANDS = { "ls", "dir /b" } 
-for i, cmd in ipairs(LS_COMMANDS) do
-   local f = io.popen (cmd)
-   ls = f :read '*a'
-   f :close()
-   if ls ~= '' then
-      break
-   elseif i == #LS_COMMANDS then
-      error "Can't figure out how to list files on your OS"
-   end
-end
-
-this_script = arg[1]
-
-local errors = {}
-
-for filename in ls :gmatch "[^\n]+" if filename ~= this_script and filename :strmatch  "%.m?lua$" do
-   printf ("*** running %s ***", filename)
-   local ret = os.execute ("metalua "..filename)
-   if ret ~= 0 then 
-      errors[#errors + 1] = "Test "..filename.." failed, returned "..ret
-   end
-end
-
-if #errors > 0 then
-   print("\n\n================================================================================") 
-   error(
-      "TEST FAILURES DETECTED:\n" ..
-      "-----------------------\n" ..
-      " * " .. table.concat(errors, "\n * ")
-    ) 
-end
diff --git a/lib/verbose_require.lua b/verbose_require.lua
similarity index 96%
rename from lib/verbose_require.lua
rename to verbose_require.lua
index 0e07650..7d0af79 100644
--- a/lib/verbose_require.lua
+++ b/verbose_require.lua
@@ -1,4 +1,4 @@
--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
 -- Copyright (c) 2006-2013 Fabien Fleutot and others.
 --
 -- All rights reserved.
@@ -15,8 +15,7 @@
 -- Contributors:
 --     Fabien Fleutot - API and implementation
 --
--------------------------------------------------------------------------------
-
+--------------------------------------------------------------------------------
 
 do
    local xrequire, n, ind = require, 0, "| "