Removed the partial AST generation on invalid inputs
diff --git a/metalua/compiler.lua b/metalua/compiler.lua
index 96c4e3d..c54ed52 100644
--- a/metalua/compiler.lua
+++ b/metalua/compiler.lua
@@ -17,9 +17,9 @@
 --
 --------------------------------------------------------------------------------
 
---*-lua-*-----------------------------------------------------------------------
+--------------------------------------------------------------------------------
 --
--- Convert between various code representation formats. Some atomic
+-- Convert between various code representation formats. Atomic
 -- converters are written in extenso, others are composed automatically
 -- by chaining the atomic ones together in a closure.
 --
@@ -29,10 +29,10 @@
 -- * 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:      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 
+-- * luacstring: a string dump of the function, as taken by
 --               loadstring() and produced by string.dump().
 -- * function:   an executable lua function in RAM.
 --
@@ -63,90 +63,6 @@
 
 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)
@@ -176,8 +92,6 @@
 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
diff --git a/metalua/compiler/bytecode/compile.lua b/metalua/compiler/bytecode/compile.lua
index 1e2c972..7b9116c 100644
--- a/metalua/compiler/bytecode/compile.lua
+++ b/metalua/compiler/bytecode/compile.lua
@@ -20,41 +20,10 @@
 
 ----------------------------------------------------------------------
 --
--- WARNING! You're entering a hackish area, proceed at your own risks!
+-- This code mainly results from the borrowing, then ruthless abuse, of
+-- Yueliang's implementation of Lua 5.0 compiler.
 --
--- 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. 
--- Largely based on:
---
--- * Yueliang (http://luaforge.net/projects/yueliang),
---   yueliang-0.1.2/orig-5.0.2/lparser.lua
---
--- * 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.
---
-----------------------------------------------------------------------
+---------------------------------------------------------------------
 
 local luaK = require 'metalua.compiler.bytecode.lcode'
 local luaP = require 'metalua.compiler.bytecode.lopcodes'
@@ -748,9 +717,7 @@
          first = fs.nactvar
          nret = luaK.LUA_MULTRET  -- return all values
       elseif nret == 1 then
-         if ast[1].tag ~= "Error" then
-            first = luaK:exp2anyreg(fs, e)
-         end
+         first = luaK:exp2anyreg(fs, e)
       else
          --printf("* Return multiple vals in nextreg %i", fs.freereg)
          luaK:exp2nextreg(fs, e)  -- values must go to the 'stack'
@@ -1275,8 +1242,6 @@
    --printf(" * End of Stat")
 end
 
-function expr.Error() end
-
 ------------------------------------------------------------------------
 -- Main function: ast --> proto
 ------------------------------------------------------------------------
@@ -1292,13 +1257,4 @@
   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/metalua/compiler/parser/expr.lua b/metalua/compiler/parser/expr.lua
index 935d2c9..b277f4e 100644
--- a/metalua/compiler/parser/expr.lua
+++ b/metalua/compiler/parser/expr.lua
@@ -112,7 +112,7 @@
       else
          msg = "Unexpected expr token " .. table.tostring (a, 'nohash')
       end
-      return gg.parse_error (lx, msg)
+      gg.parse_error (lx, msg)
    end
    return a
 end
@@ -120,29 +120,29 @@
 
 --------------------------------------------------------------------------------
 -- Builder generator for operators. Wouldn't be worth it if "|x|" notation
--- were allowed, but then lua 5.1 wouldn't compile it 
+-- were allowed, but then lua 5.1 wouldn't compile it
 --------------------------------------------------------------------------------
 
 -- opf1 = |op| |_,a| `Op{ op, a }
-local function opf1 (op) return 
+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 
+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 
+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", 
+    return { tag="Op", "not",
              { tag="Op", "eq", a, b, lineinfo= {
                    first = a.lineinfo.first, last = b.lineinfo.last } } }
 end
-   
+
 
 --------------------------------------------------------------------------------
 --
@@ -202,7 +202,7 @@
          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) 
+      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/metalua/compiler/parser/ext.lua b/metalua/compiler/parser/ext.lua
index e6cd1f2..9e4c776 100644
--- a/metalua/compiler/parser/ext.lua
+++ b/metalua/compiler/parser/ext.lua
@@ -110,7 +110,7 @@
       return { tag="Op", op, a, b }
    end
    local function f(a,b)
-       if #a ~= #b then return gg.parse_error "assymetric operator+assignment" end
+       if #a ~= #b then 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
diff --git a/metalua/compiler/parser/misc.lua b/metalua/compiler/parser/misc.lua
index 04c4f98..27bd5d3 100644
--- a/metalua/compiler/parser/misc.lua
+++ b/metalua/compiler/parser/misc.lua
@@ -77,7 +77,7 @@
    if lx:is_keyword (a, "-{") then
        local v = splice(lx)
        if v.tag ~= "Id" and v.tag ~= "Splice" then
-           return gg.parse_error(lx, "Bad id splice")
+           gg.parse_error(lx, "Bad id splice")
        end
        return v
    elseif a.tag == "Id" then return lx:next()
@@ -111,9 +111,8 @@
       -- Morally, this is what I want:
       -- return `String{ `Index{ `Splice{ id[1] }, `Number 1 } }
       -- That is, without sugar:
-      return {tag="String",  {tag="Index", {tag="Splice", id[1] }, 
+      return {tag="String",  {tag="Index", {tag="Splice", id[1] },
                                            {tag="Number", 1 } } }
-   elseif id.tag == 'Error' then return id
    else error ("Identifier expected: "..table.tostring(id, 'nohash')) end
 end
 
@@ -125,7 +124,7 @@
    if lx:is_keyword (a, "-{") then
       local v = splice(lx)
       if v.tag ~= "String" and v.tag ~= "Splice" then
-         return gg.parse_error(lx,"Bad string splice")
+         gg.parse_error(lx,"Bad string splice")
       end
       return v
    elseif a.tag == "String" then return lx:next()
@@ -157,11 +156,11 @@
 local function chunk (lx)
    if lx:peek().tag == 'Eof' then
        return { } -- handle empty files
-   else 
+   else
       M.skip_initial_sharp_comment (lx)
       local chunk = mlp.block (lx)
-      if lx:peek().tag ~= "Eof" then 
-          table.insert(chunk, gg.parse_error(lx, "End-of-file expected"))
+      if lx:peek().tag ~= "Eof" then
+          gg.parse_error(lx, "End-of-file expected")
       end
       return chunk
    end
diff --git a/metalua/compiler/parser/stat.lua b/metalua/compiler/parser/stat.lua
index fc9a064..3c671db 100644
--- a/metalua/compiler/parser/stat.lua
+++ b/metalua/compiler/parser/stat.lua
@@ -56,7 +56,7 @@
 M.block_terminators = { "else", "elseif", "end", "until", ")", "}", "]" }
 
 -- FIXME: this must be handled from within GG!!!
-function M.block_terminators :add(x) 
+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
@@ -84,15 +84,15 @@
 -- sync if it was relying on a copy.
 --------------------------------------------------------------------------------
 local return_expr_list_parser = gg.multisequence{
-   { ";" , builder = function() return { } end }, 
-   default = gg.list { 
+   { ";" , builder = function() return { } end },
+   default = gg.list {
       expr, separators = ",", terminators = M.block_terminators } }
 
 
 local for_vars_list = gg.list{
     name        = "for variables list",
     primary     = mlp_misc.id,
-    separators  = ",", 
+    separators  = ",",
     terminators = "in" }
 
 --------------------------------------------------------------------------------
@@ -101,19 +101,19 @@
 --------------------------------------------------------------------------------
 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")
+    if lx :is_keyword (lx:peek(), "=") then
+        if #vars ~= 1 then
+            gg.parse_error (lx, "numeric for only accepts one variable")
         end
         lx:next() -- skip "="
         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")
+            gg.parse_error (lx, "numeric for requires 2 or 3 boundaries")
         end
         return { tag="Fornum", vars[1], unpack (exprs) }
     else
         if not lx :is_keyword (lx :next(), "in") then
-            return gg.parse_error (lx, '"=" or "in" expected in for loop')
+            gg.parse_error (lx, '"=" or "in" expected in for loop')
         end
         local exprs = mlp.expr_list (lx)
         return { tag="Forin", vars, exprs }
@@ -133,7 +133,7 @@
 --------------------------------------------------------------------------------
 -- Function def parser helper: ( : id )?
 --------------------------------------------------------------------------------
-local method_name = gg.onkeyword{ name = "method invocation", ":", mlp_misc.id, 
+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 } }
 
 --------------------------------------------------------------------------------
@@ -141,33 +141,29 @@
 --------------------------------------------------------------------------------
 local function funcdef_builder(x)
 
-   local name   = x[1] or gg.earlier_error()
-   local method = x[2]
-   local func   = x[3] or gg.earlier_error()
+   local name, method, func = unpack(x)
 
-
-   if method then 
+   if method then
       name = { tag="Index", name, method, lineinfo = {
          first = name.lineinfo.first,
          last  = method.lineinfo.last } }
-      table.insert (func[1], 1, {tag="Id", "self"}) 
+      table.insert (func[1], 1, {tag="Id", "self"})
    end
-   local r = { tag="Set", {name}, {func} } 
+   local r = { tag="Set", {name}, {func} }
    r[1].lineinfo = name.lineinfo
    r[2].lineinfo = func.lineinfo
    return r
-end 
+end
 
 
 --------------------------------------------------------------------------------
 -- if statement builder
 --------------------------------------------------------------------------------
 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
-   local n_pairs = #cb_pairs
+   local cond_block_pairs, else_block, r = x[1], x[2], {tag="If"}
+   local n_pairs = #cond_block_pairs
    for i = 1, n_pairs do
-       local cond, block = unpack(cb_pairs[i])
+       local cond, block = unpack(cond_block_pairs[i])
        r[2*i-1], r[2*i] = cond, block
    end
    if else_block then table.insert(r, #r+1, else_block) end
@@ -214,20 +210,21 @@
    else
       assert (#e > 0)
       if #e > 1 then
-         return gg.parse_error (lx,
+         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
             typename = '("'..e[1][1]..'") is an identifier'
-         elseif e[1].tag == 'Op' then 
+         elseif e[1].tag == 'Op' then
             typename = "is an arithmetic operation"
          else typename = "is of type '"..(e[1].tag or "<list>").."'" end
 
-         return gg.parse_error (lx, "This expression " .. typename ..
-            "; a statement was expected, and only function and method call "..
-            "expressions can be used as statements");
+         gg.parse_error (lx,
+                         "This expression %s; "..
+                         "a statement was expected, and only function and method call "..
+                         "expressions can be used as statements", typename);
       end
       return e[1]
    end
@@ -235,14 +232,14 @@
 
 M.local_stat_parser = gg.multisequence{
     -- local function <name> <func_val>
-    { "function", mlp_misc.id, func_val, builder = 
-      function(x) 
+    { "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 } 
+          return { tag="Localrec", vars, vals }
       end },
     -- local <id_list> ( = <expr_list> )?
-    default = gg.sequence{ 
+    default = gg.sequence{
         gg.list{
             primary = annot.opt(mlp_misc.id, 'tf'),
             separators = ',' },
@@ -256,17 +253,17 @@
 --------------------------------------------------------------------------------
 -- statement
 --------------------------------------------------------------------------------
-M.stat = gg.multisequence { 
+M.stat = gg.multisequence {
    name = "statement",
-   { "do", M.block, "end", builder = 
+   { "do", M.block, "end", builder =
       function (x) return { tag="Do", unpack (x[1]) } end },
-   { "for", M.for_header, "do", M.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", 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 = 
+   { "return", return_expr_list_parser, builder =
      function(x) x[1].tag='Return'; return x[1] end },
    { "break", builder = function() return { tag="Break" } end },
    { "-{", mlp_meta.splice_content, "}", builder = unpack },
diff --git a/metalua/compiler/parser/table.lua b/metalua/compiler/parser/table.lua
index 713edbc..373a192 100644
--- a/metalua/compiler/parser/table.lua
+++ b/metalua/compiler/parser/table.lua
@@ -19,15 +19,6 @@
 
 --------------------------------------------------------------------------------
 --
--- Copyright (c) 2006-2012, Fabien Fleutot <metalua@gmail.com>.
---
--- This software is released under the MIT Licence, see licence.txt
--- for details.
---
---------------------------------------------------------------------------------
-
---------------------------------------------------------------------------------
---
 -- Exported API:
 -- * [M.bracket_field()]
 -- * [M.field()]
@@ -60,17 +51,16 @@
 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 
+   if lx :is_keyword (lx :peek(), "=") then
       lx :next(); -- skip the "="
       -- Allowing only the right type of key, here `Id
       local etag = e.tag
       if etag ~= 'Id' then
-         local message = string.format('Identifier expected, got %s.', etag)
-         return gg.parse_error(lx, message)
+         gg.parse_error(lx, 'Identifier expected, got %s.', etag)
       end
       local key = mlp.id2string(e)
       local val = _expr(lx)
-      local r = { tag="Pair", key, val } 
+      local r = { tag="Pair", key, val }
       r.lineinfo = { first = key.lineinfo.first, last = val.lineinfo.last }
       return r
    else return e end
@@ -79,9 +69,9 @@
 --------------------------------------------------------------------------------
 -- table constructor, without enclosing braces; returns a full table object
 --------------------------------------------------------------------------------
-M.content  = gg.list { 
-   primary     =  function(...) return M.field(...) end, 
-   separators  = { ",", ";" }, 
+M.content  = gg.list {
+   primary     =  function(...) return M.field(...) end,
+   separators  = { ",", ";" },
    terminators = "}",
    builder     = "Table" }
 
diff --git a/metalua/grammar/generator.lua b/metalua/grammar/generator.lua
index 078b291..67972bf 100644
--- a/metalua/grammar/generator.lua
+++ b/metalua/grammar/generator.lua
@@ -66,25 +66,11 @@
 -------------------------------------------------------------------------------
 -- parser metatable, which maps __call to method parse, and adds some
 -- error tracing boilerplate.
---
--- TODO: parsers don't throw errors anymore, they return `Error{ } nodes instead.
--- Therefore the accumulation of error positions won't work anymore.
--- Instead, the mlc.check_ast() function should retrace the whole path to
--- the actual error position.
---
 -------------------------------------------------------------------------------
 local parser_metatable = { }
 
 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 (lx, ...)
 end
 
 -------------------------------------------------------------------------------
@@ -110,39 +96,26 @@
 
 -------------------------------------------------------------------------------
 -- Parse a sequence, without applying builder nor transformers.
--- Won't fail: if the parsing can't be completed, the missing results
--- will be filled with Error nodes.
---
--- TODO: This introduces a new assumption in gg that it must produce
--- AST as results. This should be decoupled by passing an error handler
--- from outside.
 -------------------------------------------------------------------------------
 local function raw_parse_sequence (lx, p)
-   local r = { }
-   local failed = false
-   for i=1, #p do
-      local e=p[i]
-      if failed then
-         if type(e)=="string" then table.insert(r, M.earlier_error(lx)) end
-      elseif type(e) == "string" then
-         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 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 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
+    local r = { }
+    for i=1, #p do
+        local e=p[i]
+        if type(e) == "string" then
+            local kw = lx :next()
+            if not lx :is_keyword (kw, e) then
+                M.parse_error(
+                    lx, "A keyword was expected, probably `%s'.", e)
+            end
+        elseif M.is_parser (e) then
+            table.insert (r, e(lx))
+        else -- Invalid parser definition, this is *not* a parsing error
+            error(string.format(
+                      "Sequence `%s': element #%i is neither a string nor a parser: %s",
+                      p.name, i, table.tostring(e)))
+        end
+    end
+    return r
 end
 
 -------------------------------------------------------------------------------
@@ -185,35 +158,20 @@
       line, column, offset = -1, -1, -1
    end
 
-   local msg  = string.format("line %i, char %i: "..fmt, line, column, ...)   
+   local msg  = string.format("line %i, char %i: "..fmt, line, column, ...)
    local src = lx.src
    if offset>0 and src then
       local i, j = offset, offset
       while src:sub(i,i) ~= '\n' and i>=0    do i=i-1 end
-      while src:sub(j,j) ~= '\n' and j<=#src do j=j+1 end      
+      while src:sub(j,j) ~= '\n' and j<=#src do j=j+1 end
       local srcline = src:sub (i+1, j-1)
       local idx  = string.rep (" ", column).."^"
       msg = string.format("%s\n>>> %s\n>>> %s", msg, srcline, idx)
    end
-   lx :kill()
-   return { tag='Error', msg , lineinfo = positions }
+   --lx :kill()
+   error(msg)
 end
 
-function M.wrap_error(lx, nchildren, tag, ...)
-    local li = lx :peek() .lineinfo
-    local r = { tag=tag or 'Error', lineinfo=li }
-    local children = {...}
-    for i=1, nchildren do
-        r[i] = children[i] or M.earlier_error(lx)
-    end
-    return r
-end
-
-function M.earlier_error(lx)
-    local li = lx and lx :peek().lineinfo
-    return { tag='Error', "earlier error", lineinfo=li, error=true, earlier=true }
-end
-   
 -------------------------------------------------------------------------------
 --
 -- Sequence parser generator
@@ -232,7 +190,7 @@
 -- * [transformers]: a list of AST->AST functions, applied in order on ASTs
 --   returned by the parser.
 --
--- * Table-part entries corresponds to keywords (strings) and subparsers 
+-- * Table-part entries corresponds to keywords (strings) and subparsers
 --   (function and callable objects).
 --
 -- After creation, the following fields are added:
@@ -322,7 +280,7 @@
 -- * [kind] == "multisequence"
 --
 -------------------------------------------------------------------------------
-function M.multisequence (p)   
+function M.multisequence (p)
    M.make_parser ("multisequence", p)
 
    -------------------------------------------------------------------
@@ -332,7 +290,7 @@
       -- compile if necessary:
       local keyword = type(s)=='table' and s[1]
       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 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")
@@ -355,8 +313,8 @@
    -------------------------------------------------------------------
    -- Remove the sequence starting with keyword [kw :: string]
    -------------------------------------------------------------------
-   function p :del (kw) 
-      if not self.sequences[kw] then 
+   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 "..
                  "entry ***", kw) end
@@ -534,7 +492,7 @@
          -- Check for non-associative operators, and complain if applicable. 
          -----------------------------------------
          elseif p2.assoc=="none" and p2.prec==prec then
-            return M.parse_error (lx, "non-associative operator!")
+            M.parse_error (lx, "non-associative operator!")
 
          -----------------------------------------
          -- No infix operator suitable at that precedence
@@ -632,23 +590,21 @@
    function p :parse (lx)
 
       ------------------------------------------------------
-      -- Used to quickly check whether there's a terminator 
+      -- Used to quickly check whether there's a terminator
       -- or a separator immediately ahead
       ------------------------------------------------------
-      local function peek_is_in (keywords) 
+      local function peek_is_in (keywords)
          return keywords and lx:is_keyword(lx:peek(), unpack(keywords)) end
 
       local x = { }
       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 
+      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
@@ -659,8 +615,8 @@
       end
 
       local lli = lx:lineinfo_left()
-      
-      -- Apply the builder. It can be a string, or a callable value, 
+
+      -- Apply the builder. It can be a string, or a callable value,
       -- or simply nothing.
       local b = self.builder
       if b then
@@ -752,7 +708,7 @@
       if type(x)=="string" then table.insert (p.keywords, x)
       else assert (not p.primary and M.is_parser (x)); p.primary = x end
    end
-   if not next (p.keywords) then 
+   if not next (p.keywords) then
       eprintf("Warning, no keyword to trigger gg.onkeyword") end
    assert (p.primary, 'no primary parser in gg.onkeyword')
    return p
@@ -839,7 +795,7 @@
          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")
+           M.parse_error (lx, "`%s' must not be empty.", self.name or "list")
        else
            return transform (content, self, fli, lli)
        end
diff --git a/metalua/repl.mlua b/metalua/repl.mlua
index 204482e..9dfa7cc 100644
--- a/metalua/repl.mlua
+++ b/metalua/repl.mlua
@@ -25,6 +25,8 @@
 
 local M = { }
 
+mlc = require 'metalua.compiler'.new()
+
 local readline
 
 do -- set readline() to a line reader, either editline otr a default
@@ -61,38 +63,30 @@
          table.insert(lines, line)
          src = table.concat (lines, "\n")
       until #line>0
-
       lx  = mlc :src_to_lexstream(src)
       success, ast = pcall(mlc.lexstream_to_ast, mlc, lx)
       if success then
-         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, mlc, ast, '=stdin')
-             if success then
-                 results = { xpcall(f, debug.traceback) }
-                 success = table.remove (results, 1)
-                 if success then
-                     -- Success!
-                     table.iforeach(|x| table.print(x, LINE_WIDTH), results)
-                     lines = { }
-                 else
-                     print "Evaluation error:"
-                     print (results[1])
-                     lines = { }
-                 end
-             else
-                 print "Can't compile into bytecode:"
-                 print (f)
-                 lines = { }
-             end
-         end
+          success, f = pcall(mlc.ast_to_function, mlc, ast, '=stdin')
+          if success then
+              results = { xpcall(f, debug.traceback) }
+              success = table.remove (results, 1)
+              if success then
+                  -- Success!
+                  table.iforeach(|x| table.print(x, LINE_WIDTH), results)
+                  lines = { }
+              else
+                  print "Evaluation error:"
+                  print (results[1])
+                  lines = { }
+              end
+          else
+              print "Can't compile into bytecode:"
+              print (f)
+              lines = { }
+          end
       else
-         -- If lx has been read entirely, try to read another
-         -- line before failing.
+         -- If lx has been read entirely, try to read
+         --  another line before failing.
          if not reached_eof(lx, ast) then
             print "Can't compile source into AST:"
             print (ast)