Преглед изворни кода

Merge pull request #5020 from Simn/merge_candidate

Lua support
Nicolas Cannasse пре 9 година
родитељ
комит
751adebe02
91 измењених фајлова са 5939 додато и 48 уклоњено
  1. 8 1
      .travis.yml
  2. 15 0
      .travis/platform.sh
  3. 3 0
      .travis/setenv_lua.sh
  4. 124 0
      .travis/setup_lua.sh
  5. 6 2
      Makefile
  6. 2 0
      extra/ImportAll.hx
  7. 1722 0
      src/generators/genlua.ml
  8. 8 2
      src/main.ml
  9. 9 1
      src/optimization/analyzerTexpr.ml
  10. 3 3
      src/optimization/analyzerTexprTransformer.ml
  11. 1 0
      src/syntax/ast.ml
  12. 14 0
      src/typing/common.ml
  13. 19 4
      std/StringTools.hx
  14. 36 4
      std/haxe/Int32.hx
  15. 8 4
      std/haxe/Int64.hx
  16. 3 1
      std/haxe/Log.hx
  17. 1 1
      std/haxe/Serializer.hx
  18. 1 0
      std/haxe/Unserializer.hx
  19. 1 1
      std/haxe/format/JsonParser.hx
  20. 11 1
      std/haxe/io/Bytes.hx
  21. 10 5
      std/haxe/io/Input.hx
  22. 1 1
      std/haxe/macro/Compiler.hx
  23. 1 1
      std/haxe/unit/TestRunner.hx
  24. 1 1
      std/haxe/xml/Parser.hx
  25. 42 0
      std/lua/Bit.hx
  26. 353 0
      std/lua/Boot.hx
  27. 46 0
      std/lua/Coroutine.hx
  28. 66 0
      std/lua/Debug.hx
  29. 61 0
      std/lua/Ffi.hx
  30. 41 0
      std/lua/FileHandle.hx
  31. 42 0
      std/lua/HaxeIterator.hx
  32. 61 0
      std/lua/Io.hx
  33. 21 0
      std/lua/Jit.hx
  34. 66 0
      std/lua/Lib.hx
  35. 10 0
      std/lua/LocaleCategory.hx
  36. 55 0
      std/lua/Lua.hx
  37. 89 0
      std/lua/Map.hx
  38. 46 0
      std/lua/Math.hx
  39. 47 0
      std/lua/NativeIterator.hx
  40. 31 0
      std/lua/NativeStringTools.hx
  41. 51 0
      std/lua/Os.hx
  42. 38 0
      std/lua/Package.hx
  43. 50 0
      std/lua/PairTools.hx
  44. 33 0
      std/lua/Table.hx
  45. 31 0
      std/lua/Thread.hx
  46. 6 0
      std/lua/Time.hx
  47. 2 0
      std/lua/UserData.hx
  48. 28 0
      std/lua/_lua/_hx_anon.lua
  49. 12 0
      std/lua/_lua/_hx_bit.lua
  50. 10 0
      std/lua/_lua/_hx_function_to_instance_function.lua
  51. 1 0
      std/lua/_lua/_hx_print.lua
  52. 13 0
      std/lua/_lua/_hx_static_to_instance_function.lua
  53. 13 0
      std/lua/_lua/_hx_tab_array.lua
  54. 4 0
      std/lua/_lua/_hx_table_polyfill.lua
  55. 199 0
      std/lua/_std/Array.hx
  56. 69 0
      std/lua/_std/Date.hx
  57. 158 0
      std/lua/_std/EReg.hx
  58. 80 0
      std/lua/_std/Math.hx
  59. 167 0
      std/lua/_std/Reflect.hx
  60. 113 0
      std/lua/_std/Std.hx
  61. 132 0
      std/lua/_std/String.hx
  62. 111 0
      std/lua/_std/StringBuf.hx
  63. 134 0
      std/lua/_std/Sys.hx
  64. 208 0
      std/lua/_std/Type.hx
  65. 35 0
      std/lua/_std/haxe/Json.hx
  66. 285 0
      std/lua/_std/haxe/Utf8.hx
  67. 86 0
      std/lua/_std/haxe/ds/IntMap.hx
  68. 99 0
      std/lua/_std/haxe/ds/ObjectMap.hx
  69. 93 0
      std/lua/_std/haxe/ds/StringMap.hx
  70. 106 0
      std/lua/_std/sys/FileSystem.hx
  71. 72 0
      std/lua/_std/sys/io/File.hx
  72. 63 0
      std/lua/_std/sys/io/FileInput.hx
  73. 50 0
      std/lua/_std/sys/io/FileOutput.hx
  74. 51 0
      std/lua/_std/sys/io/Process.hx
  75. 40 0
      std/lua/lib/lfs/Lfs.hx
  76. 46 0
      std/lua/lib/lfs/LfsFileStat.hx
  77. 57 0
      std/lua/lib/lrexlib/Rex.hx
  78. 1 1
      tests/README.md
  79. 55 0
      tests/RunCi.hx
  80. 14 0
      tests/sys/compile-lua.hxml
  81. 6 4
      tests/sys/src/ExitCode.hx
  82. 2 1
      tests/sys/src/TestArguments.hx
  83. 12 2
      tests/sys/src/TestCommandBase.hx
  84. 4 2
      tests/sys/src/TestSys.hx
  85. 3 0
      tests/unit/compile-lua.hxml
  86. 1 0
      tests/unit/compile.hxml
  87. 1 1
      tests/unit/src/unit/Test.hx
  88. 1 1
      tests/unit/src/unit/TestBytes.hx
  89. 3 2
      tests/unit/src/unit/TestDCE.hx
  90. 1 1
      tests/unit/src/unitstd/StringTools.unit.hx
  91. 4 0
      tests/unit/unit.html

+ 8 - 1
.travis.yml

@@ -19,6 +19,9 @@ env:
     - PPA="ppa:haxe/snapshots"
     - DEBFULLNAME="Haxe CI Bot"
     - DEBEMAIL="[email protected]"
+    # lua specific versions
+    - LUAROCKS=2.3.0
+    - LUA=lua5.2
 
 sudo: false
 addons:
@@ -91,6 +94,8 @@ matrix:
       addons: {apt: {packages: *apt_python}}
     - os: linux
       env: TEST=hl
+    - os: linux
+      env: TEST=lua
 
     #######
     # osx #
@@ -120,12 +125,14 @@ matrix:
       env: TEST=cs
     - os: osx
       env: TEST=python
+    - os: osx
+      env: TEST=lua
 
 install:
   # Install haxe and neko dependencies
   - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
     travis_retry brew update;
-    travis_retry brew install ocaml camlp4;
+    travis_retry brew install ocaml camlp4 pcre;
     fi
   # Install neko
   - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then

+ 15 - 0
.travis/platform.sh

@@ -0,0 +1,15 @@
+if [ -z "${PLATFORM:-}" ]; then
+  PLATFORM=$TRAVIS_OS_NAME;
+fi
+
+if [ "$PLATFORM" == "osx" ]; then
+  PLATFORM="macosx";
+fi
+
+if [ -z "$PLATFORM" ]; then
+  if [ "$(uname)" == "Linux" ]; then
+    PLATFORM="linux";
+  else
+    PLATFORM="macosx";
+  fi;
+fi

+ 3 - 0
.travis/setenv_lua.sh

@@ -0,0 +1,3 @@
+export PATH=${PATH}:$HOME/.lua:$HOME/.local/bin:$TRAVIS_BUILD_DIR/install/luarocks/bin
+bash .travis/setup_lua.sh
+eval `$HOME/.lua/luarocks path`

+ 124 - 0
.travis/setup_lua.sh

@@ -0,0 +1,124 @@
+#! /bin/bash
+
+# A script for setting up environment for travis-ci testing.
+# Sets up Lua and Luarocks.
+# LUA must be "lua5.1", "lua5.2", "lua5.3", or "luajit".
+# luajit2.0 - master v2.0
+# luajit2.1 - master v2.1
+
+set -eufo pipefail
+
+LUAJIT_VERSION="2.0.4"
+LUAJIT_BASE="LuaJIT-$LUAJIT_VERSION"
+
+source .travis/platform.sh
+
+LUA_HOME_DIR=$TRAVIS_BUILD_DIR/install/lua
+
+LR_HOME_DIR=$TRAVIS_BUILD_DIR/install/luarocks
+
+mkdir $HOME/.lua
+
+LUAJIT="no"
+
+if [ "$PLATFORM" == "macosx" ]; then
+  if [ "$LUA" == "luajit" ]; then
+    LUAJIT="yes";
+  fi
+  if [ "$LUA" == "luajit2.0" ]; then
+    LUAJIT="yes";
+  fi
+  if [ "$LUA" == "luajit2.1" ]; then
+    LUAJIT="yes";
+  fi;
+elif [ "$(expr substr $LUA 1 6)" == "luajit" ]; then
+  LUAJIT="yes";
+fi
+
+mkdir -p "$LUA_HOME_DIR"
+
+if [ "$LUAJIT" == "yes" ]; then
+
+  if [ "$LUA" == "luajit" ]; then
+    curl --location https://github.com/LuaJIT/LuaJIT/archive/v$LUAJIT_VERSION.tar.gz | tar xz;
+  else
+    git clone https://github.com/LuaJIT/LuaJIT.git $LUAJIT_BASE;
+  fi
+
+  cd $LUAJIT_BASE
+
+  if [ "$LUA" == "luajit2.1" ]; then
+    git checkout v2.1;
+    # force the INSTALL_TNAME to be luajit
+    perl -i -pe 's/INSTALL_TNAME=.+/INSTALL_TNAME= luajit/' Makefile
+  fi
+
+  make && make install PREFIX="$LUA_HOME_DIR"
+
+  ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/luajit
+  ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/lua;
+
+else
+
+  if [ "$LUA" == "lua5.1" ]; then
+    curl http://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz
+    cd lua-5.1.5;
+  elif [ "$LUA" == "lua5.2" ]; then
+    curl http://www.lua.org/ftp/lua-5.2.4.tar.gz | tar xz
+    cd lua-5.2.4;
+  elif [ "$LUA" == "lua5.3" ]; then
+    curl http://www.lua.org/ftp/lua-5.3.2.tar.gz | tar xz
+    cd lua-5.3.2;
+  fi
+
+  # Build Lua without backwards compatibility for testing
+  perl -i -pe 's/-DLUA_COMPAT_(ALL|5_2)//' src/Makefile
+  make $PLATFORM
+  make INSTALL_TOP="$LUA_HOME_DIR" install;
+
+  ln -s $LUA_HOME_DIR/bin/lua $HOME/.lua/lua
+  ln -s $LUA_HOME_DIR/bin/luac $HOME/.lua/luac;
+
+fi
+
+ls -l $HOME/.lua
+echo $PATH
+
+cd $TRAVIS_BUILD_DIR
+lua -v
+
+LUAROCKS_BASE=luarocks-$LUAROCKS
+
+curl --location http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz
+
+cd $LUAROCKS_BASE
+
+if [ "$LUA" == "luajit" ]; then
+  ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR";
+elif [ "$LUA" == "luajit2.0" ]; then
+  ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR";
+elif [ "$LUA" == "luajit2.1" ]; then
+  ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.1" --prefix="$LR_HOME_DIR";
+else
+  ./configure --with-lua="$LUA_HOME_DIR" --prefix="$LR_HOME_DIR"
+fi
+
+make build && make install
+
+ln -s $LR_HOME_DIR/bin/luarocks $HOME/.lua/luarocks
+
+cd $TRAVIS_BUILD_DIR
+
+luarocks --version
+
+rm -rf $LUAROCKS_BASE
+
+if [ "$LUAJIT" == "yes" ]; then
+  rm -rf $LUAJIT_BASE;
+elif [ "$LUA" == "lua5.1" ]; then
+  rm -rf lua-5.1.5;
+elif [ "$LUA" == "lua5.2" ]; then
+  rm -rf lua-5.2.4;
+elif [ "$LUA" == "lua5.3" ]; then
+  rm -rf lua-5.3.2;
+fi

+ 6 - 2
Makefile

@@ -55,6 +55,7 @@ MODULES=syntax/ast typing/type syntax/lexer typing/common generators/genxml synt
 	optimization/optimizer typing/typeload generators/codegen generators/gencommon generators/genas3 \
 	generators/gencpp generators/genjs generators/genneko generators/genphp generators/genswf9 \
 	generators/genswf generators/genjava generators/gencs generators/genpy macro/interp generators/genhl \
+	generators/genlua \
 	optimization/dce optimization/analyzerConfig optimization/analyzerTypes optimization/analyzerTexpr \
 	optimization/analyzerTexprTransformer optimization/analyzer \
 	optimization/filters typing/typer typing/matcher version main
@@ -147,6 +148,8 @@ src/generators/genjs.$(MODULE_EXT): src/typing/type.$(MODULE_EXT) src/syntax/lex
 
 src/generators/genneko.$(MODULE_EXT): src/typing/type.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
 
+src/generators/genlua.$(MODULE_EXT): src/typing/type.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
+
 src/generators/genphp.$(MODULE_EXT): src/typing/type.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
 
 src/generators/genpy.$(MODULE_EXT): src/typing/type.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
@@ -202,11 +205,12 @@ src/typing/typecore.$(MODULE_EXT): src/typing/type.$(MODULE_EXT) src/typing/comm
 
 src/typing/typeload.$(MODULE_EXT): src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
 
-src/typing/typer.$(MODULE_EXT): src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/optimization/filters.$(MODULE_EXT) src/generators/gencommon.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT)
+src/typing/typer.$(MODULE_EXT): src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/optimization/filters.$(MODULE_EXT) src/generators/gencommon.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT) src/generators/genlua.$(MODULE_EXT)
+
 
 # main
 
-src/main.$(MODULE_EXT): src/optimization/filters.$(MODULE_EXT) src/typing/matcher.$(MODULE_EXT) src/typing/typer.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/generators/genxml.$(MODULE_EXT) src/generators/genswf.$(MODULE_EXT) src/generators/genphp.$(MODULE_EXT) src/generators/genneko.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT) src/generators/gencpp.$(MODULE_EXT) src/generators/genas3.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/generators/gencommon.$(MODULE_EXT) src/generators/genjava.$(MODULE_EXT) src/generators/gencs.$(MODULE_EXT) src/generators/genpy.$(MODULE_EXT) src/generators/genhl.$(MODULE_EXT) src/version.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
+src/main.$(MODULE_EXT): src/optimization/filters.$(MODULE_EXT) src/typing/matcher.$(MODULE_EXT) src/typing/typer.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/generators/genxml.$(MODULE_EXT) src/generators/genswf.$(MODULE_EXT) src/generators/genphp.$(MODULE_EXT) src/generators/genneko.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT) src/generators/genlua.$(MODULE_EXT) src/generators/gencpp.$(MODULE_EXT) src/generators/genas3.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/generators/gencommon.$(MODULE_EXT) src/generators/genjava.$(MODULE_EXT) src/generators/gencs.$(MODULE_EXT) src/generators/genpy.$(MODULE_EXT) src/generators/genhl.$(MODULE_EXT) src/version.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
 
 src/version.$(MODULE_EXT):
 	$(MAKE) -f Makefile.version_extra -s --no-print-directory ADD_REVISION=$(ADD_REVISION) BRANCH=$(BRANCH) COMMIT_SHA=$(COMMIT_SHA) COMMIT_DATE=$(COMMIT_DATE) > src/version.ml

+ 2 - 0
extra/ImportAll.hx

@@ -49,6 +49,8 @@ class ImportAll {
 			if ( !Context.defined("python") ) return;
 		case "hl":
 			if( !Context.defined("hl") ) return;
+		case "lua":
+			if( !Context.defined("lua") ) return;
 		case "tools":
 			return;
 		case "build-tool":

+ 1722 - 0
src/generators/genlua.ml

@@ -0,0 +1,1722 @@
+(*
+ * Copyright (C)2005-2013 Haxe Foundation
+ *
+ * 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.
+ *)
+
+open Ast
+open Type
+open Common
+open ExtList
+
+type pos = Ast.pos
+
+type ctx = {
+	com : Common.context;
+	buf : Buffer.t;
+	packages : (string list,unit) Hashtbl.t;
+	mutable current : tclass;
+	mutable statics : (tclass * string * texpr) list;
+	mutable inits : texpr list;
+	mutable tabs : string;
+	mutable in_value : tvar option;
+	mutable in_loop : bool;
+	mutable iife_assign : bool;
+	mutable handle_break : bool;
+	mutable id_counter : int;
+	mutable type_accessor : module_type -> string;
+	mutable separator : bool;
+	mutable found_expose : bool;
+	mutable lua_jit : bool;
+	mutable lua_ver : float;
+}
+
+type object_store = {
+	os_name : string;
+	mutable os_fields : object_store list;
+}
+
+let debug_expression expression  =
+    " --[[ " ^ Type.s_expr_kind expression  ^ " --]] "
+
+let debug_type t  =
+    " --[[ " ^ Type.s_type_kind t  ^ " --]] ";;
+
+let get_exposed ctx path meta = try
+		let (_, args, pos) = Meta.get Meta.Expose meta in
+		(match args with
+			| [ EConst (String s), _ ] -> [s]
+			| [] -> [path]
+			| _ -> error "Invalid @:expose parameters" pos)
+	with Not_found -> []
+
+let dot_path = Ast.s_type_path
+
+let s_path ctx = dot_path
+
+(* TODO: are all these kwds necessary for field quotes *and* id escapes? *)
+let kwds =
+	let h = Hashtbl.create 0 in
+	List.iter (fun s -> Hashtbl.add h s ()) [
+	    ""; "and"; "break"; "do"; "else"; "elseif";
+	    "end"; "false"; "for"; "function"; "if";
+	    "in"; "local"; "nil"; "not"; "or"; "repeat";
+	    "return"; "then"; "true"; "until"; "while";
+	    "goto"
+	];
+	h
+
+let valid_lua_ident s =
+	try
+		for i = 0 to String.length s - 1 do
+		    match String.unsafe_get s i with
+		    | 'a'..'z' | 'A'..'Z' | '_' -> ()
+		    | '0'..'9' when i > 0 -> ()
+		    | _ -> raise Exit
+		done;
+		true
+	with Exit ->
+		false
+
+let field s = if Hashtbl.mem kwds s || not (valid_lua_ident s) then "[\"" ^ s ^ "\"]" else "." ^ s
+let ident s = if Hashtbl.mem kwds s then "_" ^ s else s
+
+let anon_field s = if Hashtbl.mem kwds s || not (valid_lua_ident s) then "['" ^ (Ast.s_escape s) ^ "']" else s
+
+let has_feature ctx = Common.has_feature ctx.com
+let add_feature ctx = Common.add_feature ctx.com
+
+let temp ctx =
+	ctx.id_counter <- ctx.id_counter + 1;
+	"_hx_" ^ string_of_int (ctx.id_counter)
+
+let spr ctx s =
+	ctx.separator <- false;
+	Buffer.add_string ctx.buf s
+
+let print ctx =
+	ctx.separator <- false;
+	Printf.kprintf (fun s -> begin
+		Buffer.add_string ctx.buf s
+	end)
+
+let newline ctx = print ctx "\n%s" ctx.tabs
+
+(* spr with newline *)
+let sprln ctx s = spr ctx s; newline ctx
+
+(* print with newline *)
+let println ctx =
+	ctx.separator <- false;
+	Printf.kprintf (fun s -> begin
+		Buffer.add_string ctx.buf s;
+		newline ctx
+	end)
+
+let unsupported p = error "This expression cannot be compiled to Lua" p
+
+let basename path =
+	try
+		let idx = String.rindex path '/' in
+		String.sub path (idx + 1) (String.length path - idx - 1)
+	with Not_found -> path
+
+(* TODO : make this work properly... it was inserting commas where they shouldn't be *)
+let newprop ctx =
+	match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with
+	| '{' -> print ctx "\n%s" ctx.tabs
+	| _ -> print ctx "\n%s" ctx.tabs
+
+let semicolon ctx =
+	match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with
+	| '}' when not ctx.separator -> ()
+	| _ -> spr ctx ";"
+
+let rec concat ctx s f = function
+	| [] -> ()
+	| [x] -> f x
+	| x :: l ->
+		f x;
+		spr ctx s;
+		concat ctx s f l
+
+let fun_block ctx f p =
+	let e = List.fold_left (fun e (a,c) ->
+		match c with
+		| None | Some TNull -> e
+		| Some c -> Type.concat (Codegen.set_default ctx.com a c p) e
+	) f.tf_expr f.tf_args in
+	e
+
+let open_block ctx =
+	let oldt = ctx.tabs in
+	ctx.tabs <- "\t" ^ ctx.tabs;
+	(fun() -> ctx.tabs <- oldt)
+
+let rec iter_switch_break in_switch e =
+	match e.eexpr with
+	| TFunction _ | TWhile _ | TFor _ -> ()
+	| TSwitch _ when not in_switch -> iter_switch_break true e
+	| TBreak when in_switch -> raise Exit
+	| _ -> iter (iter_switch_break in_switch) e
+
+let handle_break ctx e =
+	let old = ctx.in_loop, ctx.handle_break in
+	ctx.in_loop <- true;
+	try
+		iter_switch_break false e;
+		ctx.handle_break <- false;
+		(fun() ->
+			ctx.in_loop <- fst old;
+			ctx.handle_break <- snd old;
+		)
+	with
+		Exit ->
+			spr ctx "try {";
+			let b = open_block ctx in
+			newline ctx;
+			ctx.handle_break <- true;
+			(fun() ->
+				b();
+				ctx.in_loop <- fst old;
+				ctx.handle_break <- snd old;
+				newline ctx;
+				spr ctx "} catch( e ) { if( e != \"_hx__break__\" ) throw e; }";
+			)
+
+let this ctx = match ctx.in_value with None -> "self" | Some _ -> "self"
+
+let is_dynamic_iterator ctx e =
+	let check x =
+		has_feature ctx "HxOverrides.iter" && (match follow x.etype with
+			| TInst ({ cl_path = [],"Array" },_)
+			| TInst ({ cl_kind = KTypeParameter _}, _)
+			| TAnon _
+			| TDynamic _
+			| TMono _ ->
+				true
+			| _ -> false
+		)
+	in
+	match e.eexpr with
+	| TField (x,f) when field_name f = "iterator" -> check x
+	| _ ->
+		false
+
+(* from genphp *)
+let rec is_uncertain_type t =
+	match follow t with
+	| TInst (c, _) -> c.cl_interface
+	| TMono _ -> true
+	| TAnon a ->
+	  (match !(a.a_status) with
+	  | Statics _
+	  | EnumStatics _ -> false
+	  | _ -> true)
+	| TDynamic _ -> true
+	| _ -> false
+
+let is_uncertain_expr e =
+	is_uncertain_type e.etype
+
+let rec is_anonym_type t =
+	match follow t with
+	| TAnon a ->
+	  (match !(a.a_status) with
+	  | Statics _
+	  | EnumStatics _ -> false
+	  | _ -> true)
+	| TDynamic _ -> true
+	| _ -> false
+
+let is_anonym_expr e = is_anonym_type e.etype
+
+let rec is_unknown_type t =
+	match follow t with
+	| TMono r ->
+		(match !r with
+		| None -> true
+		| Some t -> is_unknown_type t)
+	| _ -> false
+
+let is_unknown_expr e =	is_unknown_type e.etype
+
+let rec is_string_type t =
+	match follow t with
+	| TInst ({cl_path = ([], "String")}, _) -> true
+	| TAnon a ->
+	   (match !(a.a_status) with
+	   | Statics ({cl_path = ([], "String")}) -> true
+	   | _ -> false)
+	| TAbstract (a,pl) -> is_string_type (Abstract.get_underlying_type a pl)
+	| _ -> false
+
+let is_string_expr e = is_string_type e.etype
+(* /from genphp *)
+
+let rec is_int_type ctx t =
+    match follow t with
+	| TInst ({cl_path = ([], "Int")}, _) -> true
+	| TAnon a ->
+		(match !(a.a_status) with
+	    | Statics ({cl_path = ([], "Int")}) -> true
+	    | _ -> false)
+		| TAbstract ({a_path = ([],"Float")}, pl) -> false
+	| TAbstract ({a_path = ([],"Int")}, pl) -> true
+	| TAbstract (a,pl) -> is_int_type ctx (Abstract.get_underlying_type a pl)
+	| _ -> false
+
+let rec should_wrap_int_op ctx op e1 e2 =
+    match op with
+    | Ast.OpAdd | Ast.OpMult | Ast.OpDiv | Ast.OpSub | Ast.OpAnd | Ast.OpOr
+    | Ast.OpXor | Ast.OpShl  | Ast.OpShr | Ast.OpUShr ->
+	    is_int_type ctx e1.etype && is_int_type ctx e2.etype
+    | _ -> false
+
+let gen_constant ctx p = function
+	| TInt i -> print ctx "%ld" i
+	| TFloat s -> spr ctx s
+	| TString s -> print ctx "\"%s\"" (Ast.s_escape s)
+	| TBool b -> spr ctx (if b then "true" else "false")
+	| TNull -> spr ctx "nil"
+	| TThis -> spr ctx (this ctx)
+	| TSuper -> assert false
+
+let rec gen_call ctx e el in_value =
+	ctx.iife_assign <- true;
+	(match e.eexpr , el with
+	| TConst TSuper , params ->
+		(match ctx.current.cl_super with
+		| None -> error "Missing api.setCurrentClass" e.epos
+		| Some (c,_) ->
+			print ctx "%s.super(%s" (ctx.type_accessor (TClassDecl c)) (this ctx);
+			List.iter (fun p -> print ctx ","; gen_value ctx p) params;
+			spr ctx ")";
+		);
+	| TField ({ eexpr = TConst TSuper },f) , params ->
+		(match ctx.current.cl_super with
+		| None -> error "Missing api.setCurrentClass" e.epos
+		| Some (c,_) ->
+			let name = field_name f in
+			print ctx "%s.prototype%s(%s" (ctx.type_accessor (TClassDecl c)) (field name) (this ctx);
+			List.iter (fun p -> print ctx ","; gen_value ctx p) params;
+			spr ctx ")";
+		);
+	| TCall (x,_) , el when (match x.eexpr with TLocal { v_name = "__lua__" } -> false | _ -> true) ->
+		spr ctx "(";
+		gen_value ctx e;
+		spr ctx ")";
+		spr ctx "(";
+		concat ctx "," (gen_value ctx) el;
+		spr ctx ")";
+	| TLocal { v_name = "__new__" }, { eexpr = TConst (TString cl) } :: params ->
+		print ctx "%s.new(" cl;
+		concat ctx "," (gen_value ctx) params;
+		spr ctx ")";
+	| TLocal { v_name = "__new__" }, e :: params ->
+		gen_value ctx e;
+		spr ctx ".new(";
+		concat ctx "," (gen_value ctx) params;
+		spr ctx ")";
+	| TLocal { v_name = "__callself__" }, { eexpr = TConst (TString head) } :: { eexpr = TConst (TString tail) } :: el ->
+		print ctx "%s:%s" head tail;
+		spr ctx "(";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")";
+	| TLocal { v_name = "__call__" }, { eexpr = TConst (TString code) } :: el ->
+		spr ctx code;
+		spr ctx "(";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")";
+	| TLocal { v_name = "__lua_table__" }, el ->
+		spr ctx "{";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx "}";
+	| TLocal { v_name = "__lua__" }, [{ eexpr = TConst (TString code) }] ->
+		spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n"))
+	| TLocal { v_name = "__lua__" }, { eexpr = TConst (TString code); epos = p } :: tl ->
+		Codegen.interpolate_code ctx.com code tl (spr ctx) (gen_expr ctx) p
+	| TLocal { v_name = "__type__" },  [o] ->
+		spr ctx "type(";
+		gen_value ctx o;
+		spr ctx ")";
+	| TLocal ({v_name = "__define_feature__"}), [_;e] ->
+		gen_expr ctx e
+	| TLocal { v_name = "__feature__" }, { eexpr = TConst (TString f) } :: eif :: eelse ->
+		(if has_feature ctx f then
+			gen_value ctx eif
+		else match eelse with
+			| [] -> ()
+			| e :: _ -> gen_value ctx e)
+	| TLocal { v_name = "__resources__" }, [] ->
+		(* TODO: Array declaration helper *)
+		spr ctx "_hx_tabArray({";
+		let count = ref 0 in
+		concat ctx "," (fun (name,data) ->
+			if (!count == 0) then spr ctx "[0]=";
+			spr ctx "{ ";
+			spr ctx "name = ";
+			gen_constant ctx e.epos (TString name);
+			spr ctx ", data = ";
+			gen_constant ctx e.epos (TString (Codegen.bytes_serialize data));
+			spr ctx "}";
+			incr count
+		) (Hashtbl.fold (fun name data acc -> (name,data) :: acc) ctx.com.resources []);
+		print ctx "}, %i)" !count;
+	| TLocal { v_name = "`trace" }, [e;infos] ->
+		if has_feature ctx "haxe.Log.trace" then begin
+			let t = (try List.find (fun t -> t_path t = (["haxe"],"Log")) ctx.com.types with _ -> assert false) in
+			spr ctx (ctx.type_accessor t);
+			spr ctx ".trace(";
+			gen_value ctx e;
+			spr ctx ",";
+			gen_value ctx infos;
+			spr ctx ")";
+		end else begin
+			spr ctx "_hx_print(";
+			gen_value ctx e;
+			spr ctx ")";
+		end
+	| TCall ({eexpr = TField(e,((FInstance _ | FAnon _) as ef)) }, _), el ->
+		gen_value ctx e;
+		print ctx ":%s(" (field_name ef);
+		concat ctx "," (gen_value ctx) el;
+		spr ctx ")";
+	| TField ( { eexpr = TConst(TInt _ | TFloat _| TString _| TBool _) } as e , ((FInstance _ | FAnon _) as ef)), el ->
+		spr ctx ("(");
+		gen_value ctx e;
+		print ctx ("):%s(") (field_name ef);
+		concat ctx "," (gen_value ctx) el;
+		spr ctx ")";
+	| TField (e, ((FInstance _ | FAnon _ | FDynamic _) as ef)), el ->
+		gen_value ctx e;
+		spr ctx ":";
+		print ctx "%s" (field_name ef);
+		spr ctx "(";
+		concat ctx "," (gen_value ctx) el;
+		spr ctx ")"
+	| _ ->
+		gen_value ctx e;
+		spr ctx "(";
+		concat ctx "," (gen_value ctx) el;
+		spr ctx ")");
+	ctx.iife_assign <- false;
+
+and gen_expr ?(local=true) ctx e = begin
+	match e.eexpr with
+	 TConst c ->
+		gen_constant ctx e.epos c;
+	| TLocal v when v.v_name = "this" ->
+		spr ctx "self";
+	| TLocal v -> spr ctx (ident v.v_name)
+	| TArray (e1,{ eexpr = TConst (TString s) }) when valid_lua_ident s && (match e1.eexpr with TConst (TInt _|TFloat _) -> false | _ -> true) ->
+		gen_value ctx e1;
+		spr ctx (field s)
+	| TArray (e1,e2) ->
+		gen_value ctx e1;
+		spr ctx "[";
+		gen_value ctx e2;
+		spr ctx "]";
+	| TBinop (op,e1,e2) ->
+		gen_tbinop ctx op e1 e2;
+	| TField (x,f) when field_name f = "iterator" && is_dynamic_iterator ctx e ->
+		add_feature ctx "use._iterator";
+		print ctx "_iterator(";
+		gen_value ctx x;
+		print ctx ")";
+	| TField (x,FClosure (_,f)) ->
+		add_feature ctx "use._hx_bind";
+		(match x.eexpr with
+		| TConst _ | TLocal _ ->
+			print ctx "_hx_bind(";
+			gen_value ctx x;
+			print ctx ",";
+			gen_value ctx x;
+			print ctx "%s)" (field f.cf_name)
+		| _ ->
+			print ctx "(__=";
+			gen_value ctx x;
+			print ctx ",_hx_bind(__,__%s))" (field f.cf_name))
+	| TEnumParameter (x,_,i) ->
+		gen_value ctx x;
+		print ctx "[%i]" (i + 2)
+	| TField ({ eexpr = TConst(TInt _ | TFloat _| TString _| TBool _) } as e , ((FInstance _ | FAnon _) as ef)) ->
+		spr ctx ("(");
+		gen_value ctx e;
+		print ctx (").%s") (field_name ef);
+	| TField ({ eexpr = TConst (TInt _ | TFloat _) } as x,f) ->
+		gen_expr ctx { e with eexpr = TField(mk (TParenthesis x) x.etype x.epos,f) }
+	| TField ({ eexpr = TObjectDecl fields }, ef ) ->
+		spr ctx "(function(x) return x.";
+		print ctx "%s" (field_name ef);
+		spr ctx " end )({";
+		concat ctx ", " (fun (f,e) -> print ctx "%s = " (anon_field f); gen_value ctx e) fields;
+		spr ctx "})";
+	| TField (x,f) ->
+		gen_value ctx x;
+		let name = field_name f in
+		spr ctx (match f with FStatic _ | FEnum _ | FInstance _ | FAnon _ | FDynamic _ | FClosure _ -> field name)
+	| TTypeExpr t ->
+		spr ctx (ctx.type_accessor t)
+	| TParenthesis e ->
+		spr ctx "(";
+		gen_value ctx e;
+		spr ctx ")";
+	| TMeta (_,e) ->
+		gen_expr ctx e
+	| TReturn eo -> gen_return ctx e eo;
+	| TBreak ->
+		if not ctx.in_loop then unsupported e.epos;
+		if ctx.handle_break then spr ctx "error(\"_hx__break__\")" else spr ctx "break" (*todo*)
+	| TContinue ->
+		if not ctx.in_loop then unsupported e.epos;
+		spr ctx "goto _hx_continue";
+	| TBlock el ->
+		let bend = open_block ctx in
+		List.iter (gen_block_element ctx) el;
+		bend();
+		newline ctx;
+	| TFunction f ->
+		let old = ctx.in_value, ctx.in_loop in
+		ctx.in_value <- None;
+		ctx.in_loop <- false;
+		print ctx "function(%s) " (String.concat "," (List.map ident (List.map arg_name f.tf_args)));
+		let fblock = fun_block ctx f e.epos in
+		(match fblock.eexpr with
+		| TBlock el ->
+		    let bend = open_block ctx in
+		    List.iter (gen_block_element ctx) el;
+		    bend();
+		    newline ctx;
+		|_ -> ());
+		spr ctx "end";
+		ctx.in_value <- fst old;
+		ctx.in_loop <- snd old;
+		ctx.separator <- true
+	| TCall (e,el) ->
+		begin
+		    gen_call ctx e el false;
+		end;
+	| TArrayDecl el ->
+		spr ctx "_hx_tabArray({";
+		let count = ref 0 in
+		List.iteri (fun i e ->
+		    incr count;
+		    if (i == 0) then spr ctx "[0]="
+		    else spr ctx ", ";
+		    gen_value ctx e) el;
+		print ctx " }, %i)" !count;
+	| TThrow e ->
+		spr ctx "error(";
+		gen_value ctx e;
+		spr ctx ",0)";
+	| TVar (v,eo) ->
+		begin match eo with
+			| None ->
+				if local then
+				    spr ctx "local ";
+				spr ctx (ident v.v_name);
+			| Some e ->
+				match e.eexpr with
+				| TBinop(OpAssign, e1, e2) ->
+				    gen_tbinop ctx OpAssign e1 e2;
+				    if local then
+					spr ctx " local ";
+				    spr ctx (ident v.v_name);
+				    spr ctx " = ";
+				    gen_value ctx e1;
+				    semicolon ctx;
+
+				| _ ->
+				    if local then
+					spr ctx "local ";
+				    spr ctx (ident v.v_name);
+				    spr ctx " = ";
+				    gen_value ctx e;
+				    semicolon ctx;
+		end
+	| TNew (c,_,el) ->
+		print ctx "%s.new(" (ctx.type_accessor (TClassDecl c));
+		    concat ctx "," (gen_value ctx) el;
+		spr ctx ")"
+	| TIf (cond,e,eelse) ->
+		ctx.iife_assign <- true;
+		spr ctx "if ";
+		gen_cond ctx cond;
+		spr ctx " then ";
+		let bend = open_block ctx in
+		gen_block_element ctx e;
+		bend();
+		newline ctx;
+		(match eelse with
+		| None -> ();
+		| Some e2 ->
+			(match e.eexpr with
+			| TObjectDecl _ -> ctx.separator <- false
+			| _ ->());
+			spr ctx "else";
+			let bend = open_block ctx in
+			gen_block_element ctx e2;
+			bend();
+			newline ctx);
+		spr ctx "end";
+		ctx.iife_assign <- false;
+	| TUnop ((Increment|Decrement) as op,unop_flag, e) ->
+		(* TODO: Refactor this mess *)
+		sprln ctx "(function() ";
+		(match e.eexpr, unop_flag with
+		    | TArray(e1,e2), _ ->
+			spr ctx "local _hx_idx = "; gen_value ctx e2; semicolon ctx; newline ctx;
+			spr ctx "local _hx_arr ="; gen_value ctx e1; semicolon ctx; newline ctx;
+			(match unop_flag with
+			    | Ast.Postfix ->
+				    spr ctx "local _ = _hx_arr[_hx_idx]"; semicolon ctx; newline ctx;
+			    | _ -> ());
+			spr ctx "_hx_arr[_hx_idx] = _hx_arr[_hx_idx]";
+		    | TField(e1,e2), _ ->
+			spr ctx "local _hx_obj = "; gen_value ctx e1; semicolon ctx; newline ctx;
+			spr ctx "local _hx_fld = ";
+			(match e2 with
+			| FInstance(_,_,fld)
+			| FStatic(_,fld)
+			| FAnon fld
+			| FClosure(_,fld) ->
+				print ctx "'%s'" fld.cf_name;
+			| FDynamic name ->
+				print ctx "'%s'" name;
+			| FEnum(_,efld) ->
+				print ctx "'%s'" efld.ef_name);
+			semicolon ctx; newline ctx;
+			(match unop_flag with
+			    | Ast.Postfix ->
+				    spr ctx "local _ = _hx_obj[_hx_fld]"; semicolon ctx; newline ctx;
+			    | _ -> ());
+			spr ctx "_hx_obj[_hx_fld] = _hx_obj[_hx_fld] ";
+		    | _, Ast.Prefix ->
+			gen_value ctx e;
+			spr ctx " = ";
+			gen_value ctx e;
+		    | _, Ast.Postfix ->
+			spr ctx "local _ = ";
+			gen_value ctx e; semicolon ctx;
+			gen_value ctx e;
+			spr ctx " = ";
+			gen_value ctx e);
+		(match op with
+		    |Increment -> spr ctx " + 1;"
+		    |Decrement -> spr ctx " - 1;"
+		    |_-> print ctx " %s 1;" (Ast.s_unop op));
+		newline ctx;
+		spr ctx " return ";
+		(match unop_flag, e.eexpr with
+		    | Ast.Postfix, _ ->
+			    spr ctx "_";
+		    | _, TArray(e1,e2) ->
+			    spr ctx "_hx_arr[_hx_idx]";
+		    | _, TField(e1,e2) ->
+			    spr ctx "_hx_obj[_hx_fld]";
+		    | _, _ ->
+			    gen_value ctx e;
+		    );
+		semicolon ctx; newline ctx;
+		spr ctx " end)()";
+	| TUnop (Not,unop_flag,e) ->
+		spr ctx "not ";
+		gen_value ctx e;
+	| TUnop (NegBits,unop_flag,e) ->
+		spr ctx "_hx_bit.bnot(";
+		gen_value ctx e;
+		spr ctx ")";
+	| TUnop (op,Ast.Prefix,e) ->
+		spr ctx (Ast.s_unop op);
+		gen_value ctx e
+	| TUnop (op,Ast.Postfix,e) ->
+		gen_value ctx e;
+		spr ctx (Ast.s_unop op)
+	| TWhile (cond,e,Ast.NormalWhile) ->
+		let handle_break = handle_break ctx e in
+		spr ctx "while ";
+		gen_cond ctx cond;
+		spr ctx " do ";
+		gen_block_element ctx e;
+		handle_break();
+		if has_continue e then begin
+		    newline ctx;
+		    spr ctx "::_hx_continue::";
+		end;
+		newline ctx;
+		spr ctx "end";
+	| TWhile (cond,e,Ast.DoWhile) ->
+		let handle_break = handle_break ctx e in
+		spr ctx "while true do ";
+		gen_block_element ctx e;
+		newline ctx;
+		spr ctx " while ";
+		gen_cond ctx cond;
+		spr ctx " do ";
+		gen_block_element ctx e;
+		handle_break();
+		newline ctx;
+		if has_continue e then begin
+		    newline ctx;
+		    spr ctx "::_hx_continue::";
+		end;
+		newline ctx;
+		sprln ctx "end";
+		spr ctx "break end";
+	| TObjectDecl [] ->
+		spr ctx "_hx_empty()";
+		ctx.separator <- true
+	| TObjectDecl fields ->
+		spr ctx "_hx_o({__fields__={";
+		concat ctx "," (fun (f,e) -> print ctx "%s=" (anon_field f); spr ctx "true") fields;
+		spr ctx "},";
+		concat ctx "," (fun (f,e) -> print ctx "%s=" (anon_field f); gen_value ctx e) fields;
+		spr ctx "})";
+		ctx.separator <- true
+	| TFor (v,it,e) ->
+		let handle_break = handle_break ctx e in
+		let it = ident (match it.eexpr with
+			| TLocal v -> v.v_name
+			| _ ->
+				let name = temp ctx in
+				print ctx "local %s = " name;
+				gen_value ctx it;
+				newline ctx;
+				name
+		) in
+		print ctx "while( %s:hasNext() ) do" it;
+		let bend = open_block ctx in
+		newline ctx;
+		print ctx "local %s = %s:next();" (ident v.v_name) it;
+		gen_block_element ctx e;
+		bend();
+		newline ctx;
+		spr ctx "end";
+		handle_break();
+		newline ctx;
+	| TTry (e,catchs) ->
+		(* TODO: add temp variables *)
+		sprln ctx "local _hx_expected_result = {}";
+		spr ctx "local _hx_status, _hx_result = pcall(function() ";
+		gen_expr ctx e;
+		let vname = temp ctx in
+		sprln ctx " return _hx_expected_result end)";
+		spr ctx " if not _hx_status then ";
+		let bend = open_block ctx in
+		newline ctx;
+		print ctx "local %s = _hx_result" vname;
+		let last = ref false in
+		let else_block = ref false in
+		List.iter (fun (v,e) ->
+			if !last then () else
+			let t = (match follow v.v_type with
+			| TEnum (e,_) -> Some (TEnumDecl e)
+			| TInst (c,_) -> Some (TClassDecl c)
+			| TAbstract (a,_) -> Some (TAbstractDecl a)
+			| TFun _
+			| TLazy _
+			| TType _
+			| TAnon _ ->
+				assert false
+			| TMono _
+			| TDynamic _ ->
+				None
+			) in
+			match t with
+			| None ->
+				last := true;
+				if !else_block then print ctx "";
+				if vname <> v.v_name then begin
+					newline ctx;
+					print ctx "local %s = %s" v.v_name vname;
+				end;
+				gen_block_element ctx e;
+				if !else_block then begin
+					newline ctx;
+					print ctx " end ";
+				end
+			| Some t ->
+				if not !else_block then newline ctx;
+				print ctx "if( %s.__instanceof(%s," (ctx.type_accessor (TClassDecl { null_class with cl_path = ["lua"],"Boot" })) vname;
+				gen_value ctx (mk (TTypeExpr t) (mk_mono()) e.epos);
+				spr ctx ") ) then ";
+				let bend = open_block ctx in
+				if vname <> v.v_name then begin
+					newline ctx;
+					print ctx "local %s = %s" v.v_name vname;
+				end;
+				gen_block_element ctx e;
+				bend();
+				newline ctx;
+				spr ctx "else";
+				else_block := true
+		) catchs;
+		if not !last then begin
+		    println ctx " error(%s)" vname;
+		    spr ctx "end";
+		end;
+		bend();
+		newline ctx;
+		spr ctx " elseif _hx_result ~= _hx_expected_result then return _hx_result end";
+	| TSwitch (e,cases,def) ->
+		List.iteri (fun cnt (el,e2) ->
+		    if cnt == 0 then spr ctx "if " else spr ctx "elseif ";
+		    List.iteri (fun ccnt e3 ->
+			if ccnt > 0 then spr ctx " or ";
+			gen_value ctx e;
+			spr ctx " == ";
+			gen_value ctx e3;
+		    ) el;
+		    spr ctx " then ";
+		    let bend = open_block ctx in
+		    gen_block_element ctx e2;
+		    bend();
+		    newline ctx;
+		) cases;
+		(match def with
+		| None -> spr ctx "end"
+		| Some e ->
+			begin
+			if (List.length(cases) > 0) then
+			    spr ctx "else";
+			let bend = open_block ctx in
+			gen_block_element ctx e;
+			bend();
+			newline ctx;
+			if (List.length(cases) > 0) then
+			    spr ctx "end";
+			end;);
+	| TCast (e1,Some t) ->
+		print ctx "%s.__cast(" (ctx.type_accessor (TClassDecl { null_class with cl_path = ["lua"],"Boot" }));
+		gen_expr ctx e1;
+		spr ctx " , ";
+		spr ctx (ctx.type_accessor t);
+		spr ctx ")"
+	| TCast (e1,None) ->
+		gen_value ctx e1;
+end;
+
+and gen__init__hoist ctx e =
+    begin match e.eexpr with
+	| TVar (v,eo) ->(
+		print ctx ", %s" (ident v.v_name);
+	    )
+	| TBlock el ->
+		List.iter (gen__init__hoist ctx) el
+	| TCall (e, el) ->
+		(match e.eexpr , el with
+		    | TLocal { v_name = "__feature__" }, { eexpr = TConst (TString f) } :: eif :: eelse ->
+			    (if has_feature ctx f then
+				    gen__init__hoist ctx eif
+			    else match eelse with
+				    | [] -> ()
+				    | e :: _ -> gen__init__hoist ctx e)
+		    |_->());
+	| _ -> ()
+    end
+
+and gen__init__impl ctx e =
+    begin match e.eexpr with
+	| TVar (v,eo) ->
+		newline ctx;
+		gen_expr ~local:false ctx e
+	| TBlock el ->
+		List.iter (gen__init__impl ctx) el
+	| TCall (e, el) ->
+		(match e.eexpr , el with
+		    | TLocal { v_name = "__feature__" }, { eexpr = TConst (TString f) } :: eif :: eelse ->
+			    (if has_feature ctx f then
+				    gen__init__impl ctx eif
+			    else match eelse with
+				    | [] -> ()
+				    | e :: _ -> gen__init__impl ctx e)
+		    |_->
+			begin
+			    newline ctx;
+			    gen_call ctx e el false
+			end;
+			    );
+	| _ -> gen_block_element ctx e;
+    end
+
+and gen_block_element ?(after=false) ctx e  =
+    newline ctx;
+    ctx.iife_assign <- false;
+    begin match e.eexpr with
+	| TTypeExpr _ -> ()
+	| TCast (ce,_) -> gen_block_element ctx ce
+	| TParenthesis pe -> gen_block_element ctx pe
+	| TArrayDecl el -> concat ctx " " (gen_block_element ctx) el;
+	| TBinop (op,e1,e2) when op <> Ast.OpAssign ->
+		let f () = gen_tbinop ctx op e1 e2 in
+		gen_iife_assign ctx f;
+		semicolon ctx;
+	| TUnop ((Increment|Decrement) as op,_,e) ->
+		newline ctx;
+		gen_expr ctx e;
+		print ctx " = ";
+		gen_expr ctx e;
+		(match op with
+			| Increment -> print ctx " + 1;"
+			| _ -> print ctx " - 1;"
+		)
+	| TArray (e1,e2) ->
+		gen_block_element ctx e1;
+		gen_block_element ctx e2;
+	| TSwitch (e,[],def) ->
+		(match def with
+		| None -> ()
+		| Some e -> gen_block_element ctx e)
+	| TField _ ->
+		let f () = gen_expr ctx e in
+		gen_iife_assign ctx f;
+		semicolon ctx;
+	| TConst _ | TLocal _ -> ()
+	| TBlock el ->
+		List.iter (gen_block_element ~after ctx) el
+	| TCall ({ eexpr = TLocal { v_name = "__feature__" } }, { eexpr = TConst (TString f) } :: eif :: eelse) ->
+		if has_feature ctx f then
+			gen_block_element ~after ctx eif
+		else (match eelse with
+			| [] -> ()
+			| [e] -> gen_block_element ~after ctx e
+			| _ -> assert false)
+	| TFunction _ -> ()
+	| TObjectDecl fl ->
+		List.iter (fun (_,e) -> gen_block_element ~after ctx e) fl
+	| TVar (v,eo) ->
+		gen_expr ctx e; (* these already generate semicolons*)
+	| TMeta (_,e) ->
+		gen_block_element ctx e
+	| _ ->
+		gen_expr ctx e;
+		semicolon ctx;
+		if after then newline ctx;
+    end;
+
+and gen_value ctx e =
+	let assign e =
+		mk (TBinop (Ast.OpAssign,
+			mk (TLocal (match ctx.in_value with None -> assert false | Some v -> v)) t_dynamic e.epos,
+			e
+		)) e.etype e.epos
+	in
+	let value() =
+		let old = ctx.in_value, ctx.in_loop in
+		let r_id = temp ctx in
+		let r = alloc_var r_id t_dynamic in
+		ctx.in_value <- Some r;
+		ctx.in_loop <- false;
+		spr ctx "(function() ";
+		let b = open_block ctx in
+		newline ctx;
+		sprln ctx ("local " ^ r_id);
+		(fun() ->
+			newline ctx;
+			spr ctx ("return " ^ r_id);
+			b();
+			newline ctx;
+			ctx.in_value <- fst old;
+			ctx.in_loop <- snd old;
+			spr ctx "end )()"
+		)
+	in
+	match e.eexpr with
+	| TBinop (OpAssign, e1, e2) ->
+		spr ctx "(function() ";
+		gen_block_element ctx e;
+		spr ctx " return ";
+		gen_value ctx e1;
+		spr ctx " end)()";
+	| TConst _
+	| TLocal _
+	| TArray _
+	| TBinop _
+	| TField _
+	| TEnumParameter _
+	| TTypeExpr _
+	| TParenthesis _
+	| TObjectDecl _
+	| TArrayDecl _
+	| TNew _
+	| TUnop _
+	| TFunction _ ->
+		gen_expr ctx e
+	| TMeta (_,e1) ->
+		gen_value ctx e1
+	| TCall (e,el) ->
+		gen_call ctx e el true
+	| TReturn _
+	| TBreak
+	| TContinue ->
+		unsupported e.epos
+	(* TODO: this is just a hack because this specific case is a TestReflect unit test. I don't know how to address this properly
+	   at the moment. - Simon *)
+	| TCast ({ eexpr = TTypeExpr mt } as e1, None) when (match mt with TClassDecl {cl_path = ([],"Array")} -> false | _ -> true) ->
+	    spr ctx "_hx_staticToInstance(";
+	    gen_expr ctx e1;
+	    spr ctx ")";
+	| TCast (e1, Some t) ->
+		print ctx "%s.__cast(" (ctx.type_accessor (TClassDecl { null_class with cl_path = ["lua"],"Boot" }));
+		gen_value ctx e1;
+		spr ctx " , ";
+		spr ctx (ctx.type_accessor t);
+		spr ctx ")"
+	| TCast (e1, _) ->
+		gen_value ctx e1
+	| TVar _
+	| TFor _
+	| TWhile _
+	| TThrow _ ->
+		(* value is discarded anyway *)
+		let v = value() in
+		gen_expr ctx e;
+		v()
+	| TBlock [e] ->
+		gen_value ctx e
+	| TBlock el ->
+		let v = value() in
+		let rec loop = function
+			| [] ->
+				spr ctx "return nil";
+			| [e] ->
+				gen_block_element ctx (assign e);
+			| e :: l ->
+				gen_block_element ctx e;
+				newline ctx;
+				loop l
+		in
+		loop el;
+		v();
+	| TIf (cond,e,eo) ->
+		let v = value() in
+		spr ctx "if ";
+		gen_cond ctx cond;
+		spr ctx " then ";
+		gen_block_element ctx (assign e);
+		let rec gen_elseif ctx e =
+		(match e with
+		| None->();
+		| Some e2->
+		    (match e2.eexpr with
+		    | TIf(cond3, e3, eo3) ->
+			spr ctx " elseif ";
+			gen_cond ctx cond3;
+			spr ctx " then ";
+			gen_block_element ctx (assign e3);
+			gen_elseif ctx eo3;
+		    | _ ->
+			spr ctx " else ";
+			gen_expr ctx (assign e2);
+			semicolon ctx;
+		    ));
+		in
+		gen_elseif ctx eo;
+		spr ctx " end";
+		v()
+	| TSwitch (cond,cases,def) ->
+		let v = value() in
+		gen_expr ctx (mk (TSwitch (cond,
+			List.map (fun (e1,e2) -> (e1,assign e2)) cases,
+			match def with None -> None | Some e -> Some (assign e)
+		)) e.etype e.epos);
+		v()
+	| TTry (b,catchs) ->
+		let v = value() in
+		let block e = mk (TBlock [e]) e.etype e.epos in
+		gen_block_element ctx (mk (TTry (block (assign b),
+			List.map (fun (v,e) -> v, block (assign e)) catchs
+		)) e.etype e.epos);
+		v()
+
+and is_function_type ctx t =
+    match t.v_type with
+    | TFun _ -> true
+    | TMono r -> (match !r with | Some (TFun _) -> true | _ -> false)
+    | _ -> false;
+
+and gen_tbinop ctx op e1 e2 =
+    (match op, e1.eexpr, e2.eexpr with
+    | Ast.OpAssign, TField(e3, FInstance(_,_,_) ), TFunction f ->
+	    gen_expr ctx e1;
+	    spr ctx " = " ;
+	    print ctx "function(%s) " (String.concat "," ("self" :: List.map ident (List.map arg_name f.tf_args)));
+	    let fblock = fun_block ctx f e1.epos in
+	    (match fblock.eexpr with
+	    | TBlock el ->
+		    let rec loop ctx el = (match el with
+		    | [hd] -> (match hd.eexpr with
+			    | TReturn eo -> begin
+				    newline ctx;
+				    gen_return ctx e1 eo;
+				end;
+			    | _ -> gen_block_element ctx hd);
+		    | hd :: tl ->
+			    gen_block_element ctx hd;
+			    loop ctx tl
+		    |[] ->()
+		    ) in
+		    let bend = open_block ctx in
+		    loop ctx el;
+		    bend();
+		    newline ctx;
+	    | _ -> gen_value ctx e2);
+	    spr ctx " end"
+    | Ast.OpAssign, _, _ ->
+	    let iife_assign = ctx.iife_assign in
+	    if iife_assign then spr ctx "(function() ";
+	    (match e1.eexpr, e2.eexpr with
+	    | _, TBinop(OpAssign as op, e3, e4) ->
+		gen_tbinop ctx op e3 e4;
+		newline ctx;
+		gen_value ctx e1;
+		spr ctx " = ";
+		gen_value ctx e3;
+	    | TField(e3, FInstance _ ), TLocal t  when (is_function_type ctx t)   ->
+		gen_value ctx e1;
+		print ctx " %s " (Ast.s_binop op);
+		spr ctx "_hx_functionToInstanceFunction(";
+		gen_value ctx e2;
+		spr ctx ")";
+	    | _,_ ->
+		gen_value ctx e1;
+		print ctx " %s " (Ast.s_binop op);
+		gen_value ctx e2);
+	    if iife_assign then begin
+		spr ctx " return ";
+		gen_value ctx e1;
+		spr ctx " end)()";
+	    end;
+    | Ast.OpAssignOp(op2), TArray(e3,e4), _ ->
+	    (* TODO: Figure out how to rewrite this expression more cleanly *)
+	    sprln ctx "(function() ";
+	    let idx = alloc_var "idx" e4.etype in
+	    let idx_var =  mk (TVar( idx , Some(e4))) e4.etype e4.epos in
+	    gen_expr ctx idx_var;
+	    let arr = alloc_var "arr" e3.etype in
+	    let arr_var = mk (TVar(arr, Some(e3))) e3.etype e3.epos in
+	    gen_expr ctx arr_var;
+	    newline ctx;
+	    let arr_expr = (mk (TArray(
+	    	(mk ( TLocal(arr)) e3.etype e3.epos),
+	    	(mk ( TLocal(idx)) e4.etype e4.epos)
+	    	)) e3.etype e3.epos) in
+	    spr ctx "arr[idx] = ";
+	    gen_tbinop ctx op2 arr_expr e2; semicolon ctx; newline ctx;
+	    spr ctx "return arr[idx]";
+	    spr ctx " end)()";
+    | Ast.OpAssignOp(op2), TField(e3,e4), _ ->
+	    (* TODO: Figure out how to rewrite this expression more cleanly *)
+	    sprln ctx "(function() ";
+	    let obj = alloc_var "obj" e3.etype in
+	    spr ctx "local fld = ";
+	    (match e4 with
+	    | FInstance(_,_,fld)
+	    | FStatic(_,fld)
+	    | FAnon fld
+	    | FClosure(_,fld) ->
+		    print ctx "'%s'" fld.cf_name;
+	    | FDynamic name ->
+		    print ctx "'%s'" name;
+	    | FEnum(_,efld) ->
+		    print ctx "'%s'" efld.ef_name);
+	    semicolon ctx; newline ctx;
+	    let obj_var = mk (TVar(obj, Some(e3))) e3.etype e3.epos in
+	    gen_expr ctx obj_var;
+	    newline ctx;
+	    let obj_expr = (mk (TField(
+	    	(mk ( TLocal(obj)) e3.etype e3.epos),
+		e4
+	    	)) e3.etype e3.epos) in
+	    spr ctx "obj[fld] = ";
+	    gen_tbinop ctx op2 obj_expr e2; semicolon ctx; newline ctx;
+	    spr ctx "return obj[fld]";
+	    spr ctx " end)()";
+    | Ast.OpAssignOp(op2),_,_ ->
+	    (* TODO: Rewrite expression *)
+	    spr ctx "(function() "; gen_value ctx e1;
+	    spr ctx " = "; gen_tbinop ctx op2 e1 e2;
+	    spr ctx " return "; gen_value ctx e1;
+	    spr ctx " end)()";
+    | Ast.OpXor,_,_ | Ast.OpAnd,_,_  | Ast.OpShl,_,_ | Ast.OpShr,_,_ | Ast.OpUShr,_,_ | Ast.OpOr,_,_ ->
+	    gen_bitop ctx op e1 e2;
+    | Ast.OpMod,_,_ ->
+	    spr ctx "_G.math.fmod(";
+	    gen_expr ctx e1;
+	    spr ctx ", ";
+	    gen_expr ctx e2;
+	    spr ctx ")";
+    | Ast.OpAdd,_,_ when (is_string_expr e1 || is_string_expr e2) ->
+	    gen_value ctx e1;
+	    print ctx " .. ";
+	    gen_value ctx e2;
+    | _ -> begin
+	    spr ctx "(";
+	    gen_value ctx e1;
+	    spr ctx ")";
+	    (match op with
+		| Ast.OpNotEq -> print ctx " ~= ";
+		| Ast.OpBoolAnd -> print ctx " and ";
+		| Ast.OpBoolOr -> print ctx " or ";
+		| _ -> print ctx " %s " (Ast.s_binop op));
+	    spr ctx "(";
+	    gen_value ctx e2;
+	    spr ctx ")";
+	    end;
+    );
+
+and gen_wrap_tbinop ctx e=
+    match e.eexpr with
+    | TBinop _  ->
+	    spr ctx "(";
+	    gen_value ctx e;
+	    spr ctx ")";
+    | _ ->
+	    gen_value ctx e
+
+and gen_bitop ctx op e1 e2 =
+    print ctx "_hx_bit.%s(" (match op with
+	| Ast.OpXor  ->  "bxor"
+	| Ast.OpAnd  ->  "band"
+	| Ast.OpShl  ->  "lshift"
+	| Ast.OpShr  ->  "arshift"
+	| Ast.OpUShr ->  "rshift"
+	| Ast.OpOr   ->  "bor"
+	| _ -> "");
+    gen_value ctx e1;
+    spr ctx ",";
+    gen_value ctx e2;
+    spr ctx ")"
+
+and gen_return ctx e eo =
+    if ctx.in_value <> None then unsupported e.epos;
+    (match eo with
+    | None ->
+	    spr ctx "do return end"
+    | Some e ->
+	    (match e.eexpr with
+	    | TBinop(OpAssign, e1, e2) ->
+		gen_expr ctx e;
+		spr ctx " do return ";
+		gen_value ctx e1;
+		spr ctx " end";
+	    | _ ->
+		spr ctx "do return ";
+		gen_value ctx e;
+		spr ctx " end");
+	)
+
+and gen_iife_assign ctx f =
+    spr ctx "(function() return ";
+    f();
+    spr ctx " end)()";
+
+and gen_cond ctx cond =
+    ctx.iife_assign <- true;
+    gen_value ctx cond;
+    ctx.iife_assign <- false;
+
+and has_class ctx c =
+    has_feature ctx "lua.Boot.getClass" && (c.cl_super <> None || c.cl_ordered_fields <> [] || c.cl_constructor <> None)
+
+and has_prototype ctx c =
+    c.cl_super <> None || (has_class ctx c) || List.exists (can_gen_class_field ctx) c.cl_ordered_fields
+
+and can_gen_class_field ctx = function
+	| { cf_expr = (None | Some { eexpr = TConst TNull }) } when not (has_feature ctx "Type.getInstanceFields") ->
+		false
+	| f ->
+		not (is_extern_field f)
+
+and has_continue e =
+    let rec loop e = match e.eexpr with
+	| TContinue -> raise Exit
+	| TWhile(e1,_,_) | TFor(_,e1,_) -> loop e1 (* in theory there could be a continue there. Note that we don't want to recurse into the loop body because we do not care about inner continue expressions *)
+	| _ -> Type.iter loop e
+    in
+    try
+	loop e;
+	false;
+    with Exit ->
+	true
+
+let generate_package_create ctx (p,_) =
+	let rec loop acc = function
+		| [] -> ()
+		| p :: l when Hashtbl.mem ctx.packages (p :: acc) -> loop (p :: acc) l
+		| p :: l ->
+			Hashtbl.add ctx.packages (p :: acc) ();
+			(match acc with
+			| [] -> print ctx "local %s = {}" p
+			| _ ->
+				let p = String.concat "." (List.rev acc) ^ (field p) in
+				print ctx "%s = {}" p
+			);
+			ctx.separator <- true;
+			newline ctx;
+			loop (p :: acc) l
+	in
+	match p with
+	| [] -> print ctx "local "
+	| _ -> loop [] p
+
+let check_field_name c f =
+	match f.cf_name with
+	| "prototype" | "__proto__" | "constructor" ->
+		error ("The field name '" ^ f.cf_name ^ "'  is not allowed in Lua") (match f.cf_expr with None -> c.cl_pos | Some e -> e.epos);
+	| _ -> ()
+
+let gen_class_static_field ctx c f =
+	match f.cf_expr with
+	| None | Some { eexpr = TConst TNull } when not (has_feature ctx "Type.getClassFields") ->
+		()
+	| None when is_extern_field f ->
+		()
+	| None ->
+		println ctx "%s%s = nil" (s_path ctx c.cl_path) (field f.cf_name);
+	| Some e ->
+		match e.eexpr with
+		| TFunction _ ->
+			let path = (s_path ctx c.cl_path) ^ (field f.cf_name) in
+			ctx.id_counter <- 0;
+			print ctx "%s = " path;
+			gen_value ctx e;
+			newline ctx;
+		| _ ->
+			ctx.statics <- (c,f.cf_name,e) :: ctx.statics
+
+let gen_class_field ctx c f predelimit =
+	check_field_name c f;
+	if predelimit then sprln ctx ",";
+	match f.cf_expr with
+	| None ->
+		print ctx "'%s', nil" (anon_field f.cf_name);
+	| Some e ->
+		ctx.id_counter <- 0;
+		(match e.eexpr with
+		| TFunction f2 ->
+		    let old = ctx.in_value, ctx.in_loop in
+		    ctx.in_value <- None;
+		    ctx.in_loop <- false;
+		    print ctx "'%s', function" (anon_field f.cf_name);
+		    print ctx "(%s) " (String.concat "," ("self" :: List.map ident (List.map arg_name f2.tf_args)));
+		    let fblock = fun_block ctx f2 e.epos in
+		    (match fblock.eexpr with
+		    | TBlock el ->
+			let rec loop ctx el = (match el with
+			    | [hd] -> (match hd.eexpr with
+				    | TReturn eo -> begin
+					    newline ctx;
+					    gen_return ctx e eo;
+					end;
+				    | _ -> gen_block_element ctx hd);
+			    | hd :: tl ->
+				    gen_block_element ctx hd;
+				    loop ctx tl
+			    |[] ->()
+			    ) in
+			let bend = open_block ctx in
+			loop ctx el;
+			bend();
+			newline ctx;
+		    |_ -> ());
+		    spr ctx "end";
+		    ctx.in_value <- fst old;
+		    ctx.in_loop <- snd old;
+		    ctx.separator <- true;
+		| _ -> gen_value ctx e)
+
+let generate_class___name__ ctx c =
+	if has_feature ctx "lua.Boot.isClass" then begin
+		let p = s_path ctx c.cl_path in
+		print ctx "%s.__name__ = " p;
+		if has_feature ctx "Type.getClassName" then
+			println ctx "{%s}" (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst c.cl_path @ [snd c.cl_path])))
+		else
+			println ctx "true";
+	end
+
+let generate_class ctx c =
+	ctx.current <- c;
+	ctx.id_counter <- 0;
+	(match c.cl_path with
+	| [],"Function" -> error "This class redefines a native one" c.cl_pos
+	| _ -> ());
+	let p = s_path ctx c.cl_path in
+	let hxClasses = has_feature ctx "Type.resolveClass" in
+	newline ctx;
+	print ctx "%s.new = " p;
+	(match c.cl_kind with
+		| KAbstractImpl _ ->
+			(* abstract implementations only contain static members and don't need to have constructor functions *)
+			print ctx "{}"; ctx.separator <- true
+		| _ ->
+			(match c.cl_constructor with
+			| Some { cf_expr = Some e } ->
+				(match e.eexpr with
+				| TFunction f ->
+				    let old = ctx.in_value, ctx.in_loop in
+				    ctx.in_value <- None;
+				    ctx.in_loop <- false;
+				    print ctx "function(%s) " (String.concat "," (List.map ident (List.map arg_name f.tf_args)));
+				    let fblock = fun_block ctx f e.epos in
+				    (match fblock.eexpr with
+				    | TBlock el ->
+					let bend = open_block ctx in
+					newline ctx;
+					if not (has_prototype ctx c) then println ctx "local self = _hx_new()" else
+					println ctx "local self = _hx_new(%s.prototype)" p;
+					println ctx "%s.super(%s)" p (String.concat "," ("self" :: (List.map ident (List.map arg_name f.tf_args))));
+					if p = "String" then sprln ctx "self = string";
+					spr ctx "return self";
+					bend(); newline ctx;
+					spr ctx "end"; newline ctx; newline ctx;
+					let bend = open_block ctx in
+					print ctx "%s.super = function(%s) " p (String.concat "," ("self" :: (List.map ident (List.map arg_name f.tf_args))));
+					List.iter (gen_block_element ctx) el;
+					bend();
+					newline ctx;
+					spr ctx "end";
+				    |_ -> ());
+				    ctx.in_value <- fst old;
+				    ctx.in_loop <- snd old;
+				    ctx.separator <- true
+				| _ -> gen_expr ctx e);
+			| _ -> (print ctx "{}"); ctx.separator <- true)
+	);
+	newline ctx;
+	if hxClasses then println ctx "_hxClasses[\"%s\"] = %s" (dot_path c.cl_path) p;
+	generate_class___name__ ctx c;
+	(match c.cl_implements with
+	| [] -> ()
+	| l ->
+		println ctx "%s.__interfaces__ = {%s}" p (String.concat "," (List.map (fun (i,_) -> ctx.type_accessor (TClassDecl i)) l));
+	);
+
+	let gen_props props =
+		String.concat "," (List.map (fun (p,v) -> p ^"=\""^v^"\"") props) in
+	let has_property_reflection =
+		(has_feature ctx "Reflect.getProperty") || (has_feature ctx "Reflect.setProperty") in
+
+	if has_property_reflection then begin
+		(match Codegen.get_properties c.cl_ordered_statics with
+		| [] -> ()
+		| props -> println ctx "%s.__properties__ = {%s}" p (gen_props props);
+		);
+	end;
+
+	List.iter (gen_class_static_field ctx c) c.cl_ordered_statics;
+
+	newline ctx;
+	if (has_prototype ctx c) then begin
+		print ctx "%s.prototype = _hx_anon(" p;
+		let bend = open_block ctx in
+		newline ctx;
+		let count = ref 0 in
+
+		List.iter (fun f -> if can_gen_class_field ctx f then (gen_class_field ctx c f (!count > 0); incr count;) ) c.cl_ordered_fields;
+		if (has_class ctx c) then begin
+			newprop ctx;
+			if !count > 0 then spr ctx ",";
+			print ctx "'__class__',  %s" p;
+			incr count;
+		end;
+
+		if has_property_reflection then begin
+			let props = Codegen.get_properties c.cl_ordered_fields in
+			(match c.cl_super with
+			| _ when props = [] -> ()
+			| _ ->
+				if !count > 0 then spr ctx ",";
+				newprop ctx;
+				print ctx "'__properties__',  {%s}" (gen_props props));
+		end;
+
+		bend(); newline ctx;
+		println ctx ")";
+		(match c.cl_super with
+		| None -> ()
+		| Some (csup,_) ->
+			let psup = ctx.type_accessor (TClassDecl csup) in
+			println ctx "%s.__super__ = %s" p psup;
+			println ctx "setmetatable(%s.prototype,{__index=%s.prototype})" p psup;
+			(* Also use the __properties__  from the super class as the __index metatable *)
+			if has_property_reflection && Codegen.has_properties csup then
+			    println ctx "setmetatable(%s.prototype.__properties__,{__index=%s.prototype.__properties__})" p psup;
+		);
+	end
+
+let generate_enum ctx e =
+	let p = s_path ctx e.e_path in
+	let ename = List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst e.e_path @ [snd e.e_path]) in
+
+	(* TODO: Unify the _hxClasses declaration *)
+	if has_feature ctx "Type.resolveEnum" then begin
+	    newline ctx;
+	    print ctx "_hxClasses[\"%s\"] = %s" (dot_path e.e_path) p; semicolon ctx; newline ctx;
+	end;
+	if has_feature ctx "lua.Boot.isEnum" then begin
+	    newline ctx;
+	    print ctx "_hxClasses[\"%s\"] = {" (dot_path e.e_path);
+	    if has_feature ctx "lua.Boot.isEnum" then  begin
+		print ctx " __ename__ = %s," (if has_feature ctx "Type.getEnumName" then "{" ^ String.concat "," ename ^ "}" else "true");
+	    end;
+	    (* TODO :  Come up with a helper function for _hx_tabArray declarations *)
+	    spr ctx " __constructs__ = _hx_tabArray({";
+	    if ((List.length e.e_names) > 0) then begin
+		    spr ctx "[0]=";
+		    spr ctx (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" s) e.e_names));
+	    end;
+	    print ctx "},%i)}" (List.length e.e_names);
+	    ctx.separator <- true;
+	    newline ctx;
+	end;
+
+	if has_feature ctx "Type.resolveEnum" || has_feature ctx "lua.Boot.isEnum" then
+	    print ctx "%s = _hxClasses[\"%s\"];" p (dot_path e.e_path);
+
+	newline ctx;
+	List.iter (fun n ->
+		let f = PMap.find n e.e_constrs in
+		print ctx "%s%s = " p (field f.ef_name);
+		(match f.ef_type with
+		| TFun (args,_) ->
+			let count = List.length args in
+			let sargs = String.concat "," (List.map (fun (n,_,_) -> ident n) args) in
+			print ctx "function(%s) local _x = _hx_tabArray({[0]=\"%s\",%d,%s,__enum__=%s}, %i);" sargs f.ef_name f.ef_index sargs p (count + 2);
+			if has_feature ctx "may_print_enum" then
+				(* TODO: better namespacing for _estr *)
+				spr ctx " _x.toString = _estr;";
+			spr ctx " return _x; end ";
+			ctx.separator <- true;
+		| _ ->
+			println ctx "_hx_tabArray({[0]=\"%s\",%d},2)" f.ef_name f.ef_index;
+			if has_feature ctx "may_print_enum" then begin
+				println ctx "%s%s.toString = _estr" p (field f.ef_name);
+			end;
+			print ctx "%s%s.__enum__ = %s" p (field f.ef_name) p;
+		);
+		newline ctx
+	) e.e_names;
+	if has_feature ctx "Type.allEnums" then begin
+		let ctors_without_args = List.filter (fun s ->
+			let ef = PMap.find s e.e_constrs in
+			match follow ef.ef_type with
+				| TFun _ -> false
+				| _ -> true
+		) e.e_names in
+		print ctx "%s.__empty_constructs__ = " p;
+		spr ctx "_hx_tabArray({";
+		if (List.length ctors_without_args)  > 0 then
+		    begin
+			spr ctx "[0] = ";
+			print ctx "%s" (String.concat "," (List.map (fun s -> Printf.sprintf "%s.%s" p s) ctors_without_args));
+		    end;
+		println ctx "}, %i)"  (List.length ctors_without_args);
+	end
+
+let generate_static ctx (c,f,e) =
+	print ctx "%s%s = " (s_path ctx c.cl_path) (field f);
+	gen_value ctx e;
+	newline ctx
+
+let generate_enumMeta_fields ctx = function
+    | TEnumDecl e -> begin
+	    let p = s_path ctx e.e_path in
+	    match Codegen.build_metadata ctx.com (TEnumDecl e) with
+	| None -> ()
+	| Some e ->
+		print ctx "%s.__meta__ = " p;
+		gen_expr ctx e;
+		newline ctx
+	end
+    | _ -> ()
+
+let generate_require ctx path meta =
+	let _, args, mp = Meta.get Meta.LuaRequire meta in
+	let p = (s_path ctx path) in
+
+	generate_package_create ctx path;
+
+	(match args with
+	| [(EConst(String(module_name)),_)] ->
+		print ctx "%s = require(\"%s\")" p module_name
+	| [(EConst(String(module_name)),_) ; (EConst(String(object_path)),_)] ->
+		print ctx "%s = require(\"%s\").%s" p module_name object_path
+	| _ ->
+		error "Unsupported @:luaRequire format" mp);
+
+	newline ctx
+
+let generate_type ctx = function
+	| TClassDecl c ->
+		(match c.cl_init with
+		| None -> ()
+		| Some e ->
+			ctx.inits <- e :: ctx.inits);
+		(* Special case, want to add Math.__name__ only when required, handle here since Math is extern *)
+		let p = s_path ctx c.cl_path in
+		if p = "Math" then generate_class___name__ ctx c;
+		(* Another special case for Std because we do not want to generate it if it's empty. *)
+		if p = "Std" && c.cl_ordered_statics = [] then
+			()
+		else if not c.cl_extern then
+			generate_class ctx c
+		else if Meta.has Meta.LuaRequire c.cl_meta && is_directly_used ctx.com c.cl_meta then
+			generate_require ctx c.cl_path c.cl_meta
+		else if Meta.has Meta.InitPackage c.cl_meta then
+			(match c.cl_path with
+			| ([],_) -> ()
+			| _ -> generate_package_create ctx c.cl_path)
+	| TEnumDecl e when e.e_extern ->
+		if Meta.has Meta.LuaRequire e.e_meta && is_directly_used ctx.com e.e_meta then
+		    generate_require ctx e.e_path e.e_meta;
+	| TEnumDecl e -> generate_enum ctx e
+	| TTypeDecl _ | TAbstractDecl _ -> ()
+
+let generate_type_forward ctx = function
+	| TClassDecl c ->
+		(match c.cl_init with
+		| None -> ()
+		| Some e ->
+			ctx.inits <- e :: ctx.inits);
+		if not c.cl_extern then begin
+		    generate_package_create ctx c.cl_path;
+		    let p = s_path ctx c.cl_path in
+		    print ctx "%s = _hx_empty() " p;
+		end
+	| TEnumDecl e when e.e_extern ->
+		()
+	| TEnumDecl e ->
+		generate_package_create ctx e.e_path;
+		let p = s_path ctx e.e_path in
+		print ctx "%s = _hx_empty() " p;
+	| TTypeDecl _ | TAbstractDecl _ -> ()
+
+let set_current_class ctx c =
+	ctx.current <- c
+
+let alloc_ctx com =
+	let ctx = {
+		com = com;
+		buf = Buffer.create 16000;
+		packages = Hashtbl.create 0;
+		statics = [];
+		inits = [];
+		current = null_class;
+		tabs = "";
+		in_value = None;
+		iife_assign = false;
+		in_loop = false;
+		handle_break = false;
+		id_counter = 0;
+		type_accessor = (fun _ -> assert false);
+		separator = false;
+		found_expose = false;
+		lua_jit = Common.defined com Define.LuaJit;
+		lua_ver = try
+			float_of_string (PMap.find "lua_ver" com.defines)
+		    with | Not_found -> 5.2;
+	} in
+	ctx.type_accessor <- (fun t ->
+		let p = t_path t in
+		match t with
+		| TClassDecl ({ cl_extern = true } as c) when not (Meta.has Meta.LuaRequire c.cl_meta)
+			-> dot_path p
+		| TEnumDecl { e_extern = true }
+			-> dot_path p
+		| _ -> s_path ctx p);
+	ctx
+
+let gen_single_expr ctx e expr =
+	if expr then gen_expr ctx e else gen_value ctx e;
+	let str = Buffer.contents ctx.buf in
+	Buffer.reset ctx.buf;
+	ctx.id_counter <- 0;
+	str
+
+let generate com =
+	let t = Common.timer "generate lua" in
+	let ctx = alloc_ctx com in
+
+	if has_feature ctx "Class" || has_feature ctx "Type.getClassName" then add_feature ctx "lua.Boot.isClass";
+	if has_feature ctx "Enum" || has_feature ctx "Type.getEnumName" then add_feature ctx "lua.Boot.isEnum";
+
+	let include_files = List.rev com.include_files in
+
+	List.iter (fun file ->
+		match file with
+		| path, "top" ->
+			let file_content = Std.input_file ~bin:true (fst file) in
+			print ctx "%s\n" file_content;
+			()
+		| _ -> ()
+	) include_files;
+
+	sprln ctx "local _hxClasses = {}";
+	let vars = [] in
+	(* let vars = (if has_feature ctx "Type.resolveClass" || has_feature ctx "Type.resolveEnum" then ("_hxClasses = " ^ "{}") :: vars else vars) in *)
+	let vars = if has_feature ctx "may_print_enum"
+		then ("_estr = function(self) return " ^ (ctx.type_accessor (TClassDecl { null_class with cl_path = ["lua"],"Boot" })) ^ ".__string_rec(self,''); end") :: vars
+		else vars in
+	(match List.rev vars with
+	| [] -> ()
+	| vl ->
+		print ctx "local %s" (String.concat ";" vl);
+		ctx.separator <- true;
+		newline ctx
+	);
+
+	List.iter (generate_type_forward ctx) com.types; newline ctx;
+
+	spr ctx "local _hx_bind";
+	List.iter (gen__init__hoist ctx) (List.rev ctx.inits); newline ctx;
+	ctx.inits <- []; (* reset inits *)
+
+	List.iter (generate_type ctx) com.types;
+
+	let rec chk_features e =
+		if is_dynamic_iterator ctx e then add_feature ctx "use._iterator";
+		match e.eexpr with
+		| TField (_,FClosure _) ->
+			add_feature ctx "use._hx_bind"
+		| _ ->
+			Type.iter chk_features e
+	in
+	List.iter chk_features ctx.inits;
+	List.iter (fun (_,_,e) -> chk_features e) ctx.statics;
+	if has_feature ctx "use._iterator" then begin
+		add_feature ctx "use._hx_bind";
+		println ctx "function _hx_iterator(o) { if ( lua.Boot.__instanceof(o, Array) ) return function() { return HxOverrides.iter(o); }; return typeof(o.iterator) == 'function' ? _hx_bind(o,o.iterator) : o.iterator; }";
+	end;
+	if has_feature ctx "use._hx_bind" then println ctx "_hx_bind = lua.Boot.bind";
+
+	List.iter (gen__init__impl ctx) (List.rev ctx.inits);
+	List.iter (generate_enumMeta_fields ctx) com.types;
+	List.iter (generate_static ctx) (List.rev ctx.statics);
+
+	(match com.main with
+	| None -> ()
+	| Some e -> gen_expr ctx e; newline ctx);
+	let ch = open_out_bin com.file in
+	output_string ch (Buffer.contents ctx.buf);
+	close_out ch;
+	t()
+

+ 8 - 2
src/main.ml

@@ -165,7 +165,7 @@ let htmlescape s =
 	s
 
 let reserved_flags = [
-	"cross";"js";"neko";"flash";"php";"cpp";"cs";"java";"python";
+	"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python";
 	"as3";"swc";"macro";"sys"
 	]
 
@@ -988,7 +988,7 @@ and do_connect host port args =
 
 and init ctx =
 	let usage = Printf.sprintf
-		"Haxe Compiler %s - (C)2005-2016 Haxe Foundation\n Usage : haxe%s -main <class> [-swf|-js|-neko|-php|-cpp|-cppia|-as3|-cs|-java|-python|-hl] <output> [options]\n Options :"
+		"Haxe Compiler %s - (C)2005-2016 Haxe Foundation\n Usage : haxe%s -main <class> [-swf|-js|-neko|-php|-cpp|-cppia|-as3|-cs|-java|-python|-hl|-lua] <output> [options]\n Options :"
 		s_version (if Sys.os_type = "Win32" then ".exe" else "")
 	in
 	let com = ctx.com in
@@ -1060,6 +1060,7 @@ try
 			com.class_path <- normalize_path path :: com.class_path
 		),"<path> : add a directory to find source files");
 		("-js",Arg.String (set_platform Js),"<file> : compile code to JavaScript file");
+		("-lua",Arg.String (set_platform Lua),"<file> : compile code to Lua file");
 		("-swf",Arg.String (set_platform Flash),"<file> : compile code to Flash SWF file");
 		("-as3",Arg.String (fun dir ->
 			set_platform Flash dir;
@@ -1476,6 +1477,9 @@ try
 
 			add_std "js";
 			"js"
+		| Lua ->
+			add_std "lua";
+			"lua"
 		| Php ->
 			add_std "php";
 			"php"
@@ -1595,6 +1599,8 @@ try
 					Genneko.generate,"neko"
 				| Js ->
 					Genjs.generate,"js"
+				| Lua ->
+					Genlua.generate,"lua"
 				| Php ->
 					Genphp.generate,"php"
 				| Cpp ->

+ 9 - 1
src/optimization/analyzerTexpr.ml

@@ -97,6 +97,14 @@ let rec can_be_inlined e = match e.eexpr with
 	| TParenthesis e1 | TMeta(_,e1) -> can_be_inlined e1
 	| _ -> false
 
+let target_handles_unops com = match com.platform with
+	| Lua | Python -> false
+	| _ -> true
+
+let target_handles_assign_ops com = match com.platform with
+	| Lua -> false
+	| _ -> true
+
 let rec can_be_used_as_value com e =
 	let rec loop e = match e.eexpr with
 		| TBlock [e] -> loop e
@@ -104,7 +112,7 @@ let rec can_be_used_as_value com e =
 		| TCall({eexpr = TConst (TString "phi")},_) -> raise Exit
 		(* | TCall _ | TNew _ when (match com.platform with Cpp | Php -> true | _ -> false) -> raise Exit *)
 		| TReturn _ | TThrow _ | TBreak | TContinue -> raise Exit
-		| TUnop((Increment | Decrement),_,_) when com.platform = Python -> raise Exit
+		| TUnop((Increment | Decrement),_,_) when not (target_handles_unops com) -> raise Exit
 		| TNew _ when com.platform = Php -> raise Exit
 		| TFunction _ -> ()
 		| _ -> Type.iter loop e

+ 3 - 3
src/optimization/analyzerTexprTransformer.ml

@@ -666,7 +666,7 @@ and func ctx i =
 			let eo = Option.map loop eo in
 			let v' = get_var_origin ctx.graph v in
 			{e with eexpr = TVar(v',eo)}
-		| TBinop(OpAssign,e1,({eexpr = TBinop(op,e2,e3)} as e4)) ->
+		| TBinop(OpAssign,e1,({eexpr = TBinop(op,e2,e3)} as e4)) when target_handles_assign_ops ctx.com ->
 			let e1 = loop e1 in
 			let e2 = loop e2 in
 			let e3 = loop e3 in
@@ -681,8 +681,8 @@ and func ctx i =
 			begin match e1.eexpr,e2.eexpr with
 				| TLocal v1,TLocal v2 when v1 == v2 && is_valid_assign_op op ->
 					begin match op,e3.eexpr with
-						| OpAdd,TConst (TInt i32) when Int32.to_int i32 = 1 -> {e with eexpr = TUnop(Increment,Prefix,e1)}
-						| OpSub,TConst (TInt i32) when Int32.to_int i32 = 1 -> {e with eexpr = TUnop(Decrement,Prefix,e1)}
+						| OpAdd,TConst (TInt i32) when Int32.to_int i32 = 1 && target_handles_assign_ops ctx.com -> {e with eexpr = TUnop(Increment,Prefix,e1)}
+						| OpSub,TConst (TInt i32) when Int32.to_int i32 = 1 && target_handles_assign_ops ctx.com -> {e with eexpr = TUnop(Decrement,Prefix,e1)}
 						| _ -> {e with eexpr = TBinop(OpAssignOp op,e1,e3)}
 					end
 				| _ ->

+ 1 - 0
src/syntax/ast.ml

@@ -110,6 +110,7 @@ module Meta = struct
 		| KeepInit
 		| KeepSub
 		| LibType
+		| LuaRequire
 		| Meta
 		| Macro
 		| MaybeUsed

+ 14 - 0
src/typing/common.ml

@@ -47,6 +47,7 @@ type stats = {
 type platform =
 	| Cross
 	| Js
+	| Lua
 	| Neko
 	| Flash
 	| Php
@@ -199,6 +200,8 @@ module Define = struct
 		| JsUnflatten
 		| KeepOldOutput
 		| LoopUnrollMaxCost
+	        | LuaVer
+	        | LuaJit
 		| Macro
 		| MacroTimes
 		| NekoSource
@@ -287,6 +290,8 @@ module Define = struct
 		| JsUnflatten -> ("js_unflatten","Generate nested objects for packages and types")
 		| KeepOldOutput -> ("keep_old_output","Keep old source files in the output directory (for C#/Java)")
 		| LoopUnrollMaxCost -> ("loop_unroll_max_cost","Maximum cost (number of expressions * iterations) before loop unrolling is canceled (default 250)")
+		| LuaJit -> ("lua_jit","Enable the jit compiler for lua (version 5.2 only")
+		| LuaVer -> ("lua_ver","The lua version to target")
 		| Macro -> ("macro","Defined when code is compiled in the macro context")
 		| MacroTimes -> ("macro_times","Display per-macro timing when used with --times")
 		| NetVer -> ("net_ver", "<version:20-45> Sets the .NET version to be targeted")
@@ -433,6 +438,7 @@ module MetaInfo = struct
 		| JavaCanonical -> ":javaCanonical",("Used by the Java target to annotate the canonical path of the type",[HasParam "Output type package";HasParam "Output type name";UsedOnEither [TClass;TEnum]; Platform Java])
 		| JavaNative -> ":javaNative",("Automatically added by -java-lib on classes generated from JAR/class files",[Platform Java; UsedOnEither[TClass;TEnum]; Internal])
 		| JsRequire -> ":jsRequire",("Generate javascript module require expression for given extern",[Platform Js; UsedOn TClass])
+		| LuaRequire -> ":luaRequire",("Generate lua module require expression for given extern",[Platform Lua; UsedOn TClass])
 		| Keep -> ":keep",("Causes a field or type to be kept by DCE",[])
 		| KeepInit -> ":keepInit",("Causes a class to be kept by DCE even if all its field are removed",[UsedOn TClass])
 		| KeepSub -> ":keepSub",("Extends @:keep metadata to all implementing and extending classes",[UsedOn TClass])
@@ -568,6 +574,12 @@ let get_config com =
 			pf_capture_policy = CPLoopVars;
 			pf_reserved_type_paths = [([],"Object");([],"Error")];
 		}
+	| Lua ->
+		{
+			default_config with
+			pf_static = false;
+			pf_capture_policy = CPLoopVars;
+		}
 	| Neko ->
 		{
 			default_config with
@@ -735,6 +747,7 @@ let file_extension file =
 
 let platforms = [
 	Js;
+	Lua;
 	Neko;
 	Flash;
 	Php;
@@ -748,6 +761,7 @@ let platforms = [
 let platform_name = function
 	| Cross -> "cross"
 	| Js -> "js"
+	| Lua -> "lua"
 	| Neko -> "neko"
 	| Flash -> "flash"
 	| Php -> "php"

+ 19 - 4
std/StringTools.hx

@@ -34,7 +34,7 @@ class StringTools {
 	/**
 		Encode an URL by using the standard format.
 	**/
-	#if (!java && !cpp) inline #end public static function urlEncode( s : String ) : String {
+	#if (!java && !cpp && !lua) inline #end public static function urlEncode( s : String ) : String {
 		#if flash
 			return untyped __global__["encodeURIComponent"](s);
 		#elseif neko
@@ -55,6 +55,13 @@ class StringTools {
 			var len = 0;
 			var b = @:privateAccess s.bytes.urlEncode(len);
 			return @:privateAccess String.__alloc__(b,len);
+		#elseif lua
+			s = lua.NativeStringTools.gsub(s, "\n", "\r\n");
+			s = lua.NativeStringTools.gsub(s, "([^%w %-%_%.%~])", function (c) {
+				return lua.NativeStringTools.format("%%%02X", lua.NativeStringTools.byte(c) + '');
+			});
+			s = lua.NativeStringTools.gsub(s, " ", "+");
+			return s;
 		#else
 			return null;
 		#end
@@ -63,7 +70,7 @@ class StringTools {
 	/**
 		Decode an URL using the standard format.
 	**/
-	#if (!java && !cpp) inline #end public static function urlDecode( s : String ) : String {
+	#if (!java && !cpp && !lua) inline #end public static function urlDecode( s : String ) : String {
 		#if flash
 			return untyped __global__["decodeURIComponent"](s.split("+").join(" "));
 		#elseif neko
@@ -84,6 +91,12 @@ class StringTools {
 			var len = 0;
 			var b = @:privateAccess s.bytes.urlDecode(len);
 			return @:privateAccess String.__alloc__(b,len);
+		#elseif lua
+			s = lua.NativeStringTools.gsub (s, "+", " ");
+			s = lua.NativeStringTools.gsub (s, "%%(%x%x)",
+				function(h) {return lua.NativeStringTools.char(lua.Lua.tonumber(h,16));});
+			s = lua.NativeStringTools.gsub (s, "\r\n", "\n");
+			return s;
 		#else
 			return null;
 		#end
@@ -196,7 +209,7 @@ class StringTools {
 		`s`, the result is false.
 	**/
 	public static function isSpace( s : String, pos : Int ) : Bool {
-		#if python
+		#if (python || lua)
 		if (s.length == 0 || pos < 0 || pos >= s.length) return false;
 		#end
 		var c = s.charCodeAt( pos );
@@ -405,6 +418,8 @@ class StringTools {
 		return if (index >= s.length) -1 else python.internal.UBuiltins.ord(python.Syntax.arrayAccess(s, index));
 		#elseif hl
 		return @:privateAccess s.bytes.getUI16(index << 1);
+		#elseif lua
+		return lua.NativeStringTools.byte(s,index+1);
 		#else
 		return untyped s.cca(index);
 		#end
@@ -418,7 +433,7 @@ class StringTools {
 		return c == 0;
 		#elseif js
 		return c != c; // fast NaN
-		#elseif neko
+		#elseif (neko || lua)
 		return c == null;
 		#elseif cs
 		return c == -1;

+ 36 - 4
std/haxe/Int32.hx

@@ -67,7 +67,7 @@ abstract Int32(Int) from Int to Int {
 
 	@:op(A - B) public static function floatSub(a:Float, b:Int32):Float;
 
-	#if (as3 || js || php || python)
+	#if (as3 || js || php || python || lua)
 
 	@:op(A * B) private static function mul(a:Int32, b:Int32):Int32
 		return clamp( (a : Int) * ((b : Int) & 0xFFFF) + clamp( (a : Int) * ((b : Int) >>> 16) << 16 ) );
@@ -128,27 +128,55 @@ abstract Int32(Int) from Int to Int {
 	@:op(A >= B) private static function gteFloat(a:Int32, b:Float):Bool;
 	@:op(A >= B) private static function floatGte(a:Float, b:Int32):Bool;
 
+	#if lua
+	@:op(~A) private static inline function complement( a : Int32 ) : Int32
+		return lua.Boot.clamp(~a);
+	#else
 	@:op(~A) private function complement():Int32;
+	#end
 
 	@:op(A & B) private static function and(a:Int32, b:Int32):Int32;
 	@:op(A & B) @:commutative private static function andInt(a:Int32, b:Int):Int32;
 
+	#if lua
+	@:op(A | B) private static function or(a:Int32, b:Int32):Int32
+		return clamp((a:Int) | (b:Int));
+	@:op(A | B) @:commutative private static function orInt(a:Int32, b:Int):Int32
+		return clamp((a:Int) | b);
+	#else
 	@:op(A | B) private static function or(a:Int32, b:Int32):Int32;
 	@:op(A | B) @:commutative private static function orInt(a:Int32, b:Int):Int32;
+	#end
 
+	#if lua
+	@:op(A ^ B) private static function xor(a:Int32, b:Int32):Int32
+		return clamp((a:Int) ^ (b:Int));
+	@:op(A ^ B) @:commutative private static function xorInt(a:Int32, b:Int):Int32
+		return clamp((a:Int) ^ b);
+	#else
 	@:op(A ^ B) private static function xor(a:Int32, b:Int32):Int32;
 	@:op(A ^ B) @:commutative private static function xorInt(a:Int32, b:Int):Int32;
+	#end
 
 
+#if lua
+	@:op(A >> B) private static function shr(a:Int32, b:Int32):Int32
+		return clamp((a:Int) >> (b:Int));
+	@:op(A >> B) private static function shrInt(a:Int32, b:Int):Int32
+		return clamp((a:Int) >> b);
+	@:op(A >> B) private static function intShr(a:Int, b:Int32):Int32
+		return clamp(a >> (b:Int));
+#else
 	@:op(A >> B) private static function shr(a:Int32, b:Int32):Int32;
 	@:op(A >> B) private static function shrInt(a:Int32, b:Int):Int32;
 	@:op(A >> B) private static function intShr(a:Int, b:Int32):Int32;
+#end
 
 	@:op(A >>> B) private static function ushr(a:Int32, b:Int32):Int32;
 	@:op(A >>> B) private static function ushrInt(a:Int32, b:Int):Int32;
 	@:op(A >>> B) private static function intUshr(a:Int, b:Int32):Int32;
 
-	#if (php || python)
+	#if (php || python || lua)
 
 	// PHP may be 64-bit, so shifts must be clamped
 	@:op(A << B) private static inline function shl(a:Int32, b:Int32):Int32
@@ -158,7 +186,7 @@ abstract Int32(Int) from Int to Int {
 		return clamp( (a : Int) << b );
 
 	@:op(A << B) private static inline function intShl(a:Int, b:Int32):Int32
-		return clamp( a << (b : Int) );
+ 		return clamp( a << (b : Int) );
 
 	#else
 
@@ -168,6 +196,7 @@ abstract Int32(Int) from Int to Int {
 
 	#end
 
+
 	@:to private inline function toFloat():Float
 		return this;
 
@@ -184,7 +213,8 @@ abstract Int32(Int) from Int to Int {
 	static var extraBits : Int = untyped __php__("PHP_INT_SIZE") * 8 - 32;
 	#end
 
-	static inline function clamp( x : Int ) : Int {
+#if !lua inline #end
+	static function clamp( x : Int ) : Int {
 		// force to-int conversion on platforms that require it
 		#if (as3 || js)
 		return x | 0;
@@ -193,6 +223,8 @@ abstract Int32(Int) from Int to Int {
 		return (x << extraBits) >> extraBits;
 		#elseif python
 		return python.Syntax.pythonCode("{0} % {1}", (x + python.Syntax.opPow(2, 31)), python.Syntax.opPow(2, 32)) - python.Syntax.opPow(2, 31);
+		#elseif lua
+		return lua.Boot.clamp(x);
 		#else
 		return (x);
 		#end

+ 8 - 4
std/haxe/Int64.hx

@@ -52,7 +52,11 @@ abstract Int64(__Int64) from __Int64 to __Int64
 		`x` is sign-extended to fill 64 bits.
 	**/
 	@:from public static inline function ofInt( x : Int ) : Int64
+#if lua
+		return make( (x:Int32) >> 31, (x:Int32));
+#else
 		return make( x >> 31, x );
+#end
 
 	/**
 		Returns an Int with the value of the Int64 `x`.
@@ -275,7 +279,7 @@ abstract Int64(__Int64) from __Int64 to __Int64
 	/**
 		Returns the product of `a` and `b`.
 	**/
-	@:op(A * B) public static inline function mul( a : Int64, b : Int64 ) : Int64 {
+	@:op(A * B) public static #if !lua inline #end function mul( a : Int64, b : Int64 ) : Int64 {
 		var mask = 0xFFFF;
 		var al = a.low & mask, ah = a.low >>> 16;
 		var bl = b.low & mask, bh = b.low >>> 16;
@@ -417,7 +421,7 @@ abstract Int64(__Int64) from __Int64 to __Int64
 	@:op(A >> B) public static inline function shr( a : Int64, b : Int) : Int64 {
 		b &= 63;
 		return if( b == 0 ) a.copy()
-			else if( b < 32 ) make( a.high >> b, (a.high << (32-b)) | (a.low >>> b) )
+			else if( b < 32 ) make( a.high >> b, (a.high << (32-b)) | (a.low >>> b) );
 			else make( a.high >> 31, a.high >> (b - 32) );
 	}
 
@@ -428,7 +432,7 @@ abstract Int64(__Int64) from __Int64 to __Int64
 	@:op(A >>> B) public static inline function ushr( a : Int64, b : Int ) : Int64 {
 		b &= 63;
 		return if( b == 0 ) a.copy()
-			else if( b < 32 ) make( a.high >>> b, (a.high << (32-b)) | (a.low >>> b) )
+			else if( b < 32 ) make( a.high >>> b, (a.high << (32-b)) | (a.low >>> b) );
 			else make( 0, a.high >>> (b - 32) );
 	}
 
@@ -450,7 +454,7 @@ private typedef __Int64 = ___Int64;
 
 private class ___Int64 {
 	public var high : Int32;
-	public var low : Int32;
+	public var low : Int32; 
 
 	public inline function new( high, low ) {
 		this.high = high;

+ 3 - 1
std/haxe/Log.hx

@@ -78,7 +78,7 @@ class Log {
 			}
 			else
 				untyped __trace(v,infos);
-		#elseif (cs || java)
+		#elseif (cs || java || lua)
 			var str:String = null;
 			if (infos != null) {
 				str = infos.fileName + ":" + infos.lineNumber + ": " + v;
@@ -93,6 +93,8 @@ class Log {
 			cs.system.Console.WriteLine(str);
 			#elseif java
 			untyped __java__("java.lang.System.out.println(str)");
+			#elseif lua
+			untyped __lua__("_hx_print({0})", lua.Boot.__string_rec(str));
 			#end
 		#elseif (python)
 			var str:String = null;

+ 1 - 1
std/haxe/Serializer.hx

@@ -262,7 +262,7 @@ class Serializer {
 				#if (flash || python || hl)
 				var v : Array<Dynamic> = v;
 				#end
-				var l = #if (neko || flash || php || cs || java || python || hl) v.length #elseif cpp v.__length() #else __getField(v, "length") #end;
+				var l = #if (neko || flash || php || cs || java || python || hl || lua) v.length #elseif cpp v.__length() #else __getField(v, "length") #end;
 				for( i in 0...l ) {
 					if( v[i] == null )
 						ucount++;

+ 1 - 0
std/haxe/Unserializer.hx

@@ -173,6 +173,7 @@ class Unserializer {
 		var p1 = pos;
  		while( true ) {
  			var c = get(pos);
+			if( StringTools.isEof(c)) break;
  			// + - . , 0-9
  			if( (c >= 43 && c < 58) || c == "e".code || c == "E".code )
  				pos++;

+ 1 - 1
std/haxe/format/JsonParser.hx

@@ -158,7 +158,7 @@ class JsonParser {
 				case 'u'.code:
 					var uc = Std.parseInt("0x" + str.substr(pos, 4));
 					pos += 4;
-					#if (neko || php || cpp)
+					#if (neko || php || cpp || lua)
 					if( uc <= 0x7F )
 						buf.addChar(uc);
 					else if( uc <= 0x7FF ) {

+ 11 - 1
std/haxe/io/Bytes.hx

@@ -319,7 +319,10 @@ class Bytes {
 		return untyped $sget32(b, pos, false);
 		#elseif (php || python)
 		var v = get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos+3) << 24);
-        return if( v & 0x80000000 != 0 ) v | 0x80000000 else v;
+		return if( v & 0x80000000 != 0 ) v | 0x80000000 else v;
+		#elseif lua
+		var v = get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos+3) << 24);
+		return lua.Boot.clamp(if( v & 0x80000000 != 0 ) v | 0x80000000 else v);
 		#else
 		return get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos+3) << 24);
 		#end
@@ -377,6 +380,10 @@ class Bytes {
 		catch (e:Dynamic) throw e;
 		#elseif python
 		return python.Syntax.pythonCode("self.b[{0}:{0}+{1}].decode('UTF-8','replace')", pos, len);
+		#elseif lua
+		var begin = cast(Math.min(pos,b.length),Int);
+		var end = cast(Math.min(pos+len,b.length),Int);
+		return [for (i in begin...end) String.fromCharCode(b[i])].join("");
 		#else
 		var s = "";
 		var b = b;
@@ -509,6 +516,9 @@ class Bytes {
 			var b:BytesData = new python.Bytearray(s, "UTF-8");
 			return new Bytes(b.length, b);
 
+		#elseif lua
+			var bytes = [for (c in 0...s.length) StringTools.fastCodeAt(s,c)];
+			return new Bytes(bytes.length, bytes);
 		#else
 		var a = new Array();
 		// utf16-decode and utf8-encode

+ 10 - 5
std/haxe/io/Input.hx

@@ -278,11 +278,16 @@ class Input {
 		var ch3 = readByte();
 		var ch4 = readByte();
 #if (php || python)
-        // php will overflow integers.  Convert them back to signed 32-bit ints.
-        var n = bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
-        if (n & 0x80000000 != 0)
-            return ( n | 0x80000000);
-        else return n;
+		// php will overflow integers.  Convert them back to signed 32-bit ints.
+		var n = bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
+		if (n & 0x80000000 != 0)
+		    return ( n | 0x80000000);
+		else return n;
+#elseif lua
+		var n = bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
+		// lua can't do 32 bit ints, the adjustment for 64 bits must be numeric
+		if (n > 2147483647) n -=  untyped 4294967296.;
+		return n ;
 #else
 		return bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
 #end

+ 1 - 1
std/haxe/macro/Compiler.hx

@@ -360,7 +360,7 @@ class Compiler {
 
 #end
 
-	#if (js || macro)
+	#if (js || lua || macro)
 	/**
 		Embed a JavaScript file at compile time (can be called by `--macro` or within an `__init__` method).
 	**/

+ 1 - 1
std/haxe/unit/TestRunner.hx

@@ -69,7 +69,7 @@ class TestRunner {
 			untyped __java__("java.lang.System.out.print(str)");
 		#elseif python
 			python.Lib.print(v);
-		#elseif hl
+		#elseif (hl || lua)
 			Sys.print(Std.string(v));
 		#end
 	}

+ 1 - 1
std/haxe/xml/Parser.hx

@@ -378,7 +378,7 @@ class Parser
 							var c = s.fastCodeAt(1) == 'x'.code
 								? Std.parseInt("0" +s.substr(1, s.length - 1))
 								: Std.parseInt(s.substr(1, s.length - 1));
-							#if (neko || cpp || php)
+							#if (neko || cpp || php || lua)
 							if( c >= 128 ) {
 								// UTF8-encode it
 								if( c <= 0x7FF ) {

+ 42 - 0
std/lua/Bit.hx

@@ -0,0 +1,42 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+
+package lua;
+/**
+  Externs for the "bit" class that is required for haxe lua
+**/
+
+@:native("_hx_bit")
+extern class Bit {
+	public static function bnot(x:Float) : Int;
+	public static function band(a:Float, b:Float) : Int;
+	public static function bor(a:Float, b:Float) : Int;
+	public static function bxor(a:Float, b:Float) : Int;
+	public static function lshift(x:Float, places:Int) : Int;
+	public static function rshift(x:Float, places:Int) : Int;
+	public static function arshift(x:Float, places:Int) : Int;
+	public static function mod(numerator:Float, denominator:Float) : Int;
+	public static function __init__() : Void {
+		//bit library fixes
+		haxe.macro.Compiler.includeFile("lua/_lua/_hx_bit.lua");
+	}
+}

+ 353 - 0
std/lua/Boot.hx

@@ -0,0 +1,353 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * 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.
+ */
+
+package lua;
+
+// Bit and Table must be imported for basic haxe datatypes to work.
+import lua.Bit;
+import lua.Table;
+import lua.Thread;
+import haxe.io.Path;
+
+import haxe.Constraints.Function;
+using lua.PairTools;
+
+class Boot {
+
+	// Used temporarily for bind()
+	static var _;
+	static var _fid = 0;
+
+	public static var platformBigEndian = NativeStringTools.byte(NativeStringTools.dump(function(){}),7) > 0;
+
+	public static var hiddenFields = [
+		"__id__", "hx__closures", "super",
+		"prototype", "__fields__", "__ifields__", "__class__", "__properties__"
+	];
+
+	static function __unhtml(s : String)
+		return s.split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;");
+
+	/*
+	   Binds a function definition to the given instance
+	*/
+	@:keep
+	public static function bind(o:Dynamic, m: Function) : Function{
+		if (m == null) return null;
+		// if (m.__id.__ == nil) m.__id__ = _fid + 1;
+		var f: Function = null;
+		if ( o.hx__closures__ == null ) o.hx__closures__ = {};
+		else untyped f = o.hx__closures__[m];
+		if (f == null){
+			f = untyped __lua__("function(...) return m(o, ...) end");
+			untyped o.hx__closures__[m] = f;
+		}
+		return f;
+	}
+
+	static inline public function isClass(o:Dynamic) : Bool {
+		if (Lua.type(o) != "table") return false;
+		else return untyped __define_feature__("lua.Boot.isClass", o.__name__);
+	}
+
+	static inline public function isEnum(e:Dynamic) : Bool {
+		if (Lua.type(e) != "table") return false;
+		else return untyped __define_feature__("lua.Boot.isEnum", e.__ename__);
+	}
+
+	/*
+	   Returns the class of a given object, and defines the getClass feature
+	   for the given class.
+	*/
+	static inline public function getClass(o:Dynamic) : Dynamic {
+		if (Std.is(o, Array)) return Array;
+		else {
+			var cl = untyped __define_feature__("lua.Boot.getClass", o.__class__);
+			if (cl != null) return cl;
+			else return null;
+		}
+	}
+
+	/*
+	   Indicates if the given object is an instance of the given Type
+	*/
+	@:ifFeature("typed_catch")
+	private static function __instanceof(o : Dynamic, cl : Dynamic) {
+		if( cl == null ) return false;
+
+		switch( cl ) {
+			case Int:
+				// TODO: matching js behavior here, but js behavior clamps.  Is that correct?
+				return (Lua.type(o) == "number" &&  clamp(o) == o);
+			case Float:
+				return Lua.type(o) == "number";
+			case Bool:
+				return Lua.type(o) == "boolean";
+			case String:
+				return Lua.type(o) == "string";
+			case Thread:
+				return Lua.type(o) == "thread";
+			case UserData:
+				return Lua.type(o) == "userdata";
+			case Array:
+				return Lua.type(o) == "table"
+					&& untyped o.__enum__ == null
+					&& lua.Lua.getmetatable(o) != null
+					&& lua.Lua.getmetatable(o).__index == untyped Array.prototype;
+			case Table:
+				return Lua.type(o) == "table";
+			case Dynamic:
+				return true;
+			default: {
+				if ( o!= null &&  Lua.type(o)  == "table" && Lua.type(cl) == "table"){
+					// first check if o is instance of cl
+					if (inheritsFrom(o, cl)) return true;
+
+					// do not use isClass/isEnum here, perform raw checks
+					untyped __feature__("Class.*",if( cl == Class && o.__name__ != null ) return true);
+					untyped __feature__("Enum.*",if( cl == Enum && o.__ename__ != null ) return true);
+					// last chance, is it an enum instance?
+					return o.__enum__ == cl;
+				} else {
+					return false;
+				}
+			}
+		}
+	}
+
+	/*
+	   Indicates if the given object inherits from the given class
+	*/
+	static function inheritsFrom(o:Dynamic, cl:Class<Dynamic>) : Bool {
+		while (Lua.getmetatable(o) != null && Lua.getmetatable(o).__index != null){
+			if (Lua.getmetatable(o).__index == untyped cl.prototype) return true;
+			o = Lua.getmetatable(o).__index;
+		}
+		return false;
+	}
+
+	@:ifFeature("typed_cast")
+	private static function __cast(o : Dynamic, t : Dynamic) {
+		if (__instanceof(o, t)) return o;
+		else throw "Cannot cast " +Std.string(o) + " to " +Std.string(t);
+	}
+
+	/*
+	   Helper method to generate a string representation of an enum
+	*/
+	static function printEnum(o:Array<Dynamic>, s : String){
+		if (o.length == 2){
+			return o[0];
+		} else {
+			// parameterized enums are arrays
+			var str = o[0] + "(";
+			s += "\t";
+			for (i in 2...o.length){
+				if( i != 2 )
+					str += "," + __string_rec(o[i],s);
+				else
+					str += __string_rec(o[i],s);
+			}
+			return str + ")";
+		}
+	}
+
+	/*
+	   Helper method to generate a string representation of a class
+	*/
+	static inline function printClass(c:Table<String,Dynamic>, s : String) : String {
+		return '{${printClassRec(c,'',s)}}';
+
+	}
+
+	/*
+	   Helper method to generate a string representation of a class
+	*/
+	static function printClassRec(c:Table<String,Dynamic>, result='', s : String) : String {
+		c.pairsEach(function(k,v){
+			if (result != "")
+				result += ", ";
+			result += '$k: ${__string_rec(v, s + "\t")}';
+		});
+		return result;
+	}
+
+	/*
+	   Generate a string representation for arbitrary object.
+	*/
+	@:ifFeature("has_enum")
+	static function __string_rec(o : Dynamic, s:String = "") {
+		return switch(untyped __type__(o)){
+			case "nil": "null";
+			case "number" : {
+				if (o == std.Math.POSITIVE_INFINITY) "Infinity";
+				else if (o == std.Math.NEGATIVE_INFINITY) "-Infinity";
+				else if (o != o) "NaN";
+				else untyped tostring(o);
+			}
+			case "boolean" : untyped tostring(o);
+			case "string"  : o;
+			case "userdata": "<userdata>";
+			case "function": "<function>";
+			case "thread"  : "<thread>";
+			case "table": {
+			    if (o.__enum__ != null) printEnum(o,s);
+				else if (o.toString != null && !__instanceof(o,Array)) o.toString();
+				else if (__instanceof(o, Array)) {
+					if (s.length > 5) "[...]"
+					else '[${[for (i in cast(o,Array<Dynamic>)) __string_rec(i,s+1)].join(",")}]';
+				} else if (s.length > 5){
+					"{...}";
+				}
+				else if (Reflect.hasField(o,"__tostring")) Lua.tostring(o);
+				else if (Reflect.hasField(o,"__class__")) printClass(o,s+"\t");
+				else if (Lua.next(o) == null) "{}";
+				else {
+					var fields = Reflect.fields(o);
+					var buffer = new StringBuf();
+					var first = true;
+					buffer.add("{ ");
+					for (f in fields){
+						if (first) first = false;
+						else buffer.add(", ");
+						buffer.add('${s}${Std.string(f)} : ${untyped Std.string(o[f])}');
+					}
+					buffer.add(" }");
+					buffer.toString();
+				}
+			};
+			default : {
+				throw "Unknown Lua type";
+				null;
+			}
+		}
+
+	}
+
+	/*
+	   Define an array from the given table
+	*/
+	public inline static function defArray<T>(tab: Table<Int,T>, ?length : Int) : Array<T> {
+		if (length == null) length = Table.maxn(tab);
+		return untyped _hx_tabArray(tab, length);
+	}
+
+	/*
+	   Create a Haxe object from the given table structure
+	*/
+	public inline static function tableToObject<T>(t:Table<String,T>) : Dynamic<T> {
+		return untyped _hx_o(t);
+	}
+
+	public static function dateStr( date : std.Date ) : String {
+		var m = date.getMonth() + 1;
+		var d = date.getDate();
+		var h = date.getHours();
+		var mi = date.getMinutes();
+		var s = date.getSeconds();
+		return date.getFullYear()
+			+"-"+(if( m < 10 ) "0"+m else ""+m)
+			+"-"+(if( d < 10 ) "0"+d else ""+d)
+			+" "+(if( h < 10 ) "0"+h else ""+h)
+			+":"+(if( mi < 10 ) "0"+mi else ""+mi)
+			+":"+(if( s < 10 ) "0"+s else ""+s);
+	}
+
+	/*
+	   A 32 bit clamp function for integers
+	*/
+	public inline static function clamp(x:Int){
+		return untyped _hx_bit_clamp(x);
+	}
+
+	/*
+	   Create a standard date object from a lua string representation
+	*/
+	public static function strDate( s : String ) : std.Date {
+		switch( s.length ) {
+		case 8: // hh:mm:ss
+			var k = s.split(":");
+			var t = lua.Os.time({
+				year  : 0,
+				month : 1,
+				day   : 1,
+				hour  : Std.parseInt(k[0]),
+				min   : Std.parseInt(k[1]),
+				sec   : Std.parseInt(k[2])
+			});
+			return std.Date.fromTime(t);
+		case 10: // YYYY-MM-DD
+			var k = s.split("-");
+			return new std.Date(Std.parseInt(k[0]), Std.parseInt(k[1]) - 1, Std.parseInt(k[2]),0,0,0);
+		case 19: // YYYY-MM-DD hh:mm:ss
+			var k = s.split(" ");
+			var y = k[0].split("-");
+			var t = k[1].split(":");
+			return new std.Date(cast y[0],Std.parseInt(y[1]) - 1, Std.parseInt(y[2]),Std.parseInt(t[0]),Std.parseInt(t[1]),Std.parseInt(t[2]));
+		default:
+			throw "Invalid date format : " + s;
+		}
+	}
+
+	/*
+	   create an empty table.
+	*/
+	public inline static function createTable<K,V>() : Table<K,V> {
+		return untyped __lua__("{}");
+	}
+
+	/*
+		Returns a shell escaped version of "cmd" along with any args
+	*/
+	public static function shellEscapeCmd(cmd : String, ?args : Array<String>){
+		if (args != null) {
+			switch (Sys.systemName()) {
+				case "Windows":
+					cmd = [
+						for (a in [StringTools.replace(cmd, "/", "\\")].concat(args))
+						StringTools.quoteWinArg(a, true)
+					].join(" ");
+				case _:
+					cmd = [cmd].concat(args).map(StringTools.quoteUnixArg).join(" ");
+			}
+		}
+		return cmd;
+	}
+
+	/*
+	   Returns a temp file path that can be used for reading and writing
+	*/
+	public static function tempFile() : String {
+		switch (Sys.systemName()){
+			case "Windows" : return Path.join([Os.getenv("TMP"), Os.tmpname()]);
+			default : return Os.tmpname();
+		}
+	}
+
+
+	public static function __init__(){
+		// anonymous to instance method wrapper
+		haxe.macro.Compiler.includeFile("lua/_lua/_hx_function_to_instance_function.lua");
+		// static to instance class wrapper
+		haxe.macro.Compiler.includeFile("lua/_lua/_hx_static_to_instance_function.lua");
+	}
+}

+ 46 - 0
std/lua/Coroutine.hx

@@ -0,0 +1,46 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+
+package lua;
+
+import haxe.Constraints.Function;
+import haxe.extern.Rest;
+
+/**
+  Externs for native Lua coroutines.
+ **/
+@:native("_G.coroutine")
+extern class Coroutine {
+	public static function create(f : Function)  : Thread;
+	public static function status(c : Coroutine) : ThreadState;
+	public static function resume(c : Coroutine, args : Rest<Dynamic>) : Dynamic;
+	public static function yield(args : Rest<Dynamic>) : Dynamic;
+	public static function wrap(f : Function) : Thread;
+}
+
+@:enum
+abstract ThreadState(String) {
+	var Suspended = "suspended";
+	var Running   = "running";
+	var Dead      = "dead";
+}
+

+ 66 - 0
std/lua/Debug.hx

@@ -0,0 +1,66 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+
+package lua;
+/**
+  Externs for the "debug" class for haxe lua  
+**/
+import haxe.Constraints.Function;
+
+import lua.Table.AnyTable;
+
+@:native("debug")
+extern class Debug {
+	public static function getlocal(stackLevel : Int, varName : String) : Dynamic;
+	public static function setlocal(stackLevel : Int, varName: String, value: Dynamic) : Void;
+	public static function getinfo(stackLevel  : Int) : DebugInfo;
+	public static function sethook(?fun : Function, ?monitor : String) : Void;
+	public static function debug() : Void;
+	public static function gethook(thread : Coroutine) : Function;
+	public static function getregistry() : AnyTable;
+	public static function getmetatable(value : AnyTable) : AnyTable;
+	public static function setmetatable(value : AnyTable, table : AnyTable) : Void;
+	public static function getupvalue(f : Function, up : Int) : Dynamic;
+	public static function setupvalue(f : Function, up : Int, val : Dynamic) : Void;
+	public static function getuservalue(val : Dynamic) : Dynamic;
+	public static function setuservalue(udata : Dynamic, val : Dynamic) : Void;
+	public static function traceback(?thread : Coroutine, ?message : String, ?level : Int) : Void;
+	public static function upvalueid(f : Function, n : Int) : Dynamic;
+	public static function upvaluejoin(f1 : Function, n1 : Int, f2 : Function, n2 : Int) : Void;
+}
+
+typedef DebugInfo = { 
+	currentline     : Int,
+	func            : Function,
+	istailcall      : Bool,
+	isvararg        : Bool,
+	lastlinedefined : Int,
+	linedefined     : Int,
+	name            : String,
+	namewhat        : String,
+	nparams         : Int,
+	nups            : Int,
+	short_src       : String,
+	source          : String,
+	what            : String
+}
+

+ 61 - 0
std/lua/Ffi.hx

@@ -0,0 +1,61 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+
+package lua;
+
+#if lua_jit
+@:native("_G.ffi")
+extern class Ffi {
+
+	// Declaring and accessing external symbols
+	public static var C : Dynamic;
+	public static function gc(cdata : Dynamic, finalizer : Function) : Void;
+	public static function load : (name : String, ?global : Bool) : Dynamic;
+	public static function metatype<T>(ct : Ctype<T>, metatable : Table<Dynamic>) : Ctype<T>;
+	public static function typeof(str:String) : Ctype<Dynamic>;
+
+	// C Type functionality 
+	public static function alignof(ct : Ctype<T>) : Int;
+	public static function istype(ct : Ctype<T>, obj:Dynamic) : Bool;
+	public static function offsetof(ct : Ctype<T>, field:String) : Int;
+	public static function sizeof(ct : Ctype<T>, ?nelem : Int) : Int;
+
+
+	// Utility functionality
+	public static function errno(?newerr : Int) : Int;
+	public static function fill(dst : Dynamic, len : Int, c:Int) : Void; 
+	public static function string(ptr : Dynamic, ?len : Int) : String;
+
+	@:overload(   function     (dst : Dynamic, str : String)             : Dynamic {})
+	public static function copy(dst : Dynamic, src : Dynamic, len : Int) : String;
+
+	// Target specific functionality
+	public static var os : String;
+	public static var arch : String;
+	public static function abi(param : String) : Bool; 
+}
+
+extern class Ctype<T> {}
+
+// TODO FFI callback type (gc methods)
+#end
+

+ 41 - 0
std/lua/FileHandle.hx

@@ -0,0 +1,41 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package lua;
+import haxe.extern.EitherType;
+import haxe.extern.Rest;
+import sys.io.FileInput;
+
+extern class FileHandle extends UserData {
+	public function flush() : Void;
+	public function read(arg : Rest<EitherType<ReadArgument,Int>>) : String;
+	public function close() : Void;
+	public function write(str : String) : Void;
+
+	@:overload(function () : Int {})
+	public function seek(arg : String, pos : Int) : Void;
+}
+
+@:enum
+abstract ReadArgument(String) {
+	var All = "*all";
+	var Line = "*line";
+}

+ 42 - 0
std/lua/HaxeIterator.hx

@@ -0,0 +1,42 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+
+package lua;
+
+/**
+  An implementation of the haxe iterator datastructure needed for identical 
+  lua iterator behavior. 
+ **/
+class HaxeIterator<T> {
+	var state : T;
+	var f : Void->T;
+	public function new(f:Void->T){
+		this.f = f;
+		this.state = f();
+	}
+	public function next(){
+		var ret = this.state;
+		this.state = this.f();
+		return ret;
+	}
+	public function hasNext() return this.state != null;
+}

+ 61 - 0
std/lua/Io.hx

@@ -0,0 +1,61 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package lua;
+import haxe.extern.Rest;
+
+@:native("_G.io")
+extern class Io {
+	public static var stdin  : FileHandle;
+	public static var stderr : FileHandle;
+	public static var stdout : FileHandle;
+
+	public static function close(?file : FileHandle) : Void;
+	public static function flush() : Void;
+
+	@:overload(   function      (file : String)     : Void {})
+	public static function input(file : FileHandle) : Void;
+
+	public static function lines(?file : String) : NativeIterator<String>;
+
+	public static function open (filename : String, ?mode : String) : FileHandle;
+	public static function popen(command  : String, ?mode : String) : FileHandle;
+
+	@:overload(   function     (?count    : Int)    : String {})
+	public static function read(?filename : String) : String;
+
+	public static function write(v : Rest<String>) : Void;
+
+	public static function output(?file : String) : FileHandle;
+
+	public static function tmpfile() : FileHandle;
+	public static function type(obj : FileHandle) : IoType;
+}
+
+@:enum
+abstract IoType(String) {
+	var File = "file";
+	var ClosedFile = "closed file";
+	var NotAFile = null;
+	@:to public function toString(){
+		return this;
+	}
+}

+ 21 - 0
std/lua/Jit.hx

@@ -0,0 +1,21 @@
+package lua;
+
+import haxe.Constraints.Function;
+
+#if lua_jit
+@:native("_G.jit")
+extern class Jit {
+	public static function on(?f:Function, ?recursive:Bool) : Void;
+	public static function off(?f:Function, ?recursive:Bool) : Void;
+	public static function flush(?f:Function, ?recursive:Bool) : Void;
+	public static function status() : Bool;
+	public static var version : String;
+	public static var version_num : Int;
+	public static var os : String;
+	public static var arch : String;
+	public static var opt : { start : Function };
+	public static var util : Dynamic;
+}
+#end
+
+

+ 66 - 0
std/lua/Lib.hx

@@ -0,0 +1,66 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package lua;
+import lua.Lua;
+import lua.Io;
+import lua.NativeStringTools;
+
+class Lib {
+
+	public static inline function println( v : Dynamic ) : Void {
+		Lua.print(Std.string(v));
+	}
+
+	public static inline function print(v:Dynamic) : Void {
+		Io.write(Std.string(v));
+		Io.flush();
+	}
+
+	public inline static function tableToArray<T>(t:Table<Int,T>, ?length:Int) : Array<T> {
+		return Boot.defArray(t, length);
+	}
+
+	public inline static function tableToObject<T>(t:Table<String,T>) : Dynamic<T> {
+		return Boot.tableToObject(t);
+	}
+
+	public inline static function patternQuote(str:String) : String {
+		return NativeStringTools.gsub(str, "[%(%)%.%%%+%-%*%?%[%]%^%$]", function(c:String){ return "%" + c; });
+	}
+
+	public inline static function defArray<T>(tab: Table<Int,T>, length : Int) : Array<T> {
+		return Boot.defArray(tab, length);
+	}
+
+	public static function fillArray<T>(itr:Void->T) : Array<T> {
+		var i: T = null;
+		var ret : Array<T> = [];
+		while({i = itr(); i != null;}){
+			ret.push(i);
+		}
+		return ret;
+	}
+	public inline static function isShellAvailable() : Bool {
+		return Os.execute();
+	}
+
+}

+ 10 - 0
std/lua/LocaleCategory.hx

@@ -0,0 +1,10 @@
+package lua;
+@:enum
+abstract LocaleCategory(String){
+	var All      = "all";
+	var Collate  = "collate";
+	var Ctype    = "ctype";
+	var Monetary = "monetary";
+	var Numeric  = "numeric";
+	var Time     = "time";
+}

+ 55 - 0
std/lua/Lua.hx

@@ -0,0 +1,55 @@
+package lua;
+import haxe.extern.Rest;
+import haxe.Constraints.Function;
+import haxe.extern.Rest;
+
+/**
+  These are all global static methods within lua
+ **/
+
+@:native("_G")
+extern class Lua {
+	public static var _VERSION : String;
+	public static var arg : Table<Int, String>;
+	public static function getmetatable(tbl:Table<Dynamic,Dynamic>): Table<Dynamic,Dynamic>;
+	public static function setmetatable(tbl:Table<Dynamic,Dynamic>, mtbl: Table<Dynamic, Dynamic>): Void;
+	public static function setfenv(i:Int , tbl:Table<Dynamic, Dynamic>): Void;
+	public static function next<T>(k:Table<Dynamic, T>, ?i : Null<Int>): T;
+	public static function tostring(v:Dynamic): String;
+	public static function ipairs<T>(t:Table<Int,T>): Void->T;
+	public static function pairs<A,B>(t:Table<A,B>): Void->A;
+	public static function tonumber(str:String, ?base:Int): Int;
+	public static function type(v:Dynamic) : String;
+	public static function print(v:Dynamic) : Void;
+	public static function select(n:Dynamic, rest:Rest<Dynamic>) : Dynamic;
+	public static function rawget<K,V>(t:Table<K,V>, k:K) : V;
+	public static function rawset<K,V>(t:Table<K,V>, k:K, v:V) : Void;
+	public static function collectgarbage(opt:CollectGarbageOption, ?arg:Int) : Int;
+	public static function assert<T>(v:T, ?message:String) : T;
+	public static function dofile(filename:String) : Void;
+	public static function error(message:String, ?level:Int) : Void;
+	public static function pcall(f:Function, rest:Rest<Dynamic>) : Bool;
+	public static function rawequal(v1:Dynamic, v2:Dynamic) : Bool;
+	public static function xpcall(f:Function, msgh:Function, rest:Rest<Dynamic> ) : Bool;
+	public static function loadfile(filename:String) : Void;
+	public static function loadstring(code:String) : Void;
+
+	private static function __init__() : Void {
+		// print polyfill
+		haxe.macro.Compiler.includeFile("lua/_lua/_hx_print.lua");
+	}
+}
+
+/**
+  Enum for describing garbage collection options
+  */
+@:enum
+abstract CollectGarbageOption(String) {
+	var Stop = "stop";
+	var Restart = "restart";
+	var Collect = "collect";
+	var Count = "count";
+	var Step = "step";
+	var SetPause = "setpause";
+	var SetStepMul = "setstepmul";
+}

+ 89 - 0
std/lua/Map.hx

@@ -0,0 +1,89 @@
+/*
+ * Copyright (C)2005-2015 Haxe Foundation
+ *
+ * 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.
+ */
+package lua;
+class Map<A,B> implements haxe.Constraints.IMap<A,B> {
+
+	private var h : Dynamic;
+	private var k : Dynamic;
+
+	public inline function new() : Void {
+		h = {};
+		k = {};
+	}
+
+	public inline function set( key : A, value : B ) : Void untyped {
+		 h[key] = value;
+		 k[key] = true;
+	}
+
+	public inline function get( key : A ) : Null<B> untyped {
+		return h[key];
+	}
+
+	public inline function exists( key : A ) : Bool untyped {
+		return k[key] != null;
+	}
+
+	public function remove( key : A ) : Bool untyped {
+		if ( k[key] == null) return false;
+		k[key] = null;
+		h[key] = null;
+		return true;
+	}
+
+	public function keys() : Iterator<A> untyped {
+		var cur = next(k,null);
+		return {
+			next : function() {
+				var ret = cur;
+				cur = untyped next(k, cur);
+				return ret;
+			},
+			hasNext : function() return cur != null
+		}
+	}
+
+	public function iterator() : Iterator<B> {
+		var itr = keys();
+		return untyped {
+			hasNext : itr.hasNext,
+			next : function() return h[itr.next()]
+		};
+	}
+
+	public function toString() : String {
+		var s = new StringBuf();
+		s.add("{");
+		var it = keys();
+		for( i in it ) {
+			s.add(i);
+			s.add(" => ");
+			s.add(Std.string(get(i)));
+			if( it.hasNext() )
+				s.add(", ");
+		}
+		s.add("}");
+		return s.toString();
+	}
+
+}
+

+ 46 - 0
std/lua/Math.hx

@@ -0,0 +1,46 @@
+package lua;
+
+@:native("_G.math")
+extern class Math {
+	public static var pi   : Float;
+	public static var huge : Float;
+	public static var NaN  : Float;
+
+	public static function abs  (i : Float) : Float;
+	public static function ceil (i : Float) : Int;
+	public static function floor(i : Float) : Int;
+
+	public static function acos (i : Float) : Float;
+	public static function asin (i : Float) : Float;
+	public static function atan (i : Float) : Float;
+	public static function atan2(i : Float, j : Float) : Float;
+	public static function cos  (i : Float) : Float;
+	public static function cosh (i : Float) : Float;
+	public static function sin  (i : Float) : Float;
+	public static function sinh (i : Float) : Float;
+	public static function tan  (i : Float) : Float;
+	public static function tanh (i : Float) : Float;
+	public static function rad  (i : Float) : Float;
+
+	public static function modf (i : Float) : Float;
+	public static function fmod (i : Float) : Float;
+
+	public static function pow  (i : Float, j : Float) : Float;
+	public static function sqrt (i : Float) : Float;
+	public static function exp  (i : Float) : Float;
+	public static function frexp(i : Float) : Float;
+	public static function ldexp(i : Float) : Float;
+
+	public static function log  (i : Float) : Float;
+	public static function log10(i : Float) : Float;
+
+	public static function max  (i : Float, j :Float) : Float;
+	public static function min  (i : Float, j :Float) : Float;
+
+	public static function random() : Float;
+	public static function randomseed(i : Float) : Float;
+
+	//  initialize the random seed with the current time
+	public static function __init__() : Void randomseed(Os.time());
+}
+

+ 47 - 0
std/lua/NativeIterator.hx

@@ -0,0 +1,47 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+
+package lua;
+
+/**
+	This abstract enables easy conversion from basic lua iterators
+	(i.e., a function that is called until it returns null), and 
+	Haxe iterators, which provide a next/hasNext interface.
+**/
+
+@:callable
+abstract NativeIterator<T>(Void->T) {
+	public function new(f : Void->T) {
+		this = f; 
+	}
+
+	@:from
+	public static function fromF<T>(f : Void->T){
+		return new NativeIterator(f);
+	}
+
+	@:to
+	public function toIterator() : Iterator<T> {
+		return new HaxeIterator(this);
+	}
+}
+

+ 31 - 0
std/lua/NativeStringTools.hx

@@ -0,0 +1,31 @@
+package lua;
+/**
+  These are all externs for the base Lua "string" class, which functions 
+  as an additional set of string tools.
+
+  Note that all relevant indexes are "1" based.
+ **/
+@:native("_G.string")
+extern class NativeStringTools {
+	public static function len(str : String): Int;
+	public static function char(codes: haxe.extern.Rest<Int>): String;
+	public static function sub(str : String, start : Int, ?end : Int): String;
+	public static function charCodeAt(str : String, index : Int): Int;
+	public static function find(str : String, target : String, ?start : Int, ?plain : Bool): Int;
+	public static function byte(str : String, ?index : Int) : Int;
+	public static function format(str : String, ?e1 : Dynamic, ?e2 : Dynamic, ?e3 : Dynamic, ?e4 : Dynamic): String;
+
+	@:overload(   function     (str : String, pattern : String, replace : String->Void,   ?n : Int): String {})
+	@:overload(   function     (str : String, pattern : String, replace : String->String, ?n : Int): String {})
+	public static function gsub(str : String, pattern : String, replace : String,		  ?n : Int): String;
+
+	@:overload(   function     (str : String, pattern : String, match : Void->String,   ?n : Int): String->Void {})
+	public static function gmatch(str : String, pattern : String): Void->String;
+
+	public static function match(str : String, pattern : String, ?n : Int): String;
+
+	public static function upper(str:String) : String;
+	public static function lower(str:String) : String;
+	public static function dump(d:Dynamic) : Dynamic;
+}
+

+ 51 - 0
std/lua/Os.hx

@@ -0,0 +1,51 @@
+package lua;
+
+@:native("_G.os")
+extern class Os {
+	public static function clock() : Float;
+
+	@:overload(   function     (format : String, time : Time) : DateType {})
+	@:overload(   function     (format : String) : DateType {})
+	public static function date() : DateType;
+
+	public static function difftime(t2: Time, t1: Time) : Float;
+
+	// TODO: multi-return
+	public static function execute(?command:String) : Bool;
+
+	public static function exit(code: Int) : Int;
+	public static function getenv(varname : String) : String;
+	public static function remove(filename : String) : Void;
+	public static function rename(oldname : String, newname : String) : Void;
+	public static function setlocale(locale : String, ?category : LocaleCategory ) : String;
+	public static function time(?arg : TimeParam) : Time;
+	public static function tmpname() : String;
+}
+
+/**
+  A typedef that matches the date parameter time() will accept.
+ **/
+typedef TimeParam = {
+	year   : Float,
+	month  : Float,
+	day    : Float,
+	?hour  : Int,
+	?min   : Int,
+	?sec   : Int,
+	?isdst : Bool
+}
+
+/**
+  A typedef that describes the output of date().
+ **/
+typedef DateType = {
+	hour  : Int,
+	min   : Int,
+	sec   : Int,
+	isdst : Bool,
+	year  : Int,
+	month : Int,
+	wday  : Int,
+	yday  : Int,
+	day   : Int,
+}

+ 38 - 0
std/lua/Package.hx

@@ -0,0 +1,38 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package lua;
+
+/**
+  Externs for lua package handling
+ **/
+@:native("_G.package")
+extern class Package {
+	public static var config : String;
+	public static var path : String;
+	public static var cpath : String;
+	public static var loaded : Table<String, Bool>;
+	public static var preload : Table<String, Bool>;
+	public static var searchers :Table<Int,Void->Null<String>>;
+
+	public static function searchpath(name : String, path : String, ?sep : String, ?rep : String) : Null<String>;
+	public static function loadlib(libname : String, funcname : String) : Void;
+}

+ 50 - 0
std/lua/PairTools.hx

@@ -0,0 +1,50 @@
+package lua;
+/**
+  A set of utility methods for working with the Lua table extern.
+ **/
+class PairTools {
+	public static function ipairsEach<T>(table:Table<Dynamic,T>, func : Int->T->Void) : Void {
+		untyped __lua__("for i,v in _G.ipairs(table) do func(i,v) end");
+	}
+	public static function pairsEach<A,B>(table:Table<A,B>, func : A->B->Void) : Void {
+		untyped __lua__("for k,v in _G.pairs(table) do func(k,v) end");
+	}
+	public static function ipairsMap<A,B>(table:Table<Dynamic,A>, func : Int->A->B) : Table<Int,B>  {
+		var ret : Table<Int,B> = cast {};
+		untyped __lua__( "for i,v in _G.ipairs(table) do ret[i] = func(i,v) end;");
+		return ret;
+	}
+	public static function pairsMap<A,B,C>(table:Table<A,B>, func : A->B->C->Void) : Table<A,C> {
+		var ret : Table<A,C> = cast {};
+		untyped __lua__( "for k,v in _G.pairs(table) do ret[k] = func(k,v) end;");
+		return ret;
+	}
+	public static function ipairsFold<A,B>(table:Table<Int,A>, func : Int->A->B->B, seed: B) : B  {
+		untyped __lua__("for i,v in _G.ipairs(table) do seed = func(i,v,seed) end");
+		return untyped __lua__("seed");
+	}
+	public static function pairsFold<A,B,C>(table:Table<A,B>, func : A->B->C->C, seed: C) : C {
+		untyped __lua__("for k,v in _G.pairs(table) do seed = func(k,v,seed) end");
+		return untyped __lua__("seed");
+	}
+
+	public static function ipairsConcat<T>(table1:Table<Int,T>, table2:Table<Int,T>){
+		var ret:Table<Int,T> = cast {};
+		ipairsFold(table1, function(a,b,c:Table<Int,T>){ c[a] = b; return c;}, ret);
+		var size = lua.Table.maxn(ret);
+		ipairsFold(table2, function(a,b,c:Table<Int,T>){ c[a + size] = b; return c;}, ret);
+		return ret;
+	}
+
+	public static function pairsMerge<A,B>(table1:Table<A,B>, table2:Table<A,B>){
+		var ret = copy(table1);
+		pairsEach(table2, function(a,b:B) ret[cast a] = b);
+		return ret;
+	}
+
+	public static function copy<A,B>(table1:Table<A,B>) : Table<A,B> {
+		var ret : Table<A,B> = cast {};
+		untyped __lua__("for k,v in _G.pairs(table1) do ret[k] = v end");
+		return ret;
+	}
+}

+ 33 - 0
std/lua/Table.hx

@@ -0,0 +1,33 @@
+package lua;
+
+@:native("_G.table") 
+extern class Table<A,B> implements ArrayAccess<B> implements Dynamic<B> {
+	@:overload(function<A,B>(table:Table<A,B>):Void{})
+	public static function concat<A,B>(table:Table<A,B>, ?sep:String) : String;
+
+	public static function foreach<A,B>(table:Table<A,B>, f:A->B->Void) : Void;
+	public static function foreachi<A,B>(table:Table<A,B>, f:A->B->Int->Void) : Void;
+
+	public static function sort<A,B>(table:Table<A,B>, ?order : A->A->Bool) : Void;
+
+	@:overload(function<B>(table:Table<Int,B>, value:B):Void{})
+	public static function insert<B>(table:Table<Int,B>, pos:Int, value:B) : Void;
+
+	@:overload(function<B>(table:Table<Int,B>):Void{})
+	public static function remove<B>(table:Table<Int,B>, ?pos:Int) : Void;
+
+	public static function maxn<B>(table: Table<Int,B>) : Int;
+	public static function pack<T>(args:T) : Table<Int,T>;
+	public static function unpack(arg:lua.Table<Dynamic,Dynamic>, ?min:Int, ?max:Int) : Dynamic;
+	private static function __init__() : Void {
+		// lua table polyfills
+		haxe.macro.Compiler.includeFile("lua/_lua/_hx_table_polyfill.lua");
+
+		// lua workarounds for basic anonymous object functionality
+		// (built on tables)
+		haxe.macro.Compiler.includeFile("lua/_lua/_hx_anon.lua");
+
+	}
+}
+
+typedef AnyTable = Table<Dynamic, Dynamic>;

+ 31 - 0
std/lua/Thread.hx

@@ -0,0 +1,31 @@
+
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+
+package lua;
+
+/**
+  The sole purpose of this extern is to provide a concrete type for 
+  basic reflection purposes.
+**/
+
+class Thread {}

+ 6 - 0
std/lua/Time.hx

@@ -0,0 +1,6 @@
+package lua;
+/*
+   Note: Lua timestamps are usually ints. Platform differences can produce 
+   Floats in certain cases.
+ */
+typedef Time = Float;

+ 2 - 0
std/lua/UserData.hx

@@ -0,0 +1,2 @@
+package lua;
+class UserData {}

+ 28 - 0
std/lua/_lua/_hx_anon.lua

@@ -0,0 +1,28 @@
+local function _hx_anon_newindex(t,k,v) t.__fields__[k] = true; rawset(t,k,v); end
+local _hx_anon_mt = {__newindex=_hx_anon_newindex}
+local function _hx_anon(...)
+  local __fields__ = {};
+  local ret = {__fields__ = __fields__};
+  local max = select('#',...);
+  local tab = {...};
+  local cur = 1;
+  while cur < max do
+    local v = tab[cur];
+    __fields__[v] = true;
+    ret[v] = tab[cur+1];
+    cur = cur + 2
+  end
+  return setmetatable(ret, _hx_anon_mt)
+end
+
+local function _hx_empty()
+  return setmetatable({__fields__ = {}}, _hx_anon_mt)
+end
+
+local function _hx_o(obj)
+  return setmetatable(obj, _hx_anon_mt)
+end
+
+local function _hx_new(prototype)
+  return setmetatable({__fields__ = {}}, {__newindex=_hx_anon_newindex, __index=prototype})
+end

+ 12 - 0
std/lua/_lua/_hx_bit.lua

@@ -0,0 +1,12 @@
+local _hx_bit
+pcall(require, 'bit32') pcall(require, 'bit')
+local _hx_bit_raw = bit or bit32
+
+local function _hx_bit_clamp(v) return _hx_bit_raw.band(v, 2147483647 ) - _hx_bit_raw.band(v, 2147483648) end
+
+if type(jit) == 'table' then
+  _hx_bit = setmetatable({},{__index = function(t,k) return function(...) return _hx_bit_clamp(rawget(_hx_bit_raw,k)(...)) end end})
+else
+  _hx_bit = setmetatable({}, { __index = _hx_bit_raw })
+  _hx_bit.bnot = function(...) return _hx_bit_clamp(_hx_bit_raw.bnot(...)) end
+end

+ 10 - 0
std/lua/_lua/_hx_function_to_instance_function.lua

@@ -0,0 +1,10 @@
+local function _hx_functionToInstanceFunction(f)
+  if type(f) == "function" then 
+    return function(self,...) 
+      return f(...) 
+    end
+  else 
+    return f
+  end
+end
+    

+ 1 - 0
std/lua/_lua/_hx_print.lua

@@ -0,0 +1 @@
+local _hx_print = print or (function()end)

+ 13 - 0
std/lua/_lua/_hx_static_to_instance_function.lua

@@ -0,0 +1,13 @@
+local function _hx_staticToInstance(tab)
+  return setmetatable({}, {
+    __index = function(t,k)
+      if type(rawget(tab,k)) == 'function' then 
+	return function(self,...)
+	  return rawget(tab,k)(...)
+	end
+      else
+	return rawget(tab,k)
+      end
+    end
+  })
+end

+ 13 - 0
std/lua/_lua/_hx_tab_array.lua

@@ -0,0 +1,13 @@
+local _hx_array_mt = {
+  __newindex = function(t,k,v)
+    if type(k) == 'number' and k >= t.length then
+      t.length = k + 1
+    end
+    rawset(t,k,v)
+  end
+}
+
+local function _hx_tabArray(tab,length)
+  tab.length = length
+  return setmetatable(tab, _hx_array_mt)
+end

+ 4 - 0
std/lua/_lua/_hx_table_polyfill.lua

@@ -0,0 +1,4 @@
+
+table.pack=table.pack or pack or function(...) return { n=select('#',...),...} end
+table.unpack=table.unpack or unpack or function(t, i) i = i or 1 if t[i] ~= nil then return t[i], table.unpack(t, i + 1) end end
+table.maxn=table.maxn or function(t) local maxn=0 for i in pairs(t) do maxn=type(i)=='number'and i>maxn and i or maxn end return maxn end

+ 199 - 0
std/lua/_std/Array.hx

@@ -0,0 +1,199 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * 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.
+ */
+@:coreApi
+class Array<T> {
+
+	public var length(default,null) : Int;
+
+	public function new() : Void  {
+		lua.Lib.defArray(cast this,0);
+	}
+	public function concat( a : Array<T> ) : Array<T> {
+		var ret = this.copy();
+		for (i in a) ret.push(i);
+		return ret;
+	}
+	public function join( sep : String ) : String {
+		var sb = new StringBuf();
+		var first = true;
+		for (i in iterator()){
+			if (first) first = false;
+			else sb.add(sep);
+			sb.add(Std.string(i));
+		}
+		return sb.toString();
+	}
+
+	public function pop() : Null<T> {
+		return this.length == 0 ? null : this[this.length-- -1];
+	}
+	public function push(x : T) : Int {
+		this[this.length++] = x;
+		return this.length;
+	}
+	public function reverse() : Void {
+		var tmp:T;
+		var i = 0;
+		while(i < Std.int(this.length/2)){
+			tmp = this[i];
+			this[i] = this[this.length-i-1];
+			this[this.length-i-1] = tmp;
+			i++;
+		}
+	}
+	public function shift() : Null<T> {
+		if (this.length == 0) return null;
+		var ret = this[0];
+		for (i in 0...length){
+			this[i] = this[i+1];
+		}
+		this.length-=1;
+		return ret;
+	}
+	public function slice( pos : Int, ?end : Int ) : Array<T> {
+		if (end == null || end > length) end = length;
+		else if (end < 0) end = (length-(-end % length)) % length; // negative pos needs to be wrapped from the end, and mod according to array length
+		if (pos < 0) pos = (length -(-pos % length)) % length;  // and here
+		if (pos > end || pos > length) return [];
+
+		var ret = [];
+		for (i in pos...end){
+			ret.push(this[i]);
+		}
+		return ret;
+	}
+	public function sort( f : T -> T -> Int ) : Void {
+		return haxe.ds.ArraySort.sort(this,f);
+	}
+	public function splice( pos : Int, len : Int ) : Array<T> {
+		if (len < 0 || pos > length) return [];
+		else if (pos < 0) pos = length -(-pos % length);
+		len = cast Math.min(len,this.length-pos);
+		var ret = [];
+		for (i in pos...(pos+len)){
+			ret.push(this[i]);
+			this[i] = this[i+len];
+		}
+		for (i in (pos+len)...length){
+			this[i] = this[i+len];
+		}
+		this.length-= len;
+		return ret;
+	}
+
+	public function toString() : String {
+		var sb = new StringBuf();
+		sb.add("[");
+		sb.add(join(","));
+		sb.add("]");
+		return sb.toString();
+	}
+
+	public function unshift( x : T ) : Void {
+		var len = length;
+		for (i in 0...len) this[len - i] = this[len - i - 1];
+		this[0] = x;
+	}
+
+	public inline function insert( pos : Int, x : T ) : Void {
+		if (pos > length) pos = length;
+		if (pos < 0) {
+			pos = (length + pos);
+			if (pos < 0) pos = 0;
+		}
+		var cur_len = length;
+		while (cur_len > pos){
+			this[cur_len] = this[cur_len-1];
+			cur_len -=1;
+		}
+		this[pos] = x;
+	}
+
+	public function remove( x : T ) : Bool {
+		for (i in 0...length){
+			if (this[i] == x){
+				for (j in i...length-1){
+					this[j] = this[j+1];
+				}
+				// We need to decrement the length variable, and set its 
+				// value to null to avoid hanging on to a reference in the 
+				// underlying lua table.  
+				this[length-1] = null;
+				// Do this in two steps to avoid re-updating the __index metamethod
+				length--;
+
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public function indexOf( x : T, ?fromIndex:Int ) : Int {
+		var end = length;
+		if (fromIndex == null) fromIndex = 0;
+		else if (fromIndex < 0 ) {
+			fromIndex = length + fromIndex;
+			if (fromIndex < 0) fromIndex = 0;
+		}
+		for (i in fromIndex...end){
+			if (x == this[i]) return i;
+		}
+		return -1;
+	}
+	public function lastIndexOf( x : T, ?fromIndex:Int ) : Int {
+		if (fromIndex == null || fromIndex >= length ) fromIndex = length-1;
+		else if (fromIndex < 0) {
+			fromIndex = length + fromIndex;
+			if (fromIndex < 0) return -1;
+		}
+		var i = fromIndex;
+		while(i >= 0){
+			if (this[i] == x) return i;
+			else i--;
+		}
+		return -1;
+	}
+	public inline function copy() : Array<T> {
+		return [for (i in this) i];
+	}
+	public function map<S>(f:T->S):Array<S> {
+		return [for (i in this) f(i)];
+	}
+	public function filter(f:T->Bool):Array<T> {
+		return [for (i in this) if (f(i)) i];
+	}
+	public inline function iterator() : Iterator<T> {
+		var cur_length = 0;
+		return {
+			hasNext : function() return cur_length < length,
+			next : function() return this[cur_length++]
+		}
+	}
+	private static function __init__() : Void{
+		// table-to-array helper
+		haxe.macro.Compiler.includeFile("lua/_lua/_hx_tab_array.lua");
+		// attach the prototype for Array to the metatable for 
+		// the tabToArray helper function
+		untyped __lua__("_hx_array_mt.__index = Array.prototype");
+	}
+
+}

+ 69 - 0
std/lua/_std/Date.hx

@@ -0,0 +1,69 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * 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.
+ */
+@:coreApi class Date {
+	var d : lua.Os.DateType;
+	var t : lua.Time;
+
+	public function new(year : Int, month : Int, day : Int, hour : Int, min : Int, sec : Int ) {
+		t =  lua.Os.time({
+			year  : year,
+			month : month+1,
+			day   : day,
+			hour  : hour,
+			min   : min,
+			sec   : sec
+		});
+		d =lua.Os.date("*t", t);
+	};
+	public function getTime()     : Float return cast t * 1000;
+	public function getHours()    : Int return d.hour;
+	public function getMinutes()  : Int return d.min;
+	public function getSeconds()  : Int return d.sec;
+	public function getFullYear() : Int return d.year;
+	public function getMonth()    : Int return d.month-1;
+	public function getDate()     : Int return d.day;
+	public function getDay()      : Int return d.wday-1;
+
+	@:keep
+	public inline function toString() : String {
+		return lua.Boot.dateStr(this);
+	}
+
+	public static inline function now() : Date {
+		return fromTime(lua.Os.time());
+	}
+
+	public static inline function fromTime( t : Float ) : Date {
+		var d : Dynamic = {}
+		untyped {
+			lua.Lua.setmetatable(d, untyped {__index : Date.prototype});
+			d.t = t/1000;
+			d.d = lua.Os.date("*t", d.t);
+		}
+		return d;
+	}
+
+	public static inline function fromString( s : String ) : Date {
+		return lua.Boot.strDate(s);
+	}
+}
+

+ 158 - 0
std/lua/_std/EReg.hx

@@ -0,0 +1,158 @@
+/*
+ * Copyright (C)2005-2015 Haxe Foundation
+ *
+ * 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.
+ */
+import lua.lib.lrexlib.Rex;
+import lua.Table;
+import lua.Lib;
+import lua.NativeStringTools;
+
+@:coreApi
+class EReg {
+
+	var r : Rex; // the Rex extern instance.
+	var global : Bool;  // whether the regex is in global mode.
+	var s : String; // the last matched string
+	var m : Table<Int,Int>; // the [start:Int, end:Int, and submatches:String (matched groups)] as a single table.
+
+	public function new( r : String, opt : String ) : Void {
+		var ropt = new StringBuf();
+		for (i in 0...opt.length){
+			switch(opt.charAt(i)){
+				case "i", "m", "s" : ropt.add(opt.charAt(i));
+				case "g" : global = true;
+				default : null;
+			}
+		}
+		if (global == null) global = false;
+		this.r = Rex.create(r, ropt.toString());
+	}
+
+	public function match( s : String ) : Bool {
+		this.m = Table.pack(r.exec(s));
+		this.s = s;
+		return  m[1] != null;
+	}
+
+	public function matched( n : Int ) : String {
+		if (m[1] == null || n < 0) throw "EReg::matched";
+		else if (n == 0) {
+			var k =  NativeStringTools.sub(s, m[1], m[2]);
+			return k;
+		} else if (Std.is(m[3], lua.Table)){
+			var mn = 2 * (n - 1);
+			if (Std.is(untyped m[3][mn+1], Bool)) return null;
+			return NativeStringTools.sub(s, untyped m[3][mn + 1], untyped m[3][mn + 2]);
+		} else {
+			throw "EReg:matched";
+		}
+	}
+
+	public function matchedLeft() : String {
+		if( m[1] == null ) throw "No string matched";
+		return NativeStringTools.sub(s, 1, m[1]-1);
+	}
+
+	public function matchedRight() : String {
+		if( m[1] == null ) throw "No string matched";
+		return NativeStringTools.sub(s, m[2]+1);
+	}
+
+	public function matchedPos() : { pos : Int, len : Int } {
+		if( m[1] == null ) throw "No string matched";
+		return {
+			pos : m[1]-1,
+			len : m[2]-m[1]+ 1
+		}
+	}
+
+	public function matchSub( s : String, pos : Int, len : Int = -1):Bool {
+
+		var ss = s.substr(0, len < 0 ? s.length : pos + len);
+
+		if (global){
+			m = Table.pack(r.exec(ss, pos + 1));
+			var b = m[1] != null;
+			if (b){
+				this.s = s;
+			}
+			return b;
+		} else {
+			m = Table.pack(r.exec(ss, pos + 1));
+			var b = m[1] != null;
+			if (b){
+				this.s = s;
+			}
+			return b;
+		}
+	}
+
+	public function split( s : String ) : Array<String> {
+		if (global){
+			return Lib.fillArray(Rex.split(s, r));
+		} else {
+			// we can't use directly Rex.split because it's ignoring the 'g' flag
+			var d = "#__delim__#";
+			return Lib.fillArray(Rex.split(replace(s,d), d));
+		}
+	}
+
+	public function replace( s : String, by : String ) : String {
+		by = Rex.gsub(by, "\\$(\\d)", "%%1"); // convert dollar sign matched groups to Rex equivalent
+		by = Rex.gsub(by, "\\${2}", "$"); // escape double dollar signs
+		return Rex.gsub(s,r,by, global ? null : 1);
+	}
+
+	public function map( s : String, f : EReg -> String ) : String {
+		var offset = 0;
+		var buf = new StringBuf();
+		do {
+			if (offset >= s.length){
+				break;
+			}
+			else if (!matchSub(s, offset)) {
+				buf.add(s.substr(offset));
+				break;
+			}
+			var p = matchedPos();
+
+			buf.add(s.substr(offset, p.pos - offset));
+			buf.add(f(this));
+			if (p.len == 0) {
+				buf.add(s.substr(p.pos, 1));
+				offset = p.pos + 1;
+			}
+			else
+				offset = p.pos + p.len;
+
+		} while (global);
+		if (!global && offset > 0 && offset < s.length)
+			buf.add(s.substr(offset));
+		return buf.toString();
+	}
+
+	static function __init__() : Void {
+		if (Rex == null){
+			throw "Rex is missing.  Please install lrexlib-pcre.";
+		}
+	}
+
+}
+

+ 80 - 0
std/lua/_std/Math.hx

@@ -0,0 +1,80 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * 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.
+ */
+package;
+
+class Math
+{
+	public static var PI(get,null) : Float;
+	static inline function get_PI () : Float return lua.Math.pi;
+
+	public static var NEGATIVE_INFINITY(get, null) : Float;
+	static inline function get_NEGATIVE_INFINITY () : Float return -lua.Math.huge;
+
+	public static var POSITIVE_INFINITY(get,null) : Float;
+	static inline function get_POSITIVE_INFINITY () : Float return lua.Math.huge;
+
+	public static var NaN(get, null) : Float;
+
+	// Note: this has to be an untyped literal, otherwise the compiler tries
+	// to unify it to an Int, which defeats useful numeric reflection behavior.
+	static inline function get_NaN () : Float return untyped __lua__("0/0");
+
+	public static function isNaN( f : Float ) : Bool return (f != f);
+	public static inline function isFinite( f : Float ) : Bool {
+		return (f > Math.NEGATIVE_INFINITY && f < Math.POSITIVE_INFINITY);
+	}
+
+	public static inline function abs(v:Float) :Float return lua.Math.abs(v);
+	public static inline function acos(v:Float):Float return lua.Math.acos(v);
+	public static inline function asin(v:Float):Float return lua.Math.asin(v);
+	public static inline function atan(v:Float):Float return lua.Math.atan(v);
+	public static inline function ceil(v:Float):Int   return lua.Math.ceil(v);
+	public static inline function cos(v:Float):Float  return lua.Math.cos(v);
+	public static inline function exp(v:Float):Float  return lua.Math.exp(v);
+	public static inline function sin(v:Float):Float  return lua.Math.sin(v);
+	public static inline function sqrt(v:Float):Float return lua.Math.sqrt(v);
+	public static inline function tan(v:Float):Float  return lua.Math.tan(v);
+
+	public static inline function floor(v:Float):Int  return lua.Math.floor(v);
+	public static inline function log(v:Float):Float  return lua.Math.log(v);
+
+	public static inline function random() : Float    return lua.Math.random();
+
+	public static inline function atan2(y:Float, x:Float):Float return lua.Math.atan2(y,x);
+	public static inline function max(a:Float, b:Float):Float {
+		return Math.isNaN(a) || Math.isNaN(b) ? Math.NaN : lua.Math.max(a,b);
+	}
+	public static inline function min(a:Float, b:Float):Float {
+		return Math.isNaN(a) || Math.isNaN(b) ? Math.NaN : lua.Math.min(a,b);
+	}
+	public static inline function pow(v:Float, exp:Float):Float return lua.Math.pow(v,exp);
+
+	public static inline function round(v:Float):Int return Math.floor(v + 0.5);
+
+	public static inline function ffloor( v : Float ) : Float return floor(v);
+	public static inline function fceil( v : Float ) : Float return ceil(v);
+	public static inline function fround( v : Float ) : Float return round(v);
+
+	static function __init__() : Void {
+		untyped __feature__("Type.resolveClass", _hxClasses["Math"] = Math);
+	}
+}

+ 167 - 0
std/lua/_std/Reflect.hx

@@ -0,0 +1,167 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * 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.
+ */
+import lua.Lua;
+import lua.Boot;
+@:coreApi class Reflect {
+
+	public inline static function hasField( o : Dynamic, field : String ) : Bool {
+		// TODO: Lua can't detect fields that are set to null, figure out a workaround.
+		return untyped o.__fields__ != null ? o.__fields__[field] != null :  o[field] != null;
+	}
+
+	public static function field( o : Dynamic, field : String ) : Dynamic untyped {
+		return try o[field] catch( e : Dynamic ) null;
+	}
+
+	public inline static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
+		o[field] = value;
+	}
+
+	public static inline function getProperty( o : Dynamic, field : String ) : Dynamic {
+		var tmp : Dynamic;
+		return if( o == null ) {
+				untyped __define_feature__("Reflect.getProperty",null);
+			} else if( o.__properties__ != null && Reflect.field(o, "get_" + field) != null){
+				callMethod(o, Reflect.field(o,"get_" + field), []);
+			} else {
+				Reflect.field(o,field);
+			}
+	}
+
+	public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
+		var tmp : String;
+		if( o.__properties__ && o.__properties__["set_"+field]) {
+			tmp = o.__properties__["set_" + field];
+			if (o.__name__ != null){
+				callMethod(null,Reflect.field(o, tmp), [value]) ;
+			} else {
+				callMethod(o,Reflect.field(o, tmp), [value]) ;
+			}
+		} else {
+			o[field] = __define_feature__("Reflect.setProperty",value);
+		}
+	}
+
+	public inline static function callMethod( o : Dynamic, func : haxe.Constraints.Function, args : Array<Dynamic> ) : Dynamic  {
+		if (args == null || args.length == 0){
+			return func(o);
+		} else {
+			var self_arg = false;
+			if (o != null && Type.getClass(o) != null){
+				// if o is not null, it means we need to pass it as the "self"
+				// parameter.  However, we should also check to see if it's
+				// a valid class instance in the first place.
+				// TODO: Find a more flexible way of determining if we need
+				// self or not
+				self_arg = true;
+			}
+			var new_args = lua.Boot.createTable();
+			for (i in 0...args.length){
+				// copy args to 1-indexed table
+				new_args[i + 1] = args[i];
+			}
+			return if (self_arg){
+				// call with o as leading self param
+				func(o, lua.Table.unpack(new_args, 1, lua.Table.maxn(new_args)));
+			} else {
+				// call with no self param
+				func(lua.Table.unpack(new_args, 1, lua.Table.maxn(new_args)));
+			}
+		}
+	}
+
+	public static function fields( o : Dynamic ) : Array<String> {
+		if (untyped o.__fields__ != null) {
+			return lua.PairTools.pairsFold(o.__fields__, function(a,b,c:Array<String>){
+				if (Boot.hiddenFields.indexOf(a) == -1) c.push(a);
+				return c;
+			}, []);
+		} else {
+			return lua.PairTools.pairsFold(o, function(a,b,c:Array<String>){
+			if (Boot.hiddenFields.indexOf(a) == -1) c.push(cast a);
+			return c;
+			}, []);
+		}
+	}
+
+	public static function isFunction( f : Dynamic ) : Bool {
+		return Lua.type(f) == "function" && !(Boot.isClass(f) || Boot.isEnum(f));
+	}
+
+	public static function compare<T>( a : T, b : T ) : Int {
+		if (a == b) return 0
+		else if (a == null) return -1
+		else if (b == null) return 1
+		else return (cast a) > (cast b) ? 1 : -1;
+	}
+
+	public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool {
+		return f1 == f2;
+	}
+
+	public static function isObject( v : Dynamic ) : Bool untyped {
+		if( v == null )
+			return false;
+		var t = __lua__("type(v)");
+		return (t == "string" || (t == "table" && v.__enum__ == null)) || (t == "function" && (lua.Boot.isClass(v) || lua.Boot.isEnum(v)) != null);
+	}
+
+	public static function isEnumValue( v : Dynamic ) : Bool {
+		return v != null && Std.is(v,lua.Table) && v.__enum__ != null;
+	}
+
+	public static function deleteField( o : Dynamic, field : String ) : Bool untyped {
+		if( !hasField(o,field) ) return false;
+		o[field] = null;
+		o.__fields__[field]=null;
+		return true;
+	}
+
+	public static function copy<T>( o : T ) : T {
+		var o2 : Dynamic = {};
+		for( f in Reflect.fields(o) )
+			Reflect.setField(o2,f,Reflect.field(o,f));
+		return o2;
+	}
+
+	@:overload(function( f : Array<Dynamic> -> Void ) : Dynamic {})
+	public static function makeVarArgs( f : Array<Dynamic> -> Dynamic ) : Dynamic {
+		/*
+			- Convert var arg to table
+			- Set indexing from zero
+			- Extract real table length
+			- Recreate as dynamic array
+			- Return function called with this array
+		*/
+		return untyped __lua__("function(...)
+			local a = {...}
+			local b = {}
+			local l = 0
+			for k, v in pairs(a) do
+				b[k-1] = v
+				l = math.max(k,l)
+			end
+			return f(_hx_tabArray(b, l))
+		end");
+	}
+
+}

+ 113 - 0
std/lua/_std/Std.hx

@@ -0,0 +1,113 @@
+/*
+ * Copyright (C)2005-2015 Haxe Foundation
+ *
+ * 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.
+ */
+import lua.Boot;
+import lua.NativeStringTools;
+
+@:keepInit
+@:coreApi class Std {
+
+	public static inline function is( v : Dynamic, t : Dynamic ) : Bool {
+		return untyped lua.Boot.__instanceof(v,t);
+	}
+
+	public static inline function instance<T:{},S:T>( value : T, c : Class<S> ) : S {
+		return untyped lua.Boot.__instanceof(value, c) ? cast value : null;
+	}
+
+	@:keep
+	public static function string( s : Dynamic ) : String {
+		return untyped lua.Boot.__string_rec(s);
+	}
+
+	public static inline function int( x : Float ) : Int {
+		return x > 0 ? Math.floor(x) : Math.ceil(x);
+	}
+
+	public static function parseInt( x : String ) : Null<Int> {
+		if (x == null) return null;
+		var hexMatch = NativeStringTools.match(x, "^ *[%-+]*0[xX][%da-FA-F]*");
+		if (hexMatch != null){
+			return lua.Lua.tonumber(hexMatch.substr(2), 16);
+		} else {
+			var intMatch = NativeStringTools.match(x, "^ *[%-+]?%d*");
+			if (intMatch != null){
+				return lua.Lua.tonumber(intMatch);
+			} else {
+				return null;
+			}
+		}
+	}
+
+	public static function parseFloat( x : String ) : Float {
+		if (x == null || x == "") return Math.NaN;
+		var digitMatch = NativeStringTools.match(x,  "^ *[%.%-+]?[0-9]%d*");
+		if (digitMatch == null){
+			return Math.NaN;
+		}
+		x = x.substr(digitMatch.length);
+
+		var decimalMatch = NativeStringTools.match(x, "^%.%d*");
+		if (decimalMatch == null) decimalMatch = "";
+		x = x.substr(decimalMatch.length);
+
+		var eMatch = NativeStringTools.match(x, "^[eE][+%-]?%d+");
+		if (eMatch == null) eMatch = "";
+		var result =  lua.Lua.tonumber(digitMatch + decimalMatch + eMatch);
+		return result != null ? result : Math.NaN;
+	}
+
+	public static function random( x : Int ) : Int {
+		return untyped x <= 0 ? 0 : Math.floor(Math.random()*x);
+	}
+
+	static function __init__() : Void untyped {
+		__feature__("lua.Boot.getClass", String.prototype.__class__ = __feature__("Type.resolveClass",_hxClasses["String"] = String,String));
+		__feature__("lua.Boot.isClass", String.__name__ = __feature__("Type.getClassName", __lua_table__("String"),true));
+		__feature__("Type.resolveClass",_hxClasses["Array"] = Array);
+		__feature__("lua.Boot.isClass",Array.__name__ = __feature__("Type.getClassName",__lua_table__("Array"),true));
+		__feature__("Int.*",{
+			var Int = __feature__("Type.resolveClass", _hxClasses["Int"] = { __name__ : __lua_table__("Int") }, { __name__ : __lua_table__("Int") });
+		});
+		__feature__("Dynamic.*",{
+			var Dynamic = __feature__("Type.resolveClass", _hxClasses["Dynamic"] = { __name__ : __lua_table__("Dynamic") }, { __name__ : __lua_table__("Dynamic") });
+		});
+		__feature__("Float.*",{
+			var Float = __feature__("Type.resolveClass", _hxClasses["Float"]={}, {});
+			Float.__name__ = __lua_table__("Float");
+		});
+		__feature__("Bool.*",{
+			var Bool = __feature__("Type.resolveEnum",_hxClasses["Bool"] = {}, {});
+			Bool.__ename__ = __lua_table__("Bool");
+		});
+		__feature__("Class.*",{
+			var Class = __feature__("Type.resolveClass", _hxClasses["Class"] = { __name__ : __lua_table__("Class") }, { __name__ : __lua_table__("Class") });
+		});
+		__feature__("Enum.*",{
+			var Enum = {};
+		});
+		__feature__("Void.*",{
+			var Void = __feature__("Type.resolveEnum", _hxClasses["Void"] = { __ename__ : ["Void"] }, { __ename__ : ["Void"] });
+		});
+
+	}
+
+}

+ 132 - 0
std/lua/_std/String.hx

@@ -0,0 +1,132 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * 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.
+ */
+
+import lua.Lua;
+import lua.Table;
+import lua.Boot;
+import lua.NativeStringTools;
+
+@:coreApi
+class String {
+	public var length(default,null) : Int;
+
+
+	public function new(string:String) untyped {}
+
+	static function __init__() : Void untyped{
+		__lua__("getmetatable('').__index = String.__index;");
+		__lua__("getmetatable('').__add = function(a,b) return Std.string(a)..Std.string(b) end;");
+		__lua__("getmetatable('').__concat = getmetatable('').__add");
+	}
+
+	@:keep
+	static function __index(s:Dynamic, k:Dynamic) : Dynamic {
+		if (k == "length") return untyped __lua__("#s");
+		else return untyped String.prototype[k];
+	}
+
+
+	public function toUpperCase() : String return NativeStringTools.upper(this);
+	public function toLowerCase() : String return NativeStringTools.lower(this);
+	public function indexOf( str : String, ?startIndex : Int ) : Int {
+		if (startIndex == null) startIndex = 1;
+		else startIndex += 1;
+		var r = NativeStringTools.find(this, str, startIndex, true);
+		if (r != null && r > 0) return r-1;
+		else return -1;
+	}
+
+	public function lastIndexOf( str : String, ?startIndex : Int ) : Int {
+		var i = 0;
+		var ret = -1;
+		if( startIndex == null ) startIndex = length;
+		while( true ) {
+			var p = indexOf(str, ret+1);
+			if( p == -1 || p > startIndex ) return ret;
+			ret = p;
+		}
+	}
+
+	public function split( delimiter : String ) : Array<String> {
+		var idx = 1;
+		var ret = [];
+		var delim_offset = delimiter.length > 0 ? delimiter.length : 1;
+		while (idx != null){
+			var newidx = 0;
+			if (delimiter.length > 0){
+				newidx = NativeStringTools.find(this, delimiter, idx, true);
+			} else if (idx >= this.length){
+				newidx = null;
+			} else {
+				newidx = idx + 1;
+			}
+
+			if (newidx != null){
+				var match = NativeStringTools.sub(this, idx, newidx-1);
+				ret.push(match);
+				idx = newidx + delimiter.length;
+			} else {
+				ret.push(NativeStringTools.sub(this,idx,NativeStringTools.len(this)));
+				idx = null;
+			}
+		}
+		return ret;
+	}
+
+	public function toString() : String {
+		return this;
+	}
+	public function substring( startIndex : Int, ?endIndex : Int ) : String {
+		if (endIndex == null) endIndex = this.length;
+		if (endIndex < 0) endIndex = 0;
+		if (startIndex < 0) startIndex = 0;
+		if (endIndex == 0) {
+			// swap the index positions
+			return NativeStringTools.sub(this, endIndex+1, startIndex);
+		} else {
+			return NativeStringTools.sub(this, startIndex+1, endIndex);
+		}
+	}
+
+	function get_length() : Int {
+		return NativeStringTools.len(this);
+	}
+	public function charAt( index : Int) : String {
+		return NativeStringTools.sub(this,index+1, index+1);
+	}
+	public function charCodeAt( index : Int) : Null<Int> {
+		return NativeStringTools.byte(this,index+1);
+	}
+
+	public function substr( pos : Int, ?len : Int ) : String {
+		if (len == null || len > pos + this.length) len = this.length;
+		else if (len < 0) len = length + len;
+		if (pos < 0) pos = length + pos;
+		if (pos < 0) pos = 0;
+		return NativeStringTools.sub(this, pos + 1, pos+len);
+	}
+
+	public inline static function fromCharCode( code : Int ) : String {
+		return NativeStringTools.char(code);
+	}
+}
+

+ 111 - 0
std/lua/_std/StringBuf.hx

@@ -0,0 +1,111 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * 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.
+ */
+/**
+	A String buffer is an efficient way to build a big string by appending small
+	elements together.
+
+	Its cross-platform implementation uses String concatenation internally, but
+	StringBuf may be optimized for different targets.
+
+	Unlike String, an instance of StringBuf is not immutable in the sense that
+	it can be passed as argument to functions which modify it by appending more
+	values. However, the internal buffer cannot be modified.
+**/
+import lua.Table;
+
+class StringBuf {
+
+	var b:Dynamic;
+
+	/*
+		The length of `this` StringBuf in characters.
+	**/
+	public var length(get,null) : Int;
+
+	/**
+		Creates a new StringBuf instance.
+
+		This may involve initialization of the internal buffer.
+	**/
+	public inline function new() {
+		b = {};
+		this.length = 0;
+	}
+
+	inline function get_length() : Int {
+		return length;
+	}
+
+	/**
+		Appends the representation of `x` to `this` StringBuf.
+
+		The exact representation of `x` may vary per platform. To get more
+		consistent behavior, this function should be called with
+		Std.string(x).
+
+		If `x` is null, the String "null" is appended.
+	**/
+	public inline function add<T>( x : T ) : Void {
+		var str = Std.string(x);
+		Table.insert(b, str);
+		length += str.length;
+	}
+
+	/**
+		Appends the character identified by `c` to `this` StringBuf.
+
+		If `c` is negative or has another invalid value, the result is
+		unspecified.
+	**/
+	public inline function addChar( c : Int ) : Void {
+		Table.insert(b, String.fromCharCode(c));
+		length += 1;
+	}
+
+	/**
+		Appends a substring of `s` to `this` StringBuf.
+
+		This function expects `pos` and `len` to describe a valid substring of
+		`s`, or else the result is unspecified. To get more robust behavior,
+		`this.add(s.substr(pos,len))` can be used instead.
+
+		If `s` or `pos` are null, the result is unspecified.
+
+		If `len` is omitted or null, the substring ranges from `pos` to the end
+		of `s`.
+	**/
+	public inline function addSub( s : String, pos : Int, ?len : Int) : Void {
+		var part = len == null ? s.substr(pos) : s.substr(pos, len);
+		Table.insert(b, part);
+		length += part.length;
+	}
+
+	/**
+		Returns the content of `this` StringBuf as String.
+
+		The buffer is not emptied by this operation.
+	**/
+	public inline function toString() : String {
+		return Table.concat(b);
+	}
+
+}

+ 134 - 0
std/lua/_std/Sys.hx

@@ -0,0 +1,134 @@
+
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+
+using lua.NativeStringTools;
+import lua.Package;
+import lua.Lua;
+import lua.Table;
+import lua.Os;
+import lua.lib.lfs.Lfs;
+import lua.FileHandle;
+import lua.Io;
+import lua.Boot;
+import sys.io.FileInput;
+import sys.io.FileOutput;
+
+@:coreApi
+class Sys {
+	public static inline function print( v : Dynamic ) : Void {
+		return lua.Lib.print(v);
+	}
+	public static inline function println( v : Dynamic ) : Void {
+		return lua.Lib.println(v);
+	}
+	public inline static function args() : Array<String> {
+		var args = lua.Lib.tableToArray(lua.Lua.arg).copy();
+		args.shift();
+		return args;
+	}
+	public static function command( cmd : String, ?args : Array<String> ) : Int  {
+		cmd = Boot.shellEscapeCmd(cmd, args);
+		return cast Table.pack(Os.execute(cmd))[3];
+	}
+
+
+	public inline static function cpuTime() : Float {
+		return lua.Os.clock();
+	}
+
+	public inline static function exit(code : Int) : Void {
+		lua.Os.exit(code);
+	}
+
+	public inline static function getChar(echo : Bool) : Int {
+		return lua.Io.read(1).byte();
+	}
+
+	public static function systemName() : String {
+		switch(Package.config.sub(1,1)){
+			case "/" : {
+				var f = Lua.assert(lua.Io.popen("uname"));
+				var s = Lua.assert(f.read(All));
+				f.close();
+				s = s.gsub('^%s+', '');
+				s = s.gsub('%s+$', '');
+				s = s.gsub('[\n\r]+', ' ');
+				if (s == "Darwin") return "Mac";
+				else if (s.lower().find("bsd") > 0) return "BSD";
+				else return "Linux";
+			}
+			case "\\" : return "Windows";
+			default : return null;
+		}
+	}
+
+	public inline static function environment() : Map<String,String>  {
+		throw "not supported";
+		return new Map();
+	}
+
+	public inline static function executablePath() : String {
+		throw "not supported";
+		return null;
+	}
+
+	public inline static function programPath() : String {
+		return haxe.io.Path.join([getCwd(), Lua.arg[0]]);
+	}
+
+	public inline static function getCwd() : String {
+		return lua.lib.lfs.Lfs.currentdir();
+	}
+
+	public inline static function setCwd(s : String) : Void {
+		lua.lib.lfs.Lfs.chdir(s);
+	}
+
+	public inline static function getEnv(s : String) : String {
+		return lua.Os.getenv(s);
+	}
+	public inline static function putEnv(s : String, v : String ) : Void {
+		throw "not supported";
+	}
+
+	public inline static function setTimeLocale(loc : String) : Bool  {
+		// TODO Verify
+		return lua.Os.setlocale(loc) != null;
+	}
+
+	public static function sleep(seconds : Float) : Void {
+		if (seconds <= 0) return;
+		if (Sys.systemName() == "Windows") {
+			Os.execute("ping -n " + (seconds+1) + " localhost > NUL");
+		} else {
+			Os.execute('sleep $seconds');
+		}
+	}
+
+
+	public inline static function stderr() : haxe.io.Output return new FileOutput(Io.stderr);
+	public inline static function stdin()  : haxe.io.Input return new FileInput(Io.stdin);
+	public inline static function stdout() : haxe.io.Output return new FileOutput(Io.stdout);
+
+	public static function time() : Float return lua.Os.time();
+}

+ 208 - 0
std/lua/_std/Type.hx

@@ -0,0 +1,208 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * 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.
+ */
+import lua.Lua;
+import lua.Table;
+
+enum ValueType {
+	TNull;
+	TInt;
+	TFloat;
+	TBool;
+	TObject;
+	TFunction;
+	TClass( c : Class<Dynamic> );
+	TEnum( e : Enum<Dynamic> );
+	TUnknown;
+}
+
+@:coreApi class Type {
+
+	public static function getClass<T>( o : T ) : Class<T> untyped {
+		if( o == null )
+			return null;
+		return lua.Boot.getClass(o);
+	}
+
+	public static function getEnum( o : EnumValue ) : Enum<Dynamic> untyped {
+		if( o == null )
+			return null;
+		return o.__enum__;
+	}
+
+	public static function getSuperClass( c : Class<Dynamic> ) : Class<Dynamic> untyped {
+		return c.__super__;
+	}
+
+
+	public static function getClassName( c : Class<Dynamic> ) : String {
+		if (untyped c.__name__ == null) return null;
+		return lua.Table.concat(untyped c.__name__,'.');
+	}
+
+	public static function getEnumName( e : Enum<Dynamic> ) : String {
+		if (untyped e.__ename__ == null) return null;
+		return lua.Table.concat(untyped e.__ename__,'.');
+	}
+
+	public static function resolveClass( name : String ) : Class<Dynamic> untyped {
+		// TODO: better tmp name for _hxClasses
+		var cl : Class<Dynamic> = _hxClasses[name];
+		// ensure that this is a class
+		if( cl == null || !lua.Boot.isClass(cl) )
+			return null;
+		return cl;
+	}
+
+	public static function resolveEnum( name : String ) : Enum<Dynamic> untyped {
+		// TODO: better tmp name for _hxClasses
+		var e : Dynamic = _hxClasses[name];
+		// ensure that this is an enum
+		if( e == null || !lua.Boot.isEnum(e) )
+			return null;
+		return e;
+	}
+
+	public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T untyped {
+		return __new__(cl, lua.Table.unpack(cast args, 0));
+	}
+
+	public static function createEmptyInstance<T>( cl : Class<T> ) : T untyped {
+		var ret = __lua_table__();
+		Lua.setmetatable(ret, untyped {__index : cl.prototype});
+		return ret;
+	}
+
+	public static function createEnum<T>( e : Enum<T>, constr : String, ?params : Array<Dynamic> ) : T {
+		var f:Dynamic = Reflect.field(e,constr);
+		if( f == null ) throw "No such constructor "+constr;
+		if( Reflect.isFunction(f) ) {
+			if( params == null ) throw "Constructor "+constr+" need parameters";
+			return Reflect.callMethod(null,f,params);
+		}
+		if( params != null && params.length != 0 )
+			throw "Constructor "+constr+" does not need parameters";
+		return f;
+	}
+
+	public static function createEnumIndex<T>( e : Enum<T>, index : Int, ?params : Array<Dynamic> ) : T {
+		var c : String = (untyped e.__constructs__)[index];
+		if( c == null ) throw index+" is not a valid enum constructor index";
+		return createEnum(e,c,params);
+	}
+
+	public static function getInstanceFields( c : Class<Dynamic> ) : Array<String> {
+		var p : Dynamic = untyped c.prototype;
+		var a = new Map<String,Dynamic>();
+		while (p != null){
+			var pfields : lua.Table<Int, Dynamic>  = untyped p.__fields__;
+			for (f in Reflect.fields(pfields)){
+				a.set(f, true);
+			}
+			var mt = lua.Lua.getmetatable(p);
+			if (mt != null && mt.__index != null ) p = mt.__index;
+			else p = null;
+		}
+		return [for (f in a.keys()) f];
+	}
+
+	public static function getClassFields( c : Class<Dynamic> ) : Array<String> {
+		var a = Reflect.fields(c);
+		a.remove("__name__");
+		a.remove("__interfaces__");
+		a.remove("__properties__");
+		a.remove("__super__");
+		a.remove("__meta__");
+		a.remove("prototype");
+		a.remove("new");
+		return a;
+	}
+
+	public static function getEnumConstructs( e : Enum<Dynamic> ) : Array<String> {
+		var a : Array<String> = untyped e.__constructs__;
+		return a.copy();
+	}
+
+	public static function typeof( v : Dynamic ) : ValueType  {
+
+		switch( Lua.type(v) ) {
+			case "boolean": return TBool;
+			case "string": return TClass(String);
+			case "number":
+						   // this should handle all cases : NaN, +/-Inf and Floats outside range
+						   if( Math.ceil(v) == v%2147483648.0 )
+							   return TInt;
+						   return TFloat;
+			case "table":
+						   var e = v.__enum__;
+						   if( e != null )
+							   return TEnum(e);
+						   var c = lua.Boot.getClass(v);
+						   if( c != null )
+							   return TClass(c);
+						   return TObject;
+			case "function":
+						   if( lua.Boot.isClass(v) || lua.Boot.isEnum(v) )
+							   return TObject;
+						   return TFunction;
+			case "nil":
+						   return TNull;
+			default:
+						   return TUnknown;
+		}
+	}
+
+	public static function enumEq<T>( a : T, b : T ) : Bool untyped {
+		if( a == b )
+			return true;
+		try {
+			if( a[0] != b[0] )
+				return false;
+			for( i in 2...a.length )
+				if( !enumEq(a[i],b[i]) )
+					return false;
+			var e = a.__enum__;
+			if( e != b.__enum__ || e == null )
+				return false;
+		} catch( e : Dynamic ) {
+			return false;
+		}
+		return true;
+	}
+
+	public inline static function enumConstructor( e : EnumValue ) : String {
+		return untyped e[0];
+	}
+
+	public inline static function enumParameters( e : EnumValue ) : Array<Dynamic> {
+		return untyped e.slice(2);
+	}
+
+	public inline static function enumIndex( e : EnumValue ) : Int {
+		return untyped e[1];
+	}
+
+	public static function allEnums<T>( e : Enum<T> ) : Array<T> {
+		return untyped e.__empty_constructs__;
+	}
+
+}
+

+ 35 - 0
std/lua/_std/haxe/Json.hx

@@ -0,0 +1,35 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * 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.
+ */
+package haxe;
+
+@:coreApi
+class Json {
+
+	public static function parse( text : String ) : Dynamic {
+		return haxe.format.JsonParser.parse(text);
+	}
+
+	public static function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String ) : String {
+		return haxe.format.JsonPrinter.print(value, replacer, space);
+	}
+
+}

+ 285 - 0
std/lua/_std/haxe/Utf8.hx

@@ -0,0 +1,285 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package haxe;
+
+import lua.NativeStringTools;
+
+/**
+  A Lua-specific implementation of Utf8, using a helper library.
+ **/
+
+class Utf8 {
+
+    var __b : String;
+
+    /**
+      Allocate a new Utf8 buffer using an optional bytes size.
+     **/
+    public function new( ?size : Int ) {
+	__b = "";
+    }
+
+    /**
+      Add the given UTF8 character code to the buffer.
+     **/
+    public inline function addChar( c : Int ) : Void {
+	__b += char(c);
+    }
+
+    /**
+      Returns the buffer converted to a String;
+     **/
+    public inline function toString() : String {
+	return __b;
+    }
+
+    /**
+      Call the `chars` function for each UTF8 char of the string.
+     **/
+    public static function iter( s : String, chars : Int -> Void ) {
+	var cur = 0;
+	while (cur < s.length){
+	    var code = s.charCodeAt(cur);
+	    var width = charWidth(code);
+	    var l = (code << 6)  | s.charCodeAt(cur+1);
+	    trace(l + " is the value for l");
+	    switch(width){
+		case 1 : chars(code);
+		case 2 : chars((code << 6)  | s.charCodeAt(cur+1));
+		case 3 : chars((code << 12) | (s.charCodeAt(cur+1) << 6) | s.charCodeAt(cur+2));
+	    }
+	    cur += width;
+	}
+    }
+
+    /**
+      Encode the input ISO string into the corresponding UTF8 one.
+     **/
+    public static function encode( s : String ) : String {
+	// ported from : http://phpjs.org/functions/utf8_encode/
+	if (s == null ) {
+	    return '';
+	}
+	var string = (s + ''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n");
+	var utftext = '';
+	var start = 0;
+	var end = 0;
+	var n = 0;
+	while (n < s.length) {
+	    var c1 = string.charCodeAt(n);
+	    var enc = null;
+
+	    if (c1 < 128) {
+		end++;
+	    } else if (c1 > 127 && c1 < 2048) {
+		enc = String.fromCharCode( (c1 >> 6) | 192) 
+		    + String.fromCharCode( (c1 & 63) | 128);
+	    } else if ((c1 & 0xF800) != 0xD800) {
+		enc = String.fromCharCode( (c1 >> 12) | 224)
+		    + String.fromCharCode( ((c1 >> 6) & 63) | 128)
+		    + String.fromCharCode( (c1 & 63) | 128);
+	    } else { // surrogate pairs
+		if ((c1 & 0xFC00) != 0xD800) {
+		    throw 'Unmatched trail surrogate at ' + n;
+		}
+		var c2 = string.charCodeAt(++n);
+		if ((c2 & 0xFC00) != 0xDC00) {
+		    throw 'Unmatched lead surrogate at ' + (n - 1);
+		}
+		c1 = ((c1 & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000;
+		enc = String.fromCharCode( (c1 >> 18) | 240)
+		    + String.fromCharCode( ((c1 >> 12) & 63) | 128)
+		    + String.fromCharCode(((c1 >> 6) & 63) | 128)
+		    + String.fromCharCode((c1 & 63) | 128);
+	    }
+	    if (enc != null) {
+		if (end > start) {
+		    utftext += string.substring(start, end);
+		}
+		utftext += enc;
+		start = end = n + 1;
+	    }
+	    n++;
+	}
+
+	if (end > start) {
+	    utftext += string.substring(start, s.length);
+	}
+
+	return utftext;
+
+    }
+
+    /**
+      Decode an UTF8 string back to an ISO string.
+      Throw an exception if a given UTF8 character is not supported by the decoder.
+     **/
+    public static function decode( s : String ) : String {
+	var ret = new StringBuf();
+	iter(s, function(c){
+	    if( c == 8364 ) // euro symbol
+		c = 164;
+	    else if( c > 255 ){
+		// throw new RangeError('Utf8 decode invalid character ($c)');
+		throw 'Utf8::decode invalid character ($c)';
+	    }
+
+	    if (c != 0xFEFF) // BOM
+		ret.add(String.fromCharCode(c));
+	});
+	return ret.toString();
+    }
+
+    /**
+      Similar to `String.charCodeAt` but uses the UTF8 character position.
+     **/
+    public static inline function charCodeAt( s : String, index : Int ) : Int {
+	var cur_idx = 0;
+	var pos = 0;
+	for (i in 0...index){
+	    pos += charWidth(s.charCodeAt(pos));
+	}
+	var ret = 0;
+	var code = s.charCodeAt(pos);
+	var bytes = charWidth(code);
+	if (bytes == 1){
+	    return code;
+	} else if (bytes == 2){
+	    return ((code & 0x1F) << 6) | (s.charCodeAt(pos+1) & 0x3F);
+	} else if (bytes == 3){
+	    return ((code & 0x0F) << 12) | (((s.charCodeAt(pos+1) & 0x3F) << 6) | (s.charCodeAt(pos+2) & 0x3F));
+	} else {
+	    return null;
+	}
+    }
+
+    /**
+      Tells if the String is correctly encoded as UTF8.
+     **/
+    public static function validate( s : String ) : Bool {
+	if (s == null) return false;
+	var cur = 0;
+	while (cur < s.length){
+	    var code = s.charCodeAt(cur);
+	    var width = charWidth(code);
+	    var expectedLen = 0;
+
+		 if ((code & 0x10000000) == 0x00000000) expectedLen = 1;
+	    else if ((code & 0x11100000) == 0x11000000) expectedLen = 2;
+	    else if ((code & 0x11110000) == 0x11100000) expectedLen = 3;
+	    else if ((code & 0x11111000) == 0x11110000) expectedLen = 4;
+	    else if ((code & 0x11111100) == 0x11111000) expectedLen = 5;
+	    else if ((code & 0x11111110) == 0x11111100) expectedLen = 6;
+	    else return false;
+
+	    if (cur + expectedLen > s.length) return false;
+
+	    for (i in (cur + 1)...expectedLen) {
+		if ((s.charCodeAt(i) & 0x11000000) != 0x10000000) {
+		    return false;
+		}
+	    }
+
+	    cur += width;
+	}
+	return true;
+    }
+
+    /**
+      Returns the number of UTF8 chars of the String.
+     **/
+    public static inline function length( s : String ) : Int {
+	var pos = 0;
+	var len = 0;
+	while (pos < s.length){
+	    pos += charWidth(s.charCodeAt(pos));
+	    len++;
+	}
+	return len;
+    }
+
+    /**
+      Compare two UTF8 strings, character by character.
+     **/
+    public static function compare( a : String, b : String ) : Int {
+	return a > b ? 1 : (a == b ? 0 : -1);
+    }
+
+    /**
+      This is similar to `String.substr` but the `pos` and `len` parts are considering UTF8 characters.
+     **/
+    public static inline function sub( s : String, pos : Int, len : Int ) : String {
+	var startpos = 0;
+	var ret = new StringBuf();
+	for (i in 0...pos){
+	    startpos += charWidth(s.charCodeAt(startpos));
+	}
+	var endpos = startpos;
+	for (i in 0...len){
+	    endpos += charWidth(s.charCodeAt(endpos));
+	}
+	return s.substring(startpos, endpos);
+    }
+
+    /**
+      Determines the expected character width of the utf8 codepoint
+     **/
+    static function charWidth(c:Int) : Int {
+	return   if (c >  0   && c <= 127) 1;
+	    else if (c >= 194 && c <= 223) 2;
+	    else if (c >= 224 && c <= 239) 3;
+	    else if (c >= 240 && c <= 244) 4;
+	    else null;
+    }
+
+    /**
+      Returns the string representation of the unicode codepoint
+     **/
+    public static function char( unicode : Int ) : String {
+	if (unicode <= 0x7F) {
+	    return String.fromCharCode(unicode);
+	} else if (unicode <= 0x7FF) {
+	    var b0 = 0xC0 + Math.floor(unicode / 0x40);
+	    var b1 = 0x80 + (unicode % 0x40);
+	    return NativeStringTools.char(b0, b1);
+	} else if (unicode <= 0xFFFF) {
+	    var b0 = 0xE0 +  Math.floor(unicode / 0x1000);
+	    var b1 = 0x80 + (Math.floor(unicode / 0x40) % 0x40);
+	    var b2 = 0x80 + (unicode % 0x40);
+	    return NativeStringTools.char(b0, b1, b2);
+	} else if (unicode <= 0x10FFFF) {
+	    var code = unicode;
+	    var b3   = 0x80 + (code % 0x40);
+	    code     = Math.floor(code / 0x40);
+	    var b2   = 0x80 + (code % 0x40);
+	    code     = Math.floor(code / 0x40);
+	    var b1   = 0x80 + (code % 0x40);
+	    code     = Math.floor(code / 0x40);
+	    var b0   = 0xF0 + code;
+
+	    return NativeStringTools.char(b0, b1, b2, b3);
+	} else {
+	    throw 'Unicode greater than U+10FFFF';
+	}
+    }
+}
+

+ 86 - 0
std/lua/_std/haxe/ds/IntMap.hx

@@ -0,0 +1,86 @@
+/*
+ * Copyright (C)2005-2015 Haxe Foundation
+ *
+ * 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.
+ */
+package haxe.ds;
+import lua.Lua;
+
+class IntMap<T> implements haxe.Constraints.IMap<Int,T> {
+
+	private var h : Dynamic;
+
+	public inline function new() : Void {
+		h = {};
+	}
+
+	public inline function set( key : Int, value : T ) : Void {
+		 h[key] = value;
+	}
+
+	public inline function get( key : Int ) : Null<T> {
+		return h[key];
+	}
+
+	public inline function exists( key : Int ) : Bool {
+		return Reflect.hasField(h,cast key);
+	}
+
+	public function remove( key : Int ) : Bool {
+		if (!Reflect.hasField(h,cast key)) return false;
+		Reflect.deleteField(h, cast key);
+		return true;
+	}
+
+	public function keys() : Iterator<Int> {
+		var cur = Reflect.fields(h).iterator();
+		return {
+			next : function() {
+				var ret = cur.next();
+				return cast ret;
+			},
+			hasNext : function() return cur.hasNext()
+		}
+	}
+
+	public function iterator() : Iterator<T> {
+		var it = keys();
+		return untyped {
+			hasNext : function() return it.hasNext(),
+			next : function() return h[it.next()]
+		};
+	}
+
+	public function toString() : String {
+		var s = new StringBuf();
+		s.add("{");
+		var it = keys();
+		for( i in it ) {
+			s.add(i);
+			s.add(" => ");
+			s.add(Std.string(get(i)));
+			if( it.hasNext() )
+				s.add(", ");
+		}
+		s.add("}");
+		return s.toString();
+	}
+
+}
+

+ 99 - 0
std/lua/_std/haxe/ds/ObjectMap.hx

@@ -0,0 +1,99 @@
+/*
+ * Copyright (C)2005-2015 Haxe Foundation
+ *
+ * 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.
+ */
+package haxe.ds;
+class ObjectMap<A,B> implements haxe.Constraints.IMap<A,B> {
+
+	static var count = 0;
+
+	static inline function assignId(obj: { } ):Int {
+		return untyped obj.__id__ = ++count;
+	}
+
+	static inline function getId(obj: { } ):Int {
+		return untyped obj.__id__;
+	}
+
+	var h : Dynamic;
+	var k : Dynamic;
+
+	public inline function new() : Void {
+		h = lua.Boot.createTable();
+		k = lua.Boot.createTable();
+	}
+
+	public inline function set( key : A, value : B ) : Void untyped {
+		h[key] = value;
+		k[key] = true;
+	}
+
+	public inline function get( key : A ) : Null<B> untyped {
+		return h[key];
+	}
+
+	public inline function exists( key : A ) : Bool untyped {
+		return k[key] != null;
+	}
+
+	public function remove( key : A ) : Bool untyped {
+		if ( k[key] == null) return false;
+		k[key] = null;
+		h[key] = null;
+		return true;
+	}
+
+	public function keys() : Iterator<A> untyped {
+		var cur = next(h,null);
+		return {
+			next : function() {
+				var ret = cur;
+				cur = untyped next(k, cur);
+				return ret;
+			},
+			hasNext : function() return cur != null
+		}
+	}
+
+	public function iterator() : Iterator<B> {
+		var itr = keys();
+		return untyped {
+			hasNext : itr.hasNext, 
+			next : function() return h[itr.next()]
+		};
+	}
+
+	public function toString() : String {
+		var s = new StringBuf();
+		s.add("{");
+		var it = keys();
+		for( i in it ) {
+			s.add(i);
+			s.add(" => ");
+			s.add(Std.string(get(i)));
+			if( it.hasNext() )
+				s.add(", ");
+		}
+		s.add("}");
+		return s.toString();
+	}
+
+}
+

+ 93 - 0
std/lua/_std/haxe/ds/StringMap.hx

@@ -0,0 +1,93 @@
+/*
+ * Copyright (C)2005-2015 Haxe Foundation
+ *
+ * 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.
+ */
+package haxe.ds;
+import lua.Lua;
+
+class StringMap<T> implements haxe.Constraints.IMap<String,T> {
+
+	private var k : Dynamic; // Is item exists
+	private var v : Dynamic; // Values table
+
+	public inline function new() : Void {
+		v = untyped __lua__("{}");
+		k = untyped __lua__("{}");
+	}
+
+	public inline function set( key : String, value : T ) : Void untyped {
+		untyped __lua__("{0}[{1}] = {2}", v, key, value);
+		untyped __lua__("{0}[{1}] = true", k, key);
+	}
+
+	public inline function get( key : String ) : Null<T> untyped {
+		return untyped __lua__("{0}[{1}]", v, key);
+	}
+
+	public inline function exists( key : String ) : Bool untyped {
+		return untyped __lua__("{0}[{1}] or false", k, key);
+	}
+
+	public function remove( key : String ) : Bool untyped {
+		if (untyped __lua__("not {0}[{1}]", k, key)) return false;
+		untyped __lua__("{0}[{1}] = nil", v, key);
+		untyped __lua__("{0}[{1}] = nil", k, key);
+		return true;
+	}
+
+	public function keys() : Iterator<String> {
+		var cur : Array<String> = [];
+		untyped __lua__("for _k,_v in pairs({1}) do
+			if(_v)then {0}:push(_k) end
+		end", cur, k);
+		return {
+			next : function() {
+				var ret = cur.pop();
+				return ret;
+			},
+			hasNext : function() return cur.length > 0
+		}
+	}
+
+	public function iterator() : Iterator<T> {
+		var it = keys();
+		return  {
+			hasNext : function() return it.hasNext(),
+			next : function() return untyped __lua__("{0}[{1}]", v, it.next())
+		};
+	}
+
+	public function toString() : String {
+		var s = new StringBuf();
+		s.add("{");
+		var it = keys();
+		for( i in it ) {
+			s.add(i);
+			s.add(" => ");
+			s.add(Std.string(get(i)));
+			if( it.hasNext() )
+				s.add(", ");
+		}
+		s.add("}");
+		return s.toString();
+	}
+
+}
+

+ 106 - 0
std/lua/_std/sys/FileSystem.hx

@@ -0,0 +1,106 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package sys;
+
+import lua.lib.lfs.Lfs;
+import lua.Io;
+import lua.Os;
+import lua.Lib;
+import lua.Table;
+import haxe.io.Path;
+
+class FileSystem {
+	public static function exists( path : String ) : Bool {
+		if (path == null) return false;
+		else{
+			var f = Io.open(path);
+			if (f == null) return false;
+			else {
+				f.close();
+				return true;
+			}
+		}
+	}
+
+	public inline static function rename( path : String, newPath : String ) : Void {
+		return  Os.rename(path, newPath);
+	}
+
+	public inline static function stat( path : String ) : FileStat {
+		// the lua lfs attributes command uses a string for "mode".
+		// we just need to patch it.
+
+		var attr : sys.FileStat = cast Lfs.attributes(path);
+		var lfs_mode : String = cast(attr.mode, String);
+		var mode = switch(lfs_mode){
+			case "file"         : 0x0100000;
+			case "directory"    : 0x0040000;
+			case "link"         : 0x0120000;
+			case "socket"       : 0x0140000;
+			case "named pipe"   : 0x0010000;
+			case "char device"  : 0x0020000;
+			case "block device" : 0x0060000;
+			default             : 0x0000000;
+		}
+		attr.mode = mode;
+		return attr;
+	}
+
+	public inline static function fullPath( relPath : String ) : String {
+		return Path.normalize(absolutePath(relPath));
+	}
+
+	public inline static function absolutePath( relPath : String ) : String {
+		if (relPath == null) return null;
+		var pwd = Lfs.currentdir() ;
+		if (pwd == null) return relPath;
+		return Path.join([pwd, relPath]);
+	}
+
+	public inline static function deleteFile( path : String ) : Void {
+		lua.Os.remove(path);
+	}
+
+	public inline static function readDirectory( path : String ) : Array<String> {
+		var parts : Table<Dynamic, Dynamic> = Table.pack(Lfs.dir(path));
+		var itr = function(){
+			var res = parts[1](parts[2]);
+			while(res == "." || res == ".."){
+				res = parts[1](parts[2]);
+			}
+			return res;
+		}
+		return lua.Lib.fillArray(itr);
+	}
+
+	public inline static function isDirectory( path : String ) : Bool {
+		return  Lfs.attributes(path, "mode") ==  "directory";
+	}
+
+	public inline static function deleteDirectory( path : String ) : Void {
+		Lfs.rmdir(path);
+	}
+
+	public inline static function createDirectory( path : String ) : Void {
+	   Lfs.mkdir(path);
+	}
+}

+ 72 - 0
std/lua/_std/sys/io/File.hx

@@ -0,0 +1,72 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package sys.io;
+import lua.Lua;
+import lua.Io;
+import lua.Os;
+import lua.FileHandle;
+
+@:coreApi
+class File {
+	public static function getContent( path : String ) : String {
+		var f = Io.open(path, "r");
+		var s = f.read(All);
+		f.close();
+		return s;
+	}
+
+	public static function append( path : String, binary : Bool = true ) : FileOutput {
+		return new FileOutput(Io.open(path, "a"));
+
+	}
+
+	public static function copy( srcPath : String, dstPath : String ) : Void {
+		Os.execute('copy $srcPath $dstPath');
+	}
+
+	public static function getBytes( path : String ) : haxe.io.Bytes {
+		var f = read(path, true);
+		var ret = f.readAll();
+		f.close();
+		return ret;
+	}
+
+	public static function read( path : String, binary : Bool = true ) : FileInput {
+		return new FileInput(Io.open(path,'r'));
+	}
+
+	public static function write( path : String, binary : Bool = true ) : FileOutput {
+		return new FileOutput(Io.open(path,'w'));
+	}
+
+	public static function saveBytes( path : String, bytes : haxe.io.Bytes ) : Void {
+		var f = write(path, true);
+		f.writeBytes(bytes, 0, bytes.length);
+		f.close();
+	}
+
+	public static function saveContent( path : String, content : String ) : Void {
+		var f = write(path, false);
+		f.writeString(content);
+		f.close();
+	}
+}

+ 63 - 0
std/lua/_std/sys/io/FileInput.hx

@@ -0,0 +1,63 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package sys.io;
+
+import lua.FileHandle;
+import lua.Io;
+import lua.NativeStringTools;
+import lua.Boot;
+import lua.Os;
+
+class FileInput extends haxe.io.Input {
+	var f:FileHandle;
+
+	public function new(f:FileHandle){
+		this.bigEndian = Boot.platformBigEndian;
+		this.f = f;
+	}
+
+	inline public function seek( p : Int, pos : FileSeek ) : Void {
+		var arg = switch(pos){
+			case SeekBegin : "set";
+			case SeekCur   : "cur";
+			case SeekEnd   : "end";
+		}
+		return f.seek(arg, p);
+	}
+
+	inline public function tell() : Int {
+		return f.seek();
+	}
+
+	inline public function eof() : Bool {
+		return f.read(0) == null;
+	}
+
+	override inline public function readByte() : Int {
+		return NativeStringTools.byte(f.read(1));
+	}
+
+	override inline public function close() : Void {
+		f.close();
+	}
+
+}

+ 50 - 0
std/lua/_std/sys/io/FileOutput.hx

@@ -0,0 +1,50 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package sys.io;
+
+import lua.FileHandle;
+
+class FileOutput extends haxe.io.Output {
+	var f:FileHandle;
+
+	public function new(f:FileHandle){
+		this.f = f;
+	}
+
+	public inline function seek( p : Int, pos : FileSeek ) : Void {
+		var arg = switch(pos){
+			case SeekBegin : "set";
+			case SeekCur : "cur";
+			case SeekEnd : "end";
+		}
+		return f.seek(arg, p);
+	}
+
+	public inline function tell() : Int {
+		return f.seek();
+	}
+
+	override inline public function writeByte(c : Int) : Void {
+		f.write(String.fromCharCode(c));
+	}
+
+}

+ 51 - 0
std/lua/_std/sys/io/Process.hx

@@ -0,0 +1,51 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package sys.io;
+import lua.Io;
+import lua.FileHandle;
+import lua.Boot;
+import lua.Io;
+
+@:coreApi
+class Process {
+	var fh : FileHandle; 
+	var eh : FileHandle;
+	var errTmpFile : String;
+
+	public var stdout(default,null) : haxe.io.Input;
+	public var stderr(default,null) : haxe.io.Input;
+	public var stdin(default, null) : haxe.io.Output;
+	public function new( cmd : String, ?args : Array<String>){
+		if (args == null) args = [];
+		this.errTmpFile = Boot.tempFile();
+		this.eh = Io.open(errTmpFile, 'r');
+		args.push('>2 ${Boot.tempFile()}');
+		cmd = Boot.shellEscapeCmd(cmd, args);
+		this.fh = Io.popen(cmd, "w+");
+		this.stdout = new FileInput(fh);
+		this.stderr = new FileInput(eh);
+		this.stdin = new FileOutput(fh);
+	}
+	public function getPid() : Int {
+		
+	}
+}

+ 40 - 0
std/lua/lib/lfs/Lfs.hx

@@ -0,0 +1,40 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package lua.lib.lfs;
+@:luaRequire("lfs")
+extern class Lfs {
+	@:overload(   function			 (filepath : String, aname : String) : Dynamic {})
+	public static function attributes(filepath : String) : LfsFileStat;
+
+	public static function chdir(path : String) : Bool;
+	public static function lock_dir(path : String, ?second_stale : Int) : String; 
+	public static function currentdir() : String;
+	public static function dir(path : String) : Void->String;
+	public static function lock(filename : String, mode : String, ?start : Int, ?length : Int) : Bool;
+	public static function link(old : String, _new :String, ?symlink : Bool) : Void;
+	public static function mkdir(dirname : String) : Bool;
+	public static function rmdir(dirname : String) : Bool;
+	public static function setmode(file: String, mode : String) : String;
+	public static function symlinkattributes(filepath : String, ?aname : String) : Table<String, String>;
+	public static function touch(filepath : String, ?atime : Int, ?mtime : Int) : Bool;
+	public static function unlock(filehandle : String, ?start : Int, ?length : Int) : Bool;
+}

+ 46 - 0
std/lua/lib/lfs/LfsFileStat.hx

@@ -0,0 +1,46 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+package lua.lib.lfs;
+
+/**
+	File informations, as given by [sys.FileSystem.stat]
+**/
+typedef LfsFileStat = {
+	/** the user group id for the file **/
+	var gid : Int;
+	/** the user id for the file **/
+	var uid : Int;
+	/** the last access time for the file (when enabled by the file system) **/
+	var atime : Date;
+	/** the last modification time for the file **/
+	var mtime : Date;
+	/** the creation time for the file (not all filesystems support this) **/
+	var ctime : Date;
+	/** the size of the file **/
+	var size : Int;
+	var dev : Int;
+	var ino : Int;
+	var nlink : Int;
+	var rdev : Int;
+	var mode : String;
+}
+

+ 57 - 0
std/lua/lib/lrexlib/Rex.hx

@@ -0,0 +1,57 @@
+package lua.lib.lrexlib;
+@:luaRequire("rex_pcre")
+extern class Rex {
+
+	inline public static function create(expr : String, flag : String) : Rex{
+		return untyped Rex['new'](expr, flag);
+	}
+
+	/**
+	  The function searches for the first match of the regexp patt in the
+	  string subj, starting from offset init, subject to flags cf and ef.
+	  Returns matched string, or array of strings.
+	 **/
+	public static function match(patt : String, ?init : Int, ?ef : Int) : Dynamic;
+
+	/**
+	 The function searches for the first match of the regexp patt in the string
+	 subj, starting from offset init, subject to flags cf and ef. 
+	 Returns 
+	 **/
+	public static function find(subj : String, ?init : Int, ?ef : Int) : Dynamic;
+
+
+	/**
+	 The function is intended for use in the generic for Lua construct. It is
+	 used for splitting a subject string subj into parts (sections). The sep
+	 parameter is a regular expression pattern representing separators between
+	 the sections. 
+	 **/
+	@:overload(   function      (subj : String, sep : Rex,    ?cf : Int, ?ef : Int) : Void->String{})
+	public static function split(subj : String, sep : String, ?cf : Int, ?ef : Int) : Void->String;
+
+
+	/**
+	  This function counts matches of the pattern patt in the string subj.
+	**/	
+	public static function count(subj : String, patt : String, cf : Int, ef : Int) : Dynamic;
+	public static function flags(tb:Dynamic) : Dynamic;
+
+	public function tfind(subj : String, ?init : Int, ?ef : Int) : Dynamic;
+	public function exec(subj : String, ?init : Int, ?ef : Int) : Dynamic;
+
+	/**
+	 The function is intended for use in the generic for Lua construct. It
+	 returns an iterator for repeated matching of the pattern patt in the
+	 string subj, subject to flags cf and ef.
+	 **/
+	public static function gmatch(subj : String, ?cf : Int, ?ef : Int) : Dynamic; // TODO: Extern a lua iterator
+
+	/**
+	  This function searches for all matches of the pattern patt in the string subj
+	  and replaces them according to the parameters repl and n.
+	 **/
+	@:overload(	  function     (subj : String, patt : Rex,    repl: Dynamic, ?n: Int, ?cf : Int, ?ef : Int) : String {})
+	public static function gsub(subj : String, patt : String, repl: Dynamic, ?n: Int, ?cf : Int, ?ef : Int) : String;
+}
+

+ 1 - 1
tests/README.md

@@ -45,7 +45,7 @@ It is possible to run it in local machines too:
 
  1. Change to this directory.
  2. Compile the script: `haxe RunCi.hxml`.
- 3. Define the test target by `export TEST=$TARGET` (or `set "TEST=$TARGET"` on Windows), where `$TARGET` should be a comma-seperated list of targets, e.g. `neko,macro`. Possible targets are `macro`, `neko`, `js`, `php`, `cpp`, `flash9`, `as3`, `java`, `cs`, `python`, and `third-party`. However, `flash9`, `as3`, and `third-party` are not likely to work on local machines (TODO).
+ 3. Define the test target by `export TEST=$TARGET` (or `set "TEST=$TARGET"` on Windows), where `$TARGET` should be a comma-seperated list of targets, e.g. `neko,macro`. Possible targets are `macro`, `neko`, `js`, `lua`, `php`, `cpp`, `flash9`, `as3`, `java`, `cs`, `python`, and `third-party`. However, `flash9`, `as3`, and `third-party` are not likely to work on local machines (TODO).
  4. Run it: `neko RunCi.n`.
 
 Note that the script will try to look for test dependencies and install them if they are not found. Look at the `getXXXDependencies` functions for the details.

+ 55 - 0
tests/RunCi.hx

@@ -19,6 +19,7 @@ private typedef TravisConfig = {
 	var Macro = "macro";
 	var Neko = "neko";
 	var Js = "js";
+	var Lua = "lua";
 	var Php = "php";
 	var Cpp = "cpp";
 	var Flash9 = "flash9";
@@ -428,6 +429,56 @@ class RunCi {
 		runCommand("node", ["-v"]);
 	}
 
+	static function getLuaDependencies(jit = false, lua_version = "lua5.2", luarocks_version = "2.3.0") {
+		switch (systemName){
+			case "Linux": requireAptPackages(["libpcre3-dev"]);
+			case "Mac": runCommand("brew", ["install", "pcre"]);
+		}
+
+		var home_dir = Sys.getEnv("HOME");
+
+		// the lua paths created by the setup script.
+		addToPATH('$home_dir/.lua');
+		addToPATH('$home_dir/.local/bin');
+
+		// we need to cd back into the build directory to do some work
+		var build_dir = Sys.getEnv("TRAVIS_BUILD_DIR");
+		changeDirectory(build_dir);
+
+		// luarocks needs to be in the path
+		addToPATH('$build_dir/install/luarocks/bin');
+
+
+		if (jit) Sys.putEnv("LUAJIT","yes");
+		Sys.putEnv("LUAROCKS", luarocks_version);
+		Sys.putEnv("LUA", lua_version);
+
+		// use the helper scripts in .travis. TODO: Refactor as pure haxe?
+		runCommand("sh", ['${build_dir}/.travis/setenv_lua.sh']);
+		if (jit){
+			runCommand("luajit", ["-v"]);
+		} else {
+			runCommand("lua", ["-v"]);
+		}
+		runCommand("pip", ["install", "--user", "cpp-coveralls"]);
+		runCommand("luarocks", ["install", "lrexlib-pcre", "2.7.2-1", "--server=https://luarocks.org/dev"]);
+		runCommand("luarocks", ["install", "luautf8", "--server=https://luarocks.org/dev"]);
+
+		// we did user land installs of luarocks and lua.  We need to point lua
+		// to the luarocks install using the luarocks path and env variables
+		var lua_path = commandResult("luarocks", ["path", "--lr-path"]).stdout.trim();
+		Sys.putEnv("LUA_PATH", lua_path);
+		trace(lua_path + " is the value for lua_path");
+
+		// step two of the variable setting
+		var lua_cpath = commandResult("luarocks", ["path", "--lr-cpath"]).stdout.trim();
+		Sys.putEnv("LUA_CPATH", lua_cpath);
+		trace(lua_cpath + " is the value for lua_cpath");
+
+		// change back to the unit dir for the rest of the tests
+		changeDirectory(unitDir);
+	}
+
 	static function getCsDependencies() {
 		switch (systemName) {
 			case "Linux":
@@ -924,6 +975,10 @@ class RunCi {
 					for (py in pys) {
 						runCommand(py, ["test.py"]);
 					}
+				case Lua:
+					getLuaDependencies();
+					runCommand("haxe", ["compile-lua.hxml"].concat(args));
+					runCommand("lua", ["bin/unit.lua"]);
 				case Cpp:
 					getCppDependencies();
 					runCommand("haxe", ["compile-cpp.hxml", "-D", "HXCPP_M32"].concat(args));

+ 14 - 0
tests/sys/compile-lua.hxml

@@ -0,0 +1,14 @@
+
+compile-each.hxml
+-main Main
+-lua bin/lua/sys.lua
+
+--next
+compile-each.hxml
+-main TestArguments
+-lua bin/lua/TestArguments.lua
+
+--next
+compile-each.hxml
+-main ExitCode
+-lua bin/lua/ExitCode.lua

+ 6 - 4
tests/sys/src/ExitCode.hx

@@ -31,13 +31,15 @@ class ExitCode {
 		"bin/python/ExitCode.py";
 	#elseif php
 		"bin/php/ExitCode/index.php";
+	#elseif lua
+		"bin/lua/ExitCode.lua";
 	#else
 		null;
 	#end
 
 	static public function getNative():String {
-		// This is just a script that behaves like ExitCode.hx, 
-		// which exits with the code same as the first given argument. 
+		// This is just a script that behaves like ExitCode.hx,
+		// which exits with the code same as the first given argument.
 		// var scriptContent = switch (Sys.systemName()) {
 		// 	case "Windows":
 		// 		'@echo off\nexit /b %1';
@@ -80,8 +82,8 @@ class ExitCode {
 
 		return binPath;
 	}
-	
+
 	static function main():Void {
 		Sys.exit(Std.parseInt(Sys.args()[0]));
 	}
-}
+}

+ 2 - 1
tests/sys/src/TestArguments.hx

@@ -82,6 +82,8 @@ class TestArguments extends haxe.unit.TestCase {
 		"bin/python/TestArguments.py";
 	#elseif php
 		"bin/php/TestArguments/index.php";
+	#elseif lua
+		"bin/lua/TestArguments.lua";
 	#else
 		null;
 	#end
@@ -90,7 +92,6 @@ class TestArguments extends haxe.unit.TestCase {
 
 	function testArgs() {
 		var args = Sys.args();
-		// trace(args);
 		for (i in 0...expectedArgs.length) {
 			assertEquals(expectedArgs[i], args[i]);
 		}

+ 12 - 2
tests/sys/src/TestCommandBase.hx

@@ -37,6 +37,11 @@ class TestCommandBase extends haxe.unit.TestCase {
 				run(Sys.executablePath(), [bin].concat(args));
 			#elseif php
 				run(untyped __php__("defined('PHP_BINARY') ? PHP_BINARY : 'php'"), [bin].concat(args));
+			#elseif lua
+				switch(Sys.getEnv("LUA")){
+					case null : run("lua", [bin].concat(args));
+					default   : run(Sys.getEnv("LUA"), [bin].concat(args));
+				};
 			#else
 				-1;
 			#end
@@ -45,7 +50,7 @@ class TestCommandBase extends haxe.unit.TestCase {
 		assertEquals(0, exitCode);
 	}
 
-	function testCommandName() {		
+	function testCommandName() {
 		var binExt = switch (Sys.systemName()) {
 			case "Windows":
 				".exe";
@@ -117,6 +122,11 @@ class TestCommandBase extends haxe.unit.TestCase {
 					run(Sys.executablePath(), [bin].concat(args));
 				#elseif php
 					run(untyped __php__("defined('PHP_BINARY') ? PHP_BINARY : 'php'"), [bin].concat(args));
+				#elseif lua
+					switch(Sys.getEnv("LUA")){
+						case null: run("lua", [bin].concat(args));
+						default : run(Sys.getEnv("LUA"), [bin].concat(args));
+					};
 				#else
 					-1;
 				#end
@@ -130,4 +140,4 @@ class TestCommandBase extends haxe.unit.TestCase {
 		var exitCode = run('$native 1 || $native 0');
 		assertEquals(0, exitCode);
 	}
-}
+}

+ 4 - 2
tests/sys/src/TestSys.hx

@@ -4,13 +4,13 @@ class TestSys extends TestCommandBase {
 	}
 
 	function testEnv() {
-		#if !(java || php)
+		#if !(java || php || lua)
 		Sys.putEnv("foo", "value");
 		assertEquals("value", Sys.getEnv("foo"));
 		#end
 		assertEquals(null, Sys.getEnv("doesn't exist"));
 
-		#if !(java || php)
+		#if !(java || php || lua)
 		var env = Sys.environment();
 		assertEquals("value", env.get("foo"));
 		#end
@@ -48,6 +48,8 @@ class TestSys extends TestCommandBase {
 			assertTrue(StringTools.endsWith(p, "sys.py"));
 		#elseif php
 			assertTrue(StringTools.endsWith(p, "index.php"));
+		#elseif lua
+			assertTrue(StringTools.endsWith(p, "sys.lua"));
 		#end
 	}
 

+ 3 - 0
tests/unit/compile-lua.hxml

@@ -0,0 +1,3 @@
+compile-each.hxml
+-main unit.Test
+-lua bin/unit.lua

+ 1 - 0
tests/unit/compile.hxml

@@ -16,6 +16,7 @@ compile-java-runner.hxml
 
 --next compile-flash9.hxml
 --next compile-js.hxml
+--next compile-lua.hxml
 --next compile-neko.hxml
 --next compile-php.hxml
 --next compile-as3.hxml

+ 1 - 1
tests/unit/src/unit/Test.hx

@@ -252,7 +252,7 @@ class Test {
 	}
 
 	static function resetTimer() {
-		#if (neko || php || cpp || java || cs || python || hl)
+		#if (neko || php || cpp || java || cs || python || hl || lua)
 		#else
 		if( timer != null ) timer.stop();
 		timer = new haxe.Timer(30000);

+ 1 - 1
tests/unit/src/unit/TestBytes.hx

@@ -137,4 +137,4 @@ class TestBytes extends Test {
 		eq(b1.getString(0,2), b2.getString(0,2));
 
 	}
-}
+}

+ 3 - 2
tests/unit/src/unit/TestDCE.hx

@@ -117,7 +117,8 @@ class TestDCE extends Test {
 		nhf(bc, "get_x");
 	}
 
-	#if (!cpp && !java && !cs)
+	// TODO: this should be possible in lua
+	#if (!cpp && !java && !cs && !lua)
 	public function testProperty2() {
 		var a = new RemovePropertyKeepAccessors();
 		a.test = 3;
@@ -243,4 +244,4 @@ class RemovePropertyKeepAccessors
 
 	public function get_test():Float return _test;
 	public function set_test(a:Float):Float { _test = a; return _test; }
-}
+}

+ 1 - 1
tests/unit/src/unitstd/StringTools.unit.hx

@@ -133,7 +133,7 @@ StringTools.isEof(StringTools.fastCodeAt(str, 3)) == true;
 StringTools.isEof(StringTools.fastCodeAt("", 0)) == true;
 
 // isEOF
-#if neko
+#if (neko || lua)
 StringTools.isEof(null) == true;
 #elseif (cs || java || python)
 StringTools.isEof( -1) == true;

+ 4 - 0
tests/unit/unit.html

@@ -47,6 +47,10 @@ iframe {
   <div class="label">Neko</div>
   <div id="neko_container" class="cont"><iframe src="bin/unit.n"></iframe></div>
 </div>
+<div class="window">
+  <div class="label">Lua</div>
+  <div id="lua_container" class="cont"><iframe src="bin/runexe.n?bin/lua/bin/unit.lua"></iframe></div>
+</div>
 <div class="window">
   <div class="label">Php</div>
   <div id="php_container" class="cont"><iframe src="bin/php/index.php"></iframe></div>