← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/lua_eris into lp:widelands

 

SirVer has proposed merging lp:~widelands-dev/widelands/lua_eris into lp:widelands.

Commit message:
This is meant for merging after b18. It gets rid of some subtle persistence bugs in Lua like bug 1237016. This brings the following changes:

- kill our hacked and modified version of Pluto and instead include a pristine, unchanged version of Eris and use this for persistence (https://github.com/fnuecke/eris). 
- This also means that we no longer depend on Lua 5.1 to be on the system as Eris brings Lua 5.2 with it. That also means that players with the same Widelands version use the exact same persistence and Lua logic - which is a good thing, though I am not aware that we had trouble with inconsistencies between Lua's minor versions before. 
- Makes the necessary changes so that widelands runs with Lua 5.2. This brought a bunch of code simplifications with it - But **killed safegame compatibility for all safegames**.
- Some code cleanups and removal of bad c++ style like virtual inheritance.

Requested reviews:
  Jens Beyer (Qcumber-some) (qcumber-some)
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #1073932 in widelands: "LUAI_UINT32 no longer exists"
  https://bugs.launchpad.net/widelands/+bug/1073932
  Bug #1237016 in widelands: "Strange Lua script behaviour after starting MP game with saved game"
  https://bugs.launchpad.net/widelands/+bug/1237016

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/lua_eris/+merge/191901

This is meant for merging after b18. It gets rid of some subtle persistence bugs in Lua like bug 1237016. This brings the following changes:

- kill our hacked and modified version of Pluto and instead include a pristine, unchanged version of Eris and use this for persistence (https://github.com/fnuecke/eris). 
- This also means that we no longer depend on Lua 5.1 to be on the system as Eris brings Lua 5.2 with it. That also means that players with the same Widelands version use the exact same persistence and Lua logic - which is a good thing, though I am not aware that we had trouble with inconsistencies between Lua's minor versions before. 
- Makes the necessary changes so that widelands runs with Lua 5.2. This brought a bunch of code simplifications with it - But **killed safegame compatibility for all safegames**.
- Some code cleanups and removal of bad c++ style like virtual inheritance.

Todos:
- our Cmake setup is not equipped to compile .c files it seems, so I am not sure if the CFLAGS are set correctly (or at all). Works on my system though :P. Also, lua sets some cflags depending on which system it compiles, but they should not be needed. Jens, could you look into this?
- As this breaks safegame compatiblity anyways, we can use this to get rid of cruft - compatibilty wares, backwards compatible loading branches for old safegames and so on.

-- 
The attached diff has been truncated due to its size.
https://code.launchpad.net/~widelands-dev/widelands/lua_eris/+merge/191901
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/lua_eris into lp:widelands.
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt	2013-09-06 15:01:38 +0000
+++ CMakeLists.txt	2013-10-19 12:35:28 +0000
@@ -481,9 +481,6 @@
   message(FATAL_ERROR "Required package SDL_gfx not found, please install and re-run cmake")
 endif (NOT SDLGFX_FOUND)
 
-find_package(Lua51 REQUIRED)
-include_directories(${LUA_INCLUDE_DIR})
-
 IF (WIN32)
   SET(GUI_TYPE WIN32)
 ENDIF (WIN32)

=== modified file 'CREDITS'
--- CREDITS	2012-06-20 09:59:07 +0000
+++ CREDITS	2013-10-19 12:35:28 +0000
@@ -75,9 +75,9 @@
     * http://www.lua.org
 
 
-    Pluto
-    * by Ben Sunshine-Hill, Rob Hoelz
-    * http://luaforge.net/projects/pluto/
+    Eris
+    * by Florian Nücke
+    * https://github.com/fnuecke/eris
 
 
     Lodepng (for testing, not in Widelands itself)

=== modified file 'doc/sphinx/source/implementation.rst'
--- doc/sphinx/source/implementation.rst	2012-06-20 09:07:10 +0000
+++ doc/sphinx/source/implementation.rst	2013-10-19 12:35:28 +0000
@@ -104,20 +104,18 @@
 -----------
 
 When a savegame is created, the current environment of Lua is persisted. For
-this, I used a library called Pluto_ which is in the public domain. It was
-heavily modified to work with widelands, the ``FileRead`` and ``FileWrite``
-classes and with the Luna class concepts.
+this, I used a library called Eris_.  
 
-.. _Pluto: http://luaforge.net/projects/pluto/
+.. _Eris: https://github.com/fnuecke
  
 The global environment is persisted into the file map/globals.dump. Everything
 is persisted except of the Lua build-in functions and everything in the ``wl``
-table. Those are c-functions that can not be written out to disk portably.
-Everything else can be saved, that is also everything in the auxiliary scripts
-are saved to disk, so save games only depend on the API defined inside the
-``wl`` module.
+table and some of our own global functions. Those are c-functions that can not
+be written out to disk portably. Everything else can be saved, that is also
+everything in the auxiliary scripts are saved to disk, so save games only
+depend on the API defined inside the Widelands.
 
-Coroutines are persisted together with their ``Cmd_LuaCoroutine`` package. 
+Coroutines are persisted in their ``Cmd_LuaCoroutine`` package. 
 
 Luna classes have to implement two functions to be properly persistable:
 
@@ -130,9 +128,10 @@
 ``__unpersist(lua_State *)``
    On loading, an instance of the user object is created via the default
    constructor. This function is then called with the table that was created
-   by ``__persist()`` on the top of the stack. The object is then expected to
-   recreate it's former state with this table. There are equivalent
-   unpersisting macros defined to help with this task (e.g. UNPERS_UINT32).
+   by ``__persist()`` as an upvalue (because it is inside a closure). The
+   object is then expected to recreate it's former state with this table.
+   There are equivalent unpersisting macros defined to help with this task
+   (e.g. UNPERS_UINT32).
 
 Widelands reassigns some serial number upon saving and restores them upon
 loading. Some Luna classes need this information (for example

=== modified file 'scripting/lunit.lua'
--- scripting/lunit.lua	2013-10-10 20:39:19 +0000
+++ scripting/lunit.lua	2013-10-19 12:35:28 +0000
@@ -28,60 +28,18 @@
     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+
+    This file was heavily modified for the internal use of Widelands.
+
 --]]--------------------------------------------------------------------------
 
-
-
-
------------------------
--- Intialize package --
------------------------
-
-local P = { }
-lunit = P
-
--- Import
-local type = type
-local print = print
-local ipairs = ipairs
-local pairs = pairs
-local string = string
-local table = table
-local pcall = pcall
-local xpcall = xpcall
-local debug = debug
-local assert = assert
-local error = error
-local setmetatable = setmetatable
-local rawset = rawset
-local getfenv = getfenv
-local setfenv = setfenv
-local tostring = tostring
-
-
--- Start package scope
-setfenv(1, P)
-
-
-
-
---------------------------------
--- Private data and functions --
---------------------------------
-
-local run_testcase
-local do_assert, check_msg
-local stats = { }
-local testcases = { }
-local stats_inc, tc_mt
-
-
-
+lunit = {}
+lunit.testcases = {}
+lunit.stats = {}
 
 --------------------------
 -- Type check functions --
 --------------------------
-
 function is_nil(x)
   return type(x) == "nil"
 end
@@ -114,229 +72,198 @@
   return type(x) == "userdata"
 end
 
-
-
-
 ----------------------
 -- Assert functions --
 ----------------------
-
 function assert_fail(msg)
-  stats_inc("assertions")
-  check_msg("assert_fail", msg)
-  do_assert(false, "failure", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_fail", msg)
+  lunit_do_assert(false, "failure", msg)
 end
 
-
 function assert_true(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_true", msg)
-  do_assert(is_boolean(actual), "true expected but was a "..type(actual), msg)
-  do_assert(actual == true, "true expected but was false", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_true", msg)
+  lunit_do_assert(is_boolean(actual), "true expected but was a "..type(actual), msg)
+  lunit_do_assert(actual == true, "true expected but was false", msg)
   return actual
 end
 
-
 function assert_false(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_false", msg)
-  do_assert(is_boolean(actual), "false expected but was a "..type(actual), msg)
-  do_assert(actual == false, "false expected but was true", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_false", msg)
+  lunit_do_assert(is_boolean(actual), "false expected but was a "..type(actual), msg)
+  lunit_do_assert(actual == false, "false expected but was true", msg)
   return actual
 end
 
-
 function assert_equal(expected, actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_equal", msg)
-  do_assert(expected == actual, "expected '"..tostring(expected).."' but was '"..tostring(actual).."'", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_equal", msg)
+  lunit_do_assert(expected == actual, "expected '"..tostring(expected).."' but was '"..tostring(actual).."'", msg)
   return actual
 end
 
-
 function assert_not_equal(unexpected, actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_not_equal", msg)
-  do_assert(unexpected ~= actual, "'"..tostring(expected).."' not expected but was one", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_not_equal", msg)
+  lunit_do_assert(unexpected ~= actual, "'"..tostring(expected).."' not expected but was one", msg)
   return actual
 end
 
-
 function assert_match(pattern, actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_match", msg)
-  do_assert(is_string(pattern), "assert_match expects the pattern as a string")
-  do_assert(is_string(actual), "expected a string to match pattern '"..pattern.."' but was a '"..type(actual).."'", msg)
-  do_assert(not not string.find(actual, pattern), "expected '"..actual.."' to match pattern '"..pattern.."' but doesn't", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_match", msg)
+  lunit_do_assert(is_string(pattern), "assert_match expects the pattern as a string")
+  lunit_do_assert(is_string(actual), "expected a string to match pattern '"..pattern.."' but was a '"..type(actual).."'", msg)
+  lunit_do_assert(not not string.find(actual, pattern), "expected '"..actual.."' to match pattern '"..pattern.."' but doesn't", msg)
   return actual
 end
 
-
 function assert_not_match(pattern, actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_not_match", msg)
-  do_assert(is_string(actual), "expected a string to not match pattern '"..pattern.."' but was a '"..type(actual).."'", msg)
-  do_assert(string.find(actual, pattern) == nil, "expected '"..actual.."' to not match pattern '"..pattern.."' but it does", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_not_match", msg)
+  lunit_do_assert(is_string(actual), "expected a string to not match pattern '"..pattern.."' but was a '"..type(actual).."'", msg)
+  lunit_do_assert(string.find(actual, pattern) == nil, "expected '"..actual.."' to not match pattern '"..pattern.."' but it does", msg)
   return actual
 end
 
-
 function assert_nil(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_nil", msg)
-  do_assert(is_nil(actual), "nil expected but was a "..type(actual), msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_nil", msg)
+  lunit_do_assert(is_nil(actual), "nil expected but was a "..type(actual), msg)
   return actual
 end
 
-
 function assert_not_nil(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_not_nil", msg)
-  do_assert(not is_nil(actual), "nil not expected but was one", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_not_nil", msg)
+  lunit_do_assert(not is_nil(actual), "nil not expected but was one", msg)
   return actual
 end
 
-
 function assert_boolean(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_boolean", msg)
-  do_assert(is_boolean(actual), "boolean expected but was a "..type(actual), msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_boolean", msg)
+  lunit_do_assert(is_boolean(actual), "boolean expected but was a "..type(actual), msg)
   return actual
 end
 
-
 function assert_not_boolean(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_not_boolean", msg)
-  do_assert(not is_boolean(actual), "boolean not expected but was one", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_not_boolean", msg)
+  lunit_do_assert(not is_boolean(actual), "boolean not expected but was one", msg)
   return actual
 end
 
-
 function assert_number(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_number", msg)
-  do_assert(is_number(actual), "number expected but was a "..type(actual), msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_number", msg)
+  lunit_do_assert(is_number(actual), "number expected but was a "..type(actual), msg)
   return actual
 end
 
-
 function assert_not_number(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_not_number", msg)
-  do_assert(not is_number(actual), "number not expected but was one", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_not_number", msg)
+  lunit_do_assert(not is_number(actual), "number not expected but was one", msg)
   return actual
 end
 
-
 function assert_string(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_string", msg)
-  do_assert(is_string(actual), "string expected but was a "..type(actual), msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_string", msg)
+  lunit_do_assert(is_string(actual), "string expected but was a "..type(actual), msg)
   return actual
 end
 
-
 function assert_not_string(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_not_string", msg)
-  do_assert(not is_string(actual), "string not expected but was one", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_not_string", msg)
+  lunit_do_assert(not is_string(actual), "string not expected but was one", msg)
   return actual
 end
 
-
 function assert_table(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_table", msg)
-  do_assert(is_table(actual), "table expected but was a "..type(actual), msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_table", msg)
+  lunit_do_assert(is_table(actual), "table expected but was a "..type(actual), msg)
   return actual
 end
 
-
 function assert_not_table(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_not_table", msg)
-  do_assert(not is_table(actual), "table not expected but was one", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_not_table", msg)
+  lunit_do_assert(not is_table(actual), "table not expected but was one", msg)
   return actual
 end
 
-
 function assert_function(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_function", msg)
-  do_assert(is_function(actual), "function expected but was a "..type(actual), msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_function", msg)
+  lunit_do_assert(is_function(actual), "function expected but was a "..type(actual), msg)
   return actual
 end
 
-
 function assert_not_function(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_not_function", msg)
-  do_assert(not is_function(actual), "function not expected but was one", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_not_function", msg)
+  lunit_do_assert(not is_function(actual), "function not expected but was one", msg)
   return actual
 end
 
-
 function assert_thread(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_thread", msg)
-  do_assert(is_thread(actual), "thread expected but was a "..type(actual), msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_thread", msg)
+  lunit_do_assert(is_thread(actual), "thread expected but was a "..type(actual), msg)
   return actual
 end
 
-
 function assert_not_thread(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_not_thread", msg)
-  do_assert(not is_thread(actual), "thread not expected but was one", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_not_thread", msg)
+  lunit_do_assert(not is_thread(actual), "thread not expected but was one", msg)
   return actual
 end
 
-
 function assert_userdata(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_userdata", msg)
-  do_assert(is_userdata(actual), "userdata expected but was a "..type(actual), msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_userdata", msg)
+  lunit_do_assert(is_userdata(actual), "userdata expected but was a "..type(actual), msg)
   return actual
 end
 
-
 function assert_not_userdata(actual, msg)
-  stats_inc("assertions")
-  check_msg("assert_not_userdata", msg)
-  do_assert(not is_userdata(actual), "userdata not expected but was one", msg)
+  lunit_stats_inc("assertions")
+  lunit_check_msg("assert_not_userdata", msg)
+  lunit_do_assert(not is_userdata(actual), "userdata not expected but was one", msg)
   return actual
 end
 
-
 function assert_error(msg, func)
-  stats_inc("assertions")
+  lunit_stats_inc("assertions")
   if is_nil(func) then func, msg = msg, nil end
-  check_msg("assert_error", msg)
-  do_assert(is_function(func), "assert_error expects a function as the last argument but it was a "..type(func))
+  lunit_check_msg("assert_error", msg)
+  lunit_do_assert(is_function(func), "assert_error expects a function as the last argument but it was a "..type(func))
   local ok, errmsg = pcall(func)
-  do_assert(ok == false, "error expected but no error occurred", msg)
+  lunit_do_assert(ok == false, "error expected but no error occurred", msg)
 end
 
-
 function assert_pass(msg, func)
-  stats_inc("assertions")
+  lunit_stats_inc("assertions")
   if is_nil(func) then func, msg = msg, nil end
-  check_msg("assert_pass", msg)
-  do_assert(is_function(func), "assert_pass expects a function as the last argument but it was a "..type(func))
+  lunit_check_msg("assert_pass", msg)
+  lunit_do_assert(is_function(func), "assert_pass expects a function as the last argument but it was a "..type(func))
   local ok, errmsg = pcall(func)
-  if not ok then do_assert(ok == true, "no error expected but error was: "..errmsg, msg) end
+  if not ok then lunit_do_assert(ok == true, "no error expected but error was: "..errmsg, msg) end
 end
 
 
-
-
 -----------------------------------------------------------
 -- Assert implementation that assumes it was called from --
 -- lunit code which was called directly from user code.  --
 -----------------------------------------------------------
-
-function do_assert(assertion, base_msg, user_msg)
+function lunit_do_assert(assertion, base_msg, user_msg)
   assert(is_boolean(assertion))
   assert(is_string(base_msg))
   assert(is_string(user_msg) or is_nil(user_msg))
@@ -352,8 +279,7 @@
 -------------------------------------------
 -- Checks the msg argument in assert_xxx --
 -------------------------------------------
-
-function check_msg(name, msg)
+function lunit_check_msg(name, msg)
   assert(is_string(name))
   if not (is_nil(msg) or is_string(msg)) then
     error("lunit."..name.."() expects the optional message as a string but it was a "..type(msg).."!" ,3)
@@ -361,26 +287,23 @@
 end
 
 
-
-
 -------------------------------------
 -- Creates a new TestCase 'Object' --
 -------------------------------------
-
-function TestCase(name)
-  do_assert(is_string(name), "lunit.TestCase() needs a string as an argument")
+function lunit.TestCase(name)
+  lunit_do_assert(is_string(name), "lunit.TestCase() needs a string as an argument")
   local tc = {
     __lunit_name = name;
     __lunit_setup = nil;
     __lunit_tests = { };
     __lunit_teardown = nil;
   }
-  setmetatable(tc, tc_mt)
-  table.insert(testcases, tc)
+  setmetatable(tc, lunit.tc_mt)
+  table.insert(lunit.testcases, tc)
   return tc
 end
 
-tc_mt = {
+lunit.tc_mt = {
   __newindex = function(tc, key, value)
     rawset(tc, key, value)
     if is_string(key) and is_function(value) then
@@ -396,84 +319,69 @@
   end
 }
 
-
-
 -----------------------------------------
 -- Wrap Functions in a TestCase object --
 -----------------------------------------
-
 function wrap(name, ...)
   if is_function(name) then
     table.insert(arg, 1, name)
     name = "Anonymous Testcase"
   end
 
-  local tc = TestCase(name)
+  local tc = lunit.TestCase(name)
   for index, test in ipairs(arg) do
     tc["Test #"..tostring(index)] = test
   end
   return tc
 end
 
-
-
-
-
-
 ----------------------------------
 -- Runs the complete Test Suite --
 ----------------------------------
-
-function run()
-
+function lunit.run()
   ---------------------------
   -- Initialize statistics --
   ---------------------------
-
-  stats.testcases = 0	-- Total number of Test Cases
-  stats.tests = 0	-- Total number of all Tests in all Test Cases
-  stats.run = 0		-- Number of Tests run
-  stats.notrun = 0	-- Number of Tests not run
-  stats.failed = 0	-- Number of Tests failed
-  stats.passed = 0	-- Number of Test passed
-  stats.assertions = 0	-- Number of all assertions made in all Test in all Test Cases
+  lunit.stats.ntestcases = 0	-- Total number of Test Cases
+  lunit.stats.tests = 0	-- Total number of all Tests in all Test Cases
+  lunit.stats.run = 0		-- Number of Tests run
+  lunit.stats.notrun = 0	-- Number of Tests not run
+  lunit.stats.failed = 0	-- Number of Tests failed
+  lunit.stats.passed = 0	-- Number of Test passed
+  lunit.stats.assertions = 0	-- Number of all assertions made in all Test in all Test Cases
 
   --------------------------------
   -- Count Test Cases and Tests --
   --------------------------------
-
-  stats.testcases = table.getn(testcases)
-
-  for _, tc in ipairs(testcases) do
-    stats_inc("tests" , table.getn(tc.__lunit_tests))
+  lunit.stats.ntestcases = #lunit.testcases
+
+  for _, tc in ipairs(lunit.testcases) do
+    lunit_stats_inc("tests" , #tc.__lunit_tests)
   end
 
   ------------------
   -- Print Header --
   ------------------
-
   print()
-  print("#### Test Suite with "..stats.tests.." Tests in "..stats.testcases.." Test Cases loaded.")
+  print("#### Test Suite with "..lunit.stats.tests.." Tests in "..lunit.stats.ntestcases.." Test Cases loaded.")
 
   ------------------------
   -- Run all Test Cases --
   ------------------------
-
-  for _, tc in ipairs(testcases) do
-    run_testcase(tc)
+  for _, tc in ipairs(lunit.testcases) do
+    lunit_run_testcase(tc)
   end
 
   ------------------
   -- Print Footer --
   ------------------
-
   print()
   print("#### Test Suite finished.")
 
-  local msg_assertions = stats.assertions.." Assertions checked. "
-  local msg_passed     = stats.passed == stats.tests and "All Tests passed" or  stats.passed.." Tests passed"
-  local msg_failed     = stats.failed > 0 and ", "..stats.failed.." failed" or ""
-  local msg_run	       = stats.notrun > 0 and ", "..stats.notrun.." not run" or ""
+  local msg_assertions = lunit.stats.assertions.." Assertions checked. "
+  local msg_passed     = lunit.stats.passed == lunit.stats.tests and "All Tests passed" or  lunit.stats.passed.." Tests passed"
+  local msg_failed     = lunit.stats.failed > 0 and ", "..lunit.stats.failed.." failed" or ""
+  local msg_run	       = lunit.stats.notrun > 0 and ", "..lunit.stats.notrun.." not run" or ""
 
   print()
   print(msg_assertions..msg_passed..msg_failed..msg_run.."!")
@@ -481,23 +389,17 @@
   -----------------
   -- Return code --
   -----------------
-
-  if stats.passed == stats.tests then
+  if lunit.stats.passed == lunit.stats.tests then
     return 0
   else
     return 1
   end
 end
 
-
-
-
 -----------------------------
 -- Runs a single Test Case --
 -----------------------------
-
-function run_testcase(tc)
-
+function lunit_run_testcase(tc)
   assert(is_table(tc))
   assert(is_table(tc.__lunit_tests))
   assert(is_string(tc.__lunit_name))
@@ -507,7 +409,6 @@
   --------------------------------------------
   -- Protected call to a Test Case function --
   --------------------------------------------
-
   local function call(errprefix, func)
     assert(is_string(errprefix))
     assert(is_function(func))
@@ -522,7 +423,6 @@
   ------------------------------------
   -- Calls setup() on the Test Case --
   ------------------------------------
-
   local function setup()
     if tc.__lunit_setup then
       return call("ERROR: setup() failed", tc.__lunit_setup)
@@ -534,15 +434,14 @@
   ------------------------------------------
   -- Calls a single Test on the Test Case --
   ------------------------------------------
-
   local function run(testname)
     assert(is_string(testname))
     assert(is_function(tc[testname]))
     local ok = call("FAIL: "..testname, tc[testname])
     if not ok then
-      stats_inc("failed")
+      lunit_stats_inc("failed")
     else
-      stats_inc("passed")
+      lunit_stats_inc("passed")
     end
     return ok
   end
@@ -550,7 +449,6 @@
   ---------------------------------------
   -- Calls teardown() on the Test Case --
   ---------------------------------------
-
   local function teardown()
      if tc.__lunit_teardown then
        call("WARNING: teardown() failed", tc.__lunit_teardown)
@@ -560,117 +458,28 @@
   ---------------------------------
   -- Run all Tests on a TestCase --
   ---------------------------------
-
   print()
-  print("#### Running '"..tc.__lunit_name.."' ("..table.getn(tc.__lunit_tests).." Tests)...")
+  print("#### Running '"..tc.__lunit_name.."' ("..#tc.__lunit_tests.." Tests)...")
 
   for _, testname in ipairs(tc.__lunit_tests) do
     if setup() then
       run(testname)
-      stats_inc("run")
+      lunit_stats_inc("run")
       teardown()
     else
       print("WARN: Skipping '"..testname.."'...")
-      stats_inc("notrun")
-    end
-  end
-
-end
-
-
-
-
----------------------
--- Import function --
----------------------
-
-function import(name)
-
-  do_assert(is_string(name), "lunit.import() expects a single string as argument")
-
-  local user_env = getfenv(2)
-
-  --------------------------------------------------
-  -- Installs a specific function in the user env --
-  --------------------------------------------------
-
-  local function install(funcname)
-    user_env[funcname] = P[funcname]
-  end
-
-
-  ----------------------------------------------------------
-  -- Install functions matching a pattern in the user env --
-  ----------------------------------------------------------
-
-  local function install_pattern(pattern)
-    for funcname, _ in pairs(P) do
-      if string.find(funcname, pattern) then
-        install(funcname)
-      end
-    end
-  end
-
-  ------------------------------------------------------------
-  -- Installs assert() and all assert_xxx() in the user env --
-  ------------------------------------------------------------
-
-  local function install_asserts()
-    install_pattern("^assert.*")
-  end
-
-  -------------------------------------------
-  -- Installs all is_xxx() in the user env --
-  -------------------------------------------
-
-  local function install_tests()
-    install_pattern("^is_.+")
-  end
-
-  if name == "asserts" or name == "assertions" then
-    install_asserts()
-  elseif name == "tests" or name == "checks" then
-    install_tests()
-  elseif name == "all" then
-    install_asserts()
-    install_tests()
-    install("TestCase")
-  elseif string.find(name, "^assert.*") and P[name] then
-    install(name)
-  elseif string.find(name, "^is_.+") and P[name] then
-    install(name)
-  elseif name == "TestCase" then
-    install("TestCase")
-  else
-    error("luniit.import(): invalid function '"..name.."' to import", 2)
-  end
-end
-
-
-
-
---------------------------------------------------
--- Installs a private environment on the caller --
---------------------------------------------------
-
-function setprivfenv()
-  local new_env = { }
-  local new_env_mt = { __index = getfenv(2) }
-  setmetatable(new_env, new_env_mt)
-  setfenv(2, new_env)
-end
-
-
-
+      lunit_stats_inc("notrun")
+    end
+  end
+end
 
 --------------------------------------------------
 -- Increments a counter in the statistics table --
 --------------------------------------------------
-
-function stats_inc(varname, value)
-  assert(is_table(stats))
+function lunit_stats_inc(varname, value)
+  assert(is_table(lunit.stats))
   assert(is_string(varname))
   assert(is_nil(value) or is_number(value))
-  if not stats[varname] then return end
-  stats[varname] = stats[varname] + (value or 1)
+  if not lunit.stats[varname] then return end
+  lunit.stats[varname] = lunit.stats[varname] + (value or 1)
 end

=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt	2012-11-30 18:16:47 +0000
+++ src/CMakeLists.txt	2013-10-19 12:35:28 +0000
@@ -36,10 +36,10 @@
     list (REMOVE_ITEM WL_SRCS_CC ${sourcefile})
     list (REMOVE_ITEM WL_SRCS_H ${sourcefile})
   endif (${sourcefile} MATCHES ".*/test/.*")
-  # exclude test sources from Codecheck, as well as the scripting/pdep sources from lua
-  if (NOT ${sourcefile} MATCHES ".*/scripting/pdep/.*" AND NOT ${sourcefile} MATCHES ".*/test/.*")
+  # exclude test sources from Codecheck, as well as the scripting/eris sources from lua
+  if (NOT ${sourcefile} MATCHES ".*/scripting/eris/.*" AND NOT ${sourcefile} MATCHES ".*/test/.*")
     list (APPEND WL_CODECHECK_SRCS ${sourcefile})
-  endif (NOT ${sourcefile} MATCHES ".*/scripting/pdep/.*" AND NOT ${sourcefile} MATCHES ".*/test/.*")
+  endif (NOT ${sourcefile} MATCHES ".*/scripting/eris/.*" AND NOT ${sourcefile} MATCHES ".*/test/.*")
 endforeach (sourcefile ${WL_SRCS_CC} ${WL_SRCS_H})
 foreach (sourcefile ${WL_SRCS_CPP})
   list (APPEND WL_CODECHECK_SRCS ${sourcefile})
@@ -91,29 +91,31 @@
   # Tests need to link with SDL library without main
   set(TEST_EXTRA_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/build_info.cc)
   set(TEST_EXTRA_LIBS ${SDL_LIBRARY} )
-  list(REMOVE_ITEM TEST_EXTRA_LIBS  ${SDLMAIN_LIBRARY}) 
+  list(REMOVE_ITEM TEST_EXTRA_LIBS  ${SDLMAIN_LIBRARY})
 
   add_subdirectory(economy)
   add_subdirectory(io)
-  add_subdirectory(scripting)
 endif (WL_UNIT_TESTS)
 
+add_subdirectory(scripting)
+
 if (NOT MINIZIP_FOUND)
   add_subdirectory(minizip)
   target_link_libraries(widelands_all wl_minizip)
 endif (NOT MINIZIP_FOUND)
 
+target_link_libraries(widelands_all eris)
 target_link_libraries(widelands_all ${SDLIMAGE_LIBRARY})
 target_link_libraries(widelands_all ${SDLMIXER_LIBRARY})
 target_link_libraries(widelands_all ${SDLNET_LIBRARY})
 target_link_libraries(widelands_all ${SDLTTF_LIBRARY})
 target_link_libraries(widelands_all ${SDLGFX_LIBRARY})
-target_link_libraries(widelands_all ${LUA_LIBRARY})
 target_link_libraries(widelands_all ${PNG_LIBRARY})
 target_link_libraries(widelands_all ${ZLIB_LIBRARY})
 target_link_libraries(widelands_all ${OPENGL_gl_LIBRARY})
 target_link_libraries(widelands_all ${GLEW_LIBRARY})
 target_link_libraries(widelands_all ${Boost_SIGNALS_LIBRARY})
+
 if (MINIZIP_FOUND)
   target_link_libraries(widelands_all ${MINIZIP_LIBRARY})
 endif (MINIZIP_FOUND)

=== modified file 'src/logic/editor_game_base.cc'
--- src/logic/editor_game_base.cc	2013-08-06 10:40:54 +0000
+++ src/logic/editor_game_base.cc	2013-10-19 12:35:28 +0000
@@ -69,7 +69,7 @@
 m_lasttrackserial   (0)
 {
 	if (not m_lua) // TODO SirVer: this is sooo ugly, I can't say
-		m_lua = create_LuaEditorInterface(this);
+		m_lua = new LuaEditorInterface(this);
 
 	g_sound_handler.m_egbase = this;
 

=== modified file 'src/logic/game.cc'
--- src/logic/game.cc	2013-10-16 19:29:35 +0000
+++ src/logic/game.cc	2013-10-19 12:35:28 +0000
@@ -128,7 +128,7 @@
 
 
 Game::Game() :
-	Editor_Game_Base(create_LuaGameInterface(this)),
+	Editor_Game_Base(new LuaGameInterface(this)),
 	m_syncwrapper         (*this, m_synchash),
 	m_ctrl                (0),
 	m_writereplay         (true),

=== modified file 'src/logic/tribe.cc'
--- src/logic/tribe.cc	2013-10-08 20:13:35 +0000
+++ src/logic/tribe.cc	2013-10-19 12:35:28 +0000
@@ -298,7 +298,7 @@
 			}
 
 			// Read initializations -- all scripts are initializations currently
-			ScriptContainer & scripts =
+			const ScriptContainer& scripts =
 				egbase.lua().get_scripts_for("tribe_" + tribename);
 			container_iterate_const(ScriptContainer, scripts, s) {
 				std::unique_ptr<LuaTable> t =
@@ -376,7 +376,7 @@
 	buf            += name;
 	buf            += "/conf";
 
-	LuaInterface * lua = create_LuaInterface();
+	LuaInterface lua;
 	FileRead f;
 	if (f.TryOpen(*g_fs, buf.c_str())) {
 		if (info)
@@ -389,30 +389,25 @@
 				std::string path = "tribes/" + name + "/scripting";
 				if (g_fs->IsDirectory(path)) {
 					std::unique_ptr<FileSystem> sub_fs(g_fs->MakeSubFileSystem(path));
-					lua->register_scripts(*sub_fs, "tribe_" + name, "");
+					lua.register_scripts(*sub_fs, "tribe_" + name, "");
 				}
 
-				ScriptContainer & scripts = lua->get_scripts_for("tribe_" + name);
+				const ScriptContainer& scripts = lua.get_scripts_for("tribe_" + name);
 				container_iterate_const(ScriptContainer, scripts, s) {
 					std::unique_ptr<LuaTable> t =
-						lua->run_script("tribe_" + name, s->first);
+						lua.run_script("tribe_" + name, s->first);
 
 					info->initializations.push_back
 						(TribeBasicInfo::Initialization
 						 	(s->first, t->get_string("name")));
 				}
 			} catch (const _wexception & e) {
-				delete lua;
 				throw game_data_error
 					("reading basic info for tribe \"%s\": %s",
 					 name.c_str(), e.what());
 			}
-
-		delete lua;
 		return true;
 	}
-
-	delete lua;
 	return false;
 }
 

=== modified file 'src/map_io/widelands_map_scripting_data_packet.cc'
--- src/map_io/widelands_map_scripting_data_packet.cc	2013-10-08 20:13:35 +0000
+++ src/map_io/widelands_map_scripting_data_packet.cc	2013-10-19 12:35:28 +0000
@@ -60,11 +60,11 @@
 void Map_Scripting_Data_Packet::Write
 	(FileSystem & fs, Editor_Game_Base & egbase, Map_Map_Object_Saver & mos)
 {
-	ScriptContainer & p = egbase.lua().get_scripts_for("map");
+	const ScriptContainer& p = egbase.lua().get_scripts_for("map");
 
 	fs.EnsureDirectoryExists("scripting");
 
-	for (ScriptContainer::iterator i = p.begin(); i != p.end(); ++i) {
+	for (ScriptContainer::const_iterator i = p.begin(); i != p.end(); ++i) {
 		std::string fname = "scripting/";
 		fname += i->first;
 		fname += ".lua";

=== modified file 'src/network/netclient.cc'
--- src/network/netclient.cc	2013-09-20 17:47:29 +0000
+++ src/network/netclient.cc	2013-10-19 12:35:28 +0000
@@ -119,15 +119,14 @@
 	file = 0;
 
 	// Temporarily register win condition scripts to get the default
-	LuaInterface * lua = create_LuaInterface();
-	lua->register_scripts(*g_fs, "win_conditions", "scripting/win_conditions");
-	ScriptContainer sc = lua->get_scripts_for("win_conditions");
+	LuaInterface lua;
+	lua.register_scripts(*g_fs, "win_conditions", "scripting/win_conditions");
+	ScriptContainer sc = lua.get_scripts_for("win_conditions");
 	std::vector<std::string> win_conditions;
 	container_iterate_const(ScriptContainer, sc, wc)
 		win_conditions.push_back(wc->first);
 	assert(win_conditions.size());
 	d->settings.win_condition = win_conditions[0];
-	delete lua;
 }
 
 NetClient::~NetClient ()
@@ -906,16 +905,16 @@
 			info.name = packet.String();
 
 			// Get initializations (we have to do this locally, for translations)
-			LuaInterface * lua = create_LuaInterface();
+			LuaInterface lua;
 			std::string path = "tribes/" + info.name;
 			if (g_fs->IsDirectory(path)) {
 				std::unique_ptr<FileSystem> sub_fs(g_fs->MakeSubFileSystem(path));
-				lua->register_scripts(*sub_fs, "tribe_" + info.name, "scripting");
+				lua.register_scripts(*sub_fs, "tribe_" + info.name, "scripting");
 			}
 
 			for (uint8_t j = packet.Unsigned8(); j; --j) {
 				std::string const name = packet.String();
-				std::unique_ptr<LuaTable> t = lua->run_script
+				std::unique_ptr<LuaTable> t = lua.run_script
 					("tribe_" + info.name, name);
 				info.initializations.push_back
 					(TribeBasicInfo::Initialization(name, t->get_string("name")));

=== modified file 'src/network/nethost.cc'
--- src/network/nethost.cc	2013-10-08 20:13:35 +0000
+++ src/network/nethost.cc	2013-10-19 12:35:28 +0000
@@ -293,7 +293,7 @@
 		if (m_win_conditions.size() < 1) {
 			// Register win condition scripts
 			if (!m_lua)
-				m_lua = create_LuaInterface();
+				m_lua = new LuaInterface();
 			m_lua->register_scripts(*g_fs, "win_conditions", "scripting/win_conditions");
 
 			ScriptContainer sc = m_lua->get_scripts_for("win_conditions");

=== modified file 'src/scripting/CMakeLists.txt'
--- src/scripting/CMakeLists.txt	2010-11-01 03:43:56 +0000
+++ src/scripting/CMakeLists.txt	2013-10-19 12:35:28 +0000
@@ -1,4 +1,77 @@
+file(GLOB_RECURSE ERIS_SRCS_C *.c)
+file(GLOB_RECURSE ERIS_SRCS_H *.h)
+
+SET(ERIS_SOURCES
+  eris/eris.c
+  eris/lapi.c
+  eris/lauxlib.c
+  eris/lbaselib.c
+  eris/lbitlib.c
+  eris/lcode.c
+  eris/lcorolib.c
+  eris/lctype.c
+  eris/ldblib.c
+  eris/ldebug.c
+  eris/ldo.c
+  eris/ldump.c
+  eris/lfunc.c
+  eris/lgc.c
+  eris/linit.c
+  eris/liolib.c
+  eris/llex.c
+  eris/lmathlib.c
+  eris/lmem.c
+  eris/loadlib.c
+  eris/lobject.c
+  eris/lopcodes.c
+  eris/loslib.c
+  eris/lparser.c
+  eris/lstate.c
+  eris/lstring.c
+  eris/lstrlib.c
+  eris/ltable.c
+  eris/ltablib.c
+  eris/ltm.c
+  eris/lua.c
+  eris/luac.c
+  eris/lundump.c
+  eris/lvm.c
+  eris/lzio.c
+)
+
+SET(ERIS_HEADERS
+  eris/eris.h
+  eris/lapi.h
+  eris/lauxlib.h
+  eris/lcode.h
+  eris/lctype.h
+  eris/ldebug.h
+  eris/ldo.h
+  eris/lfunc.h
+  eris/lgc.h
+  eris/llex.h
+  eris/llimits.h
+  eris/lmem.h
+  eris/lobject.h
+  eris/lopcodes.h
+  eris/lparser.h
+  eris/lstate.h
+  eris/lstring.h
+  eris/ltable.h
+  eris/ltm.h
+  eris/lua.h
+  eris/luaconf.h
+  eris/lualib.h
+  eris/lundump.h
+  eris/lvm.h
+  eris/lzio.h
+)
+
+add_library(eris STATIC
+  ${ERIS_SOURCES}
+  ${ERIS_HEADERS}
+)
+
 if (WL_UNIT_TESTS)
   add_subdirectory(test)
 endif (WL_UNIT_TESTS)
-

=== modified file 'src/scripting/c_utils.cc'
--- src/scripting/c_utils.cc	2013-07-26 20:19:36 +0000
+++ src/scripting/c_utils.cc	2013-10-19 12:35:28 +0000
@@ -107,9 +107,8 @@
 	vsnprintf(buffer, sizeof(buffer), fmt, va);
 	va_end(va);
 
-
 	// Also create a traceback
-	lua_getfield(L, LUA_GLOBALSINDEX, "debug");
+	lua_getglobal(L, "debug");
 	if (!lua_istable(L, -1)) {
 		lua_pop(L, 1);
 		return 1;
@@ -127,4 +126,3 @@
 
 	return 0;
 }
-

=== modified file 'src/scripting/c_utils.h'
--- src/scripting/c_utils.h	2013-07-26 20:19:36 +0000
+++ src/scripting/c_utils.h	2013-10-19 12:35:28 +0000
@@ -20,12 +20,12 @@
 #ifndef C_UTILS_H
 #define C_UTILS_H
 
-#include <lua.hpp>
 
-#include "scripting/factory.h"
 #include "logic/game.h"
 #include "map_io/widelands_map_map_object_loader.h"
 #include "map_io/widelands_map_map_object_saver.h"
+#include "scripting/eris/lua.hpp"
+#include "scripting/factory.h"
 
 Factory & get_factory(lua_State *);
 Widelands::Game & get_game(lua_State *);

=== removed file 'src/scripting/coroutine_impl.cc'
--- src/scripting/coroutine_impl.cc	2013-07-26 20:19:36 +0000
+++ src/scripting/coroutine_impl.cc	1970-01-01 00:00:00 +0000
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2006-2010 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#include "scripting/coroutine_impl.h"
-
-#include <csetjmp>
-
-#include <boost/lexical_cast.hpp>
-
-#include "log.h"
-#include "logic/player.h"
-#include "scripting/c_utils.h"
-#include "scripting/lua_game.h"
-#include "scripting/lua_map.h"
-#include "scripting/persistence.h"
-
-LuaCoroutine_Impl::LuaCoroutine_Impl(lua_State * ms)
-	: m_L(ms), m_idx(LUA_REFNIL), m_nargs(0)
-{
-	m_reference();
-}
-
-LuaCoroutine_Impl::~LuaCoroutine_Impl()
-{
-	m_unreference();
-}
-
-int LuaCoroutine_Impl::resume(uint32_t * sleeptime)
-{
-	int rv = lua_resume(m_L, m_nargs);
-	m_nargs = 0;
-	int n = lua_gettop(m_L);
-
-	uint32_t sleep_for = 0;
-	if (n == 1) {
-		sleep_for = luaL_checkint32(m_L, -1);
-		lua_pop(m_L, 1);
-	}
-
-	if (sleeptime)
-		*sleeptime = sleep_for;
-
-	if (rv != 0 && rv != YIELDED) {
-		// lua_error() never returns. prints error and exit program imediately
-		//return  lua_error(m_L);
-		const char * err = lua_tostring(m_L, -1);
-		throw LuaError(err);
-	}
-
-	return rv;
-}
-
-/*
- * Push an argument that will be passed to the coroutine the next time it is
- * resumed
- */
-void LuaCoroutine_Impl::push_arg(const Widelands::Player * plr) {
-	to_lua<LuaGame::L_Player>(m_L, new LuaGame::L_Player(plr->player_number()));
-	m_nargs++;
-}
-void LuaCoroutine_Impl::push_arg(const Widelands::Coords & coords) {
-	to_lua<LuaMap::L_Field>(m_L, new LuaMap::L_Field(coords));
-	++m_nargs;
-}
-
-#define COROUTINE_DATA_PACKET_VERSION 1
-uint32_t LuaCoroutine_Impl::write
-	(lua_State * parent, Widelands::FileWrite & fw,
-	 Widelands::Map_Map_Object_Saver & mos)
-{
-	fw.Unsigned8(COROUTINE_DATA_PACKET_VERSION);
-
-	// The current numbers of arguments on the stack
-	fw.Unsigned32(m_nargs);
-
-	// Empty table + object to persist on the stack Stack
-	lua_newtable(parent);
-	lua_pushthread(m_L);
-	lua_xmove (m_L, parent, 1);
-
-	return persist_object(parent, fw, mos);
-}
-
-void LuaCoroutine_Impl::read
-	(lua_State * parent, Widelands::FileRead & fr,
-	 Widelands::Map_Map_Object_Loader & mol, uint32_t size)
-{
-	uint8_t version = fr.Unsigned8();
-
-	if (version != COROUTINE_DATA_PACKET_VERSION)
-		throw wexception("Unknown data packet version: %i\n", version);
-
-	// The current numbers of arguments on the stack
-	m_nargs = fr.Unsigned32();
-
-	// Empty table + object to persist on the stack Stack
-	unpersist_object(parent, fr, mol, size);
-
-	m_L = luaL_checkthread(parent, -1);
-	lua_pop(parent, 1);
-
-	// Cache a lua reference to this object so that it does not
-	// get garbage collected
-	lua_pushthread(m_L);
-	m_idx = luaL_ref(m_L, LUA_REGISTRYINDEX);
-
-}
-
-/*
- * ========================================================================
- *                         PRIVATE FUNCTIONS
- * ========================================================================
- */
-/**
- * Cache a lua reference to this object so that it does not get garbage
- * collected
- */
-void LuaCoroutine_Impl::m_reference() {
-	if (m_L) {
-		lua_pushthread(m_L);
-		m_idx = luaL_ref(m_L, LUA_REGISTRYINDEX);
-	}
-}
-void LuaCoroutine_Impl::m_unreference() {
-	luaL_unref(m_L, LUA_REGISTRYINDEX, m_idx);
-}
-
-

=== removed file 'src/scripting/coroutine_impl.h'
--- src/scripting/coroutine_impl.h	2013-09-22 18:01:36 +0000
+++ src/scripting/coroutine_impl.h	1970-01-01 00:00:00 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2006-2010 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#ifndef COROUTINE_IMPL_H
-#define COROUTINE_IMPL_H
-
-#include "scripting/scripting.h"
-
-namespace Widelands {
-	class Player;
-}
-
-/*
-============================================
-       Lua Coroutine
-============================================
-*/
-class LuaCoroutine_Impl : public LuaCoroutine {
-public:
-	LuaCoroutine_Impl(lua_State * L);
-	virtual ~LuaCoroutine_Impl();
-
-	virtual int get_status() {return lua_status(m_L);}
-	virtual int resume(uint32_t * sleeptime = 0);
-
-	virtual uint32_t write
-		(lua_State *, Widelands::FileWrite &,
-		 Widelands::Map_Map_Object_Saver &);
-	virtual void read
-		(lua_State *, Widelands::FileRead &,
-		 Widelands::Map_Map_Object_Loader &, uint32_t);
-
-	virtual void push_arg(const Widelands::Player *);
-	virtual void push_arg(const Widelands::Coords &);
-
-private:
-	void m_reference();
-	void m_unreference();
-
-private:
-	lua_State * m_L;
-	uint32_t m_idx;
-	uint32_t m_nargs;
-};
-
-
-#endif /* end of include guard: COROUTINE_IMPL_H */

=== added directory 'src/scripting/eris'
=== added file 'src/scripting/eris.h'
--- src/scripting/eris.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2006-2013 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_ERIS_H
+#define WL_ERIS_H
+
+// We need eris in a cpp context. Include it as such.
+extern "C" {
+#include "scripting/eris/eris.h"
+}
+
+
+#endif /* end of include guard: WL_ERIS_H */

=== added file 'src/scripting/eris/Makefile'
--- src/scripting/eris/Makefile	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/Makefile	2013-10-19 12:35:28 +0000
@@ -0,0 +1,207 @@
+# Makefile for building Lua+Eris, based on the original Lua Makefile.
+
+# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
+
+# Your platform. See PLATS for possible values.
+PLAT= none
+
+CC= gcc
+CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS)
+LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
+LIBS= -lm $(SYSLIBS) $(MYLIBS)
+
+AR= ar rcu
+RANLIB= ranlib
+RM= rm -f
+
+SYSCFLAGS=
+SYSLDFLAGS=
+SYSLIBS=
+
+MYCFLAGS=
+MYLDFLAGS=
+MYLIBS=
+MYOBJS=eris.o
+
+# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
+
+PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris
+
+LUA_A=	liblua.a
+CORE_O=	lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \
+	lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \
+	ltm.o lundump.o lvm.o lzio.o
+LIB_O=	lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o \
+	lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o
+BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)
+
+LUA_T=	lua
+LUA_O=	lua.o
+
+LUAC_T=	luac
+LUAC_O=	luac.o
+
+TESTP_T= ../test/persist
+TESTP_O= ../test/persist.o
+
+TESTUP_T= ../test/unpersist
+TESTUP_O= ../test/unpersist.o
+
+ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O) $(TESTP_O) $(TESTUP_O)
+ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) $(TESTP_T) $(TESTUP_T)
+ALL_A= $(LUA_A)
+
+# Targets start here.
+default: $(PLAT)
+
+all:	$(ALL_T)
+
+o:	$(ALL_O)
+
+a:	$(ALL_A)
+
+$(LUA_A): $(BASE_O)
+	$(AR) $@ $(BASE_O)
+	$(RANLIB) $@
+
+$(LUA_T): $(LUA_O) $(LUA_A)
+	$(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
+
+$(LUAC_T): $(LUAC_O) $(LUA_A)
+	$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
+
+$(TESTP_T): $(TESTP_O) $(LUA_A)
+	$(CC) -o $@ $(LDFLAGS) $(TESTP_O) $(LUA_A) $(LIBS)
+
+$(TESTUP_T): $(TESTUP_O) $(LUA_A)
+	$(CC) -o $@ $(LDFLAGS) $(TESTUP_O) $(LUA_A) $(LIBS)
+
+$(TESTP_O): lua.h lualib.h lauxlib.h
+	$(CC) -c -o $@ ../test/persist.c -I../src
+
+$(TESTUP_O): ../test/unpersist.c lua.h lualib.h lauxlib.h
+	 $(CC) -c -o $@ ../test/unpersist.c -I../src
+
+clean:
+	$(RM) $(ALL_T) $(ALL_O)
+
+depend:
+	@$(CC) $(CFLAGS) -MM l*.c
+
+echo:
+	@echo "PLAT= $(PLAT)"
+	@echo "CC= $(CC)"
+	@echo "CFLAGS= $(CFLAGS)"
+	@echo "LDFLAGS= $(SYSLDFLAGS)"
+	@echo "LIBS= $(LIBS)"
+	@echo "AR= $(AR)"
+	@echo "RANLIB= $(RANLIB)"
+	@echo "RM= $(RM)"
+
+# Convenience targets for popular platforms
+ALL= all
+
+none:
+	@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
+	@echo "   $(PLATS)"
+
+aix:
+	$(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall"
+
+ansi:
+	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_ANSI"
+
+bsd:
+	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E"
+
+freebsd:
+	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline"
+
+generic: $(ALL)
+
+linux:
+	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"
+
+macosx:
+	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline"
+
+mingw:
+	$(MAKE) "LUA_A=lua52.dll" "LUA_T=lua.exe" \
+	"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
+	"SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe
+	$(MAKE) "LUAC_T=luac.exe" luac.exe
+	$(MAKE) "TESTP_T=../test/persist.exe" ../test/persist.exe
+	$(MAKE) "TESTUP_T=../test/unpersist.exe" ../test/unpersist.exe
+
+posix:
+	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX"
+
+solaris:
+	$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl"
+
+# list targets that do not create files (but not all makes understand .PHONY)
+.PHONY: all $(PLATS) default o a clean depend echo none
+
+# DO NOT DELETE
+
+lapi.o: lapi.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \
+ lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h ltable.h lundump.h \
+ lvm.h
+lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h
+lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h
+lbitlib.o: lbitlib.c lua.h luaconf.h lauxlib.h lualib.h
+lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
+ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \
+ lstring.h ltable.h lvm.h
+lcorolib.o: lcorolib.c lua.h luaconf.h lauxlib.h lualib.h
+lctype.o: lctype.c lctype.h lua.h luaconf.h llimits.h
+ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h
+ldebug.o: ldebug.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \
+ ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h ldebug.h ldo.h \
+ lfunc.h lstring.h lgc.h ltable.h lvm.h
+ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \
+ lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h \
+ lstring.h ltable.h lundump.h lvm.h
+ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \
+ lzio.h lmem.h lundump.h
+lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h \
+ lstate.h ltm.h lzio.h lmem.h
+lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
+ lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
+linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h
+liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h
+llex.o: llex.c lua.h luaconf.h lctype.h llimits.h ldo.h lobject.h \
+ lstate.h ltm.h lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h
+lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h
+lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
+ ltm.h lzio.h lmem.h ldo.h lgc.h
+loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h
+lobject.o: lobject.c lua.h luaconf.h lctype.h llimits.h ldebug.h lstate.h \
+ lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h lvm.h
+lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h
+loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h
+lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
+ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lfunc.h \
+ lstring.h lgc.h ltable.h
+lstate.o: lstate.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \
+ ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h lstring.h \
+ ltable.h
+lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \
+ ltm.h lzio.h lstring.h lgc.h
+lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h
+ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
+ ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
+ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h
+ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \
+ lmem.h lstring.h lgc.h ltable.h
+lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h
+luac.o: luac.c lua.h luaconf.h lauxlib.h lobject.h llimits.h lstate.h \
+ ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
+lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \
+ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h
+lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
+ lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h
+lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \
+ lzio.h
+eris.o: eris.c lua.h lauxlib.h lualib.h ldebug.h ldo.h lfunc.h lobject.h \
+ lstate.h lstring.h lzio.h eris.h

=== renamed file 'src/scripting/README.pluto' => 'src/scripting/eris/README.eris'
--- src/scripting/README.pluto	2010-01-30 14:54:27 +0000
+++ src/scripting/eris/README.eris	2013-10-19 12:35:28 +0000
@@ -1,11 +1,11 @@
-Our scripting support contains the stripped down essentials of pluto[1]. You
-find the complete source and README of pluto on the github repo from one of
-it's authors Rob Hoelz at [2]. Our version of pluto has been heavily modified
-to create system agnostic files and to work with the widelands file streaming.
-The Widelands Team wishes to expresses total and complete gratitude to the
-authors of Pluto for making it public domain. 
-
-[1] http://luaforge.net/projects/pluto/
-[2] http://github.com/hoelzro/pluto
+This directory contains a verbatim copy of Eris by Florian Nücke.
+
+URL: https://github.com/fnuecke/eris
+VERSION: 8746276c5dc8f81086c2687a3bb50ce1560abfb4
+
+We use this for heavy persistence and it also brings with it the Lua version
+that we use in Widelands. The Widelands Team wishes to expresses total and
+complete gratitude to the authors of Eris for making it available under the MIT
+License. 
 
    -- SirVer, in behalf of the Widelands Team

=== added file 'src/scripting/eris/eris.c'
--- src/scripting/eris/eris.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/eris.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,2636 @@
+/*
+Eris - Heavy-duty persistence for Lua 5.2.2 - Based on Pluto
+Copyright (c) 2013 by Florian Nuecke.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/* Standard library headers. */
+#include <assert.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Not using stdbool because Visual Studio lives in the past... */
+typedef int bool;
+#define false 0
+#define true 1
+
+/* Mark us as part of the Lua core to get access to what we need. */
+#define LUA_CORE
+
+/* Public Lua headers. */
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+
+/* Internal Lua headers. */
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "lzio.h"
+
+/* Eris header. */
+#include "eris.h"
+
+/*
+** {===========================================================================
+** Default settings.
+** ============================================================================
+*/
+
+/* Note that these are the default settings. They can be changed either from C
+ * by calling eris_g|set_setting() or from Lua using eris.settings(). */
+
+/* The metatable key we use to allow customized persistence for tables and
+ * userdata. */
+static const char *const kPersistKey = "__persist";
+
+/* Whether to pass the IO object (reader/writer) to the special function
+ * defined in the metafield or not. This is disabled per default because it
+ * mey allow Lua scripts to do more than they should. Enable this as needed. */
+static const bool kPassIOToPersist = false;
+
+/* Whether to persist debug information such as line numbers and upvalue and
+ * local variable names. */
+static const bool kWriteDebugInformation = true;
+
+/* Generate a human readable "path" that is shown together with error messages
+ * to indicate where in the object the error occurred. For example:
+ * eris.persist({false, bad = setmetatable({}, {__persist = false})})
+ * Will produce: main:1: attempt to persist forbidden table (root.bad)
+ * This can be used for debugging, but is disabled per default due to the
+ * processing and memory overhead this introduces. */
+static const bool kGeneratePath = false;
+
+/* The maximum object complexity. This is the number of allowed recursions when
+ * persisting or unpersisting an object, for example for nested tables. This is
+ * used to avoid segfaults when writing or reading user data. */
+static const lua_Unsigned kMaxComplexity = 10000;
+
+/*
+** ============================================================================
+** Lua internals interfacing.
+** ============================================================================
+*/
+
+/* Lua internals we use. We define these as macros to make it easier to swap
+ * them out, should the need ever arise. For example, the later Pluto versions
+ * copied these function to own files (presumably to allow building it as an
+ * extra shared library). These should be all functions we use that are not
+ * declared in lua.h or lauxlib.h. If there are some still directly in the code
+ * they were missed and should be replaced with a macro added here instead. */
+/* I'm quite sure we won't ever want to do this, because Eris needs a slightly
+ * patched Lua version to be able to persist some of the library functions,
+ * anyway: it needs to put the continuation C functions in the perms table. */
+/* ldebug.h */
+#define eris_ci_func ci_func
+/* ldo.h */
+#define eris_incr_top incr_top
+#define eris_savestack savestack
+#define eris_restorestack restorestack
+#define eris_reallocstack luaD_reallocstack
+/* lfunc.h */
+#define eris_newproto luaF_newproto
+#define eris_newLclosure luaF_newLclosure
+#define eris_newupval luaF_newupval
+#define eris_findupval luaF_findupval
+/* lgc.h */
+#define eris_barrierproto luaC_barrierproto
+/* lmem.h */
+#define eris_reallocvector luaM_reallocvector
+/* lobject.h */
+#define eris_ttypenv ttypenv
+#define eris_setnilvalue setnilvalue
+#define eris_setclLvalue setclLvalue
+#define eris_setobj setobj
+#define eris_setsvalue2n setsvalue2n
+/* lstate.h */
+#define eris_isLua isLua
+#define eris_gch gch
+#define eris_gco2uv gco2uv
+#define eris_obj2gco obj2gco
+#define eris_extendCI luaE_extendCI
+/* lstring. h */
+#define eris_newlstr luaS_newlstr
+/* lzio.h */
+#define eris_initbuffer luaZ_initbuffer
+#define eris_buffer luaZ_buffer
+#define eris_sizebuffer luaZ_sizebuffer
+#define eris_bufflen luaZ_bufflen
+#define eris_init luaZ_init
+#define eris_read luaZ_read
+
+/* These are required for cross-platform support, since the size of TValue may
+ * differ, so the byte offset used by savestack/restorestack in Lua it is not a
+ * valid measure. */
+#define eris_savestackidx(L, p) ((p) - (L)->stack)
+#define eris_restorestackidx(L, n) ((L)->stack + (n))
+
+/* Enabled if we have a patched version of Lua (for accessing internals). */
+#if 1
+
+/* Functions in Lua libraries used to access C functions we need to add to the
+ * permanents table to fully support yielded coroutines. */
+extern void eris_permbaselib(lua_State *L, bool forUnpersist);
+extern void eris_permcorolib(lua_State *L, bool forUnpersist);
+extern void eris_permloadlib(lua_State *L, bool forUnpersist);
+extern void eris_permiolib(lua_State *L, bool forUnpersist);
+extern void eris_permstrlib(lua_State *L, bool forUnpersist);
+
+/* Utility macro for populating the perms table with internal C functions. */
+#define populateperms(L, forUnpersist) {\
+  eris_permbaselib(L, forUnpersist);\
+  eris_permcorolib(L, forUnpersist);\
+  eris_permloadlib(L, forUnpersist);\
+  eris_permiolib(L, forUnpersist);\
+  eris_permstrlib(L, forUnpersist);\
+}
+
+#else
+
+/* Does nothing if we don't have a patched version of Lua. */
+#define populateperms(L, forUnpersist) ((void)0)
+
+#endif
+
+/*
+** ============================================================================
+** Constants, settings, types and forward declarations.
+** ============================================================================
+*/
+
+/* The "type" we write when we persist a value via a replacement from the
+ * permanents table. This is just an arbitrary number, but it must we lower
+ * than the reference offset (below) and outside the range Lua uses for its
+ * types (> LUA_TOTALTAGS). */
+#define ERIS_PERMANENT (LUA_TOTALTAGS + 1)
+
+/* This is essentially the first reference we'll use. We do this to save one
+ * field in our persisted data: if the value is smaller than this, the object
+ * itself follows, otherwise we have a reference to an already unpersisted
+ * object. Note that in the reftable the actual entries are still stored
+ * starting at the first array index to have a sequence (when unpersisting). */
+#define ERIS_REFERENCE_OFFSET (ERIS_PERMANENT + 1)
+
+/* Avoids having to write the NULL all the time, plus makes it easier adding
+ * a custom error message should you ever decide you want one. */
+#define eris_checkstack(L, n) luaL_checkstack(L, n, NULL)
+
+/* Used for internal consistency checks, for debugging. These are true asserts
+ * in the sense that they should never fire, even for bad inputs. */
+#if 0
+#define eris_assert(c) assert(c)
+#define eris_ifassert(e) e
+#else
+#define eris_assert(c) ((void)0)
+#define eris_ifassert(e) ((void)0)
+#endif
+
+/* State information when persisting an object. */
+typedef struct PersistInfo {
+  lua_Writer writer;
+  void *ud;
+  const char *metafield;
+  bool writeDebugInfo;
+} PersistInfo;
+
+/* State information when unpersisting an object. */
+typedef struct UnpersistInfo {
+  ZIO zio;
+  size_t sizeof_int;
+  size_t sizeof_size_t;
+} UnpersistInfo;
+
+/* Info shared in persist and unpersist. */
+typedef struct Info {
+  lua_State *L;
+  lua_Unsigned level;
+  int refcount; /* int because rawseti/rawgeti takes an int. */
+  lua_Unsigned maxComplexity;
+  bool generatePath;
+  bool passIOToPersist;
+  /* Which one it really is will always be clear from the context. */
+  union {
+    PersistInfo pi;
+    UnpersistInfo upi;
+  } u;
+} Info;
+
+/* Type names, used for error messages. */
+static const char *const kTypenames[] = {
+  "nil", "boolean", "lightuserdata", "number", "string",
+  "table", "function", "userdata", "thread", "proto", "upval"
+};
+
+/* Setting names as used in eris.settings / eris_g|set_setting. Also, the
+ * addresses of these static variables are used as keys in the registry of Lua
+ * states to save the current values of the settings (as light userdata). */
+static const char *const kSettingMetafield = "spkey";
+static const char *const kSettingPassIOToPersist = "spio";
+static const char *const kSettingGeneratePath = "path";
+static const char *const kSettingWriteDebugInfo = "debug";
+static const char *const kSettingMaxComplexity = "maxrec";
+
+/* Header we prefix to persisted data for a quick check when unpersisting. */
+static const char *const kHeader = "ERIS";
+#define HEADER_LENGTH sizeof(kHeader)
+
+/* Floating point number used to check compatibility of loaded data. */
+static const lua_Number kHeaderNumber = (lua_Number)-1.234567890;
+
+/* Stack indices of some internal values/tables, to avoid magic numbers. */
+#define PERMIDX 1
+#define REFTIDX 2
+#define BUFFIDX 3
+#define PATHIDX 4
+
+/* }======================================================================== */
+
+/*
+** {===========================================================================
+** Utility functions.
+** ============================================================================
+*/
+
+/* Pushes an object into the reference table when unpersisting. This creates an
+ * entry pointing from the id the object is referenced by to the object. */
+static int
+registerobject(Info *info) {                          /* perms reftbl ... obj */
+  const int reference = ++(info->refcount);
+  eris_checkstack(info->L, 1);
+  lua_pushvalue(info->L, -1);                     /* perms reftbl ... obj obj */
+  lua_rawseti(info->L, REFTIDX, reference);           /* perms reftbl ... obj */
+  return reference;
+}
+
+/** ======================================================================== */
+
+/* Pushes a TString* onto the stack if it holds a value, nil if it is NULL. */
+static void
+pushtstring(lua_State* L, TString *ts) {                               /* ... */
+  if (ts) {
+    eris_setsvalue2n(L, L->top, ts);
+    eris_incr_top(L);                                              /* ... str */
+  }
+  else {
+    lua_pushnil(L);                                                /* ... nil */
+  }
+}
+
+/* Creates a copy of the string on top of the stack and sets it as the value
+ * of the specified TString**. */
+static void
+copytstring(lua_State* L, TString **ts) {
+  size_t length;
+  const char *value = lua_tolstring(L, -1, &length);
+  *ts = eris_newlstr(L, value, length);
+}
+
+/** ======================================================================== */
+
+/* Pushes the specified segment to the current path, if we're generating one.
+ * This supports formatting strings using Lua's formatting capabilities. */
+static void
+pushpath(Info *info, const char* fmt, ...) {     /* perms reftbl var path ... */
+  if (!info->generatePath) {
+    return;
+  }
+  else {
+    va_list argp;
+    eris_checkstack(info->L, 1);
+    va_start(argp, fmt);
+    lua_pushvfstring(info->L, fmt, argp);    /* perms reftbl var path ... str */
+    va_end(argp);
+    lua_rawseti(info->L, PATHIDX, luaL_len(info->L, PATHIDX) + 1);
+  }                                              /* perms reftbl var path ... */
+}  
+
+/* Pops the last added segment from the current path if we're generating one. */
+static void
+poppath(Info *info) {                            /* perms reftbl var path ... */
+  if (!info->generatePath) {
+    return;
+  }
+  eris_checkstack(info->L, 1);
+  lua_pushnil(info->L);                      /* perms reftbl var path ... nil */
+  lua_rawseti(info->L, PATHIDX, luaL_len(info->L, PATHIDX));
+}                                                /* perms reftbl var path ... */
+
+/* Concatenates all current path segments into one string, pushes it and
+ * returns it. This is relatively inefficient, but it's for errors only and
+ * keeps the stack small, so it's better this way. */
+static const char*
+path(Info *info) {                               /* perms reftbl var path ... */
+  if (!info->generatePath) {
+    return "";
+  }
+  eris_checkstack(info->L, 3);
+  lua_pushstring(info->L, "");               /* perms reftbl var path ... str */
+  lua_pushnil(info->L);                  /* perms reftbl var path ... str nil */
+  while (lua_next(info->L, PATHIDX)) {   /* perms reftbl var path ... str k v */
+    lua_insert(info->L, -2);             /* perms reftbl var path ... str v k */
+    lua_insert(info->L, -3);             /* perms reftbl var path ... k str v */
+    lua_concat(info->L, 2);                /* perms reftbl var path ... k str */
+    lua_insert(info->L, -2);               /* perms reftbl var path ... str k */
+  }                                          /* perms reftbl var path ... str */
+  return lua_tostring(info->L, -1);
+}
+
+/* Generates an error message with the appended path, if available. */
+static int
+eris_error(Info *info, const char *fmt, ...) {                         /* ... */
+    va_list argp;
+    eris_checkstack(info->L, 5);
+
+    luaL_where(info->L, 1);                                     /* ... where */
+    va_start(argp, fmt);
+    lua_pushvfstring(info->L, fmt, argp);                    /* ... where str */
+    va_end(argp);
+    if (info->generatePath) {
+      lua_pushstring(info->L, " (");                    /* ... where str " (" */
+      path(info);                                 /* ...  where str " (" path */
+      lua_pushstring(info->L, ")");            /* ... where str " (" path ")" */
+      lua_concat(info->L, 5);                                      /* ... msg */
+    }
+    else {
+      lua_concat(info->L, 2);                                      /* ... msg */
+    }
+    return lua_error(info->L);
+}
+
+/** ======================================================================== */
+
+/* Tries to get a setting from the registry. */
+static bool
+get_setting(lua_State *L, void *key) {                                 /* ... */
+  eris_checkstack(L, 1);
+  lua_pushlightuserdata(L, key);                                   /* ... key */
+  lua_gettable(L, LUA_REGISTRYINDEX);                        /* ... value/nil */
+  if (lua_isnil(L, -1)) {                                          /* ... nil */
+    lua_pop(L, 1);                                                     /* ... */
+    return false;
+  }                                                              /* ... value */
+  return true;
+}
+
+/* Stores a setting in the registry (or removes it if the value is nil). */
+static void
+set_setting(lua_State *L, void *key) {                           /* ... value */
+  eris_checkstack(L, 2);
+  lua_pushlightuserdata(L, key);                             /* ... value key */
+  lua_insert(L, -2);                                         /* ... key value */
+  lua_settable(L, LUA_REGISTRYINDEX);                                  /* ... */
+}
+
+/* Used as a callback for luaL_opt to check boolean setting values. */
+static void
+checkboolean(lua_State *L, int narg) {                       /* ... bool? ... */
+  if (!lua_isboolean(L, narg)) {                                /* ... :( ... */
+    luaL_argerror(L, narg, lua_pushfstring(L,
+      "boolean expected, got %s", lua_typename(L, lua_type(L, narg))));
+  }                                                           /* ... bool ... */
+}
+
+/* }======================================================================== */
+
+/*
+** {===========================================================================
+** Persist and unpersist.
+** ============================================================================
+*/
+
+/* I have macros and I'm not afraid to use them! These are highly situational
+ * and assume an Info* named 'info' is available. */
+
+/* Writes a raw memory block with the specified size. */
+#define WRITE_RAW(value, size) {\
+  if (info->u.pi.writer(info->L, (value), (size), info->u.pi.ud)) \
+    eris_error(info, "could not write data"); }
+
+/* Writes a single value with the specified type. */
+#define WRITE_VALUE(value, type) write_##type(info, value)
+
+/* Writes a typed array with the specified length. */
+#define WRITE(value, length, type) { \
+    int i; for (i = 0; i < length; ++i) WRITE_VALUE((value)[i], type); }
+
+/** ======================================================================== */
+
+/* Reads a raw block of memory with the specified size. */
+#define READ_RAW(value, size) {\
+  if (eris_read(&info->u.upi.zio, (value), (size))) \
+    eris_error(info, "could not read data"); }
+
+/* Reads a single value with the specified type. */
+#define READ_VALUE(type) read_##type(info)
+
+/* Reads a typed array with the specified length. */
+#define READ(value, length, type) { \
+    int i; for (i = 0; i < length; ++i) (value)[i] = READ_VALUE(type); }
+
+/** ======================================================================== */
+
+static void
+write_uint8_t(Info *info, uint8_t value) {
+  WRITE_RAW(&value, sizeof(uint8_t));
+}
+
+static void
+write_uint16_t(Info *info, uint16_t value) {
+  write_uint8_t(info, value);
+  write_uint8_t(info, value >> 8);
+}
+
+static void
+write_uint32_t(Info *info, uint32_t value) {
+  write_uint8_t(info, value);
+  write_uint8_t(info, value >> 8);
+  write_uint8_t(info, value >> 16);
+  write_uint8_t(info, value >> 24);
+}
+
+static void
+write_uint64_t(Info *info, uint64_t value) {
+  write_uint8_t(info, value);
+  write_uint8_t(info, value >> 8);
+  write_uint8_t(info, value >> 16);
+  write_uint8_t(info, value >> 24);
+  write_uint8_t(info, value >> 32);
+  write_uint8_t(info, value >> 40);
+  write_uint8_t(info, value >> 48);
+  write_uint8_t(info, value >> 56);
+}
+
+static void
+write_int16_t(Info *info, int16_t value) {
+  write_uint16_t(info, (uint16_t)value);
+}
+
+static void
+write_int32_t(Info *info, int32_t value) {
+  write_uint32_t(info, (uint32_t)value);
+}
+
+static void
+write_int64_t(Info *info, int64_t value) {
+  write_uint64_t(info, (uint64_t)value);
+}
+
+static void
+write_float32(Info *info, float value) {
+  uint32_t rep;
+  memcpy(&rep, &value, sizeof(float));
+  write_uint32_t(info, rep);
+}
+
+static void
+write_float64(Info *info, double value) {
+  uint64_t rep;
+  memcpy(&rep, &value, sizeof(double));
+  write_uint64_t(info, rep);
+}
+
+/* Note regarding the following: any decent compiler should be able
+ * to reduce these to just the write call, since sizeof is constant. */
+
+static void
+write_int(Info *info, int value) {
+  if (sizeof(int) == sizeof(int16_t)) {
+    write_int16_t(info, value);
+  }
+  else if (sizeof(int) == sizeof(int32_t)) {
+    write_int32_t(info, value);
+  }
+  else if (sizeof(int) == sizeof(int64_t)) {
+    write_int64_t(info, value);
+  }
+  else {
+    eris_error(info, "unsupported int type");
+  }
+}
+
+static void
+write_size_t(Info *info, size_t value) {
+  if (sizeof(size_t) == sizeof(uint16_t)) {
+    write_uint16_t(info, value);
+  }
+  else if (sizeof(size_t) == sizeof(uint32_t)) {
+    write_uint32_t(info, value);
+  }
+  else if (sizeof(size_t) == sizeof(uint64_t)) {
+    write_uint64_t(info, value);
+  }
+  else {
+    eris_error(info, "unsupported size_t type");
+  }
+}
+
+static void
+write_lua_Number(Info *info, lua_Number value) {
+  if (sizeof(lua_Number) == sizeof(uint32_t)) {
+    write_float32(info, value);
+  }
+  else if (sizeof(lua_Number) == sizeof(uint64_t)) {
+    write_float64(info, value);
+  }
+  else {
+    eris_error(info, "unsupported lua_Number type");
+  }
+}
+
+/* Note that Lua only ever uses 32 bits of the Instruction type, so we can
+ * assert that there will be no truncation, even if the underlying type has
+ * more bits (might be the case on some 64 bit systems). */
+
+static void
+write_Instruction(Info *info, Instruction value) {
+  if (sizeof(Instruction) == sizeof(uint32_t)) {
+    write_uint32_t(info, value);
+  }
+  else {
+    uint32_t pvalue = (uint32_t)value;
+    /* Lua only uses 32 bits for its instructions. */
+    eris_assert((Instruction)pvalue == value);
+    write_uint32_t(info, pvalue);
+  }
+}
+
+/** ======================================================================== */
+
+static uint8_t
+read_uint8_t(Info *info) {
+  uint8_t value;
+  READ_RAW(&value, sizeof(uint8_t));
+  return value;
+}
+
+static uint16_t
+read_uint16_t(Info *info) {
+  return  (uint16_t)read_uint8_t(info) |
+         ((uint16_t)read_uint8_t(info) << 8);
+}
+
+static uint32_t
+read_uint32_t(Info *info) {
+  return  (uint32_t)read_uint8_t(info) |
+         ((uint32_t)read_uint8_t(info) << 8) |
+         ((uint32_t)read_uint8_t(info) << 16) |
+         ((uint32_t)read_uint8_t(info) << 24);
+}
+
+static uint64_t
+read_uint64_t(Info *info) {
+  return  (uint64_t)read_uint8_t(info) |
+         ((uint64_t)read_uint8_t(info) << 8) |
+         ((uint64_t)read_uint8_t(info) << 16) |
+         ((uint64_t)read_uint8_t(info) << 24) |
+         ((uint64_t)read_uint8_t(info) << 32) |
+         ((uint64_t)read_uint8_t(info) << 40) |
+         ((uint64_t)read_uint8_t(info) << 48) |
+         ((uint64_t)read_uint8_t(info) << 56);
+}
+
+static int16_t
+read_int16_t(Info *info) {
+  return (int16_t)read_uint16_t(info);
+}
+
+static int32_t
+read_int32_t(Info *info) {
+  return (int32_t)read_uint32_t(info);
+}
+
+static int64_t
+read_int64_t(Info *info) {
+  return (int64_t)read_uint64_t(info);
+}
+
+static float
+read_float32(Info *info) {
+  float value;
+  uint32_t rep = read_uint32_t(info);
+  memcpy(&value, &rep, sizeof(float));
+  return value;
+}
+
+static double
+read_float64(Info *info) {
+  double value;
+  uint64_t rep = read_uint64_t(info);
+  memcpy(&value, &rep, sizeof(double));
+  return value;
+}
+
+/* Note regarding the following: unlike with writing the sizeof check will be
+ * impossible to optimize away, since it depends on the input; however, the
+ * truncation check may be optimized away in the case where the read data size
+ * equals the native one, so reading data written on the same machine should be
+ * reasonably quick. Doing a (rather rudimentary) benchmark this did not have
+ * any measurable impact on performance. */
+
+static int
+read_int(Info *info) {
+  int value;
+  if (info->u.upi.sizeof_int == sizeof(int16_t)) {
+    int16_t pvalue = read_int16_t(info);
+    value = (int)pvalue;
+    if ((int32_t)value != pvalue) {
+      eris_error(info, "int value would get truncated");
+    }
+  }
+  else if (info->u.upi.sizeof_int == sizeof(int32_t)) {
+    int32_t pvalue = read_int32_t(info);
+    value = (int)pvalue;
+    if ((int32_t)value != pvalue) {
+      eris_error(info, "int value would get truncated");
+    }
+  }
+  else if (info->u.upi.sizeof_int == sizeof(int64_t)) {
+    int64_t pvalue = read_int64_t(info);
+    value = (int)pvalue;
+    if ((int64_t)value != pvalue) {
+      eris_error(info, "int value would get truncated");
+    }
+  }
+  else {
+    eris_error(info, "unsupported int type");
+    value = 0; /* not reached */
+  }
+  return value;
+}
+
+static size_t
+read_size_t(Info *info) {
+  size_t value;
+  if (info->u.upi.sizeof_size_t == sizeof(uint16_t)) {
+    uint16_t pvalue = read_uint16_t(info);
+    value = (size_t)pvalue;
+    if ((uint32_t)value != pvalue) {
+      eris_error(info, "size_t value would get truncated");
+    }
+  }
+  else if (info->u.upi.sizeof_size_t == sizeof(uint32_t)) {
+    uint32_t pvalue = read_uint32_t(info);
+    value = (size_t)pvalue;
+    if ((uint32_t)value != pvalue) {
+      eris_error(info, "size_t value would get truncated");
+    }
+  }
+  else if (info->u.upi.sizeof_size_t == sizeof(uint64_t)) {
+    uint64_t pvalue = read_uint64_t(info);
+    value = (size_t)pvalue;
+    if ((uint64_t)value != pvalue) {
+      eris_error(info, "size_t value would get truncated");
+    }
+  }
+  else {
+    eris_error(info, "unsupported size_t type");
+    value = 0; /* not reached */
+  }
+  return value;
+}
+
+static lua_Number
+read_lua_Number(Info *info) {
+  if (sizeof(lua_Number) == sizeof(uint32_t)) {
+    return read_float32(info);
+  }
+  else if (sizeof(lua_Number) == sizeof(uint64_t)) {
+    return read_float64(info);
+  }
+  else {
+    eris_error(info, "unsupported lua_Number type");
+    return 0; /* not reached */
+  }
+}
+
+static Instruction
+read_Instruction(Info *info) {
+  return (Instruction)read_uint32_t(info);
+}
+
+/** ======================================================================== */
+
+/* Forward declarations for recursively called top-level functions. */
+static void persist_keyed(Info*, int type);
+static void persist(Info*);
+static void unpersist(Info*);
+
+/*
+** ============================================================================
+** Simple types.
+** ============================================================================
+*/
+
+static void
+p_boolean(Info *info) {                                           /* ... bool */
+  WRITE_VALUE(lua_toboolean(info->L, -1), uint8_t);
+}
+
+static void
+u_boolean(Info *info) {                                                /* ... */
+  eris_checkstack(info->L, 1);
+  lua_pushboolean(info->L, READ_VALUE(uint8_t));                  /* ... bool */
+
+  eris_assert(lua_type(info->L, -1) == LUA_TBOOLEAN);
+}
+
+/** ======================================================================== */
+
+static void
+p_pointer(Info *info) {                                         /* ... ludata */
+  WRITE_VALUE((size_t)lua_touserdata(info->L, -1), size_t);
+}
+
+static void
+u_pointer(Info *info) {                                                /* ... */
+  eris_checkstack(info->L, 1);
+  lua_pushlightuserdata(info->L, (void*)READ_VALUE(size_t));    /* ... ludata */
+
+  eris_assert(lua_type(info->L, -1) == LUA_TLIGHTUSERDATA);
+}
+
+/** ======================================================================== */
+
+static void
+p_number(Info *info) {                                             /* ... num */
+  WRITE_VALUE(lua_tonumber(info->L, -1), lua_Number);
+}
+
+static void
+u_number(Info *info) {                                                 /* ... */
+  eris_checkstack(info->L, 1);
+  lua_pushnumber(info->L, READ_VALUE(lua_Number));                 /* ... num */
+
+  eris_assert(lua_type(info->L, -1) == LUA_TNUMBER);
+}
+
+/** ======================================================================== */
+
+static void
+p_string(Info *info) {                                             /* ... str */
+  size_t length;
+  const char *value = lua_tolstring(info->L, -1, &length);
+  WRITE_VALUE(length, size_t);
+  WRITE_RAW(value, length);
+}
+
+static void
+u_string(Info *info) {                                                 /* ... */
+  eris_checkstack(info->L, 2);
+  {
+    /* TODO Can we avoid this copy somehow? (Without it getting too nasty) */
+    const size_t length = READ_VALUE(size_t);
+    char *value = lua_newuserdata(info->L, length * sizeof(char)); /* ... tmp */
+    READ_RAW(value, length);
+    lua_pushlstring(info->L, value, length);                   /* ... tmp str */
+    lua_replace(info->L, -2);                                      /* ... str */
+  }
+  registerobject(info);
+
+  eris_assert(lua_type(info->L, -1) == LUA_TSTRING);
+}
+
+/*
+** ============================================================================
+** Tables and userdata.
+** ============================================================================
+*/
+
+static void
+p_metatable(Info *info) {                                          /* ... obj */
+  eris_checkstack(info->L, 1);
+  pushpath(info, "@metatable");
+  if (!lua_getmetatable(info->L, -1)) {                        /* ... obj mt? */
+    lua_pushnil(info->L);                                      /* ... obj nil */
+  }                                                         /* ... obj mt/nil */
+  persist(info);                                            /* ... obj mt/nil */
+  lua_pop(info->L, 1);                                             /* ... obj */
+  poppath(info);
+}
+
+static void
+u_metatable(Info *info) {                                          /* ... tbl */
+  eris_checkstack(info->L, 1);
+  pushpath(info, "@metatable");
+  unpersist(info);                                         /* ... tbl mt/nil? */
+  if (lua_istable(info->L, -1)) {                               /* ... tbl mt */
+    lua_setmetatable(info->L, -2);                                 /* ... tbl */
+  }
+  else if (lua_isnil(info->L, -1)) {                           /* ... tbl nil */
+    lua_pop(info->L, 1);                                           /* ... tbl */
+  }
+  else {                                                            /* tbl :( */
+    eris_error(info, "bad metatable, not nil or table");
+  }
+  poppath(info);
+}
+
+/** ======================================================================== */
+
+static void
+p_literaltable(Info *info) {                                       /* ... tbl */
+  eris_checkstack(info->L, 3);
+
+  /* Persist all key / value pairs. */
+  lua_pushnil(info->L);                                        /* ... tbl nil */
+  while (lua_next(info->L, -2)) {                              /* ... tbl k v */
+    lua_pushvalue(info->L, -2);                              /* ... tbl k v k */
+
+    if (info->generatePath) {
+      if (lua_type(info->L, -1) == LUA_TSTRING) {
+        const char *key = lua_tostring(info->L, -1);
+        pushpath(info, ".%s", key);
+      }
+      else {
+        const char *key = luaL_tolstring(info->L, -1, NULL);
+        pushpath(info, "[%s]", key);
+        lua_pop(info->L, 1);
+      }
+    }
+
+    persist(info);                                           /* ... tbl k v k */
+    lua_pop(info->L, 1);                                       /* ... tbl k v */
+    persist(info);                                             /* ... tbl k v */
+    lua_pop(info->L, 1);                                         /* ... tbl k */
+
+    poppath(info);
+  }                                                                /* ... tbl */
+
+  /* Terminate list. */
+  lua_pushnil(info->L);                                        /* ... tbl nil */
+  persist(info);                                               /* ... tbl nil */
+  lua_pop(info->L, 1);                                             /* ... tbl */
+
+  p_metatable(info);
+}
+
+static void
+u_literaltable(Info *info) {                                           /* ... */
+  eris_checkstack(info->L, 3);
+
+  lua_newtable(info->L);                                           /* ... tbl */
+
+  /* Preregister table for handling of cycles (keys, values or metatable). */
+  registerobject(info);
+
+  /* Unpersist all key / value pairs. */
+  for (;;) {
+    pushpath(info, "@key");
+    unpersist(info);                                       /* ... tbl key/nil */
+    poppath(info);
+    if (lua_isnil(info->L, -1)) {                              /* ... tbl nil */
+      lua_pop(info->L, 1);                                         /* ... tbl */
+      break;
+    }                                                          /* ... tbl key */
+
+    if (info->generatePath) {
+      if (lua_type(info->L, -1) == LUA_TSTRING) {
+        const char *key = lua_tostring(info->L, -1);
+        pushpath(info, ".%s", key);
+      }
+      else {
+        const char *key = luaL_tolstring(info->L, -1, NULL);
+        pushpath(info, "[%s]", key);
+        lua_pop(info->L, 1);
+      }
+    }
+
+    unpersist(info);                                    /* ... tbl key value? */
+    if (!lua_isnil(info->L, -1)) {                       /* ... tbl key value */
+      lua_rawset(info->L, -3);                                     /* ... tbl */
+    }
+    else {
+      eris_error(info, "bad table value, got a nil value");
+    }
+
+    poppath(info);
+  }
+
+  u_metatable(info);                                               /* ... tbl */
+}
+
+/** ======================================================================== */
+
+static void
+p_literaluserdata(Info *info) {                                  /* ... udata */
+  const size_t size = lua_rawlen(info->L, -1);
+  const void *value = lua_touserdata(info->L, -1);
+  WRITE_VALUE(size, size_t);
+  WRITE_RAW(value, size);
+  p_metatable(info);                                             /* ... udata */
+}
+
+static void
+u_literaluserdata(Info *info) {                                        /* ... */
+  eris_checkstack(info->L, 1);
+  {
+    size_t size = READ_VALUE(size_t);
+    void *value = lua_newuserdata(info->L, size);                /* ... udata */
+    READ_RAW(value, size);                                       /* ... udata */
+  }
+  registerobject(info);
+  u_metatable(info);
+}
+
+/** ======================================================================== */
+
+typedef void (*Callback) (Info*);
+
+static void
+p_special(Info *info, Callback literal) {                          /* ... obj */
+  int allow = (lua_type(info->L, -1) == LUA_TTABLE);
+  eris_checkstack(info->L, 4);
+
+  /* Check whether we should persist literally, or via the metafunction. */
+  if (lua_getmetatable(info->L, -1)) {                          /* ... obj mt */
+    lua_pushstring(info->L, info->u.pi.metafield);         /* ... obj mt pkey */
+    lua_rawget(info->L, -2);                           /* ... obj mt persist? */
+    switch (lua_type(info->L, -1)) {
+      /* No entry, act according to default. */
+      case LUA_TNIL:                                        /* ... obj mt nil */
+        lua_pop(info->L, 2);                                       /* ... obj */
+        break;
+
+      /* Boolean value, tells us whether allowed or not. */
+      case LUA_TBOOLEAN:                                   /* ... obj mt bool */
+        allow = lua_toboolean(info->L, -1);
+        lua_pop(info->L, 2);                                       /* ... obj */
+        break;
+
+      /* Function value, call it and don't persist literally. */
+      case LUA_TFUNCTION:                                  /* ... obj mt func */
+        lua_replace(info->L, -2);                             /* ... obj func */
+        lua_pushvalue(info->L, -2);                       /* ... obj func obj */
+
+        if (info->passIOToPersist) {
+          lua_pushlightuserdata(info->L, info->u.pi.writer);
+                                                   /* ... obj func obj writer */
+          lua_pushlightuserdata(info->L, info->u.pi.ud);
+                                                /* ... obj func obj writer ud */
+          lua_call(info->L, 3, 1);                           /* ... obj func? */
+        }
+        else {
+          lua_call(info->L, 1, 1);                           /* ... obj func? */
+        }
+        if (!lua_isfunction(info->L, -1)) {                     /* ... obj :( */
+          eris_error(info, "%s did not return a function",
+                     info->u.pi.metafield);
+        }                                                     /* ... obj func */
+
+        /* Special persistence, call this function when unpersisting. */
+        WRITE_VALUE(true, uint8_t);
+        persist(info);                                        /* ... obj func */
+        lua_pop(info->L, 1);                                       /* ... obj */
+        return;
+      default:                                               /* ... obj mt :( */
+        eris_error(info, "%d not nil, boolean, or function",
+                   info->u.pi.metafield);
+        return; /* not reached */
+    }
+  }
+
+  if (allow) {
+    /* Not special but literally persisted object. */
+    WRITE_VALUE(false, uint8_t);
+    literal(info);                                                 /* ... obj */
+  }
+  else if (lua_type(info->L, -1) == LUA_TTABLE) {
+    eris_error(info, "attempt to persist forbidden table");
+  }
+  else {
+    eris_error(info, "attempt to literally persist userdata");
+  }
+}
+
+static void
+u_special(Info *info, int type, Callback literal) {                    /* ... */
+  eris_checkstack(info->L, 2);
+  if (READ_VALUE(uint8_t)) {
+    int reference;
+    /* Reserve entry in the reftable before unpersisting the function to keep
+     * the reference order intact. We can set this to nil at first, because
+     * there's no way the special function would access this. */
+    lua_pushnil(info->L);                                          /* ... nil */
+    reference = registerobject(info);
+    lua_pop(info->L, 1);                                               /* ... */
+    /* Increment reference counter by one to compensate for the increment when
+     * persisting a special object. */
+    unpersist(info);                                           /* ... spfunc? */
+    if (!lua_isfunction(info->L, -1)) {                             /* ... :( */
+      eris_error(info, "invalid restore function");
+    }                                                           /* ... spfunc */
+
+    if (info->passIOToPersist) {
+      lua_pushlightuserdata(info->L, &info->u.upi.zio);     /* ... spfunc zio */
+      lua_call(info->L, 1, 1);                                    /* ... obj? */
+    } else {
+      lua_call(info->L, 0, 1);                                    /* ... obj? */
+    }
+
+    if (lua_type(info->L, -1) != type) {                            /* ... :( */
+      eris_error(info, "bad unpersist function (%s expected, returned %s)",
+                       kTypenames[type], kTypenames[lua_type(info->L, -1)]);
+    }                                                              /* ... obj */
+
+    /* Update the reftable entry. */
+    lua_pushvalue(info->L, -1);                                /* ... obj obj */
+    lua_rawseti(info->L, 2, reference);                            /* ... obj */
+  }
+  else {
+    literal(info);                                                 /* ... obj */
+  }
+}
+
+/** ======================================================================== */
+
+static void
+p_table(Info *info) {                                              /* ... tbl */
+  p_special(info, p_literaltable);                                 /* ... tbl */
+}
+
+static void
+u_table(Info *info) {                                                  /* ... */
+  u_special(info, LUA_TTABLE, u_literaltable);                     /* ... tbl */
+
+  eris_assert(lua_type(info->L, -1) == LUA_TTABLE);
+}
+
+/** ======================================================================== */
+
+static void
+p_userdata(Info *info) {                            /* perms reftbl ... udata */
+  p_special(info, p_literaluserdata);
+}
+
+static void
+u_userdata(Info *info) {                                               /* ... */
+  u_special(info, LUA_TUSERDATA, u_literaluserdata);             /* ... udata */
+
+  eris_assert(lua_type(info->L, -1) == LUA_TUSERDATA);
+}
+
+/*
+** ============================================================================
+** Closures and threads.
+** ============================================================================
+*/
+
+/* We track the actual upvalues themselves by pushing their "id" (meaning a
+ * pointer to them) as lightuserdata to the reftable. This is safe because
+ * lightuserdata will not normally end up in there, because simple value types
+ * are always persisted directly (because that'll be just as large, memory-
+ * wise as when pointing to the first instance). Same for protos. */
+
+static void
+p_proto(Info *info) {                                            /* ... proto */
+  int i;
+  const Proto *p = lua_touserdata(info->L, -1);
+  eris_checkstack(info->L, 3);
+
+  /* Write general information. */
+  WRITE_VALUE(p->linedefined, int);
+  WRITE_VALUE(p->lastlinedefined, int);
+  WRITE_VALUE(p->numparams, uint8_t);
+  WRITE_VALUE(p->is_vararg, uint8_t);
+  WRITE_VALUE(p->maxstacksize, uint8_t);
+
+  /* Write byte code. */
+  WRITE_VALUE(p->sizecode, int);
+  WRITE(p->code, p->sizecode, Instruction);
+
+  /* Write constants. */
+  WRITE_VALUE(p->sizek, int);
+  pushpath(info, ".constants");
+  for (i = 0; i < p->sizek; ++i) {
+    pushpath(info, "[%d]", i);
+    eris_setobj(info->L, info->L->top++, &p->k[i]);      /* ... lcl proto obj */
+    persist(info);                                       /* ... lcl proto obj */
+    lua_pop(info->L, 1);                                     /* ... lcl proto */
+    poppath(info);
+  }
+  poppath(info);
+
+  /* Write child protos. */
+  WRITE_VALUE(p->sizep, int);
+  pushpath(info, ".protos");
+  for (i = 0; i < p->sizep; ++i) {
+    pushpath(info, "[%d]", i);
+    lua_pushlightuserdata(info->L, p->p[i]);           /* ... lcl proto proto */
+    lua_pushvalue(info->L, -1);                  /* ... lcl proto proto proto */
+    persist_keyed(info, LUA_TPROTO);                   /* ... lcl proto proto */
+    lua_pop(info->L, 1);                                     /* ... lcl proto */
+    poppath(info);
+  }
+  poppath(info);
+
+  /* Write upvalues. */
+  WRITE_VALUE(p->sizeupvalues, int);
+  for (i = 0; i < p->sizeupvalues; ++i) {
+    WRITE_VALUE(p->upvalues[i].instack, uint8_t);
+    WRITE_VALUE(p->upvalues[i].idx, uint8_t);
+  }
+
+  /* If we don't have to persist debug information skip the rest. */
+  WRITE_VALUE(info->u.pi.writeDebugInfo, uint8_t);
+  if (!info->u.pi.writeDebugInfo) {
+    return;
+  }
+
+  /* Write function source code. */
+  pushtstring(info->L, p->source);                    /* ... lcl proto source */
+  persist(info);                                      /* ... lcl proto source */
+  lua_pop(info->L, 1);                                       /* ... lcl proto */
+
+  /* Write line information. */
+  WRITE_VALUE(p->sizelineinfo, int);
+  WRITE(p->lineinfo, p->sizelineinfo, int);
+
+  /* Write locals info. */
+  WRITE_VALUE(p->sizelocvars, int);
+  pushpath(info, ".locvars");
+  for (i = 0; i < p->sizelocvars; ++i) {
+    pushpath(info, "[%d]", i);
+    WRITE_VALUE(p->locvars[i].startpc, int);
+    WRITE_VALUE(p->locvars[i].endpc, int);
+    pushtstring(info->L, p->locvars[i].varname);     /* ... lcl proto varname */
+    persist(info);                                   /* ... lcl proto varname */
+    lua_pop(info->L, 1);                                     /* ... lcl proto */
+    poppath(info);
+  }
+  poppath(info);
+
+  /* Write upvalue names. */
+  pushpath(info, ".upvalnames");
+  for (i = 0; i < p->sizeupvalues; ++i) {
+    pushpath(info, "[%d]", i);
+    pushtstring(info->L, p->upvalues[i].name);          /* ... lcl proto name */
+    persist(info);                                      /* ... lcl proto name */
+    lua_pop(info->L, 1);                                     /* ... lcl proto */
+    poppath(info);
+  }
+  poppath(info);
+}
+
+static void
+u_proto(Info *info) {                                            /* ... proto */
+  int i, n;
+  Proto *p = lua_touserdata(info->L, -1);
+  eris_assert(p);
+
+  eris_checkstack(info->L, 2);
+
+  /* Preregister proto for handling of cycles (probably impossible, but
+   * maybe via the constants of the proto... not worth taking the risk). */
+  registerobject(info);
+
+  /* Read general information. */
+  p->linedefined = READ_VALUE(int);
+  p->lastlinedefined = READ_VALUE(int);
+  p->numparams = READ_VALUE(uint8_t);
+  p->is_vararg = READ_VALUE(uint8_t);
+  p->maxstacksize = READ_VALUE(uint8_t);
+
+  /* Read byte code. */
+  p->sizecode = READ_VALUE(int);
+  eris_reallocvector(info->L, p->code, 0, p->sizecode, Instruction);
+  READ(p->code, p->sizecode, Instruction);
+
+  /* Read constants. */
+  p->sizek = READ_VALUE(int);
+  eris_reallocvector(info->L, p->k, 0, p->sizek, TValue);
+  /* Set all values to nil to avoid confusing the GC. */
+  for (i = 0, n = p->sizek; i < n; ++i) {
+    eris_setnilvalue(&p->k[i]);
+  }
+  pushpath(info, ".constants");
+  for (i = 0, n = p->sizek; i < n; ++i) {
+    pushpath(info, "[%d]", i);
+    unpersist(info);                                         /* ... proto obj */
+    eris_setobj(info->L, &p->k[i], info->L->top - 1);
+    lua_pop(info->L, 1);                                         /* ... proto */
+    poppath(info);
+  }
+  poppath(info);
+
+  /* Read child protos. */
+  p->sizep = READ_VALUE(int);
+  eris_reallocvector(info->L, p->p, 0, p->sizep, Proto*);
+  /* Null all entries to avoid confusing the GC. */
+  memset(p->p, 0, p->sizep * sizeof(Proto*));
+  pushpath(info, ".protos");
+  for (i = 0, n = p->sizep; i < n; ++i) {
+    Proto *cp;
+    pushpath(info, "[%d]", i);
+    p->p[i] = eris_newproto(info->L);
+    lua_pushlightuserdata(info->L, p->p[i]);              /* ... proto nproto */
+    unpersist(info);                        /* ... proto nproto nproto/oproto */
+    cp = lua_touserdata(info->L, -1);
+    if (cp != p->p[i]) {                           /* ... proto nproto oproto */
+      /* Just overwrite it, GC will clean this up. */
+      p->p[i] = cp;
+    }
+    lua_pop(info->L, 2);                                         /* ... proto */
+    poppath(info);
+  }
+  poppath(info);
+
+  /* Read upvalues. */
+  p->sizeupvalues = READ_VALUE(int);
+  eris_reallocvector(info->L, p->upvalues, 0, p->sizeupvalues, Upvaldesc);
+  for (i = 0, n = p->sizeupvalues; i < n; ++i) {
+    p->upvalues[i].name = NULL;
+    p->upvalues[i].instack = READ_VALUE(uint8_t);
+    p->upvalues[i].idx = READ_VALUE(uint8_t);
+  }
+
+  /* Read debug information if any is present. */
+  if (!READ_VALUE(uint8_t)) {
+    return;
+  }
+
+  /* Read function source code. */
+  unpersist(info);                                           /* ... proto str */
+  copytstring(info->L, &p->source);
+  lua_pop(info->L, 1);                                           /* ... proto */
+
+  /* Read line information. */
+  p->sizelineinfo = READ_VALUE(int);
+  eris_reallocvector(info->L, p->lineinfo, 0, p->sizelineinfo, int);
+  READ(p->lineinfo, p->sizelineinfo, int);
+
+  /* Read locals info. */
+  p->sizelocvars = READ_VALUE(int);
+  eris_reallocvector(info->L, p->locvars, 0, p->sizelocvars, LocVar);
+  /* Null the variable names to avoid confusing the GC. */
+  for (i = 0, n = p->sizelocvars; i < n; ++i) {
+    p->locvars[i].varname = NULL;
+  }
+  pushpath(info, ".locvars");
+  for (i = 0, n = p->sizelocvars; i < n; ++i) {
+    pushpath(info, "[%d]", i);
+    p->locvars[i].startpc = READ_VALUE(int);
+    p->locvars[i].endpc = READ_VALUE(int);
+    unpersist(info);                                         /* ... proto str */
+    copytstring(info->L, &p->locvars[i].varname);
+    lua_pop(info->L, 1);                                         /* ... proto */
+    poppath(info);
+  }
+  poppath(info);
+
+  /* Read upvalue names. */
+  pushpath(info, ".upvalnames");
+  for (i = 0, n = p->sizeupvalues; i < n; ++i) {
+    pushpath(info, "[%d]", i);
+    unpersist(info);                                         /* ... proto str */
+    copytstring(info->L, &p->upvalues[i].name);
+    lua_pop(info->L, 1);                                         /* ... proto */
+    poppath(info);
+  }
+  poppath(info);
+  lua_pushvalue(info->L, -1);                              /* ... proto proto */
+
+  eris_assert(lua_type(info->L, -1) == LUA_TLIGHTUSERDATA);
+}
+
+/** ======================================================================== */
+
+static void
+p_upval(Info *info) {                                              /* ... obj */
+  persist(info);                                                   /* ... obj */
+}
+
+static void
+u_upval(Info *info) {                                                  /* ... */
+  eris_checkstack(info->L, 2);
+
+  /* Create the table we use to store the pointer to the actual upval (1), the
+   * value of the upval (2) and any pointers to the pointer to the upval (3+).*/
+  lua_createtable(info->L, 3, 0);                                  /* ... tbl */
+  registerobject(info);
+  unpersist(info);                                             /* ... tbl obj */
+  lua_rawseti(info->L, -2, 1);                                     /* ... tbl */
+
+  eris_assert(lua_type(info->L, -1) == LUA_TTABLE);
+}
+
+/** ======================================================================== */
+
+/* For Lua closures we write the upvalue ID, which is usually the memory
+ * address at which it is stored. This is used to tell which upvalues are
+ * identical when unpersisting. */
+/* In either case we store the upvale *values*, i.e. the actual objects they
+ * point to. As in Pluto, we will restore any upvalues of Lua closures as
+ * closed as first, i.e. the upvalue will store the TValue itself. When
+ * loading a thread containing the upvalue (meaning it's the actual owner of
+ * the upvalue) we open it, i.e. we point it to the thread's upvalue list.
+ * For C closures, upvalues are always closed. */
+static void
+p_closure(Info *info) {                              /* perms reftbl ... func */
+  int nup;
+  eris_checkstack(info->L, 2);
+  switch (ttype(info->L->top - 1)) {
+    case LUA_TLCF: /* light C function */
+      /* We cannot persist these, they have to be handled via the permtable. */
+      eris_error(info, "Attempt to persist a light C function (%p)",
+                 lua_tocfunction(info->L, -1));
+      return; /* not reached */
+    case LUA_TCCL: /* C closure */ {                  /* perms reftbl ... ccl */
+      CClosure *cl = clCvalue(info->L->top - 1);
+      /* Mark it as a C closure. */
+      WRITE_VALUE(true, uint8_t);
+      /* Write the upvalue count first, since we have to know it when creating
+       * a new closure when unpersisting. */
+      WRITE_VALUE(cl->nupvalues, uint8_t);
+
+      /* We can only persist these if the underlying C function is in the
+       * permtable. So we try to persist it first as a light C function. If it
+       * isn't in the permtable that'll cause an error (in the case above). */
+      lua_pushcclosure(info->L, lua_tocfunction(info->L, -1), 0);
+                                                /* perms reftbl ... ccl cfunc */
+      persist(info);                            /* perms reftbl ... ccl cfunc */
+      lua_pop(info->L, 1);                            /* perms reftbl ... ccl */
+
+      /* Persist the upvalues. Since for C closures all upvalues are always
+       * closed we can just write the actual values. */
+      pushpath(info, ".upvalues");
+      for (nup = 1; nup <= cl->nupvalues; ++nup) {
+        pushpath(info, "[%d]", nup);
+        lua_getupvalue(info->L, -1, nup);         /* perms reftbl ... ccl obj */
+        persist(info);                            /* perms reftbl ... ccl obj */
+        lua_pop(info->L, 1);                          /* perms reftbl ... ccl */
+        poppath(info);
+      }
+      poppath(info);
+      break;
+    }
+    case LUA_TLCL: /* Lua function */ {               /* perms reftbl ... lcl */
+      LClosure *cl = clLvalue(info->L->top - 1);
+      /* Mark it as a Lua closure. */
+      WRITE_VALUE(false, uint8_t);
+      /* Write the upvalue count first, since we have to know it when creating
+       * a new closure when unpersisting. */
+      WRITE_VALUE(cl->nupvalues, uint8_t);
+
+      /* Persist the function's prototype. Pass the proto as a parameter to
+       * p_proto so that it can access it and register it in the ref table. */
+      pushpath(info, ".proto");
+      lua_pushlightuserdata(info->L, cl->p);    /* perms reftbl ... lcl proto */
+      lua_pushvalue(info->L, -1);         /* perms reftbl ... lcl proto proto */
+      persist_keyed(info, LUA_TPROTO);          /* perms reftbl ... lcl proto */
+      lua_pop(info->L, 1);                            /* perms reftbl ... lcl */
+      poppath(info);
+
+      /* Persist the upvalues. We pretend to write these as their own type,
+       * to get proper identity preservation. We also pass them as a parameter
+       * to p_upval so it can register the upvalue in the reference table. */
+      pushpath(info, ".upvalues");
+      for (nup = 1; nup <= cl->nupvalues; ++nup) {
+        const char *name = lua_getupvalue(info->L, -1, nup);
+                                                  /* perms reftbl ... lcl obj */
+        pushpath(info, ".%s", name);
+        lua_pushlightuserdata(info->L, lua_upvalueid(info->L, -2, nup));
+                                               /* perms reftbl ... lcl obj id */
+        persist_keyed(info, LUA_TUPVAL);          /* perms reftbl ... lcl obj */
+        lua_pop(info->L, 1);                         /* perms reftble ... lcl */
+        poppath(info);
+      }
+      poppath(info);
+      break;
+    }
+    default:
+      eris_error(info, "Attempt to persist unknown function type");
+      return; /* not reached */
+  }
+}
+
+static void
+u_closure(Info *info) {                                                /* ... */
+  int nup;
+  bool isCClosure = READ_VALUE(uint8_t);
+  lu_byte nups = READ_VALUE(uint8_t);
+  if (isCClosure) {
+    lua_CFunction f;
+
+    /* nups is guaranteed to be >= 1, otherwise it'd be a light C function. */
+    eris_checkstack(info->L, nups);
+
+    /* Read the C function from the permanents table. */
+    unpersist(info);                                             /* ... cfunc */
+    f = lua_tocfunction(info->L, -1);
+    lua_pop(info->L, 1);                                               /* ... */
+
+    /* Now this is a little roundabout, but we want to create the closure
+     * before unpersisting the actual upvalues to avoid cycles. So we have to
+     * create it with all nil first, then fill the upvalues in afterwards. */
+    for (nup = 1; nup <= nups; ++nup) {
+      lua_pushnil(info->L);                        /* ... nil[1] ... nil[nup] */
+    }
+    lua_pushcclosure(info->L, f, nups);                            /* ... ccl */
+
+    /* Preregister closure for handling of cycles (upvalues). */
+    registerobject(info);
+
+    /* Unpersist actual upvalues. */
+    pushpath(info, ".upvalues");
+    for (nup = 1; nup <= nups; ++nup) {
+      pushpath(info, "[%d]", nup);
+      unpersist(info);                                         /* ... ccl obj */
+      lua_setupvalue(info->L, -2, nup);                            /* ... ccl */
+      poppath(info);
+    }
+    poppath(info);
+  }
+  else {
+    Closure *cl;
+    Proto *p;
+
+    eris_checkstack(info->L, 4);
+
+    /* Create closure and anchor it on the stack (avoid collection via GC). */
+    cl = eris_newLclosure(info->L, nups);
+    eris_setclLvalue(info->L, info->L->top, cl);                   /* ... lcl */
+    eris_incr_top(info->L);
+
+    /* Preregister closure for handling of cycles (upvalues). */
+    registerobject(info);
+
+    /* Read prototype. In general, we create protos (and upvalues) before
+     * trying to read them and pass a pointer to the instance along to the
+     * unpersist function. This way the instance is safely hooked up to an
+     * object, so we don't have to worry about it getting GCed. */
+    pushpath(info, ".proto");
+    cl->l.p = eris_newproto(info->L);
+    /* Push the proto into which to unpersist as a parameter to u_proto. */
+    lua_pushlightuserdata(info->L, cl->l.p);                /* ... lcl nproto */
+    unpersist(info);                          /* ... lcl nproto nproto/oproto */
+    eris_assert(lua_type(info->L, -1) == LUA_TLIGHTUSERDATA);
+    /* The proto we have now may differ, if we already unpersisted it before.
+     * In that case we now have a reference to the originally unpersisted
+     * proto so we'll use that. */
+    p = lua_touserdata(info->L, -1);
+    if (p != cl->l.p) {                              /* ... lcl nproto oproto */
+      /* Just overwrite the old one, GC will clean this up. */
+      cl->l.p = p;
+    }
+    lua_pop(info->L, 2);                                           /* ... lcl */
+    eris_assert(cl->l.p->sizeupvalues == nups);
+    poppath(info);
+
+    /* Unpersist all upvalues. */
+    pushpath(info, ".upvalues");
+    for (nup = 1; nup <= nups; ++nup) {
+      UpVal **uv = &cl->l.upvals[nup - 1];
+      /* Get the actual name of the upvalue, if possible. */
+      if (p->upvalues[nup - 1].name) {
+        pushpath(info, "[%s]", getstr(p->upvalues[nup - 1].name));
+      }
+      else {
+        pushpath(info, "[%d]", nup);
+      }
+      unpersist(info);                                         /* ... lcl tbl */
+      eris_assert(lua_type(info->L, -1) == LUA_TTABLE);
+      lua_rawgeti(info->L, -1, 2);                   /* ... lcl tbl upval/nil */
+      if (lua_isnil(info->L, -1)) {                        /* ... lcl tbl nil */
+        lua_pop(info->L, 1);                                   /* ... lcl tbl */
+        *uv = eris_newupval(info->L);
+        lua_pushlightuserdata(info->L, *uv);             /* ... lcl tbl upval */
+        lua_rawseti(info->L, -2, 2);                           /* ... lcl tbl */
+      }
+      else {                                             /* ... lcl tbl upval */
+        eris_assert(lua_type(info->L, -1) == LUA_TLIGHTUSERDATA);
+        *uv = (UpVal*)lua_touserdata(info->L, -1);
+        lua_pop(info->L, 1);                                   /* ... lcl tbl */
+      }
+
+      /* Set the upvalue's actual value and add our reference to the upvalue to
+       * the list, for pointer patching if we have to open the upvalue in
+       * u_thread. Either is only necessary if the upvalue is still closed. */
+      if ((*uv)->v == &(*uv)->u.value) {
+        /* Always update the value of the upvalue's value for closed upvalues,
+         * even if we re-used one - if we had a cycle, it might have been
+         * incorrectly initialized to nil before. */
+        lua_rawgeti(info->L, -1, 1);                       /* ... lcl tbl obj */
+        eris_setobj(info->L, &(*uv)->u.value, info->L->top - 1);
+        lua_pop(info->L, 1);                                   /* ... lcl tbl */
+
+        lua_pushlightuserdata(info->L, uv);             /* ... lcl tbl upvalp */
+        if (luaL_len(info->L, -2) >= 2) {
+          /* Got a valid sequence, insert at the end. */
+          lua_rawseti(info->L, -2, luaL_len(info->L, -2) + 1); /* ... lcl tbl */
+        }
+        else {                                          /* ... lcl tbl upvalp */
+          int i;
+          /* Find where to insert. This can happen if we have cycles, in which
+           * case the table is not fully initialized at this point, i.e. the
+           * value is not in it, yet (we work around that by always setting it,
+           * as seen above). */
+          for (i = 3;; ++i) {
+            lua_rawgeti(info->L, -2, i);     /* ... lcl tbl upvalp upvalp/nil */
+            if (lua_isnil(info->L, -1)) {           /* ... lcl tbl upvalp nil */
+              lua_pop(info->L, 1);                      /* ... lcl tbl upvalp */
+              lua_rawseti(info->L, -2, i);                     /* ... lcl tbl */
+              break;
+            }
+            else {
+              lua_pop(info->L, 1);                      /* ... lcl tbl upvalp */
+            }
+          }                                                    /* ... lcl tbl */
+        }
+      }
+
+      lua_pop(info->L, 1);                                         /* ... lcl */
+      poppath(info);
+    }
+    poppath(info);
+
+    eris_barrierproto(info->L, p, cl);
+    p->cache = cl; /* save it in cache for reuse, see lvm.c:416 */
+  }
+
+  eris_assert(lua_type(info->L, -1) == LUA_TFUNCTION);
+}
+
+/** ======================================================================== */
+
+static void
+p_thread(Info *info) {                                          /* ... thread */
+  lua_State* thread = lua_tothread(info->L, -1);
+  size_t level;
+  StkId o;
+  CallInfo *ci;
+  UpVal *uv;
+
+  eris_checkstack(info->L, 2);
+
+  /* We cannot persist any running threads, because by definition we *are* that
+   * running thread. And we use the stack. So yeah, really not a good idea. */
+  if (thread == info->L) {
+    eris_error(info, "cannot persist currently running thread");
+    return; /* not reached */
+  }
+
+  /* Persist the stack. Save the total size and used space first. */
+  WRITE_VALUE(thread->stacksize, int);
+  WRITE_VALUE(thread->top - thread->stack, size_t);
+
+  /* The Lua stack looks like this:
+   * stack ... top ... stack_last
+   * Where stack <= top <= stack_last, and "top" actually being the first free
+   * element, i.e. there's nothing stored there. So we stop one below that. */
+  pushpath(info, ".stack");
+  lua_pushnil(info->L);                                     /* ... thread nil */
+  level = 0;
+  for (o = thread->stack; o < thread->top; ++o) {
+    pushpath(info, "[%d]", level++);
+    eris_setobj(info->L, info->L->top - 1, o);              /* ... thread obj */
+    persist(info);                                          /* ... thread obj */
+    poppath(info);
+  }
+  lua_pop(info->L, 1);                                          /* ... thread */
+  poppath(info);
+
+  /* If the thread isn't running this must be the default value, which is 1. */
+  eris_assert(thread->nny == 1);
+
+  /* Error jump info should only be set while thread is running. */
+  eris_assert(thread->errorJmp == NULL);
+
+  /* thread->oldpc always seems to be uninitialized, at least gdb always shows
+   * it as 0xbaadf00d when I set a breakpoint here. */
+
+  /* Write general information. */
+  WRITE_VALUE(thread->status, uint8_t);
+  WRITE_VALUE(eris_savestackidx(thread,
+    eris_restorestack(thread, thread->errfunc)), size_t);
+  /* These are only used while a thread is being executed or can be deduced:
+  WRITE_VALUE(thread->nCcalls, uint16_t);
+  WRITE_VALUE(thread->allowhook, uint8_t); */
+
+  /* Hooks are not supported, bloody can of worms, those.
+  WRITE_VALUE(thread->hookmask, uint8_t);
+  WRITE_VALUE(thread->basehookcount, int);
+  WRITE_VALUE(thread->hookcount, int); */
+
+  if (thread->hook) {
+    /* TODO Warn that hooks are not persisted? */
+  }
+
+  /* Write call information (stack frames). In 5.2 CallInfo is stored in a
+   * linked list that originates in thead.base_ci. Upon initialization the
+   * thread.ci is set to thread.base_ci. During thread calls this is extended
+   * and always represents the tail of the callstack, though not necessarily of
+   * the linked list (which can be longer if the callstack was deeper earlier,
+   * but shrunk due to returns). */
+  pushpath(info, ".callinfo");
+  level = 0;
+  eris_assert(&thread->base_ci != thread->ci->next);
+  for (ci = &thread->base_ci; ci != thread->ci->next; ci = ci->next) {
+    pushpath(info, "[%d]", level++);
+    WRITE_VALUE(eris_savestackidx(thread, ci->func), size_t);
+    WRITE_VALUE(eris_savestackidx(thread, ci->top), size_t);
+    WRITE_VALUE(ci->nresults, int16_t);
+    WRITE_VALUE(ci->callstatus, uint8_t);
+    /* CallInfo.extra is used in two contexts: if L->status == LUA_YIELD and
+     * CallInfo is the one stored as L->ci, in which case ci->extra refers to
+     * the original value of L->ci->func, and when we have a yieldable pcall
+     * (ci->callstatus & CIST_YPCALL) where ci->extra holds the stack level
+     * of the function being called (see lua_pcallk). We save the ci->extra
+     * for L->ci after the loop, because we won't know which one it is when
+     * unpersisting. */
+    if (ci->callstatus & CIST_YPCALL) {
+      WRITE_VALUE(eris_savestackidx(thread,
+        eris_restorestack(thread, ci->extra)), size_t);
+    }
+
+    eris_assert(eris_isLua(ci) || (ci->callstatus & CIST_TAIL) == 0);
+    if (ci->callstatus & CIST_HOOKYIELD) {
+      eris_error(info, "cannot persist yielded hooks");
+    }
+
+    if (eris_isLua(ci)) {
+      const LClosure *lcl = eris_ci_func(ci);
+      WRITE_VALUE(eris_savestackidx(thread, ci->u.l.base), size_t);
+      WRITE_VALUE(ci->u.l.savedpc - lcl->p->code, size_t);
+    }
+    else {
+      WRITE_VALUE(ci->u.c.status, uint8_t);
+
+      /* These are only used while a thread is being executed:
+      WRITE_VALUE(ci->u.c.old_errfunc, ptrdiff_t);
+      WRITE_VALUE(ci->u.c.old_allowhook, uint8_t); */
+
+      /* TODO Is this really right? Hooks may be a problem? */
+      if (ci->callstatus & (CIST_YPCALL | CIST_YIELDED)) {
+        WRITE_VALUE(ci->u.c.ctx, int);
+        eris_assert(ci->u.c.k);
+        lua_pushcfunction(info->L, ci->u.c.k);             /* ... thread func */
+        persist(info);                                 /* ... thread func/nil */
+        lua_pop(info->L, 1);                                    /* ... thread */
+      }
+    }
+
+    /* Write whether there's more to come. */
+    WRITE_VALUE(ci->next == thread->ci->next, uint8_t);
+
+    poppath(info);
+  }
+  /** See comment on ci->extra in loop. */
+  if (thread->status == LUA_YIELD) {
+    WRITE_VALUE(eris_savestackidx(thread,
+        eris_restorestack(thread, thread->ci->extra)), size_t);
+  }
+  poppath(info);
+
+  pushpath(info, ".openupval");
+  lua_pushnil(info->L);                                     /* ... thread nil */
+  level = 0;
+  for (uv = eris_gco2uv(thread->openupval);
+       uv != NULL;
+       uv = eris_gco2uv(eris_gch(eris_obj2gco(uv))->next))
+  {
+    pushpath(info, "[%d]", level);
+    WRITE_VALUE(eris_savestackidx(thread, uv->v) + 1, size_t);
+    eris_setobj(info->L, info->L->top - 1, uv->v);          /* ... thread obj */
+    lua_pushlightuserdata(info->L, uv);                  /* ... thread obj id */
+    persist_keyed(info, LUA_TUPVAL);                        /* ... thread obj */
+    poppath(info);
+  }
+  WRITE_VALUE(0, size_t);
+  lua_pop(info->L, 1);                                          /* ... thread */
+  poppath(info);
+}
+
+/* Used in u_thread to validate read stack positions. */
+#define validate(stackpos, inclmax) \
+  if ((stackpos) < thread->stack || stackpos > (inclmax)) { \
+    (stackpos) = thread->stack; \
+    eris_error(info, "stack index out of bounds"); }
+
+/* I had so hoped to get by without any 'hacks', but I surrender. We mark the
+ * thread as incomplete to avoid the GC messing with it while we're building
+ * it. Otherwise it may try to shrink its stack. We do this by setting its
+ * stack field to null for every call that may trigger a GC run, since that
+ * field is what's used to determine whether threads should be shrunk. See
+ * lgc.c:699. Some of the locks could probably be joined (since nothing
+ * inbetween requires the stack field to be valid), but I prefer to keep the
+ * "invalid" blocks as small as possible to make it clearer. Also, locking and
+ * unlocking are really just variable assignments, so they're really cheap. */
+#define LOCK(L) (L->stack = NULL)
+#define UNLOCK(L) (L->stack = stack)
+
+static void
+u_thread(Info *info) {                                                 /* ... */
+  lua_State* thread;
+  size_t level;
+  StkId stack, o;
+
+  eris_checkstack(info->L, 3);
+
+  thread = lua_newthread(info->L);                              /* ... thread */
+  registerobject(info);
+
+  /* Unpersist the stack. Read size first and adjust accordingly. */
+  eris_reallocstack(thread, READ_VALUE(int));
+  stack = thread->stack; /* After the realloc in case the address changes. */
+  thread->top = thread->stack + READ_VALUE(size_t);
+  validate(thread->top, thread->stack_last);
+
+  /* Read the elements one by one. */
+  LOCK(thread);
+  pushpath(info, ".stack");
+  UNLOCK(thread);
+  level = 0;
+  for (o = stack; o < thread->top; ++o) {
+    LOCK(thread);
+    pushpath(info, "[%d]", level++);
+    unpersist(info);                                        /* ... thread obj */
+    UNLOCK(thread);
+    eris_setobj(thread, o, info->L->top - 1);
+    lua_pop(info->L, 1);                                        /* ... thread */
+    LOCK(thread);
+    poppath(info);
+    UNLOCK(thread);
+  }
+  LOCK(thread);
+  poppath(info);
+  UNLOCK(thread);
+
+  /* As in p_thread, just to make sure. */
+  eris_assert(thread->nny == 1);
+  eris_assert(thread->errorJmp == NULL);
+  eris_assert(thread->hook == NULL);
+
+  /* See comment in persist. */
+  thread->oldpc = NULL;
+
+  /* Read general information. */
+  thread->status = READ_VALUE(uint8_t);
+  thread->errfunc = eris_savestack(thread,
+    eris_restorestackidx(thread, READ_VALUE(size_t)));
+  if (thread->errfunc) {
+    o = eris_restorestack(thread, thread->errfunc);
+    validate(o, thread->top);
+    if (eris_ttypenv(o) != LUA_TFUNCTION) {
+      eris_error(info, "invalid errfunc");
+    }
+  }
+  /* These are only used while a thread is being executed or can be deduced:
+  thread->nCcalls = READ_VALUE(uint16_t);
+  thread->allowhook = READ_VALUE(uint8_t); */
+  eris_assert(thread->allowhook == 1);
+
+  /* Not supported.
+  thread->hookmask = READ_VALUE(uint8_t);
+  thread->basehookcount = READ_VALUE(int);
+  thread->hookcount = READ_VALUE(int); */
+
+  /* Read call information (stack frames). */
+  LOCK(thread);
+  pushpath(info, ".callinfo");
+  UNLOCK(thread);
+  thread->ci = &thread->base_ci;
+  level = 0;
+  for (;;) {
+    LOCK(thread);
+    pushpath(info, "[%d]", level++);
+    UNLOCK(thread);
+    thread->ci->func = eris_restorestackidx(thread, READ_VALUE(size_t));
+    validate(thread->ci->func, thread->top - 1);
+    thread->ci->top = eris_restorestackidx(thread, READ_VALUE(size_t));
+    validate(thread->ci->top, thread->stack_last);
+    thread->ci->nresults = READ_VALUE(int16_t);
+    thread->ci->callstatus = READ_VALUE(uint8_t);
+    /** See comment in p_thread. */
+    if (thread->ci->callstatus & CIST_YPCALL) {
+      thread->ci->extra = eris_savestack(thread,
+        eris_restorestackidx(thread, READ_VALUE(size_t)));
+      o = eris_restorestack(thread, thread->ci->extra);
+      validate(o, thread->top);
+      if (eris_ttypenv(o) != LUA_TFUNCTION) {
+        eris_error(info, "invalid callinfo");
+      }
+    }
+
+    if (eris_isLua(thread->ci)) {
+      LClosure *lcl = eris_ci_func(thread->ci);
+      thread->ci->u.l.base = eris_restorestackidx(thread, READ_VALUE(size_t));
+      validate(thread->ci->u.l.base, thread->top);
+      thread->ci->u.l.savedpc = lcl->p->code + READ_VALUE(size_t);
+      if (thread->ci->u.l.savedpc < lcl->p->code ||
+          thread->ci->u.l.savedpc > lcl->p->code + lcl->p->sizecode)
+      {
+        thread->ci->u.l.savedpc = lcl->p->code; /* Just to be safe. */
+        eris_error(info, "saved program counter out of bounds");
+      }
+    }
+    else {
+      thread->ci->u.c.status = READ_VALUE(uint8_t);
+
+      /* These are only used while a thread is being executed:
+      thread->ci->u.c.old_errfunc = READ_VALUE(ptrdiff_t);
+      thread->ci->u.c.old_allowhook = READ_VALUE(uint8_t); */
+      thread->ci->u.c.old_errfunc = 0;
+      thread->ci->u.c.old_allowhook = 0;
+
+      /* TODO Is this really right? */
+      if (thread->ci->callstatus & (CIST_YPCALL | CIST_YIELDED)) {
+        thread->ci->u.c.ctx = READ_VALUE(int);
+        LOCK(thread);
+        unpersist(info);                                  /* ... thread func? */
+        UNLOCK(thread);
+        if (lua_iscfunction(info->L, -1)) {                /* ... thread func */
+          thread->ci->u.c.k = lua_tocfunction(info->L, -1);
+        }
+        else {
+          eris_error(info, "bad C continuation function");
+          return; /* not reached */
+        }
+        lua_pop(info->L, 1);                                    /* ... thread */
+      }
+      else {
+        thread->ci->u.c.ctx = 0;
+        thread->ci->u.c.k = NULL;
+      }
+    }
+    LOCK(thread);
+    poppath(info);
+    UNLOCK(thread);
+
+    /* Read in value for check for next iteration. */
+    if (READ_VALUE(uint8_t)) {
+      break;
+    }
+    else {
+      thread->ci = eris_extendCI(thread);
+    }
+  }
+  if (thread->status == LUA_YIELD) {
+    thread->ci->extra = eris_savestack(thread,
+      eris_restorestackidx(thread, READ_VALUE(size_t)));
+    o = eris_restorestack(thread, thread->ci->extra);
+    validate(o, thread->top);
+    if (eris_ttypenv(o) != LUA_TFUNCTION) {
+      eris_error(info, "invalid callinfo");
+    }
+  }
+  LOCK(thread);
+  poppath(info);
+  UNLOCK(thread);
+
+  /* Get from context: only zero for dead threads, otherwise one. */
+  thread->nCcalls = thread->status != LUA_OK || lua_gettop(thread) != 0;
+
+  /* Proceed to open upvalues. These upvalues will already exist due to the
+   * functions using them having been unpersisted (they'll usually be in the
+   * stack of the thread). For this reason we store all previous references to
+   * the upvalue in a table that is returned when we try to unpersist an
+   * upvalue, so that we can adjust these pointers in here. */
+  LOCK(thread);
+  pushpath(info, ".openupval");
+  UNLOCK(thread);
+  level = 0;
+  for (;;) {
+    UpVal *nuv;
+    StkId stk;
+    /* Get the position of the upvalue on the stack. As a special value we pass
+     * zero to indicate there are no more upvalues. */
+    const size_t offset = READ_VALUE(size_t);
+    if (offset == 0) {
+      break;
+    }
+    LOCK(thread);
+    pushpath(info, "[%d]", level);
+    UNLOCK(thread);
+    stk = eris_restorestackidx(thread, offset - 1);
+    validate(stk, thread->top - 1);
+    LOCK(thread);
+    unpersist(info);                                        /* ... thread tbl */
+    UNLOCK(thread);
+    eris_assert(lua_type(info->L, -1) == LUA_TTABLE);
+
+    /* Create the open upvalue either way. */
+    LOCK(thread);
+    nuv = eris_findupval(thread, stk);
+    UNLOCK(thread);
+
+    /* Then check if we need to patch some pointers. */
+    lua_rawgeti(info->L, -1, 2);                  /* ... thread tbl upval/nil */
+    if (!lua_isnil(info->L, -1)) {                    /* ... thread tbl upval */
+      int i, n;
+      eris_assert(lua_type(info->L, -1) == LUA_TLIGHTUSERDATA);
+      /* Already exists, replace it. To do this we have to patch all the
+       * pointers to the already existing one, which we added to the table in
+       * u_closure, starting at index 3. */
+      lua_pop(info->L, 1);                                  /* ... thread tbl */
+      for (i = 3, n = luaL_len(info->L, -1); i <= n; ++i) {
+        lua_rawgeti(info->L, -1, i);                 /* ... thread tbl upvalp */
+        (*(UpVal**)lua_touserdata(info->L, -1)) = nuv;
+        lua_pop(info->L, 1);                                /* ... thread tbl */
+      }
+    }
+    else {                                              /* ... thread tbl nil */
+      eris_assert(lua_isnil(info->L, -1));
+      lua_pop(info->L, 1);                                  /* ... thread tbl */
+    }
+
+    /* Store open upvalue in table for future references. */
+    LOCK(thread);
+    lua_pushlightuserdata(info->L, nuv);              /* ... thread tbl upval */
+    lua_rawseti(info->L, -2, 2);                            /* ... thread tbl */
+    lua_pop(info->L, 1);                                        /* ... thread */
+    poppath(info);
+    UNLOCK(thread);
+  }
+  poppath(info);
+
+  eris_assert(lua_type(info->L, -1) == LUA_TTHREAD);
+}
+
+#undef UNLOCK
+#undef LOCK
+
+#undef validate
+
+/*
+** ============================================================================
+** Top-level delegator.
+** ============================================================================
+*/
+
+static void
+persist_typed(Info *info, int type) {                 /* perms reftbl ... obj */
+  eris_ifassert(const int top = lua_gettop(info->L));
+  if (info->level >= info->maxComplexity) {
+    eris_error(info, "object too complex");
+  }
+  ++info->level;
+
+  WRITE_VALUE(type, int);
+  switch(type) {
+    case LUA_TBOOLEAN:
+      p_boolean(info);
+      break;
+    case LUA_TLIGHTUSERDATA:
+      p_pointer(info);
+      break;
+    case LUA_TNUMBER:
+      p_number(info);
+      break;
+    case LUA_TSTRING:
+      p_string(info);
+      break;
+    case LUA_TTABLE:
+      p_table(info);
+      break;
+    case LUA_TFUNCTION:
+      p_closure(info);
+      break;
+    case LUA_TUSERDATA:
+      p_userdata(info);
+      break;
+    case LUA_TTHREAD:
+      p_thread(info);
+      break;
+    case LUA_TPROTO:
+      p_proto(info);
+      break;
+    case LUA_TUPVAL:
+      p_upval(info);
+      break;
+    default:
+      eris_error(info, "trying to persist unknown type");
+  }                                                   /* perms reftbl ... obj */
+
+  --info->level;
+  eris_assert(top == lua_gettop(info->L));
+}
+
+/* Second-level delegating persist function, used for cases when persisting
+ * data that's stored in the reftable with a key that is not the data itself,
+ * namely upvalues and protos. */
+static void
+persist_keyed(Info *info, int type) {          /* perms reftbl ... obj refkey */
+  eris_checkstack(info->L, 2);
+
+  /* Keep a copy of the key for pushing it to the reftable, if necessary. */
+  lua_pushvalue(info->L, -1);           /* perms reftbl ... obj refkey refkey */
+
+  /* If the object has already been written, write a reference to it. */
+  lua_rawget(info->L, REFTIDX);           /* perms reftbl ... obj refkey ref? */
+  if (!lua_isnil(info->L, -1)) {           /* perms reftbl ... obj refkey ref */
+    const int reference = lua_tointeger(info->L, -1);
+    WRITE_VALUE(reference + ERIS_REFERENCE_OFFSET, int);
+    lua_pop(info->L, 2);                              /* perms reftbl ... obj */
+    return;
+  }                                        /* perms reftbl ... obj refkey nil */
+  lua_pop(info->L, 1);                         /* perms reftbl ... obj refkey */
+
+  /* Copy the refkey for the perms check below. */
+  lua_pushvalue(info->L, -1);           /* perms reftbl ... obj refkey refkey */
+
+  /* Put the value in the reference table. This creates an entry pointing from
+   * the object (or its key) to the id the object is referenced by. */
+  lua_pushinteger(info->L, ++(info->refcount));
+                                    /* perms reftbl ... obj refkey refkey ref */
+  lua_rawset(info->L, REFTIDX);                /* perms reftbl ... obj refkey */
+
+  /* At this point, we'll give the permanents table a chance to play. */
+  lua_gettable(info->L, PERMIDX);            /* perms reftbl ... obj permkey? */
+  if (!lua_isnil(info->L, -1)) {              /* perms reftbl ... obj permkey */
+    type = lua_type(info->L, -2);
+    /* Prepend permanent "type" so that we know it's a permtable key. This will
+     * trigger u_permanent when unpersisting. Also write the original type, so
+     * that we can verify what we get in the permtable when unpersisting is of
+     * the same kind we had when persisting. */
+    WRITE_VALUE(ERIS_PERMANENT, int);
+    WRITE_VALUE(type, uint8_t);
+    persist(info);                            /* perms reftbl ... obj permkey */
+    lua_pop(info->L, 1);                              /* perms reftbl ... obj */
+  }
+  else {                                          /* perms reftbl ... obj nil */
+    /* No entry in the permtable for this object, persist it directly. */
+    lua_pop(info->L, 1);                              /* perms reftbl ... obj */
+    persist_typed(info, type);                        /* perms reftbl ... obj */
+  }                                                   /* perms reftbl ... obj */
+}
+
+/* Top-level delegating persist function. */
+static void
+persist(Info *info) {                                 /* perms reftbl ... obj */
+  /* Grab the object's type. */
+  const int type = lua_type(info->L, -1);
+
+  /* If the object is nil, only write its type. */
+  if (type == LUA_TNIL) {
+    WRITE_VALUE(type, int);
+  }
+  /* Write simple values directly, because writing a "reference" would take up
+   * just as much space and we can save ourselves work this way. */
+  else if (type == LUA_TBOOLEAN ||
+           type == LUA_TLIGHTUSERDATA ||
+           type == LUA_TNUMBER)
+  {
+    persist_typed(info, type);                        /* perms reftbl ... obj */
+  }
+  /* For all non-simple values we keep a record in the reftable, so that we
+   * keep references alive across persisting and unpersisting an object. This
+   * has the nice side-effect of saving some space. */
+  else {
+    eris_checkstack(info->L, 1);
+    lua_pushvalue(info->L, -1);                   /* perms reftbl ... obj obj */
+    persist_keyed(info, type);                        /* perms reftbl ... obj */
+  }
+}
+
+/** ======================================================================== */
+
+static void
+u_permanent(Info *info) {                                 /* perms reftbl ... */
+  const int type = READ_VALUE(uint8_t);
+  /* Reserve reference to avoid the key going first. This registers whatever
+   * else is on the stack in the reftable, but that shouldn't really matter. */
+  const int reference = registerobject(info);
+  eris_checkstack(info->L, 1);
+  unpersist(info);                                /* perms reftbl ... permkey */
+  lua_gettable(info->L, PERMIDX);                    /* perms reftbl ... obj? */
+  if (lua_isnil(info->L, -1)) {                       /* perms reftbl ... nil */
+    /* Since we may need permanent values to rebuild other structures, namely
+     * closures and threads, we cannot allow perms to fail unpersisting. */
+    eris_error(info, "bad permanent value (no value)");
+  }
+  else if (lua_type(info->L, -1) != type) {            /* perms reftbl ... :( */
+    /* For the same reason that we cannot allow nil we must also require the
+     * unpersisted value to be of the correct type. */
+    eris_error(info, "bad permanent value (%s expected, got %s)",
+      kTypenames[type], kTypenames[lua_type(info->L, -1)]);
+  }                                                   /* perms reftbl ... obj */
+  /* Correct the entry in the reftable. */
+  lua_pushvalue(info->L, -1);                     /* perms reftbl ... obj obj */
+  lua_rawseti(info->L, REFTIDX, reference);           /* perms reftbl ... obj */
+}
+
+static void
+unpersist(Info *info) {                                   /* perms reftbl ... */
+  eris_ifassert(const int top = lua_gettop(info->L));
+  if (info->level >= info->maxComplexity) {
+    eris_error(info, "object too complex");
+  }
+  ++info->level;
+
+  eris_checkstack(info->L, 1);
+  {
+    const int typeOrReference = READ_VALUE(int);
+    if (typeOrReference > ERIS_REFERENCE_OFFSET) {
+      const int reference = typeOrReference - ERIS_REFERENCE_OFFSET;
+      lua_rawgeti(info->L, REFTIDX, reference);   /* perms reftbl ud ... obj? */
+      if (lua_isnil(info->L, -1)) {                 /* perms reftbl ud ... :( */
+        eris_error(info, "invalid reference #%d", reference);
+      }                                            /* perms reftbl ud ... obj */
+    }
+    else {
+      const int type = typeOrReference;
+      switch (type) {
+        case LUA_TNIL:
+          lua_pushnil(info->L);
+          break;
+        case LUA_TBOOLEAN:
+          u_boolean(info);
+          break;
+        case LUA_TLIGHTUSERDATA:
+          u_pointer(info);
+          break;
+        case LUA_TNUMBER:
+          u_number(info);
+          break;
+        case LUA_TSTRING:
+          u_string(info);
+          break;
+        case LUA_TTABLE:
+          u_table(info);
+          break;
+        case LUA_TFUNCTION:
+          u_closure(info);
+          break;
+        case LUA_TUSERDATA:
+          u_userdata(info);
+          break;
+        case LUA_TTHREAD:
+          u_thread(info);
+          break;
+        case LUA_TPROTO:
+          u_proto(info);
+          break;
+        case LUA_TUPVAL:
+          u_upval(info);
+          break;
+        case ERIS_PERMANENT:
+          u_permanent(info);
+          break;
+        default:
+          eris_error(info, "trying to unpersist unknown type %d", type);
+      }                                              /* perms reftbl ... obj? */
+    }
+  }
+
+  --info->level;
+  eris_assert(top + 1 == lua_gettop(info->L));
+}
+
+/* }======================================================================== */
+
+/*
+** {===========================================================================
+** Writer and reader implementation for library calls.
+** ============================================================================
+*/
+
+/* Implementation note: we use the MBuffer struct, but we don't use the built-
+ * in reallocation functions since we'll keep our working copy on the stack, to
+ * allow for proper collection if we have to throw an error. This is very much
+ * what the auxlib does with its buffer functionality. Which we don't use since
+ * we cannot guarantee stack balance inbetween calls to luaL_add*. */
+
+static int
+writer(lua_State *L, const void *p, size_t sz, void *ud) {
+                                               /* perms reftbl buff path? ... */
+  const char *value = (const char*)p;
+  Mbuffer *buff = (Mbuffer*)ud;
+  const size_t size = eris_bufflen(buff);
+  const size_t capacity = eris_sizebuffer(buff);
+  if (capacity - size < sz) {
+    size_t newcapacity = capacity * 2; /* overflow checked below */
+    if (newcapacity - size < sz) {
+      newcapacity = capacity + sz; /* overflow checked below */
+    }
+    if (newcapacity <= capacity) {
+      /* Overflow in capacity, buffer size limit reached. */
+      return 1;
+    } else {
+      char *newbuff;
+      eris_checkstack(L, 1);
+      newbuff = (char*)lua_newuserdata(L, newcapacity * sizeof(char));
+                                         /* perms reftbl buff path? ... nbuff */
+      memcpy(newbuff, eris_buffer(buff), eris_bufflen(buff));
+      lua_replace(L, BUFFIDX);                /* perms reftbl nbuff path? ... */
+      eris_buffer(buff) = newbuff;
+      eris_sizebuffer(buff) = newcapacity;
+    }
+  }
+  memcpy(&eris_buffer(buff)[eris_bufflen(buff)], value, sz);
+  eris_bufflen(buff) += sz;
+  return 0;
+}
+
+/** ======================================================================== */
+
+/* Readonly, interface compatible with MBuffer macros. */
+typedef struct RBuffer {
+  const char *buffer;
+  size_t n;
+  size_t buffsize;
+} RBuffer;
+
+static const char*
+reader(lua_State *L, void *ud, size_t *sz) {
+  RBuffer *buff = (RBuffer*)ud;
+  (void) L; /* unused */
+  if (eris_bufflen(buff) == 0) {
+    return NULL;
+  }
+  *sz = eris_bufflen(buff);
+  eris_bufflen(buff) = 0;
+  return eris_buffer(buff);
+}
+
+/* }======================================================================== */
+
+/*
+** {===========================================================================
+** Library functions.
+** ============================================================================
+*/
+
+static void
+p_header(Info *info) {
+  WRITE_RAW(kHeader, HEADER_LENGTH);
+  WRITE_VALUE(sizeof(lua_Number), uint8_t);
+  WRITE_VALUE(kHeaderNumber, lua_Number);
+  WRITE_VALUE(sizeof(int), uint8_t);
+  WRITE_VALUE(sizeof(size_t), uint8_t);
+}
+
+static void
+u_header(Info *info) {
+  char header[HEADER_LENGTH];
+  READ_RAW(header, HEADER_LENGTH);
+  if (strncmp(kHeader, header, HEADER_LENGTH)) {
+    luaL_error(info->L, "invalid data");
+  }
+  if (READ_VALUE(uint8_t) != sizeof(lua_Number)) {
+    luaL_error(info->L, "incompatible floating point type");
+  }
+  /* In this case we really do want floating point equality. */
+  if (READ_VALUE(lua_Number) != kHeaderNumber) {
+    luaL_error(info->L, "incompatible floating point representation");
+  }
+  info->u.upi.sizeof_int = READ_VALUE(uint8_t);
+  info->u.upi.sizeof_size_t = READ_VALUE(uint8_t);
+}
+
+static void
+unchecked_persist(lua_State *L, lua_Writer writer, void *ud) {
+  Info info;                                            /* perms buff rootobj */
+  info.L = L;
+  info.level = 0;
+  info.refcount = 0;
+  info.maxComplexity = kMaxComplexity;
+  info.passIOToPersist = kPassIOToPersist;
+  info.generatePath = kGeneratePath;
+  info.u.pi.writer = writer;
+  info.u.pi.ud = ud;
+  info.u.pi.metafield = kPersistKey;
+  info.u.pi.writeDebugInfo = kWriteDebugInformation;
+
+  eris_checkstack(L, 3);
+
+  if (get_setting(L, (void*)&kSettingMaxComplexity)) {
+                                                  /* perms buff rootobj value */
+    info.maxComplexity = lua_tounsigned(L, -1);
+    lua_pop(L, 1);                                      /* perms buff rootobj */
+  }
+  if (get_setting(L, (void*)&kSettingGeneratePath)) {
+                                                  /* perms buff rootobj value */
+    info.generatePath = lua_toboolean(L, -1);
+    lua_pop(L, 1);                                      /* perms buff rootobj */
+  }
+  if (get_setting(L, (void*)&kSettingPassIOToPersist)) {
+                                                  /* perms buff rootobj value */
+    info.passIOToPersist = lua_toboolean(L, -1);
+    lua_pop(L, 1);                                      /* perms buff rootobj */
+  }
+  if (get_setting(L, (void*)&kSettingMetafield)) {/* perms buff rootobj value */
+    info.u.pi.metafield = lua_tostring(L, -1);
+    lua_pop(L, 1);                                      /* perms buff rootobj */
+  }
+  if (get_setting(L, (void*)&kSettingWriteDebugInfo)) {
+                                                  /* perms buff rootobj value */
+    info.u.pi.writeDebugInfo = lua_toboolean(L, -1);
+    lua_pop(L, 1);                                      /* perms buff rootobj */
+  }
+
+  lua_newtable(L);                               /* perms buff rootobj reftbl */
+  lua_insert(L, REFTIDX);                        /* perms reftbl buff rootobj */
+  if (info.generatePath) {
+    lua_newtable(L);                        /* perms reftbl buff rootobj path */
+    lua_insert(L, PATHIDX);                 /* perms reftbl buff path rootobj */
+    pushpath(&info, "root");
+  }
+
+  /* Populate perms table with Lua internals. */
+  lua_pushvalue(L, PERMIDX);         /* perms reftbl buff path? rootobj perms */
+  populateperms(L, false);
+  lua_pop(L, 1);                           /* perms reftbl buff path? rootobj */
+
+  p_header(&info);
+  persist(&info);                          /* perms reftbl buff path? rootobj */
+
+  if (info.generatePath) {                  /* perms reftbl buff path rootobj */
+    lua_remove(L, PATHIDX);                      /* perms reftbl buff rootobj */
+  }                                              /* perms reftbl buff rootobj */
+  lua_remove(L, REFTIDX);                               /* perms buff rootobj */
+}
+
+static void
+unchecked_unpersist(lua_State *L, lua_Reader reader, void *ud) {/* perms str? */
+  Info info;
+  info.L = L;
+  info.level = 0;
+  info.refcount = 0;
+  info.maxComplexity = kMaxComplexity;
+  info.generatePath = kGeneratePath;
+  info.passIOToPersist = kPassIOToPersist;
+  eris_init(L, &info.u.upi.zio, reader, ud);
+
+  eris_checkstack(L, 3);
+
+  if (get_setting(L, (void*)&kSettingMaxComplexity)) {
+                                                  /* perms buff rootobj value */
+    info.maxComplexity = lua_tounsigned(L, -1);
+    lua_pop(L, 1);                                      /* perms buff rootobj */
+  }
+  if (get_setting(L, (void*)&kSettingGeneratePath)) {
+                                                 /* perms buff? rootobj value */
+    info.generatePath = lua_toboolean(L, -1);
+    lua_pop(L, 1);                                     /* perms buff? rootobj */
+  }
+  if (get_setting(L, (void*)&kSettingPassIOToPersist)) {  /* perms str? value */
+    info.passIOToPersist = lua_toboolean(L, -1);
+    lua_pop(L, 1);                                              /* perms str? */
+  }
+
+  lua_newtable(L);                                       /* perms str? reftbl */
+  lua_insert(L, REFTIDX);                                /* perms reftbl str? */
+  if (info.generatePath) {
+    /* Make sure the path is always at index 4, so that it's the same for
+     * persist and unpersist. */
+    lua_pushnil(L);                                  /* perms reftbl str? nil */
+    lua_insert(L, BUFFIDX);                          /* perms reftbl nil str? */
+    lua_newtable(L);                            /* perms reftbl nil str? path */
+    lua_insert(L, PATHIDX);                     /* perms reftbl nil path str? */
+    pushpath(&info, "root");
+  }
+
+  /* Populate perms table with Lua internals. */
+  lua_pushvalue(L, PERMIDX);            /* perms reftbl nil? path? str? perms */
+  populateperms(L, true);
+  lua_pop(L, 1);                              /* perms reftbl nil? path? str? */
+
+  u_header(&info);
+  unpersist(&info);                   /* perms reftbl nil? path? str? rootobj */
+  if (info.generatePath) {              /* perms reftbl nil path str? rootobj */
+    lua_remove(L, PATHIDX);                  /* perms reftbl nil str? rootobj */
+    lua_remove(L, BUFFIDX);                      /* perms reftbl str? rootobj */
+  }                                              /* perms reftbl str? rootobj */
+  lua_remove(L, REFTIDX);                               /* perms str? rootobj */
+}
+
+/** ======================================================================== */
+
+static int
+l_persist(lua_State *L) {                             /* perms? rootobj? ...? */
+  Mbuffer buff;
+
+  /* See if we have anything at all. */
+  luaL_checkany(L, 1);
+
+  /* If we only have one object we assume it is the root object and that there
+   * is no perms table, so we create an empty one for internal use. */
+  if (lua_gettop(L) == 1) {                                        /* rootobj */
+    eris_checkstack(L, 1);
+    lua_newtable(L);                                         /* rootobj perms */
+    lua_insert(L, PERMIDX);                                  /* perms rootobj */
+  }
+  else {
+    luaL_checktype(L, 1, LUA_TTABLE);                  /* perms rootobj? ...? */
+    luaL_checkany(L, 2);                                /* perms rootobj ...? */
+    lua_settop(L, 2);                                        /* perms rootobj */
+  }
+  eris_checkstack(L, 1);
+  lua_pushnil(L);                                       /* perms rootobj buff */
+  lua_insert(L, 2);                                     /* perms buff rootobj */
+
+  eris_initbuffer(L, &buff);
+  eris_bufflen(&buff) = 0; /* Not initialized by initbuffer... */
+
+  unchecked_persist(L, writer, &buff);                  /* perms buff rootobj */
+
+  /* Copy the buffer as the result string before removing it, to avoid the data
+   * being garbage collected. */
+  lua_pushlstring(L, eris_buffer(&buff), eris_bufflen(&buff));
+                                                    /* perms buff rootobj str */
+
+  return 1;
+}
+
+static int
+l_unpersist(lua_State *L) {                               /* perms? str? ...? */
+  RBuffer buff;
+
+  /* See if we have anything at all. */
+  luaL_checkany(L, 1);
+
+  /* If we only have one object we assume it is the root object and that there
+   * is no perms table, so we create an empty one for internal use. */
+  if (lua_gettop(L) == 1) {                                           /* str? */
+    eris_checkstack(L, 1);
+    lua_newtable(L);                                            /* str? perms */
+    lua_insert(L, PERMIDX);                                     /* perms str? */
+  }
+  else {
+    luaL_checktype(L, 1, LUA_TTABLE);                      /* perms str? ...? */
+  }
+  eris_buffer(&buff) = luaL_checklstring(L, 2, &eris_bufflen(&buff));
+  eris_sizebuffer(&buff) = eris_bufflen(&buff);             /* perms str ...? */
+  lua_settop(L, 2);                                              /* perms str */
+
+  unchecked_unpersist(L, reader, &buff);                 /* perms str rootobj */
+
+  return 1;
+}
+
+#define IS(s) strncmp(s, name, length < sizeof(s) ? length : sizeof(s)) == 0
+
+static int
+l_settings(lua_State *L) {                                /* name value? ...? */
+  size_t length;
+  const char *name = luaL_checklstring(L, 1, &length);
+  if (lua_isnone(L, 2)) {                                        /* name ...? */
+    lua_settop(L, 1);                                                 /* name */
+    /* Get the current setting value and return it. */
+    if (IS(kSettingMetafield)) {
+      if (!get_setting(L, (void*)&kSettingMetafield)) {
+        lua_pushstring(L, kPersistKey);
+      }
+    }
+    else if (IS(kSettingPassIOToPersist)) {
+      if (!get_setting(L, (void*)&kSettingPassIOToPersist)) {
+        lua_pushboolean(L, kPassIOToPersist);
+      }
+    }
+    else if (IS(kSettingWriteDebugInfo)) {
+      if (!get_setting(L, (void*)&kSettingWriteDebugInfo)) {
+        lua_pushboolean(L, kWriteDebugInformation);
+      }
+    }
+    else if (IS(kSettingGeneratePath)) {
+      if (!get_setting(L, (void*)&kSettingGeneratePath)) {
+        lua_pushboolean(L, kGeneratePath);
+      }
+    }
+    else if (IS(kSettingMaxComplexity)) {
+      if (!get_setting(L, (void*)&kSettingMaxComplexity)) {
+        lua_pushunsigned(L, kMaxComplexity);
+      }
+    }
+    else {
+      return luaL_argerror(L, 1, "no such setting");
+    }                                                           /* name value */
+    return 1;
+  }
+  else {                                                   /* name value ...? */
+    lua_settop(L, 2);                                           /* name value */
+    /* Set a new value for the setting. */
+    if (IS(kSettingMetafield)) {
+      luaL_optstring(L, 2, NULL);
+      set_setting(L, (void*)&kSettingMetafield);
+    }
+    else if (IS(kSettingPassIOToPersist)) {
+      luaL_opt(L, checkboolean, 2, false);
+      set_setting(L, (void*)&kSettingPassIOToPersist);
+    }
+    else if (IS(kSettingWriteDebugInfo)) {
+      luaL_opt(L, checkboolean, 2, false);
+      set_setting(L, (void*)&kSettingWriteDebugInfo);
+    }
+    else if (IS(kSettingGeneratePath)) {
+      luaL_opt(L, checkboolean, 2, false);
+      set_setting(L, (void*)&kSettingGeneratePath);
+    }
+    else if (IS(kSettingMaxComplexity)) {
+      luaL_optunsigned(L, 2, 0);
+      set_setting(L, (void*)&kSettingMaxComplexity);
+    }
+    else {
+      return luaL_argerror(L, 1, "no such setting");
+    }                                                                 /* name */
+    return 0;
+  }
+}
+
+#undef IS
+
+/** ======================================================================== */
+
+static luaL_Reg erislib[] = {
+  { "persist", l_persist },
+  { "unpersist", l_unpersist },
+  { "settings", l_settings },
+  { NULL, NULL }
+};
+
+LUA_API int luaopen_eris(lua_State *L) {
+  luaL_newlib(L, erislib);
+  return 1;
+}
+
+/* }======================================================================== */
+
+/*
+** {===========================================================================
+** Public API functions.
+** ============================================================================
+*/
+
+LUA_API void
+eris_dump(lua_State *L, lua_Writer writer, void *ud) {     /* perms? rootobj? */
+  if (lua_gettop(L) > 2) {
+    luaL_error(L, "too many arguments");
+  }
+  luaL_checktype(L, 1, LUA_TTABLE);                         /* perms rootobj? */
+  luaL_checkany(L, 2);                                       /* perms rootobj */
+  lua_pushnil(L);                                        /* perms rootobj nil */
+  lua_insert(L, -2);                                     /* perms nil rootobj */
+  unchecked_persist(L, writer, ud);                      /* perms nil rootobj */
+  lua_remove(L, -2);                                         /* perms rootobj */
+}
+
+LUA_API void
+eris_undump(lua_State *L, lua_Reader reader, void *ud) {            /* perms? */
+  if (lua_gettop(L) > 1) {
+    luaL_error(L, "too many arguments");
+  }
+  luaL_checktype(L, 1, LUA_TTABLE);                                  /* perms */
+  unchecked_unpersist(L, reader, ud);                        /* perms rootobj */
+}
+
+/** ======================================================================== */
+
+LUA_API void
+eris_persist(lua_State *L, int perms, int value) {                    /* ...? */
+  eris_checkstack(L, 3);
+  lua_pushcfunction(L, l_persist);                           /* ... l_persist */
+  lua_pushvalue(L, perms);                             /* ... l_persist perms */
+  lua_pushvalue(L, value);                     /* ... l_persist perms rootobj */
+  lua_call(L, 2, 1);                                               /* ... str */
+}
+
+LUA_API void
+eris_unpersist(lua_State *L, int perms, int value) {                   /* ... */
+  eris_checkstack(L, 3);
+  lua_pushcfunction(L, l_unpersist);                       /* ... l_unpersist */
+  lua_pushvalue(L, perms);                           /* ... l_unpersist perms */
+  lua_pushvalue(L, value);                       /* ... l_unpersist perms str */
+  lua_call(L, 2, 1);                                           /* ... rootobj */
+}
+
+LUA_API void
+eris_get_setting(lua_State *L, const char *name) {                     /* ... */
+  eris_checkstack(L, 2);
+  lua_pushcfunction(L, l_settings);                         /* ... l_settings */
+  lua_pushstring(L, name);                             /* ... l_settings name */
+  lua_call(L, 1, 1);                                             /* ... value */
+}
+
+LUA_API void
+eris_set_setting(lua_State *L, const char *name, int value) {          /* ... */
+  eris_checkstack(L, 3);
+  lua_pushcfunction(L, l_settings);                         /* ... l_settings */
+  lua_pushstring(L, name);                             /* ... l_settings name */
+  lua_pushvalue(L, value);                       /* ... l_settings name value */
+  lua_call(L, 2, 0);                                                   /* ... */
+}
+
+/* }======================================================================== */
+

=== added file 'src/scripting/eris/eris.h'
--- src/scripting/eris/eris.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/eris.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,148 @@
+/*
+Eris - Heavy-duty persistence for Lua 5.2.2 - Based on Pluto
+Copyright (c) 2013 by Florian Nuecke.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/* lua.h must be included before this file */
+
+#ifndef ERIS_H
+#define ERIS_H
+
+/*
+** ==================================================================
+** API
+** ==================================================================
+*/
+
+/**
+ * This provides an interface to Eris' persist functionality for writing in
+ * an arbitrary way, using a writer.
+ *
+ * When called, the stack in 'L' must look like this:
+ * 1: perms:table
+ * 2: value:any
+ *
+ * 'writer' is the writer function used to store all data, 'ud' is passed to
+ * the writer function whenever it is called.
+ *
+ * [-0, +0, e]
+ */
+LUA_API void eris_dump(lua_State* L, lua_Writer writer, void* ud);
+
+/**
+ * This provides an interface to Eris' unpersist functionality for reading
+ * in an arbitrary way, using a reader.
+ *
+ * When called, the stack in 'L' must look like this:
+ * 1: perms:table
+ *
+ * 'reader' is the reader function used to read all data, 'ud' is passed to
+ * the reader function whenever it is called.
+ *
+ * The result of the operation will be pushed onto the stack.
+ *
+ * [-0, +1, e]
+ */
+LUA_API void eris_undump(lua_State* L, lua_Reader reader, void* ud);
+
+/**
+ * This is a stack-based alternative to eris_dump.
+ *
+ * It expects the perms table at the specified index 'perms' and the value to
+ * persist at the specified index 'value'. It will push the resulting string
+ * onto the stack on success.
+ *
+ * [-0, +1, e]
+ */
+LUA_API void eris_persist(lua_State* L, int perms, int value);
+
+/**
+ * This is a stack-based alternative to eris_undump.
+ *
+ * It expects the perms table at the specified index 'perms' and the string
+ * containing persisted data at the specified index 'value'. It will push the
+ * resulting value onto the stack on success.
+ *
+ * [-0, +1, e]
+ */
+LUA_API void eris_unpersist(lua_State* L, int perms, int value);
+
+/**
+ * Pushes the current value of a setting onto the stack.
+ *
+ * The name is the name of the setting to get the value for:
+ * - 'debug'  whether to write debug information when persisting function
+ *            prototypes (line numbers, local variable names, upvalue names).
+ * - 'maxrec' the maximum complexity of objects we support (the nesting level
+ *            of tables, for example). This can be useful to avoid segmentation
+ *            faults due to too deep recursion when working with user-provided
+ *            data.
+ * - 'path'   whether to generate a "path" used to indicate where in an object
+ *            an error occurred. This adds considerable overhead and should
+ *            only be used to debug errors as they appear.
+ * - 'spio'   whether to pass IO objects along as light userdata to special
+ *            persistence functions. When persisting this will pass along the
+ *            lua_Writer and its void* in addition to the original object, when
+ *            unpersisting it will pass along a ZIO*.
+ * - 'spkey'  the name of the field in the metatable of tables and userdata
+ *            used to control persistence (on/off or special persistence).
+ *
+ * If an unknown name is specified this will throw an error.
+ *
+ * [-0, +1, e]
+ */
+LUA_API void eris_get_setting(lua_State *L, const char *name);
+
+/**
+ * Changes the value of a setting to a value on the stack.
+ *
+ * For the available settings see eris_set_setting(). This will get the new
+ * value from the specified stack index 'value'. If the type does not match
+ * this will throw an error. Specify a nil value to reset the setting to its
+ * default value.
+ *
+ * [-0, +0, e]
+ */
+LUA_API void eris_set_setting(lua_State *L, const char *name, int value);
+
+/*
+** ==================================================================
+** Library installer
+** ==================================================================
+*/
+
+/**
+ * This pushes a table with the two functions 'persist' and 'unpersist':
+ *   persist([perms,] value)
+ *     Where 'perms' is a table with "permanent" objects and 'value' is the
+ *     value that should be persisted. Returns the string with persisted data.
+ *     If only one value is given, the perms table is assumed to be empty.
+ *
+ *   unpersist([perms,] value)
+ *     Where 'perms' is a table with the inverse mapping as used when
+ *     persisting the data via persist() and 'value' is the string with the
+ *     persisted data returned by persist(). Returns the unpersisted value.
+ *     If only one value is given, the perms table is assumed to be empty.
+ */
+LUA_API int luaopen_eris(lua_State* L);
+
+#endif
+

=== added file 'src/scripting/eris/lapi.c'
--- src/scripting/eris/lapi.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lapi.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,1284 @@
+/*
+** $Id: lapi.c,v 2.171 2013/03/16 21:10:18 roberto Exp $
+** Lua API
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdarg.h>
+#include <string.h>
+
+#define lapi_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lundump.h"
+#include "lvm.h"
+
+
+
+const char lua_ident[] =
+  "$LuaVersion: " LUA_COPYRIGHT " $"
+  "$LuaAuthors: " LUA_AUTHORS " $";
+
+
+/* value at a non-valid index */
+#define NONVALIDVALUE		cast(TValue *, luaO_nilobject)
+
+/* corresponding test */
+#define isvalid(o)	((o) != luaO_nilobject)
+
+/* test for pseudo index */
+#define ispseudo(i)		((i) <= LUA_REGISTRYINDEX)
+
+/* test for valid but not pseudo index */
+#define isstackindex(i, o)	(isvalid(o) && !ispseudo(i))
+
+#define api_checkvalidindex(L, o)  api_check(L, isvalid(o), "invalid index")
+
+#define api_checkstackindex(L, i, o)  \
+	api_check(L, isstackindex(i, o), "index not in the stack")
+
+
+static TValue *index2addr (lua_State *L, int idx) {
+  CallInfo *ci = L->ci;
+  if (idx > 0) {
+    TValue *o = ci->func + idx;
+    api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index");
+    if (o >= L->top) return NONVALIDVALUE;
+    else return o;
+  }
+  else if (!ispseudo(idx)) {  /* negative index */
+    api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
+    return L->top + idx;
+  }
+  else if (idx == LUA_REGISTRYINDEX)
+    return &G(L)->l_registry;
+  else {  /* upvalues */
+    idx = LUA_REGISTRYINDEX - idx;
+    api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
+    if (ttislcf(ci->func))  /* light C function? */
+      return NONVALIDVALUE;  /* it has no upvalues */
+    else {
+      CClosure *func = clCvalue(ci->func);
+      return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE;
+    }
+  }
+}
+
+
+/*
+** to be called by 'lua_checkstack' in protected mode, to grow stack
+** capturing memory errors
+*/
+static void growstack (lua_State *L, void *ud) {
+  int size = *(int *)ud;
+  luaD_growstack(L, size);
+}
+
+
+LUA_API int lua_checkstack (lua_State *L, int size) {
+  int res;
+  CallInfo *ci = L->ci;
+  lua_lock(L);
+  if (L->stack_last - L->top > size)  /* stack large enough? */
+    res = 1;  /* yes; check is OK */
+  else {  /* no; need to grow stack */
+    int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
+    if (inuse > LUAI_MAXSTACK - size)  /* can grow without overflow? */
+      res = 0;  /* no */
+    else  /* try to grow stack */
+      res = (luaD_rawrunprotected(L, &growstack, &size) == LUA_OK);
+  }
+  if (res && ci->top < L->top + size)
+    ci->top = L->top + size;  /* adjust frame top */
+  lua_unlock(L);
+  return res;
+}
+
+
+LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
+  int i;
+  if (from == to) return;
+  lua_lock(to);
+  api_checknelems(from, n);
+  api_check(from, G(from) == G(to), "moving among independent states");
+  api_check(from, to->ci->top - to->top >= n, "not enough elements to move");
+  from->top -= n;
+  for (i = 0; i < n; i++) {
+    setobj2s(to, to->top++, from->top + i);
+  }
+  lua_unlock(to);
+}
+
+
+LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) {
+  lua_CFunction old;
+  lua_lock(L);
+  old = G(L)->panic;
+  G(L)->panic = panicf;
+  lua_unlock(L);
+  return old;
+}
+
+
+LUA_API const lua_Number *lua_version (lua_State *L) {
+  static const lua_Number version = LUA_VERSION_NUM;
+  if (L == NULL) return &version;
+  else return G(L)->version;
+}
+
+
+
+/*
+** basic stack manipulation
+*/
+
+
+/*
+** convert an acceptable stack index into an absolute index
+*/
+LUA_API int lua_absindex (lua_State *L, int idx) {
+  return (idx > 0 || ispseudo(idx))
+         ? idx
+         : cast_int(L->top - L->ci->func + idx);
+}
+
+
+LUA_API int lua_gettop (lua_State *L) {
+  return cast_int(L->top - (L->ci->func + 1));
+}
+
+
+LUA_API void lua_settop (lua_State *L, int idx) {
+  StkId func = L->ci->func;
+  lua_lock(L);
+  if (idx >= 0) {
+    api_check(L, idx <= L->stack_last - (func + 1), "new top too large");
+    while (L->top < (func + 1) + idx)
+      setnilvalue(L->top++);
+    L->top = (func + 1) + idx;
+  }
+  else {
+    api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
+    L->top += idx+1;  /* `subtract' index (index is negative) */
+  }
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_remove (lua_State *L, int idx) {
+  StkId p;
+  lua_lock(L);
+  p = index2addr(L, idx);
+  api_checkstackindex(L, idx, p);
+  while (++p < L->top) setobjs2s(L, p-1, p);
+  L->top--;
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_insert (lua_State *L, int idx) {
+  StkId p;
+  StkId q;
+  lua_lock(L);
+  p = index2addr(L, idx);
+  api_checkstackindex(L, idx, p);
+  for (q = L->top; q > p; q--)  /* use L->top as a temporary */
+    setobjs2s(L, q, q - 1);
+  setobjs2s(L, p, L->top);
+  lua_unlock(L);
+}
+
+
+static void moveto (lua_State *L, TValue *fr, int idx) {
+  TValue *to = index2addr(L, idx);
+  api_checkvalidindex(L, to);
+  setobj(L, to, fr);
+  if (idx < LUA_REGISTRYINDEX)  /* function upvalue? */
+    luaC_barrier(L, clCvalue(L->ci->func), fr);
+  /* LUA_REGISTRYINDEX does not need gc barrier
+     (collector revisits it before finishing collection) */
+}
+
+
+LUA_API void lua_replace (lua_State *L, int idx) {
+  lua_lock(L);
+  api_checknelems(L, 1);
+  moveto(L, L->top - 1, idx);
+  L->top--;
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
+  TValue *fr;
+  lua_lock(L);
+  fr = index2addr(L, fromidx);
+  moveto(L, fr, toidx);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushvalue (lua_State *L, int idx) {
+  lua_lock(L);
+  setobj2s(L, L->top, index2addr(L, idx));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+
+/*
+** access functions (stack -> C)
+*/
+
+
+LUA_API int lua_type (lua_State *L, int idx) {
+  StkId o = index2addr(L, idx);
+  return (isvalid(o) ? ttypenv(o) : LUA_TNONE);
+}
+
+
+LUA_API const char *lua_typename (lua_State *L, int t) {
+  UNUSED(L);
+  return ttypename(t);
+}
+
+
+LUA_API int lua_iscfunction (lua_State *L, int idx) {
+  StkId o = index2addr(L, idx);
+  return (ttislcf(o) || (ttisCclosure(o)));
+}
+
+
+LUA_API int lua_isnumber (lua_State *L, int idx) {
+  TValue n;
+  const TValue *o = index2addr(L, idx);
+  return tonumber(o, &n);
+}
+
+
+LUA_API int lua_isstring (lua_State *L, int idx) {
+  int t = lua_type(L, idx);
+  return (t == LUA_TSTRING || t == LUA_TNUMBER);
+}
+
+
+LUA_API int lua_isuserdata (lua_State *L, int idx) {
+  const TValue *o = index2addr(L, idx);
+  return (ttisuserdata(o) || ttislightuserdata(o));
+}
+
+
+LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
+  StkId o1 = index2addr(L, index1);
+  StkId o2 = index2addr(L, index2);
+  return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0;
+}
+
+
+LUA_API void lua_arith (lua_State *L, int op) {
+  StkId o1;  /* 1st operand */
+  StkId o2;  /* 2nd operand */
+  lua_lock(L);
+  if (op != LUA_OPUNM) /* all other operations expect two operands */
+    api_checknelems(L, 2);
+  else {  /* for unary minus, add fake 2nd operand */
+    api_checknelems(L, 1);
+    setobjs2s(L, L->top, L->top - 1);
+    L->top++;
+  }
+  o1 = L->top - 2;
+  o2 = L->top - 1;
+  if (ttisnumber(o1) && ttisnumber(o2)) {
+    setnvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2)));
+  }
+  else
+    luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD));
+  L->top--;
+  lua_unlock(L);
+}
+
+
+LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
+  StkId o1, o2;
+  int i = 0;
+  lua_lock(L);  /* may call tag method */
+  o1 = index2addr(L, index1);
+  o2 = index2addr(L, index2);
+  if (isvalid(o1) && isvalid(o2)) {
+    switch (op) {
+      case LUA_OPEQ: i = equalobj(L, o1, o2); break;
+      case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break;
+      case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break;
+      default: api_check(L, 0, "invalid option");
+    }
+  }
+  lua_unlock(L);
+  return i;
+}
+
+
+LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *isnum) {
+  TValue n;
+  const TValue *o = index2addr(L, idx);
+  if (tonumber(o, &n)) {
+    if (isnum) *isnum = 1;
+    return nvalue(o);
+  }
+  else {
+    if (isnum) *isnum = 0;
+    return 0;
+  }
+}
+
+
+LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum) {
+  TValue n;
+  const TValue *o = index2addr(L, idx);
+  if (tonumber(o, &n)) {
+    lua_Integer res;
+    lua_Number num = nvalue(o);
+    lua_number2integer(res, num);
+    if (isnum) *isnum = 1;
+    return res;
+  }
+  else {
+    if (isnum) *isnum = 0;
+    return 0;
+  }
+}
+
+
+LUA_API lua_Unsigned lua_tounsignedx (lua_State *L, int idx, int *isnum) {
+  TValue n;
+  const TValue *o = index2addr(L, idx);
+  if (tonumber(o, &n)) {
+    lua_Unsigned res;
+    lua_Number num = nvalue(o);
+    lua_number2unsigned(res, num);
+    if (isnum) *isnum = 1;
+    return res;
+  }
+  else {
+    if (isnum) *isnum = 0;
+    return 0;
+  }
+}
+
+
+LUA_API int lua_toboolean (lua_State *L, int idx) {
+  const TValue *o = index2addr(L, idx);
+  return !l_isfalse(o);
+}
+
+
+LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
+  StkId o = index2addr(L, idx);
+  if (!ttisstring(o)) {
+    lua_lock(L);  /* `luaV_tostring' may create a new string */
+    if (!luaV_tostring(L, o)) {  /* conversion failed? */
+      if (len != NULL) *len = 0;
+      lua_unlock(L);
+      return NULL;
+    }
+    luaC_checkGC(L);
+    o = index2addr(L, idx);  /* previous call may reallocate the stack */
+    lua_unlock(L);
+  }
+  if (len != NULL) *len = tsvalue(o)->len;
+  return svalue(o);
+}
+
+
+LUA_API size_t lua_rawlen (lua_State *L, int idx) {
+  StkId o = index2addr(L, idx);
+  switch (ttypenv(o)) {
+    case LUA_TSTRING: return tsvalue(o)->len;
+    case LUA_TUSERDATA: return uvalue(o)->len;
+    case LUA_TTABLE: return luaH_getn(hvalue(o));
+    default: return 0;
+  }
+}
+
+
+LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
+  StkId o = index2addr(L, idx);
+  if (ttislcf(o)) return fvalue(o);
+  else if (ttisCclosure(o))
+    return clCvalue(o)->f;
+  else return NULL;  /* not a C function */
+}
+
+
+LUA_API void *lua_touserdata (lua_State *L, int idx) {
+  StkId o = index2addr(L, idx);
+  switch (ttypenv(o)) {
+    case LUA_TUSERDATA: return (rawuvalue(o) + 1);
+    case LUA_TLIGHTUSERDATA: return pvalue(o);
+    default: return NULL;
+  }
+}
+
+
+LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
+  StkId o = index2addr(L, idx);
+  return (!ttisthread(o)) ? NULL : thvalue(o);
+}
+
+
+LUA_API const void *lua_topointer (lua_State *L, int idx) {
+  StkId o = index2addr(L, idx);
+  switch (ttype(o)) {
+    case LUA_TTABLE: return hvalue(o);
+    case LUA_TLCL: return clLvalue(o);
+    case LUA_TCCL: return clCvalue(o);
+    case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o)));
+    case LUA_TTHREAD: return thvalue(o);
+    case LUA_TUSERDATA:
+    case LUA_TLIGHTUSERDATA:
+      return lua_touserdata(L, idx);
+    default: return NULL;
+  }
+}
+
+
+
+/*
+** push functions (C -> stack)
+*/
+
+
+LUA_API void lua_pushnil (lua_State *L) {
+  lua_lock(L);
+  setnilvalue(L->top);
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
+  lua_lock(L);
+  setnvalue(L->top, n);
+  luai_checknum(L, L->top,
+    luaG_runerror(L, "C API - attempt to push a signaling NaN"));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
+  lua_lock(L);
+  setnvalue(L->top, cast_num(n));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushunsigned (lua_State *L, lua_Unsigned u) {
+  lua_Number n;
+  lua_lock(L);
+  n = lua_unsigned2number(u);
+  setnvalue(L->top, n);
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
+  TString *ts;
+  lua_lock(L);
+  luaC_checkGC(L);
+  ts = luaS_newlstr(L, s, len);
+  setsvalue2s(L, L->top, ts);
+  api_incr_top(L);
+  lua_unlock(L);
+  return getstr(ts);
+}
+
+
+LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
+  if (s == NULL) {
+    lua_pushnil(L);
+    return NULL;
+  }
+  else {
+    TString *ts;
+    lua_lock(L);
+    luaC_checkGC(L);
+    ts = luaS_new(L, s);
+    setsvalue2s(L, L->top, ts);
+    api_incr_top(L);
+    lua_unlock(L);
+    return getstr(ts);
+  }
+}
+
+
+LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
+                                      va_list argp) {
+  const char *ret;
+  lua_lock(L);
+  luaC_checkGC(L);
+  ret = luaO_pushvfstring(L, fmt, argp);
+  lua_unlock(L);
+  return ret;
+}
+
+
+LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
+  const char *ret;
+  va_list argp;
+  lua_lock(L);
+  luaC_checkGC(L);
+  va_start(argp, fmt);
+  ret = luaO_pushvfstring(L, fmt, argp);
+  va_end(argp);
+  lua_unlock(L);
+  return ret;
+}
+
+
+LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
+  lua_lock(L);
+  if (n == 0) {
+    setfvalue(L->top, fn);
+  }
+  else {
+    Closure *cl;
+    api_checknelems(L, n);
+    api_check(L, n <= MAXUPVAL, "upvalue index too large");
+    luaC_checkGC(L);
+    cl = luaF_newCclosure(L, n);
+    cl->c.f = fn;
+    L->top -= n;
+    while (n--)
+      setobj2n(L, &cl->c.upvalue[n], L->top + n);
+    setclCvalue(L, L->top, cl);
+  }
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushboolean (lua_State *L, int b) {
+  lua_lock(L);
+  setbvalue(L->top, (b != 0));  /* ensure that true is 1 */
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
+  lua_lock(L);
+  setpvalue(L->top, p);
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API int lua_pushthread (lua_State *L) {
+  lua_lock(L);
+  setthvalue(L, L->top, L);
+  api_incr_top(L);
+  lua_unlock(L);
+  return (G(L)->mainthread == L);
+}
+
+
+
+/*
+** get functions (Lua -> stack)
+*/
+
+
+LUA_API void lua_getglobal (lua_State *L, const char *var) {
+  Table *reg = hvalue(&G(L)->l_registry);
+  const TValue *gt;  /* global table */
+  lua_lock(L);
+  gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
+  setsvalue2s(L, L->top++, luaS_new(L, var));
+  luaV_gettable(L, gt, L->top - 1, L->top - 1);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_gettable (lua_State *L, int idx) {
+  StkId t;
+  lua_lock(L);
+  t = index2addr(L, idx);
+  luaV_gettable(L, t, L->top - 1, L->top - 1);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
+  StkId t;
+  lua_lock(L);
+  t = index2addr(L, idx);
+  setsvalue2s(L, L->top, luaS_new(L, k));
+  api_incr_top(L);
+  luaV_gettable(L, t, L->top - 1, L->top - 1);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_rawget (lua_State *L, int idx) {
+  StkId t;
+  lua_lock(L);
+  t = index2addr(L, idx);
+  api_check(L, ttistable(t), "table expected");
+  setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_rawgeti (lua_State *L, int idx, int n) {
+  StkId t;
+  lua_lock(L);
+  t = index2addr(L, idx);
+  api_check(L, ttistable(t), "table expected");
+  setobj2s(L, L->top, luaH_getint(hvalue(t), n));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_rawgetp (lua_State *L, int idx, const void *p) {
+  StkId t;
+  TValue k;
+  lua_lock(L);
+  t = index2addr(L, idx);
+  api_check(L, ttistable(t), "table expected");
+  setpvalue(&k, cast(void *, p));
+  setobj2s(L, L->top, luaH_get(hvalue(t), &k));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
+  Table *t;
+  lua_lock(L);
+  luaC_checkGC(L);
+  t = luaH_new(L);
+  sethvalue(L, L->top, t);
+  api_incr_top(L);
+  if (narray > 0 || nrec > 0)
+    luaH_resize(L, t, narray, nrec);
+  lua_unlock(L);
+}
+
+
+LUA_API int lua_getmetatable (lua_State *L, int objindex) {
+  const TValue *obj;
+  Table *mt = NULL;
+  int res;
+  lua_lock(L);
+  obj = index2addr(L, objindex);
+  switch (ttypenv(obj)) {
+    case LUA_TTABLE:
+      mt = hvalue(obj)->metatable;
+      break;
+    case LUA_TUSERDATA:
+      mt = uvalue(obj)->metatable;
+      break;
+    default:
+      mt = G(L)->mt[ttypenv(obj)];
+      break;
+  }
+  if (mt == NULL)
+    res = 0;
+  else {
+    sethvalue(L, L->top, mt);
+    api_incr_top(L);
+    res = 1;
+  }
+  lua_unlock(L);
+  return res;
+}
+
+
+LUA_API void lua_getuservalue (lua_State *L, int idx) {
+  StkId o;
+  lua_lock(L);
+  o = index2addr(L, idx);
+  api_check(L, ttisuserdata(o), "userdata expected");
+  if (uvalue(o)->env) {
+    sethvalue(L, L->top, uvalue(o)->env);
+  } else
+    setnilvalue(L->top);
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+/*
+** set functions (stack -> Lua)
+*/
+
+
+LUA_API void lua_setglobal (lua_State *L, const char *var) {
+  Table *reg = hvalue(&G(L)->l_registry);
+  const TValue *gt;  /* global table */
+  lua_lock(L);
+  api_checknelems(L, 1);
+  gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
+  setsvalue2s(L, L->top++, luaS_new(L, var));
+  luaV_settable(L, gt, L->top - 1, L->top - 2);
+  L->top -= 2;  /* pop value and key */
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_settable (lua_State *L, int idx) {
+  StkId t;
+  lua_lock(L);
+  api_checknelems(L, 2);
+  t = index2addr(L, idx);
+  luaV_settable(L, t, L->top - 2, L->top - 1);
+  L->top -= 2;  /* pop index and value */
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
+  StkId t;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  t = index2addr(L, idx);
+  setsvalue2s(L, L->top++, luaS_new(L, k));
+  luaV_settable(L, t, L->top - 1, L->top - 2);
+  L->top -= 2;  /* pop value and key */
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_rawset (lua_State *L, int idx) {
+  StkId t;
+  lua_lock(L);
+  api_checknelems(L, 2);
+  t = index2addr(L, idx);
+  api_check(L, ttistable(t), "table expected");
+  setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1);
+  invalidateTMcache(hvalue(t));
+  luaC_barrierback(L, gcvalue(t), L->top-1);
+  L->top -= 2;
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_rawseti (lua_State *L, int idx, int n) {
+  StkId t;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  t = index2addr(L, idx);
+  api_check(L, ttistable(t), "table expected");
+  luaH_setint(L, hvalue(t), n, L->top - 1);
+  luaC_barrierback(L, gcvalue(t), L->top-1);
+  L->top--;
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
+  StkId t;
+  TValue k;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  t = index2addr(L, idx);
+  api_check(L, ttistable(t), "table expected");
+  setpvalue(&k, cast(void *, p));
+  setobj2t(L, luaH_set(L, hvalue(t), &k), L->top - 1);
+  luaC_barrierback(L, gcvalue(t), L->top - 1);
+  L->top--;
+  lua_unlock(L);
+}
+
+
+LUA_API int lua_setmetatable (lua_State *L, int objindex) {
+  TValue *obj;
+  Table *mt;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  obj = index2addr(L, objindex);
+  if (ttisnil(L->top - 1))
+    mt = NULL;
+  else {
+    api_check(L, ttistable(L->top - 1), "table expected");
+    mt = hvalue(L->top - 1);
+  }
+  switch (ttypenv(obj)) {
+    case LUA_TTABLE: {
+      hvalue(obj)->metatable = mt;
+      if (mt) {
+        luaC_objbarrierback(L, gcvalue(obj), mt);
+        luaC_checkfinalizer(L, gcvalue(obj), mt);
+      }
+      break;
+    }
+    case LUA_TUSERDATA: {
+      uvalue(obj)->metatable = mt;
+      if (mt) {
+        luaC_objbarrier(L, rawuvalue(obj), mt);
+        luaC_checkfinalizer(L, gcvalue(obj), mt);
+      }
+      break;
+    }
+    default: {
+      G(L)->mt[ttypenv(obj)] = mt;
+      break;
+    }
+  }
+  L->top--;
+  lua_unlock(L);
+  return 1;
+}
+
+
+LUA_API void lua_setuservalue (lua_State *L, int idx) {
+  StkId o;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  o = index2addr(L, idx);
+  api_check(L, ttisuserdata(o), "userdata expected");
+  if (ttisnil(L->top - 1))
+    uvalue(o)->env = NULL;
+  else {
+    api_check(L, ttistable(L->top - 1), "table expected");
+    uvalue(o)->env = hvalue(L->top - 1);
+    luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
+  }
+  L->top--;
+  lua_unlock(L);
+}
+
+
+/*
+** `load' and `call' functions (run Lua code)
+*/
+
+
+#define checkresults(L,na,nr) \
+     api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
+	"results from function overflow current stack size")
+
+
+LUA_API int lua_getctx (lua_State *L, int *ctx) {
+  if (L->ci->callstatus & CIST_YIELDED) {
+    if (ctx) *ctx = L->ci->u.c.ctx;
+    return L->ci->u.c.status;
+  }
+  else return LUA_OK;
+}
+
+
+LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx,
+                        lua_CFunction k) {
+  StkId func;
+  lua_lock(L);
+  api_check(L, k == NULL || !isLua(L->ci),
+    "cannot use continuations inside hooks");
+  api_checknelems(L, nargs+1);
+  api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
+  checkresults(L, nargs, nresults);
+  func = L->top - (nargs+1);
+  if (k != NULL && L->nny == 0) {  /* need to prepare continuation? */
+    L->ci->u.c.k = k;  /* save continuation */
+    L->ci->u.c.ctx = ctx;  /* save context */
+    luaD_call(L, func, nresults, 1);  /* do the call */
+  }
+  else  /* no continuation or no yieldable */
+    luaD_call(L, func, nresults, 0);  /* just do the call */
+  adjustresults(L, nresults);
+  lua_unlock(L);
+}
+
+
+
+/*
+** Execute a protected call.
+*/
+struct CallS {  /* data to `f_call' */
+  StkId func;
+  int nresults;
+};
+
+
+static void f_call (lua_State *L, void *ud) {
+  struct CallS *c = cast(struct CallS *, ud);
+  luaD_call(L, c->func, c->nresults, 0);
+}
+
+
+
+LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
+                        int ctx, lua_CFunction k) {
+  struct CallS c;
+  int status;
+  ptrdiff_t func;
+  lua_lock(L);
+  api_check(L, k == NULL || !isLua(L->ci),
+    "cannot use continuations inside hooks");
+  api_checknelems(L, nargs+1);
+  api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
+  checkresults(L, nargs, nresults);
+  if (errfunc == 0)
+    func = 0;
+  else {
+    StkId o = index2addr(L, errfunc);
+    api_checkstackindex(L, errfunc, o);
+    func = savestack(L, o);
+  }
+  c.func = L->top - (nargs+1);  /* function to be called */
+  if (k == NULL || L->nny > 0) {  /* no continuation or no yieldable? */
+    c.nresults = nresults;  /* do a 'conventional' protected call */
+    status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
+  }
+  else {  /* prepare continuation (call is already protected by 'resume') */
+    CallInfo *ci = L->ci;
+    ci->u.c.k = k;  /* save continuation */
+    ci->u.c.ctx = ctx;  /* save context */
+    /* save information for error recovery */
+    ci->extra = savestack(L, c.func);
+    ci->u.c.old_allowhook = L->allowhook;
+    ci->u.c.old_errfunc = L->errfunc;
+    L->errfunc = func;
+    /* mark that function may do error recovery */
+    ci->callstatus |= CIST_YPCALL;
+    luaD_call(L, c.func, nresults, 1);  /* do the call */
+    ci->callstatus &= ~CIST_YPCALL;
+    L->errfunc = ci->u.c.old_errfunc;
+    status = LUA_OK;  /* if it is here, there were no errors */
+  }
+  adjustresults(L, nresults);
+  lua_unlock(L);
+  return status;
+}
+
+
+LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
+                      const char *chunkname, const char *mode) {
+  ZIO z;
+  int status;
+  lua_lock(L);
+  if (!chunkname) chunkname = "?";
+  luaZ_init(L, &z, reader, data);
+  status = luaD_protectedparser(L, &z, chunkname, mode);
+  if (status == LUA_OK) {  /* no errors? */
+    LClosure *f = clLvalue(L->top - 1);  /* get newly created function */
+    if (f->nupvalues == 1) {  /* does it have one upvalue? */
+      /* get global table from registry */
+      Table *reg = hvalue(&G(L)->l_registry);
+      const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
+      /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
+      setobj(L, f->upvals[0]->v, gt);
+      luaC_barrier(L, f->upvals[0], gt);
+    }
+  }
+  lua_unlock(L);
+  return status;
+}
+
+
+LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) {
+  int status;
+  TValue *o;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  o = L->top - 1;
+  if (isLfunction(o))
+    status = luaU_dump(L, getproto(o), writer, data, 0);
+  else
+    status = 1;
+  lua_unlock(L);
+  return status;
+}
+
+
+LUA_API int lua_status (lua_State *L) {
+  return L->status;
+}
+
+
+/*
+** Garbage-collection function
+*/
+
+LUA_API int lua_gc (lua_State *L, int what, int data) {
+  int res = 0;
+  global_State *g;
+  lua_lock(L);
+  g = G(L);
+  switch (what) {
+    case LUA_GCSTOP: {
+      g->gcrunning = 0;
+      break;
+    }
+    case LUA_GCRESTART: {
+      luaE_setdebt(g, 0);
+      g->gcrunning = 1;
+      break;
+    }
+    case LUA_GCCOLLECT: {
+      luaC_fullgc(L, 0);
+      break;
+    }
+    case LUA_GCCOUNT: {
+      /* GC values are expressed in Kbytes: #bytes/2^10 */
+      res = cast_int(gettotalbytes(g) >> 10);
+      break;
+    }
+    case LUA_GCCOUNTB: {
+      res = cast_int(gettotalbytes(g) & 0x3ff);
+      break;
+    }
+    case LUA_GCSTEP: {
+      if (g->gckind == KGC_GEN) {  /* generational mode? */
+        res = (g->GCestimate == 0);  /* true if it will do major collection */
+        luaC_forcestep(L);  /* do a single step */
+      }
+      else {
+       lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE;
+       if (g->gcrunning)
+         debt += g->GCdebt;  /* include current debt */
+       luaE_setdebt(g, debt);
+       luaC_forcestep(L);
+       if (g->gcstate == GCSpause)  /* end of cycle? */
+         res = 1;  /* signal it */
+      }
+      break;
+    }
+    case LUA_GCSETPAUSE: {
+      res = g->gcpause;
+      g->gcpause = data;
+      break;
+    }
+    case LUA_GCSETMAJORINC: {
+      res = g->gcmajorinc;
+      g->gcmajorinc = data;
+      break;
+    }
+    case LUA_GCSETSTEPMUL: {
+      res = g->gcstepmul;
+      g->gcstepmul = data;
+      break;
+    }
+    case LUA_GCISRUNNING: {
+      res = g->gcrunning;
+      break;
+    }
+    case LUA_GCGEN: {  /* change collector to generational mode */
+      luaC_changemode(L, KGC_GEN);
+      break;
+    }
+    case LUA_GCINC: {  /* change collector to incremental mode */
+      luaC_changemode(L, KGC_NORMAL);
+      break;
+    }
+    default: res = -1;  /* invalid option */
+  }
+  lua_unlock(L);
+  return res;
+}
+
+
+
+/*
+** miscellaneous functions
+*/
+
+
+LUA_API int lua_error (lua_State *L) {
+  lua_lock(L);
+  api_checknelems(L, 1);
+  luaG_errormsg(L);
+  /* code unreachable; will unlock when control actually leaves the kernel */
+  return 0;  /* to avoid warnings */
+}
+
+
+LUA_API int lua_next (lua_State *L, int idx) {
+  StkId t;
+  int more;
+  lua_lock(L);
+  t = index2addr(L, idx);
+  api_check(L, ttistable(t), "table expected");
+  more = luaH_next(L, hvalue(t), L->top - 1);
+  if (more) {
+    api_incr_top(L);
+  }
+  else  /* no more elements */
+    L->top -= 1;  /* remove key */
+  lua_unlock(L);
+  return more;
+}
+
+
+LUA_API void lua_concat (lua_State *L, int n) {
+  lua_lock(L);
+  api_checknelems(L, n);
+  if (n >= 2) {
+    luaC_checkGC(L);
+    luaV_concat(L, n);
+  }
+  else if (n == 0) {  /* push empty string */
+    setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));
+    api_incr_top(L);
+  }
+  /* else n == 1; nothing to do */
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_len (lua_State *L, int idx) {
+  StkId t;
+  lua_lock(L);
+  t = index2addr(L, idx);
+  luaV_objlen(L, L->top, t);
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) {
+  lua_Alloc f;
+  lua_lock(L);
+  if (ud) *ud = G(L)->ud;
+  f = G(L)->frealloc;
+  lua_unlock(L);
+  return f;
+}
+
+
+LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
+  lua_lock(L);
+  G(L)->ud = ud;
+  G(L)->frealloc = f;
+  lua_unlock(L);
+}
+
+
+LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
+  Udata *u;
+  lua_lock(L);
+  luaC_checkGC(L);
+  u = luaS_newudata(L, size, NULL);
+  setuvalue(L, L->top, u);
+  api_incr_top(L);
+  lua_unlock(L);
+  return u + 1;
+}
+
+
+
+static const char *aux_upvalue (StkId fi, int n, TValue **val,
+                                GCObject **owner) {
+  switch (ttype(fi)) {
+    case LUA_TCCL: {  /* C closure */
+      CClosure *f = clCvalue(fi);
+      if (!(1 <= n && n <= f->nupvalues)) return NULL;
+      *val = &f->upvalue[n-1];
+      if (owner) *owner = obj2gco(f);
+      return "";
+    }
+    case LUA_TLCL: {  /* Lua closure */
+      LClosure *f = clLvalue(fi);
+      TString *name;
+      Proto *p = f->p;
+      if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
+      *val = f->upvals[n-1]->v;
+      if (owner) *owner = obj2gco(f->upvals[n - 1]);
+      name = p->upvalues[n-1].name;
+      return (name == NULL) ? "" : getstr(name);
+    }
+    default: return NULL;  /* not a closure */
+  }
+}
+
+
+LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
+  const char *name;
+  TValue *val = NULL;  /* to avoid warnings */
+  lua_lock(L);
+  name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL);
+  if (name) {
+    setobj2s(L, L->top, val);
+    api_incr_top(L);
+  }
+  lua_unlock(L);
+  return name;
+}
+
+
+LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
+  const char *name;
+  TValue *val = NULL;  /* to avoid warnings */
+  GCObject *owner = NULL;  /* to avoid warnings */
+  StkId fi;
+  lua_lock(L);
+  fi = index2addr(L, funcindex);
+  api_checknelems(L, 1);
+  name = aux_upvalue(fi, n, &val, &owner);
+  if (name) {
+    L->top--;
+    setobj(L, val, L->top);
+    luaC_barrier(L, owner, L->top);
+  }
+  lua_unlock(L);
+  return name;
+}
+
+
+static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
+  LClosure *f;
+  StkId fi = index2addr(L, fidx);
+  api_check(L, ttisLclosure(fi), "Lua function expected");
+  f = clLvalue(fi);
+  api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
+  if (pf) *pf = f;
+  return &f->upvals[n - 1];  /* get its upvalue pointer */
+}
+
+
+LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
+  StkId fi = index2addr(L, fidx);
+  switch (ttype(fi)) {
+    case LUA_TLCL: {  /* lua closure */
+      return *getupvalref(L, fidx, n, NULL);
+    }
+    case LUA_TCCL: {  /* C closure */
+      CClosure *f = clCvalue(fi);
+      api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index");
+      return &f->upvalue[n - 1];
+    }
+    default: {
+      api_check(L, 0, "closure expected");
+      return NULL;
+    }
+  }
+}
+
+
+LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
+                                            int fidx2, int n2) {
+  LClosure *f1;
+  UpVal **up1 = getupvalref(L, fidx1, n1, &f1);
+  UpVal **up2 = getupvalref(L, fidx2, n2, NULL);
+  *up1 = *up2;
+  luaC_objbarrier(L, f1, *up2);
+}
+

=== added file 'src/scripting/eris/lapi.h'
--- src/scripting/eris/lapi.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lapi.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,24 @@
+/*
+** $Id: lapi.h,v 2.7 2009/11/27 15:37:59 roberto Exp $
+** Auxiliary functions from Lua API
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lapi_h
+#define lapi_h
+
+
+#include "llimits.h"
+#include "lstate.h"
+
+#define api_incr_top(L)   {L->top++; api_check(L, L->top <= L->ci->top, \
+				"stack overflow");}
+
+#define adjustresults(L,nres) \
+    { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
+
+#define api_checknelems(L,n)	api_check(L, (n) < (L->top - L->ci->func), \
+				  "not enough elements in the stack")
+
+
+#endif

=== added file 'src/scripting/eris/lauxlib.c'
--- src/scripting/eris/lauxlib.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lauxlib.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,959 @@
+/*
+** $Id: lauxlib.c,v 1.248 2013/03/21 13:54:57 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* This file uses only the official API of Lua.
+** Any function declared here could be written as an application function.
+*/
+
+#define lauxlib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+
+
+/*
+** {======================================================
+** Traceback
+** =======================================================
+*/
+
+
+#define LEVELS1	12	/* size of the first part of the stack */
+#define LEVELS2	10	/* size of the second part of the stack */
+
+
+
+/*
+** search for 'objidx' in table at index -1.
+** return 1 + string at top if find a good name.
+*/
+static int findfield (lua_State *L, int objidx, int level) {
+  if (level == 0 || !lua_istable(L, -1))
+    return 0;  /* not found */
+  lua_pushnil(L);  /* start 'next' loop */
+  while (lua_next(L, -2)) {  /* for each pair in table */
+    if (lua_type(L, -2) == LUA_TSTRING) {  /* ignore non-string keys */
+      if (lua_rawequal(L, objidx, -1)) {  /* found object? */
+        lua_pop(L, 1);  /* remove value (but keep name) */
+        return 1;
+      }
+      else if (findfield(L, objidx, level - 1)) {  /* try recursively */
+        lua_remove(L, -2);  /* remove table (but keep name) */
+        lua_pushliteral(L, ".");
+        lua_insert(L, -2);  /* place '.' between the two names */
+        lua_concat(L, 3);
+        return 1;
+      }
+    }
+    lua_pop(L, 1);  /* remove value */
+  }
+  return 0;  /* not found */
+}
+
+
+static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
+  int top = lua_gettop(L);
+  lua_getinfo(L, "f", ar);  /* push function */
+  lua_pushglobaltable(L);
+  if (findfield(L, top + 1, 2)) {
+    lua_copy(L, -1, top + 1);  /* move name to proper place */
+    lua_pop(L, 2);  /* remove pushed values */
+    return 1;
+  }
+  else {
+    lua_settop(L, top);  /* remove function and global table */
+    return 0;
+  }
+}
+
+
+static void pushfuncname (lua_State *L, lua_Debug *ar) {
+  if (*ar->namewhat != '\0')  /* is there a name? */
+    lua_pushfstring(L, "function " LUA_QS, ar->name);
+  else if (*ar->what == 'm')  /* main? */
+      lua_pushliteral(L, "main chunk");
+  else if (*ar->what == 'C') {
+    if (pushglobalfuncname(L, ar)) {
+      lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
+      lua_remove(L, -2);  /* remove name */
+    }
+    else
+      lua_pushliteral(L, "?");
+  }
+  else
+    lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
+}
+
+
+static int countlevels (lua_State *L) {
+  lua_Debug ar;
+  int li = 1, le = 1;
+  /* find an upper bound */
+  while (lua_getstack(L, le, &ar)) { li = le; le *= 2; }
+  /* do a binary search */
+  while (li < le) {
+    int m = (li + le)/2;
+    if (lua_getstack(L, m, &ar)) li = m + 1;
+    else le = m;
+  }
+  return le - 1;
+}
+
+
+LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
+                                const char *msg, int level) {
+  lua_Debug ar;
+  int top = lua_gettop(L);
+  int numlevels = countlevels(L1);
+  int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
+  if (msg) lua_pushfstring(L, "%s\n", msg);
+  lua_pushliteral(L, "stack traceback:");
+  while (lua_getstack(L1, level++, &ar)) {
+    if (level == mark) {  /* too many levels? */
+      lua_pushliteral(L, "\n\t...");  /* add a '...' */
+      level = numlevels - LEVELS2;  /* and skip to last ones */
+    }
+    else {
+      lua_getinfo(L1, "Slnt", &ar);
+      lua_pushfstring(L, "\n\t%s:", ar.short_src);
+      if (ar.currentline > 0)
+        lua_pushfstring(L, "%d:", ar.currentline);
+      lua_pushliteral(L, " in ");
+      pushfuncname(L, &ar);
+      if (ar.istailcall)
+        lua_pushliteral(L, "\n\t(...tail calls...)");
+      lua_concat(L, lua_gettop(L) - top);
+    }
+  }
+  lua_concat(L, lua_gettop(L) - top);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Error-report functions
+** =======================================================
+*/
+
+LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
+  lua_Debug ar;
+  if (!lua_getstack(L, 0, &ar))  /* no stack frame? */
+    return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);
+  lua_getinfo(L, "n", &ar);
+  if (strcmp(ar.namewhat, "method") == 0) {
+    narg--;  /* do not count `self' */
+    if (narg == 0)  /* error is in the self argument itself? */
+      return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
+                           ar.name, extramsg);
+  }
+  if (ar.name == NULL)
+    ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
+  return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
+                        narg, ar.name, extramsg);
+}
+
+
+static int typeerror (lua_State *L, int narg, const char *tname) {
+  const char *msg = lua_pushfstring(L, "%s expected, got %s",
+                                    tname, luaL_typename(L, narg));
+  return luaL_argerror(L, narg, msg);
+}
+
+
+static void tag_error (lua_State *L, int narg, int tag) {
+  typeerror(L, narg, lua_typename(L, tag));
+}
+
+
+LUALIB_API void luaL_where (lua_State *L, int level) {
+  lua_Debug ar;
+  if (lua_getstack(L, level, &ar)) {  /* check function at level */
+    lua_getinfo(L, "Sl", &ar);  /* get info about it */
+    if (ar.currentline > 0) {  /* is there info? */
+      lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
+      return;
+    }
+  }
+  lua_pushliteral(L, "");  /* else, no information available... */
+}
+
+
+LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
+  va_list argp;
+  va_start(argp, fmt);
+  luaL_where(L, 1);
+  lua_pushvfstring(L, fmt, argp);
+  va_end(argp);
+  lua_concat(L, 2);
+  return lua_error(L);
+}
+
+
+LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
+  int en = errno;  /* calls to Lua API may change this value */
+  if (stat) {
+    lua_pushboolean(L, 1);
+    return 1;
+  }
+  else {
+    lua_pushnil(L);
+    if (fname)
+      lua_pushfstring(L, "%s: %s", fname, strerror(en));
+    else
+      lua_pushstring(L, strerror(en));
+    lua_pushinteger(L, en);
+    return 3;
+  }
+}
+
+
+#if !defined(inspectstat)	/* { */
+
+#if defined(LUA_USE_POSIX)
+
+#include <sys/wait.h>
+
+/*
+** use appropriate macros to interpret 'pclose' return status
+*/
+#define inspectstat(stat,what)  \
+   if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \
+   else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; }
+
+#else
+
+#define inspectstat(stat,what)  /* no op */
+
+#endif
+
+#endif				/* } */
+
+
+LUALIB_API int luaL_execresult (lua_State *L, int stat) {
+  const char *what = "exit";  /* type of termination */
+  if (stat == -1)  /* error? */
+    return luaL_fileresult(L, 0, NULL);
+  else {
+    inspectstat(stat, what);  /* interpret result */
+    if (*what == 'e' && stat == 0)  /* successful termination? */
+      lua_pushboolean(L, 1);
+    else
+      lua_pushnil(L);
+    lua_pushstring(L, what);
+    lua_pushinteger(L, stat);
+    return 3;  /* return true/nil,what,code */
+  }
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Userdata's metatable manipulation
+** =======================================================
+*/
+
+LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
+  luaL_getmetatable(L, tname);  /* try to get metatable */
+  if (!lua_isnil(L, -1))  /* name already in use? */
+    return 0;  /* leave previous value on top, but return 0 */
+  lua_pop(L, 1);
+  lua_newtable(L);  /* create metatable */
+  lua_pushvalue(L, -1);
+  lua_setfield(L, LUA_REGISTRYINDEX, tname);  /* registry.name = metatable */
+  return 1;
+}
+
+
+LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) {
+  luaL_getmetatable(L, tname);
+  lua_setmetatable(L, -2);
+}
+
+
+LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) {
+  void *p = lua_touserdata(L, ud);
+  if (p != NULL) {  /* value is a userdata? */
+    if (lua_getmetatable(L, ud)) {  /* does it have a metatable? */
+      luaL_getmetatable(L, tname);  /* get correct metatable */
+      if (!lua_rawequal(L, -1, -2))  /* not the same? */
+        p = NULL;  /* value is a userdata with wrong metatable */
+      lua_pop(L, 2);  /* remove both metatables */
+      return p;
+    }
+  }
+  return NULL;  /* value is not a userdata with a metatable */
+}
+
+
+LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
+  void *p = luaL_testudata(L, ud, tname);
+  if (p == NULL) typeerror(L, ud, tname);
+  return p;
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Argument check functions
+** =======================================================
+*/
+
+LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
+                                 const char *const lst[]) {
+  const char *name = (def) ? luaL_optstring(L, narg, def) :
+                             luaL_checkstring(L, narg);
+  int i;
+  for (i=0; lst[i]; i++)
+    if (strcmp(lst[i], name) == 0)
+      return i;
+  return luaL_argerror(L, narg,
+                       lua_pushfstring(L, "invalid option " LUA_QS, name));
+}
+
+
+LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
+  /* keep some extra space to run error routines, if needed */
+  const int extra = LUA_MINSTACK;
+  if (!lua_checkstack(L, space + extra)) {
+    if (msg)
+      luaL_error(L, "stack overflow (%s)", msg);
+    else
+      luaL_error(L, "stack overflow");
+  }
+}
+
+
+LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
+  if (lua_type(L, narg) != t)
+    tag_error(L, narg, t);
+}
+
+
+LUALIB_API void luaL_checkany (lua_State *L, int narg) {
+  if (lua_type(L, narg) == LUA_TNONE)
+    luaL_argerror(L, narg, "value expected");
+}
+
+
+LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
+  const char *s = lua_tolstring(L, narg, len);
+  if (!s) tag_error(L, narg, LUA_TSTRING);
+  return s;
+}
+
+
+LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
+                                        const char *def, size_t *len) {
+  if (lua_isnoneornil(L, narg)) {
+    if (len)
+      *len = (def ? strlen(def) : 0);
+    return def;
+  }
+  else return luaL_checklstring(L, narg, len);
+}
+
+
+LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
+  int isnum;
+  lua_Number d = lua_tonumberx(L, narg, &isnum);
+  if (!isnum)
+    tag_error(L, narg, LUA_TNUMBER);
+  return d;
+}
+
+
+LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
+  return luaL_opt(L, luaL_checknumber, narg, def);
+}
+
+
+LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
+  int isnum;
+  lua_Integer d = lua_tointegerx(L, narg, &isnum);
+  if (!isnum)
+    tag_error(L, narg, LUA_TNUMBER);
+  return d;
+}
+
+
+LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) {
+  int isnum;
+  lua_Unsigned d = lua_tounsignedx(L, narg, &isnum);
+  if (!isnum)
+    tag_error(L, narg, LUA_TNUMBER);
+  return d;
+}
+
+
+LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
+                                                      lua_Integer def) {
+  return luaL_opt(L, luaL_checkinteger, narg, def);
+}
+
+
+LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg,
+                                                        lua_Unsigned def) {
+  return luaL_opt(L, luaL_checkunsigned, narg, def);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+/*
+** check whether buffer is using a userdata on the stack as a temporary
+** buffer
+*/
+#define buffonstack(B)	((B)->b != (B)->initb)
+
+
+/*
+** returns a pointer to a free area with at least 'sz' bytes
+*/
+LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
+  lua_State *L = B->L;
+  if (B->size - B->n < sz) {  /* not enough space? */
+    char *newbuff;
+    size_t newsize = B->size * 2;  /* double buffer size */
+    if (newsize - B->n < sz)  /* not big enough? */
+      newsize = B->n + sz;
+    if (newsize < B->n || newsize - B->n < sz)
+      luaL_error(L, "buffer too large");
+    /* create larger buffer */
+    newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
+    /* move content to new buffer */
+    memcpy(newbuff, B->b, B->n * sizeof(char));
+    if (buffonstack(B))
+      lua_remove(L, -2);  /* remove old buffer */
+    B->b = newbuff;
+    B->size = newsize;
+  }
+  return &B->b[B->n];
+}
+
+
+LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
+  char *b = luaL_prepbuffsize(B, l);
+  memcpy(b, s, l * sizeof(char));
+  luaL_addsize(B, l);
+}
+
+
+LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
+  luaL_addlstring(B, s, strlen(s));
+}
+
+
+LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
+  lua_State *L = B->L;
+  lua_pushlstring(L, B->b, B->n);
+  if (buffonstack(B))
+    lua_remove(L, -2);  /* remove old buffer */
+}
+
+
+LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
+  luaL_addsize(B, sz);
+  luaL_pushresult(B);
+}
+
+
+LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
+  lua_State *L = B->L;
+  size_t l;
+  const char *s = lua_tolstring(L, -1, &l);
+  if (buffonstack(B))
+    lua_insert(L, -2);  /* put value below buffer */
+  luaL_addlstring(B, s, l);
+  lua_remove(L, (buffonstack(B)) ? -2 : -1);  /* remove value */
+}
+
+
+LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
+  B->L = L;
+  B->b = B->initb;
+  B->n = 0;
+  B->size = LUAL_BUFFERSIZE;
+}
+
+
+LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
+  luaL_buffinit(L, B);
+  return luaL_prepbuffsize(B, sz);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Reference system
+** =======================================================
+*/
+
+/* index of free-list header */
+#define freelist	0
+
+
+LUALIB_API int luaL_ref (lua_State *L, int t) {
+  int ref;
+  if (lua_isnil(L, -1)) {
+    lua_pop(L, 1);  /* remove from stack */
+    return LUA_REFNIL;  /* `nil' has a unique fixed reference */
+  }
+  t = lua_absindex(L, t);
+  lua_rawgeti(L, t, freelist);  /* get first free element */
+  ref = (int)lua_tointeger(L, -1);  /* ref = t[freelist] */
+  lua_pop(L, 1);  /* remove it from stack */
+  if (ref != 0) {  /* any free element? */
+    lua_rawgeti(L, t, ref);  /* remove it from list */
+    lua_rawseti(L, t, freelist);  /* (t[freelist] = t[ref]) */
+  }
+  else  /* no free elements */
+    ref = (int)lua_rawlen(L, t) + 1;  /* get a new reference */
+  lua_rawseti(L, t, ref);
+  return ref;
+}
+
+
+LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
+  if (ref >= 0) {
+    t = lua_absindex(L, t);
+    lua_rawgeti(L, t, freelist);
+    lua_rawseti(L, t, ref);  /* t[ref] = t[freelist] */
+    lua_pushinteger(L, ref);
+    lua_rawseti(L, t, freelist);  /* t[freelist] = ref */
+  }
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Load functions
+** =======================================================
+*/
+
+typedef struct LoadF {
+  int n;  /* number of pre-read characters */
+  FILE *f;  /* file being read */
+  char buff[LUAL_BUFFERSIZE];  /* area for reading file */
+} LoadF;
+
+
+static const char *getF (lua_State *L, void *ud, size_t *size) {
+  LoadF *lf = (LoadF *)ud;
+  (void)L;  /* not used */
+  if (lf->n > 0) {  /* are there pre-read characters to be read? */
+    *size = lf->n;  /* return them (chars already in buffer) */
+    lf->n = 0;  /* no more pre-read characters */
+  }
+  else {  /* read a block from file */
+    /* 'fread' can return > 0 *and* set the EOF flag. If next call to
+       'getF' called 'fread', it might still wait for user input.
+       The next check avoids this problem. */
+    if (feof(lf->f)) return NULL;
+    *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);  /* read block */
+  }
+  return lf->buff;
+}
+
+
+static int errfile (lua_State *L, const char *what, int fnameindex) {
+  const char *serr = strerror(errno);
+  const char *filename = lua_tostring(L, fnameindex) + 1;
+  lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
+  lua_remove(L, fnameindex);
+  return LUA_ERRFILE;
+}
+
+
+static int skipBOM (LoadF *lf) {
+  const char *p = "\xEF\xBB\xBF";  /* Utf8 BOM mark */
+  int c;
+  lf->n = 0;
+  do {
+    c = getc(lf->f);
+    if (c == EOF || c != *(const unsigned char *)p++) return c;
+    lf->buff[lf->n++] = c;  /* to be read by the parser */
+  } while (*p != '\0');
+  lf->n = 0;  /* prefix matched; discard it */
+  return getc(lf->f);  /* return next character */
+}
+
+
+/*
+** reads the first character of file 'f' and skips an optional BOM mark
+** in its beginning plus its first line if it starts with '#'. Returns
+** true if it skipped the first line.  In any case, '*cp' has the
+** first "valid" character of the file (after the optional BOM and
+** a first-line comment).
+*/
+static int skipcomment (LoadF *lf, int *cp) {
+  int c = *cp = skipBOM(lf);
+  if (c == '#') {  /* first line is a comment (Unix exec. file)? */
+    do {  /* skip first line */
+      c = getc(lf->f);
+    } while (c != EOF && c != '\n') ;
+    *cp = getc(lf->f);  /* skip end-of-line, if present */
+    return 1;  /* there was a comment */
+  }
+  else return 0;  /* no comment */
+}
+
+
+LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
+                                             const char *mode) {
+  LoadF lf;
+  int status, readstatus;
+  int c;
+  int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */
+  if (filename == NULL) {
+    lua_pushliteral(L, "=stdin");
+    lf.f = stdin;
+  }
+  else {
+    lua_pushfstring(L, "@%s", filename);
+    lf.f = fopen(filename, "r");
+    if (lf.f == NULL) return errfile(L, "open", fnameindex);
+  }
+  if (skipcomment(&lf, &c))  /* read initial portion */
+    lf.buff[lf.n++] = '\n';  /* add line to correct line numbers */
+  if (c == LUA_SIGNATURE[0] && filename) {  /* binary file? */
+    lf.f = freopen(filename, "rb", lf.f);  /* reopen in binary mode */
+    if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
+    skipcomment(&lf, &c);  /* re-read initial portion */
+  }
+  if (c != EOF)
+    lf.buff[lf.n++] = c;  /* 'c' is the first character of the stream */
+  status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
+  readstatus = ferror(lf.f);
+  if (filename) fclose(lf.f);  /* close file (even in case of errors) */
+  if (readstatus) {
+    lua_settop(L, fnameindex);  /* ignore results from `lua_load' */
+    return errfile(L, "read", fnameindex);
+  }
+  lua_remove(L, fnameindex);
+  return status;
+}
+
+
+typedef struct LoadS {
+  const char *s;
+  size_t size;
+} LoadS;
+
+
+static const char *getS (lua_State *L, void *ud, size_t *size) {
+  LoadS *ls = (LoadS *)ud;
+  (void)L;  /* not used */
+  if (ls->size == 0) return NULL;
+  *size = ls->size;
+  ls->size = 0;
+  return ls->s;
+}
+
+
+LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size,
+                                 const char *name, const char *mode) {
+  LoadS ls;
+  ls.s = buff;
+  ls.size = size;
+  return lua_load(L, getS, &ls, name, mode);
+}
+
+
+LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
+  return luaL_loadbuffer(L, s, strlen(s), s);
+}
+
+/* }====================================================== */
+
+
+
+LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
+  if (!lua_getmetatable(L, obj))  /* no metatable? */
+    return 0;
+  lua_pushstring(L, event);
+  lua_rawget(L, -2);
+  if (lua_isnil(L, -1)) {
+    lua_pop(L, 2);  /* remove metatable and metafield */
+    return 0;
+  }
+  else {
+    lua_remove(L, -2);  /* remove only metatable */
+    return 1;
+  }
+}
+
+
+LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
+  obj = lua_absindex(L, obj);
+  if (!luaL_getmetafield(L, obj, event))  /* no metafield? */
+    return 0;
+  lua_pushvalue(L, obj);
+  lua_call(L, 1, 1);
+  return 1;
+}
+
+
+LUALIB_API int luaL_len (lua_State *L, int idx) {
+  int l;
+  int isnum;
+  lua_len(L, idx);
+  l = (int)lua_tointegerx(L, -1, &isnum);
+  if (!isnum)
+    luaL_error(L, "object length is not a number");
+  lua_pop(L, 1);  /* remove object */
+  return l;
+}
+
+
+LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
+  if (!luaL_callmeta(L, idx, "__tostring")) {  /* no metafield? */
+    switch (lua_type(L, idx)) {
+      case LUA_TNUMBER:
+      case LUA_TSTRING:
+        lua_pushvalue(L, idx);
+        break;
+      case LUA_TBOOLEAN:
+        lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false"));
+        break;
+      case LUA_TNIL:
+        lua_pushliteral(L, "nil");
+        break;
+      default:
+        lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
+                                            lua_topointer(L, idx));
+        break;
+    }
+  }
+  return lua_tolstring(L, -1, len);
+}
+
+
+/*
+** {======================================================
+** Compatibility with 5.1 module functions
+** =======================================================
+*/
+#if defined(LUA_COMPAT_MODULE)
+
+static const char *luaL_findtable (lua_State *L, int idx,
+                                   const char *fname, int szhint) {
+  const char *e;
+  if (idx) lua_pushvalue(L, idx);
+  do {
+    e = strchr(fname, '.');
+    if (e == NULL) e = fname + strlen(fname);
+    lua_pushlstring(L, fname, e - fname);
+    lua_rawget(L, -2);
+    if (lua_isnil(L, -1)) {  /* no such field? */
+      lua_pop(L, 1);  /* remove this nil */
+      lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
+      lua_pushlstring(L, fname, e - fname);
+      lua_pushvalue(L, -2);
+      lua_settable(L, -4);  /* set new table into field */
+    }
+    else if (!lua_istable(L, -1)) {  /* field has a non-table value? */
+      lua_pop(L, 2);  /* remove table and value */
+      return fname;  /* return problematic part of the name */
+    }
+    lua_remove(L, -2);  /* remove previous table */
+    fname = e + 1;
+  } while (*e == '.');
+  return NULL;
+}
+
+
+/*
+** Count number of elements in a luaL_Reg list.
+*/
+static int libsize (const luaL_Reg *l) {
+  int size = 0;
+  for (; l && l->name; l++) size++;
+  return size;
+}
+
+
+/*
+** Find or create a module table with a given name. The function
+** first looks at the _LOADED table and, if that fails, try a
+** global variable with that name. In any case, leaves on the stack
+** the module table.
+*/
+LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
+                                 int sizehint) {
+  luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);  /* get _LOADED table */
+  lua_getfield(L, -1, modname);  /* get _LOADED[modname] */
+  if (!lua_istable(L, -1)) {  /* not found? */
+    lua_pop(L, 1);  /* remove previous result */
+    /* try global variable (and create one if it does not exist) */
+    lua_pushglobaltable(L);
+    if (luaL_findtable(L, 0, modname, sizehint) != NULL)
+      luaL_error(L, "name conflict for module " LUA_QS, modname);
+    lua_pushvalue(L, -1);
+    lua_setfield(L, -3, modname);  /* _LOADED[modname] = new table */
+  }
+  lua_remove(L, -2);  /* remove _LOADED table */
+}
+
+
+LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
+                               const luaL_Reg *l, int nup) {
+  luaL_checkversion(L);
+  if (libname) {
+    luaL_pushmodule(L, libname, libsize(l));  /* get/create library table */
+    lua_insert(L, -(nup + 1));  /* move library table to below upvalues */
+  }
+  if (l)
+    luaL_setfuncs(L, l, nup);
+  else
+    lua_pop(L, nup);  /* remove upvalues */
+}
+
+#endif
+/* }====================================================== */
+
+/*
+** set functions from list 'l' into table at top - 'nup'; each
+** function gets the 'nup' elements at the top as upvalues.
+** Returns with only the table at the stack.
+*/
+LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
+  luaL_checkversion(L);
+  luaL_checkstack(L, nup, "too many upvalues");
+  for (; l->name != NULL; l++) {  /* fill the table with given functions */
+    int i;
+    for (i = 0; i < nup; i++)  /* copy upvalues to the top */
+      lua_pushvalue(L, -nup);
+    lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
+    lua_setfield(L, -(nup + 2), l->name);
+  }
+  lua_pop(L, nup);  /* remove upvalues */
+}
+
+
+/*
+** ensure that stack[idx][fname] has a table and push that table
+** into the stack
+*/
+LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
+  lua_getfield(L, idx, fname);
+  if (lua_istable(L, -1)) return 1;  /* table already there */
+  else {
+    lua_pop(L, 1);  /* remove previous result */
+    idx = lua_absindex(L, idx);
+    lua_newtable(L);
+    lua_pushvalue(L, -1);  /* copy to be left at top */
+    lua_setfield(L, idx, fname);  /* assign new table to field */
+    return 0;  /* false, because did not find table there */
+  }
+}
+
+
+/*
+** stripped-down 'require'. Calls 'openf' to open a module,
+** registers the result in 'package.loaded' table and, if 'glb'
+** is true, also registers the result in the global table.
+** Leaves resulting module on the top.
+*/
+LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
+                               lua_CFunction openf, int glb) {
+  lua_pushcfunction(L, openf);
+  lua_pushstring(L, modname);  /* argument to open function */
+  lua_call(L, 1, 1);  /* open module */
+  luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
+  lua_pushvalue(L, -2);  /* make copy of module (call result) */
+  lua_setfield(L, -2, modname);  /* _LOADED[modname] = module */
+  lua_pop(L, 1);  /* remove _LOADED table */
+  if (glb) {
+    lua_pushvalue(L, -1);  /* copy of 'mod' */
+    lua_setglobal(L, modname);  /* _G[modname] = module */
+  }
+}
+
+
+LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
+                                                               const char *r) {
+  const char *wild;
+  size_t l = strlen(p);
+  luaL_Buffer b;
+  luaL_buffinit(L, &b);
+  while ((wild = strstr(s, p)) != NULL) {
+    luaL_addlstring(&b, s, wild - s);  /* push prefix */
+    luaL_addstring(&b, r);  /* push replacement in place of pattern */
+    s = wild + l;  /* continue after `p' */
+  }
+  luaL_addstring(&b, s);  /* push last suffix */
+  luaL_pushresult(&b);
+  return lua_tostring(L, -1);
+}
+
+
+static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
+  (void)ud; (void)osize;  /* not used */
+  if (nsize == 0) {
+    free(ptr);
+    return NULL;
+  }
+  else
+    return realloc(ptr, nsize);
+}
+
+
+static int panic (lua_State *L) {
+  luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
+                   lua_tostring(L, -1));
+  return 0;  /* return to Lua to abort */
+}
+
+
+LUALIB_API lua_State *luaL_newstate (void) {
+  lua_State *L = lua_newstate(l_alloc, NULL);
+  if (L) lua_atpanic(L, &panic);
+  return L;
+}
+
+
+LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) {
+  const lua_Number *v = lua_version(L);
+  if (v != lua_version(NULL))
+    luaL_error(L, "multiple Lua VMs detected");
+  else if (*v != ver)
+    luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
+                  ver, *v);
+  /* check conversions number -> integer types */
+  lua_pushnumber(L, -(lua_Number)0x1234);
+  if (lua_tointeger(L, -1) != -0x1234 ||
+      lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234)
+    luaL_error(L, "bad conversion number->int;"
+                  " must recompile Lua with proper settings");
+  lua_pop(L, 1);
+}
+

=== added file 'src/scripting/eris/lauxlib.h'
--- src/scripting/eris/lauxlib.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lauxlib.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,212 @@
+/*
+** $Id: lauxlib.h,v 1.120 2011/11/29 15:55:08 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lauxlib_h
+#define lauxlib_h
+
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "lua.h"
+
+
+
+/* extra error code for `luaL_load' */
+#define LUA_ERRFILE     (LUA_ERRERR+1)
+
+
+typedef struct luaL_Reg {
+  const char *name;
+  lua_CFunction func;
+} luaL_Reg;
+
+
+LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver);
+#define luaL_checkversion(L)	luaL_checkversion_(L, LUA_VERSION_NUM)
+
+LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
+LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
+LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
+LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
+LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
+                                                          size_t *l);
+LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
+                                          const char *def, size_t *l);
+LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
+LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
+
+LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
+LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
+                                          lua_Integer def);
+LUALIB_API lua_Unsigned (luaL_checkunsigned) (lua_State *L, int numArg);
+LUALIB_API lua_Unsigned (luaL_optunsigned) (lua_State *L, int numArg,
+                                            lua_Unsigned def);
+
+LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
+LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
+LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
+
+LUALIB_API int   (luaL_newmetatable) (lua_State *L, const char *tname);
+LUALIB_API void  (luaL_setmetatable) (lua_State *L, const char *tname);
+LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
+LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
+
+LUALIB_API void (luaL_where) (lua_State *L, int lvl);
+LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
+
+LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
+                                   const char *const lst[]);
+
+LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
+LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
+
+/* pre-defined references */
+#define LUA_NOREF       (-2)
+#define LUA_REFNIL      (-1)
+
+LUALIB_API int (luaL_ref) (lua_State *L, int t);
+LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
+
+LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
+                                               const char *mode);
+
+#define luaL_loadfile(L,f)	luaL_loadfilex(L,f,NULL)
+
+LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
+                                   const char *name, const char *mode);
+LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
+
+LUALIB_API lua_State *(luaL_newstate) (void);
+
+LUALIB_API int (luaL_len) (lua_State *L, int idx);
+
+LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
+                                                  const char *r);
+
+LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
+
+LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
+
+LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
+                                  const char *msg, int level);
+
+LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
+                                 lua_CFunction openf, int glb);
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+
+#define luaL_newlibtable(L,l)	\
+  lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
+
+#define luaL_newlib(L,l)	(luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
+
+#define luaL_argcheck(L, cond,numarg,extramsg)	\
+		((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
+#define luaL_checkstring(L,n)	(luaL_checklstring(L, (n), NULL))
+#define luaL_optstring(L,n,d)	(luaL_optlstring(L, (n), (d), NULL))
+#define luaL_checkint(L,n)	((int)luaL_checkinteger(L, (n)))
+#define luaL_optint(L,n,d)	((int)luaL_optinteger(L, (n), (d)))
+#define luaL_checklong(L,n)	((long)luaL_checkinteger(L, (n)))
+#define luaL_optlong(L,n,d)	((long)luaL_optinteger(L, (n), (d)))
+
+#define luaL_typename(L,i)	lua_typename(L, lua_type(L,(i)))
+
+#define luaL_dofile(L, fn) \
+	(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_dostring(L, s) \
+	(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_getmetatable(L,n)	(lua_getfield(L, LUA_REGISTRYINDEX, (n)))
+
+#define luaL_opt(L,f,n,d)	(lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
+
+#define luaL_loadbuffer(L,s,sz,n)	luaL_loadbufferx(L,s,sz,n,NULL)
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+typedef struct luaL_Buffer {
+  char *b;  /* buffer address */
+  size_t size;  /* buffer size */
+  size_t n;  /* number of characters in buffer */
+  lua_State *L;
+  char initb[LUAL_BUFFERSIZE];  /* initial buffer */
+} luaL_Buffer;
+
+
+#define luaL_addchar(B,c) \
+  ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
+   ((B)->b[(B)->n++] = (c)))
+
+#define luaL_addsize(B,s)	((B)->n += (s))
+
+LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
+LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
+LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
+LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
+
+#define luaL_prepbuffer(B)	luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** File handles for IO library
+** =======================================================
+*/
+
+/*
+** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
+** initial structure 'luaL_Stream' (it may contain other fields
+** after that initial structure).
+*/
+
+#define LUA_FILEHANDLE          "FILE*"
+
+
+typedef struct luaL_Stream {
+  FILE *f;  /* stream (NULL for incompletely created streams) */
+  lua_CFunction closef;  /* to close stream (NULL for closed streams) */
+} luaL_Stream;
+
+/* }====================================================== */
+
+
+
+/* compatibility with old module system */
+#if defined(LUA_COMPAT_MODULE)
+
+LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
+                                   int sizehint);
+LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
+                                const luaL_Reg *l, int nup);
+
+#define luaL_register(L,n,l)	(luaL_openlib(L,(n),(l),0))
+
+#endif
+
+
+#endif
+
+

=== added file 'src/scripting/eris/lbaselib.c'
--- src/scripting/eris/lbaselib.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lbaselib.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,494 @@
+/*
+** $Id: lbaselib.c,v 1.276 2013/02/21 13:44:53 roberto Exp $
+** Basic library
+** See Copyright Notice in lua.h
+*/
+
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define lbaselib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+static int luaB_print (lua_State *L) {
+  int n = lua_gettop(L);  /* number of arguments */
+  int i;
+  lua_getglobal(L, "tostring");
+  for (i=1; i<=n; i++) {
+    const char *s;
+    size_t l;
+    lua_pushvalue(L, -1);  /* function to be called */
+    lua_pushvalue(L, i);   /* value to print */
+    lua_call(L, 1, 1);
+    s = lua_tolstring(L, -1, &l);  /* get result */
+    if (s == NULL)
+      return luaL_error(L,
+         LUA_QL("tostring") " must return a string to " LUA_QL("print"));
+    if (i>1) luai_writestring("\t", 1);
+    luai_writestring(s, l);
+    lua_pop(L, 1);  /* pop result */
+  }
+  luai_writeline();
+  return 0;
+}
+
+
+#define SPACECHARS	" \f\n\r\t\v"
+
+static int luaB_tonumber (lua_State *L) {
+  if (lua_isnoneornil(L, 2)) {  /* standard conversion */
+    int isnum;
+    lua_Number n = lua_tonumberx(L, 1, &isnum);
+    if (isnum) {
+      lua_pushnumber(L, n);
+      return 1;
+    }  /* else not a number; must be something */
+    luaL_checkany(L, 1);
+  }
+  else {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    const char *e = s + l;  /* end point for 's' */
+    int base = luaL_checkint(L, 2);
+    int neg = 0;
+    luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
+    s += strspn(s, SPACECHARS);  /* skip initial spaces */
+    if (*s == '-') { s++; neg = 1; }  /* handle signal */
+    else if (*s == '+') s++;
+    if (isalnum((unsigned char)*s)) {
+      lua_Number n = 0;
+      do {
+        int digit = (isdigit((unsigned char)*s)) ? *s - '0'
+                       : toupper((unsigned char)*s) - 'A' + 10;
+        if (digit >= base) break;  /* invalid numeral; force a fail */
+        n = n * (lua_Number)base + (lua_Number)digit;
+        s++;
+      } while (isalnum((unsigned char)*s));
+      s += strspn(s, SPACECHARS);  /* skip trailing spaces */
+      if (s == e) {  /* no invalid trailing characters? */
+        lua_pushnumber(L, (neg) ? -n : n);
+        return 1;
+      }  /* else not a number */
+    }  /* else not a number */
+  }
+  lua_pushnil(L);  /* not a number */
+  return 1;
+}
+
+
+static int luaB_error (lua_State *L) {
+  int level = luaL_optint(L, 2, 1);
+  lua_settop(L, 1);
+  if (lua_isstring(L, 1) && level > 0) {  /* add extra information? */
+    luaL_where(L, level);
+    lua_pushvalue(L, 1);
+    lua_concat(L, 2);
+  }
+  return lua_error(L);
+}
+
+
+static int luaB_getmetatable (lua_State *L) {
+  luaL_checkany(L, 1);
+  if (!lua_getmetatable(L, 1)) {
+    lua_pushnil(L);
+    return 1;  /* no metatable */
+  }
+  luaL_getmetafield(L, 1, "__metatable");
+  return 1;  /* returns either __metatable field (if present) or metatable */
+}
+
+
+static int luaB_setmetatable (lua_State *L) {
+  int t = lua_type(L, 2);
+  luaL_checktype(L, 1, LUA_TTABLE);
+  luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
+                    "nil or table expected");
+  if (luaL_getmetafield(L, 1, "__metatable"))
+    return luaL_error(L, "cannot change a protected metatable");
+  lua_settop(L, 2);
+  lua_setmetatable(L, 1);
+  return 1;
+}
+
+
+static int luaB_rawequal (lua_State *L) {
+  luaL_checkany(L, 1);
+  luaL_checkany(L, 2);
+  lua_pushboolean(L, lua_rawequal(L, 1, 2));
+  return 1;
+}
+
+
+static int luaB_rawlen (lua_State *L) {
+  int t = lua_type(L, 1);
+  luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
+                   "table or string expected");
+  lua_pushinteger(L, lua_rawlen(L, 1));
+  return 1;
+}
+
+
+static int luaB_rawget (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  luaL_checkany(L, 2);
+  lua_settop(L, 2);
+  lua_rawget(L, 1);
+  return 1;
+}
+
+static int luaB_rawset (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  luaL_checkany(L, 2);
+  luaL_checkany(L, 3);
+  lua_settop(L, 3);
+  lua_rawset(L, 1);
+  return 1;
+}
+
+
+static int luaB_collectgarbage (lua_State *L) {
+  static const char *const opts[] = {"stop", "restart", "collect",
+    "count", "step", "setpause", "setstepmul",
+    "setmajorinc", "isrunning", "generational", "incremental", NULL};
+  static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
+    LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
+    LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
+  int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
+  int ex = luaL_optint(L, 2, 0);
+  int res = lua_gc(L, o, ex);
+  switch (o) {
+    case LUA_GCCOUNT: {
+      int b = lua_gc(L, LUA_GCCOUNTB, 0);
+      lua_pushnumber(L, res + ((lua_Number)b/1024));
+      lua_pushinteger(L, b);
+      return 2;
+    }
+    case LUA_GCSTEP: case LUA_GCISRUNNING: {
+      lua_pushboolean(L, res);
+      return 1;
+    }
+    default: {
+      lua_pushinteger(L, res);
+      return 1;
+    }
+  }
+}
+
+
+static int luaB_type (lua_State *L) {
+  luaL_checkany(L, 1);
+  lua_pushstring(L, luaL_typename(L, 1));
+  return 1;
+}
+
+
+static int pairsmeta (lua_State *L, const char *method, int iszero,
+                      lua_CFunction iter) {
+  if (!luaL_getmetafield(L, 1, method)) {  /* no metamethod? */
+    luaL_checktype(L, 1, LUA_TTABLE);  /* argument must be a table */
+    lua_pushcfunction(L, iter);  /* will return generator, */
+    lua_pushvalue(L, 1);  /* state, */
+    if (iszero) lua_pushinteger(L, 0);  /* and initial value */
+    else lua_pushnil(L);
+  }
+  else {
+    lua_pushvalue(L, 1);  /* argument 'self' to metamethod */
+    lua_call(L, 1, 3);  /* get 3 values from metamethod */
+  }
+  return 3;
+}
+
+
+static int luaB_next (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  lua_settop(L, 2);  /* create a 2nd argument if there isn't one */
+  if (lua_next(L, 1))
+    return 2;
+  else {
+    lua_pushnil(L);
+    return 1;
+  }
+}
+
+
+static int luaB_pairs (lua_State *L) {
+  return pairsmeta(L, "__pairs", 0, luaB_next);
+}
+
+
+static int ipairsaux (lua_State *L) {
+  int i = luaL_checkint(L, 2);
+  luaL_checktype(L, 1, LUA_TTABLE);
+  i++;  /* next value */
+  lua_pushinteger(L, i);
+  lua_rawgeti(L, 1, i);
+  return (lua_isnil(L, -1)) ? 1 : 2;
+}
+
+
+static int luaB_ipairs (lua_State *L) {
+  return pairsmeta(L, "__ipairs", 1, ipairsaux);
+}
+
+
+static int load_aux (lua_State *L, int status, int envidx) {
+  if (status == LUA_OK) {
+    if (envidx != 0) {  /* 'env' parameter? */
+      lua_pushvalue(L, envidx);  /* environment for loaded function */
+      if (!lua_setupvalue(L, -2, 1))  /* set it as 1st upvalue */
+        lua_pop(L, 1);  /* remove 'env' if not used by previous call */
+    }
+    return 1;
+  }
+  else {  /* error (message is on top of the stack) */
+    lua_pushnil(L);
+    lua_insert(L, -2);  /* put before error message */
+    return 2;  /* return nil plus error message */
+  }
+}
+
+
+static int luaB_loadfile (lua_State *L) {
+  const char *fname = luaL_optstring(L, 1, NULL);
+  const char *mode = luaL_optstring(L, 2, NULL);
+  int env = (!lua_isnone(L, 3) ? 3 : 0);  /* 'env' index or 0 if no 'env' */
+  int status = luaL_loadfilex(L, fname, mode);
+  return load_aux(L, status, env);
+}
+
+
+/*
+** {======================================================
+** Generic Read function
+** =======================================================
+*/
+
+
+/*
+** reserved slot, above all arguments, to hold a copy of the returned
+** string to avoid it being collected while parsed. 'load' has four
+** optional arguments (chunk, source name, mode, and environment).
+*/
+#define RESERVEDSLOT	5
+
+
+/*
+** Reader for generic `load' function: `lua_load' uses the
+** stack for internal stuff, so the reader cannot change the
+** stack top. Instead, it keeps its resulting string in a
+** reserved slot inside the stack.
+*/
+static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
+  (void)(ud);  /* not used */
+  luaL_checkstack(L, 2, "too many nested functions");
+  lua_pushvalue(L, 1);  /* get function */
+  lua_call(L, 0, 1);  /* call it */
+  if (lua_isnil(L, -1)) {
+    lua_pop(L, 1);  /* pop result */
+    *size = 0;
+    return NULL;
+  }
+  else if (!lua_isstring(L, -1))
+    luaL_error(L, "reader function must return a string");
+  lua_replace(L, RESERVEDSLOT);  /* save string in reserved slot */
+  return lua_tolstring(L, RESERVEDSLOT, size);
+}
+
+
+static int luaB_load (lua_State *L) {
+  int status;
+  size_t l;
+  const char *s = lua_tolstring(L, 1, &l);
+  const char *mode = luaL_optstring(L, 3, "bt");
+  int env = (!lua_isnone(L, 4) ? 4 : 0);  /* 'env' index or 0 if no 'env' */
+  if (s != NULL) {  /* loading a string? */
+    const char *chunkname = luaL_optstring(L, 2, s);
+    status = luaL_loadbufferx(L, s, l, chunkname, mode);
+  }
+  else {  /* loading from a reader function */
+    const char *chunkname = luaL_optstring(L, 2, "=(load)");
+    luaL_checktype(L, 1, LUA_TFUNCTION);
+    lua_settop(L, RESERVEDSLOT);  /* create reserved slot */
+    status = lua_load(L, generic_reader, NULL, chunkname, mode);
+  }
+  return load_aux(L, status, env);
+}
+
+/* }====================================================== */
+
+
+static int dofilecont (lua_State *L) {
+  return lua_gettop(L) - 1;
+}
+
+
+static int luaB_dofile (lua_State *L) {
+  const char *fname = luaL_optstring(L, 1, NULL);
+  lua_settop(L, 1);
+  if (luaL_loadfile(L, fname) != LUA_OK)
+    return lua_error(L);
+  lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
+  return dofilecont(L);
+}
+
+
+static int luaB_assert (lua_State *L) {
+  if (!lua_toboolean(L, 1))
+    return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
+  return lua_gettop(L);
+}
+
+
+static int luaB_select (lua_State *L) {
+  int n = lua_gettop(L);
+  if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
+    lua_pushinteger(L, n-1);
+    return 1;
+  }
+  else {
+    int i = luaL_checkint(L, 1);
+    if (i < 0) i = n + i;
+    else if (i > n) i = n;
+    luaL_argcheck(L, 1 <= i, 1, "index out of range");
+    return n - i;
+  }
+}
+
+
+static int finishpcall (lua_State *L, int status) {
+  if (!lua_checkstack(L, 1)) {  /* no space for extra boolean? */
+    lua_settop(L, 0);  /* create space for return values */
+    lua_pushboolean(L, 0);
+    lua_pushstring(L, "stack overflow");
+    return 2;  /* return false, msg */
+  }
+  lua_pushboolean(L, status);  /* first result (status) */
+  lua_replace(L, 1);  /* put first result in first slot */
+  return lua_gettop(L);
+}
+
+
+static int pcallcont (lua_State *L) {
+  int status = lua_getctx(L, NULL);
+  return finishpcall(L, (status == LUA_YIELD));
+}
+
+
+static int luaB_pcall (lua_State *L) {
+  int status;
+  luaL_checkany(L, 1);
+  lua_pushnil(L);
+  lua_insert(L, 1);  /* create space for status result */
+  status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont);
+  return finishpcall(L, (status == LUA_OK));
+}
+
+
+static int luaB_xpcall (lua_State *L) {
+  int status;
+  int n = lua_gettop(L);
+  luaL_argcheck(L, n >= 2, 2, "value expected");
+  lua_pushvalue(L, 1);  /* exchange function... */
+  lua_copy(L, 2, 1);  /* ...and error handler */
+  lua_replace(L, 2);
+  status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont);
+  return finishpcall(L, (status == LUA_OK));
+}
+
+
+static int luaB_tostring (lua_State *L) {
+  luaL_checkany(L, 1);
+  luaL_tolstring(L, 1, NULL);
+  return 1;
+}
+
+
+static const luaL_Reg base_funcs[] = {
+  {"assert", luaB_assert},
+  {"collectgarbage", luaB_collectgarbage},
+  {"dofile", luaB_dofile},
+  {"error", luaB_error},
+  {"getmetatable", luaB_getmetatable},
+  {"ipairs", luaB_ipairs},
+  {"loadfile", luaB_loadfile},
+  {"load", luaB_load},
+#if defined(LUA_COMPAT_LOADSTRING)
+  {"loadstring", luaB_load},
+#endif
+  {"next", luaB_next},
+  {"pairs", luaB_pairs},
+  {"pcall", luaB_pcall},
+  {"print", luaB_print},
+  {"rawequal", luaB_rawequal},
+  {"rawlen", luaB_rawlen},
+  {"rawget", luaB_rawget},
+  {"rawset", luaB_rawset},
+  {"select", luaB_select},
+  {"setmetatable", luaB_setmetatable},
+  {"tonumber", luaB_tonumber},
+  {"tostring", luaB_tostring},
+  {"type", luaB_type},
+  {"xpcall", luaB_xpcall},
+  {NULL, NULL}
+};
+
+
+LUAMOD_API int luaopen_base (lua_State *L) {
+  /* set global _G */
+  lua_pushglobaltable(L);
+  lua_pushglobaltable(L);
+  lua_setfield(L, -2, "_G");
+  /* open lib into global table */
+  luaL_setfuncs(L, base_funcs, 0);
+  lua_pushliteral(L, LUA_VERSION);
+  lua_setfield(L, -2, "_VERSION");  /* set global _VERSION */
+  return 1;
+}
+
+
+void eris_permbaselib(lua_State *L, int forUnpersist) {
+  luaL_checktype(L, -1, LUA_TTABLE);
+  luaL_checkstack(L, 2, NULL);
+
+  if (forUnpersist) {
+    lua_pushstring(L, "__eris.baselib_pcallcont");
+    lua_pushcfunction(L, pcallcont);
+  }
+  else {
+    lua_pushcfunction(L, pcallcont);
+    lua_pushstring(L, "__eris.baselib_pcallcont");
+  }
+  lua_rawset(L, -3);
+
+  if (forUnpersist) {
+    lua_pushstring(L, "__eris.baselib_luaB_next");
+    lua_pushcfunction(L, luaB_next);
+  }
+  else {
+    lua_pushcfunction(L, luaB_next);
+    lua_pushstring(L, "__eris.baselib_luaB_next");
+  }
+  lua_rawset(L, -3);
+
+  if (forUnpersist) {
+    lua_pushstring(L, "__eris.baselib_ipairsaux");
+    lua_pushcfunction(L, ipairsaux);
+  }
+  else {
+    lua_pushcfunction(L, ipairsaux);
+    lua_pushstring(L, "__eris.baselib_ipairsaux");
+  }
+  lua_rawset(L, -3);
+}
+

=== added file 'src/scripting/eris/lbitlib.c'
--- src/scripting/eris/lbitlib.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lbitlib.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,211 @@
+/*
+** $Id: lbitlib.c,v 1.18 2013/03/19 13:19:12 roberto Exp $
+** Standard library for bitwise operations
+** See Copyright Notice in lua.h
+*/
+
+#define lbitlib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/* number of bits to consider in a number */
+#if !defined(LUA_NBITS)
+#define LUA_NBITS	32
+#endif
+
+
+#define ALLONES		(~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))
+
+/* macro to trim extra bits */
+#define trim(x)		((x) & ALLONES)
+
+
+/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */
+#define mask(n)		(~((ALLONES << 1) << ((n) - 1)))
+
+
+typedef lua_Unsigned b_uint;
+
+
+
+static b_uint andaux (lua_State *L) {
+  int i, n = lua_gettop(L);
+  b_uint r = ~(b_uint)0;
+  for (i = 1; i <= n; i++)
+    r &= luaL_checkunsigned(L, i);
+  return trim(r);
+}
+
+
+static int b_and (lua_State *L) {
+  b_uint r = andaux(L);
+  lua_pushunsigned(L, r);
+  return 1;
+}
+
+
+static int b_test (lua_State *L) {
+  b_uint r = andaux(L);
+  lua_pushboolean(L, r != 0);
+  return 1;
+}
+
+
+static int b_or (lua_State *L) {
+  int i, n = lua_gettop(L);
+  b_uint r = 0;
+  for (i = 1; i <= n; i++)
+    r |= luaL_checkunsigned(L, i);
+  lua_pushunsigned(L, trim(r));
+  return 1;
+}
+
+
+static int b_xor (lua_State *L) {
+  int i, n = lua_gettop(L);
+  b_uint r = 0;
+  for (i = 1; i <= n; i++)
+    r ^= luaL_checkunsigned(L, i);
+  lua_pushunsigned(L, trim(r));
+  return 1;
+}
+
+
+static int b_not (lua_State *L) {
+  b_uint r = ~luaL_checkunsigned(L, 1);
+  lua_pushunsigned(L, trim(r));
+  return 1;
+}
+
+
+static int b_shift (lua_State *L, b_uint r, int i) {
+  if (i < 0) {  /* shift right? */
+    i = -i;
+    r = trim(r);
+    if (i >= LUA_NBITS) r = 0;
+    else r >>= i;
+  }
+  else {  /* shift left */
+    if (i >= LUA_NBITS) r = 0;
+    else r <<= i;
+    r = trim(r);
+  }
+  lua_pushunsigned(L, r);
+  return 1;
+}
+
+
+static int b_lshift (lua_State *L) {
+  return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2));
+}
+
+
+static int b_rshift (lua_State *L) {
+  return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2));
+}
+
+
+static int b_arshift (lua_State *L) {
+  b_uint r = luaL_checkunsigned(L, 1);
+  int i = luaL_checkint(L, 2);
+  if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1))))
+    return b_shift(L, r, -i);
+  else {  /* arithmetic shift for 'negative' number */
+    if (i >= LUA_NBITS) r = ALLONES;
+    else
+      r = trim((r >> i) | ~(~(b_uint)0 >> i));  /* add signal bit */
+    lua_pushunsigned(L, r);
+    return 1;
+  }
+}
+
+
+static int b_rot (lua_State *L, int i) {
+  b_uint r = luaL_checkunsigned(L, 1);
+  i &= (LUA_NBITS - 1);  /* i = i % NBITS */
+  r = trim(r);
+  r = (r << i) | (r >> (LUA_NBITS - i));
+  lua_pushunsigned(L, trim(r));
+  return 1;
+}
+
+
+static int b_lrot (lua_State *L) {
+  return b_rot(L, luaL_checkint(L, 2));
+}
+
+
+static int b_rrot (lua_State *L) {
+  return b_rot(L, -luaL_checkint(L, 2));
+}
+
+
+/*
+** get field and width arguments for field-manipulation functions,
+** checking whether they are valid.
+** ('luaL_error' called without 'return' to avoid later warnings about
+** 'width' being used uninitialized.)
+*/
+static int fieldargs (lua_State *L, int farg, int *width) {
+  int f = luaL_checkint(L, farg);
+  int w = luaL_optint(L, farg + 1, 1);
+  luaL_argcheck(L, 0 <= f, farg, "field cannot be negative");
+  luaL_argcheck(L, 0 < w, farg + 1, "width must be positive");
+  if (f + w > LUA_NBITS)
+    luaL_error(L, "trying to access non-existent bits");
+  *width = w;
+  return f;
+}
+
+
+static int b_extract (lua_State *L) {
+  int w;
+  b_uint r = luaL_checkunsigned(L, 1);
+  int f = fieldargs(L, 2, &w);
+  r = (r >> f) & mask(w);
+  lua_pushunsigned(L, r);
+  return 1;
+}
+
+
+static int b_replace (lua_State *L) {
+  int w;
+  b_uint r = luaL_checkunsigned(L, 1);
+  b_uint v = luaL_checkunsigned(L, 2);
+  int f = fieldargs(L, 3, &w);
+  int m = mask(w);
+  v &= m;  /* erase bits outside given width */
+  r = (r & ~(m << f)) | (v << f);
+  lua_pushunsigned(L, r);
+  return 1;
+}
+
+
+static const luaL_Reg bitlib[] = {
+  {"arshift", b_arshift},
+  {"band", b_and},
+  {"bnot", b_not},
+  {"bor", b_or},
+  {"bxor", b_xor},
+  {"btest", b_test},
+  {"extract", b_extract},
+  {"lrotate", b_lrot},
+  {"lshift", b_lshift},
+  {"replace", b_replace},
+  {"rrotate", b_rrot},
+  {"rshift", b_rshift},
+  {NULL, NULL}
+};
+
+
+
+LUAMOD_API int luaopen_bit32 (lua_State *L) {
+  luaL_newlib(L, bitlib);
+  return 1;
+}
+

=== added file 'src/scripting/eris/lcode.c'
--- src/scripting/eris/lcode.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lcode.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,881 @@
+/*
+** $Id: lcode.c,v 2.62 2012/08/16 17:34:28 roberto Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+
+#define lcode_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "lvm.h"
+
+
+#define hasjumps(e)	((e)->t != (e)->f)
+
+
+static int isnumeral(expdesc *e) {
+  return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
+}
+
+
+void luaK_nil (FuncState *fs, int from, int n) {
+  Instruction *previous;
+  int l = from + n - 1;  /* last register to set nil */
+  if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
+    previous = &fs->f->code[fs->pc-1];
+    if (GET_OPCODE(*previous) == OP_LOADNIL) {
+      int pfrom = GETARG_A(*previous);
+      int pl = pfrom + GETARG_B(*previous);
+      if ((pfrom <= from && from <= pl + 1) ||
+          (from <= pfrom && pfrom <= l + 1)) {  /* can connect both? */
+        if (pfrom < from) from = pfrom;  /* from = min(from, pfrom) */
+        if (pl > l) l = pl;  /* l = max(l, pl) */
+        SETARG_A(*previous, from);
+        SETARG_B(*previous, l - from);
+        return;
+      }
+    }  /* else go through */
+  }
+  luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0);  /* else no optimization */
+}
+
+
+int luaK_jump (FuncState *fs) {
+  int jpc = fs->jpc;  /* save list of jumps to here */
+  int j;
+  fs->jpc = NO_JUMP;
+  j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
+  luaK_concat(fs, &j, jpc);  /* keep them on hold */
+  return j;
+}
+
+
+void luaK_ret (FuncState *fs, int first, int nret) {
+  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
+}
+
+
+static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
+  luaK_codeABC(fs, op, A, B, C);
+  return luaK_jump(fs);
+}
+
+
+static void fixjump (FuncState *fs, int pc, int dest) {
+  Instruction *jmp = &fs->f->code[pc];
+  int offset = dest-(pc+1);
+  lua_assert(dest != NO_JUMP);
+  if (abs(offset) > MAXARG_sBx)
+    luaX_syntaxerror(fs->ls, "control structure too long");
+  SETARG_sBx(*jmp, offset);
+}
+
+
+/*
+** returns current `pc' and marks it as a jump target (to avoid wrong
+** optimizations with consecutive instructions not in the same basic block).
+*/
+int luaK_getlabel (FuncState *fs) {
+  fs->lasttarget = fs->pc;
+  return fs->pc;
+}
+
+
+static int getjump (FuncState *fs, int pc) {
+  int offset = GETARG_sBx(fs->f->code[pc]);
+  if (offset == NO_JUMP)  /* point to itself represents end of list */
+    return NO_JUMP;  /* end of list */
+  else
+    return (pc+1)+offset;  /* turn offset into absolute position */
+}
+
+
+static Instruction *getjumpcontrol (FuncState *fs, int pc) {
+  Instruction *pi = &fs->f->code[pc];
+  if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
+    return pi-1;
+  else
+    return pi;
+}
+
+
+/*
+** check whether list has any jump that do not produce a value
+** (or produce an inverted value)
+*/
+static int need_value (FuncState *fs, int list) {
+  for (; list != NO_JUMP; list = getjump(fs, list)) {
+    Instruction i = *getjumpcontrol(fs, list);
+    if (GET_OPCODE(i) != OP_TESTSET) return 1;
+  }
+  return 0;  /* not found */
+}
+
+
+static int patchtestreg (FuncState *fs, int node, int reg) {
+  Instruction *i = getjumpcontrol(fs, node);
+  if (GET_OPCODE(*i) != OP_TESTSET)
+    return 0;  /* cannot patch other instructions */
+  if (reg != NO_REG && reg != GETARG_B(*i))
+    SETARG_A(*i, reg);
+  else  /* no register to put value or register already has the value */
+    *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
+
+  return 1;
+}
+
+
+static void removevalues (FuncState *fs, int list) {
+  for (; list != NO_JUMP; list = getjump(fs, list))
+      patchtestreg(fs, list, NO_REG);
+}
+
+
+static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
+                          int dtarget) {
+  while (list != NO_JUMP) {
+    int next = getjump(fs, list);
+    if (patchtestreg(fs, list, reg))
+      fixjump(fs, list, vtarget);
+    else
+      fixjump(fs, list, dtarget);  /* jump to default target */
+    list = next;
+  }
+}
+
+
+static void dischargejpc (FuncState *fs) {
+  patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
+  fs->jpc = NO_JUMP;
+}
+
+
+void luaK_patchlist (FuncState *fs, int list, int target) {
+  if (target == fs->pc)
+    luaK_patchtohere(fs, list);
+  else {
+    lua_assert(target < fs->pc);
+    patchlistaux(fs, list, target, NO_REG, target);
+  }
+}
+
+
+LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level) {
+  level++;  /* argument is +1 to reserve 0 as non-op */
+  while (list != NO_JUMP) {
+    int next = getjump(fs, list);
+    lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
+                (GETARG_A(fs->f->code[list]) == 0 ||
+                 GETARG_A(fs->f->code[list]) >= level));
+    SETARG_A(fs->f->code[list], level);
+    list = next;
+  }
+}
+
+
+void luaK_patchtohere (FuncState *fs, int list) {
+  luaK_getlabel(fs);
+  luaK_concat(fs, &fs->jpc, list);
+}
+
+
+void luaK_concat (FuncState *fs, int *l1, int l2) {
+  if (l2 == NO_JUMP) return;
+  else if (*l1 == NO_JUMP)
+    *l1 = l2;
+  else {
+    int list = *l1;
+    int next;
+    while ((next = getjump(fs, list)) != NO_JUMP)  /* find last element */
+      list = next;
+    fixjump(fs, list, l2);
+  }
+}
+
+
+static int luaK_code (FuncState *fs, Instruction i) {
+  Proto *f = fs->f;
+  dischargejpc(fs);  /* `pc' will change */
+  /* put new instruction in code array */
+  luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
+                  MAX_INT, "opcodes");
+  f->code[fs->pc] = i;
+  /* save corresponding line information */
+  luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
+                  MAX_INT, "opcodes");
+  f->lineinfo[fs->pc] = fs->ls->lastline;
+  return fs->pc++;
+}
+
+
+int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
+  lua_assert(getOpMode(o) == iABC);
+  lua_assert(getBMode(o) != OpArgN || b == 0);
+  lua_assert(getCMode(o) != OpArgN || c == 0);
+  lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);
+  return luaK_code(fs, CREATE_ABC(o, a, b, c));
+}
+
+
+int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
+  lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
+  lua_assert(getCMode(o) == OpArgN);
+  lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
+  return luaK_code(fs, CREATE_ABx(o, a, bc));
+}
+
+
+static int codeextraarg (FuncState *fs, int a) {
+  lua_assert(a <= MAXARG_Ax);
+  return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
+}
+
+
+int luaK_codek (FuncState *fs, int reg, int k) {
+  if (k <= MAXARG_Bx)
+    return luaK_codeABx(fs, OP_LOADK, reg, k);
+  else {
+    int p = luaK_codeABx(fs, OP_LOADKX, reg, 0);
+    codeextraarg(fs, k);
+    return p;
+  }
+}
+
+
+void luaK_checkstack (FuncState *fs, int n) {
+  int newstack = fs->freereg + n;
+  if (newstack > fs->f->maxstacksize) {
+    if (newstack >= MAXSTACK)
+      luaX_syntaxerror(fs->ls, "function or expression too complex");
+    fs->f->maxstacksize = cast_byte(newstack);
+  }
+}
+
+
+void luaK_reserveregs (FuncState *fs, int n) {
+  luaK_checkstack(fs, n);
+  fs->freereg += n;
+}
+
+
+static void freereg (FuncState *fs, int reg) {
+  if (!ISK(reg) && reg >= fs->nactvar) {
+    fs->freereg--;
+    lua_assert(reg == fs->freereg);
+  }
+}
+
+
+static void freeexp (FuncState *fs, expdesc *e) {
+  if (e->k == VNONRELOC)
+    freereg(fs, e->u.info);
+}
+
+
+static int addk (FuncState *fs, TValue *key, TValue *v) {
+  lua_State *L = fs->ls->L;
+  TValue *idx = luaH_set(L, fs->h, key);
+  Proto *f = fs->f;
+  int k, oldsize;
+  if (ttisnumber(idx)) {
+    lua_Number n = nvalue(idx);
+    lua_number2int(k, n);
+    if (luaV_rawequalobj(&f->k[k], v))
+      return k;
+    /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0");
+       go through and create a new entry for this value */
+  }
+  /* constant not found; create a new entry */
+  oldsize = f->sizek;
+  k = fs->nk;
+  /* numerical value does not need GC barrier;
+     table has no metatable, so it does not need to invalidate cache */
+  setnvalue(idx, cast_num(k));
+  luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
+  while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
+  setobj(L, &f->k[k], v);
+  fs->nk++;
+  luaC_barrier(L, f, v);
+  return k;
+}
+
+
+int luaK_stringK (FuncState *fs, TString *s) {
+  TValue o;
+  setsvalue(fs->ls->L, &o, s);
+  return addk(fs, &o, &o);
+}
+
+
+int luaK_numberK (FuncState *fs, lua_Number r) {
+  int n;
+  lua_State *L = fs->ls->L;
+  TValue o;
+  setnvalue(&o, r);
+  if (r == 0 || luai_numisnan(NULL, r)) {  /* handle -0 and NaN */
+    /* use raw representation as key to avoid numeric problems */
+    setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r)));
+    n = addk(fs, L->top - 1, &o);
+    L->top--;
+  }
+  else
+    n = addk(fs, &o, &o);  /* regular case */
+  return n;
+}
+
+
+static int boolK (FuncState *fs, int b) {
+  TValue o;
+  setbvalue(&o, b);
+  return addk(fs, &o, &o);
+}
+
+
+static int nilK (FuncState *fs) {
+  TValue k, v;
+  setnilvalue(&v);
+  /* cannot use nil as key; instead use table itself to represent nil */
+  sethvalue(fs->ls->L, &k, fs->h);
+  return addk(fs, &k, &v);
+}
+
+
+void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
+  if (e->k == VCALL) {  /* expression is an open function call? */
+    SETARG_C(getcode(fs, e), nresults+1);
+  }
+  else if (e->k == VVARARG) {
+    SETARG_B(getcode(fs, e), nresults+1);
+    SETARG_A(getcode(fs, e), fs->freereg);
+    luaK_reserveregs(fs, 1);
+  }
+}
+
+
+void luaK_setoneret (FuncState *fs, expdesc *e) {
+  if (e->k == VCALL) {  /* expression is an open function call? */
+    e->k = VNONRELOC;
+    e->u.info = GETARG_A(getcode(fs, e));
+  }
+  else if (e->k == VVARARG) {
+    SETARG_B(getcode(fs, e), 2);
+    e->k = VRELOCABLE;  /* can relocate its simple result */
+  }
+}
+
+
+void luaK_dischargevars (FuncState *fs, expdesc *e) {
+  switch (e->k) {
+    case VLOCAL: {
+      e->k = VNONRELOC;
+      break;
+    }
+    case VUPVAL: {
+      e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
+      e->k = VRELOCABLE;
+      break;
+    }
+    case VINDEXED: {
+      OpCode op = OP_GETTABUP;  /* assume 't' is in an upvalue */
+      freereg(fs, e->u.ind.idx);
+      if (e->u.ind.vt == VLOCAL) {  /* 't' is in a register? */
+        freereg(fs, e->u.ind.t);
+        op = OP_GETTABLE;
+      }
+      e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
+      e->k = VRELOCABLE;
+      break;
+    }
+    case VVARARG:
+    case VCALL: {
+      luaK_setoneret(fs, e);
+      break;
+    }
+    default: break;  /* there is one value available (somewhere) */
+  }
+}
+
+
+static int code_label (FuncState *fs, int A, int b, int jump) {
+  luaK_getlabel(fs);  /* those instructions may be jump targets */
+  return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
+}
+
+
+static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
+  luaK_dischargevars(fs, e);
+  switch (e->k) {
+    case VNIL: {
+      luaK_nil(fs, reg, 1);
+      break;
+    }
+    case VFALSE: case VTRUE: {
+      luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
+      break;
+    }
+    case VK: {
+      luaK_codek(fs, reg, e->u.info);
+      break;
+    }
+    case VKNUM: {
+      luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));
+      break;
+    }
+    case VRELOCABLE: {
+      Instruction *pc = &getcode(fs, e);
+      SETARG_A(*pc, reg);
+      break;
+    }
+    case VNONRELOC: {
+      if (reg != e->u.info)
+        luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
+      break;
+    }
+    default: {
+      lua_assert(e->k == VVOID || e->k == VJMP);
+      return;  /* nothing to do... */
+    }
+  }
+  e->u.info = reg;
+  e->k = VNONRELOC;
+}
+
+
+static void discharge2anyreg (FuncState *fs, expdesc *e) {
+  if (e->k != VNONRELOC) {
+    luaK_reserveregs(fs, 1);
+    discharge2reg(fs, e, fs->freereg-1);
+  }
+}
+
+
+static void exp2reg (FuncState *fs, expdesc *e, int reg) {
+  discharge2reg(fs, e, reg);
+  if (e->k == VJMP)
+    luaK_concat(fs, &e->t, e->u.info);  /* put this jump in `t' list */
+  if (hasjumps(e)) {
+    int final;  /* position after whole expression */
+    int p_f = NO_JUMP;  /* position of an eventual LOAD false */
+    int p_t = NO_JUMP;  /* position of an eventual LOAD true */
+    if (need_value(fs, e->t) || need_value(fs, e->f)) {
+      int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
+      p_f = code_label(fs, reg, 0, 1);
+      p_t = code_label(fs, reg, 1, 0);
+      luaK_patchtohere(fs, fj);
+    }
+    final = luaK_getlabel(fs);
+    patchlistaux(fs, e->f, final, reg, p_f);
+    patchlistaux(fs, e->t, final, reg, p_t);
+  }
+  e->f = e->t = NO_JUMP;
+  e->u.info = reg;
+  e->k = VNONRELOC;
+}
+
+
+void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
+  luaK_dischargevars(fs, e);
+  freeexp(fs, e);
+  luaK_reserveregs(fs, 1);
+  exp2reg(fs, e, fs->freereg - 1);
+}
+
+
+int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
+  luaK_dischargevars(fs, e);
+  if (e->k == VNONRELOC) {
+    if (!hasjumps(e)) return e->u.info;  /* exp is already in a register */
+    if (e->u.info >= fs->nactvar) {  /* reg. is not a local? */
+      exp2reg(fs, e, e->u.info);  /* put value on it */
+      return e->u.info;
+    }
+  }
+  luaK_exp2nextreg(fs, e);  /* default */
+  return e->u.info;
+}
+
+
+void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
+  if (e->k != VUPVAL || hasjumps(e))
+    luaK_exp2anyreg(fs, e);
+}
+
+
+void luaK_exp2val (FuncState *fs, expdesc *e) {
+  if (hasjumps(e))
+    luaK_exp2anyreg(fs, e);
+  else
+    luaK_dischargevars(fs, e);
+}
+
+
+int luaK_exp2RK (FuncState *fs, expdesc *e) {
+  luaK_exp2val(fs, e);
+  switch (e->k) {
+    case VTRUE:
+    case VFALSE:
+    case VNIL: {
+      if (fs->nk <= MAXINDEXRK) {  /* constant fits in RK operand? */
+        e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE));
+        e->k = VK;
+        return RKASK(e->u.info);
+      }
+      else break;
+    }
+    case VKNUM: {
+      e->u.info = luaK_numberK(fs, e->u.nval);
+      e->k = VK;
+      /* go through */
+    }
+    case VK: {
+      if (e->u.info <= MAXINDEXRK)  /* constant fits in argC? */
+        return RKASK(e->u.info);
+      else break;
+    }
+    default: break;
+  }
+  /* not a constant in the right range: put it in a register */
+  return luaK_exp2anyreg(fs, e);
+}
+
+
+void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
+  switch (var->k) {
+    case VLOCAL: {
+      freeexp(fs, ex);
+      exp2reg(fs, ex, var->u.info);
+      return;
+    }
+    case VUPVAL: {
+      int e = luaK_exp2anyreg(fs, ex);
+      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
+      break;
+    }
+    case VINDEXED: {
+      OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
+      int e = luaK_exp2RK(fs, ex);
+      luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
+      break;
+    }
+    default: {
+      lua_assert(0);  /* invalid var kind to store */
+      break;
+    }
+  }
+  freeexp(fs, ex);
+}
+
+
+void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
+  int ereg;
+  luaK_exp2anyreg(fs, e);
+  ereg = e->u.info;  /* register where 'e' was placed */
+  freeexp(fs, e);
+  e->u.info = fs->freereg;  /* base register for op_self */
+  e->k = VNONRELOC;
+  luaK_reserveregs(fs, 2);  /* function and 'self' produced by op_self */
+  luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));
+  freeexp(fs, key);
+}
+
+
+static void invertjump (FuncState *fs, expdesc *e) {
+  Instruction *pc = getjumpcontrol(fs, e->u.info);
+  lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
+                                           GET_OPCODE(*pc) != OP_TEST);
+  SETARG_A(*pc, !(GETARG_A(*pc)));
+}
+
+
+static int jumponcond (FuncState *fs, expdesc *e, int cond) {
+  if (e->k == VRELOCABLE) {
+    Instruction ie = getcode(fs, e);
+    if (GET_OPCODE(ie) == OP_NOT) {
+      fs->pc--;  /* remove previous OP_NOT */
+      return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
+    }
+    /* else go through */
+  }
+  discharge2anyreg(fs, e);
+  freeexp(fs, e);
+  return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
+}
+
+
+void luaK_goiftrue (FuncState *fs, expdesc *e) {
+  int pc;  /* pc of last jump */
+  luaK_dischargevars(fs, e);
+  switch (e->k) {
+    case VJMP: {
+      invertjump(fs, e);
+      pc = e->u.info;
+      break;
+    }
+    case VK: case VKNUM: case VTRUE: {
+      pc = NO_JUMP;  /* always true; do nothing */
+      break;
+    }
+    default: {
+      pc = jumponcond(fs, e, 0);
+      break;
+    }
+  }
+  luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */
+  luaK_patchtohere(fs, e->t);
+  e->t = NO_JUMP;
+}
+
+
+void luaK_goiffalse (FuncState *fs, expdesc *e) {
+  int pc;  /* pc of last jump */
+  luaK_dischargevars(fs, e);
+  switch (e->k) {
+    case VJMP: {
+      pc = e->u.info;
+      break;
+    }
+    case VNIL: case VFALSE: {
+      pc = NO_JUMP;  /* always false; do nothing */
+      break;
+    }
+    default: {
+      pc = jumponcond(fs, e, 1);
+      break;
+    }
+  }
+  luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */
+  luaK_patchtohere(fs, e->f);
+  e->f = NO_JUMP;
+}
+
+
+static void codenot (FuncState *fs, expdesc *e) {
+  luaK_dischargevars(fs, e);
+  switch (e->k) {
+    case VNIL: case VFALSE: {
+      e->k = VTRUE;
+      break;
+    }
+    case VK: case VKNUM: case VTRUE: {
+      e->k = VFALSE;
+      break;
+    }
+    case VJMP: {
+      invertjump(fs, e);
+      break;
+    }
+    case VRELOCABLE:
+    case VNONRELOC: {
+      discharge2anyreg(fs, e);
+      freeexp(fs, e);
+      e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0);
+      e->k = VRELOCABLE;
+      break;
+    }
+    default: {
+      lua_assert(0);  /* cannot happen */
+      break;
+    }
+  }
+  /* interchange true and false lists */
+  { int temp = e->f; e->f = e->t; e->t = temp; }
+  removevalues(fs, e->f);
+  removevalues(fs, e->t);
+}
+
+
+void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
+  lua_assert(!hasjumps(t));
+  t->u.ind.t = t->u.info;
+  t->u.ind.idx = luaK_exp2RK(fs, k);
+  t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
+                                 : check_exp(vkisinreg(t->k), VLOCAL);
+  t->k = VINDEXED;
+}
+
+
+static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
+  lua_Number r;
+  if (!isnumeral(e1) || !isnumeral(e2)) return 0;
+  if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0)
+    return 0;  /* do not attempt to divide by 0 */
+  r = luaO_arith(op - OP_ADD + LUA_OPADD, e1->u.nval, e2->u.nval);
+  e1->u.nval = r;
+  return 1;
+}
+
+
+static void codearith (FuncState *fs, OpCode op,
+                       expdesc *e1, expdesc *e2, int line) {
+  if (constfolding(op, e1, e2))
+    return;
+  else {
+    int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
+    int o1 = luaK_exp2RK(fs, e1);
+    if (o1 > o2) {
+      freeexp(fs, e1);
+      freeexp(fs, e2);
+    }
+    else {
+      freeexp(fs, e2);
+      freeexp(fs, e1);
+    }
+    e1->u.info = luaK_codeABC(fs, op, 0, o1, o2);
+    e1->k = VRELOCABLE;
+    luaK_fixline(fs, line);
+  }
+}
+
+
+static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
+                                                          expdesc *e2) {
+  int o1 = luaK_exp2RK(fs, e1);
+  int o2 = luaK_exp2RK(fs, e2);
+  freeexp(fs, e2);
+  freeexp(fs, e1);
+  if (cond == 0 && op != OP_EQ) {
+    int temp;  /* exchange args to replace by `<' or `<=' */
+    temp = o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */
+    cond = 1;
+  }
+  e1->u.info = condjump(fs, op, cond, o1, o2);
+  e1->k = VJMP;
+}
+
+
+void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
+  expdesc e2;
+  e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
+  switch (op) {
+    case OPR_MINUS: {
+      if (isnumeral(e))  /* minus constant? */
+        e->u.nval = luai_numunm(NULL, e->u.nval);  /* fold it */
+      else {
+        luaK_exp2anyreg(fs, e);
+        codearith(fs, OP_UNM, e, &e2, line);
+      }
+      break;
+    }
+    case OPR_NOT: codenot(fs, e); break;
+    case OPR_LEN: {
+      luaK_exp2anyreg(fs, e);  /* cannot operate on constants */
+      codearith(fs, OP_LEN, e, &e2, line);
+      break;
+    }
+    default: lua_assert(0);
+  }
+}
+
+
+void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
+  switch (op) {
+    case OPR_AND: {
+      luaK_goiftrue(fs, v);
+      break;
+    }
+    case OPR_OR: {
+      luaK_goiffalse(fs, v);
+      break;
+    }
+    case OPR_CONCAT: {
+      luaK_exp2nextreg(fs, v);  /* operand must be on the `stack' */
+      break;
+    }
+    case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
+    case OPR_MOD: case OPR_POW: {
+      if (!isnumeral(v)) luaK_exp2RK(fs, v);
+      break;
+    }
+    default: {
+      luaK_exp2RK(fs, v);
+      break;
+    }
+  }
+}
+
+
+void luaK_posfix (FuncState *fs, BinOpr op,
+                  expdesc *e1, expdesc *e2, int line) {
+  switch (op) {
+    case OPR_AND: {
+      lua_assert(e1->t == NO_JUMP);  /* list must be closed */
+      luaK_dischargevars(fs, e2);
+      luaK_concat(fs, &e2->f, e1->f);
+      *e1 = *e2;
+      break;
+    }
+    case OPR_OR: {
+      lua_assert(e1->f == NO_JUMP);  /* list must be closed */
+      luaK_dischargevars(fs, e2);
+      luaK_concat(fs, &e2->t, e1->t);
+      *e1 = *e2;
+      break;
+    }
+    case OPR_CONCAT: {
+      luaK_exp2val(fs, e2);
+      if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
+        lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
+        freeexp(fs, e1);
+        SETARG_B(getcode(fs, e2), e1->u.info);
+        e1->k = VRELOCABLE; e1->u.info = e2->u.info;
+      }
+      else {
+        luaK_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */
+        codearith(fs, OP_CONCAT, e1, e2, line);
+      }
+      break;
+    }
+    case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
+    case OPR_MOD: case OPR_POW: {
+      codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line);
+      break;
+    }
+    case OPR_EQ: case OPR_LT: case OPR_LE: {
+      codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2);
+      break;
+    }
+    case OPR_NE: case OPR_GT: case OPR_GE: {
+      codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2);
+      break;
+    }
+    default: lua_assert(0);
+  }
+}
+
+
+void luaK_fixline (FuncState *fs, int line) {
+  fs->f->lineinfo[fs->pc - 1] = line;
+}
+
+
+void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
+  int c =  (nelems - 1)/LFIELDS_PER_FLUSH + 1;
+  int b = (tostore == LUA_MULTRET) ? 0 : tostore;
+  lua_assert(tostore != 0);
+  if (c <= MAXARG_C)
+    luaK_codeABC(fs, OP_SETLIST, base, b, c);
+  else if (c <= MAXARG_Ax) {
+    luaK_codeABC(fs, OP_SETLIST, base, b, 0);
+    codeextraarg(fs, c);
+  }
+  else
+    luaX_syntaxerror(fs->ls, "constructor too long");
+  fs->freereg = base + 1;  /* free registers with list values */
+}
+

=== added file 'src/scripting/eris/lcode.h'
--- src/scripting/eris/lcode.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lcode.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,83 @@
+/*
+** $Id: lcode.h,v 1.58 2011/08/30 16:26:41 roberto Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lcode_h
+#define lcode_h
+
+#include "llex.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+
+
+/*
+** Marks the end of a patch list. It is an invalid value both as an absolute
+** address, and as a list link (would link an element to itself).
+*/
+#define NO_JUMP (-1)
+
+
+/*
+** grep "ORDER OPR" if you change these enums  (ORDER OP)
+*/
+typedef enum BinOpr {
+  OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
+  OPR_CONCAT,
+  OPR_EQ, OPR_LT, OPR_LE,
+  OPR_NE, OPR_GT, OPR_GE,
+  OPR_AND, OPR_OR,
+  OPR_NOBINOPR
+} BinOpr;
+
+
+typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
+
+
+#define getcode(fs,e)	((fs)->f->code[(e)->u.info])
+
+#define luaK_codeAsBx(fs,o,A,sBx)	luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
+
+#define luaK_setmultret(fs,e)	luaK_setreturns(fs, e, LUA_MULTRET)
+
+#define luaK_jumpto(fs,t)	luaK_patchlist(fs, luaK_jump(fs), t)
+
+LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
+LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
+LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k);
+LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
+LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
+LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
+LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
+LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
+LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r);
+LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
+LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
+LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
+LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
+LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
+LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
+LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
+LUAI_FUNC int luaK_jump (FuncState *fs);
+LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
+LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
+LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
+LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level);
+LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
+LUAI_FUNC int luaK_getlabel (FuncState *fs);
+LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
+LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
+LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
+                            expdesc *v2, int line);
+LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
+
+
+#endif

=== added file 'src/scripting/eris/lcorolib.c'
--- src/scripting/eris/lcorolib.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lcorolib.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,171 @@
+/*
+** $Id: lcorolib.c,v 1.5 2013/02/21 13:44:53 roberto Exp $
+** Coroutine Library
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+
+
+#define lcorolib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+static int auxresume (lua_State *L, lua_State *co, int narg) {
+  int status;
+  if (!lua_checkstack(co, narg)) {
+    lua_pushliteral(L, "too many arguments to resume");
+    return -1;  /* error flag */
+  }
+  if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
+    lua_pushliteral(L, "cannot resume dead coroutine");
+    return -1;  /* error flag */
+  }
+  lua_xmove(L, co, narg);
+  status = lua_resume(co, L, narg);
+  if (status == LUA_OK || status == LUA_YIELD) {
+    int nres = lua_gettop(co);
+    if (!lua_checkstack(L, nres + 1)) {
+      lua_pop(co, nres);  /* remove results anyway */
+      lua_pushliteral(L, "too many results to resume");
+      return -1;  /* error flag */
+    }
+    lua_xmove(co, L, nres);  /* move yielded values */
+    return nres;
+  }
+  else {
+    lua_xmove(co, L, 1);  /* move error message */
+    return -1;  /* error flag */
+  }
+}
+
+
+static int luaB_coresume (lua_State *L) {
+  lua_State *co = lua_tothread(L, 1);
+  int r;
+  luaL_argcheck(L, co, 1, "coroutine expected");
+  r = auxresume(L, co, lua_gettop(L) - 1);
+  if (r < 0) {
+    lua_pushboolean(L, 0);
+    lua_insert(L, -2);
+    return 2;  /* return false + error message */
+  }
+  else {
+    lua_pushboolean(L, 1);
+    lua_insert(L, -(r + 1));
+    return r + 1;  /* return true + `resume' returns */
+  }
+}
+
+
+static int luaB_auxwrap (lua_State *L) {
+  lua_State *co = lua_tothread(L, lua_upvalueindex(1));
+  int r = auxresume(L, co, lua_gettop(L));
+  if (r < 0) {
+    if (lua_isstring(L, -1)) {  /* error object is a string? */
+      luaL_where(L, 1);  /* add extra info */
+      lua_insert(L, -2);
+      lua_concat(L, 2);
+    }
+    return lua_error(L);  /* propagate error */
+  }
+  return r;
+}
+
+
+static int luaB_cocreate (lua_State *L) {
+  lua_State *NL;
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+  NL = lua_newthread(L);
+  lua_pushvalue(L, 1);  /* move function to top */
+  lua_xmove(L, NL, 1);  /* move function from L to NL */
+  return 1;
+}
+
+
+static int luaB_cowrap (lua_State *L) {
+  luaB_cocreate(L);
+  lua_pushcclosure(L, luaB_auxwrap, 1);
+  return 1;
+}
+
+
+static int luaB_yield (lua_State *L) {
+  return lua_yield(L, lua_gettop(L));
+}
+
+
+static int luaB_costatus (lua_State *L) {
+  lua_State *co = lua_tothread(L, 1);
+  luaL_argcheck(L, co, 1, "coroutine expected");
+  if (L == co) lua_pushliteral(L, "running");
+  else {
+    switch (lua_status(co)) {
+      case LUA_YIELD:
+        lua_pushliteral(L, "suspended");
+        break;
+      case LUA_OK: {
+        lua_Debug ar;
+        if (lua_getstack(co, 0, &ar) > 0)  /* does it have frames? */
+          lua_pushliteral(L, "normal");  /* it is running */
+        else if (lua_gettop(co) == 0)
+            lua_pushliteral(L, "dead");
+        else
+          lua_pushliteral(L, "suspended");  /* initial state */
+        break;
+      }
+      default:  /* some error occurred */
+        lua_pushliteral(L, "dead");
+        break;
+    }
+  }
+  return 1;
+}
+
+
+static int luaB_corunning (lua_State *L) {
+  int ismain = lua_pushthread(L);
+  lua_pushboolean(L, ismain);
+  return 2;
+}
+
+
+static const luaL_Reg co_funcs[] = {
+  {"create", luaB_cocreate},
+  {"resume", luaB_coresume},
+  {"running", luaB_corunning},
+  {"status", luaB_costatus},
+  {"wrap", luaB_cowrap},
+  {"yield", luaB_yield},
+  {NULL, NULL}
+};
+
+
+
+LUAMOD_API int luaopen_coroutine (lua_State *L) {
+  luaL_newlib(L, co_funcs);
+  return 1;
+}
+
+
+void eris_permcorolib(lua_State *L, int forUnpersist) {
+  luaL_checktype(L, -1, LUA_TTABLE);
+  luaL_checkstack(L, 2, NULL);
+
+  if (forUnpersist) {
+    lua_pushstring(L, "__eris.corolib_luaB_auxwrap");
+    lua_pushcfunction(L, luaB_auxwrap);
+  }
+  else {
+    lua_pushcfunction(L, luaB_auxwrap);
+    lua_pushstring(L, "__eris.corolib_luaB_auxwrap");
+  }
+  lua_rawset(L, -3);
+}
+

=== added file 'src/scripting/eris/lctype.c'
--- src/scripting/eris/lctype.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lctype.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,52 @@
+/*
+** $Id: lctype.c,v 1.11 2011/10/03 16:19:23 roberto Exp $
+** 'ctype' functions for Lua
+** See Copyright Notice in lua.h
+*/
+
+#define lctype_c
+#define LUA_CORE
+
+#include "lctype.h"
+
+#if !LUA_USE_CTYPE	/* { */
+
+#include <limits.h>
+
+LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
+  0x00,  /* EOZ */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 0. */
+  0x00,  0x08,  0x08,  0x08,  0x08,  0x08,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 1. */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x0c,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,	/* 2. */
+  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,
+  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,  0x16,	/* 3. */
+  0x16,  0x16,  0x04,  0x04,  0x04,  0x04,  0x04,  0x04,
+  0x04,  0x15,  0x15,  0x15,  0x15,  0x15,  0x15,  0x05,	/* 4. */
+  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,
+  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,	/* 5. */
+  0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x05,
+  0x04,  0x15,  0x15,  0x15,  0x15,  0x15,  0x15,  0x05,	/* 6. */
+  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,
+  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,  0x05,	/* 7. */
+  0x05,  0x05,  0x05,  0x04,  0x04,  0x04,  0x04,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 8. */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* 9. */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* a. */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* b. */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* c. */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* d. */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* e. */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,	/* f. */
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+};
+
+#endif			/* } */

=== added file 'src/scripting/eris/lctype.h'
--- src/scripting/eris/lctype.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lctype.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,95 @@
+/*
+** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $
+** 'ctype' functions for Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lctype_h
+#define lctype_h
+
+#include "lua.h"
+
+
+/*
+** WARNING: the functions defined here do not necessarily correspond
+** to the similar functions in the standard C ctype.h. They are
+** optimized for the specific needs of Lua
+*/
+
+#if !defined(LUA_USE_CTYPE)
+
+#if 'A' == 65 && '0' == 48
+/* ASCII case: can use its own tables; faster and fixed */
+#define LUA_USE_CTYPE	0
+#else
+/* must use standard C ctype */
+#define LUA_USE_CTYPE	1
+#endif
+
+#endif
+
+
+#if !LUA_USE_CTYPE	/* { */
+
+#include <limits.h>
+
+#include "llimits.h"
+
+
+#define ALPHABIT	0
+#define DIGITBIT	1
+#define PRINTBIT	2
+#define SPACEBIT	3
+#define XDIGITBIT	4
+
+
+#define MASK(B)		(1 << (B))
+
+
+/*
+** add 1 to char to allow index -1 (EOZ)
+*/
+#define testprop(c,p)	(luai_ctype_[(c)+1] & (p))
+
+/*
+** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_'
+*/
+#define lislalpha(c)	testprop(c, MASK(ALPHABIT))
+#define lislalnum(c)	testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT)))
+#define lisdigit(c)	testprop(c, MASK(DIGITBIT))
+#define lisspace(c)	testprop(c, MASK(SPACEBIT))
+#define lisprint(c)	testprop(c, MASK(PRINTBIT))
+#define lisxdigit(c)	testprop(c, MASK(XDIGITBIT))
+
+/*
+** this 'ltolower' only works for alphabetic characters
+*/
+#define ltolower(c)	((c) | ('A' ^ 'a'))
+
+
+/* two more entries for 0 and -1 (EOZ) */
+LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2];
+
+
+#else			/* }{ */
+
+/*
+** use standard C ctypes
+*/
+
+#include <ctype.h>
+
+
+#define lislalpha(c)	(isalpha(c) || (c) == '_')
+#define lislalnum(c)	(isalnum(c) || (c) == '_')
+#define lisdigit(c)	(isdigit(c))
+#define lisspace(c)	(isspace(c))
+#define lisprint(c)	(isprint(c))
+#define lisxdigit(c)	(isxdigit(c))
+
+#define ltolower(c)	(tolower(c))
+
+#endif			/* } */
+
+#endif
+

=== added file 'src/scripting/eris/ldblib.c'
--- src/scripting/eris/ldblib.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/ldblib.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,398 @@
+/*
+** $Id: ldblib.c,v 1.132 2012/01/19 20:14:44 roberto Exp $
+** Interface from Lua to its debug API
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ldblib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#define HOOKKEY		"_HKEY"
+
+
+
+static int db_getregistry (lua_State *L) {
+  lua_pushvalue(L, LUA_REGISTRYINDEX);
+  return 1;
+}
+
+
+static int db_getmetatable (lua_State *L) {
+  luaL_checkany(L, 1);
+  if (!lua_getmetatable(L, 1)) {
+    lua_pushnil(L);  /* no metatable */
+  }
+  return 1;
+}
+
+
+static int db_setmetatable (lua_State *L) {
+  int t = lua_type(L, 2);
+  luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
+                    "nil or table expected");
+  lua_settop(L, 2);
+  lua_setmetatable(L, 1);
+  return 1;  /* return 1st argument */
+}
+
+
+static int db_getuservalue (lua_State *L) {
+  if (lua_type(L, 1) != LUA_TUSERDATA)
+    lua_pushnil(L);
+  else
+    lua_getuservalue(L, 1);
+  return 1;
+}
+
+
+static int db_setuservalue (lua_State *L) {
+  if (lua_type(L, 1) == LUA_TLIGHTUSERDATA)
+    luaL_argerror(L, 1, "full userdata expected, got light userdata");
+  luaL_checktype(L, 1, LUA_TUSERDATA);
+  if (!lua_isnoneornil(L, 2))
+    luaL_checktype(L, 2, LUA_TTABLE);
+  lua_settop(L, 2);
+  lua_setuservalue(L, 1);
+  return 1;
+}
+
+
+static void settabss (lua_State *L, const char *i, const char *v) {
+  lua_pushstring(L, v);
+  lua_setfield(L, -2, i);
+}
+
+
+static void settabsi (lua_State *L, const char *i, int v) {
+  lua_pushinteger(L, v);
+  lua_setfield(L, -2, i);
+}
+
+
+static void settabsb (lua_State *L, const char *i, int v) {
+  lua_pushboolean(L, v);
+  lua_setfield(L, -2, i);
+}
+
+
+static lua_State *getthread (lua_State *L, int *arg) {
+  if (lua_isthread(L, 1)) {
+    *arg = 1;
+    return lua_tothread(L, 1);
+  }
+  else {
+    *arg = 0;
+    return L;
+  }
+}
+
+
+static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
+  if (L == L1) {
+    lua_pushvalue(L, -2);
+    lua_remove(L, -3);
+  }
+  else
+    lua_xmove(L1, L, 1);
+  lua_setfield(L, -2, fname);
+}
+
+
+static int db_getinfo (lua_State *L) {
+  lua_Debug ar;
+  int arg;
+  lua_State *L1 = getthread(L, &arg);
+  const char *options = luaL_optstring(L, arg+2, "flnStu");
+  if (lua_isnumber(L, arg+1)) {
+    if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
+      lua_pushnil(L);  /* level out of range */
+      return 1;
+    }
+  }
+  else if (lua_isfunction(L, arg+1)) {
+    lua_pushfstring(L, ">%s", options);
+    options = lua_tostring(L, -1);
+    lua_pushvalue(L, arg+1);
+    lua_xmove(L, L1, 1);
+  }
+  else
+    return luaL_argerror(L, arg+1, "function or level expected");
+  if (!lua_getinfo(L1, options, &ar))
+    return luaL_argerror(L, arg+2, "invalid option");
+  lua_createtable(L, 0, 2);
+  if (strchr(options, 'S')) {
+    settabss(L, "source", ar.source);
+    settabss(L, "short_src", ar.short_src);
+    settabsi(L, "linedefined", ar.linedefined);
+    settabsi(L, "lastlinedefined", ar.lastlinedefined);
+    settabss(L, "what", ar.what);
+  }
+  if (strchr(options, 'l'))
+    settabsi(L, "currentline", ar.currentline);
+  if (strchr(options, 'u')) {
+    settabsi(L, "nups", ar.nups);
+    settabsi(L, "nparams", ar.nparams);
+    settabsb(L, "isvararg", ar.isvararg);
+  }
+  if (strchr(options, 'n')) {
+    settabss(L, "name", ar.name);
+    settabss(L, "namewhat", ar.namewhat);
+  }
+  if (strchr(options, 't'))
+    settabsb(L, "istailcall", ar.istailcall);
+  if (strchr(options, 'L'))
+    treatstackoption(L, L1, "activelines");
+  if (strchr(options, 'f'))
+    treatstackoption(L, L1, "func");
+  return 1;  /* return table */
+}
+
+
+static int db_getlocal (lua_State *L) {
+  int arg;
+  lua_State *L1 = getthread(L, &arg);
+  lua_Debug ar;
+  const char *name;
+  int nvar = luaL_checkint(L, arg+2);  /* local-variable index */
+  if (lua_isfunction(L, arg + 1)) {  /* function argument? */
+    lua_pushvalue(L, arg + 1);  /* push function */
+    lua_pushstring(L, lua_getlocal(L, NULL, nvar));  /* push local name */
+    return 1;
+  }
+  else {  /* stack-level argument */
+    if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */
+      return luaL_argerror(L, arg+1, "level out of range");
+    name = lua_getlocal(L1, &ar, nvar);
+    if (name) {
+      lua_xmove(L1, L, 1);  /* push local value */
+      lua_pushstring(L, name);  /* push name */
+      lua_pushvalue(L, -2);  /* re-order */
+      return 2;
+    }
+    else {
+      lua_pushnil(L);  /* no name (nor value) */
+      return 1;
+    }
+  }
+}
+
+
+static int db_setlocal (lua_State *L) {
+  int arg;
+  lua_State *L1 = getthread(L, &arg);
+  lua_Debug ar;
+  if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */
+    return luaL_argerror(L, arg+1, "level out of range");
+  luaL_checkany(L, arg+3);
+  lua_settop(L, arg+3);
+  lua_xmove(L, L1, 1);
+  lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
+  return 1;
+}
+
+
+static int auxupvalue (lua_State *L, int get) {
+  const char *name;
+  int n = luaL_checkint(L, 2);
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+  name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
+  if (name == NULL) return 0;
+  lua_pushstring(L, name);
+  lua_insert(L, -(get+1));
+  return get + 1;
+}
+
+
+static int db_getupvalue (lua_State *L) {
+  return auxupvalue(L, 1);
+}
+
+
+static int db_setupvalue (lua_State *L) {
+  luaL_checkany(L, 3);
+  return auxupvalue(L, 0);
+}
+
+
+static int checkupval (lua_State *L, int argf, int argnup) {
+  lua_Debug ar;
+  int nup = luaL_checkint(L, argnup);
+  luaL_checktype(L, argf, LUA_TFUNCTION);
+  lua_pushvalue(L, argf);
+  lua_getinfo(L, ">u", &ar);
+  luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index");
+  return nup;
+}
+
+
+static int db_upvalueid (lua_State *L) {
+  int n = checkupval(L, 1, 2);
+  lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
+  return 1;
+}
+
+
+static int db_upvaluejoin (lua_State *L) {
+  int n1 = checkupval(L, 1, 2);
+  int n2 = checkupval(L, 3, 4);
+  luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
+  luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
+  lua_upvaluejoin(L, 1, n1, 3, n2);
+  return 0;
+}
+
+
+#define gethooktable(L)	luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)
+
+
+static void hookf (lua_State *L, lua_Debug *ar) {
+  static const char *const hooknames[] =
+    {"call", "return", "line", "count", "tail call"};
+  gethooktable(L);
+  lua_pushthread(L);
+  lua_rawget(L, -2);
+  if (lua_isfunction(L, -1)) {
+    lua_pushstring(L, hooknames[(int)ar->event]);
+    if (ar->currentline >= 0)
+      lua_pushinteger(L, ar->currentline);
+    else lua_pushnil(L);
+    lua_assert(lua_getinfo(L, "lS", ar));
+    lua_call(L, 2, 0);
+  }
+}
+
+
+static int makemask (const char *smask, int count) {
+  int mask = 0;
+  if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
+  if (strchr(smask, 'r')) mask |= LUA_MASKRET;
+  if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
+  if (count > 0) mask |= LUA_MASKCOUNT;
+  return mask;
+}
+
+
+static char *unmakemask (int mask, char *smask) {
+  int i = 0;
+  if (mask & LUA_MASKCALL) smask[i++] = 'c';
+  if (mask & LUA_MASKRET) smask[i++] = 'r';
+  if (mask & LUA_MASKLINE) smask[i++] = 'l';
+  smask[i] = '\0';
+  return smask;
+}
+
+
+static int db_sethook (lua_State *L) {
+  int arg, mask, count;
+  lua_Hook func;
+  lua_State *L1 = getthread(L, &arg);
+  if (lua_isnoneornil(L, arg+1)) {
+    lua_settop(L, arg+1);
+    func = NULL; mask = 0; count = 0;  /* turn off hooks */
+  }
+  else {
+    const char *smask = luaL_checkstring(L, arg+2);
+    luaL_checktype(L, arg+1, LUA_TFUNCTION);
+    count = luaL_optint(L, arg+3, 0);
+    func = hookf; mask = makemask(smask, count);
+  }
+  if (gethooktable(L) == 0) {  /* creating hook table? */
+    lua_pushstring(L, "k");
+    lua_setfield(L, -2, "__mode");  /** hooktable.__mode = "k" */
+    lua_pushvalue(L, -1);
+    lua_setmetatable(L, -2);  /* setmetatable(hooktable) = hooktable */
+  }
+  lua_pushthread(L1); lua_xmove(L1, L, 1);
+  lua_pushvalue(L, arg+1);
+  lua_rawset(L, -3);  /* set new hook */
+  lua_sethook(L1, func, mask, count);  /* set hooks */
+  return 0;
+}
+
+
+static int db_gethook (lua_State *L) {
+  int arg;
+  lua_State *L1 = getthread(L, &arg);
+  char buff[5];
+  int mask = lua_gethookmask(L1);
+  lua_Hook hook = lua_gethook(L1);
+  if (hook != NULL && hook != hookf)  /* external hook? */
+    lua_pushliteral(L, "external hook");
+  else {
+    gethooktable(L);
+    lua_pushthread(L1); lua_xmove(L1, L, 1);
+    lua_rawget(L, -2);   /* get hook */
+    lua_remove(L, -2);  /* remove hook table */
+  }
+  lua_pushstring(L, unmakemask(mask, buff));
+  lua_pushinteger(L, lua_gethookcount(L1));
+  return 3;
+}
+
+
+static int db_debug (lua_State *L) {
+  for (;;) {
+    char buffer[250];
+    luai_writestringerror("%s", "lua_debug> ");
+    if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
+        strcmp(buffer, "cont\n") == 0)
+      return 0;
+    if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
+        lua_pcall(L, 0, 0, 0))
+      luai_writestringerror("%s\n", lua_tostring(L, -1));
+    lua_settop(L, 0);  /* remove eventual returns */
+  }
+}
+
+
+static int db_traceback (lua_State *L) {
+  int arg;
+  lua_State *L1 = getthread(L, &arg);
+  const char *msg = lua_tostring(L, arg + 1);
+  if (msg == NULL && !lua_isnoneornil(L, arg + 1))  /* non-string 'msg'? */
+    lua_pushvalue(L, arg + 1);  /* return it untouched */
+  else {
+    int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0);
+    luaL_traceback(L, L1, msg, level);
+  }
+  return 1;
+}
+
+
+static const luaL_Reg dblib[] = {
+  {"debug", db_debug},
+  {"getuservalue", db_getuservalue},
+  {"gethook", db_gethook},
+  {"getinfo", db_getinfo},
+  {"getlocal", db_getlocal},
+  {"getregistry", db_getregistry},
+  {"getmetatable", db_getmetatable},
+  {"getupvalue", db_getupvalue},
+  {"upvaluejoin", db_upvaluejoin},
+  {"upvalueid", db_upvalueid},
+  {"setuservalue", db_setuservalue},
+  {"sethook", db_sethook},
+  {"setlocal", db_setlocal},
+  {"setmetatable", db_setmetatable},
+  {"setupvalue", db_setupvalue},
+  {"traceback", db_traceback},
+  {NULL, NULL}
+};
+
+
+LUAMOD_API int luaopen_debug (lua_State *L) {
+  luaL_newlib(L, dblib);
+  return 1;
+}
+

=== added file 'src/scripting/eris/ldebug.c'
--- src/scripting/eris/ldebug.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/ldebug.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,593 @@
+/*
+** $Id: ldebug.c,v 2.90 2012/08/16 17:34:28 roberto Exp $
+** Debug Interface
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+
+
+#define ldebug_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lvm.h"
+
+
+
+#define noLuaClosure(f)		((f) == NULL || (f)->c.tt == LUA_TCCL)
+
+
+static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
+
+
+static int currentpc (CallInfo *ci) {
+  lua_assert(isLua(ci));
+  return pcRel(ci->u.l.savedpc, ci_func(ci)->p);
+}
+
+
+static int currentline (CallInfo *ci) {
+  return getfuncline(ci_func(ci)->p, currentpc(ci));
+}
+
+
+/*
+** this function can be called asynchronous (e.g. during a signal)
+*/
+LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
+  if (func == NULL || mask == 0) {  /* turn off hooks? */
+    mask = 0;
+    func = NULL;
+  }
+  if (isLua(L->ci))
+    L->oldpc = L->ci->u.l.savedpc;
+  L->hook = func;
+  L->basehookcount = count;
+  resethookcount(L);
+  L->hookmask = cast_byte(mask);
+  return 1;
+}
+
+
+LUA_API lua_Hook lua_gethook (lua_State *L) {
+  return L->hook;
+}
+
+
+LUA_API int lua_gethookmask (lua_State *L) {
+  return L->hookmask;
+}
+
+
+LUA_API int lua_gethookcount (lua_State *L) {
+  return L->basehookcount;
+}
+
+
+LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
+  int status;
+  CallInfo *ci;
+  if (level < 0) return 0;  /* invalid (negative) level */
+  lua_lock(L);
+  for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
+    level--;
+  if (level == 0 && ci != &L->base_ci) {  /* level found? */
+    status = 1;
+    ar->i_ci = ci;
+  }
+  else status = 0;  /* no such level */
+  lua_unlock(L);
+  return status;
+}
+
+
+static const char *upvalname (Proto *p, int uv) {
+  TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);
+  if (s == NULL) return "?";
+  else return getstr(s);
+}
+
+
+static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
+  int nparams = clLvalue(ci->func)->p->numparams;
+  if (n >= ci->u.l.base - ci->func - nparams)
+    return NULL;  /* no such vararg */
+  else {
+    *pos = ci->func + nparams + n;
+    return "(*vararg)";  /* generic name for any vararg */
+  }
+}
+
+
+static const char *findlocal (lua_State *L, CallInfo *ci, int n,
+                              StkId *pos) {
+  const char *name = NULL;
+  StkId base;
+  if (isLua(ci)) {
+    if (n < 0)  /* access to vararg values? */
+      return findvararg(ci, -n, pos);
+    else {
+      base = ci->u.l.base;
+      name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
+    }
+  }
+  else
+    base = ci->func + 1;
+  if (name == NULL) {  /* no 'standard' name? */
+    StkId limit = (ci == L->ci) ? L->top : ci->next->func;
+    if (limit - base >= n && n > 0)  /* is 'n' inside 'ci' stack? */
+      name = "(*temporary)";  /* generic name for any valid slot */
+    else
+      return NULL;  /* no name */
+  }
+  *pos = base + (n - 1);
+  return name;
+}
+
+
+LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
+  const char *name;
+  lua_lock(L);
+  if (ar == NULL) {  /* information about non-active function? */
+    if (!isLfunction(L->top - 1))  /* not a Lua function? */
+      name = NULL;
+    else  /* consider live variables at function start (parameters) */
+      name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
+  }
+  else {  /* active function; get information through 'ar' */
+    StkId pos = 0;  /* to avoid warnings */
+    name = findlocal(L, ar->i_ci, n, &pos);
+    if (name) {
+      setobj2s(L, L->top, pos);
+      api_incr_top(L);
+    }
+  }
+  lua_unlock(L);
+  return name;
+}
+
+
+LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
+  StkId pos = 0;  /* to avoid warnings */
+  const char *name = findlocal(L, ar->i_ci, n, &pos);
+  lua_lock(L);
+  if (name)
+    setobjs2s(L, pos, L->top - 1);
+  L->top--;  /* pop value */
+  lua_unlock(L);
+  return name;
+}
+
+
+static void funcinfo (lua_Debug *ar, Closure *cl) {
+  if (noLuaClosure(cl)) {
+    ar->source = "=[C]";
+    ar->linedefined = -1;
+    ar->lastlinedefined = -1;
+    ar->what = "C";
+  }
+  else {
+    Proto *p = cl->l.p;
+    ar->source = p->source ? getstr(p->source) : "=?";
+    ar->linedefined = p->linedefined;
+    ar->lastlinedefined = p->lastlinedefined;
+    ar->what = (ar->linedefined == 0) ? "main" : "Lua";
+  }
+  luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
+}
+
+
+static void collectvalidlines (lua_State *L, Closure *f) {
+  if (noLuaClosure(f)) {
+    setnilvalue(L->top);
+    api_incr_top(L);
+  }
+  else {
+    int i;
+    TValue v;
+    int *lineinfo = f->l.p->lineinfo;
+    Table *t = luaH_new(L);  /* new table to store active lines */
+    sethvalue(L, L->top, t);  /* push it on stack */
+    api_incr_top(L);
+    setbvalue(&v, 1);  /* boolean 'true' to be the value of all indices */
+    for (i = 0; i < f->l.p->sizelineinfo; i++)  /* for all lines with code */
+      luaH_setint(L, t, lineinfo[i], &v);  /* table[line] = true */
+  }
+}
+
+
+static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
+                       Closure *f, CallInfo *ci) {
+  int status = 1;
+  for (; *what; what++) {
+    switch (*what) {
+      case 'S': {
+        funcinfo(ar, f);
+        break;
+      }
+      case 'l': {
+        ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;
+        break;
+      }
+      case 'u': {
+        ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
+        if (noLuaClosure(f)) {
+          ar->isvararg = 1;
+          ar->nparams = 0;
+        }
+        else {
+          ar->isvararg = f->l.p->is_vararg;
+          ar->nparams = f->l.p->numparams;
+        }
+        break;
+      }
+      case 't': {
+        ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
+        break;
+      }
+      case 'n': {
+        /* calling function is a known Lua function? */
+        if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
+          ar->namewhat = getfuncname(L, ci->previous, &ar->name);
+        else
+          ar->namewhat = NULL;
+        if (ar->namewhat == NULL) {
+          ar->namewhat = "";  /* not found */
+          ar->name = NULL;
+        }
+        break;
+      }
+      case 'L':
+      case 'f':  /* handled by lua_getinfo */
+        break;
+      default: status = 0;  /* invalid option */
+    }
+  }
+  return status;
+}
+
+
+LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
+  int status;
+  Closure *cl;
+  CallInfo *ci;
+  StkId func;
+  lua_lock(L);
+  if (*what == '>') {
+    ci = NULL;
+    func = L->top - 1;
+    api_check(L, ttisfunction(func), "function expected");
+    what++;  /* skip the '>' */
+    L->top--;  /* pop function */
+  }
+  else {
+    ci = ar->i_ci;
+    func = ci->func;
+    lua_assert(ttisfunction(ci->func));
+  }
+  cl = ttisclosure(func) ? clvalue(func) : NULL;
+  status = auxgetinfo(L, what, ar, cl, ci);
+  if (strchr(what, 'f')) {
+    setobjs2s(L, L->top, func);
+    api_incr_top(L);
+  }
+  if (strchr(what, 'L'))
+    collectvalidlines(L, cl);
+  lua_unlock(L);
+  return status;
+}
+
+
+/*
+** {======================================================
+** Symbolic Execution
+** =======================================================
+*/
+
+static const char *getobjname (Proto *p, int lastpc, int reg,
+                               const char **name);
+
+
+/*
+** find a "name" for the RK value 'c'
+*/
+static void kname (Proto *p, int pc, int c, const char **name) {
+  if (ISK(c)) {  /* is 'c' a constant? */
+    TValue *kvalue = &p->k[INDEXK(c)];
+    if (ttisstring(kvalue)) {  /* literal constant? */
+      *name = svalue(kvalue);  /* it is its own name */
+      return;
+    }
+    /* else no reasonable name found */
+  }
+  else {  /* 'c' is a register */
+    const char *what = getobjname(p, pc, c, name); /* search for 'c' */
+    if (what && *what == 'c') {  /* found a constant name? */
+      return;  /* 'name' already filled */
+    }
+    /* else no reasonable name found */
+  }
+  *name = "?";  /* no reasonable name found */
+}
+
+
+static int filterpc (int pc, int jmptarget) {
+  if (pc < jmptarget)  /* is code conditional (inside a jump)? */
+    return -1;  /* cannot know who sets that register */
+  else return pc;  /* current position sets that register */
+}
+
+
+/*
+** try to find last instruction before 'lastpc' that modified register 'reg'
+*/
+static int findsetreg (Proto *p, int lastpc, int reg) {
+  int pc;
+  int setreg = -1;  /* keep last instruction that changed 'reg' */
+  int jmptarget = 0;  /* any code before this address is conditional */
+  for (pc = 0; pc < lastpc; pc++) {
+    Instruction i = p->code[pc];
+    OpCode op = GET_OPCODE(i);
+    int a = GETARG_A(i);
+    switch (op) {
+      case OP_LOADNIL: {
+        int b = GETARG_B(i);
+        if (a <= reg && reg <= a + b)  /* set registers from 'a' to 'a+b' */
+          setreg = filterpc(pc, jmptarget);
+        break;
+      }
+      case OP_TFORCALL: {
+        if (reg >= a + 2)  /* affect all regs above its base */
+          setreg = filterpc(pc, jmptarget);
+        break;
+      }
+      case OP_CALL:
+      case OP_TAILCALL: {
+        if (reg >= a)  /* affect all registers above base */
+          setreg = filterpc(pc, jmptarget);
+        break;
+      }
+      case OP_JMP: {
+        int b = GETARG_sBx(i);
+        int dest = pc + 1 + b;
+        /* jump is forward and do not skip `lastpc'? */
+        if (pc < dest && dest <= lastpc) {
+          if (dest > jmptarget)
+            jmptarget = dest;  /* update 'jmptarget' */
+        }
+        break;
+      }
+      case OP_TEST: {
+        if (reg == a)  /* jumped code can change 'a' */
+          setreg = filterpc(pc, jmptarget);
+        break;
+      }
+      default:
+        if (testAMode(op) && reg == a)  /* any instruction that set A */
+          setreg = filterpc(pc, jmptarget);
+        break;
+    }
+  }
+  return setreg;
+}
+
+
+static const char *getobjname (Proto *p, int lastpc, int reg,
+                               const char **name) {
+  int pc;
+  *name = luaF_getlocalname(p, reg + 1, lastpc);
+  if (*name)  /* is a local? */
+    return "local";
+  /* else try symbolic execution */
+  pc = findsetreg(p, lastpc, reg);
+  if (pc != -1) {  /* could find instruction? */
+    Instruction i = p->code[pc];
+    OpCode op = GET_OPCODE(i);
+    switch (op) {
+      case OP_MOVE: {
+        int b = GETARG_B(i);  /* move from 'b' to 'a' */
+        if (b < GETARG_A(i))
+          return getobjname(p, pc, b, name);  /* get name for 'b' */
+        break;
+      }
+      case OP_GETTABUP:
+      case OP_GETTABLE: {
+        int k = GETARG_C(i);  /* key index */
+        int t = GETARG_B(i);  /* table index */
+        const char *vn = (op == OP_GETTABLE)  /* name of indexed variable */
+                         ? luaF_getlocalname(p, t + 1, pc)
+                         : upvalname(p, t);
+        kname(p, pc, k, name);
+        return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";
+      }
+      case OP_GETUPVAL: {
+        *name = upvalname(p, GETARG_B(i));
+        return "upvalue";
+      }
+      case OP_LOADK:
+      case OP_LOADKX: {
+        int b = (op == OP_LOADK) ? GETARG_Bx(i)
+                                 : GETARG_Ax(p->code[pc + 1]);
+        if (ttisstring(&p->k[b])) {
+          *name = svalue(&p->k[b]);
+          return "constant";
+        }
+        break;
+      }
+      case OP_SELF: {
+        int k = GETARG_C(i);  /* key index */
+        kname(p, pc, k, name);
+        return "method";
+      }
+      default: break;  /* go through to return NULL */
+    }
+  }
+  return NULL;  /* could not find reasonable name */
+}
+
+
+static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
+  TMS tm;
+  Proto *p = ci_func(ci)->p;  /* calling function */
+  int pc = currentpc(ci);  /* calling instruction index */
+  Instruction i = p->code[pc];  /* calling instruction */
+  switch (GET_OPCODE(i)) {
+    case OP_CALL:
+    case OP_TAILCALL:  /* get function name */
+      return getobjname(p, pc, GETARG_A(i), name);
+    case OP_TFORCALL: {  /* for iterator */
+      *name = "for iterator";
+       return "for iterator";
+    }
+    /* all other instructions can call only through metamethods */
+    case OP_SELF:
+    case OP_GETTABUP:
+    case OP_GETTABLE: tm = TM_INDEX; break;
+    case OP_SETTABUP:
+    case OP_SETTABLE: tm = TM_NEWINDEX; break;
+    case OP_EQ: tm = TM_EQ; break;
+    case OP_ADD: tm = TM_ADD; break;
+    case OP_SUB: tm = TM_SUB; break;
+    case OP_MUL: tm = TM_MUL; break;
+    case OP_DIV: tm = TM_DIV; break;
+    case OP_MOD: tm = TM_MOD; break;
+    case OP_POW: tm = TM_POW; break;
+    case OP_UNM: tm = TM_UNM; break;
+    case OP_LEN: tm = TM_LEN; break;
+    case OP_LT: tm = TM_LT; break;
+    case OP_LE: tm = TM_LE; break;
+    case OP_CONCAT: tm = TM_CONCAT; break;
+    default:
+      return NULL;  /* else no useful name can be found */
+  }
+  *name = getstr(G(L)->tmname[tm]);
+  return "metamethod";
+}
+
+/* }====================================================== */
+
+
+
+/*
+** only ANSI way to check whether a pointer points to an array
+** (used only for error messages, so efficiency is not a big concern)
+*/
+static int isinstack (CallInfo *ci, const TValue *o) {
+  StkId p;
+  for (p = ci->u.l.base; p < ci->top; p++)
+    if (o == p) return 1;
+  return 0;
+}
+
+
+static const char *getupvalname (CallInfo *ci, const TValue *o,
+                                 const char **name) {
+  LClosure *c = ci_func(ci);
+  int i;
+  for (i = 0; i < c->nupvalues; i++) {
+    if (c->upvals[i]->v == o) {
+      *name = upvalname(c->p, i);
+      return "upvalue";
+    }
+  }
+  return NULL;
+}
+
+
+l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
+  CallInfo *ci = L->ci;
+  const char *name = NULL;
+  const char *t = objtypename(o);
+  const char *kind = NULL;
+  if (isLua(ci)) {
+    kind = getupvalname(ci, o, &name);  /* check whether 'o' is an upvalue */
+    if (!kind && isinstack(ci, o))  /* no? try a register */
+      kind = getobjname(ci_func(ci)->p, currentpc(ci),
+                        cast_int(o - ci->u.l.base), &name);
+  }
+  if (kind)
+    luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",
+                op, kind, name, t);
+  else
+    luaG_runerror(L, "attempt to %s a %s value", op, t);
+}
+
+
+l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
+  if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
+  lua_assert(!ttisstring(p1) && !ttisnumber(p1));
+  luaG_typeerror(L, p1, "concatenate");
+}
+
+
+l_noret luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {
+  TValue temp;
+  if (luaV_tonumber(p1, &temp) == NULL)
+    p2 = p1;  /* first operand is wrong */
+  luaG_typeerror(L, p2, "perform arithmetic on");
+}
+
+
+l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
+  const char *t1 = objtypename(p1);
+  const char *t2 = objtypename(p2);
+  if (t1 == t2)
+    luaG_runerror(L, "attempt to compare two %s values", t1);
+  else
+    luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
+}
+
+
+static void addinfo (lua_State *L, const char *msg) {
+  CallInfo *ci = L->ci;
+  if (isLua(ci)) {  /* is Lua code? */
+    char buff[LUA_IDSIZE];  /* add file:line information */
+    int line = currentline(ci);
+    TString *src = ci_func(ci)->p->source;
+    if (src)
+      luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
+    else {  /* no source available; use "?" instead */
+      buff[0] = '?'; buff[1] = '\0';
+    }
+    luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
+  }
+}
+
+
+l_noret luaG_errormsg (lua_State *L) {
+  if (L->errfunc != 0) {  /* is there an error handling function? */
+    StkId errfunc = restorestack(L, L->errfunc);
+    if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
+    setobjs2s(L, L->top, L->top - 1);  /* move argument */
+    setobjs2s(L, L->top - 1, errfunc);  /* push function */
+    L->top++;
+    luaD_call(L, L->top - 2, 1, 0);  /* call it */
+  }
+  luaD_throw(L, LUA_ERRRUN);
+}
+
+
+l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
+  va_list argp;
+  va_start(argp, fmt);
+  addinfo(L, luaO_pushvfstring(L, fmt, argp));
+  va_end(argp);
+  luaG_errormsg(L);
+}
+

=== added file 'src/scripting/eris/ldebug.h'
--- src/scripting/eris/ldebug.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/ldebug.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,34 @@
+/*
+** $Id: ldebug.h,v 2.7 2011/10/07 20:45:19 roberto Exp $
+** Auxiliary functions from Debug Interface module
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ldebug_h
+#define ldebug_h
+
+
+#include "lstate.h"
+
+
+#define pcRel(pc, p)	(cast(int, (pc) - (p)->code) - 1)
+
+#define getfuncline(f,pc)	(((f)->lineinfo) ? (f)->lineinfo[pc] : 0)
+
+#define resethookcount(L)	(L->hookcount = L->basehookcount)
+
+/* Active Lua function (given call info) */
+#define ci_func(ci)		(clLvalue((ci)->func))
+
+
+LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
+                                                const char *opname);
+LUAI_FUNC l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2);
+LUAI_FUNC l_noret luaG_aritherror (lua_State *L, const TValue *p1,
+                                                 const TValue *p2);
+LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
+                                                 const TValue *p2);
+LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
+LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
+
+#endif

=== added file 'src/scripting/eris/ldo.c'
--- src/scripting/eris/ldo.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/ldo.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,673 @@
+/*
+** $Id: ldo.c,v 2.108 2012/10/01 14:05:04 roberto Exp $
+** Stack and Call structure of Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#include <setjmp.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ldo_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lundump.h"
+#include "lvm.h"
+#include "lzio.h"
+
+
+
+
+/*
+** {======================================================
+** Error-recovery functions
+** =======================================================
+*/
+
+/*
+** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By
+** default, Lua handles errors with exceptions when compiling as
+** C++ code, with _longjmp/_setjmp when asked to use them, and with
+** longjmp/setjmp otherwise.
+*/
+#if !defined(LUAI_THROW)
+
+#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP)
+/* C++ exceptions */
+#define LUAI_THROW(L,c)		throw(c)
+#define LUAI_TRY(L,c,a) \
+	try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; }
+#define luai_jmpbuf		int  /* dummy variable */
+
+#elif defined(LUA_USE_ULONGJMP)
+/* in Unix, try _longjmp/_setjmp (more efficient) */
+#define LUAI_THROW(L,c)		_longjmp((c)->b, 1)
+#define LUAI_TRY(L,c,a)		if (_setjmp((c)->b) == 0) { a }
+#define luai_jmpbuf		jmp_buf
+
+#else
+/* default handling with long jumps */
+#define LUAI_THROW(L,c)		longjmp((c)->b, 1)
+#define LUAI_TRY(L,c,a)		if (setjmp((c)->b) == 0) { a }
+#define luai_jmpbuf		jmp_buf
+
+#endif
+
+#endif
+
+
+
+/* chain list of long jump buffers */
+struct lua_longjmp {
+  struct lua_longjmp *previous;
+  luai_jmpbuf b;
+  volatile int status;  /* error code */
+};
+
+
+static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
+  switch (errcode) {
+    case LUA_ERRMEM: {  /* memory error? */
+      setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
+      break;
+    }
+    case LUA_ERRERR: {
+      setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
+      break;
+    }
+    default: {
+      setobjs2s(L, oldtop, L->top - 1);  /* error message on current top */
+      break;
+    }
+  }
+  L->top = oldtop + 1;
+}
+
+
+l_noret luaD_throw (lua_State *L, int errcode) {
+  if (L->errorJmp) {  /* thread has an error handler? */
+    L->errorJmp->status = errcode;  /* set status */
+    LUAI_THROW(L, L->errorJmp);  /* jump to it */
+  }
+  else {  /* thread has no error handler */
+    L->status = cast_byte(errcode);  /* mark it as dead */
+    if (G(L)->mainthread->errorJmp) {  /* main thread has a handler? */
+      setobjs2s(L, G(L)->mainthread->top++, L->top - 1);  /* copy error obj. */
+      luaD_throw(G(L)->mainthread, errcode);  /* re-throw in main thread */
+    }
+    else {  /* no handler at all; abort */
+      if (G(L)->panic) {  /* panic function? */
+        lua_unlock(L);
+        G(L)->panic(L);  /* call it (last chance to jump out) */
+      }
+      abort();
+    }
+  }
+}
+
+
+int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
+  unsigned short oldnCcalls = L->nCcalls;
+  struct lua_longjmp lj;
+  lj.status = LUA_OK;
+  lj.previous = L->errorJmp;  /* chain new error handler */
+  L->errorJmp = &lj;
+  LUAI_TRY(L, &lj,
+    (*f)(L, ud);
+  );
+  L->errorJmp = lj.previous;  /* restore old error handler */
+  L->nCcalls = oldnCcalls;
+  return lj.status;
+}
+
+/* }====================================================== */
+
+
+static void correctstack (lua_State *L, TValue *oldstack) {
+  CallInfo *ci;
+  GCObject *up;
+  L->top = (L->top - oldstack) + L->stack;
+  for (up = L->openupval; up != NULL; up = up->gch.next)
+    gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
+  for (ci = L->ci; ci != NULL; ci = ci->previous) {
+    ci->top = (ci->top - oldstack) + L->stack;
+    ci->func = (ci->func - oldstack) + L->stack;
+    if (isLua(ci))
+      ci->u.l.base = (ci->u.l.base - oldstack) + L->stack;
+  }
+}
+
+
+/* some space for error handling */
+#define ERRORSTACKSIZE	(LUAI_MAXSTACK + 200)
+
+
+void luaD_reallocstack (lua_State *L, int newsize) {
+  TValue *oldstack = L->stack;
+  int lim = L->stacksize;
+  lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
+  lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
+  luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue);
+  for (; lim < newsize; lim++)
+    setnilvalue(L->stack + lim); /* erase new segment */
+  L->stacksize = newsize;
+  L->stack_last = L->stack + newsize - EXTRA_STACK;
+  correctstack(L, oldstack);
+}
+
+
+void luaD_growstack (lua_State *L, int n) {
+  int size = L->stacksize;
+  if (size > LUAI_MAXSTACK)  /* error after extra size? */
+    luaD_throw(L, LUA_ERRERR);
+  else {
+    int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;
+    int newsize = 2 * size;
+    if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;
+    if (newsize < needed) newsize = needed;
+    if (newsize > LUAI_MAXSTACK) {  /* stack overflow? */
+      luaD_reallocstack(L, ERRORSTACKSIZE);
+      luaG_runerror(L, "stack overflow");
+    }
+    else
+      luaD_reallocstack(L, newsize);
+  }
+}
+
+
+static int stackinuse (lua_State *L) {
+  CallInfo *ci;
+  StkId lim = L->top;
+  for (ci = L->ci; ci != NULL; ci = ci->previous) {
+    lua_assert(ci->top <= L->stack_last);
+    if (lim < ci->top) lim = ci->top;
+  }
+  return cast_int(lim - L->stack) + 1;  /* part of stack in use */
+}
+
+
+void luaD_shrinkstack (lua_State *L) {
+  int inuse = stackinuse(L);
+  int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
+  if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
+  if (inuse > LUAI_MAXSTACK ||  /* handling stack overflow? */
+      goodsize >= L->stacksize)  /* would grow instead of shrink? */
+    condmovestack(L);  /* don't change stack (change only for debugging) */
+  else
+    luaD_reallocstack(L, goodsize);  /* shrink it */
+}
+
+
+void luaD_hook (lua_State *L, int event, int line) {
+  lua_Hook hook = L->hook;
+  if (hook && L->allowhook) {
+    CallInfo *ci = L->ci;
+    ptrdiff_t top = savestack(L, L->top);
+    ptrdiff_t ci_top = savestack(L, ci->top);
+    lua_Debug ar;
+    ar.event = event;
+    ar.currentline = line;
+    ar.i_ci = ci;
+    luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
+    ci->top = L->top + LUA_MINSTACK;
+    lua_assert(ci->top <= L->stack_last);
+    L->allowhook = 0;  /* cannot call hooks inside a hook */
+    ci->callstatus |= CIST_HOOKED;
+    lua_unlock(L);
+    (*hook)(L, &ar);
+    lua_lock(L);
+    lua_assert(!L->allowhook);
+    L->allowhook = 1;
+    ci->top = restorestack(L, ci_top);
+    L->top = restorestack(L, top);
+    ci->callstatus &= ~CIST_HOOKED;
+  }
+}
+
+
+static void callhook (lua_State *L, CallInfo *ci) {
+  int hook = LUA_HOOKCALL;
+  ci->u.l.savedpc++;  /* hooks assume 'pc' is already incremented */
+  if (isLua(ci->previous) &&
+      GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {
+    ci->callstatus |= CIST_TAIL;
+    hook = LUA_HOOKTAILCALL;
+  }
+  luaD_hook(L, hook, -1);
+  ci->u.l.savedpc--;  /* correct 'pc' */
+}
+
+
+static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
+  int i;
+  int nfixargs = p->numparams;
+  StkId base, fixed;
+  lua_assert(actual >= nfixargs);
+  /* move fixed parameters to final position */
+  fixed = L->top - actual;  /* first fixed argument */
+  base = L->top;  /* final position of first argument */
+  for (i=0; i<nfixargs; i++) {
+    setobjs2s(L, L->top++, fixed + i);
+    setnilvalue(fixed + i);
+  }
+  return base;
+}
+
+
+static StkId tryfuncTM (lua_State *L, StkId func) {
+  const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
+  StkId p;
+  ptrdiff_t funcr = savestack(L, func);
+  if (!ttisfunction(tm))
+    luaG_typeerror(L, func, "call");
+  /* Open a hole inside the stack at `func' */
+  for (p = L->top; p > func; p--) setobjs2s(L, p, p-1);
+  incr_top(L);
+  func = restorestack(L, funcr);  /* previous call may change stack */
+  setobj2s(L, func, tm);  /* tag method is the new function to be called */
+  return func;
+}
+
+
+
+#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
+
+
+/*
+** returns true if function has been executed (C function)
+*/
+int luaD_precall (lua_State *L, StkId func, int nresults) {
+  lua_CFunction f;
+  CallInfo *ci;
+  int n;  /* number of arguments (Lua) or returns (C) */
+  ptrdiff_t funcr = savestack(L, func);
+  switch (ttype(func)) {
+    case LUA_TLCF:  /* light C function */
+      f = fvalue(func);
+      goto Cfunc;
+    case LUA_TCCL: {  /* C closure */
+      f = clCvalue(func)->f;
+     Cfunc:
+      luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
+      ci = next_ci(L);  /* now 'enter' new function */
+      ci->nresults = nresults;
+      ci->func = restorestack(L, funcr);
+      ci->top = L->top + LUA_MINSTACK;
+      lua_assert(ci->top <= L->stack_last);
+      ci->callstatus = 0;
+      luaC_checkGC(L);  /* stack grow uses memory */
+      if (L->hookmask & LUA_MASKCALL)
+        luaD_hook(L, LUA_HOOKCALL, -1);
+      lua_unlock(L);
+      n = (*f)(L);  /* do the actual call */
+      lua_lock(L);
+      api_checknelems(L, n);
+      luaD_poscall(L, L->top - n);
+      return 1;
+    }
+    case LUA_TLCL: {  /* Lua function: prepare its call */
+      StkId base;
+      Proto *p = clLvalue(func)->p;
+      luaD_checkstack(L, p->maxstacksize + p->numparams);
+      func = restorestack(L, funcr);
+      n = cast_int(L->top - func) - 1;  /* number of real arguments */
+      for (; n < p->numparams; n++)
+        setnilvalue(L->top++);  /* complete missing arguments */
+      base = (!p->is_vararg) ? func + 1 : adjust_varargs(L, p, n);
+      ci = next_ci(L);  /* now 'enter' new function */
+      ci->nresults = nresults;
+      ci->func = func;
+      ci->u.l.base = base;
+      ci->top = base + p->maxstacksize;
+      lua_assert(ci->top <= L->stack_last);
+      ci->u.l.savedpc = p->code;  /* starting point */
+      ci->callstatus = CIST_LUA;
+      L->top = ci->top;
+      luaC_checkGC(L);  /* stack grow uses memory */
+      if (L->hookmask & LUA_MASKCALL)
+        callhook(L, ci);
+      return 0;
+    }
+    default: {  /* not a function */
+      func = tryfuncTM(L, func);  /* retry with 'function' tag method */
+      return luaD_precall(L, func, nresults);  /* now it must be a function */
+    }
+  }
+}
+
+
+int luaD_poscall (lua_State *L, StkId firstResult) {
+  StkId res;
+  int wanted, i;
+  CallInfo *ci = L->ci;
+  if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
+    if (L->hookmask & LUA_MASKRET) {
+      ptrdiff_t fr = savestack(L, firstResult);  /* hook may change stack */
+      luaD_hook(L, LUA_HOOKRET, -1);
+      firstResult = restorestack(L, fr);
+    }
+    L->oldpc = ci->previous->u.l.savedpc;  /* 'oldpc' for caller function */
+  }
+  res = ci->func;  /* res == final position of 1st result */
+  wanted = ci->nresults;
+  L->ci = ci = ci->previous;  /* back to caller */
+  /* move results to correct place */
+  for (i = wanted; i != 0 && firstResult < L->top; i--)
+    setobjs2s(L, res++, firstResult++);
+  while (i-- > 0)
+    setnilvalue(res++);
+  L->top = res;
+  return (wanted - LUA_MULTRET);  /* 0 iff wanted == LUA_MULTRET */
+}
+
+
+/*
+** Call a function (C or Lua). The function to be called is at *func.
+** The arguments are on the stack, right after the function.
+** When returns, all the results are on the stack, starting at the original
+** function position.
+*/
+void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
+  if (++L->nCcalls >= LUAI_MAXCCALLS) {
+    if (L->nCcalls == LUAI_MAXCCALLS)
+      luaG_runerror(L, "C stack overflow");
+    else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
+      luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */
+  }
+  if (!allowyield) L->nny++;
+  if (!luaD_precall(L, func, nResults))  /* is a Lua function? */
+    luaV_execute(L);  /* call it */
+  if (!allowyield) L->nny--;
+  L->nCcalls--;
+}
+
+
+static void finishCcall (lua_State *L) {
+  CallInfo *ci = L->ci;
+  int n;
+  lua_assert(ci->u.c.k != NULL);  /* must have a continuation */
+  lua_assert(L->nny == 0);
+  if (ci->callstatus & CIST_YPCALL) {  /* was inside a pcall? */
+    ci->callstatus &= ~CIST_YPCALL;  /* finish 'lua_pcall' */
+    L->errfunc = ci->u.c.old_errfunc;
+  }
+  /* finish 'lua_callk'/'lua_pcall' */
+  adjustresults(L, ci->nresults);
+  /* call continuation function */
+  if (!(ci->callstatus & CIST_STAT))  /* no call status? */
+    ci->u.c.status = LUA_YIELD;  /* 'default' status */
+  lua_assert(ci->u.c.status != LUA_OK);
+  ci->callstatus = (ci->callstatus & ~(CIST_YPCALL | CIST_STAT)) | CIST_YIELDED;
+  lua_unlock(L);
+  n = (*ci->u.c.k)(L);
+  lua_lock(L);
+  api_checknelems(L, n);
+  /* finish 'luaD_precall' */
+  luaD_poscall(L, L->top - n);
+}
+
+
+static void unroll (lua_State *L, void *ud) {
+  UNUSED(ud);
+  for (;;) {
+    if (L->ci == &L->base_ci)  /* stack is empty? */
+      return;  /* coroutine finished normally */
+    if (!isLua(L->ci))  /* C function? */
+      finishCcall(L);
+    else {  /* Lua function */
+      luaV_finishOp(L);  /* finish interrupted instruction */
+      luaV_execute(L);  /* execute down to higher C 'boundary' */
+    }
+  }
+}
+
+
+/*
+** check whether thread has a suspended protected call
+*/
+static CallInfo *findpcall (lua_State *L) {
+  CallInfo *ci;
+  for (ci = L->ci; ci != NULL; ci = ci->previous) {  /* search for a pcall */
+    if (ci->callstatus & CIST_YPCALL)
+      return ci;
+  }
+  return NULL;  /* no pending pcall */
+}
+
+
+static int recover (lua_State *L, int status) {
+  StkId oldtop;
+  CallInfo *ci = findpcall(L);
+  if (ci == NULL) return 0;  /* no recovery point */
+  /* "finish" luaD_pcall */
+  oldtop = restorestack(L, ci->extra);
+  luaF_close(L, oldtop);
+  seterrorobj(L, status, oldtop);
+  L->ci = ci;
+  L->allowhook = ci->u.c.old_allowhook;
+  L->nny = 0;  /* should be zero to be yieldable */
+  luaD_shrinkstack(L);
+  L->errfunc = ci->u.c.old_errfunc;
+  ci->callstatus |= CIST_STAT;  /* call has error status */
+  ci->u.c.status = status;  /* (here it is) */
+  return 1;  /* continue running the coroutine */
+}
+
+
+/*
+** signal an error in the call to 'resume', not in the execution of the
+** coroutine itself. (Such errors should not be handled by any coroutine
+** error handler and should not kill the coroutine.)
+*/
+static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
+  L->top = firstArg;  /* remove args from the stack */
+  setsvalue2s(L, L->top, luaS_new(L, msg));  /* push error message */
+  api_incr_top(L);
+  luaD_throw(L, -1);  /* jump back to 'lua_resume' */
+}
+
+
+/*
+** do the work for 'lua_resume' in protected mode
+*/
+static void resume (lua_State *L, void *ud) {
+  int nCcalls = L->nCcalls;
+  StkId firstArg = cast(StkId, ud);
+  CallInfo *ci = L->ci;
+  if (nCcalls >= LUAI_MAXCCALLS)
+    resume_error(L, "C stack overflow", firstArg);
+  if (L->status == LUA_OK) {  /* may be starting a coroutine */
+    if (ci != &L->base_ci)  /* not in base level? */
+      resume_error(L, "cannot resume non-suspended coroutine", firstArg);
+    /* coroutine is in base level; start running it */
+    if (!luaD_precall(L, firstArg - 1, LUA_MULTRET))  /* Lua function? */
+      luaV_execute(L);  /* call it */
+  }
+  else if (L->status != LUA_YIELD)
+    resume_error(L, "cannot resume dead coroutine", firstArg);
+  else {  /* resuming from previous yield */
+    L->status = LUA_OK;
+    ci->func = restorestack(L, ci->extra);
+    if (isLua(ci))  /* yielded inside a hook? */
+      luaV_execute(L);  /* just continue running Lua code */
+    else {  /* 'common' yield */
+      if (ci->u.c.k != NULL) {  /* does it have a continuation? */
+        int n;
+        ci->u.c.status = LUA_YIELD;  /* 'default' status */
+        ci->callstatus |= CIST_YIELDED;
+        lua_unlock(L);
+        n = (*ci->u.c.k)(L);  /* call continuation */
+        lua_lock(L);
+        api_checknelems(L, n);
+        firstArg = L->top - n;  /* yield results come from continuation */
+      }
+      luaD_poscall(L, firstArg);  /* finish 'luaD_precall' */
+    }
+    unroll(L, NULL);
+  }
+  lua_assert(nCcalls == L->nCcalls);
+}
+
+
+LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
+  int status;
+  lua_lock(L);
+  luai_userstateresume(L, nargs);
+  L->nCcalls = (from) ? from->nCcalls + 1 : 1;
+  L->nny = 0;  /* allow yields */
+  api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
+  status = luaD_rawrunprotected(L, resume, L->top - nargs);
+  if (status == -1)  /* error calling 'lua_resume'? */
+    status = LUA_ERRRUN;
+  else {  /* yield or regular error */
+    while (status != LUA_OK && status != LUA_YIELD) {  /* error? */
+      if (recover(L, status))  /* recover point? */
+        status = luaD_rawrunprotected(L, unroll, NULL);  /* run continuation */
+      else {  /* unrecoverable error */
+        L->status = cast_byte(status);  /* mark thread as `dead' */
+        seterrorobj(L, status, L->top);
+        L->ci->top = L->top;
+        break;
+      }
+    }
+    lua_assert(status == L->status);
+  }
+  L->nny = 1;  /* do not allow yields */
+  L->nCcalls--;
+  lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
+  lua_unlock(L);
+  return status;
+}
+
+
+LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
+  CallInfo *ci = L->ci;
+  luai_userstateyield(L, nresults);
+  lua_lock(L);
+  api_checknelems(L, nresults);
+  if (L->nny > 0) {
+    if (L != G(L)->mainthread)
+      luaG_runerror(L, "attempt to yield across a C-call boundary");
+    else
+      luaG_runerror(L, "attempt to yield from outside a coroutine");
+  }
+  L->status = LUA_YIELD;
+  ci->extra = savestack(L, ci->func);  /* save current 'func' */
+  if (isLua(ci)) {  /* inside a hook? */
+    api_check(L, k == NULL, "hooks cannot continue after yielding");
+  }
+  else {
+    if ((ci->u.c.k = k) != NULL)  /* is there a continuation? */
+      ci->u.c.ctx = ctx;  /* save context */
+    ci->func = L->top - nresults - 1;  /* protect stack below results */
+    luaD_throw(L, LUA_YIELD);
+  }
+  lua_assert(ci->callstatus & CIST_HOOKED);  /* must be inside a hook */
+  lua_unlock(L);
+  return 0;  /* return to 'luaD_hook' */
+}
+
+
+int luaD_pcall (lua_State *L, Pfunc func, void *u,
+                ptrdiff_t old_top, ptrdiff_t ef) {
+  int status;
+  CallInfo *old_ci = L->ci;
+  lu_byte old_allowhooks = L->allowhook;
+  unsigned short old_nny = L->nny;
+  ptrdiff_t old_errfunc = L->errfunc;
+  L->errfunc = ef;
+  status = luaD_rawrunprotected(L, func, u);
+  if (status != LUA_OK) {  /* an error occurred? */
+    StkId oldtop = restorestack(L, old_top);
+    luaF_close(L, oldtop);  /* close possible pending closures */
+    seterrorobj(L, status, oldtop);
+    L->ci = old_ci;
+    L->allowhook = old_allowhooks;
+    L->nny = old_nny;
+    luaD_shrinkstack(L);
+  }
+  L->errfunc = old_errfunc;
+  return status;
+}
+
+
+
+/*
+** Execute a protected parser.
+*/
+struct SParser {  /* data to `f_parser' */
+  ZIO *z;
+  Mbuffer buff;  /* dynamic structure used by the scanner */
+  Dyndata dyd;  /* dynamic structures used by the parser */
+  const char *mode;
+  const char *name;
+};
+
+
+static void checkmode (lua_State *L, const char *mode, const char *x) {
+  if (mode && strchr(mode, x[0]) == NULL) {
+    luaO_pushfstring(L,
+       "attempt to load a %s chunk (mode is " LUA_QS ")", x, mode);
+    luaD_throw(L, LUA_ERRSYNTAX);
+  }
+}
+
+
+static void f_parser (lua_State *L, void *ud) {
+  int i;
+  Closure *cl;
+  struct SParser *p = cast(struct SParser *, ud);
+  int c = zgetc(p->z);  /* read first character */
+  if (c == LUA_SIGNATURE[0]) {
+    checkmode(L, p->mode, "binary");
+    cl = luaU_undump(L, p->z, &p->buff, p->name);
+  }
+  else {
+    checkmode(L, p->mode, "text");
+    cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
+  }
+  lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
+  for (i = 0; i < cl->l.nupvalues; i++) {  /* initialize upvalues */
+    UpVal *up = luaF_newupval(L);
+    cl->l.upvals[i] = up;
+    luaC_objbarrier(L, cl, up);
+  }
+}
+
+
+int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
+                                        const char *mode) {
+  struct SParser p;
+  int status;
+  L->nny++;  /* cannot yield during parsing */
+  p.z = z; p.name = name; p.mode = mode;
+  p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0;
+  p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
+  p.dyd.label.arr = NULL; p.dyd.label.size = 0;
+  luaZ_initbuffer(L, &p.buff);
+  status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
+  luaZ_freebuffer(L, &p.buff);
+  luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
+  luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
+  luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size);
+  L->nny--;
+  return status;
+}
+
+

=== added file 'src/scripting/eris/ldo.h'
--- src/scripting/eris/ldo.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/ldo.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,46 @@
+/*
+** $Id: ldo.h,v 2.20 2011/11/29 15:55:08 roberto Exp $
+** Stack and Call structure of Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ldo_h
+#define ldo_h
+
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lzio.h"
+
+
+#define luaD_checkstack(L,n)	if (L->stack_last - L->top <= (n)) \
+				    luaD_growstack(L, n); else condmovestack(L);
+
+
+#define incr_top(L) {L->top++; luaD_checkstack(L,0);}
+
+#define savestack(L,p)		((char *)(p) - (char *)L->stack)
+#define restorestack(L,n)	((TValue *)((char *)L->stack + (n)))
+
+
+/* type of protected functions, to be ran by `runprotected' */
+typedef void (*Pfunc) (lua_State *L, void *ud);
+
+LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
+                                                  const char *mode);
+LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
+LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
+LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults,
+                                        int allowyield);
+LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
+                                        ptrdiff_t oldtop, ptrdiff_t ef);
+LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
+LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
+LUAI_FUNC void luaD_growstack (lua_State *L, int n);
+LUAI_FUNC void luaD_shrinkstack (lua_State *L);
+
+LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
+LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
+
+#endif
+

=== added file 'src/scripting/eris/ldump.c'
--- src/scripting/eris/ldump.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/ldump.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,173 @@
+/*
+** $Id: ldump.c,v 2.17 2012/01/23 23:02:10 roberto Exp $
+** save precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#include <stddef.h>
+
+#define ldump_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lundump.h"
+
+typedef struct {
+ lua_State* L;
+ lua_Writer writer;
+ void* data;
+ int strip;
+ int status;
+} DumpState;
+
+#define DumpMem(b,n,size,D)	DumpBlock(b,(n)*(size),D)
+#define DumpVar(x,D)		DumpMem(&x,1,sizeof(x),D)
+
+static void DumpBlock(const void* b, size_t size, DumpState* D)
+{
+ if (D->status==0)
+ {
+  lua_unlock(D->L);
+  D->status=(*D->writer)(D->L,b,size,D->data);
+  lua_lock(D->L);
+ }
+}
+
+static void DumpChar(int y, DumpState* D)
+{
+ char x=(char)y;
+ DumpVar(x,D);
+}
+
+static void DumpInt(int x, DumpState* D)
+{
+ DumpVar(x,D);
+}
+
+static void DumpNumber(lua_Number x, DumpState* D)
+{
+ DumpVar(x,D);
+}
+
+static void DumpVector(const void* b, int n, size_t size, DumpState* D)
+{
+ DumpInt(n,D);
+ DumpMem(b,n,size,D);
+}
+
+static void DumpString(const TString* s, DumpState* D)
+{
+ if (s==NULL)
+ {
+  size_t size=0;
+  DumpVar(size,D);
+ }
+ else
+ {
+  size_t size=s->tsv.len+1;		/* include trailing '\0' */
+  DumpVar(size,D);
+  DumpBlock(getstr(s),size*sizeof(char),D);
+ }
+}
+
+#define DumpCode(f,D)	 DumpVector(f->code,f->sizecode,sizeof(Instruction),D)
+
+static void DumpFunction(const Proto* f, DumpState* D);
+
+static void DumpConstants(const Proto* f, DumpState* D)
+{
+ int i,n=f->sizek;
+ DumpInt(n,D);
+ for (i=0; i<n; i++)
+ {
+  const TValue* o=&f->k[i];
+  DumpChar(ttypenv(o),D);
+  switch (ttypenv(o))
+  {
+   case LUA_TNIL:
+	break;
+   case LUA_TBOOLEAN:
+	DumpChar(bvalue(o),D);
+	break;
+   case LUA_TNUMBER:
+	DumpNumber(nvalue(o),D);
+	break;
+   case LUA_TSTRING:
+	DumpString(rawtsvalue(o),D);
+	break;
+    default: lua_assert(0);
+  }
+ }
+ n=f->sizep;
+ DumpInt(n,D);
+ for (i=0; i<n; i++) DumpFunction(f->p[i],D);
+}
+
+static void DumpUpvalues(const Proto* f, DumpState* D)
+{
+ int i,n=f->sizeupvalues;
+ DumpInt(n,D);
+ for (i=0; i<n; i++)
+ {
+  DumpChar(f->upvalues[i].instack,D);
+  DumpChar(f->upvalues[i].idx,D);
+ }
+}
+
+static void DumpDebug(const Proto* f, DumpState* D)
+{
+ int i,n;
+ DumpString((D->strip) ? NULL : f->source,D);
+ n= (D->strip) ? 0 : f->sizelineinfo;
+ DumpVector(f->lineinfo,n,sizeof(int),D);
+ n= (D->strip) ? 0 : f->sizelocvars;
+ DumpInt(n,D);
+ for (i=0; i<n; i++)
+ {
+  DumpString(f->locvars[i].varname,D);
+  DumpInt(f->locvars[i].startpc,D);
+  DumpInt(f->locvars[i].endpc,D);
+ }
+ n= (D->strip) ? 0 : f->sizeupvalues;
+ DumpInt(n,D);
+ for (i=0; i<n; i++) DumpString(f->upvalues[i].name,D);
+}
+
+static void DumpFunction(const Proto* f, DumpState* D)
+{
+ DumpInt(f->linedefined,D);
+ DumpInt(f->lastlinedefined,D);
+ DumpChar(f->numparams,D);
+ DumpChar(f->is_vararg,D);
+ DumpChar(f->maxstacksize,D);
+ DumpCode(f,D);
+ DumpConstants(f,D);
+ DumpUpvalues(f,D);
+ DumpDebug(f,D);
+}
+
+static void DumpHeader(DumpState* D)
+{
+ lu_byte h[LUAC_HEADERSIZE];
+ luaU_header(h);
+ DumpBlock(h,LUAC_HEADERSIZE,D);
+}
+
+/*
+** dump Lua function as precompiled chunk
+*/
+int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
+{
+ DumpState D;
+ D.L=L;
+ D.writer=w;
+ D.data=data;
+ D.strip=strip;
+ D.status=0;
+ DumpHeader(&D);
+ DumpFunction(f,&D);
+ return D.status;
+}

=== added file 'src/scripting/eris/lfunc.c'
--- src/scripting/eris/lfunc.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lfunc.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,161 @@
+/*
+** $Id: lfunc.c,v 2.30 2012/10/03 12:36:46 roberto Exp $
+** Auxiliary functions to manipulate prototypes and closures
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stddef.h>
+
+#define lfunc_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+
+Closure *luaF_newCclosure (lua_State *L, int n) {
+  Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl;
+  c->c.nupvalues = cast_byte(n);
+  return c;
+}
+
+
+Closure *luaF_newLclosure (lua_State *L, int n) {
+  Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl;
+  c->l.p = NULL;
+  c->l.nupvalues = cast_byte(n);
+  while (n--) c->l.upvals[n] = NULL;
+  return c;
+}
+
+
+UpVal *luaF_newupval (lua_State *L) {
+  UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv;
+  uv->v = &uv->u.value;
+  setnilvalue(uv->v);
+  return uv;
+}
+
+
+UpVal *luaF_findupval (lua_State *L, StkId level) {
+  global_State *g = G(L);
+  GCObject **pp = &L->openupval;
+  UpVal *p;
+  UpVal *uv;
+  while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
+    GCObject *o = obj2gco(p);
+    lua_assert(p->v != &p->u.value);
+    lua_assert(!isold(o) || isold(obj2gco(L)));
+    if (p->v == level) {  /* found a corresponding upvalue? */
+      if (isdead(g, o))  /* is it dead? */
+        changewhite(o);  /* resurrect it */
+      return p;
+    }
+    pp = &p->next;
+  }
+  /* not found: create a new one */
+  uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv;
+  uv->v = level;  /* current value lives in the stack */
+  uv->u.l.prev = &g->uvhead;  /* double link it in `uvhead' list */
+  uv->u.l.next = g->uvhead.u.l.next;
+  uv->u.l.next->u.l.prev = uv;
+  g->uvhead.u.l.next = uv;
+  lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
+  return uv;
+}
+
+
+static void unlinkupval (UpVal *uv) {
+  lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
+  uv->u.l.next->u.l.prev = uv->u.l.prev;  /* remove from `uvhead' list */
+  uv->u.l.prev->u.l.next = uv->u.l.next;
+}
+
+
+void luaF_freeupval (lua_State *L, UpVal *uv) {
+  if (uv->v != &uv->u.value)  /* is it open? */
+    unlinkupval(uv);  /* remove from open list */
+  luaM_free(L, uv);  /* free upvalue */
+}
+
+
+void luaF_close (lua_State *L, StkId level) {
+  UpVal *uv;
+  global_State *g = G(L);
+  while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) {
+    GCObject *o = obj2gco(uv);
+    lua_assert(!isblack(o) && uv->v != &uv->u.value);
+    L->openupval = uv->next;  /* remove from `open' list */
+    if (isdead(g, o))
+      luaF_freeupval(L, uv);  /* free upvalue */
+    else {
+      unlinkupval(uv);  /* remove upvalue from 'uvhead' list */
+      setobj(L, &uv->u.value, uv->v);  /* move value to upvalue slot */
+      uv->v = &uv->u.value;  /* now current value lives here */
+      gch(o)->next = g->allgc;  /* link upvalue into 'allgc' list */
+      g->allgc = o;
+      luaC_checkupvalcolor(g, uv);
+    }
+  }
+}
+
+
+Proto *luaF_newproto (lua_State *L) {
+  Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p;
+  f->k = NULL;
+  f->sizek = 0;
+  f->p = NULL;
+  f->sizep = 0;
+  f->code = NULL;
+  f->cache = NULL;
+  f->sizecode = 0;
+  f->lineinfo = NULL;
+  f->sizelineinfo = 0;
+  f->upvalues = NULL;
+  f->sizeupvalues = 0;
+  f->numparams = 0;
+  f->is_vararg = 0;
+  f->maxstacksize = 0;
+  f->locvars = NULL;
+  f->sizelocvars = 0;
+  f->linedefined = 0;
+  f->lastlinedefined = 0;
+  f->source = NULL;
+  return f;
+}
+
+
+void luaF_freeproto (lua_State *L, Proto *f) {
+  luaM_freearray(L, f->code, f->sizecode);
+  luaM_freearray(L, f->p, f->sizep);
+  luaM_freearray(L, f->k, f->sizek);
+  luaM_freearray(L, f->lineinfo, f->sizelineinfo);
+  luaM_freearray(L, f->locvars, f->sizelocvars);
+  luaM_freearray(L, f->upvalues, f->sizeupvalues);
+  luaM_free(L, f);
+}
+
+
+/*
+** Look for n-th local variable at line `line' in function `func'.
+** Returns NULL if not found.
+*/
+const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
+  int i;
+  for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
+    if (pc < f->locvars[i].endpc) {  /* is variable active? */
+      local_number--;
+      if (local_number == 0)
+        return getstr(f->locvars[i].varname);
+    }
+  }
+  return NULL;  /* not found */
+}
+

=== added file 'src/scripting/eris/lfunc.h'
--- src/scripting/eris/lfunc.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lfunc.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,33 @@
+/*
+** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp $
+** Auxiliary functions to manipulate prototypes and closures
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lfunc_h
+#define lfunc_h
+
+
+#include "lobject.h"
+
+
+#define sizeCclosure(n)	(cast(int, sizeof(CClosure)) + \
+                         cast(int, sizeof(TValue)*((n)-1)))
+
+#define sizeLclosure(n)	(cast(int, sizeof(LClosure)) + \
+                         cast(int, sizeof(TValue *)*((n)-1)))
+
+
+LUAI_FUNC Proto *luaF_newproto (lua_State *L);
+LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems);
+LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);
+LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
+LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
+LUAI_FUNC void luaF_close (lua_State *L, StkId level);
+LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
+LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
+LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
+                                         int pc);
+
+
+#endif

=== added file 'src/scripting/eris/lgc.c'
--- src/scripting/eris/lgc.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lgc.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,1220 @@
+/*
+** $Id: lgc.c,v 2.140 2013/03/16 21:10:18 roberto Exp $
+** Garbage Collector
+** See Copyright Notice in lua.h
+*/
+
+#include <string.h>
+
+#define lgc_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+
+/*
+** cost of sweeping one element (the size of a small object divided
+** by some adjust for the sweep speed)
+*/
+#define GCSWEEPCOST	((sizeof(TString) + 4) / 4)
+
+/* maximum number of elements to sweep in each single step */
+#define GCSWEEPMAX	(cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))
+
+/* maximum number of finalizers to call in each GC step */
+#define GCFINALIZENUM	4
+
+
+/*
+** macro to adjust 'stepmul': 'stepmul' is actually used like
+** 'stepmul / STEPMULADJ' (value chosen by tests)
+*/
+#define STEPMULADJ		200
+
+
+/*
+** macro to adjust 'pause': 'pause' is actually used like
+** 'pause / PAUSEADJ' (value chosen by tests)
+*/
+#define PAUSEADJ		100
+
+
+/*
+** 'makewhite' erases all color bits plus the old bit and then
+** sets only the current white bit
+*/
+#define maskcolors	(~(bit2mask(BLACKBIT, OLDBIT) | WHITEBITS))
+#define makewhite(g,x)	\
+ (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g)))
+
+#define white2gray(x)	resetbits(gch(x)->marked, WHITEBITS)
+#define black2gray(x)	resetbit(gch(x)->marked, BLACKBIT)
+
+
+#define isfinalized(x)		testbit(gch(x)->marked, FINALIZEDBIT)
+
+#define checkdeadkey(n)	lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n)))
+
+
+#define checkconsistency(obj)  \
+  lua_longassert(!iscollectable(obj) || righttt(obj))
+
+
+#define markvalue(g,o) { checkconsistency(o); \
+  if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
+
+#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \
+		reallymarkobject(g, obj2gco(t)); }
+
+static void reallymarkobject (global_State *g, GCObject *o);
+
+
+/*
+** {======================================================
+** Generic functions
+** =======================================================
+*/
+
+
+/*
+** one after last element in a hash array
+*/
+#define gnodelast(h)	gnode(h, cast(size_t, sizenode(h)))
+
+
+/*
+** link table 'h' into list pointed by 'p'
+*/
+#define linktable(h,p)	((h)->gclist = *(p), *(p) = obj2gco(h))
+
+
+/*
+** if key is not marked, mark its entry as dead (therefore removing it
+** from the table)
+*/
+static void removeentry (Node *n) {
+  lua_assert(ttisnil(gval(n)));
+  if (valiswhite(gkey(n)))
+    setdeadvalue(gkey(n));  /* unused and unmarked key; remove it */
+}
+
+
+/*
+** tells whether a key or value can be cleared from a weak
+** table. Non-collectable objects are never removed from weak
+** tables. Strings behave as `values', so are never removed too. for
+** other objects: if really collected, cannot keep them; for objects
+** being finalized, keep them in keys, but not in values
+*/
+static int iscleared (global_State *g, const TValue *o) {
+  if (!iscollectable(o)) return 0;
+  else if (ttisstring(o)) {
+    markobject(g, rawtsvalue(o));  /* strings are `values', so are never weak */
+    return 0;
+  }
+  else return iswhite(gcvalue(o));
+}
+
+
+/*
+** barrier that moves collector forward, that is, mark the white object
+** being pointed by a black object.
+*/
+void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
+  global_State *g = G(L);
+  lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
+  lua_assert(g->gcstate != GCSpause);
+  lua_assert(gch(o)->tt != LUA_TTABLE);
+  if (keepinvariantout(g))  /* must keep invariant? */
+    reallymarkobject(g, v);  /* restore invariant */
+  else {  /* sweep phase */
+    lua_assert(issweepphase(g));
+    makewhite(g, o);  /* mark main obj. as white to avoid other barriers */
+  }
+}
+
+
+/*
+** barrier that moves collector backward, that is, mark the black object
+** pointing to a white object as gray again. (Current implementation
+** only works for tables; access to 'gclist' is not uniform across
+** different types.)
+*/
+void luaC_barrierback_ (lua_State *L, GCObject *o) {
+  global_State *g = G(L);
+  lua_assert(isblack(o) && !isdead(g, o) && gch(o)->tt == LUA_TTABLE);
+  black2gray(o);  /* make object gray (again) */
+  gco2t(o)->gclist = g->grayagain;
+  g->grayagain = o;
+}
+
+
+/*
+** barrier for prototypes. When creating first closure (cache is
+** NULL), use a forward barrier; this may be the only closure of the
+** prototype (if it is a "regular" function, with a single instance)
+** and the prototype may be big, so it is better to avoid traversing
+** it again. Otherwise, use a backward barrier, to avoid marking all
+** possible instances.
+*/
+LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c) {
+  global_State *g = G(L);
+  lua_assert(isblack(obj2gco(p)));
+  if (p->cache == NULL) {  /* first time? */
+    luaC_objbarrier(L, p, c);
+  }
+  else {  /* use a backward barrier */
+    black2gray(obj2gco(p));  /* make prototype gray (again) */
+    p->gclist = g->grayagain;
+    g->grayagain = obj2gco(p);
+  }
+}
+
+
+/*
+** check color (and invariants) for an upvalue that was closed,
+** i.e., moved into the 'allgc' list
+*/
+void luaC_checkupvalcolor (global_State *g, UpVal *uv) {
+  GCObject *o = obj2gco(uv);
+  lua_assert(!isblack(o));  /* open upvalues are never black */
+  if (isgray(o)) {
+    if (keepinvariant(g)) {
+      resetoldbit(o);  /* see MOVE OLD rule */
+      gray2black(o);  /* it is being visited now */
+      markvalue(g, uv->v);
+    }
+    else {
+      lua_assert(issweepphase(g));
+      makewhite(g, o);
+    }
+  }
+}
+
+
+/*
+** create a new collectable object (with given type and size) and link
+** it to '*list'. 'offset' tells how many bytes to allocate before the
+** object itself (used only by states).
+*/
+GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
+                       int offset) {
+  global_State *g = G(L);
+  char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz));
+  GCObject *o = obj2gco(raw + offset);
+  if (list == NULL)
+    list = &g->allgc;  /* standard list for collectable objects */
+  gch(o)->marked = luaC_white(g);
+  gch(o)->tt = tt;
+  gch(o)->next = *list;
+  *list = o;
+  return o;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** Mark functions
+** =======================================================
+*/
+
+
+/*
+** mark an object. Userdata, strings, and closed upvalues are visited
+** and turned black here. Other objects are marked gray and added
+** to appropriate list to be visited (and turned black) later. (Open
+** upvalues are already linked in 'headuv' list.)
+*/
+static void reallymarkobject (global_State *g, GCObject *o) {
+  lu_mem size;
+  white2gray(o);
+  switch (gch(o)->tt) {
+    case LUA_TSHRSTR:
+    case LUA_TLNGSTR: {
+      size = sizestring(gco2ts(o));
+      break;  /* nothing else to mark; make it black */
+    }
+    case LUA_TUSERDATA: {
+      Table *mt = gco2u(o)->metatable;
+      markobject(g, mt);
+      markobject(g, gco2u(o)->env);
+      size = sizeudata(gco2u(o));
+      break;
+    }
+    case LUA_TUPVAL: {
+      UpVal *uv = gco2uv(o);
+      markvalue(g, uv->v);
+      if (uv->v != &uv->u.value)  /* open? */
+        return;  /* open upvalues remain gray */
+      size = sizeof(UpVal);
+      break;
+    }
+    case LUA_TLCL: {
+      gco2lcl(o)->gclist = g->gray;
+      g->gray = o;
+      return;
+    }
+    case LUA_TCCL: {
+      gco2ccl(o)->gclist = g->gray;
+      g->gray = o;
+      return;
+    }
+    case LUA_TTABLE: {
+      linktable(gco2t(o), &g->gray);
+      return;
+    }
+    case LUA_TTHREAD: {
+      gco2th(o)->gclist = g->gray;
+      g->gray = o;
+      return;
+    }
+    case LUA_TPROTO: {
+      gco2p(o)->gclist = g->gray;
+      g->gray = o;
+      return;
+    }
+    default: lua_assert(0); return;
+  }
+  gray2black(o);
+  g->GCmemtrav += size;
+}
+
+
+/*
+** mark metamethods for basic types
+*/
+static void markmt (global_State *g) {
+  int i;
+  for (i=0; i < LUA_NUMTAGS; i++)
+    markobject(g, g->mt[i]);
+}
+
+
+/*
+** mark all objects in list of being-finalized
+*/
+static void markbeingfnz (global_State *g) {
+  GCObject *o;
+  for (o = g->tobefnz; o != NULL; o = gch(o)->next) {
+    makewhite(g, o);
+    reallymarkobject(g, o);
+  }
+}
+
+
+/*
+** mark all values stored in marked open upvalues. (See comment in
+** 'lstate.h'.)
+*/
+static void remarkupvals (global_State *g) {
+  UpVal *uv;
+  for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
+    if (isgray(obj2gco(uv)))
+      markvalue(g, uv->v);
+  }
+}
+
+
+/*
+** mark root set and reset all gray lists, to start a new
+** incremental (or full) collection
+*/
+static void restartcollection (global_State *g) {
+  g->gray = g->grayagain = NULL;
+  g->weak = g->allweak = g->ephemeron = NULL;
+  markobject(g, g->mainthread);
+  markvalue(g, &g->l_registry);
+  markmt(g);
+  markbeingfnz(g);  /* mark any finalizing object left from previous cycle */
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Traverse functions
+** =======================================================
+*/
+
+static void traverseweakvalue (global_State *g, Table *h) {
+  Node *n, *limit = gnodelast(h);
+  /* if there is array part, assume it may have white values (do not
+     traverse it just to check) */
+  int hasclears = (h->sizearray > 0);
+  for (n = gnode(h, 0); n < limit; n++) {
+    checkdeadkey(n);
+    if (ttisnil(gval(n)))  /* entry is empty? */
+      removeentry(n);  /* remove it */
+    else {
+      lua_assert(!ttisnil(gkey(n)));
+      markvalue(g, gkey(n));  /* mark key */
+      if (!hasclears && iscleared(g, gval(n)))  /* is there a white value? */
+        hasclears = 1;  /* table will have to be cleared */
+    }
+  }
+  if (hasclears)
+    linktable(h, &g->weak);  /* has to be cleared later */
+  else  /* no white values */
+    linktable(h, &g->grayagain);  /* no need to clean */
+}
+
+
+static int traverseephemeron (global_State *g, Table *h) {
+  int marked = 0;  /* true if an object is marked in this traversal */
+  int hasclears = 0;  /* true if table has white keys */
+  int prop = 0;  /* true if table has entry "white-key -> white-value" */
+  Node *n, *limit = gnodelast(h);
+  int i;
+  /* traverse array part (numeric keys are 'strong') */
+  for (i = 0; i < h->sizearray; i++) {
+    if (valiswhite(&h->array[i])) {
+      marked = 1;
+      reallymarkobject(g, gcvalue(&h->array[i]));
+    }
+  }
+  /* traverse hash part */
+  for (n = gnode(h, 0); n < limit; n++) {
+    checkdeadkey(n);
+    if (ttisnil(gval(n)))  /* entry is empty? */
+      removeentry(n);  /* remove it */
+    else if (iscleared(g, gkey(n))) {  /* key is not marked (yet)? */
+      hasclears = 1;  /* table must be cleared */
+      if (valiswhite(gval(n)))  /* value not marked yet? */
+        prop = 1;  /* must propagate again */
+    }
+    else if (valiswhite(gval(n))) {  /* value not marked yet? */
+      marked = 1;
+      reallymarkobject(g, gcvalue(gval(n)));  /* mark it now */
+    }
+  }
+  if (prop)
+    linktable(h, &g->ephemeron);  /* have to propagate again */
+  else if (hasclears)  /* does table have white keys? */
+    linktable(h, &g->allweak);  /* may have to clean white keys */
+  else  /* no white keys */
+    linktable(h, &g->grayagain);  /* no need to clean */
+  return marked;
+}
+
+
+static void traversestrongtable (global_State *g, Table *h) {
+  Node *n, *limit = gnodelast(h);
+  int i;
+  for (i = 0; i < h->sizearray; i++)  /* traverse array part */
+    markvalue(g, &h->array[i]);
+  for (n = gnode(h, 0); n < limit; n++) {  /* traverse hash part */
+    checkdeadkey(n);
+    if (ttisnil(gval(n)))  /* entry is empty? */
+      removeentry(n);  /* remove it */
+    else {
+      lua_assert(!ttisnil(gkey(n)));
+      markvalue(g, gkey(n));  /* mark key */
+      markvalue(g, gval(n));  /* mark value */
+    }
+  }
+}
+
+
+static lu_mem traversetable (global_State *g, Table *h) {
+  const char *weakkey, *weakvalue;
+  const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
+  markobject(g, h->metatable);
+  if (mode && ttisstring(mode) &&  /* is there a weak mode? */
+      ((weakkey = strchr(svalue(mode), 'k')),
+       (weakvalue = strchr(svalue(mode), 'v')),
+       (weakkey || weakvalue))) {  /* is really weak? */
+    black2gray(obj2gco(h));  /* keep table gray */
+    if (!weakkey)  /* strong keys? */
+      traverseweakvalue(g, h);
+    else if (!weakvalue)  /* strong values? */
+      traverseephemeron(g, h);
+    else  /* all weak */
+      linktable(h, &g->allweak);  /* nothing to traverse now */
+  }
+  else  /* not weak */
+    traversestrongtable(g, h);
+  return sizeof(Table) + sizeof(TValue) * h->sizearray +
+                         sizeof(Node) * cast(size_t, sizenode(h));
+}
+
+
+static int traverseproto (global_State *g, Proto *f) {
+  int i;
+  if (f->cache && iswhite(obj2gco(f->cache)))
+    f->cache = NULL;  /* allow cache to be collected */
+  markobject(g, f->source);
+  for (i = 0; i < f->sizek; i++)  /* mark literals */
+    markvalue(g, &f->k[i]);
+  for (i = 0; i < f->sizeupvalues; i++)  /* mark upvalue names */
+    markobject(g, f->upvalues[i].name);
+  for (i = 0; i < f->sizep; i++)  /* mark nested protos */
+    markobject(g, f->p[i]);
+  for (i = 0; i < f->sizelocvars; i++)  /* mark local-variable names */
+    markobject(g, f->locvars[i].varname);
+  return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
+                         sizeof(Proto *) * f->sizep +
+                         sizeof(TValue) * f->sizek +
+                         sizeof(int) * f->sizelineinfo +
+                         sizeof(LocVar) * f->sizelocvars +
+                         sizeof(Upvaldesc) * f->sizeupvalues;
+}
+
+
+static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
+  int i;
+  for (i = 0; i < cl->nupvalues; i++)  /* mark its upvalues */
+    markvalue(g, &cl->upvalue[i]);
+  return sizeCclosure(cl->nupvalues);
+}
+
+static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
+  int i;
+  markobject(g, cl->p);  /* mark its prototype */
+  for (i = 0; i < cl->nupvalues; i++)  /* mark its upvalues */
+    markobject(g, cl->upvals[i]);
+  return sizeLclosure(cl->nupvalues);
+}
+
+
+static lu_mem traversestack (global_State *g, lua_State *th) {
+  int n = 0;
+  StkId o = th->stack;
+  if (o == NULL)
+    return 1;  /* stack not completely built yet */
+  for (; o < th->top; o++)
+    markvalue(g, o);
+  if (g->gcstate == GCSatomic) {  /* final traversal? */
+    StkId lim = th->stack + th->stacksize;  /* real end of stack */
+    for (; o < lim; o++)  /* clear not-marked stack slice */
+      setnilvalue(o);
+  }
+  else {  /* count call infos to compute size */
+    CallInfo *ci;
+    for (ci = &th->base_ci; ci != th->ci; ci = ci->next)
+      n++;
+  }
+  return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
+         sizeof(CallInfo) * n;
+}
+
+
+/*
+** traverse one gray object, turning it to black (except for threads,
+** which are always gray).
+*/
+static void propagatemark (global_State *g) {
+  lu_mem size;
+  GCObject *o = g->gray;
+  lua_assert(isgray(o));
+  gray2black(o);
+  switch (gch(o)->tt) {
+    case LUA_TTABLE: {
+      Table *h = gco2t(o);
+      g->gray = h->gclist;  /* remove from 'gray' list */
+      size = traversetable(g, h);
+      break;
+    }
+    case LUA_TLCL: {
+      LClosure *cl = gco2lcl(o);
+      g->gray = cl->gclist;  /* remove from 'gray' list */
+      size = traverseLclosure(g, cl);
+      break;
+    }
+    case LUA_TCCL: {
+      CClosure *cl = gco2ccl(o);
+      g->gray = cl->gclist;  /* remove from 'gray' list */
+      size = traverseCclosure(g, cl);
+      break;
+    }
+    case LUA_TTHREAD: {
+      lua_State *th = gco2th(o);
+      g->gray = th->gclist;  /* remove from 'gray' list */
+      th->gclist = g->grayagain;
+      g->grayagain = o;  /* insert into 'grayagain' list */
+      black2gray(o);
+      size = traversestack(g, th);
+      break;
+    }
+    case LUA_TPROTO: {
+      Proto *p = gco2p(o);
+      g->gray = p->gclist;  /* remove from 'gray' list */
+      size = traverseproto(g, p);
+      break;
+    }
+    default: lua_assert(0); return;
+  }
+  g->GCmemtrav += size;
+}
+
+
+static void propagateall (global_State *g) {
+  while (g->gray) propagatemark(g);
+}
+
+
+static void propagatelist (global_State *g, GCObject *l) {
+  lua_assert(g->gray == NULL);  /* no grays left */
+  g->gray = l;
+  propagateall(g);  /* traverse all elements from 'l' */
+}
+
+/*
+** retraverse all gray lists. Because tables may be reinserted in other
+** lists when traversed, traverse the original lists to avoid traversing
+** twice the same table (which is not wrong, but inefficient)
+*/
+static void retraversegrays (global_State *g) {
+  GCObject *weak = g->weak;  /* save original lists */
+  GCObject *grayagain = g->grayagain;
+  GCObject *ephemeron = g->ephemeron;
+  g->weak = g->grayagain = g->ephemeron = NULL;
+  propagateall(g);  /* traverse main gray list */
+  propagatelist(g, grayagain);
+  propagatelist(g, weak);
+  propagatelist(g, ephemeron);
+}
+
+
+static void convergeephemerons (global_State *g) {
+  int changed;
+  do {
+    GCObject *w;
+    GCObject *next = g->ephemeron;  /* get ephemeron list */
+    g->ephemeron = NULL;  /* tables will return to this list when traversed */
+    changed = 0;
+    while ((w = next) != NULL) {
+      next = gco2t(w)->gclist;
+      if (traverseephemeron(g, gco2t(w))) {  /* traverse marked some value? */
+        propagateall(g);  /* propagate changes */
+        changed = 1;  /* will have to revisit all ephemeron tables */
+      }
+    }
+  } while (changed);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Sweep Functions
+** =======================================================
+*/
+
+
+/*
+** clear entries with unmarked keys from all weaktables in list 'l' up
+** to element 'f'
+*/
+static void clearkeys (global_State *g, GCObject *l, GCObject *f) {
+  for (; l != f; l = gco2t(l)->gclist) {
+    Table *h = gco2t(l);
+    Node *n, *limit = gnodelast(h);
+    for (n = gnode(h, 0); n < limit; n++) {
+      if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {
+        setnilvalue(gval(n));  /* remove value ... */
+        removeentry(n);  /* and remove entry from table */
+      }
+    }
+  }
+}
+
+
+/*
+** clear entries with unmarked values from all weaktables in list 'l' up
+** to element 'f'
+*/
+static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
+  for (; l != f; l = gco2t(l)->gclist) {
+    Table *h = gco2t(l);
+    Node *n, *limit = gnodelast(h);
+    int i;
+    for (i = 0; i < h->sizearray; i++) {
+      TValue *o = &h->array[i];
+      if (iscleared(g, o))  /* value was collected? */
+        setnilvalue(o);  /* remove value */
+    }
+    for (n = gnode(h, 0); n < limit; n++) {
+      if (!ttisnil(gval(n)) && iscleared(g, gval(n))) {
+        setnilvalue(gval(n));  /* remove value ... */
+        removeentry(n);  /* and remove entry from table */
+      }
+    }
+  }
+}
+
+
+static void freeobj (lua_State *L, GCObject *o) {
+  switch (gch(o)->tt) {
+    case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
+    case LUA_TLCL: {
+      luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues));
+      break;
+    }
+    case LUA_TCCL: {
+      luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
+      break;
+    }
+    case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
+    case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
+    case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
+    case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
+    case LUA_TSHRSTR:
+      G(L)->strt.nuse--;
+      /* go through */
+    case LUA_TLNGSTR: {
+      luaM_freemem(L, o, sizestring(gco2ts(o)));
+      break;
+    }
+    default: lua_assert(0);
+  }
+}
+
+
+#define sweepwholelist(L,p)	sweeplist(L,p,MAX_LUMEM)
+static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
+
+
+/*
+** sweep the (open) upvalues of a thread and resize its stack and
+** list of call-info structures.
+*/
+static void sweepthread (lua_State *L, lua_State *L1) {
+  if (L1->stack == NULL) return;  /* stack not completely built yet */
+  sweepwholelist(L, &L1->openupval);  /* sweep open upvalues */
+  luaE_freeCI(L1);  /* free extra CallInfo slots */
+  /* should not change the stack during an emergency gc cycle */
+  if (G(L)->gckind != KGC_EMERGENCY)
+    luaD_shrinkstack(L1);
+}
+
+
+/*
+** sweep at most 'count' elements from a list of GCObjects erasing dead
+** objects, where a dead (not alive) object is one marked with the "old"
+** (non current) white and not fixed.
+** In non-generational mode, change all non-dead objects back to white,
+** preparing for next collection cycle.
+** In generational mode, keep black objects black, and also mark them as
+** old; stop when hitting an old object, as all objects after that
+** one will be old too.
+** When object is a thread, sweep its list of open upvalues too.
+*/
+static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
+  global_State *g = G(L);
+  int ow = otherwhite(g);
+  int toclear, toset;  /* bits to clear and to set in all live objects */
+  int tostop;  /* stop sweep when this is true */
+  if (isgenerational(g)) {  /* generational mode? */
+    toclear = ~0;  /* clear nothing */
+    toset = bitmask(OLDBIT);  /* set the old bit of all surviving objects */
+    tostop = bitmask(OLDBIT);  /* do not sweep old generation */
+  }
+  else {  /* normal mode */
+    toclear = maskcolors;  /* clear all color bits + old bit */
+    toset = luaC_white(g);  /* make object white */
+    tostop = 0;  /* do not stop */
+  }
+  while (*p != NULL && count-- > 0) {
+    GCObject *curr = *p;
+    int marked = gch(curr)->marked;
+    if (isdeadm(ow, marked)) {  /* is 'curr' dead? */
+      *p = gch(curr)->next;  /* remove 'curr' from list */
+      freeobj(L, curr);  /* erase 'curr' */
+    }
+    else {
+      if (testbits(marked, tostop))
+        return NULL;  /* stop sweeping this list */
+      if (gch(curr)->tt == LUA_TTHREAD)
+        sweepthread(L, gco2th(curr));  /* sweep thread's upvalues */
+      /* update marks */
+      gch(curr)->marked = cast_byte((marked & toclear) | toset);
+      p = &gch(curr)->next;  /* go to next element */
+    }
+  }
+  return (*p == NULL) ? NULL : p;
+}
+
+
+/*
+** sweep a list until a live object (or end of list)
+*/
+static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
+  GCObject ** old = p;
+  int i = 0;
+  do {
+    i++;
+    p = sweeplist(L, p, 1);
+  } while (p == old);
+  if (n) *n += i;
+  return p;
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Finalization
+** =======================================================
+*/
+
+static void checkSizes (lua_State *L) {
+  global_State *g = G(L);
+  if (g->gckind != KGC_EMERGENCY) {  /* do not change sizes in emergency */
+    int hs = g->strt.size / 2;  /* half the size of the string table */
+    if (g->strt.nuse < cast(lu_int32, hs))  /* using less than that half? */
+      luaS_resize(L, hs);  /* halve its size */
+    luaZ_freebuffer(L, &g->buff);  /* free concatenation buffer */
+  }
+}
+
+
+static GCObject *udata2finalize (global_State *g) {
+  GCObject *o = g->tobefnz;  /* get first element */
+  lua_assert(isfinalized(o));
+  g->tobefnz = gch(o)->next;  /* remove it from 'tobefnz' list */
+  gch(o)->next = g->allgc;  /* return it to 'allgc' list */
+  g->allgc = o;
+  resetbit(gch(o)->marked, SEPARATED);  /* mark that it is not in 'tobefnz' */
+  lua_assert(!isold(o));  /* see MOVE OLD rule */
+  if (!keepinvariantout(g))  /* not keeping invariant? */
+    makewhite(g, o);  /* "sweep" object */
+  return o;
+}
+
+
+static void dothecall (lua_State *L, void *ud) {
+  UNUSED(ud);
+  luaD_call(L, L->top - 2, 0, 0);
+}
+
+
+static void GCTM (lua_State *L, int propagateerrors) {
+  global_State *g = G(L);
+  const TValue *tm;
+  TValue v;
+  setgcovalue(L, &v, udata2finalize(g));
+  tm = luaT_gettmbyobj(L, &v, TM_GC);
+  if (tm != NULL && ttisfunction(tm)) {  /* is there a finalizer? */
+    int status;
+    lu_byte oldah = L->allowhook;
+    int running  = g->gcrunning;
+    L->allowhook = 0;  /* stop debug hooks during GC metamethod */
+    g->gcrunning = 0;  /* avoid GC steps */
+    setobj2s(L, L->top, tm);  /* push finalizer... */
+    setobj2s(L, L->top + 1, &v);  /* ... and its argument */
+    L->top += 2;  /* and (next line) call the finalizer */
+    status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
+    L->allowhook = oldah;  /* restore hooks */
+    g->gcrunning = running;  /* restore state */
+    if (status != LUA_OK && propagateerrors) {  /* error while running __gc? */
+      if (status == LUA_ERRRUN) {  /* is there an error object? */
+        const char *msg = (ttisstring(L->top - 1))
+                            ? svalue(L->top - 1)
+                            : "no message";
+        luaO_pushfstring(L, "error in __gc metamethod (%s)", msg);
+        status = LUA_ERRGCMM;  /* error in __gc metamethod */
+      }
+      luaD_throw(L, status);  /* re-throw error */
+    }
+  }
+}
+
+
+/*
+** move all unreachable objects (or 'all' objects) that need
+** finalization from list 'finobj' to list 'tobefnz' (to be finalized)
+*/
+static void separatetobefnz (lua_State *L, int all) {
+  global_State *g = G(L);
+  GCObject **p = &g->finobj;
+  GCObject *curr;
+  GCObject **lastnext = &g->tobefnz;
+  /* find last 'next' field in 'tobefnz' list (to add elements in its end) */
+  while (*lastnext != NULL)
+    lastnext = &gch(*lastnext)->next;
+  while ((curr = *p) != NULL) {  /* traverse all finalizable objects */
+    lua_assert(!isfinalized(curr));
+    lua_assert(testbit(gch(curr)->marked, SEPARATED));
+    if (!(iswhite(curr) || all))  /* not being collected? */
+      p = &gch(curr)->next;  /* don't bother with it */
+    else {
+      l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
+      *p = gch(curr)->next;  /* remove 'curr' from 'finobj' list */
+      gch(curr)->next = *lastnext;  /* link at the end of 'tobefnz' list */
+      *lastnext = curr;
+      lastnext = &gch(curr)->next;
+    }
+  }
+}
+
+
+/*
+** if object 'o' has a finalizer, remove it from 'allgc' list (must
+** search the list to find it) and link it in 'finobj' list.
+*/
+void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
+  global_State *g = G(L);
+  if (testbit(gch(o)->marked, SEPARATED) || /* obj. is already separated... */
+      isfinalized(o) ||                           /* ... or is finalized... */
+      gfasttm(g, mt, TM_GC) == NULL)                /* or has no finalizer? */
+    return;  /* nothing to be done */
+  else {  /* move 'o' to 'finobj' list */
+    GCObject **p;
+    GCheader *ho = gch(o);
+    if (g->sweepgc == &ho->next) {  /* avoid removing current sweep object */
+      lua_assert(issweepphase(g));
+      g->sweepgc = sweeptolive(L, g->sweepgc, NULL);
+    }
+    /* search for pointer pointing to 'o' */
+    for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ }
+    *p = ho->next;  /* remove 'o' from root list */
+    ho->next = g->finobj;  /* link it in list 'finobj' */
+    g->finobj = o;
+    l_setbit(ho->marked, SEPARATED);  /* mark it as such */
+    if (!keepinvariantout(g))  /* not keeping invariant? */
+      makewhite(g, o);  /* "sweep" object */
+    else
+      resetoldbit(o);  /* see MOVE OLD rule */
+  }
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** GC control
+** =======================================================
+*/
+
+
+/*
+** set a reasonable "time" to wait before starting a new GC cycle;
+** cycle will start when memory use hits threshold
+*/
+static void setpause (global_State *g, l_mem estimate) {
+  l_mem debt, threshold;
+  estimate = estimate / PAUSEADJ;  /* adjust 'estimate' */
+  threshold = (g->gcpause < MAX_LMEM / estimate)  /* overflow? */
+            ? estimate * g->gcpause  /* no overflow */
+            : MAX_LMEM;  /* overflow; truncate to maximum */
+  debt = -cast(l_mem, threshold - gettotalbytes(g));
+  luaE_setdebt(g, debt);
+}
+
+
+#define sweepphases  \
+	(bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep))
+
+
+/*
+** enter first sweep phase (strings) and prepare pointers for other
+** sweep phases.  The calls to 'sweeptolive' make pointers point to an
+** object inside the list (instead of to the header), so that the real
+** sweep do not need to skip objects created between "now" and the start
+** of the real sweep.
+** Returns how many objects it swept.
+*/
+static int entersweep (lua_State *L) {
+  global_State *g = G(L);
+  int n = 0;
+  g->gcstate = GCSsweepstring;
+  lua_assert(g->sweepgc == NULL && g->sweepfin == NULL);
+  /* prepare to sweep strings, finalizable objects, and regular objects */
+  g->sweepstrgc = 0;
+  g->sweepfin = sweeptolive(L, &g->finobj, &n);
+  g->sweepgc = sweeptolive(L, &g->allgc, &n);
+  return n;
+}
+
+
+/*
+** change GC mode
+*/
+void luaC_changemode (lua_State *L, int mode) {
+  global_State *g = G(L);
+  if (mode == g->gckind) return;  /* nothing to change */
+  if (mode == KGC_GEN) {  /* change to generational mode */
+    /* make sure gray lists are consistent */
+    luaC_runtilstate(L, bitmask(GCSpropagate));
+    g->GCestimate = gettotalbytes(g);
+    g->gckind = KGC_GEN;
+  }
+  else {  /* change to incremental mode */
+    /* sweep all objects to turn them back to white
+       (as white has not changed, nothing extra will be collected) */
+    g->gckind = KGC_NORMAL;
+    entersweep(L);
+    luaC_runtilstate(L, ~sweepphases);
+  }
+}
+
+
+/*
+** call all pending finalizers
+*/
+static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
+  global_State *g = G(L);
+  while (g->tobefnz) {
+    resetoldbit(g->tobefnz);
+    GCTM(L, propagateerrors);
+  }
+}
+
+
+void luaC_freeallobjects (lua_State *L) {
+  global_State *g = G(L);
+  int i;
+  separatetobefnz(L, 1);  /* separate all objects with finalizers */
+  lua_assert(g->finobj == NULL);
+  callallpendingfinalizers(L, 0);
+  g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
+  g->gckind = KGC_NORMAL;
+  sweepwholelist(L, &g->finobj);  /* finalizers can create objs. in 'finobj' */
+  sweepwholelist(L, &g->allgc);
+  for (i = 0; i < g->strt.size; i++)  /* free all string lists */
+    sweepwholelist(L, &g->strt.hash[i]);
+  lua_assert(g->strt.nuse == 0);
+}
+
+
+static l_mem atomic (lua_State *L) {
+  global_State *g = G(L);
+  l_mem work = -cast(l_mem, g->GCmemtrav);  /* start counting work */
+  GCObject *origweak, *origall;
+  lua_assert(!iswhite(obj2gco(g->mainthread)));
+  markobject(g, L);  /* mark running thread */
+  /* registry and global metatables may be changed by API */
+  markvalue(g, &g->l_registry);
+  markmt(g);  /* mark basic metatables */
+  /* remark occasional upvalues of (maybe) dead threads */
+  remarkupvals(g);
+  propagateall(g);  /* propagate changes */
+  work += g->GCmemtrav;  /* stop counting (do not (re)count grays) */
+  /* traverse objects caught by write barrier and by 'remarkupvals' */
+  retraversegrays(g);
+  work -= g->GCmemtrav;  /* restart counting */
+  convergeephemerons(g);
+  /* at this point, all strongly accessible objects are marked. */
+  /* clear values from weak tables, before checking finalizers */
+  clearvalues(g, g->weak, NULL);
+  clearvalues(g, g->allweak, NULL);
+  origweak = g->weak; origall = g->allweak;
+  work += g->GCmemtrav;  /* stop counting (objects being finalized) */
+  separatetobefnz(L, 0);  /* separate objects to be finalized */
+  markbeingfnz(g);  /* mark objects that will be finalized */
+  propagateall(g);  /* remark, to propagate `preserveness' */
+  work -= g->GCmemtrav;  /* restart counting */
+  convergeephemerons(g);
+  /* at this point, all resurrected objects are marked. */
+  /* remove dead objects from weak tables */
+  clearkeys(g, g->ephemeron, NULL);  /* clear keys from all ephemeron tables */
+  clearkeys(g, g->allweak, NULL);  /* clear keys from all allweak tables */
+  /* clear values from resurrected weak tables */
+  clearvalues(g, g->weak, origweak);
+  clearvalues(g, g->allweak, origall);
+  g->currentwhite = cast_byte(otherwhite(g));  /* flip current white */
+  work += g->GCmemtrav;  /* complete counting */
+  return work;  /* estimate of memory marked by 'atomic' */
+}
+
+
+static lu_mem singlestep (lua_State *L) {
+  global_State *g = G(L);
+  switch (g->gcstate) {
+    case GCSpause: {
+      /* start to count memory traversed */
+      g->GCmemtrav = g->strt.size * sizeof(GCObject*);
+      lua_assert(!isgenerational(g));
+      restartcollection(g);
+      g->gcstate = GCSpropagate;
+      return g->GCmemtrav;
+    }
+    case GCSpropagate: {
+      if (g->gray) {
+        lu_mem oldtrav = g->GCmemtrav;
+        propagatemark(g);
+        return g->GCmemtrav - oldtrav;  /* memory traversed in this step */
+      }
+      else {  /* no more `gray' objects */
+        lu_mem work;
+        int sw;
+        g->gcstate = GCSatomic;  /* finish mark phase */
+        g->GCestimate = g->GCmemtrav;  /* save what was counted */;
+        work = atomic(L);  /* add what was traversed by 'atomic' */
+        g->GCestimate += work;  /* estimate of total memory traversed */ 
+        sw = entersweep(L);
+        return work + sw * GCSWEEPCOST;
+      }
+    }
+    case GCSsweepstring: {
+      int i;
+      for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++)
+        sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]);
+      g->sweepstrgc += i;
+      if (g->sweepstrgc >= g->strt.size)  /* no more strings to sweep? */
+        g->gcstate = GCSsweepudata;
+      return i * GCSWEEPCOST;
+    }
+    case GCSsweepudata: {
+      if (g->sweepfin) {
+        g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX);
+        return GCSWEEPMAX*GCSWEEPCOST;
+      }
+      else {
+        g->gcstate = GCSsweep;
+        return 0;
+      }
+    }
+    case GCSsweep: {
+      if (g->sweepgc) {
+        g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
+        return GCSWEEPMAX*GCSWEEPCOST;
+      }
+      else {
+        /* sweep main thread */
+        GCObject *mt = obj2gco(g->mainthread);
+        sweeplist(L, &mt, 1);
+        checkSizes(L);
+        g->gcstate = GCSpause;  /* finish collection */
+        return GCSWEEPCOST;
+      }
+    }
+    default: lua_assert(0); return 0;
+  }
+}
+
+
+/*
+** advances the garbage collector until it reaches a state allowed
+** by 'statemask'
+*/
+void luaC_runtilstate (lua_State *L, int statesmask) {
+  global_State *g = G(L);
+  while (!testbit(statesmask, g->gcstate))
+    singlestep(L);
+}
+
+
+static void generationalcollection (lua_State *L) {
+  global_State *g = G(L);
+  lua_assert(g->gcstate == GCSpropagate);
+  if (g->GCestimate == 0) {  /* signal for another major collection? */
+    luaC_fullgc(L, 0);  /* perform a full regular collection */
+    g->GCestimate = gettotalbytes(g);  /* update control */
+  }
+  else {
+    lu_mem estimate = g->GCestimate;
+    luaC_runtilstate(L, bitmask(GCSpause));  /* run complete (minor) cycle */
+    g->gcstate = GCSpropagate;  /* skip restart */
+    if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc)
+      g->GCestimate = 0;  /* signal for a major collection */
+    else
+      g->GCestimate = estimate;  /* keep estimate from last major coll. */
+
+  }
+  setpause(g, gettotalbytes(g));
+  lua_assert(g->gcstate == GCSpropagate);
+}
+
+
+static void incstep (lua_State *L) {
+  global_State *g = G(L);
+  l_mem debt = g->GCdebt;
+  int stepmul = g->gcstepmul;
+  if (stepmul < 40) stepmul = 40;  /* avoid ridiculous low values (and 0) */
+  /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */
+  debt = (debt / STEPMULADJ) + 1;
+  debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
+  do {  /* always perform at least one single step */
+    lu_mem work = singlestep(L);  /* do some work */
+    debt -= work;
+  } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
+  if (g->gcstate == GCSpause)
+    setpause(g, g->GCestimate);  /* pause until next cycle */
+  else {
+    debt = (debt / stepmul) * STEPMULADJ;  /* convert 'work units' to Kb */
+    luaE_setdebt(g, debt);
+  }
+}
+
+
+/*
+** performs a basic GC step
+*/
+void luaC_forcestep (lua_State *L) {
+  global_State *g = G(L);
+  int i;
+  if (isgenerational(g)) generationalcollection(L);
+  else incstep(L);
+  /* run a few finalizers (or all of them at the end of a collect cycle) */
+  for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++)
+    GCTM(L, 1);  /* call one finalizer */
+}
+
+
+/*
+** performs a basic GC step only if collector is running
+*/
+void luaC_step (lua_State *L) {
+  global_State *g = G(L);
+  if (g->gcrunning) luaC_forcestep(L);
+  else luaE_setdebt(g, -GCSTEPSIZE);  /* avoid being called too often */
+}
+
+
+
+/*
+** performs a full GC cycle; if "isemergency", does not call
+** finalizers (which could change stack positions)
+*/
+void luaC_fullgc (lua_State *L, int isemergency) {
+  global_State *g = G(L);
+  int origkind = g->gckind;
+  lua_assert(origkind != KGC_EMERGENCY);
+  if (isemergency)  /* do not run finalizers during emergency GC */
+    g->gckind = KGC_EMERGENCY;
+  else {
+    g->gckind = KGC_NORMAL;
+    callallpendingfinalizers(L, 1);
+  }
+  if (keepinvariant(g)) {  /* may there be some black objects? */
+    /* must sweep all objects to turn them back to white
+       (as white has not changed, nothing will be collected) */
+    entersweep(L);
+  }
+  /* finish any pending sweep phase to start a new cycle */
+  luaC_runtilstate(L, bitmask(GCSpause));
+  luaC_runtilstate(L, ~bitmask(GCSpause));  /* start new collection */
+  luaC_runtilstate(L, bitmask(GCSpause));  /* run entire collection */
+  if (origkind == KGC_GEN) {  /* generational mode? */
+    /* generational mode must be kept in propagate phase */
+    luaC_runtilstate(L, bitmask(GCSpropagate));
+  }
+  g->gckind = origkind;
+  setpause(g, gettotalbytes(g));
+  if (!isemergency)   /* do not run finalizers during emergency GC */
+    callallpendingfinalizers(L, 1);
+}
+
+/* }====================================================== */
+
+

=== added file 'src/scripting/eris/lgc.h'
--- src/scripting/eris/lgc.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lgc.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,157 @@
+/*
+** $Id: lgc.h,v 2.58 2012/09/11 12:53:08 roberto Exp $
+** Garbage Collector
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lgc_h
+#define lgc_h
+
+
+#include "lobject.h"
+#include "lstate.h"
+
+/*
+** Collectable objects may have one of three colors: white, which
+** means the object is not marked; gray, which means the
+** object is marked, but its references may be not marked; and
+** black, which means that the object and all its references are marked.
+** The main invariant of the garbage collector, while marking objects,
+** is that a black object can never point to a white one. Moreover,
+** any gray object must be in a "gray list" (gray, grayagain, weak,
+** allweak, ephemeron) so that it can be visited again before finishing
+** the collection cycle. These lists have no meaning when the invariant
+** is not being enforced (e.g., sweep phase).
+*/
+
+
+
+/* how much to allocate before next GC step */
+#if !defined(GCSTEPSIZE)
+/* ~100 small strings */
+#define GCSTEPSIZE	(cast_int(100 * sizeof(TString)))
+#endif
+
+
+/*
+** Possible states of the Garbage Collector
+*/
+#define GCSpropagate	0
+#define GCSatomic	1
+#define GCSsweepstring	2
+#define GCSsweepudata	3
+#define GCSsweep	4
+#define GCSpause	5
+
+
+#define issweepphase(g)  \
+	(GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
+
+#define isgenerational(g)	((g)->gckind == KGC_GEN)
+
+/*
+** macros to tell when main invariant (white objects cannot point to black
+** ones) must be kept. During a non-generational collection, the sweep
+** phase may break the invariant, as objects turned white may point to
+** still-black objects. The invariant is restored when sweep ends and
+** all objects are white again. During a generational collection, the
+** invariant must be kept all times.
+*/
+
+#define keepinvariant(g)	(isgenerational(g) || g->gcstate <= GCSatomic)
+
+
+/*
+** Outside the collector, the state in generational mode is kept in
+** 'propagate', so 'keepinvariant' is always true.
+*/
+#define keepinvariantout(g)  \
+  check_exp(g->gcstate == GCSpropagate || !isgenerational(g),  \
+            g->gcstate <= GCSatomic)
+
+
+/*
+** some useful bit tricks
+*/
+#define resetbits(x,m)		((x) &= cast(lu_byte, ~(m)))
+#define setbits(x,m)		((x) |= (m))
+#define testbits(x,m)		((x) & (m))
+#define bitmask(b)		(1<<(b))
+#define bit2mask(b1,b2)		(bitmask(b1) | bitmask(b2))
+#define l_setbit(x,b)		setbits(x, bitmask(b))
+#define resetbit(x,b)		resetbits(x, bitmask(b))
+#define testbit(x,b)		testbits(x, bitmask(b))
+
+
+/* Layout for bit use in `marked' field: */
+#define WHITE0BIT	0  /* object is white (type 0) */
+#define WHITE1BIT	1  /* object is white (type 1) */
+#define BLACKBIT	2  /* object is black */
+#define FINALIZEDBIT	3  /* object has been separated for finalization */
+#define SEPARATED	4  /* object is in 'finobj' list or in 'tobefnz' */
+#define FIXEDBIT	5  /* object is fixed (should not be collected) */
+#define OLDBIT		6  /* object is old (only in generational mode) */
+/* bit 7 is currently used by tests (luaL_checkmemory) */
+
+#define WHITEBITS	bit2mask(WHITE0BIT, WHITE1BIT)
+
+
+#define iswhite(x)      testbits((x)->gch.marked, WHITEBITS)
+#define isblack(x)      testbit((x)->gch.marked, BLACKBIT)
+#define isgray(x)  /* neither white nor black */  \
+	(!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT)))
+
+#define isold(x)	testbit((x)->gch.marked, OLDBIT)
+
+/* MOVE OLD rule: whenever an object is moved to the beginning of
+   a GC list, its old bit must be cleared */
+#define resetoldbit(o)	resetbit((o)->gch.marked, OLDBIT)
+
+#define otherwhite(g)	(g->currentwhite ^ WHITEBITS)
+#define isdeadm(ow,m)	(!(((m) ^ WHITEBITS) & (ow)))
+#define isdead(g,v)	isdeadm(otherwhite(g), (v)->gch.marked)
+
+#define changewhite(x)	((x)->gch.marked ^= WHITEBITS)
+#define gray2black(x)	l_setbit((x)->gch.marked, BLACKBIT)
+
+#define valiswhite(x)	(iscollectable(x) && iswhite(gcvalue(x)))
+
+#define luaC_white(g)	cast(lu_byte, (g)->currentwhite & WHITEBITS)
+
+
+#define luaC_condGC(L,c) \
+	{if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
+#define luaC_checkGC(L)		luaC_condGC(L, luaC_step(L);)
+
+
+#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p)))  \
+	luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
+
+#define luaC_barrierback(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p)))  \
+	luaC_barrierback_(L,p); }
+
+#define luaC_objbarrier(L,p,o)  \
+	{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
+		luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
+
+#define luaC_objbarrierback(L,p,o)  \
+   { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); }
+
+#define luaC_barrierproto(L,p,c) \
+   { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); }
+
+LUAI_FUNC void luaC_freeallobjects (lua_State *L);
+LUAI_FUNC void luaC_step (lua_State *L);
+LUAI_FUNC void luaC_forcestep (lua_State *L);
+LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
+LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
+LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz,
+                                 GCObject **list, int offset);
+LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
+LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
+LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c);
+LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
+LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv);
+LUAI_FUNC void luaC_changemode (lua_State *L, int mode);
+
+#endif

=== added file 'src/scripting/eris/linit.c'
--- src/scripting/eris/linit.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/linit.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,68 @@
+/*
+** $Id: linit.c,v 1.32 2011/04/08 19:17:36 roberto Exp $
+** Initialization of libraries for lua.c and other clients
+** See Copyright Notice in lua.h
+*/
+
+
+/*
+** If you embed Lua in your program and need to open the standard
+** libraries, call luaL_openlibs in your program. If you need a
+** different set of libraries, copy this file to your project and edit
+** it to suit your needs.
+*/
+
+
+#define linit_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lualib.h"
+#include "lauxlib.h"
+
+
+/*
+** these libs are loaded by lua.c and are readily available to any Lua
+** program
+*/
+static const luaL_Reg loadedlibs[] = {
+  {"_G", luaopen_base},
+  {LUA_LOADLIBNAME, luaopen_package},
+  {LUA_COLIBNAME, luaopen_coroutine},
+  {LUA_TABLIBNAME, luaopen_table},
+  {LUA_IOLIBNAME, luaopen_io},
+  {LUA_OSLIBNAME, luaopen_os},
+  {LUA_STRLIBNAME, luaopen_string},
+  {LUA_BITLIBNAME, luaopen_bit32},
+  {LUA_MATHLIBNAME, luaopen_math},
+  {LUA_DBLIBNAME, luaopen_debug},
+  {LUA_ERISLIBNAME, luaopen_eris},
+  {NULL, NULL}
+};
+
+
+/*
+** these libs are preloaded and must be required before used
+*/
+static const luaL_Reg preloadedlibs[] = {
+  {NULL, NULL}
+};
+
+
+LUALIB_API void luaL_openlibs (lua_State *L) {
+  const luaL_Reg *lib;
+  /* call open functions from 'loadedlibs' and set results to global table */
+  for (lib = loadedlibs; lib->func; lib++) {
+    luaL_requiref(L, lib->name, lib->func, 1);
+    lua_pop(L, 1);  /* remove lib */
+  }
+  /* add open functions from 'preloadedlibs' into 'package.preload' table */
+  luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+  for (lib = preloadedlibs; lib->func; lib++) {
+    lua_pushcfunction(L, lib->func);
+    lua_setfield(L, -2, lib->name);
+  }
+  lua_pop(L, 1);  /* remove _PRELOAD table */
+}
+

=== added file 'src/scripting/eris/liolib.c'
--- src/scripting/eris/liolib.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/liolib.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,681 @@
+/*
+** $Id: liolib.c,v 2.111 2013/03/21 13:57:27 roberto Exp $
+** Standard I/O (and system) library
+** See Copyright Notice in lua.h
+*/
+
+
+/*
+** POSIX idiosyncrasy!
+** This definition must come before the inclusion of 'stdio.h'; it
+** should not affect non-POSIX systems
+*/
+#if !defined(_FILE_OFFSET_BITS)
+#define _FILE_OFFSET_BITS 64
+#endif
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define liolib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#if !defined(lua_checkmode)
+
+/*
+** Check whether 'mode' matches '[rwa]%+?b?'.
+** Change this macro to accept other modes for 'fopen' besides
+** the standard ones.
+*/
+#define lua_checkmode(mode) \
+	(*mode != '\0' && strchr("rwa", *(mode++)) != NULL &&	\
+	(*mode != '+' || ++mode) &&  /* skip if char is '+' */	\
+	(*mode != 'b' || ++mode) &&  /* skip if char is 'b' */	\
+	(*mode == '\0'))
+
+#endif
+
+/*
+** {======================================================
+** lua_popen spawns a new process connected to the current
+** one through the file streams.
+** =======================================================
+*/
+
+#if !defined(lua_popen)	/* { */
+
+#if defined(LUA_USE_POPEN)	/* { */
+
+#define lua_popen(L,c,m)	((void)L, fflush(NULL), popen(c,m))
+#define lua_pclose(L,file)	((void)L, pclose(file))
+
+#elif defined(LUA_WIN)		/* }{ */
+
+#define lua_popen(L,c,m)		((void)L, _popen(c,m))
+#define lua_pclose(L,file)		((void)L, _pclose(file))
+
+
+#else				/* }{ */
+
+#define lua_popen(L,c,m)		((void)((void)c, m),  \
+		luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
+#define lua_pclose(L,file)		((void)((void)L, file), -1)
+
+
+#endif				/* } */
+
+#endif			/* } */
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** lua_fseek/lua_ftell: configuration for longer offsets
+** =======================================================
+*/
+
+#if !defined(lua_fseek)	/* { */
+
+#if defined(LUA_USE_POSIX)
+
+#define l_fseek(f,o,w)		fseeko(f,o,w)
+#define l_ftell(f)		ftello(f)
+#define l_seeknum		off_t
+
+#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \
+   && defined(_MSC_VER) && (_MSC_VER >= 1400)
+/* Windows (but not DDK) and Visual C++ 2005 or higher */
+
+#define l_fseek(f,o,w)		_fseeki64(f,o,w)
+#define l_ftell(f)		_ftelli64(f)
+#define l_seeknum		__int64
+
+#else
+
+#define l_fseek(f,o,w)		fseek(f,o,w)
+#define l_ftell(f)		ftell(f)
+#define l_seeknum		long
+
+#endif
+
+#endif			/* } */
+
+/* }====================================================== */
+
+
+#define IO_PREFIX	"_IO_"
+#define IO_INPUT	(IO_PREFIX "input")
+#define IO_OUTPUT	(IO_PREFIX "output")
+
+
+typedef luaL_Stream LStream;
+
+
+#define tolstream(L)	((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE))
+
+#define isclosed(p)	((p)->closef == NULL)
+
+
+static int io_type (lua_State *L) {
+  LStream *p;
+  luaL_checkany(L, 1);
+  p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE);
+  if (p == NULL)
+    lua_pushnil(L);  /* not a file */
+  else if (isclosed(p))
+    lua_pushliteral(L, "closed file");
+  else
+    lua_pushliteral(L, "file");
+  return 1;
+}
+
+
+static int f_tostring (lua_State *L) {
+  LStream *p = tolstream(L);
+  if (isclosed(p))
+    lua_pushliteral(L, "file (closed)");
+  else
+    lua_pushfstring(L, "file (%p)", p->f);
+  return 1;
+}
+
+
+static FILE *tofile (lua_State *L) {
+  LStream *p = tolstream(L);
+  if (isclosed(p))
+    luaL_error(L, "attempt to use a closed file");
+  lua_assert(p->f);
+  return p->f;
+}
+
+
+/*
+** When creating file handles, always creates a `closed' file handle
+** before opening the actual file; so, if there is a memory error, the
+** file is not left opened.
+*/
+static LStream *newprefile (lua_State *L) {
+  LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
+  p->closef = NULL;  /* mark file handle as 'closed' */
+  luaL_setmetatable(L, LUA_FILEHANDLE);
+  return p;
+}
+
+
+static int aux_close (lua_State *L) {
+  LStream *p = tolstream(L);
+  lua_CFunction cf = p->closef;
+  p->closef = NULL;  /* mark stream as closed */
+  return (*cf)(L);  /* close it */
+}
+
+
+static int io_close (lua_State *L) {
+  if (lua_isnone(L, 1))  /* no argument? */
+    lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT);  /* use standard output */
+  tofile(L);  /* make sure argument is an open stream */
+  return aux_close(L);
+}
+
+
+static int f_gc (lua_State *L) {
+  LStream *p = tolstream(L);
+  if (!isclosed(p) && p->f != NULL)
+    aux_close(L);  /* ignore closed and incompletely open files */
+  return 0;
+}
+
+
+/*
+** function to close regular files
+*/
+static int io_fclose (lua_State *L) {
+  LStream *p = tolstream(L);
+  int res = fclose(p->f);
+  return luaL_fileresult(L, (res == 0), NULL);
+}
+
+
+static LStream *newfile (lua_State *L) {
+  LStream *p = newprefile(L);
+  p->f = NULL;
+  p->closef = &io_fclose;
+  return p;
+}
+
+
+static void opencheck (lua_State *L, const char *fname, const char *mode) {
+  LStream *p = newfile(L);
+  p->f = fopen(fname, mode);
+  if (p->f == NULL)
+    luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno));
+}
+
+
+static int io_open (lua_State *L) {
+  const char *filename = luaL_checkstring(L, 1);
+  const char *mode = luaL_optstring(L, 2, "r");
+  LStream *p = newfile(L);
+  const char *md = mode;  /* to traverse/check mode */
+  luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode");
+  p->f = fopen(filename, mode);
+  return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
+}
+
+
+/*
+** function to close 'popen' files
+*/
+static int io_pclose (lua_State *L) {
+  LStream *p = tolstream(L);
+  return luaL_execresult(L, lua_pclose(L, p->f));
+}
+
+
+static int io_popen (lua_State *L) {
+  const char *filename = luaL_checkstring(L, 1);
+  const char *mode = luaL_optstring(L, 2, "r");
+  LStream *p = newprefile(L);
+  p->f = lua_popen(L, filename, mode);
+  p->closef = &io_pclose;
+  return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
+}
+
+
+static int io_tmpfile (lua_State *L) {
+  LStream *p = newfile(L);
+  p->f = tmpfile();
+  return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
+}
+
+
+static FILE *getiofile (lua_State *L, const char *findex) {
+  LStream *p;
+  lua_getfield(L, LUA_REGISTRYINDEX, findex);
+  p = (LStream *)lua_touserdata(L, -1);
+  if (isclosed(p))
+    luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX));
+  return p->f;
+}
+
+
+static int g_iofile (lua_State *L, const char *f, const char *mode) {
+  if (!lua_isnoneornil(L, 1)) {
+    const char *filename = lua_tostring(L, 1);
+    if (filename)
+      opencheck(L, filename, mode);
+    else {
+      tofile(L);  /* check that it's a valid file handle */
+      lua_pushvalue(L, 1);
+    }
+    lua_setfield(L, LUA_REGISTRYINDEX, f);
+  }
+  /* return current value */
+  lua_getfield(L, LUA_REGISTRYINDEX, f);
+  return 1;
+}
+
+
+static int io_input (lua_State *L) {
+  return g_iofile(L, IO_INPUT, "r");
+}
+
+
+static int io_output (lua_State *L) {
+  return g_iofile(L, IO_OUTPUT, "w");
+}
+
+
+static int io_readline (lua_State *L);
+
+
+static void aux_lines (lua_State *L, int toclose) {
+  int i;
+  int n = lua_gettop(L) - 1;  /* number of arguments to read */
+  /* ensure that arguments will fit here and into 'io_readline' stack */
+  luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options");
+  lua_pushvalue(L, 1);  /* file handle */
+  lua_pushinteger(L, n);  /* number of arguments to read */
+  lua_pushboolean(L, toclose);  /* close/not close file when finished */
+  for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1);  /* copy arguments */
+  lua_pushcclosure(L, io_readline, 3 + n);
+}
+
+
+static int f_lines (lua_State *L) {
+  tofile(L);  /* check that it's a valid file handle */
+  aux_lines(L, 0);
+  return 1;
+}
+
+
+static int io_lines (lua_State *L) {
+  int toclose;
+  if (lua_isnone(L, 1)) lua_pushnil(L);  /* at least one argument */
+  if (lua_isnil(L, 1)) {  /* no file name? */
+    lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT);  /* get default input */
+    lua_replace(L, 1);  /* put it at index 1 */
+    tofile(L);  /* check that it's a valid file handle */
+    toclose = 0;  /* do not close it after iteration */
+  }
+  else {  /* open a new file */
+    const char *filename = luaL_checkstring(L, 1);
+    opencheck(L, filename, "r");
+    lua_replace(L, 1);  /* put file at index 1 */
+    toclose = 1;  /* close it after iteration */
+  }
+  aux_lines(L, toclose);
+  return 1;
+}
+
+
+/*
+** {======================================================
+** READ
+** =======================================================
+*/
+
+
+static int read_number (lua_State *L, FILE *f) {
+  lua_Number d;
+  if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
+    lua_pushnumber(L, d);
+    return 1;
+  }
+  else {
+   lua_pushnil(L);  /* "result" to be removed */
+   return 0;  /* read fails */
+  }
+}
+
+
+static int test_eof (lua_State *L, FILE *f) {
+  int c = getc(f);
+  ungetc(c, f);
+  lua_pushlstring(L, NULL, 0);
+  return (c != EOF);
+}
+
+
+static int read_line (lua_State *L, FILE *f, int chop) {
+  luaL_Buffer b;
+  luaL_buffinit(L, &b);
+  for (;;) {
+    size_t l;
+    char *p = luaL_prepbuffer(&b);
+    if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) {  /* eof? */
+      luaL_pushresult(&b);  /* close buffer */
+      return (lua_rawlen(L, -1) > 0);  /* check whether read something */
+    }
+    l = strlen(p);
+    if (l == 0 || p[l-1] != '\n')
+      luaL_addsize(&b, l);
+    else {
+      luaL_addsize(&b, l - chop);  /* chop 'eol' if needed */
+      luaL_pushresult(&b);  /* close buffer */
+      return 1;  /* read at least an `eol' */
+    }
+  }
+}
+
+
+#define MAX_SIZE_T	(~(size_t)0)
+
+static void read_all (lua_State *L, FILE *f) {
+  size_t rlen = LUAL_BUFFERSIZE;  /* how much to read in each cycle */
+  luaL_Buffer b;
+  luaL_buffinit(L, &b);
+  for (;;) {
+    char *p = luaL_prepbuffsize(&b, rlen);
+    size_t nr = fread(p, sizeof(char), rlen, f);
+    luaL_addsize(&b, nr);
+    if (nr < rlen) break;  /* eof? */
+    else if (rlen <= (MAX_SIZE_T / 4))  /* avoid buffers too large */
+      rlen *= 2;  /* double buffer size at each iteration */
+  }
+  luaL_pushresult(&b);  /* close buffer */
+}
+
+
+static int read_chars (lua_State *L, FILE *f, size_t n) {
+  size_t nr;  /* number of chars actually read */
+  char *p;
+  luaL_Buffer b;
+  luaL_buffinit(L, &b);
+  p = luaL_prepbuffsize(&b, n);  /* prepare buffer to read whole block */
+  nr = fread(p, sizeof(char), n, f);  /* try to read 'n' chars */
+  luaL_addsize(&b, nr);
+  luaL_pushresult(&b);  /* close buffer */
+  return (nr > 0);  /* true iff read something */
+}
+
+
+static int g_read (lua_State *L, FILE *f, int first) {
+  int nargs = lua_gettop(L) - 1;
+  int success;
+  int n;
+  clearerr(f);
+  if (nargs == 0) {  /* no arguments? */
+    success = read_line(L, f, 1);
+    n = first+1;  /* to return 1 result */
+  }
+  else {  /* ensure stack space for all results and for auxlib's buffer */
+    luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
+    success = 1;
+    for (n = first; nargs-- && success; n++) {
+      if (lua_type(L, n) == LUA_TNUMBER) {
+        size_t l = (size_t)lua_tointeger(L, n);
+        success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
+      }
+      else {
+        const char *p = lua_tostring(L, n);
+        luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
+        switch (p[1]) {
+          case 'n':  /* number */
+            success = read_number(L, f);
+            break;
+          case 'l':  /* line */
+            success = read_line(L, f, 1);
+            break;
+          case 'L':  /* line with end-of-line */
+            success = read_line(L, f, 0);
+            break;
+          case 'a':  /* file */
+            read_all(L, f);  /* read entire file */
+            success = 1; /* always success */
+            break;
+          default:
+            return luaL_argerror(L, n, "invalid format");
+        }
+      }
+    }
+  }
+  if (ferror(f))
+    return luaL_fileresult(L, 0, NULL);
+  if (!success) {
+    lua_pop(L, 1);  /* remove last result */
+    lua_pushnil(L);  /* push nil instead */
+  }
+  return n - first;
+}
+
+
+static int io_read (lua_State *L) {
+  return g_read(L, getiofile(L, IO_INPUT), 1);
+}
+
+
+static int f_read (lua_State *L) {
+  return g_read(L, tofile(L), 2);
+}
+
+
+static int io_readline (lua_State *L) {
+  LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1));
+  int i;
+  int n = (int)lua_tointeger(L, lua_upvalueindex(2));
+  if (isclosed(p))  /* file is already closed? */
+    return luaL_error(L, "file is already closed");
+  lua_settop(L , 1);
+  for (i = 1; i <= n; i++)  /* push arguments to 'g_read' */
+    lua_pushvalue(L, lua_upvalueindex(3 + i));
+  n = g_read(L, p->f, 2);  /* 'n' is number of results */
+  lua_assert(n > 0);  /* should return at least a nil */
+  if (!lua_isnil(L, -n))  /* read at least one value? */
+    return n;  /* return them */
+  else {  /* first result is nil: EOF or error */
+    if (n > 1) {  /* is there error information? */
+      /* 2nd result is error message */
+      return luaL_error(L, "%s", lua_tostring(L, -n + 1));
+    }
+    if (lua_toboolean(L, lua_upvalueindex(3))) {  /* generator created file? */
+      lua_settop(L, 0);
+      lua_pushvalue(L, lua_upvalueindex(1));
+      aux_close(L);  /* close it */
+    }
+    return 0;
+  }
+}
+
+/* }====================================================== */
+
+
+static int g_write (lua_State *L, FILE *f, int arg) {
+  int nargs = lua_gettop(L) - arg;
+  int status = 1;
+  for (; nargs--; arg++) {
+    if (lua_type(L, arg) == LUA_TNUMBER) {
+      /* optimization: could be done exactly as for strings */
+      status = status &&
+          fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
+    }
+    else {
+      size_t l;
+      const char *s = luaL_checklstring(L, arg, &l);
+      status = status && (fwrite(s, sizeof(char), l, f) == l);
+    }
+  }
+  if (status) return 1;  /* file handle already on stack top */
+  else return luaL_fileresult(L, status, NULL);
+}
+
+
+static int io_write (lua_State *L) {
+  return g_write(L, getiofile(L, IO_OUTPUT), 1);
+}
+
+
+static int f_write (lua_State *L) {
+  FILE *f = tofile(L);
+  lua_pushvalue(L, 1);  /* push file at the stack top (to be returned) */
+  return g_write(L, f, 2);
+}
+
+
+static int f_seek (lua_State *L) {
+  static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
+  static const char *const modenames[] = {"set", "cur", "end", NULL};
+  FILE *f = tofile(L);
+  int op = luaL_checkoption(L, 2, "cur", modenames);
+  lua_Number p3 = luaL_optnumber(L, 3, 0);
+  l_seeknum offset = (l_seeknum)p3;
+  luaL_argcheck(L, (lua_Number)offset == p3, 3,
+                  "not an integer in proper range");
+  op = l_fseek(f, offset, mode[op]);
+  if (op)
+    return luaL_fileresult(L, 0, NULL);  /* error */
+  else {
+    lua_pushnumber(L, (lua_Number)l_ftell(f));
+    return 1;
+  }
+}
+
+
+static int f_setvbuf (lua_State *L) {
+  static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
+  static const char *const modenames[] = {"no", "full", "line", NULL};
+  FILE *f = tofile(L);
+  int op = luaL_checkoption(L, 2, NULL, modenames);
+  lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
+  int res = setvbuf(f, NULL, mode[op], sz);
+  return luaL_fileresult(L, res == 0, NULL);
+}
+
+
+
+static int io_flush (lua_State *L) {
+  return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
+}
+
+
+static int f_flush (lua_State *L) {
+  return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
+}
+
+
+/*
+** functions for 'io' library
+*/
+static const luaL_Reg iolib[] = {
+  {"close", io_close},
+  {"flush", io_flush},
+  {"input", io_input},
+  {"lines", io_lines},
+  {"open", io_open},
+  {"output", io_output},
+  {"popen", io_popen},
+  {"read", io_read},
+  {"tmpfile", io_tmpfile},
+  {"type", io_type},
+  {"write", io_write},
+  {NULL, NULL}
+};
+
+
+/*
+** methods for file handles
+*/
+static const luaL_Reg flib[] = {
+  {"close", io_close},
+  {"flush", f_flush},
+  {"lines", f_lines},
+  {"read", f_read},
+  {"seek", f_seek},
+  {"setvbuf", f_setvbuf},
+  {"write", f_write},
+  {"__gc", f_gc},
+  {"__tostring", f_tostring},
+  {NULL, NULL}
+};
+
+
+static void createmeta (lua_State *L) {
+  luaL_newmetatable(L, LUA_FILEHANDLE);  /* create metatable for file handles */
+  lua_pushvalue(L, -1);  /* push metatable */
+  lua_setfield(L, -2, "__index");  /* metatable.__index = metatable */
+  luaL_setfuncs(L, flib, 0);  /* add file methods to new metatable */
+  lua_pop(L, 1);  /* pop new metatable */
+}
+
+
+/*
+** function to (not) close the standard files stdin, stdout, and stderr
+*/
+static int io_noclose (lua_State *L) {
+  LStream *p = tolstream(L);
+  p->closef = &io_noclose;  /* keep file opened */
+  lua_pushnil(L);
+  lua_pushliteral(L, "cannot close standard file");
+  return 2;
+}
+
+
+static void createstdfile (lua_State *L, FILE *f, const char *k,
+                           const char *fname) {
+  LStream *p = newprefile(L);
+  p->f = f;
+  p->closef = &io_noclose;
+  if (k != NULL) {
+    lua_pushvalue(L, -1);
+    lua_setfield(L, LUA_REGISTRYINDEX, k);  /* add file to registry */
+  }
+  lua_setfield(L, -2, fname);  /* add file to module */
+}
+
+
+LUAMOD_API int luaopen_io (lua_State *L) {
+  luaL_newlib(L, iolib);  /* new module */
+  createmeta(L);
+  /* create (and set) default files */
+  createstdfile(L, stdin, IO_INPUT, "stdin");
+  createstdfile(L, stdout, IO_OUTPUT, "stdout");
+  createstdfile(L, stderr, NULL, "stderr");
+  return 1;
+}
+
+
+void eris_permiolib(lua_State *L, int forUnpersist) {
+  luaL_checktype(L, -1, LUA_TTABLE);
+  luaL_checkstack(L, 2, NULL);
+
+  if (forUnpersist) {
+    lua_pushstring(L, "__eris.iolib_io_readline");
+    lua_pushcfunction(L, io_readline);
+  }
+  else {
+    lua_pushcfunction(L, io_readline);
+    lua_pushstring(L, "__eris.iolib_io_readline");
+  }
+  lua_rawset(L, -3);
+}
+

=== added file 'src/scripting/eris/llex.c'
--- src/scripting/eris/llex.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/llex.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,527 @@
+/*
+** $Id: llex.c,v 2.63 2013/03/16 21:10:18 roberto Exp $
+** Lexical Analyzer
+** See Copyright Notice in lua.h
+*/
+
+
+#include <locale.h>
+#include <string.h>
+
+#define llex_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lctype.h"
+#include "ldo.h"
+#include "llex.h"
+#include "lobject.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "lzio.h"
+
+
+
+#define next(ls) (ls->current = zgetc(ls->z))
+
+
+
+#define currIsNewline(ls)	(ls->current == '\n' || ls->current == '\r')
+
+
+/* ORDER RESERVED */
+static const char *const luaX_tokens [] = {
+    "and", "break", "do", "else", "elseif",
+    "end", "false", "for", "function", "goto", "if",
+    "in", "local", "nil", "not", "or", "repeat",
+    "return", "then", "true", "until", "while",
+    "..", "...", "==", ">=", "<=", "~=", "::", "<eof>",
+    "<number>", "<name>", "<string>"
+};
+
+
+#define save_and_next(ls) (save(ls, ls->current), next(ls))
+
+
+static l_noret lexerror (LexState *ls, const char *msg, int token);
+
+
+static void save (LexState *ls, int c) {
+  Mbuffer *b = ls->buff;
+  if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) {
+    size_t newsize;
+    if (luaZ_sizebuffer(b) >= MAX_SIZET/2)
+      lexerror(ls, "lexical element too long", 0);
+    newsize = luaZ_sizebuffer(b) * 2;
+    luaZ_resizebuffer(ls->L, b, newsize);
+  }
+  b->buffer[luaZ_bufflen(b)++] = cast(char, c);
+}
+
+
+void luaX_init (lua_State *L) {
+  int i;
+  for (i=0; i<NUM_RESERVED; i++) {
+    TString *ts = luaS_new(L, luaX_tokens[i]);
+    luaS_fix(ts);  /* reserved words are never collected */
+    ts->tsv.extra = cast_byte(i+1);  /* reserved word */
+  }
+}
+
+
+const char *luaX_token2str (LexState *ls, int token) {
+  if (token < FIRST_RESERVED) {  /* single-byte symbols? */
+    lua_assert(token == cast(unsigned char, token));
+    return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) :
+                              luaO_pushfstring(ls->L, "char(%d)", token);
+  }
+  else {
+    const char *s = luaX_tokens[token - FIRST_RESERVED];
+    if (token < TK_EOS)  /* fixed format (symbols and reserved words)? */
+      return luaO_pushfstring(ls->L, LUA_QS, s);
+    else  /* names, strings, and numerals */
+      return s;
+  }
+}
+
+
+static const char *txtToken (LexState *ls, int token) {
+  switch (token) {
+    case TK_NAME:
+    case TK_STRING:
+    case TK_NUMBER:
+      save(ls, '\0');
+      return luaO_pushfstring(ls->L, LUA_QS, luaZ_buffer(ls->buff));
+    default:
+      return luaX_token2str(ls, token);
+  }
+}
+
+
+static l_noret lexerror (LexState *ls, const char *msg, int token) {
+  char buff[LUA_IDSIZE];
+  luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE);
+  msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
+  if (token)
+    luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token));
+  luaD_throw(ls->L, LUA_ERRSYNTAX);
+}
+
+
+l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
+  lexerror(ls, msg, ls->t.token);
+}
+
+
+/*
+** creates a new string and anchors it in function's table so that
+** it will not be collected until the end of the function's compilation
+** (by that time it should be anchored in function's prototype)
+*/
+TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
+  lua_State *L = ls->L;
+  TValue *o;  /* entry for `str' */
+  TString *ts = luaS_newlstr(L, str, l);  /* create new string */
+  setsvalue2s(L, L->top++, ts);  /* temporarily anchor it in stack */
+  o = luaH_set(L, ls->fs->h, L->top - 1);
+  if (ttisnil(o)) {  /* not in use yet? (see 'addK') */
+    /* boolean value does not need GC barrier;
+       table has no metatable, so it does not need to invalidate cache */
+    setbvalue(o, 1);  /* t[string] = true */
+    luaC_checkGC(L);
+  }
+  L->top--;  /* remove string from stack */
+  return ts;
+}
+
+
+/*
+** increment line number and skips newline sequence (any of
+** \n, \r, \n\r, or \r\n)
+*/
+static void inclinenumber (LexState *ls) {
+  int old = ls->current;
+  lua_assert(currIsNewline(ls));
+  next(ls);  /* skip `\n' or `\r' */
+  if (currIsNewline(ls) && ls->current != old)
+    next(ls);  /* skip `\n\r' or `\r\n' */
+  if (++ls->linenumber >= MAX_INT)
+    luaX_syntaxerror(ls, "chunk has too many lines");
+}
+
+
+void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
+                    int firstchar) {
+  ls->decpoint = '.';
+  ls->L = L;
+  ls->current = firstchar;
+  ls->lookahead.token = TK_EOS;  /* no look-ahead token */
+  ls->z = z;
+  ls->fs = NULL;
+  ls->linenumber = 1;
+  ls->lastline = 1;
+  ls->source = source;
+  ls->envn = luaS_new(L, LUA_ENV);  /* create env name */
+  luaS_fix(ls->envn);  /* never collect this name */
+  luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER);  /* initialize buffer */
+}
+
+
+
+/*
+** =======================================================
+** LEXICAL ANALYZER
+** =======================================================
+*/
+
+
+
+static int check_next (LexState *ls, const char *set) {
+  if (ls->current == '\0' || !strchr(set, ls->current))
+    return 0;
+  save_and_next(ls);
+  return 1;
+}
+
+
+/*
+** change all characters 'from' in buffer to 'to'
+*/
+static void buffreplace (LexState *ls, char from, char to) {
+  size_t n = luaZ_bufflen(ls->buff);
+  char *p = luaZ_buffer(ls->buff);
+  while (n--)
+    if (p[n] == from) p[n] = to;
+}
+
+
+#if !defined(getlocaledecpoint)
+#define getlocaledecpoint()	(localeconv()->decimal_point[0])
+#endif
+
+
+#define buff2d(b,e)	luaO_str2d(luaZ_buffer(b), luaZ_bufflen(b) - 1, e)
+
+/*
+** in case of format error, try to change decimal point separator to
+** the one defined in the current locale and check again
+*/
+static void trydecpoint (LexState *ls, SemInfo *seminfo) {
+  char old = ls->decpoint;
+  ls->decpoint = getlocaledecpoint();
+  buffreplace(ls, old, ls->decpoint);  /* try new decimal separator */
+  if (!buff2d(ls->buff, &seminfo->r)) {
+    /* format error with correct decimal point: no more options */
+    buffreplace(ls, ls->decpoint, '.');  /* undo change (for error message) */
+    lexerror(ls, "malformed number", TK_NUMBER);
+  }
+}
+
+
+/* LUA_NUMBER */
+/*
+** this function is quite liberal in what it accepts, as 'luaO_str2d'
+** will reject ill-formed numerals.
+*/
+static void read_numeral (LexState *ls, SemInfo *seminfo) {
+  const char *expo = "Ee";
+  int first = ls->current;
+  lua_assert(lisdigit(ls->current));
+  save_and_next(ls);
+  if (first == '0' && check_next(ls, "Xx"))  /* hexadecimal? */
+    expo = "Pp";
+  for (;;) {
+    if (check_next(ls, expo))  /* exponent part? */
+      check_next(ls, "+-");  /* optional exponent sign */
+    if (lisxdigit(ls->current) || ls->current == '.')
+      save_and_next(ls);
+    else  break;
+  }
+  save(ls, '\0');
+  buffreplace(ls, '.', ls->decpoint);  /* follow locale for decimal point */
+  if (!buff2d(ls->buff, &seminfo->r))  /* format error? */
+    trydecpoint(ls, seminfo); /* try to update decimal point separator */
+}
+
+
+/*
+** skip a sequence '[=*[' or ']=*]' and return its number of '='s or
+** -1 if sequence is malformed
+*/
+static int skip_sep (LexState *ls) {
+  int count = 0;
+  int s = ls->current;
+  lua_assert(s == '[' || s == ']');
+  save_and_next(ls);
+  while (ls->current == '=') {
+    save_and_next(ls);
+    count++;
+  }
+  return (ls->current == s) ? count : (-count) - 1;
+}
+
+
+static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
+  save_and_next(ls);  /* skip 2nd `[' */
+  if (currIsNewline(ls))  /* string starts with a newline? */
+    inclinenumber(ls);  /* skip it */
+  for (;;) {
+    switch (ls->current) {
+      case EOZ:
+        lexerror(ls, (seminfo) ? "unfinished long string" :
+                                 "unfinished long comment", TK_EOS);
+        break;  /* to avoid warnings */
+      case ']': {
+        if (skip_sep(ls) == sep) {
+          save_and_next(ls);  /* skip 2nd `]' */
+          goto endloop;
+        }
+        break;
+      }
+      case '\n': case '\r': {
+        save(ls, '\n');
+        inclinenumber(ls);
+        if (!seminfo) luaZ_resetbuffer(ls->buff);  /* avoid wasting space */
+        break;
+      }
+      default: {
+        if (seminfo) save_and_next(ls);
+        else next(ls);
+      }
+    }
+  } endloop:
+  if (seminfo)
+    seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
+                                     luaZ_bufflen(ls->buff) - 2*(2 + sep));
+}
+
+
+static void escerror (LexState *ls, int *c, int n, const char *msg) {
+  int i;
+  luaZ_resetbuffer(ls->buff);  /* prepare error message */
+  save(ls, '\\');
+  for (i = 0; i < n && c[i] != EOZ; i++)
+    save(ls, c[i]);
+  lexerror(ls, msg, TK_STRING);
+}
+
+
+static int readhexaesc (LexState *ls) {
+  int c[3], i;  /* keep input for error message */
+  int r = 0;  /* result accumulator */
+  c[0] = 'x';  /* for error message */
+  for (i = 1; i < 3; i++) {  /* read two hexadecimal digits */
+    c[i] = next(ls);
+    if (!lisxdigit(c[i]))
+      escerror(ls, c, i + 1, "hexadecimal digit expected");
+    r = (r << 4) + luaO_hexavalue(c[i]);
+  }
+  return r;
+}
+
+
+static int readdecesc (LexState *ls) {
+  int c[3], i;
+  int r = 0;  /* result accumulator */
+  for (i = 0; i < 3 && lisdigit(ls->current); i++) {  /* read up to 3 digits */
+    c[i] = ls->current;
+    r = 10*r + c[i] - '0';
+    next(ls);
+  }
+  if (r > UCHAR_MAX)
+    escerror(ls, c, i, "decimal escape too large");
+  return r;
+}
+
+
+static void read_string (LexState *ls, int del, SemInfo *seminfo) {
+  save_and_next(ls);  /* keep delimiter (for error messages) */
+  while (ls->current != del) {
+    switch (ls->current) {
+      case EOZ:
+        lexerror(ls, "unfinished string", TK_EOS);
+        break;  /* to avoid warnings */
+      case '\n':
+      case '\r':
+        lexerror(ls, "unfinished string", TK_STRING);
+        break;  /* to avoid warnings */
+      case '\\': {  /* escape sequences */
+        int c;  /* final character to be saved */
+        next(ls);  /* do not save the `\' */
+        switch (ls->current) {
+          case 'a': c = '\a'; goto read_save;
+          case 'b': c = '\b'; goto read_save;
+          case 'f': c = '\f'; goto read_save;
+          case 'n': c = '\n'; goto read_save;
+          case 'r': c = '\r'; goto read_save;
+          case 't': c = '\t'; goto read_save;
+          case 'v': c = '\v'; goto read_save;
+          case 'x': c = readhexaesc(ls); goto read_save;
+          case '\n': case '\r':
+            inclinenumber(ls); c = '\n'; goto only_save;
+          case '\\': case '\"': case '\'':
+            c = ls->current; goto read_save;
+          case EOZ: goto no_save;  /* will raise an error next loop */
+          case 'z': {  /* zap following span of spaces */
+            next(ls);  /* skip the 'z' */
+            while (lisspace(ls->current)) {
+              if (currIsNewline(ls)) inclinenumber(ls);
+              else next(ls);
+            }
+            goto no_save;
+          }
+          default: {
+            if (!lisdigit(ls->current))
+              escerror(ls, &ls->current, 1, "invalid escape sequence");
+            /* digital escape \ddd */
+            c = readdecesc(ls);
+            goto only_save;
+          }
+        }
+       read_save: next(ls);  /* read next character */
+       only_save: save(ls, c);  /* save 'c' */
+       no_save: break;
+      }
+      default:
+        save_and_next(ls);
+    }
+  }
+  save_and_next(ls);  /* skip delimiter */
+  seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1,
+                                   luaZ_bufflen(ls->buff) - 2);
+}
+
+
+static int llex (LexState *ls, SemInfo *seminfo) {
+  luaZ_resetbuffer(ls->buff);
+  for (;;) {
+    switch (ls->current) {
+      case '\n': case '\r': {  /* line breaks */
+        inclinenumber(ls);
+        break;
+      }
+      case ' ': case '\f': case '\t': case '\v': {  /* spaces */
+        next(ls);
+        break;
+      }
+      case '-': {  /* '-' or '--' (comment) */
+        next(ls);
+        if (ls->current != '-') return '-';
+        /* else is a comment */
+        next(ls);
+        if (ls->current == '[') {  /* long comment? */
+          int sep = skip_sep(ls);
+          luaZ_resetbuffer(ls->buff);  /* `skip_sep' may dirty the buffer */
+          if (sep >= 0) {
+            read_long_string(ls, NULL, sep);  /* skip long comment */
+            luaZ_resetbuffer(ls->buff);  /* previous call may dirty the buff. */
+            break;
+          }
+        }
+        /* else short comment */
+        while (!currIsNewline(ls) && ls->current != EOZ)
+          next(ls);  /* skip until end of line (or end of file) */
+        break;
+      }
+      case '[': {  /* long string or simply '[' */
+        int sep = skip_sep(ls);
+        if (sep >= 0) {
+          read_long_string(ls, seminfo, sep);
+          return TK_STRING;
+        }
+        else if (sep == -1) return '[';
+        else lexerror(ls, "invalid long string delimiter", TK_STRING);
+      }
+      case '=': {
+        next(ls);
+        if (ls->current != '=') return '=';
+        else { next(ls); return TK_EQ; }
+      }
+      case '<': {
+        next(ls);
+        if (ls->current != '=') return '<';
+        else { next(ls); return TK_LE; }
+      }
+      case '>': {
+        next(ls);
+        if (ls->current != '=') return '>';
+        else { next(ls); return TK_GE; }
+      }
+      case '~': {
+        next(ls);
+        if (ls->current != '=') return '~';
+        else { next(ls); return TK_NE; }
+      }
+      case ':': {
+        next(ls);
+        if (ls->current != ':') return ':';
+        else { next(ls); return TK_DBCOLON; }
+      }
+      case '"': case '\'': {  /* short literal strings */
+        read_string(ls, ls->current, seminfo);
+        return TK_STRING;
+      }
+      case '.': {  /* '.', '..', '...', or number */
+        save_and_next(ls);
+        if (check_next(ls, ".")) {
+          if (check_next(ls, "."))
+            return TK_DOTS;   /* '...' */
+          else return TK_CONCAT;   /* '..' */
+        }
+        else if (!lisdigit(ls->current)) return '.';
+        /* else go through */
+      }
+      case '0': case '1': case '2': case '3': case '4':
+      case '5': case '6': case '7': case '8': case '9': {
+        read_numeral(ls, seminfo);
+        return TK_NUMBER;
+      }
+      case EOZ: {
+        return TK_EOS;
+      }
+      default: {
+        if (lislalpha(ls->current)) {  /* identifier or reserved word? */
+          TString *ts;
+          do {
+            save_and_next(ls);
+          } while (lislalnum(ls->current));
+          ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
+                                  luaZ_bufflen(ls->buff));
+          seminfo->ts = ts;
+          if (isreserved(ts))  /* reserved word? */
+            return ts->tsv.extra - 1 + FIRST_RESERVED;
+          else {
+            return TK_NAME;
+          }
+        }
+        else {  /* single-char tokens (+ - / ...) */
+          int c = ls->current;
+          next(ls);
+          return c;
+        }
+      }
+    }
+  }
+}
+
+
+void luaX_next (LexState *ls) {
+  ls->lastline = ls->linenumber;
+  if (ls->lookahead.token != TK_EOS) {  /* is there a look-ahead token? */
+    ls->t = ls->lookahead;  /* use this one */
+    ls->lookahead.token = TK_EOS;  /* and discharge it */
+  }
+  else
+    ls->t.token = llex(ls, &ls->t.seminfo);  /* read next token */
+}
+
+
+int luaX_lookahead (LexState *ls) {
+  lua_assert(ls->lookahead.token == TK_EOS);
+  ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);
+  return ls->lookahead.token;
+}
+

=== added file 'src/scripting/eris/llex.h'
--- src/scripting/eris/llex.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/llex.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,78 @@
+/*
+** $Id: llex.h,v 1.72 2011/11/30 12:43:51 roberto Exp $
+** Lexical Analyzer
+** See Copyright Notice in lua.h
+*/
+
+#ifndef llex_h
+#define llex_h
+
+#include "lobject.h"
+#include "lzio.h"
+
+
+#define FIRST_RESERVED	257
+
+
+
+/*
+* WARNING: if you change the order of this enumeration,
+* grep "ORDER RESERVED"
+*/
+enum RESERVED {
+  /* terminal symbols denoted by reserved words */
+  TK_AND = FIRST_RESERVED, TK_BREAK,
+  TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
+  TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
+  TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
+  /* other terminal symbols */
+  TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_DBCOLON, TK_EOS,
+  TK_NUMBER, TK_NAME, TK_STRING
+};
+
+/* number of reserved words */
+#define NUM_RESERVED	(cast(int, TK_WHILE-FIRST_RESERVED+1))
+
+
+typedef union {
+  lua_Number r;
+  TString *ts;
+} SemInfo;  /* semantics information */
+
+
+typedef struct Token {
+  int token;
+  SemInfo seminfo;
+} Token;
+
+
+/* state of the lexer plus state of the parser when shared by all
+   functions */
+typedef struct LexState {
+  int current;  /* current character (charint) */
+  int linenumber;  /* input line counter */
+  int lastline;  /* line of last token `consumed' */
+  Token t;  /* current token */
+  Token lookahead;  /* look ahead token */
+  struct FuncState *fs;  /* current function (parser) */
+  struct lua_State *L;
+  ZIO *z;  /* input stream */
+  Mbuffer *buff;  /* buffer for tokens */
+  struct Dyndata *dyd;  /* dynamic structures used by the parser */
+  TString *source;  /* current source name */
+  TString *envn;  /* environment variable name */
+  char decpoint;  /* locale decimal point */
+} LexState;
+
+
+LUAI_FUNC void luaX_init (lua_State *L);
+LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z,
+                              TString *source, int firstchar);
+LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l);
+LUAI_FUNC void luaX_next (LexState *ls);
+LUAI_FUNC int luaX_lookahead (LexState *ls);
+LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s);
+LUAI_FUNC const char *luaX_token2str (LexState *ls, int token);
+
+
+#endif

=== added file 'src/scripting/eris/llimits.h'
--- src/scripting/eris/llimits.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/llimits.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,309 @@
+/*
+** $Id: llimits.h,v 1.103 2013/02/20 14:08:56 roberto Exp $
+** Limits, basic types, and some other `installation-dependent' definitions
+** See Copyright Notice in lua.h
+*/
+
+#ifndef llimits_h
+#define llimits_h
+
+
+#include <limits.h>
+#include <stddef.h>
+
+
+#include "lua.h"
+
+
+typedef unsigned LUA_INT32 lu_int32;
+
+typedef LUAI_UMEM lu_mem;
+
+typedef LUAI_MEM l_mem;
+
+
+
+/* chars used as small naturals (so that `char' is reserved for characters) */
+typedef unsigned char lu_byte;
+
+
+#define MAX_SIZET	((size_t)(~(size_t)0)-2)
+
+#define MAX_LUMEM	((lu_mem)(~(lu_mem)0)-2)
+
+#define MAX_LMEM	((l_mem) ((MAX_LUMEM >> 1) - 2))
+
+
+#define MAX_INT (INT_MAX-2)  /* maximum value of an int (-2 for safety) */
+
+/*
+** conversion of pointer to integer
+** this is for hashing only; there is no problem if the integer
+** cannot hold the whole pointer value
+*/
+#define IntPoint(p)  ((unsigned int)(lu_mem)(p))
+
+
+
+/* type to ensure maximum alignment */
+#if !defined(LUAI_USER_ALIGNMENT_T)
+#define LUAI_USER_ALIGNMENT_T	union { double u; void *s; long l; }
+#endif
+
+typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
+
+
+/* result of a `usual argument conversion' over lua_Number */
+typedef LUAI_UACNUMBER l_uacNumber;
+
+
+/* internal assertions for in-house debugging */
+#if defined(lua_assert)
+#define check_exp(c,e)		(lua_assert(c), (e))
+/* to avoid problems with conditions too long */
+#define lua_longassert(c)	{ if (!(c)) lua_assert(0); }
+#else
+#define lua_assert(c)		((void)0)
+#define check_exp(c,e)		(e)
+#define lua_longassert(c)	((void)0)
+#endif
+
+/*
+** assertion for checking API calls
+*/
+#if !defined(luai_apicheck)
+
+#if defined(LUA_USE_APICHECK)
+#include <assert.h>
+#define luai_apicheck(L,e)	assert(e)
+#else
+#define luai_apicheck(L,e)	lua_assert(e)
+#endif
+
+#endif
+
+#define api_check(l,e,msg)	luai_apicheck(l,(e) && msg)
+
+
+#if !defined(UNUSED)
+#define UNUSED(x)	((void)(x))	/* to avoid warnings */
+#endif
+
+
+#define cast(t, exp)	((t)(exp))
+
+#define cast_byte(i)	cast(lu_byte, (i))
+#define cast_num(i)	cast(lua_Number, (i))
+#define cast_int(i)	cast(int, (i))
+#define cast_uchar(i)	cast(unsigned char, (i))
+
+
+/*
+** non-return type
+*/
+#if defined(__GNUC__)
+#define l_noret		void __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define l_noret		void __declspec(noreturn)
+#else
+#define l_noret		void
+#endif
+
+
+
+/*
+** maximum depth for nested C calls and syntactical nested non-terminals
+** in a program. (Value must fit in an unsigned short int.)
+*/
+#if !defined(LUAI_MAXCCALLS)
+#define LUAI_MAXCCALLS		200
+#endif
+
+/*
+** maximum number of upvalues in a closure (both C and Lua). (Value
+** must fit in an unsigned char.)
+*/
+#define MAXUPVAL	UCHAR_MAX
+
+
+/*
+** type for virtual-machine instructions
+** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
+*/
+typedef lu_int32 Instruction;
+
+
+
+/* maximum stack for a Lua function */
+#define MAXSTACK	250
+
+
+
+/* minimum size for the string table (must be power of 2) */
+#if !defined(MINSTRTABSIZE)
+#define MINSTRTABSIZE	32
+#endif
+
+
+/* minimum size for string buffer */
+#if !defined(LUA_MINBUFFER)
+#define LUA_MINBUFFER	32
+#endif
+
+
+#if !defined(lua_lock)
+#define lua_lock(L)     ((void) 0)
+#define lua_unlock(L)   ((void) 0)
+#endif
+
+#if !defined(luai_threadyield)
+#define luai_threadyield(L)     {lua_unlock(L); lua_lock(L);}
+#endif
+
+
+/*
+** these macros allow user-specific actions on threads when you defined
+** LUAI_EXTRASPACE and need to do something extra when a thread is
+** created/deleted/resumed/yielded.
+*/
+#if !defined(luai_userstateopen)
+#define luai_userstateopen(L)		((void)L)
+#endif
+
+#if !defined(luai_userstateclose)
+#define luai_userstateclose(L)		((void)L)
+#endif
+
+#if !defined(luai_userstatethread)
+#define luai_userstatethread(L,L1)	((void)L)
+#endif
+
+#if !defined(luai_userstatefree)
+#define luai_userstatefree(L,L1)	((void)L)
+#endif
+
+#if !defined(luai_userstateresume)
+#define luai_userstateresume(L,n)       ((void)L)
+#endif
+
+#if !defined(luai_userstateyield)
+#define luai_userstateyield(L,n)        ((void)L)
+#endif
+
+/*
+** lua_number2int is a macro to convert lua_Number to int.
+** lua_number2integer is a macro to convert lua_Number to lua_Integer.
+** lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned.
+** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number.
+** luai_hashnum is a macro to hash a lua_Number value into an integer.
+** The hash must be deterministic and give reasonable values for
+** both small and large values (outside the range of integers).
+*/
+
+#if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK)	/* { */
+/* trick with Microsoft assembler for X86 */
+
+#define lua_number2int(i,n)  __asm {__asm fld n   __asm fistp i}
+#define lua_number2integer(i,n)		lua_number2int(i, n)
+#define lua_number2unsigned(i,n)  \
+  {__int64 l; __asm {__asm fld n   __asm fistp l} i = (unsigned int)l;}
+
+
+#elif defined(LUA_IEEE754TRICK)		/* }{ */
+/* the next trick should work on any machine using IEEE754 with
+   a 32-bit int type */
+
+union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
+
+#if !defined(LUA_IEEEENDIAN)	/* { */
+#define LUAI_EXTRAIEEE	\
+  static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)};
+#define LUA_IEEEENDIANLOC	(ieeeendian.l_p[1] == 33)
+#else
+#define LUA_IEEEENDIANLOC	LUA_IEEEENDIAN
+#define LUAI_EXTRAIEEE		/* empty */
+#endif				/* } */
+
+#define lua_number2int32(i,n,t) \
+  { LUAI_EXTRAIEEE \
+    volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \
+    (i) = (t)u.l_p[LUA_IEEEENDIANLOC]; }
+
+#define luai_hashnum(i,n)  \
+  { volatile union luai_Cast u; u.l_d = (n) + 1.0;  /* avoid -0 */ \
+    (i) = u.l_p[0]; (i) += u.l_p[1]; }  /* add double bits for his hash */
+
+#define lua_number2int(i,n)		lua_number2int32(i, n, int)
+#define lua_number2unsigned(i,n)	lua_number2int32(i, n, lua_Unsigned)
+
+/* the trick can be expanded to lua_Integer when it is a 32-bit value */
+#if defined(LUA_IEEELL)
+#define lua_number2integer(i,n)		lua_number2int32(i, n, lua_Integer)
+#endif
+
+#endif				/* } */
+
+
+/* the following definitions always work, but may be slow */
+
+#if !defined(lua_number2int)
+#define lua_number2int(i,n)	((i)=(int)(n))
+#endif
+
+#if !defined(lua_number2integer)
+#define lua_number2integer(i,n)	((i)=(lua_Integer)(n))
+#endif
+
+#if !defined(lua_number2unsigned)	/* { */
+/* the following definition assures proper modulo behavior */
+#if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT)
+#include <math.h>
+#define SUPUNSIGNED	((lua_Number)(~(lua_Unsigned)0) + 1)
+#define lua_number2unsigned(i,n)  \
+	((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED))
+#else
+#define lua_number2unsigned(i,n)	((i)=(lua_Unsigned)(n))
+#endif
+#endif				/* } */
+
+
+#if !defined(lua_unsigned2number)
+/* on several machines, coercion from unsigned to double is slow,
+   so it may be worth to avoid */
+#define lua_unsigned2number(u)  \
+    (((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u))
+#endif
+
+
+
+#if defined(ltable_c) && !defined(luai_hashnum)
+
+#include <float.h>
+#include <math.h>
+
+#define luai_hashnum(i,n) { int e;  \
+  n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP);  \
+  lua_number2int(i, n); i += e; }
+
+#endif
+
+
+
+/*
+** macro to control inclusion of some hard tests on stack reallocation
+*/
+#if !defined(HARDSTACKTESTS)
+#define condmovestack(L)	((void)0)
+#else
+/* realloc stack keeping its size */
+#define condmovestack(L)	luaD_reallocstack((L), (L)->stacksize)
+#endif
+
+#if !defined(HARDMEMTESTS)
+#define condchangemem(L)	condmovestack(L)
+#else
+#define condchangemem(L)  \
+	((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1)))
+#endif
+
+#endif

=== added file 'src/scripting/eris/lmathlib.c'
--- src/scripting/eris/lmathlib.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lmathlib.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,279 @@
+/*
+** $Id: lmathlib.c,v 1.83 2013/03/07 18:21:32 roberto Exp $
+** Standard mathematical library
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+#include <math.h>
+
+#define lmathlib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#undef PI
+#define PI	((lua_Number)(3.1415926535897932384626433832795))
+#define RADIANS_PER_DEGREE	((lua_Number)(PI/180.0))
+
+
+
+static int math_abs (lua_State *L) {
+  lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_sin (lua_State *L) {
+  lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_sinh (lua_State *L) {
+  lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_cos (lua_State *L) {
+  lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_cosh (lua_State *L) {
+  lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_tan (lua_State *L) {
+  lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_tanh (lua_State *L) {
+  lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_asin (lua_State *L) {
+  lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_acos (lua_State *L) {
+  lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_atan (lua_State *L) {
+  lua_pushnumber(L, l_mathop(atan)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_atan2 (lua_State *L) {
+  lua_pushnumber(L, l_mathop(atan2)(luaL_checknumber(L, 1),
+                                luaL_checknumber(L, 2)));
+  return 1;
+}
+
+static int math_ceil (lua_State *L) {
+  lua_pushnumber(L, l_mathop(ceil)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_floor (lua_State *L) {
+  lua_pushnumber(L, l_mathop(floor)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_fmod (lua_State *L) {
+  lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1),
+                               luaL_checknumber(L, 2)));
+  return 1;
+}
+
+static int math_modf (lua_State *L) {
+  lua_Number ip;
+  lua_Number fp = l_mathop(modf)(luaL_checknumber(L, 1), &ip);
+  lua_pushnumber(L, ip);
+  lua_pushnumber(L, fp);
+  return 2;
+}
+
+static int math_sqrt (lua_State *L) {
+  lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_pow (lua_State *L) {
+  lua_Number x = luaL_checknumber(L, 1);
+  lua_Number y = luaL_checknumber(L, 2);
+  lua_pushnumber(L, l_mathop(pow)(x, y));
+  return 1;
+}
+
+static int math_log (lua_State *L) {
+  lua_Number x = luaL_checknumber(L, 1);
+  lua_Number res;
+  if (lua_isnoneornil(L, 2))
+    res = l_mathop(log)(x);
+  else {
+    lua_Number base = luaL_checknumber(L, 2);
+    if (base == (lua_Number)10.0) res = l_mathop(log10)(x);
+    else res = l_mathop(log)(x)/l_mathop(log)(base);
+  }
+  lua_pushnumber(L, res);
+  return 1;
+}
+
+#if defined(LUA_COMPAT_LOG10)
+static int math_log10 (lua_State *L) {
+  lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
+  return 1;
+}
+#endif
+
+static int math_exp (lua_State *L) {
+  lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_deg (lua_State *L) {
+  lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE);
+  return 1;
+}
+
+static int math_rad (lua_State *L) {
+  lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE);
+  return 1;
+}
+
+static int math_frexp (lua_State *L) {
+  int e;
+  lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e));
+  lua_pushinteger(L, e);
+  return 2;
+}
+
+static int math_ldexp (lua_State *L) {
+  lua_Number x = luaL_checknumber(L, 1);
+  int ep = luaL_checkint(L, 2);
+  lua_pushnumber(L, l_mathop(ldexp)(x, ep));
+  return 1;
+}
+
+
+
+static int math_min (lua_State *L) {
+  int n = lua_gettop(L);  /* number of arguments */
+  lua_Number dmin = luaL_checknumber(L, 1);
+  int i;
+  for (i=2; i<=n; i++) {
+    lua_Number d = luaL_checknumber(L, i);
+    if (d < dmin)
+      dmin = d;
+  }
+  lua_pushnumber(L, dmin);
+  return 1;
+}
+
+
+static int math_max (lua_State *L) {
+  int n = lua_gettop(L);  /* number of arguments */
+  lua_Number dmax = luaL_checknumber(L, 1);
+  int i;
+  for (i=2; i<=n; i++) {
+    lua_Number d = luaL_checknumber(L, i);
+    if (d > dmax)
+      dmax = d;
+  }
+  lua_pushnumber(L, dmax);
+  return 1;
+}
+
+
+static int math_random (lua_State *L) {
+  /* the `%' avoids the (rare) case of r==1, and is needed also because on
+     some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
+  lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
+  switch (lua_gettop(L)) {  /* check number of arguments */
+    case 0: {  /* no arguments */
+      lua_pushnumber(L, r);  /* Number between 0 and 1 */
+      break;
+    }
+    case 1: {  /* only upper limit */
+      lua_Number u = luaL_checknumber(L, 1);
+      luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty");
+      lua_pushnumber(L, l_mathop(floor)(r*u) + (lua_Number)(1.0));  /* [1, u] */
+      break;
+    }
+    case 2: {  /* lower and upper limits */
+      lua_Number l = luaL_checknumber(L, 1);
+      lua_Number u = luaL_checknumber(L, 2);
+      luaL_argcheck(L, l <= u, 2, "interval is empty");
+      lua_pushnumber(L, l_mathop(floor)(r*(u-l+1)) + l);  /* [l, u] */
+      break;
+    }
+    default: return luaL_error(L, "wrong number of arguments");
+  }
+  return 1;
+}
+
+
+static int math_randomseed (lua_State *L) {
+  srand(luaL_checkunsigned(L, 1));
+  (void)rand(); /* discard first value to avoid undesirable correlations */
+  return 0;
+}
+
+
+static const luaL_Reg mathlib[] = {
+  {"abs",   math_abs},
+  {"acos",  math_acos},
+  {"asin",  math_asin},
+  {"atan2", math_atan2},
+  {"atan",  math_atan},
+  {"ceil",  math_ceil},
+  {"cosh",   math_cosh},
+  {"cos",   math_cos},
+  {"deg",   math_deg},
+  {"exp",   math_exp},
+  {"floor", math_floor},
+  {"fmod",   math_fmod},
+  {"frexp", math_frexp},
+  {"ldexp", math_ldexp},
+#if defined(LUA_COMPAT_LOG10)
+  {"log10", math_log10},
+#endif
+  {"log",   math_log},
+  {"max",   math_max},
+  {"min",   math_min},
+  {"modf",   math_modf},
+  {"pow",   math_pow},
+  {"rad",   math_rad},
+  {"random",     math_random},
+  {"randomseed", math_randomseed},
+  {"sinh",   math_sinh},
+  {"sin",   math_sin},
+  {"sqrt",  math_sqrt},
+  {"tanh",   math_tanh},
+  {"tan",   math_tan},
+  {NULL, NULL}
+};
+
+
+/*
+** Open math library
+*/
+LUAMOD_API int luaopen_math (lua_State *L) {
+  luaL_newlib(L, mathlib);
+  lua_pushnumber(L, PI);
+  lua_setfield(L, -2, "pi");
+  lua_pushnumber(L, HUGE_VAL);
+  lua_setfield(L, -2, "huge");
+  return 1;
+}
+

=== added file 'src/scripting/eris/lmem.c'
--- src/scripting/eris/lmem.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lmem.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,99 @@
+/*
+** $Id: lmem.c,v 1.84 2012/05/23 15:41:53 roberto Exp $
+** Interface to Memory Manager
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stddef.h>
+
+#define lmem_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+
+/*
+** About the realloc function:
+** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
+** (`osize' is the old size, `nsize' is the new size)
+**
+** * frealloc(ud, NULL, x, s) creates a new block of size `s' (no
+** matter 'x').
+**
+** * frealloc(ud, p, x, 0) frees the block `p'
+** (in this specific case, frealloc must return NULL);
+** particularly, frealloc(ud, NULL, 0, 0) does nothing
+** (which is equivalent to free(NULL) in ANSI C)
+**
+** frealloc returns NULL if it cannot create or reallocate the area
+** (any reallocation to an equal or smaller size cannot fail!)
+*/
+
+
+
+#define MINSIZEARRAY	4
+
+
+void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
+                     int limit, const char *what) {
+  void *newblock;
+  int newsize;
+  if (*size >= limit/2) {  /* cannot double it? */
+    if (*size >= limit)  /* cannot grow even a little? */
+      luaG_runerror(L, "too many %s (limit is %d)", what, limit);
+    newsize = limit;  /* still have at least one free place */
+  }
+  else {
+    newsize = (*size)*2;
+    if (newsize < MINSIZEARRAY)
+      newsize = MINSIZEARRAY;  /* minimum size */
+  }
+  newblock = luaM_reallocv(L, block, *size, newsize, size_elems);
+  *size = newsize;  /* update only when everything else is OK */
+  return newblock;
+}
+
+
+l_noret luaM_toobig (lua_State *L) {
+  luaG_runerror(L, "memory allocation error: block too big");
+}
+
+
+
+/*
+** generic allocation routine.
+*/
+void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
+  void *newblock;
+  global_State *g = G(L);
+  size_t realosize = (block) ? osize : 0;
+  lua_assert((realosize == 0) == (block == NULL));
+#if defined(HARDMEMTESTS)
+  if (nsize > realosize && g->gcrunning)
+    luaC_fullgc(L, 1);  /* force a GC whenever possible */
+#endif
+  newblock = (*g->frealloc)(g->ud, block, osize, nsize);
+  if (newblock == NULL && nsize > 0) {
+    api_check(L, nsize > realosize,
+                 "realloc cannot fail when shrinking a block");
+    if (g->gcrunning) {
+      luaC_fullgc(L, 1);  /* try to free some memory... */
+      newblock = (*g->frealloc)(g->ud, block, osize, nsize);  /* try again */
+    }
+    if (newblock == NULL)
+      luaD_throw(L, LUA_ERRMEM);
+  }
+  lua_assert((nsize == 0) == (newblock == NULL));
+  g->GCdebt = (g->GCdebt + nsize) - realosize;
+  return newblock;
+}
+

=== added file 'src/scripting/eris/lmem.h'
--- src/scripting/eris/lmem.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lmem.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,57 @@
+/*
+** $Id: lmem.h,v 1.40 2013/02/20 14:08:21 roberto Exp $
+** Interface to Memory Manager
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lmem_h
+#define lmem_h
+
+
+#include <stddef.h>
+
+#include "llimits.h"
+#include "lua.h"
+
+
+/*
+** This macro avoids the runtime division MAX_SIZET/(e), as 'e' is
+** always constant.
+** The macro is somewhat complex to avoid warnings:
+** +1 avoids warnings of "comparison has constant result";
+** cast to 'void' avoids warnings of "value unused".
+*/
+#define luaM_reallocv(L,b,on,n,e) \
+  (cast(void, \
+     (cast(size_t, (n)+1) > MAX_SIZET/(e)) ? (luaM_toobig(L), 0) : 0), \
+   luaM_realloc_(L, (b), (on)*(e), (n)*(e)))
+
+#define luaM_freemem(L, b, s)	luaM_realloc_(L, (b), (s), 0)
+#define luaM_free(L, b)		luaM_realloc_(L, (b), sizeof(*(b)), 0)
+#define luaM_freearray(L, b, n)   luaM_reallocv(L, (b), n, 0, sizeof((b)[0]))
+
+#define luaM_malloc(L,s)	luaM_realloc_(L, NULL, 0, (s))
+#define luaM_new(L,t)		cast(t *, luaM_malloc(L, sizeof(t)))
+#define luaM_newvector(L,n,t) \
+		cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t)))
+
+#define luaM_newobject(L,tag,s)	luaM_realloc_(L, NULL, tag, (s))
+
+#define luaM_growvector(L,v,nelems,size,t,limit,e) \
+          if ((nelems)+1 > (size)) \
+            ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))
+
+#define luaM_reallocvector(L, v,oldn,n,t) \
+   ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t))))
+
+LUAI_FUNC l_noret luaM_toobig (lua_State *L);
+
+/* not to be called directly */
+LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
+                                                          size_t size);
+LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,
+                               size_t size_elem, int limit,
+                               const char *what);
+
+#endif
+

=== added file 'src/scripting/eris/loadlib.c'
--- src/scripting/eris/loadlib.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/loadlib.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,759 @@
+/*
+** $Id: loadlib.c,v 1.111 2012/05/30 12:33:44 roberto Exp $
+** Dynamic library loader for Lua
+** See Copyright Notice in lua.h
+**
+** This module contains an implementation of loadlib for Unix systems
+** that have dlfcn, an implementation for Windows, and a stub for other
+** systems.
+*/
+
+
+/*
+** if needed, includes windows header before everything else
+*/
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+
+#include <stdlib.h>
+#include <string.h>
+
+
+#define loadlib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/*
+** LUA_PATH and LUA_CPATH are the names of the environment
+** variables that Lua check to set its paths.
+*/
+#if !defined(LUA_PATH)
+#define LUA_PATH	"LUA_PATH"
+#endif
+
+#if !defined(LUA_CPATH)
+#define LUA_CPATH	"LUA_CPATH"
+#endif
+
+#define LUA_PATHSUFFIX		"_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
+
+#define LUA_PATHVERSION		LUA_PATH LUA_PATHSUFFIX
+#define LUA_CPATHVERSION	LUA_CPATH LUA_PATHSUFFIX
+
+/*
+** LUA_PATH_SEP is the character that separates templates in a path.
+** LUA_PATH_MARK is the string that marks the substitution points in a
+** template.
+** LUA_EXEC_DIR in a Windows path is replaced by the executable's
+** directory.
+** LUA_IGMARK is a mark to ignore all before it when building the
+** luaopen_ function name.
+*/
+#if !defined (LUA_PATH_SEP)
+#define LUA_PATH_SEP		";"
+#endif
+#if !defined (LUA_PATH_MARK)
+#define LUA_PATH_MARK		"?"
+#endif
+#if !defined (LUA_EXEC_DIR)
+#define LUA_EXEC_DIR		"!"
+#endif
+#if !defined (LUA_IGMARK)
+#define LUA_IGMARK		"-"
+#endif
+
+
+/*
+** LUA_CSUBSEP is the character that replaces dots in submodule names
+** when searching for a C loader.
+** LUA_LSUBSEP is the character that replaces dots in submodule names
+** when searching for a Lua loader.
+*/
+#if !defined(LUA_CSUBSEP)
+#define LUA_CSUBSEP		LUA_DIRSEP
+#endif
+
+#if !defined(LUA_LSUBSEP)
+#define LUA_LSUBSEP		LUA_DIRSEP
+#endif
+
+
+/* prefix for open functions in C libraries */
+#define LUA_POF		"luaopen_"
+
+/* separator for open functions in C libraries */
+#define LUA_OFSEP	"_"
+
+
+/* table (in the registry) that keeps handles for all loaded C libraries */
+#define CLIBS		"_CLIBS"
+
+#define LIB_FAIL	"open"
+
+
+/* error codes for ll_loadfunc */
+#define ERRLIB		1
+#define ERRFUNC		2
+
+#define setprogdir(L)		((void)0)
+
+
+/*
+** system-dependent functions
+*/
+static void ll_unloadlib (void *lib);
+static void *ll_load (lua_State *L, const char *path, int seeglb);
+static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym);
+
+
+
+#if defined(LUA_USE_DLOPEN)
+/*
+** {========================================================================
+** This is an implementation of loadlib based on the dlfcn interface.
+** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+** NetBSD, AIX 4.2, HPUX 11, and  probably most other Unix flavors, at least
+** as an emulation layer on top of native functions.
+** =========================================================================
+*/
+
+#include <dlfcn.h>
+
+static void ll_unloadlib (void *lib) {
+  dlclose(lib);
+}
+
+
+static void *ll_load (lua_State *L, const char *path, int seeglb) {
+  void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL));
+  if (lib == NULL) lua_pushstring(L, dlerror());
+  return lib;
+}
+
+
+static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
+  lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
+  if (f == NULL) lua_pushstring(L, dlerror());
+  return f;
+}
+
+/* }====================================================== */
+
+
+
+#elif defined(LUA_DL_DLL)
+/*
+** {======================================================================
+** This is an implementation of loadlib for Windows using native functions.
+** =======================================================================
+*/
+
+#undef setprogdir
+
+/*
+** optional flags for LoadLibraryEx
+*/
+#if !defined(LUA_LLE_FLAGS)
+#define LUA_LLE_FLAGS	0
+#endif
+
+
+static void setprogdir (lua_State *L) {
+  char buff[MAX_PATH + 1];
+  char *lb;
+  DWORD nsize = sizeof(buff)/sizeof(char);
+  DWORD n = GetModuleFileNameA(NULL, buff, nsize);
+  if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
+    luaL_error(L, "unable to get ModuleFileName");
+  else {
+    *lb = '\0';
+    luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);
+    lua_remove(L, -2);  /* remove original string */
+  }
+}
+
+
+static void pusherror (lua_State *L) {
+  int error = GetLastError();
+  char buffer[128];
+  if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
+      NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL))
+    lua_pushstring(L, buffer);
+  else
+    lua_pushfstring(L, "system error %d\n", error);
+}
+
+static void ll_unloadlib (void *lib) {
+  FreeLibrary((HMODULE)lib);
+}
+
+
+static void *ll_load (lua_State *L, const char *path, int seeglb) {
+  HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS);
+  (void)(seeglb);  /* not used: symbols are 'global' by default */
+  if (lib == NULL) pusherror(L);
+  return lib;
+}
+
+
+static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
+  lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym);
+  if (f == NULL) pusherror(L);
+  return f;
+}
+
+/* }====================================================== */
+
+
+#else
+/*
+** {======================================================
+** Fallback for other systems
+** =======================================================
+*/
+
+#undef LIB_FAIL
+#define LIB_FAIL	"absent"
+
+
+#define DLMSG	"dynamic libraries not enabled; check your Lua installation"
+
+
+static void ll_unloadlib (void *lib) {
+  (void)(lib);  /* not used */
+}
+
+
+static void *ll_load (lua_State *L, const char *path, int seeglb) {
+  (void)(path); (void)(seeglb);  /* not used */
+  lua_pushliteral(L, DLMSG);
+  return NULL;
+}
+
+
+static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
+  (void)(lib); (void)(sym);  /* not used */
+  lua_pushliteral(L, DLMSG);
+  return NULL;
+}
+
+/* }====================================================== */
+#endif
+
+
+static void *ll_checkclib (lua_State *L, const char *path) {
+  void *plib;
+  lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
+  lua_getfield(L, -1, path);
+  plib = lua_touserdata(L, -1);  /* plib = CLIBS[path] */
+  lua_pop(L, 2);  /* pop CLIBS table and 'plib' */
+  return plib;
+}
+
+
+static void ll_addtoclib (lua_State *L, const char *path, void *plib) {
+  lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
+  lua_pushlightuserdata(L, plib);
+  lua_pushvalue(L, -1);
+  lua_setfield(L, -3, path);  /* CLIBS[path] = plib */
+  lua_rawseti(L, -2, luaL_len(L, -2) + 1);  /* CLIBS[#CLIBS + 1] = plib */
+  lua_pop(L, 1);  /* pop CLIBS table */
+}
+
+
+/*
+** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib
+** handles in list CLIBS
+*/
+static int gctm (lua_State *L) {
+  int n = luaL_len(L, 1);
+  for (; n >= 1; n--) {  /* for each handle, in reverse order */
+    lua_rawgeti(L, 1, n);  /* get handle CLIBS[n] */
+    ll_unloadlib(lua_touserdata(L, -1));
+    lua_pop(L, 1);  /* pop handle */
+  }
+  return 0;
+}
+
+
+static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
+  void *reg = ll_checkclib(L, path);  /* check loaded C libraries */
+  if (reg == NULL) {  /* must load library? */
+    reg = ll_load(L, path, *sym == '*');
+    if (reg == NULL) return ERRLIB;  /* unable to load library */
+    ll_addtoclib(L, path, reg);
+  }
+  if (*sym == '*') {  /* loading only library (no function)? */
+    lua_pushboolean(L, 1);  /* return 'true' */
+    return 0;  /* no errors */
+  }
+  else {
+    lua_CFunction f = ll_sym(L, reg, sym);
+    if (f == NULL)
+      return ERRFUNC;  /* unable to find function */
+    lua_pushcfunction(L, f);  /* else create new function */
+    return 0;  /* no errors */
+  }
+}
+
+
+static int ll_loadlib (lua_State *L) {
+  const char *path = luaL_checkstring(L, 1);
+  const char *init = luaL_checkstring(L, 2);
+  int stat = ll_loadfunc(L, path, init);
+  if (stat == 0)  /* no errors? */
+    return 1;  /* return the loaded function */
+  else {  /* error; error message is on stack top */
+    lua_pushnil(L);
+    lua_insert(L, -2);
+    lua_pushstring(L, (stat == ERRLIB) ?  LIB_FAIL : "init");
+    return 3;  /* return nil, error message, and where */
+  }
+}
+
+
+
+/*
+** {======================================================
+** 'require' function
+** =======================================================
+*/
+
+
+static int readable (const char *filename) {
+  FILE *f = fopen(filename, "r");  /* try to open file */
+  if (f == NULL) return 0;  /* open failed */
+  fclose(f);
+  return 1;
+}
+
+
+static const char *pushnexttemplate (lua_State *L, const char *path) {
+  const char *l;
+  while (*path == *LUA_PATH_SEP) path++;  /* skip separators */
+  if (*path == '\0') return NULL;  /* no more templates */
+  l = strchr(path, *LUA_PATH_SEP);  /* find next separator */
+  if (l == NULL) l = path + strlen(path);
+  lua_pushlstring(L, path, l - path);  /* template */
+  return l;
+}
+
+
+static const char *searchpath (lua_State *L, const char *name,
+                                             const char *path,
+                                             const char *sep,
+                                             const char *dirsep) {
+  luaL_Buffer msg;  /* to build error message */
+  luaL_buffinit(L, &msg);
+  if (*sep != '\0')  /* non-empty separator? */
+    name = luaL_gsub(L, name, sep, dirsep);  /* replace it by 'dirsep' */
+  while ((path = pushnexttemplate(L, path)) != NULL) {
+    const char *filename = luaL_gsub(L, lua_tostring(L, -1),
+                                     LUA_PATH_MARK, name);
+    lua_remove(L, -2);  /* remove path template */
+    if (readable(filename))  /* does file exist and is readable? */
+      return filename;  /* return that file name */
+    lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
+    lua_remove(L, -2);  /* remove file name */
+    luaL_addvalue(&msg);  /* concatenate error msg. entry */
+  }
+  luaL_pushresult(&msg);  /* create error message */
+  return NULL;  /* not found */
+}
+
+
+static int ll_searchpath (lua_State *L) {
+  const char *f = searchpath(L, luaL_checkstring(L, 1),
+                                luaL_checkstring(L, 2),
+                                luaL_optstring(L, 3, "."),
+                                luaL_optstring(L, 4, LUA_DIRSEP));
+  if (f != NULL) return 1;
+  else {  /* error message is on top of the stack */
+    lua_pushnil(L);
+    lua_insert(L, -2);
+    return 2;  /* return nil + error message */
+  }
+}
+
+
+static const char *findfile (lua_State *L, const char *name,
+                                           const char *pname,
+                                           const char *dirsep) {
+  const char *path;
+  lua_getfield(L, lua_upvalueindex(1), pname);
+  path = lua_tostring(L, -1);
+  if (path == NULL)
+    luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
+  return searchpath(L, name, path, ".", dirsep);
+}
+
+
+static int checkload (lua_State *L, int stat, const char *filename) {
+  if (stat) {  /* module loaded successfully? */
+    lua_pushstring(L, filename);  /* will be 2nd argument to module */
+    return 2;  /* return open function and file name */
+  }
+  else
+    return luaL_error(L, "error loading module " LUA_QS
+                         " from file " LUA_QS ":\n\t%s",
+                          lua_tostring(L, 1), filename, lua_tostring(L, -1));
+}
+
+
+static int searcher_Lua (lua_State *L) {
+  const char *filename;
+  const char *name = luaL_checkstring(L, 1);
+  filename = findfile(L, name, "path", LUA_LSUBSEP);
+  if (filename == NULL) return 1;  /* module not found in this path */
+  return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename);
+}
+
+
+static int loadfunc (lua_State *L, const char *filename, const char *modname) {
+  const char *funcname;
+  const char *mark;
+  modname = luaL_gsub(L, modname, ".", LUA_OFSEP);
+  mark = strchr(modname, *LUA_IGMARK);
+  if (mark) {
+    int stat;
+    funcname = lua_pushlstring(L, modname, mark - modname);
+    funcname = lua_pushfstring(L, LUA_POF"%s", funcname);
+    stat = ll_loadfunc(L, filename, funcname);
+    if (stat != ERRFUNC) return stat;
+    modname = mark + 1;  /* else go ahead and try old-style name */
+  }
+  funcname = lua_pushfstring(L, LUA_POF"%s", modname);
+  return ll_loadfunc(L, filename, funcname);
+}
+
+
+static int searcher_C (lua_State *L) {
+  const char *name = luaL_checkstring(L, 1);
+  const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP);
+  if (filename == NULL) return 1;  /* module not found in this path */
+  return checkload(L, (loadfunc(L, filename, name) == 0), filename);
+}
+
+
+static int searcher_Croot (lua_State *L) {
+  const char *filename;
+  const char *name = luaL_checkstring(L, 1);
+  const char *p = strchr(name, '.');
+  int stat;
+  if (p == NULL) return 0;  /* is root */
+  lua_pushlstring(L, name, p - name);
+  filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP);
+  if (filename == NULL) return 1;  /* root not found */
+  if ((stat = loadfunc(L, filename, name)) != 0) {
+    if (stat != ERRFUNC)
+      return checkload(L, 0, filename);  /* real error */
+    else {  /* open function not found */
+      lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
+                         name, filename);
+      return 1;
+    }
+  }
+  lua_pushstring(L, filename);  /* will be 2nd argument to module */
+  return 2;
+}
+
+
+static int searcher_preload (lua_State *L) {
+  const char *name = luaL_checkstring(L, 1);
+  lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD");
+  lua_getfield(L, -1, name);
+  if (lua_isnil(L, -1))  /* not found? */
+    lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
+  return 1;
+}
+
+
+static void findloader (lua_State *L, const char *name) {
+  int i;
+  luaL_Buffer msg;  /* to build error message */
+  luaL_buffinit(L, &msg);
+  lua_getfield(L, lua_upvalueindex(1), "searchers");  /* will be at index 3 */
+  if (!lua_istable(L, 3))
+    luaL_error(L, LUA_QL("package.searchers") " must be a table");
+  /*  iterate over available searchers to find a loader */
+  for (i = 1; ; i++) {
+    lua_rawgeti(L, 3, i);  /* get a searcher */
+    if (lua_isnil(L, -1)) {  /* no more searchers? */
+      lua_pop(L, 1);  /* remove nil */
+      luaL_pushresult(&msg);  /* create error message */
+      luaL_error(L, "module " LUA_QS " not found:%s",
+                    name, lua_tostring(L, -1));
+    }
+    lua_pushstring(L, name);
+    lua_call(L, 1, 2);  /* call it */
+    if (lua_isfunction(L, -2))  /* did it find a loader? */
+      return;  /* module loader found */
+    else if (lua_isstring(L, -2)) {  /* searcher returned error message? */
+      lua_pop(L, 1);  /* remove extra return */
+      luaL_addvalue(&msg);  /* concatenate error message */
+    }
+    else
+      lua_pop(L, 2);  /* remove both returns */
+  }
+}
+
+
+static int ll_require (lua_State *L) {
+  const char *name = luaL_checkstring(L, 1);
+  lua_settop(L, 1);  /* _LOADED table will be at index 2 */
+  lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+  lua_getfield(L, 2, name);  /* _LOADED[name] */
+  if (lua_toboolean(L, -1))  /* is it there? */
+    return 1;  /* package is already loaded */
+  /* else must load package */
+  lua_pop(L, 1);  /* remove 'getfield' result */
+  findloader(L, name);
+  lua_pushstring(L, name);  /* pass name as argument to module loader */
+  lua_insert(L, -2);  /* name is 1st argument (before search data) */
+  lua_call(L, 2, 1);  /* run loader to load module */
+  if (!lua_isnil(L, -1))  /* non-nil return? */
+    lua_setfield(L, 2, name);  /* _LOADED[name] = returned value */
+  lua_getfield(L, 2, name);
+  if (lua_isnil(L, -1)) {   /* module did not set a value? */
+    lua_pushboolean(L, 1);  /* use true as result */
+    lua_pushvalue(L, -1);  /* extra copy to be returned */
+    lua_setfield(L, 2, name);  /* _LOADED[name] = true */
+  }
+  return 1;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** 'module' function
+** =======================================================
+*/
+#if defined(LUA_COMPAT_MODULE)
+
+/*
+** changes the environment variable of calling function
+*/
+static void set_env (lua_State *L) {
+  lua_Debug ar;
+  if (lua_getstack(L, 1, &ar) == 0 ||
+      lua_getinfo(L, "f", &ar) == 0 ||  /* get calling function */
+      lua_iscfunction(L, -1))
+    luaL_error(L, LUA_QL("module") " not called from a Lua function");
+  lua_pushvalue(L, -2);  /* copy new environment table to top */
+  lua_setupvalue(L, -2, 1);
+  lua_pop(L, 1);  /* remove function */
+}
+
+
+static void dooptions (lua_State *L, int n) {
+  int i;
+  for (i = 2; i <= n; i++) {
+    if (lua_isfunction(L, i)) {  /* avoid 'calling' extra info. */
+      lua_pushvalue(L, i);  /* get option (a function) */
+      lua_pushvalue(L, -2);  /* module */
+      lua_call(L, 1, 0);
+    }
+  }
+}
+
+
+static void modinit (lua_State *L, const char *modname) {
+  const char *dot;
+  lua_pushvalue(L, -1);
+  lua_setfield(L, -2, "_M");  /* module._M = module */
+  lua_pushstring(L, modname);
+  lua_setfield(L, -2, "_NAME");
+  dot = strrchr(modname, '.');  /* look for last dot in module name */
+  if (dot == NULL) dot = modname;
+  else dot++;
+  /* set _PACKAGE as package name (full module name minus last part) */
+  lua_pushlstring(L, modname, dot - modname);
+  lua_setfield(L, -2, "_PACKAGE");
+}
+
+
+static int ll_module (lua_State *L) {
+  const char *modname = luaL_checkstring(L, 1);
+  int lastarg = lua_gettop(L);  /* last parameter */
+  luaL_pushmodule(L, modname, 1);  /* get/create module table */
+  /* check whether table already has a _NAME field */
+  lua_getfield(L, -1, "_NAME");
+  if (!lua_isnil(L, -1))  /* is table an initialized module? */
+    lua_pop(L, 1);
+  else {  /* no; initialize it */
+    lua_pop(L, 1);
+    modinit(L, modname);
+  }
+  lua_pushvalue(L, -1);
+  set_env(L);
+  dooptions(L, lastarg);
+  return 1;
+}
+
+
+static int ll_seeall (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  if (!lua_getmetatable(L, 1)) {
+    lua_createtable(L, 0, 1); /* create new metatable */
+    lua_pushvalue(L, -1);
+    lua_setmetatable(L, 1);
+  }
+  lua_pushglobaltable(L);
+  lua_setfield(L, -2, "__index");  /* mt.__index = _G */
+  return 0;
+}
+
+#endif
+/* }====================================================== */
+
+
+
+/* auxiliary mark (for internal use) */
+#define AUXMARK		"\1"
+
+
+/*
+** return registry.LUA_NOENV as a boolean
+*/
+static int noenv (lua_State *L) {
+  int b;
+  lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
+  b = lua_toboolean(L, -1);
+  lua_pop(L, 1);  /* remove value */
+  return b;
+}
+
+
+static void setpath (lua_State *L, const char *fieldname, const char *envname1,
+                                   const char *envname2, const char *def) {
+  const char *path = getenv(envname1);
+  if (path == NULL)  /* no environment variable? */
+    path = getenv(envname2);  /* try alternative name */
+  if (path == NULL || noenv(L))  /* no environment variable? */
+    lua_pushstring(L, def);  /* use default */
+  else {
+    /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
+    path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
+                              LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
+    luaL_gsub(L, path, AUXMARK, def);
+    lua_remove(L, -2);
+  }
+  setprogdir(L);
+  lua_setfield(L, -2, fieldname);
+}
+
+
+static const luaL_Reg pk_funcs[] = {
+  {"loadlib", ll_loadlib},
+  {"searchpath", ll_searchpath},
+#if defined(LUA_COMPAT_MODULE)
+  {"seeall", ll_seeall},
+#endif
+  {NULL, NULL}
+};
+
+
+static const luaL_Reg ll_funcs[] = {
+#if defined(LUA_COMPAT_MODULE)
+  {"module", ll_module},
+#endif
+  {"require", ll_require},
+  {NULL, NULL}
+};
+
+
+static void createsearcherstable (lua_State *L) {
+  static const lua_CFunction searchers[] =
+    {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
+  int i;
+  /* create 'searchers' table */
+  lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
+  /* fill it with pre-defined searchers */
+  for (i=0; searchers[i] != NULL; i++) {
+    lua_pushvalue(L, -2);  /* set 'package' as upvalue for all searchers */
+    lua_pushcclosure(L, searchers[i], 1);
+    lua_rawseti(L, -2, i+1);
+  }
+}
+
+
+LUAMOD_API int luaopen_package (lua_State *L) {
+  /* create table CLIBS to keep track of loaded C libraries */
+  luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS);
+  lua_createtable(L, 0, 1);  /* metatable for CLIBS */
+  lua_pushcfunction(L, gctm);
+  lua_setfield(L, -2, "__gc");  /* set finalizer for CLIBS table */
+  lua_setmetatable(L, -2);
+  /* create `package' table */
+  luaL_newlib(L, pk_funcs);
+  createsearcherstable(L);
+#if defined(LUA_COMPAT_LOADERS)
+  lua_pushvalue(L, -1);  /* make a copy of 'searchers' table */
+  lua_setfield(L, -3, "loaders");  /* put it in field `loaders' */
+#endif
+  lua_setfield(L, -2, "searchers");  /* put it in field 'searchers' */
+  /* set field 'path' */
+  setpath(L, "path", LUA_PATHVERSION, LUA_PATH, LUA_PATH_DEFAULT);
+  /* set field 'cpath' */
+  setpath(L, "cpath", LUA_CPATHVERSION, LUA_CPATH, LUA_CPATH_DEFAULT);
+  /* store config information */
+  lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
+                     LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
+  lua_setfield(L, -2, "config");
+  /* set field `loaded' */
+  luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
+  lua_setfield(L, -2, "loaded");
+  /* set field `preload' */
+  luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+  lua_setfield(L, -2, "preload");
+  lua_pushglobaltable(L);
+  lua_pushvalue(L, -2);  /* set 'package' as upvalue for next lib */
+  luaL_setfuncs(L, ll_funcs, 1);  /* open lib into global table */
+  lua_pop(L, 1);  /* pop global table */
+  return 1;  /* return 'package' table */
+}
+
+
+void eris_permloadlib(lua_State *L, int forUnpersist) {
+  static const lua_CFunction searchers[] = {
+    searcher_preload,
+    searcher_Lua,
+    searcher_C,
+    searcher_Croot,
+    NULL
+  };
+  static const char *const searchernames[] = {
+    "__eris.loadlib_searcher_preload",
+    "__eris.loadlib_searcher_Lua",
+    "__eris.loadlib_searcher_C",
+    "__eris.loadlib_searcher_Croot",
+    NULL
+  };
+  int i;
+
+  luaL_checktype(L, -1, LUA_TTABLE);
+  luaL_checkstack(L, 2, NULL);
+
+  for (i = 0; searchers[i]; ++i) {
+    if (forUnpersist) {
+      lua_pushstring(L, searchernames[i]);
+      lua_pushcfunction(L, searchers[i]);
+    }
+    else {
+      lua_pushcfunction(L, searchers[i]);
+      lua_pushstring(L, searchernames[i]);
+    }
+    lua_rawset(L, -3);
+  }
+}
+

=== added file 'src/scripting/eris/lobject.c'
--- src/scripting/eris/lobject.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lobject.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,287 @@
+/*
+** $Id: lobject.c,v 2.58 2013/02/20 14:08:56 roberto Exp $
+** Some generic functions over Lua objects
+** See Copyright Notice in lua.h
+*/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define lobject_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lctype.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "lvm.h"
+
+
+
+LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT};
+
+
+/*
+** converts an integer to a "floating point byte", represented as
+** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
+** eeeee != 0 and (xxx) otherwise.
+*/
+int luaO_int2fb (unsigned int x) {
+  int e = 0;  /* exponent */
+  if (x < 8) return x;
+  while (x >= 0x10) {
+    x = (x+1) >> 1;
+    e++;
+  }
+  return ((e+1) << 3) | (cast_int(x) - 8);
+}
+
+
+/* converts back */
+int luaO_fb2int (int x) {
+  int e = (x >> 3) & 0x1f;
+  if (e == 0) return x;
+  else return ((x & 7) + 8) << (e - 1);
+}
+
+
+int luaO_ceillog2 (unsigned int x) {
+  static const lu_byte log_2[256] = {
+    0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+  };
+  int l = 0;
+  x--;
+  while (x >= 256) { l += 8; x >>= 8; }
+  return l + log_2[x];
+}
+
+
+lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) {
+  switch (op) {
+    case LUA_OPADD: return luai_numadd(NULL, v1, v2);
+    case LUA_OPSUB: return luai_numsub(NULL, v1, v2);
+    case LUA_OPMUL: return luai_nummul(NULL, v1, v2);
+    case LUA_OPDIV: return luai_numdiv(NULL, v1, v2);
+    case LUA_OPMOD: return luai_nummod(NULL, v1, v2);
+    case LUA_OPPOW: return luai_numpow(NULL, v1, v2);
+    case LUA_OPUNM: return luai_numunm(NULL, v1);
+    default: lua_assert(0); return 0;
+  }
+}
+
+
+int luaO_hexavalue (int c) {
+  if (lisdigit(c)) return c - '0';
+  else return ltolower(c) - 'a' + 10;
+}
+
+
+#if !defined(lua_strx2number)
+
+#include <math.h>
+
+
+static int isneg (const char **s) {
+  if (**s == '-') { (*s)++; return 1; }
+  else if (**s == '+') (*s)++;
+  return 0;
+}
+
+
+static lua_Number readhexa (const char **s, lua_Number r, int *count) {
+  for (; lisxdigit(cast_uchar(**s)); (*s)++) {  /* read integer part */
+    r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s)));
+    (*count)++;
+  }
+  return r;
+}
+
+
+/*
+** convert an hexadecimal numeric string to a number, following
+** C99 specification for 'strtod'
+*/
+static lua_Number lua_strx2number (const char *s, char **endptr) {
+  lua_Number r = 0.0;
+  int e = 0, i = 0;
+  int neg = 0;  /* 1 if number is negative */
+  *endptr = cast(char *, s);  /* nothing is valid yet */
+  while (lisspace(cast_uchar(*s))) s++;  /* skip initial spaces */
+  neg = isneg(&s);  /* check signal */
+  if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')))  /* check '0x' */
+    return 0.0;  /* invalid format (no '0x') */
+  s += 2;  /* skip '0x' */
+  r = readhexa(&s, r, &i);  /* read integer part */
+  if (*s == '.') {
+    s++;  /* skip dot */
+    r = readhexa(&s, r, &e);  /* read fractional part */
+  }
+  if (i == 0 && e == 0)
+    return 0.0;  /* invalid format (no digit) */
+  e *= -4;  /* each fractional digit divides value by 2^-4 */
+  *endptr = cast(char *, s);  /* valid up to here */
+  if (*s == 'p' || *s == 'P') {  /* exponent part? */
+    int exp1 = 0;
+    int neg1;
+    s++;  /* skip 'p' */
+    neg1 = isneg(&s);  /* signal */
+    if (!lisdigit(cast_uchar(*s)))
+      goto ret;  /* must have at least one digit */
+    while (lisdigit(cast_uchar(*s)))  /* read exponent */
+      exp1 = exp1 * 10 + *(s++) - '0';
+    if (neg1) exp1 = -exp1;
+    e += exp1;
+  }
+  *endptr = cast(char *, s);  /* valid up to here */
+ ret:
+  if (neg) r = -r;
+  return l_mathop(ldexp)(r, e);
+}
+
+#endif
+
+
+int luaO_str2d (const char *s, size_t len, lua_Number *result) {
+  char *endptr;
+  if (strpbrk(s, "nN"))  /* reject 'inf' and 'nan' */
+    return 0;
+  else if (strpbrk(s, "xX"))  /* hexa? */
+    *result = lua_strx2number(s, &endptr);
+  else
+    *result = lua_str2number(s, &endptr);
+  if (endptr == s) return 0;  /* nothing recognized */
+  while (lisspace(cast_uchar(*endptr))) endptr++;
+  return (endptr == s + len);  /* OK if no trailing characters */
+}
+
+
+
+static void pushstr (lua_State *L, const char *str, size_t l) {
+  setsvalue2s(L, L->top++, luaS_newlstr(L, str, l));
+}
+
+
+/* this function handles only `%d', `%c', %f, %p, and `%s' formats */
+const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
+  int n = 0;
+  for (;;) {
+    const char *e = strchr(fmt, '%');
+    if (e == NULL) break;
+    luaD_checkstack(L, 2);  /* fmt + item */
+    pushstr(L, fmt, e - fmt);
+    switch (*(e+1)) {
+      case 's': {
+        const char *s = va_arg(argp, char *);
+        if (s == NULL) s = "(null)";
+        pushstr(L, s, strlen(s));
+        break;
+      }
+      case 'c': {
+        char buff;
+        buff = cast(char, va_arg(argp, int));
+        pushstr(L, &buff, 1);
+        break;
+      }
+      case 'd': {
+        setnvalue(L->top++, cast_num(va_arg(argp, int)));
+        break;
+      }
+      case 'f': {
+        setnvalue(L->top++, cast_num(va_arg(argp, l_uacNumber)));
+        break;
+      }
+      case 'p': {
+        char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */
+        int l = sprintf(buff, "%p", va_arg(argp, void *));
+        pushstr(L, buff, l);
+        break;
+      }
+      case '%': {
+        pushstr(L, "%", 1);
+        break;
+      }
+      default: {
+        luaG_runerror(L,
+            "invalid option " LUA_QL("%%%c") " to " LUA_QL("lua_pushfstring"),
+            *(e + 1));
+      }
+    }
+    n += 2;
+    fmt = e+2;
+  }
+  luaD_checkstack(L, 1);
+  pushstr(L, fmt, strlen(fmt));
+  if (n > 0) luaV_concat(L, n + 1);
+  return svalue(L->top - 1);
+}
+
+
+const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
+  const char *msg;
+  va_list argp;
+  va_start(argp, fmt);
+  msg = luaO_pushvfstring(L, fmt, argp);
+  va_end(argp);
+  return msg;
+}
+
+
+/* number of chars of a literal string without the ending \0 */
+#define LL(x)	(sizeof(x)/sizeof(char) - 1)
+
+#define RETS	"..."
+#define PRE	"[string \""
+#define POS	"\"]"
+
+#define addstr(a,b,l)	( memcpy(a,b,(l) * sizeof(char)), a += (l) )
+
+void luaO_chunkid (char *out, const char *source, size_t bufflen) {
+  size_t l = strlen(source);
+  if (*source == '=') {  /* 'literal' source */
+    if (l <= bufflen)  /* small enough? */
+      memcpy(out, source + 1, l * sizeof(char));
+    else {  /* truncate it */
+      addstr(out, source + 1, bufflen - 1);
+      *out = '\0';
+    }
+  }
+  else if (*source == '@') {  /* file name */
+    if (l <= bufflen)  /* small enough? */
+      memcpy(out, source + 1, l * sizeof(char));
+    else {  /* add '...' before rest of name */
+      addstr(out, RETS, LL(RETS));
+      bufflen -= LL(RETS);
+      memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char));
+    }
+  }
+  else {  /* string; format as [string "source"] */
+    const char *nl = strchr(source, '\n');  /* find first new line (if any) */
+    addstr(out, PRE, LL(PRE));  /* add prefix */
+    bufflen -= LL(PRE RETS POS) + 1;  /* save space for prefix+suffix+'\0' */
+    if (l < bufflen && nl == NULL) {  /* small one-line source? */
+      addstr(out, source, l);  /* keep it */
+    }
+    else {
+      if (nl != NULL) l = nl - source;  /* stop at first newline */
+      if (l > bufflen) l = bufflen;
+      addstr(out, source, l);
+      addstr(out, RETS, LL(RETS));
+    }
+    memcpy(out, POS, (LL(POS) + 1) * sizeof(char));
+  }
+}
+

=== added file 'src/scripting/eris/lobject.h'
--- src/scripting/eris/lobject.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lobject.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,607 @@
+/*
+** $Id: lobject.h,v 2.71 2012/09/11 18:21:44 roberto Exp $
+** Type definitions for Lua objects
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lobject_h
+#define lobject_h
+
+
+#include <stdarg.h>
+
+
+#include "llimits.h"
+#include "lua.h"
+
+
+/*
+** Extra tags for non-values
+*/
+#define LUA_TPROTO	LUA_NUMTAGS
+#define LUA_TUPVAL	(LUA_NUMTAGS+1)
+#define LUA_TDEADKEY	(LUA_NUMTAGS+2)
+
+/*
+** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
+*/
+#define LUA_TOTALTAGS	(LUA_TUPVAL+2)
+
+
+/*
+** tags for Tagged Values have the following use of bits:
+** bits 0-3: actual tag (a LUA_T* value)
+** bits 4-5: variant bits
+** bit 6: whether value is collectable
+*/
+
+#define VARBITS		(3 << 4)
+
+
+/*
+** LUA_TFUNCTION variants:
+** 0 - Lua function
+** 1 - light C function
+** 2 - regular C function (closure)
+*/
+
+/* Variant tags for functions */
+#define LUA_TLCL	(LUA_TFUNCTION | (0 << 4))  /* Lua closure */
+#define LUA_TLCF	(LUA_TFUNCTION | (1 << 4))  /* light C function */
+#define LUA_TCCL	(LUA_TFUNCTION | (2 << 4))  /* C closure */
+
+
+/* Variant tags for strings */
+#define LUA_TSHRSTR	(LUA_TSTRING | (0 << 4))  /* short strings */
+#define LUA_TLNGSTR	(LUA_TSTRING | (1 << 4))  /* long strings */
+
+
+/* Bit mark for collectable types */
+#define BIT_ISCOLLECTABLE	(1 << 6)
+
+/* mark a tag as collectable */
+#define ctb(t)			((t) | BIT_ISCOLLECTABLE)
+
+
+/*
+** Union of all collectable objects
+*/
+typedef union GCObject GCObject;
+
+
+/*
+** Common Header for all collectable objects (in macro form, to be
+** included in other objects)
+*/
+#define CommonHeader	GCObject *next; lu_byte tt; lu_byte marked
+
+
+/*
+** Common header in struct form
+*/
+typedef struct GCheader {
+  CommonHeader;
+} GCheader;
+
+
+
+/*
+** Union of all Lua values
+*/
+typedef union Value Value;
+
+
+#define numfield	lua_Number n;    /* numbers */
+
+
+
+/*
+** Tagged Values. This is the basic representation of values in Lua,
+** an actual value plus a tag with its type.
+*/
+
+#define TValuefields	Value value_; int tt_
+
+typedef struct lua_TValue TValue;
+
+
+/* macro defining a nil value */
+#define NILCONSTANT	{NULL}, LUA_TNIL
+
+
+#define val_(o)		((o)->value_)
+#define num_(o)		(val_(o).n)
+
+
+/* raw type tag of a TValue */
+#define rttype(o)	((o)->tt_)
+
+/* tag with no variants (bits 0-3) */
+#define novariant(x)	((x) & 0x0F)
+
+/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
+#define ttype(o)	(rttype(o) & 0x3F)
+
+/* type tag of a TValue with no variants (bits 0-3) */
+#define ttypenv(o)	(novariant(rttype(o)))
+
+
+/* Macros to test type */
+#define checktag(o,t)		(rttype(o) == (t))
+#define checktype(o,t)		(ttypenv(o) == (t))
+#define ttisnumber(o)		checktag((o), LUA_TNUMBER)
+#define ttisnil(o)		checktag((o), LUA_TNIL)
+#define ttisboolean(o)		checktag((o), LUA_TBOOLEAN)
+#define ttislightuserdata(o)	checktag((o), LUA_TLIGHTUSERDATA)
+#define ttisstring(o)		checktype((o), LUA_TSTRING)
+#define ttisshrstring(o)	checktag((o), ctb(LUA_TSHRSTR))
+#define ttislngstring(o)	checktag((o), ctb(LUA_TLNGSTR))
+#define ttistable(o)		checktag((o), ctb(LUA_TTABLE))
+#define ttisfunction(o)		checktype(o, LUA_TFUNCTION)
+#define ttisclosure(o)		((rttype(o) & 0x1F) == LUA_TFUNCTION)
+#define ttisCclosure(o)		checktag((o), ctb(LUA_TCCL))
+#define ttisLclosure(o)		checktag((o), ctb(LUA_TLCL))
+#define ttislcf(o)		checktag((o), LUA_TLCF)
+#define ttisuserdata(o)		checktag((o), ctb(LUA_TUSERDATA))
+#define ttisthread(o)		checktag((o), ctb(LUA_TTHREAD))
+#define ttisdeadkey(o)		checktag((o), LUA_TDEADKEY)
+
+#define ttisequal(o1,o2)	(rttype(o1) == rttype(o2))
+
+/* Macros to access values */
+#define nvalue(o)	check_exp(ttisnumber(o), num_(o))
+#define gcvalue(o)	check_exp(iscollectable(o), val_(o).gc)
+#define pvalue(o)	check_exp(ttislightuserdata(o), val_(o).p)
+#define rawtsvalue(o)	check_exp(ttisstring(o), &val_(o).gc->ts)
+#define tsvalue(o)	(&rawtsvalue(o)->tsv)
+#define rawuvalue(o)	check_exp(ttisuserdata(o), &val_(o).gc->u)
+#define uvalue(o)	(&rawuvalue(o)->uv)
+#define clvalue(o)	check_exp(ttisclosure(o), &val_(o).gc->cl)
+#define clLvalue(o)	check_exp(ttisLclosure(o), &val_(o).gc->cl.l)
+#define clCvalue(o)	check_exp(ttisCclosure(o), &val_(o).gc->cl.c)
+#define fvalue(o)	check_exp(ttislcf(o), val_(o).f)
+#define hvalue(o)	check_exp(ttistable(o), &val_(o).gc->h)
+#define bvalue(o)	check_exp(ttisboolean(o), val_(o).b)
+#define thvalue(o)	check_exp(ttisthread(o), &val_(o).gc->th)
+/* a dead value may get the 'gc' field, but cannot access its contents */
+#define deadvalue(o)	check_exp(ttisdeadkey(o), cast(void *, val_(o).gc))
+
+#define l_isfalse(o)	(ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
+
+
+#define iscollectable(o)	(rttype(o) & BIT_ISCOLLECTABLE)
+
+
+/* Macros for internal tests */
+#define righttt(obj)		(ttype(obj) == gcvalue(obj)->gch.tt)
+
+#define checkliveness(g,obj) \
+	lua_longassert(!iscollectable(obj) || \
+			(righttt(obj) && !isdead(g,gcvalue(obj))))
+
+
+/* Macros to set values */
+#define settt_(o,t)	((o)->tt_=(t))
+
+#define setnvalue(obj,x) \
+  { TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); }
+
+#define setnilvalue(obj) settt_(obj, LUA_TNIL)
+
+#define setfvalue(obj,x) \
+  { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); }
+
+#define setpvalue(obj,x) \
+  { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); }
+
+#define setbvalue(obj,x) \
+  { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); }
+
+#define setgcovalue(L,obj,x) \
+  { TValue *io=(obj); GCObject *i_g=(x); \
+    val_(io).gc=i_g; settt_(io, ctb(gch(i_g)->tt)); }
+
+#define setsvalue(L,obj,x) \
+  { TValue *io=(obj); \
+    TString *x_ = (x); \
+    val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \
+    checkliveness(G(L),io); }
+
+#define setuvalue(L,obj,x) \
+  { TValue *io=(obj); \
+    val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TUSERDATA)); \
+    checkliveness(G(L),io); }
+
+#define setthvalue(L,obj,x) \
+  { TValue *io=(obj); \
+    val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTHREAD)); \
+    checkliveness(G(L),io); }
+
+#define setclLvalue(L,obj,x) \
+  { TValue *io=(obj); \
+    val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TLCL)); \
+    checkliveness(G(L),io); }
+
+#define setclCvalue(L,obj,x) \
+  { TValue *io=(obj); \
+    val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TCCL)); \
+    checkliveness(G(L),io); }
+
+#define sethvalue(L,obj,x) \
+  { TValue *io=(obj); \
+    val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \
+    checkliveness(G(L),io); }
+
+#define setdeadvalue(obj)	settt_(obj, LUA_TDEADKEY)
+
+
+
+#define setobj(L,obj1,obj2) \
+	{ const TValue *io2=(obj2); TValue *io1=(obj1); \
+	  io1->value_ = io2->value_; io1->tt_ = io2->tt_; \
+	  checkliveness(G(L),io1); }
+
+
+/*
+** different types of assignments, according to destination
+*/
+
+/* from stack to (same) stack */
+#define setobjs2s	setobj
+/* to stack (not from same stack) */
+#define setobj2s	setobj
+#define setsvalue2s	setsvalue
+#define sethvalue2s	sethvalue
+#define setptvalue2s	setptvalue
+/* from table to same table */
+#define setobjt2t	setobj
+/* to table */
+#define setobj2t	setobj
+/* to new object */
+#define setobj2n	setobj
+#define setsvalue2n	setsvalue
+
+
+/* check whether a number is valid (useful only for NaN trick) */
+#define luai_checknum(L,o,c)	{ /* empty */ }
+
+
+/*
+** {======================================================
+** NaN Trick
+** =======================================================
+*/
+#if defined(LUA_NANTRICK)
+
+/*
+** numbers are represented in the 'd_' field. All other values have the
+** value (NNMARK | tag) in 'tt__'. A number with such pattern would be
+** a "signaled NaN", which is never generated by regular operations by
+** the CPU (nor by 'strtod')
+*/
+
+/* allows for external implementation for part of the trick */
+#if !defined(NNMARK)	/* { */
+
+
+#if !defined(LUA_IEEEENDIAN)
+#error option 'LUA_NANTRICK' needs 'LUA_IEEEENDIAN'
+#endif
+
+
+#define NNMARK		0x7FF7A500
+#define NNMASK		0x7FFFFF00
+
+#undef TValuefields
+#undef NILCONSTANT
+
+#if (LUA_IEEEENDIAN == 0)	/* { */
+
+/* little endian */
+#define TValuefields  \
+	union { struct { Value v__; int tt__; } i; double d__; } u
+#define NILCONSTANT	{{{NULL}, tag2tt(LUA_TNIL)}}
+/* field-access macros */
+#define v_(o)		((o)->u.i.v__)
+#define d_(o)		((o)->u.d__)
+#define tt_(o)		((o)->u.i.tt__)
+
+#else				/* }{ */
+
+/* big endian */
+#define TValuefields  \
+	union { struct { int tt__; Value v__; } i; double d__; } u
+#define NILCONSTANT	{{tag2tt(LUA_TNIL), {NULL}}}
+/* field-access macros */
+#define v_(o)		((o)->u.i.v__)
+#define d_(o)		((o)->u.d__)
+#define tt_(o)		((o)->u.i.tt__)
+
+#endif				/* } */
+
+#endif			/* } */
+
+
+/* correspondence with standard representation */
+#undef val_
+#define val_(o)		v_(o)
+#undef num_
+#define num_(o)		d_(o)
+
+
+#undef numfield
+#define numfield	/* no such field; numbers are the entire struct */
+
+/* basic check to distinguish numbers from non-numbers */
+#undef ttisnumber
+#define ttisnumber(o)	((tt_(o) & NNMASK) != NNMARK)
+
+#define tag2tt(t)	(NNMARK | (t))
+
+#undef rttype
+#define rttype(o)	(ttisnumber(o) ? LUA_TNUMBER : tt_(o) & 0xff)
+
+#undef settt_
+#define settt_(o,t)	(tt_(o) = tag2tt(t))
+
+#undef setnvalue
+#define setnvalue(obj,x) \
+	{ TValue *io_=(obj); num_(io_)=(x); lua_assert(ttisnumber(io_)); }
+
+#undef setobj
+#define setobj(L,obj1,obj2) \
+	{ const TValue *o2_=(obj2); TValue *o1_=(obj1); \
+	  o1_->u = o2_->u; \
+	  checkliveness(G(L),o1_); }
+
+
+/*
+** these redefinitions are not mandatory, but these forms are more efficient
+*/
+
+#undef checktag
+#undef checktype
+#define checktag(o,t)	(tt_(o) == tag2tt(t))
+#define checktype(o,t)	(ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS))
+
+#undef ttisequal
+#define ttisequal(o1,o2)  \
+	(ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2)))
+
+
+#undef luai_checknum
+#define luai_checknum(L,o,c)	{ if (!ttisnumber(o)) c; }
+
+#endif
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** types and prototypes
+** =======================================================
+*/
+
+
+union Value {
+  GCObject *gc;    /* collectable objects */
+  void *p;         /* light userdata */
+  int b;           /* booleans */
+  lua_CFunction f; /* light C functions */
+  numfield         /* numbers */
+};
+
+
+struct lua_TValue {
+  TValuefields;
+};
+
+
+typedef TValue *StkId;  /* index to stack elements */
+
+
+
+
+/*
+** Header for string value; string bytes follow the end of this structure
+*/
+typedef union TString {
+  L_Umaxalign dummy;  /* ensures maximum alignment for strings */
+  struct {
+    CommonHeader;
+    lu_byte extra;  /* reserved words for short strings; "has hash" for longs */
+    unsigned int hash;
+    size_t len;  /* number of characters in string */
+  } tsv;
+} TString;
+
+
+/* get the actual string (array of bytes) from a TString */
+#define getstr(ts)	cast(const char *, (ts) + 1)
+
+/* get the actual string (array of bytes) from a Lua value */
+#define svalue(o)       getstr(rawtsvalue(o))
+
+
+/*
+** Header for userdata; memory area follows the end of this structure
+*/
+typedef union Udata {
+  L_Umaxalign dummy;  /* ensures maximum alignment for `local' udata */
+  struct {
+    CommonHeader;
+    struct Table *metatable;
+    struct Table *env;
+    size_t len;  /* number of bytes */
+  } uv;
+} Udata;
+
+
+
+/*
+** Description of an upvalue for function prototypes
+*/
+typedef struct Upvaldesc {
+  TString *name;  /* upvalue name (for debug information) */
+  lu_byte instack;  /* whether it is in stack */
+  lu_byte idx;  /* index of upvalue (in stack or in outer function's list) */
+} Upvaldesc;
+
+
+/*
+** Description of a local variable for function prototypes
+** (used for debug information)
+*/
+typedef struct LocVar {
+  TString *varname;
+  int startpc;  /* first point where variable is active */
+  int endpc;    /* first point where variable is dead */
+} LocVar;
+
+
+/*
+** Function Prototypes
+*/
+typedef struct Proto {
+  CommonHeader;
+  TValue *k;  /* constants used by the function */
+  Instruction *code;
+  struct Proto **p;  /* functions defined inside the function */
+  int *lineinfo;  /* map from opcodes to source lines (debug information) */
+  LocVar *locvars;  /* information about local variables (debug information) */
+  Upvaldesc *upvalues;  /* upvalue information */
+  union Closure *cache;  /* last created closure with this prototype */
+  TString  *source;  /* used for debug information */
+  int sizeupvalues;  /* size of 'upvalues' */
+  int sizek;  /* size of `k' */
+  int sizecode;
+  int sizelineinfo;
+  int sizep;  /* size of `p' */
+  int sizelocvars;
+  int linedefined;
+  int lastlinedefined;
+  GCObject *gclist;
+  lu_byte numparams;  /* number of fixed parameters */
+  lu_byte is_vararg;
+  lu_byte maxstacksize;  /* maximum stack used by this function */
+} Proto;
+
+
+
+/*
+** Lua Upvalues
+*/
+typedef struct UpVal {
+  CommonHeader;
+  TValue *v;  /* points to stack or to its own value */
+  union {
+    TValue value;  /* the value (when closed) */
+    struct {  /* double linked list (when open) */
+      struct UpVal *prev;
+      struct UpVal *next;
+    } l;
+  } u;
+} UpVal;
+
+
+/*
+** Closures
+*/
+
+#define ClosureHeader \
+	CommonHeader; lu_byte nupvalues; GCObject *gclist
+
+typedef struct CClosure {
+  ClosureHeader;
+  lua_CFunction f;
+  TValue upvalue[1];  /* list of upvalues */
+} CClosure;
+
+
+typedef struct LClosure {
+  ClosureHeader;
+  struct Proto *p;
+  UpVal *upvals[1];  /* list of upvalues */
+} LClosure;
+
+
+typedef union Closure {
+  CClosure c;
+  LClosure l;
+} Closure;
+
+
+#define isLfunction(o)	ttisLclosure(o)
+
+#define getproto(o)	(clLvalue(o)->p)
+
+
+/*
+** Tables
+*/
+
+typedef union TKey {
+  struct {
+    TValuefields;
+    struct Node *next;  /* for chaining */
+  } nk;
+  TValue tvk;
+} TKey;
+
+
+typedef struct Node {
+  TValue i_val;
+  TKey i_key;
+} Node;
+
+
+typedef struct Table {
+  CommonHeader;
+  lu_byte flags;  /* 1<<p means tagmethod(p) is not present */
+  lu_byte lsizenode;  /* log2 of size of `node' array */
+  struct Table *metatable;
+  TValue *array;  /* array part */
+  Node *node;
+  Node *lastfree;  /* any free position is before this position */
+  GCObject *gclist;
+  int sizearray;  /* size of `array' array */
+} Table;
+
+
+
+/*
+** `module' operation for hashing (size is always a power of 2)
+*/
+#define lmod(s,size) \
+	(check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1)))))
+
+
+#define twoto(x)	(1<<(x))
+#define sizenode(t)	(twoto((t)->lsizenode))
+
+
+/*
+** (address of) a fixed nil value
+*/
+#define luaO_nilobject		(&luaO_nilobject_)
+
+
+LUAI_DDEC const TValue luaO_nilobject_;
+
+
+LUAI_FUNC int luaO_int2fb (unsigned int x);
+LUAI_FUNC int luaO_fb2int (int x);
+LUAI_FUNC int luaO_ceillog2 (unsigned int x);
+LUAI_FUNC lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2);
+LUAI_FUNC int luaO_str2d (const char *s, size_t len, lua_Number *result);
+LUAI_FUNC int luaO_hexavalue (int c);
+LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
+                                                       va_list argp);
+LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
+LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);
+
+
+#endif
+

=== added file 'src/scripting/eris/lopcodes.c'
--- src/scripting/eris/lopcodes.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lopcodes.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,107 @@
+/*
+** $Id: lopcodes.c,v 1.49 2012/05/14 13:34:18 roberto Exp $
+** Opcodes for Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+
+#define lopcodes_c
+#define LUA_CORE
+
+
+#include "lopcodes.h"
+
+
+/* ORDER OP */
+
+LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
+  "MOVE",
+  "LOADK",
+  "LOADKX",
+  "LOADBOOL",
+  "LOADNIL",
+  "GETUPVAL",
+  "GETTABUP",
+  "GETTABLE",
+  "SETTABUP",
+  "SETUPVAL",
+  "SETTABLE",
+  "NEWTABLE",
+  "SELF",
+  "ADD",
+  "SUB",
+  "MUL",
+  "DIV",
+  "MOD",
+  "POW",
+  "UNM",
+  "NOT",
+  "LEN",
+  "CONCAT",
+  "JMP",
+  "EQ",
+  "LT",
+  "LE",
+  "TEST",
+  "TESTSET",
+  "CALL",
+  "TAILCALL",
+  "RETURN",
+  "FORLOOP",
+  "FORPREP",
+  "TFORCALL",
+  "TFORLOOP",
+  "SETLIST",
+  "CLOSURE",
+  "VARARG",
+  "EXTRAARG",
+  NULL
+};
+
+
+#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
+
+LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
+/*       T  A    B       C     mode		   opcode	*/
+  opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_MOVE */
+ ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_LOADK */
+ ,opmode(0, 1, OpArgN, OpArgN, iABx)		/* OP_LOADKX */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_LOADBOOL */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_LOADNIL */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_GETUPVAL */
+ ,opmode(0, 1, OpArgU, OpArgK, iABC)		/* OP_GETTABUP */
+ ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_GETTABLE */
+ ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABUP */
+ ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_SETUPVAL */
+ ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABLE */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_NEWTABLE */
+ ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_SELF */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_ADD */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_SUB */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MUL */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_DIV */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MOD */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_POW */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_UNM */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_NOT */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LEN */
+ ,opmode(0, 1, OpArgR, OpArgR, iABC)		/* OP_CONCAT */
+ ,opmode(0, 0, OpArgR, OpArgN, iAsBx)		/* OP_JMP */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_EQ */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LT */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LE */
+ ,opmode(1, 0, OpArgN, OpArgU, iABC)		/* OP_TEST */
+ ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TESTSET */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_CALL */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_TAILCALL */
+ ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_RETURN */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORLOOP */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORPREP */
+ ,opmode(0, 0, OpArgN, OpArgU, iABC)		/* OP_TFORCALL */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_TFORLOOP */
+ ,opmode(0, 0, OpArgU, OpArgU, iABC)		/* OP_SETLIST */
+ ,opmode(0, 1, OpArgU, OpArgN, iABx)		/* OP_CLOSURE */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_VARARG */
+ ,opmode(0, 0, OpArgU, OpArgU, iAx)		/* OP_EXTRAARG */
+};
+

=== added file 'src/scripting/eris/lopcodes.h'
--- src/scripting/eris/lopcodes.h	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lopcodes.h	2013-10-19 12:35:28 +0000
@@ -0,0 +1,288 @@
+/*
+** $Id: lopcodes.h,v 1.142 2011/07/15 12:50:29 roberto Exp $
+** Opcodes for Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lopcodes_h
+#define lopcodes_h
+
+#include "llimits.h"
+
+
+/*===========================================================================
+  We assume that instructions are unsigned numbers.
+  All instructions have an opcode in the first 6 bits.
+  Instructions can have the following fields:
+	`A' : 8 bits
+	`B' : 9 bits
+	`C' : 9 bits
+	'Ax' : 26 bits ('A', 'B', and 'C' together)
+	`Bx' : 18 bits (`B' and `C' together)
+	`sBx' : signed Bx
+
+  A signed argument is represented in excess K; that is, the number
+  value is the unsigned value minus K. K is exactly the maximum value
+  for that argument (so that -max is represented by 0, and +max is
+  represented by 2*max), which is half the maximum for the corresponding
+  unsigned argument.
+===========================================================================*/
+
+
+enum OpMode {iABC, iABx, iAsBx, iAx};  /* basic instruction format */
+
+
+/*
+** size and position of opcode arguments.
+*/
+#define SIZE_C		9
+#define SIZE_B		9
+#define SIZE_Bx		(SIZE_C + SIZE_B)
+#define SIZE_A		8
+#define SIZE_Ax		(SIZE_C + SIZE_B + SIZE_A)
+
+#define SIZE_OP		6
+
+#define POS_OP		0
+#define POS_A		(POS_OP + SIZE_OP)
+#define POS_C		(POS_A + SIZE_A)
+#define POS_B		(POS_C + SIZE_C)
+#define POS_Bx		POS_C
+#define POS_Ax		POS_A
+
+
+/*
+** limits for opcode arguments.
+** we use (signed) int to manipulate most arguments,
+** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
+*/
+#if SIZE_Bx < LUAI_BITSINT-1
+#define MAXARG_Bx        ((1<<SIZE_Bx)-1)
+#define MAXARG_sBx        (MAXARG_Bx>>1)         /* `sBx' is signed */
+#else
+#define MAXARG_Bx        MAX_INT
+#define MAXARG_sBx        MAX_INT
+#endif
+
+#if SIZE_Ax < LUAI_BITSINT-1
+#define MAXARG_Ax	((1<<SIZE_Ax)-1)
+#else
+#define MAXARG_Ax	MAX_INT
+#endif
+
+
+#define MAXARG_A        ((1<<SIZE_A)-1)
+#define MAXARG_B        ((1<<SIZE_B)-1)
+#define MAXARG_C        ((1<<SIZE_C)-1)
+
+
+/* creates a mask with `n' 1 bits at position `p' */
+#define MASK1(n,p)	((~((~(Instruction)0)<<(n)))<<(p))
+
+/* creates a mask with `n' 0 bits at position `p' */
+#define MASK0(n,p)	(~MASK1(n,p))
+
+/*
+** the following macros help to manipulate instructions
+*/
+
+#define GET_OPCODE(i)	(cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
+#define SET_OPCODE(i,o)	((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
+		((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
+
+#define getarg(i,pos,size)	(cast(int, ((i)>>pos) & MASK1(size,0)))
+#define setarg(i,v,pos,size)	((i) = (((i)&MASK0(size,pos)) | \
+                ((cast(Instruction, v)<<pos)&MASK1(size,pos))))
+
+#define GETARG_A(i)	getarg(i, POS_A, SIZE_A)
+#define SETARG_A(i,v)	setarg(i, v, POS_A, SIZE_A)
+
+#define GETARG_B(i)	getarg(i, POS_B, SIZE_B)
+#define SETARG_B(i,v)	setarg(i, v, POS_B, SIZE_B)
+
+#define GETARG_C(i)	getarg(i, POS_C, SIZE_C)
+#define SETARG_C(i,v)	setarg(i, v, POS_C, SIZE_C)
+
+#define GETARG_Bx(i)	getarg(i, POS_Bx, SIZE_Bx)
+#define SETARG_Bx(i,v)	setarg(i, v, POS_Bx, SIZE_Bx)
+
+#define GETARG_Ax(i)	getarg(i, POS_Ax, SIZE_Ax)
+#define SETARG_Ax(i,v)	setarg(i, v, POS_Ax, SIZE_Ax)
+
+#define GETARG_sBx(i)	(GETARG_Bx(i)-MAXARG_sBx)
+#define SETARG_sBx(i,b)	SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
+
+
+#define CREATE_ABC(o,a,b,c)	((cast(Instruction, o)<<POS_OP) \
+			| (cast(Instruction, a)<<POS_A) \
+			| (cast(Instruction, b)<<POS_B) \
+			| (cast(Instruction, c)<<POS_C))
+
+#define CREATE_ABx(o,a,bc)	((cast(Instruction, o)<<POS_OP) \
+			| (cast(Instruction, a)<<POS_A) \
+			| (cast(Instruction, bc)<<POS_Bx))
+
+#define CREATE_Ax(o,a)		((cast(Instruction, o)<<POS_OP) \
+			| (cast(Instruction, a)<<POS_Ax))
+
+
+/*
+** Macros to operate RK indices
+*/
+
+/* this bit 1 means constant (0 means register) */
+#define BITRK		(1 << (SIZE_B - 1))
+
+/* test whether value is a constant */
+#define ISK(x)		((x) & BITRK)
+
+/* gets the index of the constant */
+#define INDEXK(r)	((int)(r) & ~BITRK)
+
+#define MAXINDEXRK	(BITRK - 1)
+
+/* code a constant index as a RK value */
+#define RKASK(x)	((x) | BITRK)
+
+
+/*
+** invalid register that fits in 8 bits
+*/
+#define NO_REG		MAXARG_A
+
+
+/*
+** R(x) - register
+** Kst(x) - constant (in constant table)
+** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
+*/
+
+
+/*
+** grep "ORDER OP" if you change these enums
+*/
+
+typedef enum {
+/*----------------------------------------------------------------------
+name		args	description
+------------------------------------------------------------------------*/
+OP_MOVE,/*	A B	R(A) := R(B)					*/
+OP_LOADK,/*	A Bx	R(A) := Kst(Bx)					*/
+OP_LOADKX,/*	A 	R(A) := Kst(extra arg)				*/
+OP_LOADBOOL,/*	A B C	R(A) := (Bool)B; if (C) pc++			*/
+OP_LOADNIL,/*	A B	R(A), R(A+1), ..., R(A+B) := nil		*/
+OP_GETUPVAL,/*	A B	R(A) := UpValue[B]				*/
+
+OP_GETTABUP,/*	A B C	R(A) := UpValue[B][RK(C)]			*/
+OP_GETTABLE,/*	A B C	R(A) := R(B)[RK(C)]				*/
+
+OP_SETTABUP,/*	A B C	UpValue[A][RK(B)] := RK(C)			*/
+OP_SETUPVAL,/*	A B	UpValue[B] := R(A)				*/
+OP_SETTABLE,/*	A B C	R(A)[RK(B)] := RK(C)				*/
+
+OP_NEWTABLE,/*	A B C	R(A) := {} (size = B,C)				*/
+
+OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C)]		*/
+
+OP_ADD,/*	A B C	R(A) := RK(B) + RK(C)				*/
+OP_SUB,/*	A B C	R(A) := RK(B) - RK(C)				*/
+OP_MUL,/*	A B C	R(A) := RK(B) * RK(C)				*/
+OP_DIV,/*	A B C	R(A) := RK(B) / RK(C)				*/
+OP_MOD,/*	A B C	R(A) := RK(B) % RK(C)				*/
+OP_POW,/*	A B C	R(A) := RK(B) ^ RK(C)				*/
+OP_UNM,/*	A B	R(A) := -R(B)					*/
+OP_NOT,/*	A B	R(A) := not R(B)				*/
+OP_LEN,/*	A B	R(A) := length of R(B)				*/
+
+OP_CONCAT,/*	A B C	R(A) := R(B).. ... ..R(C)			*/
+
+OP_JMP,/*	A sBx	pc+=sBx; if (A) close all upvalues >= R(A) + 1	*/
+OP_EQ,/*	A B C	if ((RK(B) == RK(C)) ~= A) then pc++		*/
+OP_LT,/*	A B C	if ((RK(B) <  RK(C)) ~= A) then pc++		*/
+OP_LE,/*	A B C	if ((RK(B) <= RK(C)) ~= A) then pc++		*/
+
+OP_TEST,/*	A C	if not (R(A) <=> C) then pc++			*/
+OP_TESTSET,/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/
+
+OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
+OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/
+OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see note)	*/
+
+OP_FORLOOP,/*	A sBx	R(A)+=R(A+2);
+			if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
+OP_FORPREP,/*	A sBx	R(A)-=R(A+2); pc+=sBx				*/
+
+OP_TFORCALL,/*	A C	R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));	*/
+OP_TFORLOOP,/*	A sBx	if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
+
+OP_SETLIST,/*	A B C	R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B	*/
+
+OP_CLOSURE,/*	A Bx	R(A) := closure(KPROTO[Bx])			*/
+
+OP_VARARG,/*	A B	R(A), R(A+1), ..., R(A+B-2) = vararg		*/
+
+OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
+} OpCode;
+
+
+#define NUM_OPCODES	(cast(int, OP_EXTRAARG) + 1)
+
+
+
+/*===========================================================================
+  Notes:
+  (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then `top' is
+  set to last_result+1, so next open instruction (OP_CALL, OP_RETURN,
+  OP_SETLIST) may use `top'.
+
+  (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
+  set top (like in OP_CALL with C == 0).
+
+  (*) In OP_RETURN, if (B == 0) then return up to `top'.
+
+  (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next
+  'instruction' is EXTRAARG(real C).
+
+  (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
+
+  (*) For comparisons, A specifies what condition the test should accept
+  (true or false).
+
+  (*) All `skips' (pc++) assume that next instruction is a jump.
+
+===========================================================================*/
+
+
+/*
+** masks for instruction properties. The format is:
+** bits 0-1: op mode
+** bits 2-3: C arg mode
+** bits 4-5: B arg mode
+** bit 6: instruction set register A
+** bit 7: operator is a test (next instruction must be a jump)
+*/
+
+enum OpArgMask {
+  OpArgN,  /* argument is not used */
+  OpArgU,  /* argument is used */
+  OpArgR,  /* argument is a register or a jump offset */
+  OpArgK   /* argument is a constant or register/constant */
+};
+
+LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES];
+
+#define getOpMode(m)	(cast(enum OpMode, luaP_opmodes[m] & 3))
+#define getBMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
+#define getCMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))
+#define testAMode(m)	(luaP_opmodes[m] & (1 << 6))
+#define testTMode(m)	(luaP_opmodes[m] & (1 << 7))
+
+
+LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1];  /* opcode names */
+
+
+/* number of list items to accumulate before a SETLIST instruction */
+#define LFIELDS_PER_FLUSH	50
+
+
+#endif

=== added file 'src/scripting/eris/loslib.c'
--- src/scripting/eris/loslib.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/loslib.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,323 @@
+/*
+** $Id: loslib.c,v 1.40 2012/10/19 15:54:02 roberto Exp $
+** Standard Operating System library
+** See Copyright Notice in lua.h
+*/
+
+
+#include <errno.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#define loslib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/*
+** list of valid conversion specifiers for the 'strftime' function
+*/
+#if !defined(LUA_STRFTIMEOPTIONS)
+
+#if !defined(LUA_USE_POSIX)
+#define LUA_STRFTIMEOPTIONS	{ "aAbBcdHIjmMpSUwWxXyYz%", "" }
+#else
+#define LUA_STRFTIMEOPTIONS \
+	{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \
+	  "", "E", "cCxXyY",  \
+	  "O", "deHImMSuUVwWy" }
+#endif
+
+#endif
+
+
+
+/*
+** By default, Lua uses tmpnam except when POSIX is available, where it
+** uses mkstemp.
+*/
+#if defined(LUA_USE_MKSTEMP)
+#include <unistd.h>
+#define LUA_TMPNAMBUFSIZE	32
+#define lua_tmpnam(b,e) { \
+        strcpy(b, "/tmp/lua_XXXXXX"); \
+        e = mkstemp(b); \
+        if (e != -1) close(e); \
+        e = (e == -1); }
+
+#elif !defined(lua_tmpnam)
+
+#define LUA_TMPNAMBUFSIZE	L_tmpnam
+#define lua_tmpnam(b,e)		{ e = (tmpnam(b) == NULL); }
+
+#endif
+
+
+/*
+** By default, Lua uses gmtime/localtime, except when POSIX is available,
+** where it uses gmtime_r/localtime_r
+*/
+#if defined(LUA_USE_GMTIME_R)
+
+#define l_gmtime(t,r)		gmtime_r(t,r)
+#define l_localtime(t,r)	localtime_r(t,r)
+
+#elif !defined(l_gmtime)
+
+#define l_gmtime(t,r)		((void)r, gmtime(t))
+#define l_localtime(t,r)  	((void)r, localtime(t))
+
+#endif
+
+
+
+static int os_execute (lua_State *L) {
+  const char *cmd = luaL_optstring(L, 1, NULL);
+  int stat = system(cmd);
+  if (cmd != NULL)
+    return luaL_execresult(L, stat);
+  else {
+    lua_pushboolean(L, stat);  /* true if there is a shell */
+    return 1;
+  }
+}
+
+
+static int os_remove (lua_State *L) {
+  const char *filename = luaL_checkstring(L, 1);
+  return luaL_fileresult(L, remove(filename) == 0, filename);
+}
+
+
+static int os_rename (lua_State *L) {
+  const char *fromname = luaL_checkstring(L, 1);
+  const char *toname = luaL_checkstring(L, 2);
+  return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
+}
+
+
+static int os_tmpname (lua_State *L) {
+  char buff[LUA_TMPNAMBUFSIZE];
+  int err;
+  lua_tmpnam(buff, err);
+  if (err)
+    return luaL_error(L, "unable to generate a unique filename");
+  lua_pushstring(L, buff);
+  return 1;
+}
+
+
+static int os_getenv (lua_State *L) {
+  lua_pushstring(L, getenv(luaL_checkstring(L, 1)));  /* if NULL push nil */
+  return 1;
+}
+
+
+static int os_clock (lua_State *L) {
+  lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);
+  return 1;
+}
+
+
+/*
+** {======================================================
+** Time/Date operations
+** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
+**   wday=%w+1, yday=%j, isdst=? }
+** =======================================================
+*/
+
+static void setfield (lua_State *L, const char *key, int value) {
+  lua_pushinteger(L, value);
+  lua_setfield(L, -2, key);
+}
+
+static void setboolfield (lua_State *L, const char *key, int value) {
+  if (value < 0)  /* undefined? */
+    return;  /* does not set field */
+  lua_pushboolean(L, value);
+  lua_setfield(L, -2, key);
+}
+
+static int getboolfield (lua_State *L, const char *key) {
+  int res;
+  lua_getfield(L, -1, key);
+  res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
+  lua_pop(L, 1);
+  return res;
+}
+
+
+static int getfield (lua_State *L, const char *key, int d) {
+  int res, isnum;
+  lua_getfield(L, -1, key);
+  res = (int)lua_tointegerx(L, -1, &isnum);
+  if (!isnum) {
+    if (d < 0)
+      return luaL_error(L, "field " LUA_QS " missing in date table", key);
+    res = d;
+  }
+  lua_pop(L, 1);
+  return res;
+}
+
+
+static const char *checkoption (lua_State *L, const char *conv, char *buff) {
+  static const char *const options[] = LUA_STRFTIMEOPTIONS;
+  unsigned int i;
+  for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) {
+    if (*conv != '\0' && strchr(options[i], *conv) != NULL) {
+      buff[1] = *conv;
+      if (*options[i + 1] == '\0') {  /* one-char conversion specifier? */
+        buff[2] = '\0';  /* end buffer */
+        return conv + 1;
+      }
+      else if (*(conv + 1) != '\0' &&
+               strchr(options[i + 1], *(conv + 1)) != NULL) {
+        buff[2] = *(conv + 1);  /* valid two-char conversion specifier */
+        buff[3] = '\0';  /* end buffer */
+        return conv + 2;
+      }
+    }
+  }
+  luaL_argerror(L, 1,
+    lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv));
+  return conv;  /* to avoid warnings */
+}
+
+
+static int os_date (lua_State *L) {
+  const char *s = luaL_optstring(L, 1, "%c");
+  time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL));
+  struct tm tmr, *stm;
+  if (*s == '!') {  /* UTC? */
+    stm = l_gmtime(&t, &tmr);
+    s++;  /* skip `!' */
+  }
+  else
+    stm = l_localtime(&t, &tmr);
+  if (stm == NULL)  /* invalid date? */
+    lua_pushnil(L);
+  else if (strcmp(s, "*t") == 0) {
+    lua_createtable(L, 0, 9);  /* 9 = number of fields */
+    setfield(L, "sec", stm->tm_sec);
+    setfield(L, "min", stm->tm_min);
+    setfield(L, "hour", stm->tm_hour);
+    setfield(L, "day", stm->tm_mday);
+    setfield(L, "month", stm->tm_mon+1);
+    setfield(L, "year", stm->tm_year+1900);
+    setfield(L, "wday", stm->tm_wday+1);
+    setfield(L, "yday", stm->tm_yday+1);
+    setboolfield(L, "isdst", stm->tm_isdst);
+  }
+  else {
+    char cc[4];
+    luaL_Buffer b;
+    cc[0] = '%';
+    luaL_buffinit(L, &b);
+    while (*s) {
+      if (*s != '%')  /* no conversion specifier? */
+        luaL_addchar(&b, *s++);
+      else {
+        size_t reslen;
+        char buff[200];  /* should be big enough for any conversion result */
+        s = checkoption(L, s + 1, cc);
+        reslen = strftime(buff, sizeof(buff), cc, stm);
+        luaL_addlstring(&b, buff, reslen);
+      }
+    }
+    luaL_pushresult(&b);
+  }
+  return 1;
+}
+
+
+static int os_time (lua_State *L) {
+  time_t t;
+  if (lua_isnoneornil(L, 1))  /* called without args? */
+    t = time(NULL);  /* get current time */
+  else {
+    struct tm ts;
+    luaL_checktype(L, 1, LUA_TTABLE);
+    lua_settop(L, 1);  /* make sure table is at the top */
+    ts.tm_sec = getfield(L, "sec", 0);
+    ts.tm_min = getfield(L, "min", 0);
+    ts.tm_hour = getfield(L, "hour", 12);
+    ts.tm_mday = getfield(L, "day", -1);
+    ts.tm_mon = getfield(L, "month", -1) - 1;
+    ts.tm_year = getfield(L, "year", -1) - 1900;
+    ts.tm_isdst = getboolfield(L, "isdst");
+    t = mktime(&ts);
+  }
+  if (t == (time_t)(-1))
+    lua_pushnil(L);
+  else
+    lua_pushnumber(L, (lua_Number)t);
+  return 1;
+}
+
+
+static int os_difftime (lua_State *L) {
+  lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
+                             (time_t)(luaL_optnumber(L, 2, 0))));
+  return 1;
+}
+
+/* }====================================================== */
+
+
+static int os_setlocale (lua_State *L) {
+  static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
+                      LC_NUMERIC, LC_TIME};
+  static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
+     "numeric", "time", NULL};
+  const char *l = luaL_optstring(L, 1, NULL);
+  int op = luaL_checkoption(L, 2, "all", catnames);
+  lua_pushstring(L, setlocale(cat[op], l));
+  return 1;
+}
+
+
+static int os_exit (lua_State *L) {
+  int status;
+  if (lua_isboolean(L, 1))
+    status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE);
+  else
+    status = luaL_optint(L, 1, EXIT_SUCCESS);
+  if (lua_toboolean(L, 2))
+    lua_close(L);
+  if (L) exit(status);  /* 'if' to avoid warnings for unreachable 'return' */
+  return 0;
+}
+
+
+static const luaL_Reg syslib[] = {
+  {"clock",     os_clock},
+  {"date",      os_date},
+  {"difftime",  os_difftime},
+  {"execute",   os_execute},
+  {"exit",      os_exit},
+  {"getenv",    os_getenv},
+  {"remove",    os_remove},
+  {"rename",    os_rename},
+  {"setlocale", os_setlocale},
+  {"time",      os_time},
+  {"tmpname",   os_tmpname},
+  {NULL, NULL}
+};
+
+/* }====================================================== */
+
+
+
+LUAMOD_API int luaopen_os (lua_State *L) {
+  luaL_newlib(L, syslib);
+  return 1;
+}
+

=== added file 'src/scripting/eris/lparser.c'
--- src/scripting/eris/lparser.c	1970-01-01 00:00:00 +0000
+++ src/scripting/eris/lparser.c	2013-10-19 12:35:28 +0000
@@ -0,0 +1,1638 @@
+/*
+** $Id: lparser.c,v 2.130 2013/02/06 13:37:39 roberto Exp $
+** Lua Parser
+** See Copyright Notice in lua.h
+*/
+
+
+#include <string.h>
+
+#define lparser_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+
+
+
+/* maximum number of local variables per function (must be smaller
+   than 250, due to the bytecode format) */
+#define MAXVARS		200
+
+
+#define hasmultret(k)		((k) == VCALL || (k) == VVARARG)
+
+
+
+/*
+** nodes for block list (list of active blocks)
+*/
+typedef struct BlockCnt {
+  struct BlockCnt *previous;  /* chain */
+  short firstlabel;  /* index of first label in this block */
+  short firstgoto;  /* index of first pending goto in this block */
+  lu_byte nactvar;  /* # active locals outside the block */
+  lu_byte upval;  /* true if some variable in the block is an upvalue */
+  lu_byte isloop;  /* true if `block' is a loop */
+} BlockCnt;
+
+
+
+/*
+** prototypes for recursive non-terminal functions
+*/
+static void statement (LexState *ls);
+static void expr (LexState *ls, expdesc *v);
+
+
+static void anchor_token (LexState *ls) {
+  /* last token from outer function must be EOS */
+  lua_assert(ls->fs != NULL || ls->t.token == TK_EOS);
+  if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
+    TString *ts = ls->t.seminfo.ts;
+    luaX_newstring(ls, getstr(ts), ts->tsv.len);
+  }
+}
+
+
+/* semantic error */
+static l_noret semerror (LexState *ls, const char *msg) {
+  ls->t.token = 0;  /* remove 'near to' from final message */
+  luaX_syntaxerror(ls, msg);
+}
+
+
+static l_noret error_expected (LexState *ls, int token) {
+  luaX_syntaxerror(ls,
+      luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token)));
+}
+
+
+static l_noret errorlimit (FuncState *fs, int limit, const char *what) {
+  lua_State *L = fs->ls->L;
+  const char *msg;
+  int line = fs->f->linedefined;
+  const char *where = (line == 0)
+                      ? "main function"
+                      : luaO_pushfstring(L, "function at line %d", line);
+  msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s",
+                             what, limit, where);
+  luaX_syntaxerror(fs->ls, msg);
+}
+
+
+static void checklimit (FuncState *fs, int v, int l, const char *what) {
+  if (v > l) errorlimit(fs, l, what);
+}
+
+
+static int testnext (LexState *ls, int c) {
+  if (ls->t.token == c) {
+    luaX_next(ls);
+    return 1;
+  }
+  else return 0;
+}
+
+
+static void check (LexState *ls, int c) {
+  if (ls->t.token != c)
+    error_expected(ls, c);
+}
+
+
+static void checknext (LexState *ls, int c) {
+  check(ls, c);
+  luaX_next(ls);
+}
+
+
+#define check_condition(ls,c,msg)	{ if (!(c)) luaX_syntaxerror(ls, msg); }
+
+
+
+static void check_match (LexState *ls, int what, int who, int where) {
+  if (!testnext(ls, what)) {
+    if (where == ls->linenumber)
+      error_expected(ls, what);
+    else {
+      luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
+             "%s expected (to close %s at line %d)",
+              luaX_token2str(ls, what), luaX_token2str(ls, who), where));
+    }
+  }
+}
+
+
+static TString *str_checkname (LexState *ls) {
+  TString *ts;
+  check(ls, TK_NAME);
+  ts = ls->t.seminfo.ts;
+  luaX_next(ls);
+  return ts;
+}
+
+
+static void init_exp (expdesc *e, expkind k, int i) {
+  e->f = e->t = NO_JUMP;
+  e->k = k;
+  e->u.info = i;
+}
+
+
+static void codestring (LexState *ls, expdesc *e, TString *s) {
+  init_exp(e, VK, luaK_stringK(ls->fs, s));
+}
+
+
+static void checkname (LexState *ls, expdesc *e) {
+  codestring(ls, e, str_checkname(ls));
+}
+
+
+static int registerlocalvar (LexState *ls, TString *varname) {
+  FuncState *fs = ls->fs;
+  Proto *f = fs->f;
+  int oldsize = f->sizelocvars;
+  luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
+                  LocVar, SHRT_MAX, "local variables");
+  while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
+  f->locvars[fs->nlocvars].varname = varname;
+  luaC_objbarrier(ls->L, f, varname);
+  return fs->nlocvars++;
+}
+
+
+static void new_localvar (LexState *ls, TString *name) {
+  FuncState *fs = ls->fs;
+  Dyndata *dyd = ls->dyd;
+  int reg = registerlocalvar(ls, name);
+  checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
+                  MAXVARS, "local variables");
+  luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
+                  dyd->actvar.size, Vardesc, MAX_INT, "local variables");
+  dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg);
+}
+
+
+static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
+  new_localvar(ls, luaX_newstring(ls, name, sz));
+}
+
+#define new_localvarliteral(ls,v) \
+	new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1)
+
+
+static LocVar *getlocvar (FuncState *fs, int i) {
+  int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;
+  lua_assert(idx < fs->nlocvars);
+  return &fs->f->locvars[idx];
+}
+
+
+static void adjustlocalvars (LexState *ls, int nvars) {
+  FuncState *fs = ls->fs;
+  fs->nactvar = cast_byte(fs->nactvar + nvars);
+  for (; nvars; nvars--) {
+    getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;
+  }
+}
+
+
+static void removevars (FuncState *fs, int tolevel) {
+  fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);
+  while (fs->nactvar > tolevel)
+    getlocvar(fs, --fs->nactvar)->endpc = fs->pc;
+}
+
+
+static int searchupvalue (FuncState *fs, TString *name) {
+  int i;
+  Upvaldesc *up = fs->f->upvalues;
+  for (i = 0; i < fs->nups; i++) {
+    if (luaS_eqstr(up[i].name, name)) return i;
+  }
+  return -1;  /* not found */
+}
+
+
+static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
+  Proto *f = fs->f;
+  int oldsize = f->sizeupvalues;
+  checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
+  luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
+                  Upvaldesc, MAXUPVAL, "upvalues");
+  while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
+  f->upvalues[fs->nups].instack = (v->k == VLOCAL);
+  f->upvalues[fs->nups].idx = cast_byte(v->u.info);
+  f->upvalues[fs->nups].name = name;
+  luaC_objbarrier(fs->ls->L, f, name);
+  return fs->nups++;
+}
+
+
+static int searchvar (FuncState *fs, TString *n) {
+  int i;
+  for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
+    if (luaS_eqstr(n, getlocvar(fs, i)->varname))
+      return i;
+  }
+  return -1;  /* not found */
+}
+
+
+/*
+  Mark block where variable at given level was defined
+  (to emit close instructions later).
+*/
+static void markupval (FuncState *fs, int level) {
+  BlockCnt *bl = fs->bl;
+  while (bl->nactvar > level) bl = bl->previous;
+  bl->upval = 1;
+}
+
+
+/*
+  Find variable with given name 'n'. If it is an upvalue, add this
+  upvalue into all intermediate functions.
+*/
+static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
+  if (fs == NULL)  /* no more levels? */
+    return VVOID;  /* default is global */
+  else {
+    int v = searchvar(fs, n);  /* look up locals at current level */
+    if (v >= 0) {  /* found? */
+      init_exp(