2
0
Эх сурвалжийг харах

Merge branch 'development'

Simon Krajewski 8 жил өмнө
parent
commit
54090a4ed7
100 өөрчлөгдсөн 2119 нэмэгдсэн , 2092 устгасан
  1. 2 1
      .gitignore
  2. 0 5
      .travis.yml
  3. 0 15
      .travis/platform.sh
  4. 0 6
      .travis/setenv_lua.sh
  5. 0 125
      .travis/setup_lua.sh
  6. 19 6
      Makefile
  7. 13 2
      Makefile.win
  8. 3 1
      README.md
  9. 8 7
      appveyor.yml
  10. 23 0
      extra/CHANGES.txt
  11. 27 0
      extra/choco/haxe.nuspec
  12. 0 1
      extra/release-checklist.txt
  13. 1 1
      libs
  14. 5 5
      src/context/common.ml
  15. 2 0
      src/context/meta.ml
  16. 4 2
      src/generators/codegen.ml
  17. 1 1
      src/generators/genas3.ml
  18. 1 1
      src/generators/gencommon.ml
  19. 24 12
      src/generators/gencpp.ml
  20. 1 1
      src/generators/gencs.ml
  21. 183 66
      src/generators/genhl.ml
  22. 1 1
      src/generators/genjava.ml
  23. 3 3
      src/generators/genjs.ml
  24. 14 14
      src/generators/genlua.ml
  25. 1 1
      src/generators/genneko.ml
  26. 20 15
      src/generators/genphp.ml
  27. 251 68
      src/generators/genphp7.ml
  28. 1 1
      src/generators/genpy.ml
  29. 1 1
      src/generators/genswf.ml
  30. 1 1
      src/generators/genswf9.ml
  31. 1 1
      src/generators/genxml.ml
  32. 1146 954
      src/generators/hl2c.ml
  33. 13 4
      src/generators/hlcode.ml
  34. 37 20
      src/generators/hlinterp.ml
  35. 1 5
      src/generators/hlopt.ml
  36. 1 1
      src/json.ml
  37. 2 2
      src/macro/hlmacro.ml
  38. 59 366
      src/macro/interp.ml
  39. 5 2
      src/macro/macroApi.ml
  40. 1 1
      src/macro/macroContext.ml
  41. 5 5
      src/main.ml
  42. 28 247
      src/optimization/analyzer.ml
  43. 26 25
      src/optimization/analyzerConfig.ml
  44. 22 7
      src/optimization/analyzerTexpr.ml
  45. 1 1
      src/optimization/analyzerTexprTransformer.ml
  46. 1 2
      src/optimization/analyzerTypes.ml
  47. 26 2
      src/optimization/dce.ml
  48. 3 3
      src/optimization/filters.ml
  49. 16 6
      src/optimization/optimizer.ml
  50. 4 1
      src/server.ml
  51. 1 1
      src/syntax/ast.ml
  52. 1 1
      src/syntax/lexer.mll
  53. 2 1
      src/syntax/parser.ml
  54. 1 1
      src/typing/matcher.ml
  55. 1 1
      src/typing/type.ml
  56. 1 1
      src/typing/typecore.ml
  57. 11 5
      src/typing/typeload.ml
  58. 28 21
      src/typing/typer.ml
  59. 1 1
      std/Any.hx
  60. 1 1
      std/Array.hx
  61. 1 1
      std/Class.hx
  62. 1 1
      std/Date.hx
  63. 1 1
      std/DateTools.hx
  64. 1 1
      std/EReg.hx
  65. 1 1
      std/Enum.hx
  66. 1 1
      std/EnumValue.hx
  67. 1 1
      std/IntIterator.hx
  68. 1 1
      std/Lambda.hx
  69. 1 1
      std/List.hx
  70. 1 1
      std/Map.hx
  71. 2 2
      std/Math.hx
  72. 1 1
      std/Reflect.hx
  73. 1 1
      std/Std.hx
  74. 1 1
      std/StdTypes.hx
  75. 1 1
      std/String.hx
  76. 1 1
      std/StringBuf.hx
  77. 1 1
      std/StringTools.hx
  78. 1 1
      std/Sys.hx
  79. 1 1
      std/Type.hx
  80. 1 1
      std/UInt.hx
  81. 1 1
      std/Xml.hx
  82. 1 1
      std/cpp/ArrayBase.hx
  83. 1 1
      std/cpp/AutoCast.hx
  84. 1 1
      std/cpp/Callable.hx
  85. 1 1
      std/cpp/CastCharStar.hx
  86. 1 1
      std/cpp/Char.hx
  87. 1 1
      std/cpp/ConstCharStar.hx
  88. 1 1
      std/cpp/ConstPointer.hx
  89. 1 1
      std/cpp/FILE.hx
  90. 1 1
      std/cpp/FastIterator.hx
  91. 1 1
      std/cpp/Float32.hx
  92. 1 1
      std/cpp/Float64.hx
  93. 1 1
      std/cpp/Function.hx
  94. 1 1
      std/cpp/Int16.hx
  95. 1 1
      std/cpp/Int32.hx
  96. 1 1
      std/cpp/Int64.hx
  97. 1 1
      std/cpp/Int8.hx
  98. 1 1
      std/cpp/Lib.hx
  99. 4 1
      std/cpp/NativeArray.hx
  100. 20 0
      std/cpp/NativeSocket.hx

+ 2 - 1
.gitignore

@@ -92,4 +92,5 @@ tests/misc/projects/Issue4070/cpp/
 /tests/misc/eventLoop/php
 *.vscode/
 
-/tests/sys/temp
+/tests/sys/temp
+*.dll

+ 0 - 5
.travis.yml

@@ -15,9 +15,6 @@ env:
     - PPA="ppa:haxe/snapshots"
     - DEBFULLNAME="Haxe CI Bot"
     - DEBEMAIL="[email protected]"
-    # lua specific versions
-    - LUAROCKS=2.3.0
-    - LUA=lua5.2
 
 sudo: required
 dist: trusty
@@ -87,8 +84,6 @@ install_osx: &install_osx
   - ls -l out
   - export PATH="$PATH:$TRAVIS_BUILD_DIR"
   - export HAXE_STD_PATH="$TRAVIS_BUILD_DIR/std"
-  # Install pip (used in lua test)
-  - curl https://bootstrap.pypa.io/get-pip.py -o - | sudo python
 
 matrix:
   include:

+ 0 - 15
.travis/platform.sh

@@ -1,15 +0,0 @@
-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

+ 0 - 6
.travis/setenv_lua.sh

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

+ 0 - 125
.travis/setup_lua.sh

@@ -1,125 +0,0 @@
-#! /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 -o xtrace
-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

+ 19 - 6
Makefile

@@ -24,16 +24,26 @@ EXTENSION=
 OCAMLOPT?=ocamlopt
 OCAMLC?=ocamlc
 LFLAGS=
+STATICLINK?=0
 
 CFLAGS= -bin-annot
-ALL_CFLAGS= $(CFLAGS) -g -w -3 -I libs/extlib -I libs/extc -I libs/neko -I libs/javalib -I libs/ziplib -I libs/swflib -I libs/xml-light -I libs/ttflib -I libs/ilib -I libs/objsize \
+ALL_CFLAGS= $(CFLAGS) -g -w -3 -I libs/extlib -I libs/extc -I libs/neko -I libs/javalib -I libs/ziplib -I libs/swflib -I libs/xml-light -I libs/ttflib -I libs/ilib -I libs/objsize -I libs/pcre \
 	-I src -I src/context -I src/generators -I src/macro -I src/optimization -I src/syntax -I src/typing -I src/display
 
 LIBS=unix str libs/extlib/extLib libs/xml-light/xml-light libs/swflib/swflib \
 	libs/extc/extc libs/neko/neko libs/javalib/java libs/ziplib/zip \
-	libs/ttflib/ttf libs/ilib/il libs/objsize/objsize
+	libs/ttflib/ttf libs/ilib/il libs/objsize/objsize libs/pcre/pcre
 
-NATIVE_LIBS=-cclib libs/extc/extc_stubs.o -cclib libs/extc/process_stubs.o -cclib -lz -cclib libs/objsize/c_objsize.o
+
+ifneq ($(STATICLINK),0)
+LIB_PARAMS= -cclib '-Wl,-Bstatic -lpcre -lz -Wl,-Bdynamic '
+
+else
+LIB_PARAMS?= -cclib -lpcre -cclib -lz
+
+endif
+
+NATIVE_LIBS=-cclib libs/extc/extc_stubs.o -cclib libs/extc/process_stubs.o -cclib libs/objsize/c_objsize.o -cclib libs/pcre/pcre_stubs.o -ccopt -L/usr/local/lib $(LIB_PARAMS)
 
 ifeq ($(BYTECODE),1)
 	TARGET_FLAG = bytecode
@@ -77,6 +87,7 @@ COMMIT_DATE=$(shell \
 	fi \
 )
 PACKAGE_FILE_NAME=haxe_$(COMMIT_DATE)_$(COMMIT_SHA)
+HAXE_VERSION=$(shell $(OUTPUT) -version 2>&1 | awk '{print $$1;}')
 
 # using $(CURDIR) on Windows will not work since it might be a Cygwin path
 ifdef SYSTEMROOT
@@ -98,6 +109,7 @@ libs:
 	make -C libs/xml-light OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
 	make -C libs/ttflib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
 	make -C libs/objsize OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/pcre OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
 
 haxe: $(MODULES:%=src/%.$(MODULE_EXT))
 	$(COMPILER) -o $(OUTPUT) $(NATIVE_LIBS) $(NATIVE_LIB_FLAG) $(LFLAGS) $(LIBS:=.$(LIB_EXT)) $(MODULES:%=src/%.$(MODULE_EXT))
@@ -182,7 +194,7 @@ src/generators/hlinterp.$(MODULE_EXT): src/context/common.$(MODULE_EXT) src/gene
 
 src/generators/genphp7.$(MODULE_EXT): src/typing/abstract.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/context/meta.$(MODULE_EXT) src/path.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/context/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
 
-src/generators/hl2c.$(MODULE_EXT): src/generators/hlcode.$(MODULE_EXT)
+src/generators/hl2c.$(MODULE_EXT): src/generators/hlcode.$(MODULE_EXT) src/context/common.$(MODULE_EXT)
 
 src/generators/hlopt.$(MODULE_EXT): src/generators/hlcode.$(MODULE_EXT)
 
@@ -194,7 +206,7 @@ src/generators/genxml.$(MODULE_EXT): src/globals.$(MODULE_EXT) src/context/meta.
 
 # macro
 
-src/macro/interp.$(MODULE_EXT): src/typing/abstract.$(MODULE_EXT) src/context/meta.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/typing/error.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/path.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/generators/genneko.$(MODULE_EXT) src/context/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/generators/genswf.$(MODULE_EXT) src/generators/genjava.$(MODULE_EXT) src/generators/gencs.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT) src/macro/macroApi.$(MODULE_EXT)
+src/macro/interp.$(MODULE_EXT): src/typing/abstract.$(MODULE_EXT) src/context/meta.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/typing/error.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/path.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/generators/genneko.$(MODULE_EXT) src/context/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/generators/genswf.$(MODULE_EXT) src/generators/genjava.$(MODULE_EXT) src/generators/gencs.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT) src/macro/macroApi.$(MODULE_EXT) libs/pcre/pcre.$(LIB_EXT)
 
 src/macro/macroContext.$(MODULE_EXT): src/typing/abstract.$(MODULE_EXT) src/context/meta.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/typing/error.$(MODULE_EXT) src/optimization/optimizerTexpr.$(MODULE_EXT) src/typing/overloads.$(MODULE_EXT) src/path.$(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/context/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/optimization/filters.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT) src/display/display.$(MODULE_EXT) src/macro/hlmacro.$(MODULE_EXT) src/macro/macroApi.$(MODULE_EXT)
 
@@ -208,7 +220,7 @@ src/optimization/analyzer.$(MODULE_EXT): src/context/meta.$(MODULE_EXT) src/glob
 
 src/optimization/analyzerConfig.$(MODULE_EXT): src/context/meta.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/context/common.$(MODULE_EXT)
 
-src/optimization/analyzerTexpr.$(MODULE_EXT): src/typing/abstract.$(MODULE_EXT) src/context/meta.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/typing/error.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/context/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/optimization/analyzerConfig.$(MODULE_EXT) src/optimization/optimizerTexpr.$(MODULE_EXT)
+src/optimization/analyzerTexpr.$(MODULE_EXT): src/typing/abstract.$(MODULE_EXT) src/context/meta.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/typing/error.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/context/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/optimization/analyzerConfig.$(MODULE_EXT) src/optimization/optimizerTexpr.$(MODULE_EXT) src/generators/genphp7.$(MODULE_EXT)
 
 src/optimization/analyzerTexprTransformer.$(MODULE_EXT): src/context/meta.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/typing/error.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/context/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/optimization/analyzerConfig.$(MODULE_EXT) src/optimization/analyzerTypes.$(MODULE_EXT) src/optimization/analyzerTexpr.$(MODULE_EXT)
 
@@ -318,6 +330,7 @@ clean_libs:
 	make -C libs/xml-light clean
 	make -C libs/ttflib clean
 	make -C libs/objsize clean
+	make -C libs/pcre clean
 
 clean_haxe:
 	rm -f -r  $(MODULES:%=src/%.obj) $(MODULES:%=src/%.o) $(MODULES:%=src/%.cmx) $(MODULES:%=src/%.cmi) $(MODULES:%=src/%.cmo) $(MODULES:%=src/%.cmt) src/syntax/lexer.ml src/version.ml $(OUTPUT)

+ 13 - 2
Makefile.win

@@ -36,17 +36,28 @@ CC_CMD=($(OCAMLOPT) $(ALL_CFLAGS) -c $< 2>tmp.cmi && $(FILTER)) || ($(FILTER) &&
 CC_PARSER_CMD=($(OCAMLOPT) -pp camlp4o $(ALL_CFLAGS) -c src/syntax/parser.ml 2>tmp.cmi && $(FILTER)) || ($(FILTER) && exit 1)
 endif
 
+PACKAGE_FILES=$(OUTPUT) haxelib$(EXTENSION) std "$$(cygpath -w "$$(which zlib1.dll)")" "$$(cygpath -w "$$(which libpcre-1.dll)")"
+
 package_win:
 	mkdir -p out
 	rm -rf $(PACKAGE_FILE_NAME) $(PACKAGE_FILE_NAME).zip temp.zip
 	# Copy the package contents to $(PACKAGE_FILE_NAME)
 	# Using poor man's cp (zip then unzip), because cp in cygwin is quite broken
 	mkdir -p $(PACKAGE_FILE_NAME)
-	7z a -y -tzip -mx0 temp.zip $(OUTPUT) haxelib$(EXTENSION) std > log.txt || type log.txt
+	7z a -y -tzip -mx0 temp.zip $(PACKAGE_FILES) > log.txt || type log.txt
 	cd extra && 7z a -y -tzip -mx0 ../temp.zip LICENSE.txt CONTRIB.txt CHANGES.txt > log.txt || type log.txt
 	7z x -y temp.zip -o$(PACKAGE_FILE_NAME) > log.txt || type log.txt
 	rm temp.zip
 	# archive
 	7z a -r -tzip out/$(PACKAGE_FILE_NAME)_bin.zip $(PACKAGE_FILE_NAME) > log.txt || type log.txt
 	rm -r $(PACKAGE_FILE_NAME)
-	rm log.txt extra/log.txt
+	rm log.txt extra/log.txt
+
+package_choco:
+	mkdir -p OUTPUT
+	7z x -y out/$(PACKAGE_FILE_NAME)_bin.zip -oout > log.txt || type log.txt
+	mv out/$(PACKAGE_FILE_NAME) out/choco
+	sed -e 's/@SNAPSHOT_VERSION@/$(HAXE_VERSION)-SNAP$(COMMIT_DATE)/g' extra/choco/haxe.nuspec > out/choco/haxe.nuspec
+	cd out/choco && choco pack
+	mv out/choco/haxe.*.nupkg out
+	rm -rf out/choco

+ 3 - 1
README.md

@@ -23,6 +23,7 @@ Haxe allows you to compile for the following targets:
  * PHP
  * Python
  * Lua
+ * [HashLink](http://hashlink.haxe.org/)
 
 You can try Haxe directly from your browser at [try.haxe.org](http://try.haxe.org)!
 
@@ -40,7 +41,7 @@ For the complete Haxe licenses, please see https://haxe.org/foundation/open-sour
 
 ## Installing Haxe
 
-The latest stable release is [Haxe 3.4.0-rc.2](https://haxe.org/download/). Pre-built binaries are available for your platform:
+The latest stable release is available at [https://haxe.org/download/](https://haxe.org/download/). Pre-built binaries are available for your platform:
 
  * **[Windows installer](https://haxe.org/download/file/latest/haxe-latest-win.exe/)**
  * **[Windows binaries](https://haxe.org/download/file/latest/haxe-latest-win.zip/)**
@@ -91,6 +92,7 @@ Haxe   | neko
 3.1.3  | 2.0.0
 3.2.0  | 2.0.0
 3.3.0  | 2.1.0
+3.4.0  | 2.1.0
 
 
 ## Contributing

+ 8 - 7
appveyor.yml

@@ -23,14 +23,14 @@ cache:
 
 install:
     - 'git submodule update --init --recursive'
+    - '%CYG_ROOT%/bin/bash -lc "echo initialize"'
     # Install ocaml
     - curl -fsS -o cygwin-setup.exe --retry 3 https://cygwin.com/setup-x86.exe
-    - 'cygwin-setup.exe -g -q -R "%CYG_ROOT%" -P make -P git -P mingw64-i686-zlib -P rsync -P patch -P diffutils -P curl -P unzip -P m4 -P perl -P mingw64-i686-gcc-core'
+    - 'cygwin-setup.exe -g -q -R "%CYG_ROOT%" -P make -P git -P mingw64-i686-zlib -P rsync -P patch -P diffutils -P curl -P unzip -P m4 -P perl -P mingw64-i686-gcc-core -P mingw64-i686-pcre'
     - if not exist "opam32.tar.xz" (
         curl -fsS -o opam32.tar.xz --retry 3 https://dl.dropboxusercontent.com/s/eo4igttab8ipyle/opam32.tar.xz
       )
     - 7z x "opam32.tar.xz" -so | 7z x -aoa -si -ttar
-    - '%CYG_ROOT%/bin/bash -lc "echo initialize"'
     - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && bash opam32/install.sh"'
     - '%CYG_ROOT%/bin/bash -lc "opam init mingw \"https://github.com/fdopen/opam-repository-mingw.git\" --comp 4.02.3+mingw32c --switch 4.02.3+mingw32c --auto-setup --yes"'
     - '%CYG_ROOT%/bin/bash -lc "opam install camlp4 --yes"'
@@ -41,21 +41,21 @@ install:
     - echo extension=php_sqlite3.dll >> C:\tools\php\php.ini
     - echo extension=php_openssl.dll >> C:\tools\php\php.ini
     - RefreshEnv
-    # do not use chocolatey's shim, which is buggy when processing arguments
-    # see https://github.com/chocolatey/shimgen/issues/27
-    - set PATH=C:\ProgramData\chocolatey\lib\neko;%PATH%
     - neko -version
     # setup python
     - cmd: mklink C:\Python34-x64\python3.exe C:\Python34-x64\python.exe
     - set PATH=%PATH%;C:\Python34-x64
+    # expose the dll files
+    - set "PATH=%PATH%;%CYG_ROOT%/usr/i686-w64-mingw32/sys-root/mingw/bin"
 
 build_script:
     - 'cd %APPVEYOR_BUILD_FOLDER%'
-    - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && make -s -f Makefile.win package_src"'
     - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && make -s -f Makefile.win"'
     - 'set PATH=%PATH%;%APPVEYOR_BUILD_FOLDER%'
     - 'set HAXEPATH=%APPVEYOR_BUILD_FOLDER%'
     - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && make -s -f Makefile.win package_bin"'
+    - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && make -s -f Makefile.win package_choco"'
+    - move out\haxe.*.nupkg .
     - dir %APPVEYOR_BUILD_FOLDER%\out
     - cd %APPVEYOR_BUILD_FOLDER%/tests/
     - mkdir "%HAXELIB_ROOT%"
@@ -73,4 +73,5 @@ test_script:
     - neko RunCi.n
 
 artifacts:
-    - path: out/*
+    - path: 'out/*.zip'
+    - path: '*.nupkg'

+ 23 - 0
extra/CHANGES.txt

@@ -1,3 +1,26 @@
+2017-01-31: 3.4.0
+
+	General improvements and optimizations:
+
+	all : support completion for static extensions (#5766)
+	all : removed neko dependency for macros, use PCRE instead
+	all : disabled analyzer optimizations by default, re-enable with -D analyzer-optimize
+	php7 : generate native `$v instanceof MyType` instead of `Std.is(v, MyType)` where possible for better performance
+	php7 : added @:phpNoConstructor meta for externs which do not have native php constructors and yet can be constructed
+	php7 : greatly reduced amount of generated tmp vars
+	php7 : `Array` performance improvements
+	hl : made various improvements
+
+	Bugfixes:
+
+	all : fixed `using` picking up non-static abstract functions (#5888)
+	all : fixed issue with side-effect detection when optimizing (#5911)
+	all : fixed issue with zlib bindings causing zlib_deflate errors (#5941)
+	php7 : Allow user-defined modules in `php` package (#5921)
+	php7 : Dereference some of `php.Syntax` methods if required (#5923)
+	php : fixed assigning a method of dynamic value to a variable (#5469)
+	php : fixed missing initialization of dynamic methods in classes with empty constructors (#4723)
+
 2016-12-24: 3.4.0-RC2
 
 	New features:

+ 27 - 0
extra/choco/haxe.nuspec

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
+    <metadata>
+        <id>haxe</id>
+        <version>@SNAPSHOT_VERSION@</version>
+        <title>Haxe</title>
+        <authors>Haxe Foundation</authors>
+        <owners>Haxe Foundation</owners>
+        <licenseUrl>http://haxe.org/foundation/open-source.html</licenseUrl>
+        <projectUrl>http://haxe.org/</projectUrl>
+        <docsUrl>http://haxe.org/manual/introduction.html</docsUrl>
+        <mailingListUrl>https://groups.google.com/forum/#!forum/haxelang</mailingListUrl>
+        <bugTrackerUrl>https://github.com/HaxeFoundation/haxe/issues</bugTrackerUrl>
+        <projectSourceUrl>https://github.com/HaxeFoundation/haxe</projectSourceUrl>
+        <packageSourceUrl>https://github.com/HaxeFoundation/haxe/tree/master/extra/choco</packageSourceUrl>
+        <iconUrl>http://haxe.org/img/haxe-logo.svg</iconUrl>
+        <requireLicenseAcceptance>false</requireLicenseAcceptance>
+        <summary>Haxe is an open source toolkit based on a modern, high level, strictly typed programming language, a cross-compiler, a complete cross-platform standard library and ways to access each platform's native capabilities.</summary>
+        <description>Haxe is an open source toolkit based on a modern, high level, strictly typed programming language, a cross-compiler, a complete cross-platform standard library and ways to access each platform's native capabilities.
+ 
+This package will install haxe and haxelib. After installation, you should run `haxelib setup &lt;path&gt;`, where `&lt;path&gt;` is the haxelib repository folder for placing third-party libraries. The folder should be created manually before running the command.</description>
+        <tags>haxe</tags>
+        <dependencies>
+            <dependency id="neko" />
+        </dependencies>
+    </metadata>
+</package>

+ 0 - 1
extra/release-checklist.txt

@@ -9,7 +9,6 @@
 - Make sure CHANGES.txt has a proper date set!
 - Make sure `version` in globals.ml has the correct value.
 - Update README.md:
-  - Installing Haxe: update "Latest stable version"
   - Version compatibility: add/update the Haxe/Neko version
 - Merge development branch into master.
 - Wait for Travis to greenlight master.

+ 1 - 1
libs

@@ -1 +1 @@
-Subproject commit 26d15367c229b93ef2346bf7876e681b58c18a65
+Subproject commit 5f7956d8a2f0a0d9b99339b793fb9a0a07288a20

+ 5 - 5
src/context/common.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -316,7 +316,7 @@ let get_signature com =
 		com.defines_signature <- Some s;
 		s
 
-let php7 com = com.platform = Php && PMap.exists "php7" com.defines
+let is_php7 com = com.platform = Php && PMap.exists "php7" com.defines
 
 module CompilationServer = struct
 	type cache = {
@@ -478,6 +478,7 @@ module Define = struct
 		| HaxeVer
 		| HxcppApiLevel
 		| HxcppGcGenerational
+		| HxcppDebugger
 		| IncludePrefix
 		| Interp
 		| JavaVer
@@ -498,7 +499,6 @@ module Define = struct
 		| NetworkSandbox
 		| NetVer
 		| NetTarget
-		| NoAnalyzer
 		| NoCompilation
 		| NoCOpt
 		| NoDeprecationWarnings
@@ -573,6 +573,7 @@ module Define = struct
 		| HaxeVer -> ("haxe_ver","The current Haxe version value")
 		| HxcppApiLevel -> ("hxcpp_api_level","Provided to allow compatibility between hxcpp versions")
 		| HxcppGcGenerational -> ("HXCPP_GC_GENERATIONAL","Experimental Garbage Collector")
+		| HxcppDebugger -> ("HXCPP_DEBUGGER","Include additional information for HXCPP_DEBUGGER")
 		| IncludePrefix -> ("include_prefix","prepend path to generated include files")
 		| Interp -> ("interp","The code is compiled to be run with --interp")
 		| JavaVer -> ("java_ver", "<version:5-7> Sets the Java version to be targeted")
@@ -593,7 +594,6 @@ module Define = struct
 		| NekoSource -> ("neko_source","Output neko source instead of bytecode")
 		| NekoV1 -> ("neko_v1","Keep Neko 1.x compatibility")
 		| NetworkSandbox -> ("network-sandbox","Use local network sandbox instead of local file access one")
-		| NoAnalyzer -> ("no-analyzer","Disable the static analyzer")
 		| NoCompilation -> ("no-compilation","Disable final compilation for Cs, Cpp and Java")
 		| NoCOpt -> ("no_copt","Disable completion optimization (for debug purposes)")
 		| NoDebug -> ("no_debug","Remove all debug macros from cpp output")
@@ -707,7 +707,7 @@ let get_config com =
 			pf_reserved_type_paths = [([],"Object");([],"Error")];
 		}
 	| Php ->
-		if php7 com then
+		if is_php7 com then
 			{
 				default_config with
 				pf_static = false;

+ 2 - 0
src/context/meta.ml

@@ -119,6 +119,7 @@ type strict_meta =
 	| PhpGlobal
 	| PhpClassConst
 	| PhpMagic
+	| PhpNoConstructor
 	| PrivateAccess
 	| Property
 	| Protected
@@ -312,6 +313,7 @@ let get_info = function
 	| PhpGlobal -> ":phpGlobal",("(php7) Puts the static fields of a class in the global PHP namespace",[Platforms [Php;Php];UsedOn TClass])
 	| PhpClassConst -> ":phpClassConst",("(php7)  Generate static var of an extern class as a PHP class constant",[Platform Php;UsedOn TClass])
 	| PhpMagic -> ":phpMagic",("(php7) Treat annotated field as special PHP magic field",[Platform Php;UsedOn TClassField])
+	| PhpNoConstructor -> ":phpNoConstructor",("(php7) Special meta for extern classes which does not have native constructor in PHP, but need a constructor in Haxe extern",[Platform Php;UsedOn TClass])
 	| Public -> ":public",("Marks a class field as being public",[UsedOn TClassField;UsedInternally])
 	| PublicFields -> ":publicFields",("Forces all class fields of inheriting classes to be public",[UsedOn TClass])
 	| QuotedField -> ":quotedField",("Used internally to mark structure fields which are quoted in syntax",[UsedInternally])

+ 4 - 2
src/generators/codegen.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -365,7 +365,7 @@ let rec find_field com c f =
 		| Some (c,_) ->
 			find_field com c f)
 	with Not_found -> try
-		if com.platform = Cpp then (* Cpp uses delegation for interfaces *)
+		if com.platform = Cpp || com.platform = Hl then (* uses delegation for interfaces *)
 			raise Not_found;
 		let rec loop = function
 			| [] ->
@@ -531,6 +531,8 @@ module Dump = struct
 		| [] -> assert false
 		| d :: [] ->
 			let d = make_valid_filename d in
+			let maxlen = 200 - String.length ext in
+			let d = if String.length d > maxlen then String.sub d 0 maxlen else d in
 			let ch = open_out (String.concat "/" (List.rev (d :: acc)) ^ ext) in
 			ch
 		| d :: l ->

+ 1 - 1
src/generators/genas3.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 1 - 1
src/generators/gencommon.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 24 - 12
src/generators/gencpp.ml

@@ -1,6 +1,6 @@
 (*
    The Haxe Compiler
-   Copyright (C) 2005-2016  Haxe Foundation
+   Copyright (C) 2005-2017  Haxe Foundation
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
@@ -221,7 +221,16 @@ let new_header_file common_ctx base_dir =
 
 
 (* CPP code generation context *)
-
+(*
+  ctx_debug_level
+    0 = no debug
+    1 = function + line debug via macros, which can be activated at cpp compile-time
+    2 = include macros for HXCPP_DEBUGGER
+    3 = annotate source with additional info about AST and types
+    4 = console output at haxe compile-time
+
+   normal = 1
+*)
 type context =
 {
    ctx_common : Common.context;
@@ -247,6 +256,7 @@ type context =
 
 let new_context common_ctx debug file_info member_types =
 let null_file = new source_writer common_ctx ignore ignore (fun () -> () ) in
+let has_def def = Common.defined_value_safe common_ctx def <>""  in
 let result =
 {
    ctx_common = common_ctx;
@@ -257,7 +267,9 @@ let result =
    ctx_output = (null_file#write);
    ctx_interface_slot = ref (Hashtbl.create 0);
    ctx_interface_slot_count = ref 2;
-   ctx_debug_level = if Common.defined_value_safe common_ctx Define.AnnotateSource <>"" then 2 else debug;
+   ctx_debug_level = if has_def Define.AnnotateSource then 3 else
+                     if has_def Define.HxcppDebugger then 2 else
+                        debug;
    ctx_real_this_ptr = true;
    ctx_class_member_types =  member_types;
    ctx_file_info = file_info;
@@ -1346,7 +1358,7 @@ let hx_stack_push ctx output clazz func_name pos gc_stack =
       if ctx.ctx_is_header then
          ctx.ctx_writer#write_h_unique ("HX_DECLARE_STACK_FRAME" ^ "(" ^ varName ^ ")\n")
       else
-         ctx.ctx_writer#write_h_unique ("HX_DEFINE_STACK_FRAME" ^ "(" ^ decl ^ ")\n");
+         ctx.ctx_writer#write_h_unique ( (if func_name="new" then "HX_DEFINE_STACK_FRAME" else "HX_LOCAL_STACK_FRAME") ^ "(" ^ decl ^ ")\n");
       output ( (if gc_stack then "HX_GC_STACKFRAME" else "HX_STACKFRAME") ^ "(&" ^ varName ^ ")\n");
    end else if gc_stack then
       output ("HX_JUST_GC_STACKFRAME\n")
@@ -2175,7 +2187,7 @@ let cpp_var_debug_name_of v =
 
 
 let cpp_no_debug_synbol ctx var =
-   (ctx.ctx_debug_level=0) || (has_meta_key var.v_meta Meta.CompilerGenerated) ||
+   (ctx.ctx_debug_level<=1) || (has_meta_key var.v_meta Meta.CompilerGenerated) ||
       match cpp_type_of ctx var.v_type with
       | TCppStar _ | TCppReference _ -> true
       | TCppInst (class_def) when (has_meta_key class_def.cl_meta Meta.StructAccess) -> true
@@ -3805,7 +3817,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args injection
       | CppCastNative(expr) ->
          out "("; gen expr; out ").mPtr"
       );
-      if (ctx.ctx_debug_level > 1) then
+      if (ctx.ctx_debug_level >= 3) then
          out ("/* " ^ (s_tcpp expr.cppexpr) ^ ":" ^ tcpp_to_string expr.cpptype ^ " */")
 
    and gen expr =
@@ -3921,7 +3933,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args injection
       let prologue = function gc_stack ->
           cpp_gen_default_values ctx closure.close_args "__o_";
           hx_stack_push ctx output_i class_name func_name closure.close_expr.cpppos gc_stack;
-          if (ctx.ctx_debug_level>0) then begin
+          if (ctx.ctx_debug_level>=2) then begin
              if (closure.close_this != None) then
                 output_i ("HX_STACK_THIS(__this.mPtr)\n");
              List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (cpp_var_name_of v) ^ ",\"" ^ (cpp_debug_name_of v) ^"\")\n") )
@@ -3955,7 +3967,7 @@ let gen_cpp_function_body ctx clazz is_static func_name function_def head_code t
       let output_i = fun s -> output (spacer ^ s) in
       ctx_default_values ctx function_def.tf_args "__o_";
       hx_stack_push ctx output_i dot_name func_name function_def.tf_expr.epos gc_stack;
-      if ctx.ctx_debug_level >0 then begin
+      if ctx.ctx_debug_level >= 2 then begin
          if (not is_static)
             then output_i ("HX_STACK_THIS(" ^ (if ctx.ctx_real_this_ptr then "this" else "__this") ^")\n");
          List.iter (fun (v,_) -> if not (cpp_no_debug_synbol ctx v) then
@@ -7335,7 +7347,7 @@ let generate_cppia ctx =
       | TClassDecl class_def ->
          let is_internal = is_internal_class class_def.cl_path in
          if (is_internal || (is_macro class_def.cl_meta)) then
-            ( if (debug>1) then print_endline (" internal class " ^ (join_class_path class_def.cl_path ".") ))
+            ( if (debug>=4) then print_endline (" internal class " ^ (join_class_path class_def.cl_path ".") ))
          else begin
             generate_script_class common_ctx script class_def
          end
@@ -7343,11 +7355,11 @@ let generate_cppia ctx =
       | TEnumDecl enum_def ->
          let is_internal = is_internal_class enum_def.e_path in
          if (is_internal) then
-            (if (debug>1) then print_endline (" internal enum " ^ (join_class_path enum_def.e_path ".") ))
+            (if (debug>=4) then print_endline (" internal enum " ^ (join_class_path enum_def.e_path ".") ))
          else begin
             let meta = Codegen.build_metadata common_ctx object_def in
             if (enum_def.e_extern) then
-               (if (debug>1) then print_endline ("external enum " ^  (join_class_path enum_def.e_path ".") ));
+               (if (debug>=4) then print_endline ("external enum " ^  (join_class_path enum_def.e_path ".") ));
             generate_script_enum common_ctx script enum_def meta
          end
       | TTypeDecl _ | TAbstractDecl _ -> (* already done *) ()
@@ -7408,7 +7420,7 @@ let generate_source ctx =
          let name =  class_text class_def.cl_path in
          let is_internal = is_internal_class class_def.cl_path in
          if (is_internal || (is_macro class_def.cl_meta)) then
-            ( if (debug>1) then print_endline (" internal class " ^ name ))
+            ( if (debug>=4) then print_endline (" internal class " ^ name ))
          else begin
             let rec makeId class_name seed =
                let id = gen_hash32 seed class_name in

+ 1 - 1
src/generators/gencs.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 183 - 66
src/generators/genhl.ml

@@ -46,6 +46,8 @@ type allocator = {
 	mutable a_hold : int list;
 }
 
+type lassign = (string index * int * int)
+
 type method_context = {
 	mid : int;
 	mregs : (int, ttype) lookup;
@@ -60,8 +62,10 @@ type method_context = {
 	mutable mcontinues : (int -> unit) list;
 	mutable mbreaks : (int -> unit) list;
 	mutable mtrys : int;
+	mutable mloop_trys : int;
 	mutable mcaptreg : int;
 	mutable mcurpos : Globals.pos;
+	mutable massign : lassign list;
 }
 
 type array_impl = {
@@ -104,6 +108,8 @@ type context = {
 	core_enum : tclass;
 	ref_abstract : tabstract;
 	cdebug_files : (string, string) lookup;
+	cdebug_locals : (string, string ) lookup;
+	cdebug_assigns : (lassign array) DynArray.t;
 }
 
 (* --- *)
@@ -111,7 +117,7 @@ type context = {
 type access =
 	| ANone
 	| AGlobal of global
-	| ALocal of reg
+	| ALocal of tvar * reg
 	| AStaticVar of global * ttype * field index
 	| AStaticFun of fundecl index
 	| AInstanceFun of texpr * fundecl index
@@ -224,9 +230,11 @@ let method_context id t captured hasthis =
 		mhasthis = hasthis;
 		mcaptured = captured;
 		mtrys = 0;
+		mloop_trys = 0;
 		mcaptreg = 0;
 		mdebug = DynArray.create();
 		mcurpos = Globals.null_pos;
+		massign = [];
 	}
 
 let field_name c f =
@@ -527,6 +535,7 @@ and class_type ?(tref=None) ctx c pl statics =
 			pfunctions = PMap.empty;
 			pnfields = -1;
 			pinterfaces = PMap.empty;
+			pbindings = [];
 		} in
 		let t = HObj p in
 		(match tref with
@@ -556,7 +565,7 @@ and class_type ?(tref=None) ctx c pl statics =
 		let todo = ref [] in
 		List.iter (fun f ->
 			if is_extern_field f || (statics && f.cf_name = "__meta__") then () else
-			match f.cf_kind with
+			let fid = (match f.cf_kind with
 			| Method m when m <> MethDynamic && not statics ->
 				let g = alloc_fid ctx c f in
 				p.pfunctions <- PMap.add f.cf_name g p.pfunctions;
@@ -572,9 +581,10 @@ and class_type ?(tref=None) ctx c pl statics =
 				end else
 					None
 				in
-				DynArray.add pa { fname = f.cf_name; fid = alloc_string ctx f.cf_name; fmethod = g; fvirtual = virt; }
+				DynArray.add pa { fname = f.cf_name; fid = alloc_string ctx f.cf_name; fmethod = g; fvirtual = virt; };
+				None
 			| Method MethDynamic when List.exists (fun ff -> ff.cf_name = f.cf_name) c.cl_overrides ->
-				()
+				Some (try fst (get_index f.cf_name p) with Not_found -> assert false)
 			| _ ->
 				let fid = DynArray.length fa in
 				p.pindex <- PMap.add f.cf_name (fid + start_field, t) p.pindex;
@@ -584,6 +594,11 @@ and class_type ?(tref=None) ctx c pl statics =
 					p.pindex <- PMap.add f.cf_name (fid + start_field, t) p.pindex;
 					Array.set p.pfields fid (f.cf_name, alloc_string ctx f.cf_name, t)
 				) :: !todo;
+				Some (fid + start_field)
+			) in
+			match f.cf_kind, fid with
+			| Method _, Some fid -> p.pbindings <- (fid, alloc_fun_path ctx c.cl_path f.cf_name) :: p.pbindings
+			| _ -> ()
 		) (if statics then c.cl_ordered_statics else c.cl_ordered_fields);
 		if not statics then begin
 			(* add interfaces *)
@@ -600,6 +615,11 @@ and class_type ?(tref=None) ctx c pl statics =
 				DynArray.add pa { fname = "__string"; fid = alloc_string ctx "__string"; fmethod = alloc_fun_path ctx c.cl_path "__string"; fvirtual = None; }
 			with Not_found ->
 				());
+		end else begin
+			(match c.cl_constructor with
+			| Some f when not (is_extern_field f) ->
+				p.pbindings <- ((try fst (get_index "__constructor__" p) with Not_found -> assert false),alloc_fid ctx c f) :: p.pbindings
+			| _ -> ());
 		end;
 		p.pnfields <- DynArray.length fa + start_field;
 		p.pfields <- DynArray.to_array fa;
@@ -655,6 +675,7 @@ and enum_class ctx e =
 			pfunctions = PMap.empty;
 			pnfields = -1;
 			pinterfaces = PMap.empty;
+			pbindings = [];
 		} in
 		let t = HObj p in
 		ctx.cached_types <- PMap.add cpath t ctx.cached_types;
@@ -888,6 +909,24 @@ let common_type ctx e1 e2 for_eq p =
 let captured_index ctx v =
 	if not v.v_capture then None else try Some (PMap.find v.v_id ctx.m.mcaptured.c_map) with Not_found -> None
 
+let real_name v =
+	let rec loop = function
+		| [] -> v.v_name
+		| (Meta.RealPath,[EConst (String name),_],_) :: _ -> name
+		| _ :: l -> loop l
+	in
+	loop v.v_meta
+
+let add_assign ctx v r =
+	let name = real_name v in
+	ctx.m.massign <- (lookup ctx.cdebug_locals name (fun() -> name), DynArray.length ctx.m.mops, r) :: ctx.m.massign
+
+let add_capture ctx r =
+	Array.iter (fun v ->
+		let name = real_name v in
+		ctx.m.massign <- (lookup ctx.cdebug_locals name (fun() -> name), -1, r) :: ctx.m.massign
+	) ctx.m.mcaptured.c_vars
+
 let before_return ctx =
 	let rec loop i =
 		if i > 0 then begin
@@ -897,6 +936,15 @@ let before_return ctx =
 	in
 	loop ctx.m.mtrys
 
+let before_break_continue ctx =
+	let rec loop i =
+		if i > 0 then begin
+			op ctx (OEndTrap false);
+			loop (i - 1)
+		end
+	in
+	loop (ctx.m.mtrys - ctx.m.mloop_trys)
+
 let type_value ctx t p =
 	match t with
 	| TClassDecl c ->
@@ -1182,7 +1230,7 @@ and get_access ctx e =
 			| t -> AGlobal (alloc_global ctx (efield_name e ef) (to_type ctx t))))
 	| TLocal v ->
 		(match captured_index ctx v with
-		| None -> ALocal (alloc_var ctx v false)
+		| None -> ALocal (v, alloc_var ctx v false)
 		| Some idx -> ACaptured idx)
 	| TParenthesis e ->
 		get_access ctx e
@@ -1379,7 +1427,8 @@ and eval_expr ctx e =
 			match captured_index ctx v with
 			| None ->
 				let r = alloc_var ctx v true in
-				op ctx (OMov (r,ri))
+				op ctx (OMov (r,ri));
+				add_assign ctx v r;
 			| Some idx ->
 				op ctx (OSetEnumField (ctx.m.mcaptreg, idx, ri));
 		);
@@ -2088,9 +2137,10 @@ and eval_expr ctx e =
 				free ctx rthis;
 				op ctx (OSetField (rthis, fid, r));
 				r
-			| ALocal l ->
+			| ALocal (v,l) ->
 				let r = value() in
 				op ctx (OMov (l, r));
+				add_assign ctx v l;
 				r
 			| AArray (ra,(at,vt),ridx) ->
 				hold ctx ra;
@@ -2159,9 +2209,10 @@ and eval_expr ctx e =
 			r
 		| OpAssignOp bop ->
 			(match get_access ctx e1 with
-			| ALocal l ->
+			| ALocal (v,l) ->
 				let r = eval_to ctx { e with eexpr = TBinop (bop,e1,e2) } (to_type ctx e1.etype) in
 				op ctx (OMov (l, r));
+				add_assign ctx v l;
 				r
 			| acc ->
 				gen_assign_op ctx acc e1 (fun r ->
@@ -2221,13 +2272,15 @@ and eval_expr ctx e =
 				assert false
 		in
 		(match get_access ctx v, fix with
-		| ALocal r, Prefix ->
+		| ALocal (v,r), Prefix ->
 			unop r;
+			add_assign ctx v r;
 			r
-		| ALocal r, Postfix ->
+		| ALocal (v,r), Postfix ->
 			let r2 = alloc_tmp ctx (rtype ctx r) in
 			op ctx (OMov (r2,r));
 			unop r;
+			add_assign ctx v r;
 			r2
 		| acc, _ ->
 			let ret = ref 0 in
@@ -2270,9 +2323,10 @@ and eval_expr ctx e =
 		op ctx (OThrow (eval_to ctx v HDyn));
 		alloc_tmp ctx HDyn
 	| TWhile (cond,eloop,NormalWhile) ->
-		let oldb = ctx.m.mbreaks and oldc = ctx.m.mcontinues in
+		let oldb = ctx.m.mbreaks and oldc = ctx.m.mcontinues and oldtrys = ctx.m.mloop_trys in
 		ctx.m.mbreaks <- [];
 		ctx.m.mcontinues <- [];
+		ctx.m.mloop_trys <- ctx.m.mtrys;
 		let continue_pos = current_pos ctx in
 		let ret = jump_back ctx in
 		let j = jump_expr ctx cond false in
@@ -2283,11 +2337,13 @@ and eval_expr ctx e =
 		List.iter (fun f -> f continue_pos) ctx.m.mcontinues;
 		ctx.m.mbreaks <- oldb;
 		ctx.m.mcontinues <- oldc;
+		ctx.m.mloop_trys <- oldtrys;
 		alloc_tmp ctx HVoid
 	| TWhile (cond,eloop,DoWhile) ->
-		let oldb = ctx.m.mbreaks and oldc = ctx.m.mcontinues in
+		let oldb = ctx.m.mbreaks and oldc = ctx.m.mcontinues and oldtrys = ctx.m.mloop_trys in
 		ctx.m.mbreaks <- [];
 		ctx.m.mcontinues <- [];
+		ctx.m.mloop_trys <- ctx.m.mtrys;
 		let start = jump ctx (fun p -> OJAlways p) in
 		let continue_pos = current_pos ctx in
 		let ret = jump_back ctx in
@@ -2300,6 +2356,7 @@ and eval_expr ctx e =
 		List.iter (fun f -> f continue_pos) ctx.m.mcontinues;
 		ctx.m.mbreaks <- oldb;
 		ctx.m.mcontinues <- oldc;
+		ctx.m.mloop_trys <- oldtrys;
 		alloc_tmp ctx HVoid
 	| TCast (v,None) ->
 		let t = to_type ctx e.etype in
@@ -2456,11 +2513,13 @@ and eval_expr ctx e =
 		op ctx (OEnumField (r,eval_expr ctx ec,f.ef_index,index));
 		cast_to ctx r (to_type ctx e.etype) e.epos
 	| TContinue ->
+		before_break_continue ctx;
 		let pos = current_pos ctx in
 		op ctx (OJAlways (-1)); (* loop *)
 		ctx.m.mcontinues <- (fun target -> DynArray.set ctx.m.mops pos (OJAlways (target - (pos + 1)))) :: ctx.m.mcontinues;
 		alloc_tmp ctx HVoid
 	| TBreak ->
+		before_break_continue ctx;
 		let pos = current_pos ctx in
 		op ctx (OJAlways (-1)); (* loop *)
 		ctx.m.mbreaks <- (fun target -> DynArray.set ctx.m.mops pos (OJAlways (target - (pos + 1)))) :: ctx.m.mbreaks;
@@ -2711,6 +2770,7 @@ and gen_method_wrapper ctx rt t p =
 		} in
 		ctx.m <- old;
 		DynArray.add ctx.cfunctions f;
+		DynArray.add ctx.cdebug_assigns [||];
 		fid
 
 and make_fun ?gen_content ctx name fidx f cthis cparent =
@@ -2748,6 +2808,7 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 	let args = List.map (fun (v,o) ->
 		let t = to_type ctx v.v_type in
 		let r = alloc_var ctx (if o = None then v else { v with v_type = if not (is_nullable t) then TAbstract(ctx.ref_abstract,[v.v_type]) else v.v_type }) true in
+		add_assign ctx v r;
 		rtype ctx r
 	) f.tf_args in
 
@@ -2758,13 +2819,17 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 			let r = alloc_tmp ctx capt.c_type in
 			hold ctx r;
 			op ctx (OEnumAlloc (r,0));
+			add_capture ctx r;
+			r
+		| Some r ->
+			add_capture ctx r;
 			r
-		| Some r -> r
 	);
 
 	List.iter (fun (v, o) ->
 		let r = alloc_var ctx v false in
 		let vt = to_type ctx v.v_type in
+		let capt = captured_index ctx v in
 		(match o with
 		| None | Some TNull -> ()
 		| Some c when not (is_nullable vt) ->
@@ -2788,9 +2853,11 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 				| _ -> assert false)
 			| _ ->
 				assert false);
+			if capt = None then add_assign ctx v t;
 			let jend = jump ctx (fun n -> OJAlways n) in
 			j();
 			op ctx (OUnref (t,r));
+			if capt = None then add_assign ctx v t;
 			jend();
 			Hashtbl.replace ctx.m.mvars v.v_id t;
 			free ctx r;
@@ -2822,9 +2889,10 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 			| TString s ->
 				op ctx (OMov (r, make_string ctx s f.tf_expr.epos))
 			);
+			if capt = None then add_assign ctx v r;
 			j();
 		);
-		(match captured_index ctx v with
+		(match capt with
 		| None -> ()
 		| Some index ->
 			op ctx (OSetEnumField (ctx.m.mcaptreg, index, alloc_var ctx v false)));
@@ -2864,10 +2932,12 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 		code = DynArray.to_array ctx.m.mops;
 		debug = make_debug ctx ctx.m.mdebug;
 	} in
+	let assigns = Array.of_list (List.rev ctx.m.massign) in
 	ctx.m <- old;
 	Hashtbl.add ctx.defined_funs fidx ();
 	let f = if ctx.optimize then Hlopt.optimize ctx.dump_out f else f in
 	DynArray.add ctx.cfunctions f;
+	DynArray.add ctx.cdebug_assigns assigns;
 	capt
 
 let generate_static ctx c f =
@@ -2976,6 +3046,8 @@ let generate_static_init ctx types main =
 				let path = if c == ctx.array_impl.abase then [],"Array" else if c == ctx.base_class then [],"Class" else c.cl_path in
 
 				let g, ct = class_global ~resolve:false ctx c in
+				let ctype = if c == ctx.array_impl.abase then ctx.array_impl.aall else c in
+				let t = class_type ctx ctype (List.map snd ctype.cl_params) false in
 
 				let index name =
 					match ct with
@@ -2985,24 +3057,43 @@ let generate_static_init ctx types main =
 						assert false
 				in
 
-				let rc = alloc_tmp ctx ct in
-				op ctx (ONew rc);
-				op ctx (OSetGlobal (g,rc));
-				hold ctx rc;
+				let rc = (match t with
+				| HObj o when (match o.pclassglobal with None -> -1 | Some i -> i) <> g ->
+					(* manual registration for objects with prototype tricks (Array) *)
 
-				let rt = alloc_tmp ctx HType in
-				let ctype = if c == ctx.array_impl.abase then ctx.array_impl.aall else c in
-				op ctx (OType (rt, class_type ctx ctype (List.map snd ctype.cl_params) false));
-				op ctx (OSetField (rc,index "__type__",rt));
-				op ctx (OSetField (rc,index "__name__",eval_expr ctx { eexpr = TConst (TString (s_type_path path)); epos = c.cl_pos; etype = ctx.com.basic.tstring }));
+					let rc = alloc_tmp ctx ct in
+					op ctx (ONew rc);
+					op ctx (OSetGlobal (g,rc));
+					hold ctx rc;
 
-				let rname = alloc_tmp ctx HBytes in
-				op ctx (OString (rname, alloc_string ctx (s_type_path path)));
-				op ctx (OCall2 (alloc_tmp ctx HVoid, alloc_fun_path ctx ([],"Type") "register",rname,rc));
+					let rt = alloc_tmp ctx HType in
+					op ctx (OType (rt, t));
+					op ctx (OSetField (rc,index "__type__",rt));
+					op ctx (OSetField (rc,index "__name__",eval_expr ctx { eexpr = TConst (TString (s_type_path path)); epos = c.cl_pos; etype = ctx.com.basic.tstring }));
+
+					let rname = alloc_tmp ctx HBytes in
+					op ctx (OString (rname, alloc_string ctx (s_type_path path)));
+					op ctx (OCall2 (alloc_tmp ctx HVoid, alloc_fun_path ctx ([],"Type") "register",rname,rc));
+					rc
+
+				| _ ->
+
+					let rct = alloc_tmp ctx HType in
+					op ctx (OType (rct, ct));
+					hold ctx rct;
 
-				(match c.cl_constructor with
-				| Some f when not (is_extern_field f) -> op ctx (OSetMethod (rc,index "__constructor__",alloc_fid ctx c f))
-				| _ -> ());
+					let rt = alloc_tmp ctx HType in
+					op ctx (OType (rt, t));
+
+					let rname = alloc_tmp ctx HBytes in
+					op ctx (OString (rname, alloc_string ctx (s_type_path path)));
+
+					let rc = alloc_tmp ctx (class_type ctx ctx.base_class [] false) in
+					op ctx (OCall3 (rc, alloc_fun_path ctx ([],"Type") "initClass", rct, rt, rname));
+					hold ctx rc;
+					free ctx rct;
+					rc
+				) in
 
 				let gather_implements() =
 					let classes = ref [] in
@@ -3027,17 +3118,12 @@ let generate_static_init ctx types main =
 						op ctx (OSetArray (ra, reg_int ctx i, rt));
 					) l;
 					op ctx (OSetField (rc,index "__implementedBy__",ra));
-				end;
-
-				(* register static funs *)
 
-				List.iter (fun f ->
-					match f.cf_kind with
-					| Method _ when not (is_extern_field f) ->
-						op ctx (OSetMethod (rc,index f.cf_name,alloc_fid ctx c f));
-					| _ ->
-						()
-				) c.cl_ordered_statics;
+					(* TODO : use a plain class for interface object since we don't allow statics *)
+					let rt = alloc_tmp ctx ct in
+					op ctx (OSafeCast (rt, rc));
+					op ctx (OSetGlobal (g, rt));
+				end;
 
 				(match Codegen.build_metadata ctx.com (TClassDecl c) with
 				| None -> ()
@@ -3049,54 +3135,46 @@ let generate_static_init ctx types main =
 
 			| TEnumDecl e when not e.e_extern ->
 
-				let t = enum_class ctx e in
-				let g = alloc_global ctx (match t with HObj o -> o.pname | _ -> assert false) t in
+				let et = enum_class ctx e in
+				let t = enum_type ctx e in
+
+				let ret = alloc_tmp ctx HType in
+				op ctx (OType (ret, et));
+				hold ctx ret;
+				let rt = alloc_tmp ctx HType in
+				op ctx (OType (rt, t));
+				let r = alloc_tmp ctx (class_type ctx ctx.base_enum [] false) in
+				op ctx (OCall2 (r, alloc_fun_path ctx ([],"Type") "initEnum", ret, rt));
+				free ctx ret;
 
 				let index name =
-					match t with
+					match et with
 					| HObj o ->
 						fst (try get_index name o with Not_found -> assert false)
 					| _ ->
 						assert false
 				in
-				let r = alloc_tmp ctx t in
-				let rt = alloc_tmp ctx HType in
-				op ctx (ONew r);
-
-				let max_val = ref (-1) in
-				PMap.iter (fun _ c ->
-					match follow c.ef_type with
-					| TFun _ -> ()
-					| _ -> if c.ef_index > !max_val then max_val := c.ef_index;
-				) e.e_constrs;
 
 				let avalues = alloc_tmp ctx HArray in
-				op ctx (OType (rt, HDyn));
-				op ctx (OCall2 (avalues, alloc_std ctx "alloc_array" [HType;HI32] HArray, rt, reg_int ctx (!max_val + 1)));
+				op ctx (OField (avalues, r, index "__evalues__"));
 
 				List.iter (fun n ->
 					let f = PMap.find n e.e_constrs in
 					match follow f.ef_type with
 					| TFun _ -> ()
 					| _ ->
-						let t = to_type ctx f.ef_type in
 						let g = alloc_global ctx (efield_name e f) t in
 						let r = alloc_tmp ctx t in
-						op ctx (OMakeEnum (r,f.ef_index,[]));
+						let rd = alloc_tmp ctx HDyn in
+						op ctx (OGetArray (rd,avalues, reg_int ctx f.ef_index));
+						op ctx (OSafeCast (r, rd));
 						op ctx (OSetGlobal (g,r));
-						let d = alloc_tmp ctx HDyn in
-						op ctx (OToDyn (d,r));
-						op ctx (OSetArray (avalues, reg_int ctx f.ef_index, d));
 				) e.e_names;
 
-				op ctx (OType (rt, (to_type ctx (TEnum (e,List.map snd e.e_params)))));
-				op ctx (OCall3 (alloc_tmp ctx HVoid, alloc_fun_path ctx (["hl"],"Enum") "new",r,rt,avalues));
-
 				(match Codegen.build_metadata ctx.com (TEnumDecl e) with
 				| None -> ()
 				| Some e -> op ctx (OSetField (r,index "__meta__",eval_to ctx e HDyn)));
 
-				op ctx (OSetGlobal (g,r));
 
 			| TAbstractDecl { a_path = [], name; a_pos = pos } ->
 				(match name with
@@ -3338,8 +3416,10 @@ let write_code ch code debug =
 			| Some g -> write_index (g + 1));
 			write_index (Array.length p.pfields);
 			write_index (Array.length p.pproto);
+			write_index (List.length p.pbindings);
 			Array.iter (fun (_,n,t) -> write_index n; write_type t) p.pfields;
 			Array.iter (fun f -> write_index f.fid; write_index f.fmethod; write_index (match f.fvirtual with None -> -1 | Some i -> i)) p.pproto;
+			List.iter (fun (fid,fidx) -> write_index fid; write_index fidx) p.pbindings;
 		| HArray ->
 			byte 11
 		| HType ->
@@ -3493,6 +3573,8 @@ let create_context com is_macro dump =
 		method_wrappers = PMap.empty;
 		cdebug_files = new_lookup();
 		macro_typedefs = Hashtbl.create 0;
+		cdebug_locals = new_lookup();
+		cdebug_assigns = DynArray.create();
 	} in
 	ignore(alloc_string ctx "");
 	ignore(class_type ctx ctx.base_class [] false);
@@ -3583,17 +3665,52 @@ let generate com =
 		Hlinterp.check code false;
 	end;
 	let t = Common.timer ["write";"hl"] in
-	if file_extension com.file = "c" then
-		Hl2c.write_c com.Common.version com.file code
-	else begin
+
+	let escape_command s =
+		let b = Buffer.create 0 in
+		String.iter (fun ch -> if (ch=='"' || ch=='\\' ) then Buffer.add_string b "\\";  Buffer.add_char b ch) s;
+		"\"" ^ Buffer.contents b ^ "\""
+	in
+
+	if file_extension com.file = "c" then begin
+		Hl2c.write_c com com.file code;
+		let t = Common.timer ["nativecompile";"hl"] in
+		if not (Common.defined com Define.NoCompilation) && com.run_command ("haxelib run hashlink build " ^ escape_command com.file) <> 0 then failwith "Build failed";
+		t();
+	end else begin
 		let ch = IO.output_string() in
 		write_code ch code true;
 		let str = IO.close_out ch in
 		let ch = open_out_bin com.file in
 		output_string ch str;
 		close_out ch;
+(*
+		let ch = IO.output_string() in
+		let byte = IO.write_byte ch in
+		let write_index = write_index_gen byte in
+		write_index (DynArray.length ctx.cdebug_locals.arr);
+		DynArray.iter (fun s ->
+			write_index (String.length s);
+			IO.write_string ch s;
+		) ctx.cdebug_locals.arr;
+		write_index (DynArray.length ctx.cdebug_assigns);
+		DynArray.iter (fun a ->
+			write_index (Array.length a);
+			Array.iter (fun (i,p,r) ->
+				write_index i;
+				write_index p;
+				write_index r;
+			) a;
+		) ctx.cdebug_assigns;
+		let str = IO.close_out ch in
+		let dbg = open_out_bin (com.file ^ "d") in
+		output_string dbg str;
+		close_out dbg; *)
 	end;
 	t();
+	if Common.raw_defined com "run" then begin
+		if com.run_command ("haxelib run hashlink run " ^ escape_command com.file) <> 0 then failwith "Failed to run HL";
+	end;
 	if Common.defined com Define.Interp then
 		try
 			let ctx = Hlinterp.create true in

+ 1 - 1
src/generators/genjava.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 3 - 3
src/generators/genjs.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -1134,7 +1134,7 @@ let generate_class ctx c =
 			| _ when props = [] -> ()
 			| Some (csup,_) when Codegen.has_properties csup ->
 				newprop ctx;
-				let psup = s_path ctx csup.cl_path in
+				let psup = ctx.type_accessor (TClassDecl csup) in
 				print ctx "__properties__: $extend(%s.prototype.__properties__,{%s})" psup (gen_props props)
 			| _ ->
 				newprop ctx;
@@ -1282,7 +1282,7 @@ let alloc_ctx com =
 		smap = smap;
 		js_modern = not (Common.defined com Define.JsClassic);
 		js_flatten = not (Common.defined com Define.JsUnflatten);
-		es_version = int_of_string (Common.defined_value com Define.JsEs);
+		es_version = (try int_of_string (Common.defined_value com Define.JsEs) with _ -> 0);
 		store_exception_stack = if Common.has_dce com then (Common.has_feature com "haxe.CallStack.exceptionStack") else List.exists (function TClassDecl { cl_path=["haxe"],"CallStack" } -> true | _ -> false) com.types;
 		statics = [];
 		inits = [];

+ 14 - 14
src/generators/genlua.ml

@@ -1573,7 +1573,6 @@ let generate_class ctx c =
 		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;
@@ -1644,13 +1643,13 @@ let generate_enum ctx e =
 			print ctx "function(%s) local _x = _hx_tab_array({[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 " rawset(_x, 'toString', _estr);";
 			spr ctx " return _x; end ";
 			ctx.separator <- true;
 		| _ ->
 			println ctx "_hx_tab_array({[0]=\"%s\",%d,__enum__ = %s},2)" f.ef_name f.ef_index p;
 			if has_feature ctx "may_print_enum" then begin
-				println ctx "%s%s.toString = _estr" p (field f.ef_name);
+				println ctx "rawset(%s%s, 'toString', _estr)" p (field f.ef_name);
 			end;
 		);
 		newline ctx
@@ -1711,10 +1710,8 @@ let generate_type ctx = function
 		| 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. *)
+		(* A 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
@@ -1945,13 +1942,12 @@ let generate com =
 	List.iter (generate_type_forward ctx) com.types; newline ctx;
 
 	(* Generate some dummy placeholders for utility libs that may be required*)
-	println ctx "local _hx_bind, _hx_bit, _hx_staticToInstance, _hx_funcToField, _hx_maxn, _hx_print, _hx_apply_self, _hx_box_mr, _hx_bit_clamp, _hx_table";
+	println ctx "local _hx_bind, _hx_bit, _hx_staticToInstance, _hx_funcToField, _hx_maxn, _hx_print, _hx_apply_self, _hx_box_mr, _hx_bit_clamp, _hx_table, _hx_bit_raw";
 
 	List.iter (transform_multireturn ctx) com.types;
 	List.iter (generate_type ctx) com.types;
 
 	if has_feature ctx "use._bitop" || has_feature ctx "lua.Boot.clamp" then begin
-	    println ctx "local _hx_bit_raw = require 'bit32'";
 	    println ctx "_hx_bit_clamp = function(v) ";
 	    println ctx "  if v <= 2147483647 and v >= -2147483648 then";
 	    println ctx "    if v > 0 then return _G.math.floor(v)";
@@ -1959,13 +1955,17 @@ let generate com =
 	    println ctx "    end";
 	    println ctx "  end";
 	    println ctx "  if v > 2251798999999999 then v = v*2 end;";
-	    println ctx "  return _hx_bit_raw.band(v, 2147483647 ) - _hx_bit_raw.band(v, 2147483648)";
+	    println ctx "  if (v ~= v or math.abs(v) == _G.math.huge) then return nil end";
+	    println ctx "  return _hx_bit.band(v, 2147483647 ) - math.abs(_hx_bit.band(v, 2147483648))";
 	    println ctx "end";
-	    println ctx "if type(jit) == 'table' then";
-	    println ctx "  _hx_bit = setmetatable({},{__index = function(t,k) return function(...) return _hx_bit_clamp(rawget(_hx_bit_raw,k)(...)) end end})";
-	    println ctx "else";
-	    println ctx "  _hx_bit = setmetatable({}, { __index = _hx_bit_raw })";
-	    println ctx "  _hx_bit.bnot = function(...) return _hx_bit_clamp(_hx_bit_raw.bnot(...)) end";
+	    println ctx "pcall(require, 'bit')"; (* require this for lua 5.1 *)
+	    println ctx "if bit then";
+	    println ctx "  _hx_bit = bit";
+	    println ctx "elseif bit32 then";
+	    println ctx "  local _hx_bit_raw = bit32";
+	    println ctx "  _hx_bit = setmetatable({}, { __index = _hx_bit_raw });";
+	    println ctx "  _hx_bit.bnot = function(...) return _hx_bit_clamp(_hx_bit_raw.bnot(...)) end;"; (* lua 5.2  weirdness *)
+	    println ctx "  _hx_bit.bxor = function(...) return _hx_bit_clamp(_hx_bit_raw.bxor(...)) end;"; (* lua 5.2  weirdness *)
 	    println ctx "end";
 	end;
 

+ 1 - 1
src/generators/genneko.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 20 - 15
src/generators/genphp.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -996,12 +996,13 @@ and gen_while_expr ctx e =
 	ctx.in_loop <- old_loop
 
 and gen_tfield ctx e e1 s =
+	let name = (field_name s) in
 	match follow e.etype with
 	| TFun (args, _) ->
 		(if ctx.is_call then begin
-			gen_field_access ctx false e1 s
-	  	end else if is_in_dynamic_methods ctx e1 s then begin
-	  		gen_field_access ctx true e1 s;
+			gen_field_access ctx false e1 name
+	  	end else if is_in_dynamic_methods ctx e1 name then begin
+	  		gen_field_access ctx true e1 name;
 	  	end else begin
 			let ob ex =
 				(match ex with
@@ -1014,25 +1015,29 @@ and gen_tfield ctx e e1 s =
 
 			spr ctx "(property_exists(";
 			ob e1.eexpr;
-			print ctx ", \"%s\") ? " (s_ident s);
-			gen_field_access ctx true e1 s;
+			print ctx ", \"%s\") ? " (s_ident name);
+			gen_field_access ctx true e1 name;
 			spr ctx ": array(";
 			ob e1.eexpr;
-			print ctx ", \"%s\"))" (s_ident s);
+			print ctx ", \"%s\"))" (s_ident name);
 
 		end)
 	| TMono _ ->
 		if ctx.is_call then
-			gen_field_access ctx false e1 s
+			gen_field_access ctx false e1 name
 		else
-			gen_uncertain_string_var ctx s e1
+			gen_uncertain_string_var ctx name e1
+	| TDynamic _ when not ctx.is_call && (match s with FDynamic _ -> true | _ -> false) ->
+		spr ctx "_hx_field(";
+		gen_value ctx e1;
+		print ctx ", \"%s\")" name
 	| _ ->
 		if is_string_expr e1 then
-			gen_string_var ctx s e1
+			gen_string_var ctx name e1
 		else if is_uncertain_expr e1 then
-			gen_uncertain_string_var ctx s e1
+			gen_uncertain_string_var ctx name e1
 		else
-			gen_field_access ctx true e1 s
+			gen_field_access ctx true e1 name
 
 and gen_expr ctx e =
 	let in_block = ctx.in_block in
@@ -1300,7 +1305,7 @@ and gen_expr ctx e =
 		spr ctx ")";
 		print ctx "->params[%d]" i;
 	| TField (e1,s) ->
-		gen_tfield ctx e e1 (field_name s)
+		gen_tfield ctx e e1 s
 	| TTypeExpr t ->
 		print ctx "_hx_qtype(\"%s\")" (s_path_haxe (t_path t))
 	| TParenthesis e ->
@@ -1333,7 +1338,7 @@ and gen_expr ctx e =
 		if ctx.in_loop then spr ctx "break" else print ctx "break %d" ctx.nested_loops
 	| TContinue ->
 		if ctx.in_loop then spr ctx "continue" else print ctx "continue %d" ctx.nested_loops
-	| TBlock [] ->
+	| TBlock [] when List.length ctx.dynamic_methods = 0 ->
 		spr ctx "{}"
 	| TBlock el ->
 		let old_l = ctx.inv_locals in
@@ -1514,7 +1519,7 @@ and gen_expr ctx e =
 			);
 		| TField (e1,s) ->
 			spr ctx (Ast.s_unop op);
-			gen_tfield ctx e e1 (field_name s)
+			gen_tfield ctx e e1 s
 		| _ ->
 			spr ctx (Ast.s_unop op);
 			gen_value ctx e)

+ 251 - 68
src/generators/genphp7.ml

@@ -112,6 +112,10 @@ let void_type_path = ([], "Void")
 	Type path of the `Bool`
 *)
 let bool_type_path = ([], "Bool")
+(**
+	Type path of the `Std`
+*)
+let std_type_path = ([], "Std")
 
 (**
 	Stub to use when you need a `Ast.pos` instance, but don't have one
@@ -205,6 +209,17 @@ let rec reveal_expr expr =
 		| TMeta (_, e) -> reveal_expr e
 		| _ -> expr
 
+(**
+	If `expr` is a TCast or TMeta or TParenthesis, then returns underlying expression (recursively bypassing nested casts and parenthesis).
+	Otherwise returns `expr` as is.
+*)
+let rec reveal_expr_with_parenthesis expr =
+	match expr.eexpr with
+		| TCast (e, _) -> reveal_expr_with_parenthesis e
+		| TMeta (_, e) -> reveal_expr_with_parenthesis e
+		| TParenthesis e -> reveal_expr_with_parenthesis e
+		| _ -> expr
+
 (**
 	@return Error message with position information
 *)
@@ -235,7 +250,7 @@ let rec is_dynamic_type (target:Type.t) = match follow target with TDynamic _ ->
 (**
 	Check if `target` is `php.Ref`
 *)
-let is_ref (target:Type.t) = match target with TAbstract ({ a_path = type_path }, _) -> type_path = ref_type_path | _ -> false
+let is_ref (target:Type.t) = match target with TType ({ t_path = type_path }, _) -> type_path = ref_type_path | _ -> false
 
 (**
 	Check if `field` is a `dynamic function`
@@ -364,6 +379,12 @@ let needs_dereferencing expr =
 			| TArrayDecl _ -> true
 			| TObjectDecl _ -> true
 			| TConst TNull -> true
+			(* some of `php.Syntax` methods *)
+			| TCall ({ eexpr = TField (_, FStatic ({ cl_path = syntax_type_path }, { cf_name = name })) }, _) ->
+				(match name with
+					| "binop" | "object" | "array" -> true
+					| _ -> false
+				)
 			| _ -> false
 	in
 	match expr.eexpr with
@@ -684,6 +705,26 @@ let ensure_return_in_block block_expr =
 			{ block_expr with eexpr = TBlock (List.rev reversed) }
 		| _ -> fail block_expr.epos (try assert false with Assert_failure mlpos -> mlpos)
 
+(**
+	If `expr` is a block, then return list of expressions in that block.
+	Otherwise returns a list with `expr` as a single item.
+*)
+let unpack_block expr =
+		match expr.eexpr with
+			| TBlock exprs -> exprs
+			| _ -> [ expr ]
+
+(**
+	If `expr` is a block of a single expression, then return that single expression.
+	If `expr` is a block with multiple expressions, fail compilation.
+	Otherwise return `expr` as-is.
+*)
+let unpack_single_expr_block expr =
+		match expr.eexpr with
+			| TBlock [ e ] -> e
+			| TBlock _ -> fail expr.epos (try assert false with Assert_failure mlpos -> mlpos)
+			| _ -> expr
+
 (**
 	Check if specified type has rtti meta
 *)
@@ -724,13 +765,35 @@ let field_name field =
 	else
 		field.cf_name
 
+(**
+	Check if `expr` is `Std.is`
+*)
+let is_std_is expr =
+	match expr.eexpr with
+		| TField (_, FStatic ({ cl_path = path }, { cf_name = "is" })) -> path = boot_type_path || path = std_type_path
+		| _ -> false
+
+(**
+	Check if `subject_arg` and `type_arg` can be generated as `$subject instanceof Type` expression.
+*)
+let instanceof_compatible (subject_arg:texpr) (type_arg:texpr) : bool =
+	match (reveal_expr_with_parenthesis type_arg).eexpr with
+		| TTypeExpr (TClassDecl { cl_path = path }) when path <> ([], "String") && path <> ([], "Class") ->
+			let subject_arg = reveal_expr_with_parenthesis subject_arg in
+			(match subject_arg.eexpr with
+				| TLocal _ | TField _ | TCall _ | TArray _ -> not (is_magic subject_arg)
+				| _ -> false
+			)
+		| _ -> false
+
+
 (**
 	PHP DocBlock types
 *)
 type doc_type =
 	| DocVar of string * (string option) (* (type name, description) *)
 	| DocMethod of (string * bool * t) list * t * (string option) (* (arguments, return type, description) *)
-| DocClass of string option
+	| DocClass of string option
 
 (**
 	Common interface for module_type instances
@@ -770,6 +833,10 @@ class virtual type_wrapper (type_path:path) (meta:metadata) (needs_generation:bo
 			Full type path
 		*)
 		method get_type_path = type_path
+		(**
+			If current type requires some additional type to be generated
+		*)
+		method get_service_type : module_type option = None
 	end
 
 (**
@@ -813,6 +880,33 @@ class class_wrapper (cls) =
 			Returns `Type.module_type` instance for this type
 		*)
 		method get_module_type = TClassDecl cls
+		(**
+			If current type requires some additional type to be generated
+		*)
+		method get_service_type : module_type option =
+			if not cls.cl_extern then
+				None
+			else
+				match cls.cl_init with
+					| None -> None
+					| Some body ->
+						let path =
+							match cls.cl_path with
+								| (pack, name) -> (pack @ ["_" ^ name], ("_extern_" ^ name))
+						in
+						let additional_cls = {
+							cls with
+								cl_extern =  false;
+								cl_path = path;
+								cl_fields  = PMap.create (fun a b -> 0);
+								cl_statics  = PMap.create (fun a b -> 0);
+								cl_ordered_fields  = [];
+								cl_ordered_statics  = [];
+								cl_constructor = None;
+								cl_overrides = [];
+								cl_init = Some body
+						} in
+						Some (TClassDecl additional_cls)
 	end
 
 (**
@@ -974,6 +1068,19 @@ let type_name_used_in_namespace ctx name namespace =
 		| _ ->
 			List.mem name types
 
+(**
+	Simple list intersection implementation.
+	@return A list of values existing in each of source lists.
+*)
+let rec list_intersect list1 list2 =
+	match list2 with
+		| [] -> []
+		| item :: rest ->
+			if List.mem item list1 then
+				item :: (list_intersect list1 rest)
+			else
+				list_intersect list1 rest
+
 (**
 	Class to simplify collecting lists of declared and used local vars.
 	Collected data is needed to generate closures correctly.
@@ -984,12 +1091,15 @@ class local_vars =
 		val mutable used_locals = [Hashtbl.create 100]
 		(** Hashtbl to collect local vars declared in current scope *)
 		val mutable declared_locals = [Hashtbl.create 100]
+		(** Local vars which were captured in closures (passed via `use` directive in php) *)
+		val captured_locals = Hashtbl.create 0
 		(**
 			Clear collected data
 		*)
 		method clear : unit =
 			used_locals <- [Hashtbl.create 100];
-			declared_locals <- [Hashtbl.create 100]
+			declared_locals <- [Hashtbl.create 100];
+			Hashtbl.clear captured_locals
 		(**
 			This method should be called upone entering deeper scope.
 			E.g. right before processing a closure. Just before closure arguments handling.
@@ -1001,8 +1111,9 @@ class local_vars =
 			This method should be called right after leaving a scope.
 			@return List of vars names used in finished scope, but declared in higher scopes.
 					And list of vars names declared in finished scope.
+					And list of vars names declared in finished scope and captured by closures via `use` directive
 		*)
-		method pop : string list * string list =
+		method pop : string list * string list * string list =
 			match used_locals with
 				| [] -> assert false
 				| used :: rest_used ->
@@ -1014,17 +1125,24 @@ class local_vars =
 							used_locals <- rest_used;
 							declared_locals <- rest_declared;
 							List.iter self#used higher_vars;
-							(higher_vars, declared_vars)
+							let captured_vars = list_intersect declared_vars (hashtbl_keys captured_locals) in
+							List.iter (fun name -> Hashtbl.remove captured_locals name) declared_vars;
+							(higher_vars, declared_vars, captured_vars)
 		(**
 			This method should be called right after leaving a scope.
 			@return List of vars names used in finished scope, but declared in higher scopes
 		*)
-		method pop_used : string list = match self#pop with (higher_vars, _) -> higher_vars
+		method pop_used : string list = match self#pop with (higher_vars, _, _) -> higher_vars
 		(**
 			This method should be called right after leaving a scope.
 			@return List of vars names declared in finished scope
 		*)
-		method pop_declared : string list = match self#pop with (_, declared_vars) -> declared_vars
+		method pop_declared : string list = match self#pop with (_, declared_vars, _) -> declared_vars
+		(**
+			Get current list of captured variables.
+			After leaving a scope all vars declared in that scope get removed from a list of captured variables.
+		*)
+		method pop_captured : string list = match self#pop with (_, _, captured_vars) -> captured_vars
 		(**
 			Specify local var name declared in current scope
 		*)
@@ -1039,6 +1157,11 @@ class local_vars =
 			match used_locals with
 				| [] -> assert false
 				| current :: _ -> Hashtbl.replace current name name
+		(**
+			Mark specified vars as captured by closures.
+		*)
+		method captured (var_names:string list) : unit =
+			List.iter (fun name -> Hashtbl.replace captured_locals name name) var_names
 	end
 
 (**
@@ -1248,54 +1371,66 @@ class virtual type_builder ctx wrapper =
 						| ([], "Class") -> "Class"
 						| _ when Meta.has Meta.CoreType abstr.a_meta -> "mixed"
 						| _ -> self#use_t abstr.a_this
+		(**
+			Indicates if there is no constructor in inheritance chain of this type.
+			Own constructor is ignored.
+		*)
+		method private extends_no_constructor = true
 		(**
 			Indicates whether current expression nesting level is a top level of a block
 		*)
-		method private parent_expr_is_block =
-			let rec expr_is_block expr parents =
+		method private parent_expr_is_block single_expr_is_not_block =
+			let rec expr_is_block expr parents no_parent_is_block =
 				match expr.eexpr with
+					| TBlock [_] when single_expr_is_not_block ->
+						(match parents with
+							| { eexpr = TBlock _ } :: _ -> true
+							| { eexpr = TFunction _ } :: _ -> true
+							| _ :: _ -> false
+							| [] -> no_parent_is_block
+						)
 					| TBlock _ -> true
 					| TIf (_, if_expr, Some else_expr) ->
-						if (expr_is_block if_expr []) || (expr_is_block else_expr []) then
+						if (expr_is_block if_expr [] false) || (expr_is_block else_expr [] false) then
 							true
 						else
 							(match parents with
-								| parent :: rest -> expr_is_block parent rest
+								| parent :: rest -> expr_is_block parent rest true
 								| [] -> false
 							)
 					| TIf (_, _, None) -> true
 					| TTry _ -> true
 					| TWhile _ -> true
+					| TFor _ -> true
 					| TSwitch _ -> true
 					| _ -> false
 			in
 			match expr_hierarchy with
-				| _ :: parent :: rest -> expr_is_block parent rest
+				| _ :: parent :: rest -> expr_is_block parent rest true
 				| _ -> false
 		(**
-			Returns parent expression.
+			Returns parent expression  (bypasses casts and metas)
 		*)
 		method private parent_expr =
-			match expr_hierarchy with
-				| _ :: expr :: _ -> Some expr
-				| _ -> None
-		(**
-			Indicates if parent expression is a call (bypasses casts and metas)
-		*)
-		method private parent_expr_is_call =
-			let rec expr_is_call expr parents =
+			let rec traverse expr parents =
 				match expr.eexpr with
-					| TCast _
+					| TCast (_, None)
 					| TMeta _ ->
 						(match parents with
-							| parent :: rest -> expr_is_call parent rest
-							| [] -> false
+							| parent :: rest -> traverse parent rest
+							| [] -> None
 						)
-					| TCall _ -> true
-					| _ -> false
+					| _ -> Some expr
 			in
 			match expr_hierarchy with
-				| _ :: parent :: rest -> expr_is_call parent rest
+				| _ :: parent :: rest -> traverse parent rest
+				| _ -> None
+		(**
+			Indicates if parent expression is a call (bypasses casts and metas)
+		*)
+		method private parent_expr_is_call =
+			match self#parent_expr with
+				| Some { eexpr = TCall _ } -> true
 				| _ -> false
 		(**
 			Position of currently generated code in source hx files
@@ -1515,6 +1650,7 @@ class virtual type_builder ctx wrapper =
 					self#write ")"
 				| TObjectDecl fields -> self#write_expr_object_declaration fields
 				| TArrayDecl exprs -> self#write_expr_array_decl exprs
+				| TCall (target, [arg1; arg2]) when is_std_is target && instanceof_compatible arg1 arg2 -> self#write_expr_lang_instanceof [arg1; arg2]
 				| TCall ({ eexpr = TLocal { v_name = name }}, args) when is_magic expr -> self#write_expr_magic name args
 				| TCall ({ eexpr = TField (expr, access) }, args) when is_string expr -> self#write_expr_call_string expr access args
 				| TCall (expr, args) when is_lang_extern expr -> self#write_expr_call_lang_extern expr args
@@ -1591,13 +1727,18 @@ class virtual type_builder ctx wrapper =
 		*)
 		method private write_expr_const const =
 			match const with
-				| TInt value -> self#write (Int32.to_string value)
 				| TFloat str -> self#write str
 				| TString str -> self#write ("\"" ^ (escape_bin str) ^ "\"")
 				| TBool value -> self#write (if value then "true" else "false")
 				| TNull -> self#write "null"
 				| TThis -> self#write "$this"
 				| TSuper -> self#write "parent"
+				| TInt value ->
+					(* See https://github.com/HaxeFoundation/haxe/issues/5289 *)
+					if value = Int32.min_int then
+						self#write "((int)-2147483648)"
+					else
+						self#write (Int32.to_string value)
 		(**
 			Writes TArrayDecl to output buffer
 		*)
@@ -1619,39 +1760,45 @@ class virtual type_builder ctx wrapper =
 			Writes TArray to output buffer
 		*)
 		method private write_expr_array_access target index =
-			(*self#write_expr target;
-			self#write "[";
-			self#write_expr index;
-			self#write "]"*)
 			let write_index left_bracket right_bracket =
 				self#write left_bracket;
 				self#write_expr index;
 				self#write right_bracket
 			in
+			let write_fast_access () =
+				self#write "(";
+				self#write_expr target;
+				self#write "->arr";
+				write_index "[" "] ?? null)"
+			and write_normal_access () =
+				self#write_expr target;
+				write_index "[" "]"
+			in
+			let write_depending_on e =
+				match (reveal_expr e).eexpr with
+					| TArray (t, i) when t  == target ->
+						write_normal_access ()
+					| _ ->
+						write_fast_access ()
+			in
 			match follow target.etype with
 				| TInst ({ cl_path = path }, _) when path = array_type_path ->
 					(match self#parent_expr with
-						| Some { eexpr = TBinop (OpAssign, { eexpr = TArray (t, i) }, _) } when t == target ->
-							self#write_expr target;
-							write_index "[" "]"
-						| Some { eexpr = TBinop (OpAssignOp _, { eexpr = TArray (t, i) }, _) } when t == target ->
-							self#write_expr target;
-							write_index "[" "]"
-						| Some { eexpr = TUnop (op, _, { eexpr = TArray (t, i) }) } when t == target && is_modifying_unop op ->
-							self#write_expr target;
-							write_index "[" "]"
-						| Some { eexpr = TField ({ eexpr = TArray (t, i) }, _) } ->
-							self#write_expr target;
-							write_index "[" "]"
-						| _ ->
-							self#write "(";
-							self#write_expr target;
-							self#write "->arr";
-							write_index "[" "] ?? null)"
+						| None -> write_fast_access ()
+						| Some expr ->
+							match (reveal_expr expr).eexpr with
+								| TUnop (op, _, e) when is_modifying_unop op ->
+									write_depending_on e
+								| TBinop (OpAssign, e, _)
+								| TBinop (OpAssignOp _, e, _)
+								| TField (e, _)
+								| TArray (e, _) ->
+									write_depending_on e
+								| _ ->
+									write_fast_access ()
 					)
 				| _ ->
-					self#write_expr target;
-					write_index "[" "]"
+					write_normal_access ()
 		(**
 			Writes TVar to output buffer
 		*)
@@ -1709,8 +1856,9 @@ class virtual type_builder ctx wrapper =
 			self#write_expr (inject_defaults ctx func);
 			let body = Buffer.contents buffer in
 			buffer <- original_buffer;
-			(* Use captured local vars *)
+			(* Capture local vars used in closures *)
 			let used_vars = vars#pop_used in
+			vars#captured used_vars;
 			self#write " ";
 			if List.length used_vars > 0 then begin
 				self#write " use (";
@@ -1750,7 +1898,7 @@ class virtual type_builder ctx wrapper =
 				end
 			else
 				begin
-					let inline_block = self#parent_expr_is_block in
+					let inline_block = self#parent_expr_is_block false in
 					self#write_as_block ~inline:inline_block block_expr
 				end
 		(**
@@ -1794,7 +1942,7 @@ class virtual type_builder ctx wrapper =
 						write_exprs();
 						let body = Buffer.contents buffer in
 						buffer <- original_buffer;
-						let locals = vars#pop_declared in
+						let locals = vars#pop_captured in
 						if List.length locals > 0 then begin
 							self#write ("unset($" ^ (String.concat ", $" locals) ^ ");\n");
 							self#write_indentation
@@ -1940,6 +2088,8 @@ class virtual type_builder ctx wrapper =
 							)
 						| "__var__" ->
 							(match args with
+								| [] ->
+									self#write ("$" ^ code)
 								| [expr2] ->
 									self#write ("$" ^ code ^ "[");
 									self#write_expr expr2;
@@ -2474,15 +2624,17 @@ class virtual type_builder ctx wrapper =
 		method private write_expr_lang_instanceof args =
 			match args with
 				| val_expr :: type_expr :: [] ->
+					self#write "(";
 					self#write_expr val_expr;
 					self#write " instanceof ";
-					(match type_expr.eexpr with
+					(match (reveal_expr type_expr).eexpr with
 						| TTypeExpr (TClassDecl tcls) ->
 							self#write (self#use_t (TInst (tcls, [])))
 						| _ ->
 							self#write_expr type_expr;
 							if not (is_string type_expr) then self#write "->phpClassName"
-					)
+					);
+					self#write ")"
 				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
 		(**
 			Writes `foreach` expression to output buffer (for `php.Syntax.foreach()`)
@@ -2510,15 +2662,21 @@ class virtual type_builder ctx wrapper =
 			Writes TCall to output buffer
 		*)
 		method private write_expr_call target_expr args =
-			let target_expr = reveal_expr target_expr in
+			let target_expr = reveal_expr target_expr
+			and no_call = ref false in
 			(match target_expr.eexpr with
-				| TConst TSuper -> self#write "parent::__construct"
+				| TConst TSuper ->
+					no_call := self#extends_no_constructor;
+					if not !no_call then self#write "parent::__construct"
 				| TField (expr, FClosure (_,_)) -> self#write_expr (parenthesis target_expr)
 				| _ -> self#write_expr target_expr
 			);
-			self#write "(";
-			write_args buffer self#write_expr args;
-			self#write ")";
+			if not !no_call then
+				begin
+					self#write "(";
+					write_args buffer self#write_expr args;
+					self#write ")"
+				end
 		(**
 			Writes a name of a function or a constant from global php namespace
 		*)
@@ -2546,8 +2704,9 @@ class virtual type_builder ctx wrapper =
 			Writes ternary operator expressions to output buffer
 		*)
 		method private write_expr_ternary condition if_expr (else_expr:texpr) pos =
-			let parent_is_if = match self#parent_expr with Some { eexpr = TIf _ } -> true | _ -> false in
-			if parent_is_if then self#write "(";
+			let if_expr = unpack_single_expr_block if_expr
+			and else_expr = unpack_single_expr_block else_expr in
+			self#write "(";
 			(match condition.eexpr with
 				| TParenthesis expr -> self#write_expr expr;
 				| _ -> self#write_expr else_expr
@@ -2556,17 +2715,19 @@ class virtual type_builder ctx wrapper =
 			self#write_expr if_expr;
 			self#write " : ";
 			self#write_expr else_expr;
-			if parent_is_if then self#write ")"
+			self#write ")"
 		(**
 			Writes "if...else..." expression to output buffer
 		*)
 		method private write_expr_if condition if_expr (else_expr:texpr option) =
 			let is_ternary =
-				if self#parent_expr_is_block then
+				if self#parent_expr_is_block true then
 					false
 				else
 					match (if_expr.eexpr, else_expr) with
-						| (TBlock _, _) | (_, Some { eexpr=TBlock _ }) -> false
+						| (TBlock exprs, _)  when (List.length exprs) > 1 -> false
+						| (_, Some { eexpr=TBlock exprs }) when (List.length exprs) > 1 -> false
+						| (_, None) -> false
 						| _ -> true
 			in
 			if is_ternary then
@@ -2824,6 +2985,24 @@ class class_builder ctx (cls:tclass) =
 		*)
 		method is_final_field (field:tclass_field) : bool =
 			Meta.has Meta.Final field.cf_meta
+		(**
+			Check if there is no native php constructor in inheritance chain of this class.
+			E.g. `StsClass` does have a constructor while still can be called with `new StdClass()`.
+			So this method will return true for `MyClass` if `MyClass extends StdClass`.
+		*)
+		method private extends_no_constructor =
+			let rec extends_no_constructor tcls =
+				match tcls.cl_super with
+					| None -> true
+					| Some (parent, _) ->
+						if Meta.has Meta.PhpNoConstructor parent.cl_meta then
+							true
+						else
+							match parent.cl_constructor with
+								| Some _ -> false
+								| None -> extends_no_constructor parent
+			in
+			extends_no_constructor cls
 		(**
 			Recursively check if current class is a parent class for a `child`
 		*)
@@ -3311,14 +3490,18 @@ class generator (com:context) =
 let generate (com:context) =
 	let gen = new generator com in
 	gen#initialize;
-	let generate com_type =
+	let rec generate com_type =
 		let wrapper = get_wrapper com_type in
 		if wrapper#needs_generation then
-			match com_type with
+			(match com_type with
 				| TClassDecl cls -> gen#generate (new class_builder com cls);
 				| TEnumDecl enm -> gen#generate (new enum_builder com enm);
 				| TTypeDecl typedef -> ();
 				| TAbstractDecl abstr -> ()
+			);
+		match wrapper#get_service_type with
+			| None -> ()
+			| Some service_type -> generate service_type
 	in
 	List.iter generate com.types;
 	gen#finalize;

+ 1 - 1
src/generators/genpy.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 1 - 1
src/generators/genswf.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 1 - 1
src/generators/genswf9.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 1 - 1
src/generators/genxml.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 1146 - 954
src/generators/hl2c.ml

@@ -1,5 +1,5 @@
 (*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -38,19 +38,47 @@ type output_options =
 	| OOBeginBlock
 	| OOEndBlock
 
-let c_kwds = [
-"auto";"break";"case";"char";"const";"continue";"default";"do";"double";"else";"enum";"extern";"float";"for";"goto";
-"if";"int";"long";"register";"return";"short";"signed";"sizeof";"static";"struct";"switch";"typedef";"union";"unsigned";
-"void";"volatile";"while";
-(* MS specific *)
-"__asm";"dllimport2";"__int8";"naked2";"__based1";"__except";"__int16";"__stdcall";"__cdecl";"__fastcall";"__int32";
-"thread2";"__declspec";"__finally";"__int64";"__try";"dllexport2";"__inline";"__leave";"asm";
-(* reserved by HLC *)
-"t";
-(* C11 *)
-"_Alignas";"_Alignof";"_Atomic";"_Bool";"_Complex";"_Generic";"_Imaginary";"_Noreturn";"_Static_assert";"_Thread_local";"_Pragma";
-"inline";"restrict"
-]
+type function_entry = {
+	mutable fe_name : string;
+	mutable fe_decl : fundecl option;
+	mutable fe_args : ttype list;
+	mutable fe_ret : ttype;
+}
+
+type context = {
+	version : int;
+	out : Buffer.t;
+	mutable tabs : string;
+	hash_cache : (int, int32) Hashtbl.t;
+	hlcode : code;
+	dir : string;
+	mutable curfile : string;
+	mutable cfiles : string list;
+	ftable : function_entry array;
+	htypes : (ttype, int) PMap.t;
+}
+
+let sprintf = Printf.sprintf
+
+let keywords =
+	let c_kwds = [
+	"auto";"break";"case";"char";"const";"continue";"default";"do";"double";"else";"enum";"extern";"float";"for";"goto";
+	"if";"int";"long";"register";"return";"short";"signed";"sizeof";"static";"struct";"switch";"typedef";"union";"unsigned";
+	"void";"volatile";"while";
+	(* MS specific *)
+	"__asm";"dllimport2";"__int8";"naked2";"__based1";"__except";"__int16";"__stdcall";"__cdecl";"__fastcall";"__int32";
+	"thread2";"__declspec";"__finally";"__int64";"__try";"dllexport2";"__inline";"__leave";"asm";
+	(* reserved by HLC *)
+	"t";
+	(* C11 *)
+	"_Alignas";"_Alignof";"_Atomic";"_Bool";"_Complex";"_Generic";"_Imaginary";"_Noreturn";"_Static_assert";"_Thread_local";"_Pragma";
+	"inline";"restrict"
+	] in
+	let h = Hashtbl.create 0 in
+	List.iter (fun i -> Hashtbl.add h i ()) c_kwds;
+	h
+
+let ident i = if Hashtbl.mem keywords i then "_" ^ i else i
 
 let s_comp = function
 	| CLt -> "<"
@@ -65,400 +93,171 @@ let core_types =
 	let ep = { ename = ""; eid = 0; eglobal = None; efields = [||] } in
 	[HVoid;HUI8;HUI16;HI32;HF32;HF64;HBool;HBytes;HDyn;HFun ([],HVoid);HObj null_proto;HArray;HType;HRef HVoid;HVirtual vp;HDynObj;HAbstract ("",0);HEnum ep;HNull HVoid]
 
-let write_c version file (code:code) =
-	let tabs = ref "" in
-	let file_count = ref 1 in
-	let line_count = ref 0 in
-	let main_ch = IO.output_channel (open_out_bin file) in
-	let ch = ref main_ch in
-	let end_ch = ref [(fun() -> IO.close_out main_ch)] in
-	let block() = tabs := !tabs ^ "\t" in
-	let unblock() = tabs := String.sub (!tabs) 0 (String.length (!tabs) - 1) in
-	let line str =
-		incr line_count;
-		IO.write_line !ch (!tabs ^ str)
-	in
-	let expr str = line (str ^ ";") in
-	let sexpr fmt = Printf.ksprintf expr fmt in
-	let sline fmt = Printf.ksprintf line fmt in
-	let sprintf = Printf.sprintf in
-
-	let flush_file() =
-		if !line_count > 60000 then begin
-			incr file_count;
-			let nfile = String.sub file 0 (String.length file - 2) ^ string_of_int !file_count ^ ".c" in
-			ch := main_ch;
-			sline "#include \"%s\"" (match List.rev (ExtString.String.nsplit (String.concat "/" (ExtString.String.nsplit nfile "\\")) "/") with file :: _ -> file | _ -> assert false);
-			let nch = IO.output_channel (open_out_bin nfile) in
- 			ch := nch;
-			sline "#ifdef HLC_H";
-			end_ch := (fun() -> IO.write_line nch "#endif"; IO.close_out nch) :: !end_ch;
-			line_count := 0;
-		end
-	in
-
-	let hash_cache = Hashtbl.create 0 in
-	let hash sid =
-		try
-			Hashtbl.find hash_cache sid
-		with Not_found ->
-			let h = hl_hash code.strings.(sid) in
-			Hashtbl.add hash_cache sid h;
-			h
-	in
+let tname str =
+	let n = String.concat "__" (ExtString.String.nsplit str ".") in
+	if Hashtbl.mem keywords ("_" ^ n) then "__" ^ n else n
 
-	let keywords =
-		let h = Hashtbl.create 0 in
-		List.iter (fun i -> Hashtbl.add h i ()) c_kwds;
-		h
-	in
+let is_gc_ptr = function
+	| HVoid | HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HType | HRef _ -> false
+	| HBytes | HDyn | HFun _ | HObj _ | HArray | HVirtual _ | HDynObj | HAbstract _ | HEnum _ | HNull _ -> true
 
-	let ident i = if Hashtbl.mem keywords i then "_" ^ i else i in
+let is_ptr = function
+	| HVoid | HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool -> false
+	| _ -> true
 
-	let tname str =
-		let n = String.concat "__" (ExtString.String.nsplit str ".") in
-		if Hashtbl.mem keywords ("_" ^ n) then "__" ^ n else n
-	in
+let rec ctype_no_ptr = function
+	| HVoid -> "void",0
+	| HUI8 -> "unsigned char",0
+	| HUI16 -> "unsigned short",0
+	| HI32 -> "int",0
+	| HF32 -> "float",0
+	| HF64 -> "double",0
+	| HBool -> "bool",0
+	| HBytes -> "vbyte",1
+	| HDyn -> "vdynamic",1
+	| HFun _ -> "vclosure",1
+	| HObj p -> tname p.pname,0
+	| HArray -> "varray",1
+	| HType -> "hl_type",1
+	| HRef t -> let s,i = ctype_no_ptr t in s,i + 1
+	| HVirtual _ -> "vvirtual",1
+	| HDynObj -> "vdynobj",1
+	| HAbstract (name,_) -> name,1
+	| HEnum _ -> "venum",1
+	| HNull _ -> "vdynamic",1
 
-	let is_gc_ptr = function
-		| HVoid | HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HType | HRef _ -> false
-		| HBytes | HDyn | HFun _ | HObj _ | HArray | HVirtual _ | HDynObj | HAbstract _ | HEnum _ | HNull _ -> true
-	in
+let ctype t =
+	let t, nptr = ctype_no_ptr t in
+	if nptr = 0 then t else t ^ String.make nptr '*'
 
-	let is_ptr = function
-		| HVoid | HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool -> false
-		| _ -> true
-	in
+let cast_fun s args t =
+	sprintf "((%s (*)(%s))%s)" (ctype t) (String.concat "," (List.map ctype args)) s
 
-	let rec ctype_no_ptr = function
-		| HVoid -> "void",0
-		| HUI8 -> "unsigned char",0
-		| HUI16 -> "unsigned short",0
-		| HI32 -> "int",0
-		| HF32 -> "float",0
-		| HF64 -> "double",0
-		| HBool -> "bool",0
-		| HBytes -> "vbyte",1
-		| HDyn -> "vdynamic",1
-		| HFun _ -> "vclosure",1
-		| HObj p -> tname p.pname,0
-		| HArray -> "varray",1
-		| HType -> "hl_type",1
-		| HRef t -> let s,i = ctype_no_ptr t in s,i + 1
-		| HVirtual _ -> "vvirtual",1
-		| HDynObj -> "vdynobj",1
-		| HAbstract (name,_) -> name,1
-		| HEnum _ -> "venum",1
-		| HNull _ -> "vdynamic",1
-	in
+let dyn_value_field t =
+	"->v." ^ match t with
+	| HUI8 -> "ui8"
+	| HUI16 -> "ui16"
+	| HI32 -> "i"
+	| HF32 -> "f"
+	| HF64 -> "d"
+	| HBool -> "b"
+	| _ -> "ptr"
 
-	let ctype t =
-		let t, nptr = ctype_no_ptr t in
-		if nptr = 0 then t else t ^ String.make nptr '*'
-	in
+let type_id t =
+	match t with
+	| HVoid -> "HVOID"
+	| HUI8 -> "HUI8"
+	| HUI16 -> "HUI16"
+	| HI32 -> "HI32"
+	| HF32 -> "HF32"
+	| HF64 -> "HF64"
+	| HBool -> "HBOOL"
+	| HBytes -> "HBYTES"
+	| HDyn -> "HDYN"
+	| HFun _ -> "HFUN"
+	| HObj _ -> "HOBJ"
+	| HArray -> "HARRAY"
+	| HType -> "HTYPE"
+	| HRef _ -> "HREF"
+	| HVirtual _ -> "HVIRTUAL"
+	| HDynObj -> "HDYNOBJ"
+	| HAbstract _ -> "HABSTRACT"
+	| HEnum _ -> "HENUM"
+	| HNull _ -> "HNULL"
 
-	let type_id t =
-		match t with
-		| HVoid -> "HVOID"
-		| HUI8 -> "HUI8"
-		| HUI16 -> "HUI16"
-		| HI32 -> "HI32"
-		| HF32 -> "HF32"
-		| HF64 -> "HF64"
-		| HBool -> "HBOOL"
-		| HBytes -> "HBYTES"
-		| HDyn -> "HDYN"
-		| HFun _ -> "HFUN"
-		| HObj _ -> "HOBJ"
-		| HArray -> "HARRAY"
-		| HType -> "HTYPE"
-		| HRef _ -> "HREF"
-		| HVirtual _ -> "HVIRTUAL"
-		| HDynObj -> "HDYNOBJ"
-		| HAbstract _ -> "HABSTRACT"
-		| HEnum _ -> "HENUM"
-		| HNull _ -> "HNULL"
-	in
+let var_type n t =
+	ctype t ^ " " ^ ident n
 
-	let var_type n t =
-		ctype t ^ " " ^ ident n
-	in
+let block ctx =
+	ctx.tabs <- ctx.tabs ^ "\t"
 
-	let version_major = version / 1000 in
-	let version_minor = (version mod 1000) / 100 in
-	let version_revision = (version mod 100) in
-	let ver_str = Printf.sprintf "%d.%d.%d" version_major version_minor version_revision in
-	line ("// Generated by HLC " ^ ver_str ^ " (HL v" ^ string_of_int code.version ^")");
-	line "#define HLC_BOOT";
-	line "#include <hlc.h>";
-	let all_types, htypes = gather_types code in
-	let tfuns = Array.create (Array.length code.functions + Array.length code.natives) ([],HVoid) in
-	let funnames = Array.create (Array.length code.functions + Array.length code.natives) "" in
+let unblock ctx =
+	ctx.tabs <- String.sub ctx.tabs 0 (String.length ctx.tabs - 1)
 
-	let cast_fun s args t =
-		sprintf "((%s (*)(%s))%s)" (ctype t) (String.concat "," (List.map ctype args)) s
-	in
+let hash ctx sid =
+	try
+		Hashtbl.find ctx.hash_cache sid
+	with Not_found ->
+		let h = hl_hash ctx.hlcode.strings.(sid) in
+		Hashtbl.add ctx.hash_cache sid h;
+		h
 
-	let enum_constr_type e i =
-		let cname,_, tl = e.efields.(i) in
-		if Array.length tl = 0 then
-			"venum"
-		else
-		let name = if e.eid = 0 then
-			let index = (try PMap.find (HEnum e) htypes with Not_found -> assert false) in
-			"Enum$" ^ string_of_int index
-		else
-			String.concat "_" (ExtString.String.nsplit e.ename ".")
-		in
-		if cname = "" then
-			name
-		else
-			name ^ "_" ^ cname
-	in
+let type_value ctx t =
+	let index = (try PMap.find t ctx.htypes with Not_found -> assert false) in
+	"&type$" ^ string_of_int index
 
-	let dyn_value_field t =
-		"->v." ^ match t with
-		| HUI8 -> "ui8"
-		| HUI16 -> "ui16"
-		| HI32 -> "i"
-		| HF32 -> "f"
-		| HF64 -> "d"
-		| HBool -> "b"
-		| _ -> "ptr"
+let enum_constr_type ctx e i =
+	let cname,_, tl = e.efields.(i) in
+	if Array.length tl = 0 then
+		"venum"
+	else
+	let name = if e.eid = 0 then
+		let index = (try PMap.find (HEnum e) ctx.htypes with Not_found -> assert false) in
+		"Enum$" ^ string_of_int index
+	else
+		String.concat "_" (ExtString.String.nsplit e.ename ".")
 	in
+	if cname = "" then
+		name
+	else
+		name ^ "_" ^ cname
 
-	let used_closures = Hashtbl.create 0 in
-	let bytes_strings = Hashtbl.create 0 in
-	Array.iter (fun f ->
-		Array.iteri (fun i op ->
-			match op with
-			| OStaticClosure (_,fid) | OSetMethod (_,_,fid) ->
-				Hashtbl.replace used_closures fid ()
-			| OBytes (_,sid) ->
-				Hashtbl.replace bytes_strings sid ()
-			| _ ->
-				()
-		) f.code
-	) code.functions;
-
-
-	line "";
-	line "// Types definitions";
-	Array.iter (fun t ->
-		match t with
-		| HObj o ->
-			let name = tname o.pname in
-			expr ("typedef struct _" ^ name ^ " *" ^ name);
-		| HAbstract (name,_) ->
-			expr ("typedef struct _" ^ name ^ " "  ^ name);
-		| _ ->
-			()
-	) all_types;
-
-	line "";
-	line "// Types implementation";
-
-	let unamed_field fid = "$_f" ^ string_of_int fid in
+let output ctx str =
+	Buffer.add_string ctx.out str
 
-	let obj_field fid name =
-		if name = "" then unamed_field fid else ident name
-	in
+let output_char ctx c =
+	Buffer.add_char ctx.out c
 
-	Array.iter (fun t ->
-		match t with
-		| HObj o ->
-			let name = tname o.pname in
-			line ("struct _" ^ name ^ " {");
-			block();
-			let rec loop o =
-				(match o.psuper with
-				| None -> expr ("hl_type *$type");
-				| Some c -> loop c);
-				Array.iteri (fun i (n,_,t) ->
-					let rec abs_index p v =
-						match p with
-						| None -> v
-						| Some o -> abs_index o.psuper (Array.length o.pfields + v)
-					in
-					expr (var_type (if n = "" then unamed_field (abs_index o.psuper i) else n) t)
-				) o.pfields;
-			in
-			loop o;
-			unblock();
-			expr "}";
-		| HEnum e ->
-			Array.iteri (fun i (_,_,pl) ->
-				if Array.length pl <> 0 then begin
-					line ("typedef struct {");
-					block();
-					expr "int index";
-					Array.iteri (fun i t ->
-						expr (var_type ("p" ^ string_of_int i) t)
-					) pl;
-					unblock();
-					sexpr "} %s" (enum_constr_type e i);
-				end;
-			) e.efields
-		| _ ->
-			()
-	) all_types;
+let line ctx str =
+	output ctx ctx.tabs;
+	output ctx str;
+	output_char ctx '\n'
 
-	line "";
-	line "// Types values declaration";
-	Array.iteri (fun i t ->
-		sexpr "static hl_type type$%d = { %s } /* %s */" i (type_id t) (tstr t);
-		match t with
-		| HObj o ->
-			sline "#define %s__val &type$%d" (tname o.pname) i
-		| _ ->
-			()
-	) all_types;
+let expr ctx str =
+	output ctx ctx.tabs;
+	output ctx str;
+	output ctx ";\n"
 
-	line "";
-	line "// Globals";
-	Array.iteri (fun i t ->
-		let name = "global$" ^ string_of_int i in
-		sexpr "static %s = 0" (var_type name t)
-	) code.globals;
+let unamed_field fid = "$_f" ^ string_of_int fid
 
-	line "";
-	line "// Natives functions";
-	Array.iter (fun (lib,name,t,idx) ->
-		match t with
-		| HFun (args,t) ->
-			let fname =
-				let lib = code.strings.(lib) in
-				let lib = if lib = "std" then "hl" else lib in
-				lib ^ "_" ^ code.strings.(name)
-			in
-			sexpr "HL_API %s %s(%s)" (ctype t) fname (String.concat "," (List.map ctype args));
-			funnames.(idx) <- fname;
-			Array.set tfuns idx (args,t)
-		| _ ->
-			assert false
-	) code.natives;
+let obj_field fid name =
+	if name = "" then unamed_field fid else ident name
 
-	line "";
-	line "// Functions declaration";
-	Array.iter (fun f ->
-		match f.ftype with
-		| HFun (args,t) ->
-			let fname = String.concat "_" (ExtString.String.nsplit (fundecl_name f) ".") in
-			sexpr "static %s %s(%s)" (ctype t) fname (String.concat "," (List.map ctype args));
-			Array.set tfuns f.findex (args,t);
-			funnames.(f.findex) <- fname;
-		| _ ->
-			assert false
-	) code.functions;
+let close_file ctx =
+	let str = Buffer.contents ctx.out in
+	Buffer.reset ctx.out;
+	let fpath = ctx.dir ^ "/" ^ ctx.curfile in
+	if String.sub ctx.curfile (String.length ctx.curfile - 2) 2 = ".c" then ctx.cfiles <- ctx.curfile :: ctx.cfiles;
+	ctx.curfile <- "";
+	let fcontent = (try Std.input_file ~bin:true fpath with _ -> "") in
+	if fcontent <> str then begin
+		Common.mkdir_recursive "" (ExtString.String.nsplit (Filename.dirname fpath) "/");
+		let ch = open_out_bin fpath in
+		output_string ch str;
+		close_out ch;
+	end
 
-	line "";
-	line "// Strings";
-	Array.iteri (fun i str ->
-		let rec loop s i =
-			if i = String.length s then [] else
-			let c = String.get s i in
-			string_of_int (int_of_char c) :: loop s (i+1)
-		in
-		if Hashtbl.mem bytes_strings i then
-			sexpr "static vbyte bytes$%d[] = {%s}" i (String.concat "," (loop str 0))
-		else
-			let s = utf8_to_utf16 str in
-			sexpr "static vbyte string$%d[] = {%s} /* %s */" i (String.concat "," (loop s 0)) (String.escaped (String.concat "* /" (ExtString.String.nsplit str "*/")))
-	) code.strings;
+let open_file ctx file =
+	if ctx.curfile <> "" then close_file ctx;
+	let version_major = ctx.version / 1000 in
+	let version_minor = (ctx.version mod 1000) / 100 in
+	let version_revision = (ctx.version mod 100) in
+	if file <> "hlc.json" then line ctx (sprintf "// Generated by HLC %d.%d.%d (HL v%d)" version_major version_minor version_revision ctx.hlcode.version);
+	ctx.curfile <- file
 
-	let type_value t =
-		let index = (try PMap.find t htypes with Not_found -> assert false) in
-		"&type$" ^ string_of_int index
-	in
+let string_data_limit = 64
 
-	line "";
-	line "// Types values data";
-	Array.iteri (fun i t ->
-		let field_value (name,name_id,t) =
-			sprintf "{(const uchar*)string$%d, %s, %ld}" name_id (type_value t) (hash name_id)
-		in
-		match t with
-		| HObj o ->
-			let proto_value p =
-				sprintf "{(const uchar*)string$%d, %d, %d, %ld}" p.fid p.fmethod (match p.fvirtual with None -> -1 | Some i -> i) (hash p.fid)
-			in
-			let fields =
-				if Array.length o.pfields = 0 then "NULL" else
-				let name = sprintf "fields$%d" i in
-				sexpr "static hl_obj_field %s[] = {%s}" name (String.concat "," (List.map field_value (Array.to_list o.pfields)));
-				name
-			in
-			let proto =
-				if Array.length o.pproto = 0 then "NULL" else
-				let name = sprintf "proto$%d" i in
-				sexpr "static hl_obj_proto %s[] = {%s}" name (String.concat "," (List.map proto_value (Array.to_list o.pproto)));
-				name
-			in
-			let ofields = [
-				string_of_int (Array.length o.pfields);
-				string_of_int (Array.length o.pproto);
-				sprintf "(const uchar*)string$%d" o.pid;
-				(match o.psuper with None -> "NULL" | Some c -> sprintf "%s__val" (tname c.pname));
-				fields;
-				proto
-			] in
-			sexpr "static hl_type_obj obj$%d = {%s}" i (String.concat "," ofields);
-		| HEnum e ->
-			let constr_name = sprintf "econstructs$%d" i in
-			let constr_value cid (_,nid,tl) =
-				let tval = if Array.length tl = 0 then "NULL" else
-					let name = sprintf "econstruct$%d_%d" i cid in
-					sexpr "static hl_type *%s[] = {%s}" name (String.concat "," (List.map type_value (Array.to_list tl)));
-					name
-				in
-				let size = if Array.length tl = 0 then "0" else sprintf "sizeof(%s)" (enum_constr_type e cid) in
-				let offsets = if Array.length tl = 0 then "NULL" else
-					let name = sprintf "eoffsets$%d_%d" i cid in
-					sexpr "static int %s[] = {%s}" name (String.concat "," (List.map (fun _ -> "0") (Array.to_list tl)));
-					name
-				in
-				let has_ptr = List.exists is_gc_ptr (Array.to_list tl) in
-				sprintf "{(const uchar*)string$%d, %d, %s, %s, %s, %s}" nid (Array.length tl) tval size (if has_ptr then "true" else "false") offsets
-			in
-			sexpr "static hl_enum_construct %s[] = {%s}" constr_name (String.concat "," (Array.to_list (Array.mapi constr_value e.efields)));
-			let efields = [
-				if e.eid = 0 then "NULL" else sprintf "(const uchar*)string$%d" e.eid;
-				string_of_int (Array.length e.efields);
-				constr_name
-			] in
-			sexpr "static hl_type_enum enum$%d = {%s}" i (String.concat "," efields);
-		| HVirtual v ->
-			let fields_name =
-				if Array.length v.vfields = 0 then "NULL" else
-				let name = sprintf "vfields$%d" i in
-				sexpr "static hl_obj_field %s[] = {%s}" name (String.concat "," (List.map field_value (Array.to_list v.vfields)));
-				name
-			in
-			let vfields = [
-				fields_name;
-				string_of_int (Array.length v.vfields)
-			] in
-			sexpr "static hl_type_virtual virt$%d = {%s}" i (String.concat "," vfields);
-		| HFun (args,t) ->
-			let aname = if args = [] then "NULL" else
-				let name = sprintf "fargs$%d" i in
-				sexpr "static hl_type *%s[] = {%s}" name (String.concat "," (List.map type_value args));
-				name
-			in
-			sexpr "static hl_type_fun tfun$%d = {%s,%s,%d}" i aname (type_value t) (List.length args)
-		| _ ->
-			()
-	) all_types;
+let string ctx sid =
+	let s = ctx.hlcode.strings.(sid) in
+	if String.length s < string_data_limit then
+		sprintf "USTR(\"%s\")" (Ast.s_escape ~hex:false s)
+	else
+		sprintf "string$%d" sid
 
-	line "";
-	line "// Static data";
-	Hashtbl.iter (fun fid _ ->
-		let args, t = tfuns.(fid) in
-		sexpr "static vclosure cl$%d = { %s, %s, 0 }" fid (type_value (HFun (args,t))) funnames.(fid);
-	) used_closures;
+let generate_reflection ctx =
+	let line = line ctx and expr = expr ctx in
+	let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
 
-	line "";
-	line "// Reflection helpers";
 	let funByArgs = Hashtbl.create 0 in
 	let type_kind t =
 		match t with
@@ -490,19 +289,19 @@ let write_c version file (code:code) =
 				| _ -> ())
 			| _ -> ()
 		) f.code
-	) code.functions;
-	Array.iter (fun (args,t) -> add_fun args t) tfuns;
+	) ctx.hlcode.functions;
+	Array.iter (fun f -> add_fun f.fe_args f.fe_ret) ctx.ftable;
 	let argsCounts = List.sort compare (Hashtbl.fold (fun i _ acc -> i :: acc) funByArgs []) in
 	sexpr "static int TKIND[] = {%s}" (String.concat "," (List.map (fun t -> string_of_int (type_kind_id (type_kind t))) core_types));
 	line "";
 	line "void *hlc_static_call( void *fun, hl_type *t, void **args, vdynamic *out ) {";
-	block();
+	block ctx;
 	sexpr "int chk = TKIND[t->fun->ret->kind]";
 	sexpr "vdynamic *d";
 	line "switch( t->fun->nargs ) {";
 	List.iter (fun nargs ->
 		sline "case %d:" nargs;
-		block();
+		block ctx;
 		if nargs > 9 then sexpr "hl_fatal(\"Too many arguments, TODO:use more bits\")" else begin
 		for i = 0 to nargs-1 do
 			sexpr "chk |= TKIND[t->fun->args[%d]->kind] << %d" i ((i + 1) * 3);
@@ -512,7 +311,7 @@ let write_c version file (code:code) =
 			let s = ref (-1) in
 			let chk = List.fold_left (fun chk t -> incr s; chk lor ((type_kind_id t) lsl (!s * 3))) 0 (t :: args) in
 			sline "case %d:" chk;
-			block();
+			block ctx;
 			let idx = ref (-1) in
 			let vargs = List.map (fun t ->
 				incr idx;
@@ -531,17 +330,17 @@ let write_c version file (code:code) =
 				sexpr "out%s = %s" (dyn_value_field t) call;
 				sexpr "return &out%s" (dyn_value_field t);
 			end;
-			unblock();
+			unblock ctx;
 		) (Hashtbl.find funByArgs nargs);
 		sline "}";
 		expr "break";
 		end;
-		unblock();
+		unblock ctx;
 	) argsCounts;
 	line "}";
 	sexpr "hl_fatal(\"Unsupported dynamic call\")";
 	sexpr "return NULL";
-	unblock();
+	unblock ctx;
 	line "}";
 	line "";
 	let wrap_char = function
@@ -558,7 +357,7 @@ let write_c version file (code:code) =
 		Hashtbl.iter (fun (args,t) _ ->
 			let name = make_wrap_name args t in
 			sline "static %s wrap_%s(void *value%s) {" (ctype t) name (String.concat "" (list_mapi (fun i t -> "," ^ var_type ("p" ^ string_of_int i) t) args));
-			block();
+			block ctx;
 			if args <> [] then sexpr "void *args[] = {%s}" (String.concat "," (list_mapi (fun i t ->
 				if not (is_ptr t) then
 					sprintf "&p%d" i
@@ -575,18 +374,18 @@ let write_c version file (code:code) =
 				sexpr "hl_wrapper_call(value,%s,&ret)" vargs;
 				sexpr "return ret.v.%s" (wrap_char t);
 			end;
-			unblock();
+			unblock ctx;
 			line "}";
 		) (Hashtbl.find funByArgs nargs);
 	) argsCounts;
 	line "";
 	line "void *hlc_get_wrapper( hl_type *t ) {";
-	block();
+	block ctx;
 	sexpr "int chk = TKIND[t->fun->ret->kind]";
 	line "switch( t->fun->nargs ) {";
 	List.iter (fun nargs ->
 		sline "case %d:" nargs;
-		block();
+		block ctx;
 		if nargs > 9 then sexpr "hl_fatal(\"Too many arguments, TODO:use more bits\")" else begin
 		for i = 0 to nargs-1 do
 			sexpr "chk |= TKIND[t->fun->args[%d]->kind] << %d" i ((i + 1) * 3);
@@ -600,619 +399,1012 @@ let write_c version file (code:code) =
 		sline "}";
 		expr "break";
 		end;
-		unblock();
+		unblock ctx;
 	) argsCounts;
 	line "}";
 	sexpr "return NULL";
-	unblock();
+	unblock ctx;
 	line "}";
-	line "";
-	line "// Functions code";
-	Array.iter (fun f ->
+	line ""
 
-		flush_file();
+let generate_function ctx f =
+	let line = line ctx and expr = expr ctx in
+	let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
+	let block() = block ctx and unblock() = unblock ctx in
+	let type_value = type_value ctx in
+	let code = ctx.hlcode in
 
-		let rid = ref (-1) in
-		let reg id = "r" ^ string_of_int id in
+	let rid = ref (-1) in
+	let reg id = "r" ^ string_of_int id in
 
-		let label id = "label$" ^ string_of_int f.findex ^ "$" ^ string_of_int id in
+	let label id = "label$" ^ string_of_int f.findex ^ "$" ^ string_of_int id in
 
-		let rtype r = f.regs.(r) in
+	let rtype r = f.regs.(r) in
 
-		let rcast r t =
-			if tsame (rtype r) t then (reg r)
-			else Printf.sprintf "((%s)%s)" (ctype t) (reg r)
-		in
+	let funname fid = ctx.ftable.(fid).fe_name in
 
-		let rfun r args t =
-			cast_fun (reg r ^ "->fun") args t
-		in
+	let rcast r t =
+		if tsame (rtype r) t then (reg r)
+		else Printf.sprintf "((%s)%s)" (ctype t) (reg r)
+	in
 
-		let rassign r t =
-			let rt = rtype r in
-			if t = HVoid then "" else
-			let assign = reg r ^ " = " in
-			if tsame t rt then assign else
-			if not (safe_cast t rt) then assert false
-			else assign ^ "(" ^ ctype rt ^ ")"
-		in
+	let rfun r args t =
+		cast_fun (reg r ^ "->fun") args t
+	in
 
-		let ocall r fid args =
-			let targs, rt = tfuns.(fid) in
-			let rstr = rassign r rt in
-			sexpr "%s%s(%s)" rstr funnames.(fid) (String.concat "," (List.map2 rcast args targs))
-		in
+	let rassign r t =
+		let rt = rtype r in
+		if t = HVoid then "" else
+		let assign = reg r ^ " = " in
+		if tsame t rt then assign else
+		if not (safe_cast t rt) then assert false
+		else assign ^ "(" ^ ctype rt ^ ")"
+	in
 
+	let ocall r fid args =
+		let ft = ctx.ftable.(fid) in
+		let rstr = rassign r ft.fe_ret in
+		sexpr "%s%s(%s)" rstr ft.fe_name (String.concat "," (List.map2 rcast args ft.fe_args))
+	in
 
-		let dyn_prefix = function
-			| HUI8 | HUI16 | HI32 | HBool -> "i"
-			| HF32 -> "f"
-			| HF64 -> "d"
-			| _ -> "p"
-		in
 
-		let type_value_opt t =
-			match t with HF32 | HF64 -> "" | _ -> "," ^ type_value t
-		in
+	let dyn_prefix = function
+		| HUI8 | HUI16 | HI32 | HBool -> "i"
+		| HF32 -> "f"
+		| HF64 -> "d"
+		| _ -> "p"
+	in
 
-		let dyn_call r f pl =
-			line "{";
-			block();
-			if pl <> [] then sexpr "vdynamic *args[] = {%s}" (String.concat "," (List.map (fun p ->
-				match rtype p with
-				| HDyn ->
-					reg p
-				| t ->
-					if is_dynamic t then
-						sprintf "(vdynamic*)%s" (reg p)
-					else
-						sprintf "hl_make_dyn(&%s,%s)" (reg p) (type_value t)
-			) pl));
-			let rt = rtype r in
-			let ret = if rt = HVoid then "" else if is_dynamic rt then sprintf "%s = (%s)" (reg r) (ctype rt) else "vdynamic *ret = " in
-			sexpr "%shl_dyn_call((vclosure*)%s,%s,%d)" ret (reg f) (if pl = [] then "NULL" else "args") (List.length pl);
-			if rt <> HVoid && not (is_dynamic rt) then sexpr "%s = (%s)hl_dyn_cast%s(&ret,&hlt_dyn%s)" (reg r) (ctype rt) (dyn_prefix rt) (type_value_opt rt);
-			unblock();
-			line "}";
-		in
+	let type_value_opt t =
+		match t with HF32 | HF64 -> "" | _ -> "," ^ type_value t
+	in
 
-		let mcall r fid = function
-			| [] -> assert false
-			| o :: args ->
-				match rtype o with
-				| HObj _ ->
-					let vfun = cast_fun (sprintf "%s->$type->vobj_proto[%d]" (reg o) fid) (rtype o :: List.map rtype args) (rtype r) in
-					sexpr "%s%s(%s)" (rassign r (rtype r)) vfun (String.concat "," (List.map reg (o::args)))
-				| HVirtual vp ->
-					let rt = rtype r in
-					let meth = sprintf "hl_vfields(%s)[%d]" (reg o) fid in
-					let meth = cast_fun meth (HDyn :: List.map rtype args) rt in
-					sline "if( hl_vfields(%s)[%d] ) %s%s(%s); else {" (reg o) fid (rassign r rt) meth (String.concat "," ((reg o ^ "->value") :: List.map reg args));
-					block();
-					if args <> [] then sexpr "void *args[] = {%s}" (String.concat "," (List.map (fun p ->
-						let t = rtype p in
-						if is_ptr t then
-							reg p
-						else
-							sprintf "&%s" (reg p)
-					) args));
-					let rt = rtype r in
-					let ret = if rt = HVoid then "" else if is_ptr rt then sprintf "%s = (%s)" (reg r) (ctype rt) else begin sexpr "vdynamic ret"; ""; end in
-					let fname, fid, ft = vp.vfields.(fid) in
-					sexpr "%shl_dyn_call_obj(%s->value,%s,%ld/*%s*/,%s,%s)" ret (reg o) (type_value ft) (hash fid) fname (if args = [] then "NULL" else "args") (if is_ptr rt || rt == HVoid then "NULL" else "&ret");
-					if rt <> HVoid && not (is_ptr rt) then sexpr "%s = (%s)ret.v.%s" (reg r) (ctype rt) (dyn_prefix rt);
-					unblock();
-					sline "}"
-				| _ ->
-					assert false
-		in
+	let dyn_call r f pl =
+		line "{";
+		block();
+		if pl <> [] then sexpr "vdynamic *args[] = {%s}" (String.concat "," (List.map (fun p ->
+			match rtype p with
+			| HDyn ->
+				reg p
+			| t ->
+				if is_dynamic t then
+					sprintf "(vdynamic*)%s" (reg p)
+				else
+					sprintf "hl_make_dyn(&%s,%s)" (reg p) (type_value t)
+		) pl));
+		let rt = rtype r in
+		let ret = if rt = HVoid then "" else if is_dynamic rt then sprintf "%s = (%s)" (reg r) (ctype rt) else "vdynamic *ret = " in
+		sexpr "%shl_dyn_call((vclosure*)%s,%s,%d)" ret (reg f) (if pl = [] then "NULL" else "args") (List.length pl);
+		if rt <> HVoid && not (is_dynamic rt) then sexpr "%s = (%s)hl_dyn_cast%s(&ret,&hlt_dyn%s)" (reg r) (ctype rt) (dyn_prefix rt) (type_value_opt rt);
+		unblock();
+		line "}";
+	in
 
-		let set_field obj fid v =
-			match rtype obj with
-			| HObj o ->
-				let name, t = resolve_field o fid in
-				sexpr "%s->%s = %s" (reg obj) (obj_field fid name) (rcast v t)
+	let mcall r fid = function
+		| [] -> assert false
+		| o :: args ->
+			match rtype o with
+			| HObj _ ->
+				let vfun = cast_fun (sprintf "%s->$type->vobj_proto[%d]" (reg o) fid) (rtype o :: List.map rtype args) (rtype r) in
+				sexpr "%s%s(%s)" (rassign r (rtype r)) vfun (String.concat "," (List.map reg (o::args)))
 			| HVirtual vp ->
-				let name, nid, t = vp.vfields.(fid) in
-				let dset = sprintf "hl_dyn_set%s(%s->value,%ld/*%s*/%s,%s)" (dyn_prefix t) (reg obj) (hash nid) name (type_value_opt (rtype v)) (reg v) in
-				(match t with
-				| HFun _ -> expr dset
-				| _ -> sexpr "if( hl_vfields(%s)[%d] ) *(%s*)(hl_vfields(%s)[%d]) = (%s)%s; else %s" (reg obj) fid (ctype t) (reg obj) fid (ctype t) (reg v) dset)
+				let rt = rtype r in
+				let meth = sprintf "hl_vfields(%s)[%d]" (reg o) fid in
+				let meth = cast_fun meth (HDyn :: List.map rtype args) rt in
+				sline "if( hl_vfields(%s)[%d] ) %s%s(%s); else {" (reg o) fid (rassign r rt) meth (String.concat "," ((reg o ^ "->value") :: List.map reg args));
+				block();
+				if args <> [] then sexpr "void *args[] = {%s}" (String.concat "," (List.map (fun p ->
+					let t = rtype p in
+					if is_ptr t then
+						reg p
+					else
+						sprintf "&%s" (reg p)
+				) args));
+				let rt = rtype r in
+				let ret = if rt = HVoid then "" else if is_ptr rt then sprintf "%s = (%s)" (reg r) (ctype rt) else begin sexpr "vdynamic ret"; ""; end in
+				let fname, fid, ft = vp.vfields.(fid) in
+				sexpr "%shl_dyn_call_obj(%s->value,%s,%ld/*%s*/,%s,%s)" ret (reg o) (type_value ft) (hash ctx fid) fname (if args = [] then "NULL" else "args") (if is_ptr rt || rt == HVoid then "NULL" else "&ret");
+				if rt <> HVoid && not (is_ptr rt) then sexpr "%s = (%s)ret.v.%s" (reg r) (ctype rt) (dyn_prefix rt);
+				unblock();
+				sline "}"
 			| _ ->
 				assert false
-		in
+	in
 
-		let get_field r obj fid =
-			match rtype obj with
-			| HObj o ->
-				let name, t = resolve_field o fid in
-				sexpr "%s%s->%s" (rassign r t) (reg obj) (obj_field fid name)
-			| HVirtual v ->
-				let name, nid, t = v.vfields.(fid) in
-				let dget = sprintf "(%s)hl_dyn_get%s(%s->value,%ld/*%s*/%s)" (ctype t) (dyn_prefix t) (reg obj) (hash nid) name (type_value_opt t) in
-				(match t with
-				| HFun _ -> sexpr "%s%s" (rassign r t) dget
-				| _ -> sexpr "%shl_vfields(%s)[%d] ? (*(%s*)(hl_vfields(%s)[%d])) : %s" (rassign r t) (reg obj) fid (ctype t) (reg obj) fid dget)
-			| _ ->
-				assert false
-		in
+	let set_field obj fid v =
+		match rtype obj with
+		| HObj o ->
+			let name, t = resolve_field o fid in
+			sexpr "%s->%s = %s" (reg obj) (obj_field fid name) (rcast v t)
+		| HVirtual vp ->
+			let name, nid, t = vp.vfields.(fid) in
+			let dset = sprintf "hl_dyn_set%s(%s->value,%ld/*%s*/%s,%s)" (dyn_prefix t) (reg obj) (hash ctx nid) name (type_value_opt (rtype v)) (reg v) in
+			(match t with
+			| HFun _ -> expr dset
+			| _ -> sexpr "if( hl_vfields(%s)[%d] ) *(%s*)(hl_vfields(%s)[%d]) = (%s)%s; else %s" (reg obj) fid (ctype t) (reg obj) fid (ctype t) (reg v) dset)
+		| _ ->
+			assert false
+	in
 
-		let fret = (match f.ftype with
-		| HFun (args,t) ->
-			sline "static %s %s(%s) {" (ctype t) funnames.(f.findex) (String.concat "," (List.map (fun t -> incr rid; var_type (reg !rid) t) args));
-			t
+	let get_field r obj fid =
+		match rtype obj with
+		| HObj o ->
+			let name, t = resolve_field o fid in
+			sexpr "%s%s->%s" (rassign r t) (reg obj) (obj_field fid name)
+		| HVirtual v ->
+			let name, nid, t = v.vfields.(fid) in
+			let dget = sprintf "(%s)hl_dyn_get%s(%s->value,%ld/*%s*/%s)" (ctype t) (dyn_prefix t) (reg obj) (hash ctx nid) name (type_value_opt t) in
+			(match t with
+			| HFun _ -> sexpr "%s%s" (rassign r t) dget
+			| _ -> sexpr "%shl_vfields(%s)[%d] ? (*(%s*)(hl_vfields(%s)[%d])) : %s" (rassign r t) (reg obj) fid (ctype t) (reg obj) fid dget)
 		| _ ->
 			assert false
-		) in
-		block();
-		let var_map = Hashtbl.create 0 in
-		Array.iteri (fun i t ->
-			if i <= !rid || t = HVoid then ()
-			else
-				let key = ctype_no_ptr t in
-				Hashtbl.replace var_map key (try (reg i) :: Hashtbl.find var_map key with Not_found -> [reg i])
-		) f.regs;
-		Hashtbl.iter (fun (s,i) il ->
-			let prefix = String.make i '*' in
-			let il = List.rev_map (fun s -> prefix ^ s) il in
-			sexpr "%s %s" s (String.concat ", " il)
-		) var_map;
-		let output_options = Array.make (Array.length f.code + 1) [] in
-		let output_at i oo = output_options.(i) <- oo :: output_options.(i) in
-		let output_at2 i ool = List.iter (output_at i) ool in
-		let has_label i = List.exists (function OOLabel -> true | _ -> false) output_options.(i) in
-
-		let trap_depth = ref 0 in
-		let max_trap_depth = ref 0 in
-		Array.iter (fun op ->
-			match op with
-			| OTrap _ ->
-				incr trap_depth;
-				if !trap_depth > !max_trap_depth then max_trap_depth := !trap_depth
-			| OEndTrap true ->
-				decr trap_depth
-			| _ ->
-				()
-		) f.code;
-		for i = 0 to !max_trap_depth - 1 do
-			sexpr "hl_trap_ctx trap$%d" i;
-		done;
+	in
 
-		let flush_options i =
-			match output_options.(i) with
-			| [] -> ()
-			| opts ->
-				(* put label after } *)
-				let opts = if has_label i && List.mem OOEndBlock opts then OOLabel :: List.filter (fun i -> i <> OOLabel) opts else opts in
-				let opts = List.rev opts in
-				List.iter (function
-					| OOLabel -> sline "%s:" (label i)
-					| OOCase i -> sline "case %i:" i
-					| OODefault -> line "default:"
-					| OOIncreaseIndent -> block()
-					| OODecreaseIndent -> unblock()
-					| OOBeginBlock ->  line "{"
-					| OOEndBlock -> line "}"
-				) opts
-		in
+	let fret = (match f.ftype with
+	| HFun (args,t) ->
+		sline "%s %s(%s) {" (ctype t) (funname f.findex) (String.concat "," (List.map (fun t -> incr rid; var_type (reg !rid) t) args));
+		t
+	| _ ->
+		assert false
+	) in
+	block();
+	let var_map = Hashtbl.create 0 in
+	Array.iteri (fun i t ->
+		if i <= !rid || t = HVoid then ()
+		else
+			let key = ctype_no_ptr t in
+			Hashtbl.replace var_map key (try (reg i) :: Hashtbl.find var_map key with Not_found -> [reg i])
+	) f.regs;
+	Hashtbl.iter (fun (s,i) il ->
+		let prefix = String.make i '*' in
+		let il = List.rev_map (fun s -> prefix ^ s) il in
+		sexpr "%s %s" s (String.concat ", " il)
+	) var_map;
+	let output_options = Array.make (Array.length f.code + 1) [] in
+	let output_at i oo = output_options.(i) <- oo :: output_options.(i) in
+	let output_at2 i ool = List.iter (output_at i) ool in
+	let has_label i = List.exists (function OOLabel -> true | _ -> false) output_options.(i) in
 
-		Array.iteri (fun i op ->
-			flush_options i;
-			let label delta =
-				let addr = delta + i + 1 in
-				let label = label addr in
-				if not (has_label addr) then output_at addr OOLabel;
-				label
-			in
-			let todo() =
-				sexpr "hl_fatal(\"%s\")" (ostr (fun id -> "f" ^ string_of_int id) op)
+	let trap_depth = ref 0 in
+	let max_trap_depth = ref 0 in
+	Array.iter (fun op ->
+		match op with
+		| OTrap _ ->
+			incr trap_depth;
+			if !trap_depth > !max_trap_depth then max_trap_depth := !trap_depth
+		| OEndTrap true ->
+			decr trap_depth
+		| _ ->
+			()
+	) f.code;
+	for i = 0 to !max_trap_depth - 1 do
+		sexpr "hl_trap_ctx trap$%d" i;
+	done;
+
+	let flush_options i =
+		match output_options.(i) with
+		| [] -> ()
+		| opts ->
+			(* put label after } *)
+			let opts = if has_label i && List.mem OOEndBlock opts then OOLabel :: List.filter (fun i -> i <> OOLabel) opts else opts in
+			let opts = List.rev opts in
+			List.iter (function
+				| OOLabel -> sline "%s:" (label i)
+				| OOCase i -> sline "case %i:" i
+				| OODefault -> line "default:"
+				| OOIncreaseIndent -> block()
+				| OODecreaseIndent -> unblock()
+				| OOBeginBlock ->  line "{"
+				| OOEndBlock -> line "}"
+			) opts
+	in
+
+	Array.iteri (fun i op ->
+		flush_options i;
+		let label delta =
+			let addr = delta + i + 1 in
+			let label = label addr in
+			if not (has_label addr) then output_at addr OOLabel;
+			label
+		in
+		let todo() =
+			sexpr "hl_fatal(\"%s\")" (ostr (fun id -> "f" ^ string_of_int id) op)
+		in
+		let rec compare_op op a b d =
+			let phys_compare() =
+				sexpr "if( %s %s %s ) goto %s" (reg a) (s_comp op) (rcast b (rtype a)) (label d)
 			in
-			let rec compare_op op a b d =
-				let phys_compare() =
-					sexpr "if( %s %s %s ) goto %s" (reg a) (s_comp op) (rcast b (rtype a)) (label d)
-				in
-				(*
-					safe_cast is already checked
-					two ways (same type) for eq
-					one way for comparisons
-				*)
-				match rtype a, rtype b with
-				| (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool), (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool) ->
-					phys_compare()
-				| HType, HType ->
-					sexpr "if( hl_same_type(%s,%s) %s 0 ) {} else goto %s" (reg a) (reg b) (s_comp op) (label d)
-				| HNull t, HNull _ ->
-					let field = dyn_value_field t in
-					let pcompare = sprintf "(%s%s %s %s%s)" (reg a) field (s_comp op) (reg b) field in
-					if op = CEq then
-						sexpr "if( %s == %s || (%s && %s && %s) ) goto %s" (reg a) (reg b) (reg a) (reg b) pcompare (label d)
-					else if op = CNeq then
-						sexpr "if( %s != %s && (!%s || !%s || %s) ) goto %s" (reg a) (reg b) (reg a) (reg b) pcompare (label d)
-					else
-						sexpr "if( %s && %s && %s ) goto %s" (reg a) (reg b) pcompare (label d)
-				| HDyn , _ | _, HDyn ->
-					let inv = if op = CGt || op = CGte then "&& i != hl_invalid_comparison " else "" in
-					sexpr "{ int i = hl_dyn_compare((vdynamic*)%s,(vdynamic*)%s); if( i %s 0 %s) goto %s; }" (reg a) (reg b) (s_comp op) inv (label d)
-				| HObj oa, HObj _ ->
-					(try
-						let fid = PMap.find "__compare" oa.pfunctions in
-						if op = CEq then
-							sexpr "if( %s == %s || (%s && %s && %s(%s,%s) == 0) ) goto %s" (reg a) (reg b) (reg a) (reg b) funnames.(fid) (reg a) (reg b) (label d)
-						else if op = CNeq then
-							sexpr "if( %s != %s && (!%s || !%s || %s(%s,%s) != 0) ) goto %s" (reg a) (reg b) (reg a) (reg b) funnames.(fid) (reg a) (reg b) (label d)
-						else
-							sexpr "if( %s && %s && %s(%s,%s) %s 0 ) goto %s" (reg a) (reg b) funnames.(fid) (reg a) (reg b) (s_comp op) (label d)
-					with Not_found ->
-						phys_compare())
-				| HVirtual _, HVirtual _ ->
-					if op = CEq then
-						sexpr "if( %s == %s || (%s && %s && %s->value && %s->value && %s->value == %s->value) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (label d)
-					else if op = CNeq then
-						sexpr "if( %s != %s && (!%s || !%s || !%s->value || !%s->value || %s->value != %s->value) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (label d)
-					else
-						assert false
-				| HEnum _, HEnum _ | HDynObj, HDynObj ->
-					phys_compare()
-				| HVirtual _, HObj _->
+			(*
+				safe_cast is already checked
+				two ways (same type) for eq
+				one way for comparisons
+			*)
+			match rtype a, rtype b with
+			| (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool), (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool) ->
+				phys_compare()
+			| HType, HType ->
+				sexpr "if( hl_same_type(%s,%s) %s 0 ) {} else goto %s" (reg a) (reg b) (s_comp op) (label d)
+			| HNull t, HNull _ ->
+				let field = dyn_value_field t in
+				let pcompare = sprintf "(%s%s %s %s%s)" (reg a) field (s_comp op) (reg b) field in
+				if op = CEq then
+					sexpr "if( %s == %s || (%s && %s && %s) ) goto %s" (reg a) (reg b) (reg a) (reg b) pcompare (label d)
+				else if op = CNeq then
+					sexpr "if( %s != %s && (!%s || !%s || %s) ) goto %s" (reg a) (reg b) (reg a) (reg b) pcompare (label d)
+				else
+					sexpr "if( %s && %s && %s ) goto %s" (reg a) (reg b) pcompare (label d)
+			| HDyn , _ | _, HDyn ->
+				let inv = if op = CGt || op = CGte then "&& i != hl_invalid_comparison " else "" in
+				sexpr "{ int i = hl_dyn_compare((vdynamic*)%s,(vdynamic*)%s); if( i %s 0 %s) goto %s; }" (reg a) (reg b) (s_comp op) inv (label d)
+			| HObj oa, HObj _ ->
+				(try
+					let fid = PMap.find "__compare" oa.pfunctions in
 					if op = CEq then
-						sexpr "if( %s ? (%s && %s->value == (vdynamic*)%s) : (%s == NULL) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg b) (label d)
+						sexpr "if( %s == %s || (%s && %s && %s(%s,%s) == 0) ) goto %s" (reg a) (reg b) (reg a) (reg b) (funname fid) (reg a) (reg b) (label d)
 					else if op = CNeq then
-						sexpr "if( %s ? (%s == NULL || %s->value != (vdynamic*)%s) : (%s != NULL) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg b) (label d)
+						sexpr "if( %s != %s && (!%s || !%s || %s(%s,%s) != 0) ) goto %s" (reg a) (reg b) (reg a) (reg b) (funname fid) (reg a) (reg b) (label d)
 					else
-						assert false
-				| HObj _, HVirtual _ ->
-					compare_op op b a d
-				| HFun _, HFun _ ->
-					phys_compare()
-				| ta, tb ->
-					failwith ("Don't know how to compare " ^ tstr ta ^ " and " ^ tstr tb ^ " (hlc)")
-			in
-			match op with
-			| OMov (r,v) ->
-				if rtype r <> HVoid then sexpr "%s = %s" (reg r) (rcast v (rtype r))
-			| OInt (r,idx) ->
-				if code.ints.(idx) = 0x80000000l then
-					sexpr "%s = 0x80000000" (reg r)
+						sexpr "if( %s && %s && %s(%s,%s) %s 0 ) goto %s" (reg a) (reg b) (funname fid) (reg a) (reg b) (s_comp op) (label d)
+				with Not_found ->
+					phys_compare())
+			| HVirtual _, HVirtual _ ->
+				if op = CEq then
+					sexpr "if( %s == %s || (%s && %s && %s->value && %s->value && %s->value == %s->value) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (label d)
+				else if op = CNeq then
+					sexpr "if( %s != %s && (!%s || !%s || !%s->value || !%s->value || %s->value != %s->value) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (label d)
 				else
-					sexpr "%s = %ld" (reg r) code.ints.(idx)
-			| OFloat (r,idx) ->
-				sexpr "%s = %.19g" (reg r) code.floats.(idx)
-			| OBool (r,b) ->
-				sexpr "%s = %s" (reg r) (if b then "true" else "false")
-			| OBytes (r,idx) ->
-				sexpr "%s = bytes$%d" (reg r) idx
-			| OString (r,idx) ->
-				sexpr "%s = string$%d" (reg r) idx
-			| ONull r ->
-				sexpr "%s = NULL" (reg r)
-			| OAdd (r,a,b) ->
-				sexpr "%s = %s + %s" (reg r) (reg a) (reg b)
-			| OSub (r,a,b) ->
-				sexpr "%s = %s - %s" (reg r) (reg a) (reg b)
-			| OMul (r,a,b) ->
-				sexpr "%s = %s * %s" (reg r) (reg a) (reg b)
-			| OSDiv (r,a,b) ->
-				(match rtype r with
-				| HUI8 | HUI16 | HI32 ->
-					sexpr "%s = %s == 0 ? 0 : %s / %s" (reg r) (reg b) (reg a) (reg b)
-				| _ ->
-					sexpr "%s = %s / %s" (reg r) (reg a) (reg b))
-			| OUDiv (r,a,b) ->
-				sexpr "%s = %s == 0 ? 0 : ((unsigned)%s) / ((unsigned)%s)" (reg r) (reg b) (reg a) (reg b)
-			| OSMod (r,a,b) ->
-				(match rtype r with
-				| HUI8 | HUI16 | HI32 ->
-					sexpr "%s = %s == 0 ? 0 : %s %% %s" (reg r) (reg b) (reg a) (reg b)
-				| HF32 ->
-					sexpr "%s = fmodf(%s,%s)" (reg r) (reg a) (reg b)
-				| HF64 ->
-					sexpr "%s = fmod(%s,%s)" (reg r) (reg a) (reg b)
-				| _ ->
-					assert false)
-			| OUMod (r,a,b) ->
-				sexpr "%s = %s == 0 ? 0 : ((unsigned)%s) %% ((unsigned)%s)" (reg r) (reg b) (reg a) (reg b)
-			| OShl (r,a,b) ->
-				sexpr "%s = %s << %s" (reg r) (reg a) (reg b)
-			| OSShr (r,a,b) ->
-				sexpr "%s = %s >> %s" (reg r) (reg a) (reg b)
-			| OUShr (r,a,b) ->
-				sexpr "%s = ((unsigned)%s) >> %s" (reg r) (reg a) (reg b)
-			| OAnd (r,a,b) ->
-				sexpr "%s = %s & %s" (reg r) (reg a) (reg b)
-			| OOr (r,a,b) ->
-				sexpr "%s = %s | %s" (reg r) (reg a) (reg b)
-			| OXor (r,a,b) ->
-				sexpr "%s = %s ^ %s" (reg r) (reg a) (reg b)
-			| ONeg (r,v) ->
-				sexpr "%s = -%s" (reg r) (reg v)
-			| ONot (r,v) ->
-				sexpr "%s = !%s" (reg r) (reg v)
-			| OIncr r ->
-				sexpr "++%s" (reg r)
-			| ODecr r ->
-				sexpr "--%s" (reg r)
-			| OCall0 (r,fid) ->
-				ocall r fid []
-			| OCall1 (r,fid,a) ->
-				ocall r fid [a]
-			| OCall2 (r,fid,a,b) ->
-				ocall r fid [a;b]
-			| OCall3 (r,fid,a,b,c) ->
-				ocall r fid [a;b;c]
-			| OCall4 (r,fid,a,b,c,d) ->
-				ocall r fid [a;b;c;d]
-			| OCallN (r,fid,rl) ->
-				ocall r fid rl
-			| OCallMethod (r,fid,pl) ->
-				mcall r fid pl
-			| OCallThis (r,fid,pl) ->
-				mcall r fid (0 :: pl)
-			| OCallClosure (r,cl,pl) ->
-				(match rtype cl with
-				| HDyn ->
-					dyn_call r cl pl
-				| HFun (args,ret) ->
-					let sargs = String.concat "," (List.map2 rcast pl args) in
-					sexpr "%s%s->hasValue ? %s((vdynamic*)%s->value%s) : %s(%s)" (rassign r ret) (reg cl) (rfun cl (HDyn :: args) ret) (reg cl) (if sargs = "" then "" else "," ^ sargs) (rfun cl args ret) sargs
-				| _ ->
-					assert false)
-			| OStaticClosure (r,fid) ->
-				sexpr "%s = &cl$%d" (reg r) fid
-			| OSetMethod (o,f,fid) ->
-				let name, t = resolve_field (match rtype o with HObj o -> o | _ -> assert false) f in
-				sexpr "%s->%s = (%s)&cl$%d" (reg o) (ident name) (ctype t) fid
-			| OInstanceClosure (r,fid,ptr) ->
-				let args, t = tfuns.(fid) in
-				sexpr "%s = hl_alloc_closure_ptr(%s,%s,%s)" (reg r) (type_value (HFun (args,t))) funnames.(fid) (reg ptr)
-			| OVirtualClosure (r,o,m) ->
-				(match rtype o with
-				| HObj p ->
-					let tl,t = tfuns.(p.pvirtuals.(m)) in
-					let s = sprintf "%s->$type->vobj_proto[%d]" (reg o) m in
-					sexpr "%s = hl_alloc_closure_ptr(%s,%s,%s)" (reg r) (type_value (HFun(tl,t))) s (reg o)
-				| _ ->
-					todo())
-			| OGetGlobal (r,g) ->
-				sexpr "%s = (%s)global$%d" (reg r) (ctype (rtype r)) g
-			| OSetGlobal (g,r) ->
-				sexpr "global$%d = (%s)%s" g (ctype code.globals.(g)) (reg r)
-			| ORet r ->
-				if rtype r = HVoid then expr "return" else sexpr "return %s" (rcast r fret)
-			| OJTrue (r,d) | OJNotNull (r,d) ->
-				sexpr "if( %s ) goto %s" (reg r) (label d)
-			| OJFalse (r,d) | OJNull (r,d) ->
-				sexpr "if( !%s ) goto %s" (reg r) (label d)
-			| OJSLt (a,b,d) ->
-				compare_op CLt a b d
-			| OJSGte (a,b,d) ->
-				compare_op CGte a b d
-			| OJSGt (a,b,d) ->
-				compare_op CGt a b d
-			| OJSLte (a,b,d) ->
-				compare_op CLte a b d
-			| OJULt (a,b,d) ->
-				sexpr "if( ((unsigned)%s) < ((unsigned)%s) ) goto %s" (reg a) (reg b) (label d)
-			| OJUGte (a,b,d) ->
-				sexpr "if( ((unsigned)%s) >= ((unsigned)%s) ) goto %s" (reg a) (reg b) (label d)
-			| OJEq (a,b,d) ->
-				compare_op CEq a b d
-			| OJNotEq (a,b,d) ->
-				compare_op CNeq a b d
-			| OJAlways d ->
-				sexpr "goto %s" (label d)
-			| OLabel _ ->
-				if not (has_label i) then sline "%s:" (label (-1))
-			| OToDyn (r,v) ->
-				if is_ptr (rtype v) then begin
-					sline "if( %s == NULL ) %s = NULL; else {" (reg v) (reg r);
-					block();
-				end;
-				sexpr "%s = hl_alloc_dynamic(%s)" (reg r) (type_value (rtype v));
-				(match rtype v with
-				| HUI8 | HUI16 | HI32 | HBool ->
-					sexpr "%s->v.i = %s" (reg r) (reg v)
-				| HF32 ->
-					sexpr "%s->v.f = %s" (reg r) (reg v)
-				| HF64 ->
-					sexpr "%s->v.d = %s" (reg r) (reg v)
-				| _ ->
-					sexpr "%s->v.ptr = %s" (reg r) (reg v));
-				if is_ptr (rtype v) then begin
-					unblock();
-					line "}";
-				end;
-			| OToSFloat (r,v) ->
-				sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) (reg v)
-			| OToUFloat (r,v) ->
-				sexpr "%s = (%s)(unsigned)%s" (reg r) (ctype (rtype r)) (reg v)
-			| OToInt (r,v) ->
-				sexpr "%s = (int)%s" (reg r) (reg v)
-			| ONew r ->
-				(match rtype r with
-				| HObj o -> sexpr "%s = (%s)hl_alloc_obj(%s)" (reg r) (tname o.pname) (tname o.pname ^ "__val")
-				| HDynObj -> sexpr "%s = hl_alloc_dynobj()" (reg r)
-				| HVirtual _ as t -> sexpr "%s = hl_alloc_virtual(%s)" (reg r) (type_value t)
-				| _ -> assert false)
-			| OField (r,obj,fid) ->
-				get_field r obj fid
-			| OSetField (obj,fid,v) ->
-				set_field obj fid v
-			| OGetThis (r,fid) ->
-				get_field r 0 fid
-			| OSetThis (fid,r) ->
-				set_field 0 fid r
-			| OThrow r ->
-				sexpr "hl_throw((vdynamic*)%s)" (reg r)
-			| ORethrow r ->
-				sexpr "hl_rethrow((vdynamic*)%s)" (reg r)
-			| OGetUI8 (r,b,idx) ->
-				sexpr "%s = *(unsigned char*)(%s + %s)" (reg r) (reg b) (reg idx)
-			| OGetUI16 (r,b,idx) ->
-				sexpr "%s = *(unsigned short*)(%s + %s)" (reg r) (reg b) (reg idx)
-			| OGetI32 (r,b,idx) ->
-				sexpr "%s = *(int*)(%s + %s)" (reg r) (reg b) (reg idx)
-			| OGetF32 (r,b,idx) ->
-				sexpr "%s = *(float*)(%s + %s)" (reg r) (reg b) (reg idx)
-			| OGetF64 (r,b,idx) ->
-				sexpr "%s = *(double*)(%s + %s)" (reg r) (reg b) (reg idx)
-			| OGetArray (r, arr, idx) ->
-				sexpr "%s = ((%s*)(%s + 1))[%s]" (reg r) (ctype (rtype r)) (reg arr) (reg idx)
-			| OSetUI8 (b,idx,r) ->
-				sexpr "*(unsigned char*)(%s + %s) = (unsigned char)%s" (reg b) (reg idx) (reg r)
-			| OSetUI16 (b,idx,r) ->
-				sexpr "*(unsigned short*)(%s + %s) = (unsigned short)%s" (reg b) (reg idx) (reg r)
-			| OSetI32 (b,idx,r) ->
-				sexpr "*(int*)(%s + %s) = %s" (reg b) (reg idx) (reg r)
-			| OSetF32 (b,idx,r) ->
-				sexpr "*(float*)(%s + %s) = (float)%s" (reg b) (reg idx) (reg r)
-			| OSetF64 (b,idx,r) ->
-				sexpr "*(double*)(%s + %s) = %s" (reg b) (reg idx) (reg r)
-			| OSetArray (arr,idx,v) ->
-				sexpr "((%s*)(%s + 1))[%s] = %s" (ctype (rtype v)) (reg arr) (reg idx) (reg v)
-			| OSafeCast (r,v) ->
-				let tsrc = rtype v in
-				let t = rtype r in
-				if tsrc = HNull t then
-					sexpr "%s = %s ? %s%s : 0" (reg r) (reg v) (reg v) (dyn_value_field t)
+					assert false
+			| HEnum _, HEnum _ | HDynObj, HDynObj ->
+				phys_compare()
+			| HVirtual _, HObj _->
+				if op = CEq then
+					sexpr "if( %s ? (%s && %s->value == (vdynamic*)%s) : (%s == NULL) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg b) (label d)
+				else if op = CNeq then
+					sexpr "if( %s ? (%s == NULL || %s->value != (vdynamic*)%s) : (%s != NULL) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg b) (label d)
 				else
-					sexpr "%s = (%s)hl_dyn_cast%s(&%s,%s%s)" (reg r) (ctype t) (dyn_prefix t) (reg v) (type_value (rtype v)) (type_value_opt t)
-			| OUnsafeCast (r,v) ->
-				sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) (reg v)
-			| OArraySize (r,a) ->
-				sexpr "%s = %s->size" (reg r) (reg a)
-			| OType (r,t) ->
-				sexpr "%s = %s" (reg r) (type_value t)
-			| OGetType (r,v) ->
-				sexpr "%s = %s ? ((vdynamic*)%s)->t : &hlt_void" (reg r) (reg v) (reg v)
-			| OGetTID (r,v) ->
-				sexpr "%s = %s->kind" (reg r) (reg v)
-			| ORef (r,v) ->
-				sexpr "%s = &%s" (reg r) (reg v)
-			| OUnref (r,v) ->
-				sexpr "%s = *%s" (reg r) (reg v)
-			| OSetref (r,v) ->
-				sexpr "*%s = %s" (reg r) (reg v)
-			| OToVirtual (r,v) ->
-				sexpr "%s = hl_to_virtual(%s,(vdynamic*)%s)" (reg r) (type_value (rtype r)) (reg v)
-			| ODynGet (r,o,sid) ->
-				let t = rtype r in
-				let h = hash sid in
-				sexpr "%s = (%s)hl_dyn_get%s((vdynamic*)%s,%ld/*%s*/%s)" (reg r) (ctype t) (dyn_prefix t) (reg o) h code.strings.(sid) (type_value_opt t)
-			| ODynSet (o,sid,v) ->
-				let h = hash sid in
-				sexpr "hl_dyn_set%s((vdynamic*)%s,%ld/*%s*/%s,%s)" (dyn_prefix (rtype v)) (reg o) h code.strings.(sid) (type_value_opt (rtype v)) (reg v)
-			| OMakeEnum (r,cid,rl) ->
-				let e, et = (match rtype r with HEnum e -> e, enum_constr_type e cid | _ -> assert false) in
-				let has_ptr = List.exists (fun r -> is_gc_ptr (rtype r)) rl in
-				let need_tmp = List.mem r rl in
-				let tmp = if not need_tmp then reg r else begin
-					sexpr "{ venum *tmp";
-					"tmp"
-				end in
-				sexpr "%s = (venum*)hl_gc_alloc%s(sizeof(%s))" tmp (if has_ptr then "" else "_noptr") et;
-				sexpr "%s->index = %d" tmp cid;
-				let _,_,tl = e.efields.(cid) in
-				list_iteri (fun i v ->
-					sexpr "((%s*)%s)->p%d = %s" et tmp i (rcast v tl.(i))
-				) rl;
-				if need_tmp then sexpr "%s = tmp; }" (reg r)
-			| OEnumAlloc (r,cid) ->
-				let et, (_,_,tl) = (match rtype r with HEnum e -> enum_constr_type e cid, e.efields.(cid) | _ -> assert false) in
-				let has_ptr = List.exists is_gc_ptr (Array.to_list tl) in
-				sexpr "%s = (venum*)hl_gc_alloc%s(sizeof(%s))" (reg r) (if has_ptr then "" else "_noptr") et;
-				sexpr "memset(%s,0,sizeof(%s))" (reg r) et;
-				if cid <> 0 then sexpr "%s->index = %d" (reg r) cid
-			| OEnumIndex (r,v) ->
-				(match rtype v with
-				| HEnum _ ->
-					sexpr "%s = %s->index" (reg r) (reg v)
-				| HDyn ->
-					sexpr "%s = ((venum*)%s->v.ptr)->index" (reg r) (reg v)
-				| _ ->
-					assert false)
-			| OEnumField (r,e,cid,pid) ->
-				let tname,(_,_,tl) = (match rtype e with HEnum e -> enum_constr_type e cid, e.efields.(cid) | _ -> assert false) in
-				sexpr "%s((%s*)%s)->p%d" (rassign r tl.(pid)) tname (reg e) pid
-			| OSetEnumField (e,pid,r) ->
-				let tname, (_,_,tl) = (match rtype e with HEnum e -> enum_constr_type e 0, e.efields.(0) | _ -> assert false) in
-				sexpr "((%s*)%s)->p%d = (%s)%s" tname (reg e) pid (ctype tl.(pid)) (reg r)
-			| OSwitch (r,idx,eend) ->
-				sline "switch(%s) {" (reg r);
+					assert false
+			| HObj _, HVirtual _ ->
+				compare_op op b a d
+			| HFun _, HFun _ ->
+				phys_compare()
+			| ta, tb ->
+				failwith ("Don't know how to compare " ^ tstr ta ^ " and " ^ tstr tb ^ " (hlc)")
+		in
+		match op with
+		| OMov (r,v) ->
+			if rtype r <> HVoid then sexpr "%s = %s" (reg r) (rcast v (rtype r))
+		| OInt (r,idx) ->
+			if code.ints.(idx) = 0x80000000l then
+				sexpr "%s = 0x80000000" (reg r)
+			else
+				sexpr "%s = %ld" (reg r) code.ints.(idx)
+		| OFloat (r,idx) ->
+			sexpr "%s = %.19g" (reg r) code.floats.(idx)
+		| OBool (r,b) ->
+			sexpr "%s = %s" (reg r) (if b then "true" else "false")
+		| OBytes (r,idx) ->
+			sexpr "%s = bytes$%d" (reg r) idx
+		| OString (r,idx) ->
+			sexpr "%s = (vbyte*)%s" (reg r) (string ctx idx)
+		| ONull r ->
+			sexpr "%s = NULL" (reg r)
+		| OAdd (r,a,b) ->
+			sexpr "%s = %s + %s" (reg r) (reg a) (reg b)
+		| OSub (r,a,b) ->
+			sexpr "%s = %s - %s" (reg r) (reg a) (reg b)
+		| OMul (r,a,b) ->
+			sexpr "%s = %s * %s" (reg r) (reg a) (reg b)
+		| OSDiv (r,a,b) ->
+			(match rtype r with
+			| HUI8 | HUI16 | HI32 ->
+				sexpr "%s = %s == 0 ? 0 : %s / %s" (reg r) (reg b) (reg a) (reg b)
+			| _ ->
+				sexpr "%s = %s / %s" (reg r) (reg a) (reg b))
+		| OUDiv (r,a,b) ->
+			sexpr "%s = %s == 0 ? 0 : ((unsigned)%s) / ((unsigned)%s)" (reg r) (reg b) (reg a) (reg b)
+		| OSMod (r,a,b) ->
+			(match rtype r with
+			| HUI8 | HUI16 | HI32 ->
+				sexpr "%s = %s == 0 ? 0 : %s %% %s" (reg r) (reg b) (reg a) (reg b)
+			| HF32 ->
+				sexpr "%s = fmodf(%s,%s)" (reg r) (reg a) (reg b)
+			| HF64 ->
+				sexpr "%s = fmod(%s,%s)" (reg r) (reg a) (reg b)
+			| _ ->
+				assert false)
+		| OUMod (r,a,b) ->
+			sexpr "%s = %s == 0 ? 0 : ((unsigned)%s) %% ((unsigned)%s)" (reg r) (reg b) (reg a) (reg b)
+		| OShl (r,a,b) ->
+			sexpr "%s = %s << %s" (reg r) (reg a) (reg b)
+		| OSShr (r,a,b) ->
+			sexpr "%s = %s >> %s" (reg r) (reg a) (reg b)
+		| OUShr (r,a,b) ->
+			sexpr "%s = ((unsigned)%s) >> %s" (reg r) (reg a) (reg b)
+		| OAnd (r,a,b) ->
+			sexpr "%s = %s & %s" (reg r) (reg a) (reg b)
+		| OOr (r,a,b) ->
+			sexpr "%s = %s | %s" (reg r) (reg a) (reg b)
+		| OXor (r,a,b) ->
+			sexpr "%s = %s ^ %s" (reg r) (reg a) (reg b)
+		| ONeg (r,v) ->
+			sexpr "%s = -%s" (reg r) (reg v)
+		| ONot (r,v) ->
+			sexpr "%s = !%s" (reg r) (reg v)
+		| OIncr r ->
+			sexpr "++%s" (reg r)
+		| ODecr r ->
+			sexpr "--%s" (reg r)
+		| OCall0 (r,fid) ->
+			ocall r fid []
+		| OCall1 (r,fid,a) ->
+			ocall r fid [a]
+		| OCall2 (r,fid,a,b) ->
+			ocall r fid [a;b]
+		| OCall3 (r,fid,a,b,c) ->
+			ocall r fid [a;b;c]
+		| OCall4 (r,fid,a,b,c,d) ->
+			ocall r fid [a;b;c;d]
+		| OCallN (r,fid,rl) ->
+			ocall r fid rl
+		| OCallMethod (r,fid,pl) ->
+			mcall r fid pl
+		| OCallThis (r,fid,pl) ->
+			mcall r fid (0 :: pl)
+		| OCallClosure (r,cl,pl) ->
+			(match rtype cl with
+			| HDyn ->
+				dyn_call r cl pl
+			| HFun (args,ret) ->
+				let sargs = String.concat "," (List.map2 rcast pl args) in
+				sexpr "%s%s->hasValue ? %s((vdynamic*)%s->value%s) : %s(%s)" (rassign r ret) (reg cl) (rfun cl (HDyn :: args) ret) (reg cl) (if sargs = "" then "" else "," ^ sargs) (rfun cl args ret) sargs
+			| _ ->
+				assert false)
+		| OStaticClosure (r,fid) ->
+			sexpr "%s = &cl$%d" (reg r) fid
+		| OInstanceClosure (r,fid,ptr) ->
+			let ft = ctx.ftable.(fid) in
+			sexpr "%s = hl_alloc_closure_ptr(%s,%s,%s)" (reg r) (type_value (HFun (ft.fe_args,ft.fe_ret))) (funname fid) (reg ptr)
+		| OVirtualClosure (r,o,m) ->
+			(match rtype o with
+			| HObj p ->
+				let ft = ctx.ftable.(p.pvirtuals.(m)) in
+				let s = sprintf "%s->$type->vobj_proto[%d]" (reg o) m in
+				sexpr "%s = hl_alloc_closure_ptr(%s,%s,%s)" (reg r) (type_value (HFun(ft.fe_args,ft.fe_ret))) s (reg o)
+			| _ ->
+				todo())
+		| OGetGlobal (r,g) ->
+			sexpr "%s = (%s)global$%d" (reg r) (ctype (rtype r)) g
+		| OSetGlobal (g,r) ->
+			sexpr "global$%d = (%s)%s" g (ctype code.globals.(g)) (reg r)
+		| ORet r ->
+			if rtype r = HVoid then expr "return" else sexpr "return %s" (rcast r fret)
+		| OJTrue (r,d) | OJNotNull (r,d) ->
+			sexpr "if( %s ) goto %s" (reg r) (label d)
+		| OJFalse (r,d) | OJNull (r,d) ->
+			sexpr "if( !%s ) goto %s" (reg r) (label d)
+		| OJSLt (a,b,d) ->
+			compare_op CLt a b d
+		| OJSGte (a,b,d) ->
+			compare_op CGte a b d
+		| OJSGt (a,b,d) ->
+			compare_op CGt a b d
+		| OJSLte (a,b,d) ->
+			compare_op CLte a b d
+		| OJULt (a,b,d) ->
+			sexpr "if( ((unsigned)%s) < ((unsigned)%s) ) goto %s" (reg a) (reg b) (label d)
+		| OJUGte (a,b,d) ->
+			sexpr "if( ((unsigned)%s) >= ((unsigned)%s) ) goto %s" (reg a) (reg b) (label d)
+		| OJEq (a,b,d) ->
+			compare_op CEq a b d
+		| OJNotEq (a,b,d) ->
+			compare_op CNeq a b d
+		| OJAlways d ->
+			sexpr "goto %s" (label d)
+		| OLabel _ ->
+			if not (has_label i) then sline "%s:" (label (-1))
+		| OToDyn (r,v) ->
+			if is_ptr (rtype v) then begin
+				sline "if( %s == NULL ) %s = NULL; else {" (reg v) (reg r);
 				block();
-				output_at2 (i + 1) [OODefault;OOIncreaseIndent];
-				Array.iteri (fun k delta -> output_at2 (delta + i + 1) [OODecreaseIndent;OOCase k;OOIncreaseIndent]) idx;
-				let pend = i+1+eend in
-				(* insert at end if we have another switch case here *)
-				let old = output_options.(pend) in
-				output_options.(pend) <- [];
-				output_at2 pend ([OODecreaseIndent;OODecreaseIndent;OOEndBlock] @ List.rev old);
-			| ONullCheck r ->
-				sexpr "if( %s == NULL ) hl_null_access()" (reg r)
-			| OTrap (r,d) ->
-				sexpr "hl_trap(trap$%d,%s,%s)" !trap_depth (reg r) (label d);
-				incr trap_depth
-			| OEndTrap b ->
-				sexpr "hl_endtrap(trap$%d)" (!trap_depth - 1);
-				if b then decr trap_depth;
-			| ONop _ ->
+			end;
+			sexpr "%s = hl_alloc_dynamic(%s)" (reg r) (type_value (rtype v));
+			(match rtype v with
+			| HUI8 | HUI16 | HI32 | HBool ->
+				sexpr "%s->v.i = %s" (reg r) (reg v)
+			| HF32 ->
+				sexpr "%s->v.f = %s" (reg r) (reg v)
+			| HF64 ->
+				sexpr "%s->v.d = %s" (reg r) (reg v)
+			| _ ->
+				sexpr "%s->v.ptr = %s" (reg r) (reg v));
+			if is_ptr (rtype v) then begin
+				unblock();
+				line "}";
+			end;
+		| OToSFloat (r,v) ->
+			sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) (reg v)
+		| OToUFloat (r,v) ->
+			sexpr "%s = (%s)(unsigned)%s" (reg r) (ctype (rtype r)) (reg v)
+		| OToInt (r,v) ->
+			sexpr "%s = (int)%s" (reg r) (reg v)
+		| ONew r ->
+			(match rtype r with
+			| HObj o -> sexpr "%s = (%s)hl_alloc_obj(%s)" (reg r) (tname o.pname) (tname o.pname ^ "__val")
+			| HDynObj -> sexpr "%s = hl_alloc_dynobj()" (reg r)
+			| HVirtual _ as t -> sexpr "%s = hl_alloc_virtual(%s)" (reg r) (type_value t)
+			| _ -> assert false)
+		| OField (r,obj,fid) ->
+			get_field r obj fid
+		| OSetField (obj,fid,v) ->
+			set_field obj fid v
+		| OGetThis (r,fid) ->
+			get_field r 0 fid
+		| OSetThis (fid,r) ->
+			set_field 0 fid r
+		| OThrow r ->
+			sexpr "hl_throw((vdynamic*)%s)" (reg r)
+		| ORethrow r ->
+			sexpr "hl_rethrow((vdynamic*)%s)" (reg r)
+		| OGetUI8 (r,b,idx) ->
+			sexpr "%s = *(unsigned char*)(%s + %s)" (reg r) (reg b) (reg idx)
+		| OGetUI16 (r,b,idx) ->
+			sexpr "%s = *(unsigned short*)(%s + %s)" (reg r) (reg b) (reg idx)
+		| OGetI32 (r,b,idx) ->
+			sexpr "%s = *(int*)(%s + %s)" (reg r) (reg b) (reg idx)
+		| OGetF32 (r,b,idx) ->
+			sexpr "%s = *(float*)(%s + %s)" (reg r) (reg b) (reg idx)
+		| OGetF64 (r,b,idx) ->
+			sexpr "%s = *(double*)(%s + %s)" (reg r) (reg b) (reg idx)
+		| OGetArray (r, arr, idx) ->
+			sexpr "%s = ((%s*)(%s + 1))[%s]" (reg r) (ctype (rtype r)) (reg arr) (reg idx)
+		| OSetUI8 (b,idx,r) ->
+			sexpr "*(unsigned char*)(%s + %s) = (unsigned char)%s" (reg b) (reg idx) (reg r)
+		| OSetUI16 (b,idx,r) ->
+			sexpr "*(unsigned short*)(%s + %s) = (unsigned short)%s" (reg b) (reg idx) (reg r)
+		| OSetI32 (b,idx,r) ->
+			sexpr "*(int*)(%s + %s) = %s" (reg b) (reg idx) (reg r)
+		| OSetF32 (b,idx,r) ->
+			sexpr "*(float*)(%s + %s) = (float)%s" (reg b) (reg idx) (reg r)
+		| OSetF64 (b,idx,r) ->
+			sexpr "*(double*)(%s + %s) = %s" (reg b) (reg idx) (reg r)
+		| OSetArray (arr,idx,v) ->
+			sexpr "((%s*)(%s + 1))[%s] = %s" (ctype (rtype v)) (reg arr) (reg idx) (reg v)
+		| OSafeCast (r,v) ->
+			let tsrc = rtype v in
+			let t = rtype r in
+			if tsrc = HNull t then
+				sexpr "%s = %s ? %s%s : 0" (reg r) (reg v) (reg v) (dyn_value_field t)
+			else
+				sexpr "%s = (%s)hl_dyn_cast%s(&%s,%s%s)" (reg r) (ctype t) (dyn_prefix t) (reg v) (type_value (rtype v)) (type_value_opt t)
+		| OUnsafeCast (r,v) ->
+			sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) (reg v)
+		| OArraySize (r,a) ->
+			sexpr "%s = %s->size" (reg r) (reg a)
+		| OType (r,t) ->
+			sexpr "%s = %s" (reg r) (type_value t)
+		| OGetType (r,v) ->
+			sexpr "%s = %s ? ((vdynamic*)%s)->t : &hlt_void" (reg r) (reg v) (reg v)
+		| OGetTID (r,v) ->
+			sexpr "%s = %s->kind" (reg r) (reg v)
+		| ORef (r,v) ->
+			sexpr "%s = &%s" (reg r) (reg v)
+		| OUnref (r,v) ->
+			sexpr "%s = *%s" (reg r) (reg v)
+		| OSetref (r,v) ->
+			sexpr "*%s = %s" (reg r) (reg v)
+		| OToVirtual (r,v) ->
+			sexpr "%s = hl_to_virtual(%s,(vdynamic*)%s)" (reg r) (type_value (rtype r)) (reg v)
+		| ODynGet (r,o,sid) ->
+			let t = rtype r in
+			let h = hash ctx sid in
+			sexpr "%s = (%s)hl_dyn_get%s((vdynamic*)%s,%ld/*%s*/%s)" (reg r) (ctype t) (dyn_prefix t) (reg o) h code.strings.(sid) (type_value_opt t)
+		| ODynSet (o,sid,v) ->
+			let h = hash ctx sid in
+			sexpr "hl_dyn_set%s((vdynamic*)%s,%ld/*%s*/%s,%s)" (dyn_prefix (rtype v)) (reg o) h code.strings.(sid) (type_value_opt (rtype v)) (reg v)
+		| OMakeEnum (r,cid,rl) ->
+			let e, et = (match rtype r with HEnum e -> e, enum_constr_type ctx e cid | _ -> assert false) in
+			let has_ptr = List.exists (fun r -> is_gc_ptr (rtype r)) rl in
+			let need_tmp = List.mem r rl in
+			let tmp = if not need_tmp then reg r else begin
+				sexpr "{ venum *tmp";
+				"tmp"
+			end in
+			sexpr "%s = (venum*)hl_gc_alloc%s(sizeof(%s))" tmp (if has_ptr then "" else "_noptr") et;
+			sexpr "%s->index = %d" tmp cid;
+			let _,_,tl = e.efields.(cid) in
+			list_iteri (fun i v ->
+				sexpr "((%s*)%s)->p%d = %s" et tmp i (rcast v tl.(i))
+			) rl;
+			if need_tmp then sexpr "%s = tmp; }" (reg r)
+		| OEnumAlloc (r,cid) ->
+			let et, (_,_,tl) = (match rtype r with HEnum e -> enum_constr_type ctx e cid, e.efields.(cid) | _ -> assert false) in
+			let has_ptr = List.exists is_gc_ptr (Array.to_list tl) in
+			sexpr "%s = (venum*)hl_gc_alloc%s(sizeof(%s))" (reg r) (if has_ptr then "" else "_noptr") et;
+			sexpr "memset(%s,0,sizeof(%s))" (reg r) et;
+			if cid <> 0 then sexpr "%s->index = %d" (reg r) cid
+		| OEnumIndex (r,v) ->
+			(match rtype v with
+			| HEnum _ ->
+				sexpr "%s = %s->index" (reg r) (reg v)
+			| HDyn ->
+				sexpr "%s = ((venum*)%s->v.ptr)->index" (reg r) (reg v)
+			| _ ->
+				assert false)
+		| OEnumField (r,e,cid,pid) ->
+			let tname,(_,_,tl) = (match rtype e with HEnum e -> enum_constr_type ctx e cid, e.efields.(cid) | _ -> assert false) in
+			sexpr "%s((%s*)%s)->p%d" (rassign r tl.(pid)) tname (reg e) pid
+		| OSetEnumField (e,pid,r) ->
+			let tname, (_,_,tl) = (match rtype e with HEnum e -> enum_constr_type ctx e 0, e.efields.(0) | _ -> assert false) in
+			sexpr "((%s*)%s)->p%d = (%s)%s" tname (reg e) pid (ctype tl.(pid)) (reg r)
+		| OSwitch (r,idx,eend) ->
+			sline "switch(%s) {" (reg r);
+			block();
+			output_at2 (i + 1) [OODefault;OOIncreaseIndent];
+			Array.iteri (fun k delta -> output_at2 (delta + i + 1) [OODecreaseIndent;OOCase k;OOIncreaseIndent]) idx;
+			let pend = i+1+eend in
+			(* insert at end if we have another switch case here *)
+			let old = output_options.(pend) in
+			output_options.(pend) <- [];
+			output_at2 pend ([OODecreaseIndent;OODecreaseIndent;OOEndBlock] @ List.rev old);
+		| ONullCheck r ->
+			sexpr "if( %s == NULL ) hl_null_access()" (reg r)
+		| OTrap (r,d) ->
+			sexpr "hl_trap(trap$%d,%s,%s)" !trap_depth (reg r) (label d);
+			incr trap_depth
+		| OEndTrap b ->
+			sexpr "hl_endtrap(trap$%d)" (!trap_depth - 1);
+			if b then decr trap_depth;
+		| ONop _ ->
+			()
+	) f.code;
+	flush_options (Array.length f.code);
+	unblock();
+	line "}";
+	line ""
+
+let write_c com file (code:code) =
+
+	let all_types, htypes = gather_types code in
+
+	let ctx = {
+		version = com.Common.version;
+		out = Buffer.create 1024;
+		tabs = "";
+		hlcode = code;
+		hash_cache = Hashtbl.create 0;
+		dir = (match Filename.dirname file with "" -> "." | dir -> String.concat "/" (ExtString.String.nsplit dir "\\"));
+		curfile = "";
+		cfiles = [];
+		ftable = Array.init (Array.length code.functions + Array.length code.natives) (fun _ -> { fe_args = []; fe_ret = HVoid; fe_name = ""; fe_decl = None; });
+		htypes = htypes;
+	} in
+
+	let line = line ctx and expr = expr ctx in
+	let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
+
+	open_file ctx "hl/code.h";
+	line "#ifndef HL_CODE_H";
+	line "#define HL_CODE_H";
+	line "";
+	line "#define HLC_BOOT";
+	line "#include <hlc.h>";
+	line "#include \"typedefs.h\"";
+	line "#include \"types.h\"";
+	line "#include \"functions.h\"";
+	line "#include \"globals.h\"";
+	line "#include \"natives.h\"";
+	line "";
+	line "#endif";
+
+	let used_closures = Hashtbl.create 0 in
+	let bytes_strings = Hashtbl.create 0 in
+	Array.iter (fun f ->
+		Array.iteri (fun i op ->
+			match op with
+			| OStaticClosure (_,fid) ->
+				Hashtbl.replace used_closures fid ()
+			| OBytes (_,sid) ->
+				Hashtbl.replace bytes_strings sid ()
+			| _ ->
 				()
-		) f.code;
-		flush_options (Array.length f.code);
-		unblock();
-		line "}";
-		line "";
+		) f.code
 	) code.functions;
 
+	open_file ctx "hl/typedefs.h";
+	line "// Types definitions";
+	Array.iter (fun t ->
+		match t with
+		| HObj o ->
+			let name = tname o.pname in
+			expr ("typedef struct _" ^ name ^ " *" ^ name);
+		| HAbstract (name,_) ->
+			expr ("typedef struct _" ^ name ^ " "  ^ name);
+		| _ ->
+			()
+	) all_types;
+
 	line "";
-	line "// Entry point";
-	line "void hl_entry_point() {";
-	block();
-	sexpr "static void *functions_ptrs[] = {%s}" (String.concat "," (Array.to_list funnames));
-	let rec loop i =
-		if i = Array.length code.functions + Array.length code.natives then [] else
-		let args, t = tfuns.(i) in
-		(type_value (HFun (args,t))) :: loop (i + 1)
-	in
-	sexpr "static hl_type *functions_types[] = {%s}" (String.concat "," (loop 0));
-	expr "hl_module_context ctx";
-	expr "hl_alloc_init(&ctx.alloc)";
-	expr "ctx.functions_ptrs = functions_ptrs";
-	expr "ctx.functions_types = functions_types";
-	Hashtbl.iter (fun i _ -> sexpr "hl_hash(string$%d)" i) hash_cache;
+	line "// Types implementation";
+
+	Array.iter (fun t ->
+		match t with
+		| HObj o ->
+			let name = tname o.pname in
+			line ("struct _" ^ name ^ " {");
+			block ctx;
+			let rec loop o =
+				(match o.psuper with
+				| None -> expr ("hl_type *$type");
+				| Some c -> loop c);
+				Array.iteri (fun i (n,_,t) ->
+					let rec abs_index p v =
+						match p with
+						| None -> v
+						| Some o -> abs_index o.psuper (Array.length o.pfields + v)
+					in
+					expr (var_type (if n = "" then unamed_field (abs_index o.psuper i) else n) t)
+				) o.pfields;
+			in
+			loop o;
+			unblock ctx;
+			expr "}";
+		| HEnum e ->
+			Array.iteri (fun i (_,_,pl) ->
+				if Array.length pl <> 0 then begin
+					line ("typedef struct {");
+					block ctx;
+					expr "int index";
+					Array.iteri (fun i t ->
+						expr (var_type ("p" ^ string_of_int i) t)
+					) pl;
+					unblock ctx;
+					sexpr "} %s" (enum_constr_type ctx e i);
+				end;
+			) e.efields
+		| _ ->
+			()
+	) all_types;
+
+	open_file ctx "hl/types.h";
+	line "// Types values declaration";
+	Array.iteri (fun i t ->
+		sexpr "extern hl_type type$%d" i;
+		match t with
+		| HObj o ->
+			sline "#define %s__val &type$%d" (tname o.pname) i
+		| _ ->
+			()
+	) all_types;
+	line "";
+	sexpr "void hl_init_types( hl_module_context *ctx )";
+
+	open_file ctx "hl/natives.h";
+	line "// Natives functions";
+	let native_libs = Hashtbl.create 0 in
+	Array.iter (fun (lib,name,t,idx) ->
+		match t with
+		| HFun (args,t) ->
+			let fname =
+				let lib = code.strings.(lib) in
+				Hashtbl.replace native_libs lib ();
+				let lib = if lib = "std" then "hl" else lib in
+				lib ^ "_" ^ code.strings.(name)
+			in
+			sexpr "HL_API %s %s(%s)" (ctype t) fname (String.concat "," (List.map ctype args));
+			let ft = ctx.ftable.(idx) in
+			ft.fe_name <- fname;
+			ft.fe_args <- args;
+			ft.fe_ret <- t;
+		| _ ->
+			assert false
+	) code.natives;
+
+	open_file ctx "hl/functions.h";
+	line "// Functions declaration";
+	Array.iter (fun f ->
+		match f.ftype with
+		| HFun (args,t) ->
+			let fname = String.concat "_" (ExtString.String.nsplit (fundecl_name f) ".") in
+			sexpr "%s %s(%s)" (ctype t) fname (String.concat "," (List.map ctype args));
+			let ft = ctx.ftable.(f.findex) in
+			ft.fe_name <- fname;
+			ft.fe_args <- args;
+			ft.fe_ret <- t;
+			ft.fe_decl <- Some f;
+		| _ ->
+			assert false
+	) code.functions;
+	line "";
+	sexpr "extern void *hl_functions_ptrs[]";
+	sexpr "extern hl_type *hl_functions_types[]";
+
+
+	open_file ctx "hl/globals.h";
+	line "// Globals";
+	Array.iteri (fun i t ->
+		let name = "global$" ^ string_of_int i in
+		sexpr "extern %s" (var_type name t)
+	) code.globals;
+
+	Array.iteri (fun i str ->
+		if Hashtbl.mem bytes_strings i then
+			sexpr "extern vbyte bytes$%d[]" i
+		else if String.length str >= string_data_limit then
+			sexpr "vbyte string$%d[]" i
+	) code.strings;
+
+	Hashtbl.iter (fun fid _ -> sexpr "extern vclosure cl$%d" fid) used_closures;
+	line "";
+	sexpr "void hl_init_roots()";
+
+	open_file ctx "hl/globals.c";
+	line "#include <hl/code.h>";
+	line "// Globals";
+	Array.iteri (fun i t ->
+		let name = "global$" ^ string_of_int i in
+		sexpr "%s = 0" (var_type name t)
+	) code.globals;
+	line "";
+	line "void hl_init_roots() {";
+	block ctx;
+	Array.iteri (fun i t ->
+		if is_ptr t then sexpr "hl_add_root((void**)&global$%d)" i;
+	) code.globals;
+	unblock ctx;
+	line "}";
+
+	Array.iteri (fun i str ->
+		let rec loop s i =
+			if i = String.length s then [] else
+			let c = String.get s i in
+			string_of_int (int_of_char c) :: loop s (i+1)
+		in
+		if Hashtbl.mem bytes_strings i then
+			sexpr "vbyte bytes$%d[] = {%s}" i (String.concat "," (loop str 0))
+		else if String.length str >= string_data_limit then
+			let s = utf8_to_utf16 str in
+			sline "// %s..." (String.escaped (String.sub str 0 (string_data_limit-4)));
+			sexpr "vbyte string$%d[] = {%s}" i (String.concat "," (loop s 0))
+	) code.strings;
+
+	Hashtbl.iter (fun fid _ ->
+		let ft = ctx.ftable.(fid) in
+		sexpr "vclosure cl$%d = { %s, %s, 0 }" fid (type_value ctx (HFun (ft.fe_args,ft.fe_ret))) ft.fe_name
+	) used_closures;
+
+	open_file ctx "hl/types.c";
+	line "#include <hl/code.h>";
+	line "// Types values";
+	Array.iteri (fun i t ->
+		sexpr "hl_type type$%d = { %s } /* %s */" i (type_id t) (tstr t);
+	) all_types;
+
+	line "";
+	line "// Types values data";
 	Array.iteri (fun i t ->
+		let field_value (_,name_id,t) =
+			sprintf "{(const uchar*)%s, %s, %ld}" (string ctx name_id) (type_value ctx t) (hash ctx name_id)
+		in
 		match t with
 		| HObj o ->
-			sexpr "obj$%d.m = &ctx" i;
+			let proto_value p =
+				sprintf "{(const uchar*)%s, %d, %d, %ld}" (string ctx p.fid) p.fmethod (match p.fvirtual with None -> -1 | Some i -> i) (hash ctx p.fid)
+			in
+			let fields =
+				if Array.length o.pfields = 0 then "NULL" else
+				let name = sprintf "fields$%d" i in
+				sexpr "static hl_obj_field %s[] = {%s}" name (String.concat "," (List.map field_value (Array.to_list o.pfields)));
+				name
+			in
+			let proto =
+				if Array.length o.pproto = 0 then "NULL" else
+				let name = sprintf "proto$%d" i in
+				sexpr "static hl_obj_proto %s[] = {%s}" name (String.concat "," (List.map proto_value (Array.to_list o.pproto)));
+				name
+			in
+			let bindings =
+				if o.pbindings = [] then "NULL" else
+				let name = sprintf "bindings$%d" i in
+				sexpr "static int %s[] = {%s}" name (String.concat "," (List.map (fun (fid,fidx) -> string_of_int fid ^ "," ^ string_of_int fidx) o.pbindings));
+				name
+			in
+			let ofields = [
+				string_of_int (Array.length o.pfields);
+				string_of_int (Array.length o.pproto);
+				string_of_int (List.length o.pbindings);
+				sprintf "(const uchar*)%s" (string ctx o.pid);
+				(match o.psuper with None -> "NULL" | Some c -> sprintf "%s__val" (tname c.pname));
+				fields;
+				proto;
+				bindings
+			] in
+			sexpr "static hl_type_obj obj$%d = {%s}" i (String.concat "," ofields);
+		| HEnum e ->
+			let constr_name = sprintf "econstructs$%d" i in
+			let constr_value cid (name,nid,tl) =
+				let tval = if Array.length tl = 0 then "NULL" else
+					let name = sprintf "econstruct$%d_%d" i cid in
+					sexpr "static hl_type *%s[] = {%s}" name (String.concat "," (List.map (type_value ctx) (Array.to_list tl)));
+					name
+				in
+				let size = if Array.length tl = 0 then "0" else sprintf "sizeof(%s)" (enum_constr_type ctx e cid) in
+				let offsets = if Array.length tl = 0 then "NULL" else
+					let name = sprintf "eoffsets$%d_%d" i cid in
+					sexpr "static int %s[] = {%s}" name (String.concat "," (List.map (fun _ -> "0") (Array.to_list tl)));
+					name
+				in
+				let has_ptr = List.exists is_gc_ptr (Array.to_list tl) in
+				sprintf "{(const uchar*)%s, %d, %s, %s, %s, %s}" (string ctx nid) (Array.length tl) tval size (if has_ptr then "true" else "false") offsets
+			in
+			sexpr "static hl_enum_construct %s[] = {%s}" constr_name (String.concat "," (Array.to_list (Array.mapi constr_value e.efields)));
+			let efields = [
+				if e.eid = 0 then "NULL" else sprintf "(const uchar*)%s" (string ctx e.eid);
+				string_of_int (Array.length e.efields);
+				constr_name
+			] in
+			sexpr "static hl_type_enum enum$%d = {%s}" i (String.concat "," efields);
+		| HVirtual v ->
+			let fields_name =
+				if Array.length v.vfields = 0 then "NULL" else
+				let name = sprintf "vfields$%d" i in
+				sexpr "static hl_obj_field %s[] = {%s}" name (String.concat "," (List.map field_value (Array.to_list v.vfields)));
+				name
+			in
+			let vfields = [
+				fields_name;
+				string_of_int (Array.length v.vfields)
+			] in
+			sexpr "static hl_type_virtual virt$%d = {%s}" i (String.concat "," vfields);
+		| HFun (args,t) ->
+			let aname = if args = [] then "NULL" else
+				let name = sprintf "fargs$%d" i in
+				sexpr "static hl_type *%s[] = {%s}" name (String.concat "," (List.map (type_value ctx) args));
+				name
+			in
+			sexpr "static hl_type_fun tfun$%d = {%s,%s,%d}" i aname (type_value ctx t) (List.length args)
+		| _ ->
+			()
+	) all_types;
+
+	line "";
+	line "void hl_init_types( hl_module_context *ctx ) {";
+	block ctx;
+	Array.iteri (fun i t ->
+		match t with
+		| HObj o ->
+			sexpr "obj$%d.m = ctx" i;
 			(match o.pclassglobal with None -> () | Some g -> sexpr "obj$%d.global_value = (void**)&global$%d" i g);
 			sexpr "type$%d.obj = &obj$%d" i i
 		| HNull t | HRef t ->
-			sexpr "type$%d.tparam = %s" i (type_value t)
+			sexpr "type$%d.tparam = %s" i (type_value ctx t)
 		| HEnum e ->
 			sexpr "type$%d.tenum = &enum$%d" i i;
 			(match e.eglobal with None -> () | Some g -> sexpr "enum$%d.global_value = (void**)&global$%d" i g);
-			Array.iteri (fun cid (_,_,tl) ->
-				if Array.length tl > 0 then begin
-					line "{";
-					block();
-					sexpr "%s *_e = NULL" (enum_constr_type e cid);
-					Array.iteri (fun pid _ -> sexpr "eoffsets$%d_%d[%d] = (int)(int_val)&_e->p%d" i cid pid pid) tl;
-					unblock();
-					line "}";
-				end
-			) e.efields
+			sexpr "hl_init_enum(&type$%d)" i;
 		| HVirtual _ ->
 			sexpr "type$%d.virt = &virt$%d" i i;
-			sexpr "hl_init_virtual(&type$%d,&ctx)" i;
+			sexpr "hl_init_virtual(&type$%d,ctx)" i;
 		| HFun _ ->
 			sexpr "type$%d.fun = &tfun$%d" i i
 		| _ ->
 			()
 	) all_types;
-	Array.iteri (fun i t ->
-		if is_ptr t then sexpr "hl_add_root((void**)&global$%d)" i;
-	) code.globals;
-	sexpr "%s()" funnames.(code.entrypoint);
-	unblock();
+	unblock ctx;
+	line "}";
+
+	open_file ctx "hl/reflect.c";
+	line "#include <hl/code.h>";
+	line "// Reflection helpers";
+	generate_reflection ctx;
+
+	let gen_functions = Hashtbl.create 0 in
+	let all_protos = Hashtbl.create 0 in
+	Array.iter (fun t ->
+		match t with
+		| HObj o ->
+			Hashtbl.add all_protos o.pname o
+		| _ -> ()
+	) all_types;
+
+	Array.iter (fun t ->
+		match t with
+		| HObj o when Hashtbl.mem all_protos o.pname ->
+			let file = ref false in
+			let base_name, path = match List.rev (ExtString.String.nsplit o.pname ".") with
+				| [] -> assert false
+				| name :: acc -> (if name.[0] = '$' then String.sub name 1 (String.length name - 1) else name), List.rev acc
+			in
+			let generate fid =
+				match ctx.ftable.(fid).fe_decl with
+				| None -> ()
+				| Some f ->
+					if not !file then begin
+						file := true;
+						let path = path @ [base_name] in
+						let path = List.map (fun n -> if String.length n > 128 then Digest.to_hex (Digest.string n) else n) path in
+						let path = (match path with [name] -> ["_std";name] | _ -> path) in
+						open_file ctx (String.concat "/" path ^ ".c");
+						line "#include <hl/code.h>";
+						line "";
+					end;
+					Hashtbl.replace gen_functions f.findex ();
+					generate_function ctx f
+			in
+			let gen_proto name =
+				try
+					let full_name = String.concat "." (path @ [name]) in
+					let o = Hashtbl.find all_protos full_name in
+					Array.iter (fun p -> generate p.fmethod) o.pproto;
+					List.iter (fun (_,mid) -> generate mid) o.pbindings;
+					Hashtbl.remove all_protos full_name;
+				with Not_found ->
+					()
+			in
+			gen_proto base_name;
+			gen_proto ("$" ^ base_name);
+		| _ -> ()
+	) all_types;
+
+	open_file ctx "hl/functions.c";
+	line "#include <hl/code.h>";
+	line "";
+	sexpr "void *hl_functions_ptrs[] = {%s}" (String.concat "," (List.map (fun f -> f.fe_name) (Array.to_list ctx.ftable)));
+	let rec loop i =
+		if i = Array.length ctx.ftable then [] else
+		let ft = ctx.ftable.(i) in
+		(type_value ctx (HFun (ft.fe_args,ft.fe_ret))) :: loop (i + 1)
+	in
+	sexpr "hl_type *hl_functions_types[] = {%s}" (String.concat "," (loop 0));
+	line "";
+	Array.iter (fun f ->
+		if not (Hashtbl.mem gen_functions f.findex) then generate_function ctx f;
+	) code.functions;
+
+	open_file ctx "hl/hashes.c";
+	line "#include <hl/code.h>";
+	line "";
+	line "void hl_init_hashes() {";
+	block ctx;
+	Hashtbl.iter (fun i _ -> sexpr "hl_hash((vbyte*)%s)" (string ctx i)) ctx.hash_cache;
+	unblock ctx;
+	line "}";
+
+	open_file ctx (Filename.basename file);
+	line "#include <hl/code.h>";
+	line "#include <hlc_main.c>";
+	line "";
+	line "#ifndef HL_MAKE";
+	List.iter (sline "#  include <%s>") ctx.cfiles;
+	line "#endif";
+	line "";
+	expr "void hl_init_hashes()";
+	line "";
+	line "// Entry point";
+	line "void hl_entry_point() {";
+	block ctx;
+	expr "hl_module_context ctx";
+	expr "hl_alloc_init(&ctx.alloc)";
+	expr "ctx.functions_ptrs = hl_functions_ptrs";
+	expr "ctx.functions_types = hl_functions_types";
+	expr "hl_init_types(&ctx)";
+	expr "hl_init_hashes()";
+	expr "hl_init_roots()";
+	sexpr "%s()" ctx.ftable.(code.entrypoint).fe_name;
+	unblock ctx;
 	line "}";
 	line "";
-	List.iter (fun f -> f()) !end_ch
+
+	open_file ctx "hlc.json";
+
+	line "{";
+	block ctx;
+	sline "\"version\" : %d," ctx.version;
+	sline "\"libs\" : [%s]," (String.concat "," (Hashtbl.fold (fun k _ acc -> sprintf "\"%s\"" k :: acc) native_libs []));
+	sline "\"defines\" : {%s\n\t}," (String.concat "," (PMap.foldi (fun k v acc -> sprintf "\n\t\t\"%s\" : \"%s\"" k v :: acc) com.Common.defines []));
+	sline "\"files\" : [%s\n\t]" (String.concat "," (List.map (sprintf "\n\t\t\"%s\"") ctx.cfiles));
+	unblock ctx;
+	line "}";
+
+	close_file ctx
+

+ 13 - 4
src/generators/hlcode.ml

@@ -1,5 +1,5 @@
 (*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -58,6 +58,7 @@ and class_proto = {
 	mutable pindex : (string, int * ttype) PMap.t;
 	mutable pfunctions : (string, int) PMap.t;
 	mutable pinterfaces : (ttype, int) PMap.t;
+	mutable pbindings : (int * int) list;
 }
 
 and enum_proto = {
@@ -133,7 +134,6 @@ type opcode =
 	| OSetThis of field index * reg
 	| ODynGet of reg * reg * string index
 	| ODynSet of reg * string index * reg
-	| OSetMethod of reg * field index * functable index (* init static method *)
 	(* jumps *)
 	| OJTrue of reg * int
 	| OJFalse of reg * int
@@ -232,6 +232,7 @@ let null_proto =
 		pindex = PMap.empty;
 		pfunctions = PMap.empty;
 		pinterfaces = PMap.empty;
+		pbindings = [];
 	}
 
 let list_iteri f l =
@@ -499,7 +500,6 @@ let ostr fstr o =
 	| OCallThis (r,f,rl) -> Printf.sprintf "callthis %d, [%d](%s)" r f (String.concat "," (List.map string_of_int rl))
 	| OStaticClosure (r,f) -> Printf.sprintf "staticclosure %d, %s" r (fstr f)
 	| OInstanceClosure (r,f,v) -> Printf.sprintf "instanceclosure %d, %s(%d)" r (fstr f) v
-	| OSetMethod (o,f,fid) -> Printf.sprintf "setmethod %d[%d], %d" o f fid
 	| OGetGlobal (r,g) -> Printf.sprintf "global %d, %d" r g
 	| OSetGlobal (g,r) -> Printf.sprintf "setglobal %d, %d" g r
 	| ORet r -> Printf.sprintf "ret %d" r
@@ -640,11 +640,20 @@ let dump pr code =
 		| None -> ()
 		| Some p -> pr ("		extends " ^ p.pname));
 		pr ("		" ^ string_of_int (Array.length p.pfields) ^ " fields");
+		let rec loop = function
+			| None -> 0
+			| Some p -> Array.length p.pfields + loop p.psuper
+		in
+		let start_field = loop p.psuper in
 		Array.iteri (fun i (_,id,t) ->
-			pr ("		  @" ^ string_of_int i ^ " " ^ str id ^ " " ^ tstr t)
+			pr ("		  @" ^ string_of_int (i + start_field) ^ " " ^ str id ^ " " ^ tstr t)
 		) p.pfields;
 		pr ("		" ^ string_of_int (Array.length p.pproto) ^ " methods");
 		Array.iteri (fun i f ->
 			pr ("		  @" ^ string_of_int i ^ " " ^ str f.fid ^ " fun@" ^ string_of_int f.fmethod ^ (match f.fvirtual with None -> "" | Some p -> "[" ^ string_of_int p ^ "]"))
 		) p.pproto;
+		pr ("		" ^ string_of_int (List.length p.pbindings) ^ " bindings");
+		List.iter (fun (i,fidx) ->
+			pr ("		  @" ^ string_of_int i ^ " fun@" ^ string_of_int fidx)
+		) p.pbindings;
 	) protos

+ 37 - 20
src/generators/hlinterp.ml

@@ -1,5 +1,5 @@
 (*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -111,7 +111,7 @@ type context = {
 	mutable on_error : value -> (fundecl * int ref) list -> unit;
 	mutable resolve_macro_api : string -> (value list -> value) option;
 	checked : bool;
-	cached_protos : (int, vproto * ttype array) Hashtbl.t;
+	cached_protos : (int, vproto * ttype array * (int * (value -> value)) list) Hashtbl.t;
 	cached_strings : (int, string) Hashtbl.t;
 	cached_hashes : (int32, string) Hashtbl.t;
 }
@@ -175,10 +175,17 @@ let rec get_proto ctx p =
 	try
 		Hashtbl.find ctx.cached_protos p.pid
 	with Not_found ->
-		let fields = (match p.psuper with None -> [||] | Some p -> snd(get_proto ctx p)) in
+		let fields, bindings = (match p.psuper with None -> [||],[] | Some p -> let _, fields, bindings = get_proto ctx p in fields, bindings) in
 		let meths = Array.map (get_function ctx) p.pvirtuals in
 		let fields = Array.append fields (Array.map (fun (_,_,t) -> t) p.pfields) in
-		let proto = ({ pclass = p; pmethods = meths },fields) in
+		let bindings = List.fold_left (fun acc (fid,fidx) ->
+			let f = get_function ctx fidx in
+			let ft = (match f with FFun f -> f.ftype | FNativeFun _ -> assert false) in
+			let need_closure = (match ft, fields.(fid) with HFun (args,_), HFun(args2,_) -> List.length args > List.length args2 | HFun _, HDyn -> false | _ -> assert false) in
+			let acc = List.filter (fun (fid2,_) -> fid2 <> fid) acc in
+			(fid, (fun v -> VClosure (f,if need_closure then Some v else None))) :: acc
+		) bindings p.pbindings in
+		let proto = ({ pclass = p; pmethods = meths },fields,bindings) in
 		Hashtbl.replace ctx.cached_protos p.pid proto;
 		proto
 
@@ -187,8 +194,11 @@ let alloc_obj ctx t =
 	| HDynObj ->
 		VDynObj { dfields = Hashtbl.create 0; dvalues = [||]; dtypes = [||]; dvirtuals = []; }
 	| HObj p ->
-		let p, fields = get_proto ctx p in
-		VObj { oproto = p; ofields = Array.map default fields }
+		let p, fields, bindings = get_proto ctx p in
+		let ftable = Array.map default fields in
+		let obj = VObj { oproto = p; ofields = ftable } in
+		List.iter (fun (fid,mk) -> ftable.(fid) <- mk obj) bindings;
+		obj
 	| HVirtual v ->
 		let o = {
 			dfields = Hashtbl.create 0;
@@ -391,7 +401,7 @@ let rec to_virtual ctx v vp =
 
 let rec dyn_cast ctx v t rt =
 	let invalid() =
-		error ("Can't cast " ^ vstr_d ctx v ^ ":"  ^ tstr t ^ " to " ^ tstr rt)
+		throw_msg ctx ("Can't cast " ^ vstr_d ctx v ^ ":"  ^ tstr t ^ " to " ^ tstr rt)
 	in
 	let default() =
 		let v = default rt in
@@ -743,7 +753,7 @@ let interp ctx f args =
 	let check_obj v o fid =
 		if ctx.checked then match o with
 		| VObj o ->
-			let _, fields = get_proto ctx o.oproto.pclass in
+			let _, fields, _ = get_proto ctx o.oproto.pclass in
 			check v fields.(fid) (fun() -> "obj field")
 		| VVirtual vp ->
 			let _,_, t = vp.vtype.vfields.(fid) in
@@ -903,11 +913,6 @@ let interp ctx f args =
 				check_obj rv o fid;
 				v.ofields.(fid) <- rv
 			| _ -> assert false)
-		| OSetMethod (o,fid,mid) ->
-			let o = get o in
-			(match o with
-			| VObj v -> v.ofields.(fid) <- VClosure (get_function ctx mid,None)
-			| _ -> assert false)
 		| OCallMethod (r,m,rl) ->
 			(match get (List.hd rl) with
 			| VObj v -> set r (fcall v.oproto.pmethods.(m) (List.map get rl))
@@ -1233,14 +1238,16 @@ let load_native ctx lib name t =
 			| _ -> assert false)
 		| "alloc_enum" ->
 			(function
-			| [VType (HEnum e); VInt idx; VArray (vl,vt)] ->
+			| [VType (HEnum e); VInt idx; VArray (vl,vt); VInt len] ->
 				let idx = int idx in
+				let len = int len in
 				let _, _, args = e.efields.(idx) in
-				if Array.length args <> Array.length vl then
+				if Array.length args <> len then
 					VNull
 				else
-					VDyn (VEnum (idx,Array.mapi (fun i v -> dyn_cast ctx v vt args.(i)) vl),HEnum e)
-			| _ -> assert false)
+					VDyn (VEnum (idx,Array.mapi (fun i v -> dyn_cast ctx v vt args.(i)) (Array.sub vl 0 len)),HEnum e)
+			| vl ->
+				assert false)
 		| "array_blit" ->
 			(function
 			| [VArray (dst,_); VInt dp; VArray (src,_); VInt sp; VInt len] ->
@@ -1545,6 +1552,14 @@ let load_native ctx lib name t =
 				| HEnum e -> (match e.eglobal with None -> VNull | Some g -> ctx.t_globals.(g))
 				| _ -> VNull)
 			| _ -> assert false)
+		| "type_set_global" ->
+			(function
+			| [VType t; v] ->
+				VBool (match t with
+				| HObj c -> (match c.pclassglobal with None -> false | Some g -> ctx.t_globals.(g) <- v; true)
+				| HEnum e -> (match e.eglobal with None -> false | Some g -> ctx.t_globals.(g) <- v; true)
+				| _ -> false)
+			| _ -> assert false)
 		| "type_name" ->
 			(function
 			| [VType t] ->
@@ -1611,6 +1626,11 @@ let load_native ctx lib name t =
 				| HEnum e -> VArray (Array.map (fun (f,_,_) -> VBytes (caml_to_hl f)) e.efields,HBytes)
 				| _ -> VNull)
 			| _ -> assert false)
+		| "type_enum_values" ->
+			(function
+			| [VType (HEnum e as t)] ->
+				VArray (Array.mapi (fun i (_,_,args) -> if Array.length args <> 0 then VNull else VDyn (VEnum (i,[||]),t)) e.efields,HDyn)
+			| _ -> assert false)
 		| "type_enum_eq" ->
 			(function
 			| [VDyn (VEnum _, HEnum _); VNull] | [VNull; VDyn (VEnum _, HEnum _)] -> VBool false
@@ -2290,8 +2310,6 @@ let check code macros =
 				reg r (tfield 0 fid false)
 			| OStaticClosure (r,f) ->
 				reg r ftypes.(f)
-			| OSetMethod (o,f,fid) ->
-				check ftypes.(fid) (tfield o f false)
 			| OVirtualClosure (r,o,fid) ->
 				(match rtype o with
 				| HObj _ ->
@@ -2745,7 +2763,6 @@ let make_spec (code:code) (f:fundecl) =
 			| OCallThis (d,fid,rl) -> args.(d) <- make_call (SMethod fid) (List.map (fun r -> args.(r)) (0 :: rl))
 			| OCallClosure (d,r,rl) -> args.(d) <- make_call (SClosure args.(r)) (List.map (fun r -> args.(r)) rl)
 			| OStaticClosure (d,fid) -> args.(d) <- SFun (fid,None)
-			| OSetMethod (o,f,fid) -> semit (SFieldSet (args.(o),f,SFun(fid,None)))
 			| OInstanceClosure (d,fid,r) -> args.(d) <- SFun (fid,Some args.(r))
 			| OVirtualClosure (d,r,index) -> args.(d) <- SMeth (args.(r),index)
 			| OGetGlobal (d,g) -> args.(d) <- SGlobal g

+ 1 - 5
src/generators/hlopt.ml

@@ -1,5 +1,5 @@
 (*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -111,8 +111,6 @@ let opcode_fx frw op =
 		write d
 	| OSetGlobal (_,a) ->
 		read a;
-	| OSetMethod (o,_,_) ->
-		read o;
 	| OField (d,a,_) | ODynGet (d,a,_) ->
 		read a; write d
 	| OSetField (a,_,b) | ODynSet (a,_,b)->
@@ -272,8 +270,6 @@ let opcode_map read write op =
 		OGetGlobal (write d, g)
 	| OSetGlobal (g,r) ->
 		OSetGlobal (g, read r)
-	| OSetMethod (o,f,m) ->
-		OSetMethod (read o, f, m)
 	| OField (d,a,f) ->
 		let a = read a in
 		OField (write d, a, f)

+ 1 - 1
src/json.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 2 - 2
src/macro/hlmacro.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -403,7 +403,7 @@ let enc_inst path fields =
 	let t = (match ctx.gen with None -> assert false | Some gen -> try Genhl.resolve_type gen path with Not_found -> assert false) in
 	match t with
 	| HObj o ->
-		let proto, _ = Hlinterp.get_proto ctx.interp o in
+		let proto, _, _ = Hlinterp.get_proto ctx.interp o in
 		VObj { oproto = proto; ofields = fields }
 	| _ ->
 		assert false

+ 59 - 366
src/macro/interp.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -79,9 +79,9 @@ and vfunction =
 	| FunVar of (value list -> value)
 
 and regexp = {
-	r : Str.regexp;
+	r : Pcre.regexp;
 	mutable r_string : string;
-	mutable r_groups : (int * int) option array;
+	mutable r_groups : int array;
 }
 
 and zlib = {
@@ -460,248 +460,6 @@ let rec dlopen dls =
 	| _ ->
 		None
 
-let neko =
-	match dlopen (if Globals.is_windows then
-		["neko.dll"]
-	else
-		(*
-			By defualt, the makefile of neko produces libneko.so,
-			however, the debian package creates libneko.so.0 without libneko.so...
-			The fedora rpm package creates libneko.so linked to libneko.so.1.
-		*)
-		["libneko.so"; "libneko.so.0"; "libneko.so.1"; "libneko.so.2"; "libneko.dylib"]
-	) with
-	| None ->
-		None
-	| Some(neko) ->
-	let null = Extc.dlint 0 in
-	let load v =
-		let s = Extc.dlsym neko v in
-		if (Obj.magic s) == null then failwith ("Could not load neko." ^ v);
-		s
-	in
-	ignore(Extc.dlcall0 (load "neko_global_init"));
-	let vm = Extc.dlcall1 (load "neko_vm_alloc") null in
-	ignore(Extc.dlcall1 (load "neko_vm_select") vm);
-	let loader = Extc.dlcall2 (load "neko_default_loader") null null in
-	let loadprim =
-		let l1 = load "neko_val_field" in
-		let l2 = Extc.dlcall1 (load "neko_val_id") (Extc.dlstring "loadprim") in
-		Extc.dlcall2 (l1) loader (l2) in
-
-	let callN = load "neko_val_callN" in
-	let callEx = load "neko_val_callEx" in
-	let copy_string = load "neko_copy_string" in
-
-	let alloc_root = load "neko_alloc_root" in
-	let free_root = load "neko_free_root" in
-
-	let alloc_root v =
-		let r = Extc.dlcall1 alloc_root (Extc.dlint 1) in
-		Extc.dlsetptr r v;
-		r
-	in
-	let free_root r =
-		ignore(Extc.dlcall1 free_root r)
-	in
-
-	ignore(alloc_root vm);
-	ignore(alloc_root loader);
-	ignore(alloc_root loadprim);
-
-	let alloc_string s =
-		Extc.dlcall2 copy_string (Extc.dlstring s) (Extc.dlint (String.length s))
-	in
-	let alloc_int (i:int) : Extc.value =
-		Obj.magic i
-	in
-	let loadprim n args =
-		let exc = ref null in
-		let vargs = [|alloc_string n;alloc_int args|] in
-		let p = Extc.dlcall5 callEx loader loadprim (Obj.magic vargs) (Extc.dlint 2) (Obj.magic exc) in
-		if !exc != null then failwith ("Failed to load " ^ n ^ ":" ^ string_of_int args);
-		ignore(alloc_root p);
-		(n,p,args)
-	in
-	let call_raw_prim (_,p,nargs) (args:Extc.value array) =
-		Extc.dlcall3 callN p (Obj.magic args) (Extc.dlint nargs)
-	in
-
-	(* a bit tricky since load "val_true" does not work as expected on Windows *)
-	let unser = try loadprim "std@unserialize" 2 with _ -> ("",null,0) in
-
-	(* did we fail to load std.ndll ? *)
-	if (match unser with ("",_,_) -> true | _ -> false) then None else
-
-	let val_true = call_raw_prim unser [|alloc_string "T";loader|] in
-	let val_false = call_raw_prim unser [|alloc_string "F";loader|] in
-	let val_null = call_raw_prim unser [|alloc_string "N";loader|] in
-
-	let is_64 = call_raw_prim (loadprim "std@sys_is64" 0) [||] == val_true in
-	let alloc_i32, is_v2 = (try load "neko_alloc_int32", true with _ -> Obj.magic 0, false) in
-	let alloc_i32 = if is_v2 then
-		(fun i -> Extc.dlcall1 alloc_i32 (Extc.dlint32 i))
-	else
-		(fun i -> alloc_int (Int32.to_int (if Int32.compare i Int32.zero < 0 then Int32.logand i 0x7FFFFFFFl else Int32.logor i 0x80000000l)))
-	in
-	let tag_bits = if is_v2 then 4 else 3 in
-	let tag_mask = (1 lsl tag_bits) - 1 in
-	let ptr_size = if is_64 then 8 else 4 in
-	let val_field v i = Extc.dladdr v ((i + 1) * ptr_size) in
-	let val_str v = Extc.dladdr v 4 in
-	let val_fun_env v = Extc.dladdr v (8 + ptr_size) in
-
-	(* alloc support *)
-
-	let alloc_function = load "neko_alloc_function" in
-	let alloc_array = load "neko_alloc_array" in
-	let alloc_float = load "neko_alloc_float" in
-	let alloc_object = load "neko_alloc_object" in
-	let alloc_field = load "neko_alloc_field" in
-	let alloc_abstract = load "neko_alloc_abstract" in
-	let val_gc = load "neko_val_gc" in
-	let val_field_name = load "neko_val_field_name" in
-	let val_iter_fields = load "neko_val_iter_fields" in
-	let gen_callback = Extc.dlcaml_callback 2 in
-
-	(* roots *)
-
-	let on_abstract_gc = Extc.dlcaml_callback 1 in
-	let root_index = ref 0 in
-	let roots = Hashtbl.create 0 in
-	Callback.register "dlcallb1" (fun a ->
-		let index : int = Obj.magic (Extc.dlptr (val_field a 1)) in
-		Hashtbl.remove roots index;
-		null
-	);
-
-	(* wrapping *)
-
-	let copy_string v =
-		let head = Extc.dltoint (Extc.dlptr v) in
-		let size = head asr tag_bits in
-		let s = String.create size in
-		Extc.dlmemcpy (Extc.dlstring s) (val_str v) size;
-		s
-	in
-
-	let buffers = ref [] in
-
-	let rec value_neko ?(obj=VNull) = function
-		| VNull -> val_null
-		| VBool b -> if b then val_true else val_false
-		| VInt i -> alloc_int i
-		| VAbstract (ANekoAbstract a) -> a
-		| VAbstract (ANekoBuffer (VString buf)) ->
-			let v = value_neko (VString buf) in
-			buffers := (buf,v) :: !buffers;
-			v
-		| VString s ->
-			let v = alloc_string s in (* make a copy *)
-			ignore(copy_string v);
-			v
-		| VObject o as obj ->
-			let vo = Extc.dlcall1 alloc_object null in
-			Array.iter (fun (id,v) ->
-				ignore(Extc.dlcall3 alloc_field vo (Extc.dlint id) (value_neko ~obj v))
-			) o.ofields;
-			vo
-		| VClosure _ ->
-			failwith "Closure not supported"
-		| VFunction f ->
-			let callb = Extc.dlcall3 alloc_function gen_callback (Extc.dlint (-1)) (Obj.magic "<callback>") in
-			let index = !root_index in
-			incr root_index;
-			Hashtbl.add roots index (f,obj);
-			let a = Extc.dlcall2 alloc_abstract null (Obj.magic index) in
-			if Extc.dlptr (val_field a 1) != Obj.magic index then assert false;
-			ignore(Extc.dlcall2 val_gc a on_abstract_gc);
-			Extc.dlsetptr (val_fun_env callb) a;
-			callb
-		| VArray a ->
-			let va = Extc.dlcall1 alloc_array (Extc.dlint (Array.length a)) in
-			Array.iteri (fun i v ->
-				Extc.dlsetptr (val_field va i) (value_neko v)
-			) a;
-			va
-		| VFloat f ->
-			Extc.dlcall1 alloc_float (Obj.magic f)
-		| VAbstract _ ->
-			failwith "Abstract not supported"
-		| VInt32 i ->
-			alloc_i32 i
-	in
-	let obj_r = ref [] in
-	let obj_fun = (fun v id -> obj_r := (v,id) :: !obj_r; val_null) in
-	let rec neko_value (v:Extc.value) =
-		if Obj.is_int (Obj.magic v) then
-			VInt (Obj.magic v)
-		else
-			let head = Extc.dltoint (Extc.dlptr v) in
-			match head land tag_mask with
-			| 0 -> VNull
-			| 2 -> VBool (v == val_true)
-			| 3 -> VString (copy_string v)
-			| 4 ->
-				ignore(Extc.dlcall3 val_iter_fields v (Extc.dlcallback 2) (Obj.magic obj_fun));
-				let r = !obj_r in
-				obj_r := [];
-				let ctx = get_ctx() in
-				let fields = List.rev_map (fun (v,id) ->
-					let iid = Extc.dltoint id in
-					if not (Hashtbl.mem ctx.fields_cache iid) then begin
-						let name = copy_string (Extc.dlcall1 val_field_name id) in
-						ignore(hash_field ctx name);
-					end;
-					iid, neko_value v
-				) r in
-				VObject { ofields = Array.of_list fields; oproto = None }
-			| 5 ->
-				VArray (Array.init (head asr tag_bits) (fun i -> neko_value (Extc.dlptr (val_field v i))))
-			| 7 ->
-				let r = alloc_root v in
-				let a = ANekoAbstract v in
-				Gc.finalise (fun _ -> free_root r) a;
-				VAbstract a
-			| t ->
-				failwith ("Unsupported Neko value tag " ^ string_of_int t)
-	in
-
-	Callback.register "dlcallb2" (fun args nargs ->
-		(* get back the VM env, which was set in value_neko *)
-		let env = Extc.dlptr (Extc.dladdr vm (2 * ptr_size)) in
-		(* extract the index stored in abstract data *)
-		let index : int = Obj.magic (Extc.dlptr (val_field env 1)) in
-		let f, obj = (try Hashtbl.find roots index with Not_found -> assert false) in
-		let nargs = Extc.dltoint nargs in
-		let rec loop i =
-			if i = nargs then [] else neko_value (Extc.dlptr (Extc.dladdr args (i * ptr_size))) :: loop (i + 1)
-		in
-		let v = (get_ctx()).do_call obj (VFunction f) (loop 0) { psource = "<callback>"; pline = 0; } in
-		value_neko v
-	);
-
-	let callprim (n,p,nargs) args =
-		let arr = Array.of_list (List.map value_neko args) in
-		let exc = ref null in
-		if Array.length arr <> nargs then failwith n;
-		let ret = Extc.dlcall5 callEx val_null p (Obj.magic arr) (Extc.dlint nargs) (Obj.magic exc) in
-		if !exc != null then raise (Runtime (neko_value !exc));
-		(match !buffers with
-		| [] -> ()
-		| l ->
-			buffers := [];
-			(* copy back data *)
-			List.iter (fun (buf,v) ->
-				Extc.dlmemcpy (Extc.dlstring buf) (val_str v) (String.length buf);
-			) l);
-		neko_value ret
-	in
-	Some {
-		load = loadprim;
-		call = callprim;
-	}
-
 (* ---------------------------------------------------------------------- *)
 (* BUILTINS *)
 
@@ -1006,7 +764,7 @@ let builtins =
 		);
 	(* extra *)
 		"use_neko_dll", Fun0 (fun() ->
-			VBool (neko <> None)
+			VBool false
 		);
 	] in
 	let vals = [
@@ -1873,8 +1631,8 @@ let std_lib =
 			| _ -> error()
 		));
 	(* xml *)
-		"parse_xml", (match neko with
-		| None -> Fun2 (fun str o ->
+		"parse_xml",
+			(Fun2 (fun str o ->
 			match str, o with
 			| VString str, VObject events ->
 				let ctx = get_ctx() in
@@ -1907,21 +1665,9 @@ let std_lib =
 				| e -> failwith ("Parser failure (" ^ Printexc.to_string e ^ ")"));
 				VNull
 			| _ -> error())
-		| Some neko ->
-			let parse_xml = neko.load "std@parse_xml" 2 in
-			Fun2 (fun str o -> neko.call parse_xml [str;o])
 		);
 	(* memory, module : not planned *)
-	]
-	(* process *)
-	@ (match neko with
-	| None -> []
-	| Some neko ->
-		let win_ec = (try Some (neko.load "std@win_env_changed" 0) with _ -> None) in
-	[
-		"win_env_changed", (Fun0 (fun() -> match win_ec with None -> error() | Some f -> neko.call f []));
-	]))
-
+	])
 
 (* ---------------------------------------------------------------------- *)
 (* REGEXP LIBRARY *)
@@ -1930,122 +1676,69 @@ let reg_lib =
 	let error() =
 		raise Builtin_error
 	in
-	(* try to load regexp first : we might fail if pcre is not installed *)
-	let neko = (match neko with
-		| None -> None
-		| Some neko ->
-			(try ignore(neko.load "regexp@regexp_new_options" 2); Some neko with _ -> None)
-	) in
-	match neko with
-	| None ->
+	let open Pcre in
+	let string_of_pcre_error = function
+		| BadPattern(s,i) -> Printf.sprintf "at %i: %s" i s
+		| Partial -> "Partial"
+		| BadPartial -> "BadPartial"
+		| BadUTF8 -> "BadUTF8"
+		| BadUTF8Offset -> "BadUTF8Offset"
+		| MatchLimit -> "MatchLimit"
+		| RecursionLimit -> "RecursionLimit"
+		| InternalError s -> "InternalError: " ^ s
+	in
 	make_library [
-		(* regexp_new : deprecated *)
 		"regexp_new_options", Fun2 (fun str opt ->
-			match str, opt with
-			| VString str, VString opt ->
-				let case_sensitive = ref true in
-				List.iter (function
-					| 'm' -> () (* always ON ? *)
-					| 'i' -> case_sensitive := false
+			match str,opt with
+			| VString str,VString opt ->
+				let flags = List.map (function
+					| 'i' -> `CASELESS
+					| 's' -> `DOTALL
+					| 'm' -> `MULTILINE
+					| 'u' -> `UTF8
+					| 'g' -> `UNGREEDY
 					| c -> failwith ("Unsupported regexp option '" ^ String.make 1 c ^ "'")
-				) (ExtString.String.explode opt);
-				let buf = Buffer.create 0 in
-				let rec loop prev esc = function
-					| [] -> ()
-					| c :: l when esc ->
-						(match c with
-						| 'n' -> Buffer.add_char buf '\n'
-						| 'r' -> Buffer.add_char buf '\r'
-						| 't' -> Buffer.add_char buf '\t'
-						| 'd' -> Buffer.add_string buf "[0-9]"
-						| '\\' -> Buffer.add_string buf "\\\\"
-						| '(' | ')' -> Buffer.add_char buf c
-						| '1'..'9' | '+' | '$' | '^' | '*' | '?' | '.' | '[' | ']' ->
-							Buffer.add_char buf '\\';
-							Buffer.add_char buf c;
-						| _ ->
-							Buffer.add_char buf c);
-						loop c false l
-					| c :: l ->
-						match c with
-						| '\\' -> loop prev true l
-						| '(' | '|' | ')' ->
-							Buffer.add_char buf '\\';
-							Buffer.add_char buf c;
-							loop c false l
-						| '?' when prev = '(' && (match l with ':' :: _ -> true | _ -> false) ->
-							failwith "Non capturing groups '(?:' are not supported in macros"
-						| '?' when prev = '*' ->
-							failwith "Ungreedy *? are not supported in macros"
-						| _ ->
-							Buffer.add_char buf c;
-							loop c false l
-				in
-				loop '\000' false (ExtString.String.explode str);
-				let str = Buffer.contents buf in
-				let r = {
-					r = if !case_sensitive then Str.regexp str else Str.regexp_case_fold str;
+				) (ExtString.String.explode opt) in
+				let r = try regexp ~flags str with Error error -> failwith (string_of_pcre_error error) in
+				let pcre = {
+					r = r;
 					r_string = "";
-					r_groups = [||];
+					r_groups = [||]
 				} in
-				VAbstract (AReg r)
-			| _ -> error()
-		);
-		"regexp_match", Fun4 (fun r str pos len ->
-			match r, str, pos, len with
-			| VAbstract (AReg r), VString str, VInt pos, VInt len ->
-				let nstr, npos, delta = (if len = String.length str - pos then str, pos, 0 else String.sub str pos len, 0, pos) in
-				(try
-					ignore(Str.search_forward r.r nstr npos);
-					let rec loop n =
-						if n = 9 then
-							[]
-						else try
-							(Some (Str.group_beginning n + delta, Str.group_end n + delta)) :: loop (n + 1)
-						with Not_found ->
-							None :: loop (n + 1)
-						| Invalid_argument _ ->
-							[]
-					in
-					r.r_string <- str;
-					r.r_groups <- Array.of_list (loop 0);
-					VBool true;
+				VAbstract (AReg pcre)
+			| _ -> error()
+		);
+		"regexp_match", Fun4 (fun rex str pos len -> match rex, str, pos, len with
+			| VAbstract (AReg rex),VString str,VInt pos,VInt len ->
+				begin try
+					(* A bit awkward, but the PCRE bindings don't seem to expose the len argument... *)
+					if pos + len > String.length str then raise Not_found;
+					let str = String.sub str 0 (pos + len) in
+					let a = pcre_exec ~rex:rex.r ~pos str in
+					rex.r_string <- str;
+					rex.r_groups <- a;
+					VBool true
 				with Not_found ->
-					VBool false)
+					VBool false
+				end
 			| _ -> error()
 		);
-		"regexp_matched", Fun2 (fun r n ->
-			match r, n with
-			| VAbstract (AReg r), VInt n ->
-				(match (try r.r_groups.(n) with _ -> failwith ("Invalid group " ^ string_of_int n)) with
-				| None -> VNull
-				| Some (pos,pend) -> VString (String.sub r.r_string pos (pend - pos)))
+		"regexp_matched", Fun2 (fun r n -> match r, n with
+			| VAbstract (AReg r),VInt n ->
+				let pos = r.r_groups.(n * 2) in
+				let len = r.r_groups.(n * 2 + 1) - pos in
+				if pos = -1 then VNull
+				else VString (String.sub r.r_string pos len)
 			| _ -> error()
 		);
-		"regexp_matched_pos", Fun2 (fun r n ->
-			match r, n with
-			| VAbstract (AReg r), VInt n ->
-				(match (try r.r_groups.(n) with _ -> failwith ("Invalid group " ^ string_of_int n)) with
-				| None -> VNull
-				| Some (pos,pend) -> VObject (obj (hash_field (get_ctx())) ["pos",VInt pos;"len",VInt (pend - pos)]))
+		"regexp_matched_pos", Fun2 (fun r n -> match r, n with
+			| VAbstract (AReg r),VInt n ->
+				let pos = r.r_groups.(n * 2) in
+				let len = r.r_groups.(n * 2 + 1) - pos in
+				VObject (obj (hash_field (get_ctx())) ["pos",VInt pos;"len",VInt len])
 			| _ -> error()
 		);
-		(* regexp_replace : not used by Haxe *)
-		(* regexp_replace_all : not used by Haxe *)
-		(* regexp_replace_fun : not used by Haxe *)
 	]
-	| Some neko ->
-	let regexp_new_options = neko.load "regexp@regexp_new_options" 2 in
-	let regexp_match = neko.load "regexp@regexp_match" 4 in
-	let regexp_matched = neko.load "regexp@regexp_matched" 2 in
-	let regexp_matched_pos = neko.load "regexp@regexp_matched_pos" 2 in
-	make_library [
-		"regexp_new_options", Fun2 (fun str opt -> neko.call regexp_new_options [str;opt]);
-		"regexp_match", Fun4 (fun r str pos len -> neko.call regexp_match [r;str;pos;len]);
-		"regexp_matched", Fun2 (fun r n -> neko.call regexp_matched [r;n]);
-		"regexp_matched_pos", Fun2 (fun r n -> neko.call regexp_matched_pos [r;n]);
-	]
-
 
 (* ---------------------------------------------------------------------- *)
 (* ZLIB LIBRARY *)
@@ -3142,6 +2835,7 @@ let decode_tdecl = function
 
 let dec_int = function
 	| VInt i -> i
+	| VInt32 i -> Int32.to_int i
 	| _ -> raise Invalid_expr
 
 let dec_i32 = function
@@ -3398,8 +3092,7 @@ let value_signature v =
 
 let prepare_callback v n =
 	match v with
-	| VFunction f ->
-		if nargs f <> n then raise Invalid_expr;
+	| VFunction _ | VClosure _ ->
 		let ctx = get_ctx() in
 		(fun args ->
 			match catch_errors ctx (fun() -> ctx.do_call VNull v args null_pos) with

+ 5 - 2
src/macro/macroApi.ml

@@ -1082,6 +1082,9 @@ and decode_type t =
 	| 8, [a; pl] -> TAbstract (decode_ref a, List.map decode_type (dec_array pl))
 	| _ -> raise Invalid_expr
 
+and decode_type_decl t =
+	decode_tdecl (field t "__t")
+
 (* ---------------------------------------------------------------------- *)
 (* TEXPR Encoding *)
 
@@ -1616,7 +1619,7 @@ let macro_api ccom get_api =
 						enc_string ("\"" ^ Ast.s_escape (dec_string v) ^ "\"")
 					);
 					"buildMetaData", vfun1 (fun t ->
-						match Codegen.build_metadata com (decode_tdecl t) with
+						match Codegen.build_metadata com (decode_type_decl t) with
 						| None -> vnull
 						| Some e -> encode_texpr e
 					);
@@ -1633,7 +1636,7 @@ let macro_api ccom get_api =
 						vnull
 					);
 					"setCurrentClass", vfun1 (fun c ->
-						Genjs.set_current_class js_ctx (match decode_tdecl c with TClassDecl c -> c | _ -> assert false);
+						Genjs.set_current_class js_ctx (match decode_type_decl c with TClassDecl c -> c | _ -> assert false);
 						vnull
 					);
 				] in

+ 1 - 1
src/macro/macroContext.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 5 - 5
src/main.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -277,7 +277,7 @@ module Initialize = struct
 				add_std "lua";
 				"lua"
 			| Php ->
-				if Common.php7 com then
+				if Common.is_php7 com then
 					begin
 						com.package_rules <- PMap.add "php" (Directory "php7") com.package_rules;
 						com.package_rules <- PMap.add "php7" Forbidden com.package_rules;
@@ -322,7 +322,7 @@ let generate tctx ext xml_out interp swf_header =
 	(* check file extension. In case of wrong commandline, we don't want
 		to accidentaly delete a source file. *)
 	if file_extension com.file = ext then delete_file com.file;
-	if com.platform = Flash || com.platform = Cpp then List.iter (Codegen.fix_overrides com) com.types;
+	if com.platform = Flash || com.platform = Cpp || com.platform = Hl then List.iter (Codegen.fix_overrides com) com.types;
 	if Common.defined com Define.Dump then Codegen.Dump.dump_types com;
 	if Common.defined com Define.DumpDependencies then begin
 		Codegen.Dump.dump_dependencies com;
@@ -353,7 +353,7 @@ let generate tctx ext xml_out interp swf_header =
 		| Lua ->
 			Genlua.generate,"lua"
 		| Php ->
-			if Common.php7 com then
+			if Common.is_php7 com then
 				Genphp7.generate,"php"
 			else
 				Genphp.generate,"php"
@@ -461,7 +461,7 @@ let rec process_params create pl =
 
 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|-lua] <output> [options]\n Options :"
+		"Haxe Compiler %s - (C)2005-2017 Haxe Foundation\n Usage : haxe%s -main <class> [-swf|-js|-neko|-php|-cpp|-cppia|-as3|-cs|-java|-python|-hl|-lua] <output> [options]\n Options :"
 		Globals.s_version (if Sys.os_type = "Win32" then ".exe" else "")
 	in
 	let com = ctx.com in

+ 28 - 247
src/optimization/analyzer.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -570,230 +570,6 @@ module CopyPropagation = DataFlow(struct
 		);
 end)
 
-module CodeMotion = DataFlow(struct
-	open Graph
-	open BasicBlock
-
-	let conditional = false
-	let flag = FlagCodeMotion
-		type t_def =
-		| Top
-		| Bottom
-		| Const of tconstant
-		| Local of tvar
-		| Binop of binop * t * t
-
-	and t = (t_def * Type.t * pos)
-
-	let top = (Top,t_dynamic,null_pos)
-	let bottom = (Bottom,t_dynamic,null_pos)
-
-	let rec equals (lat1,_,_) (lat2,_,_) = match lat1,lat2 with
-		| Top,Top
-		| Bottom,Bottom ->
-			true
-		| Const ct1,Const ct2 ->
-			ct1 = ct2
-		| Local v1,Local v2 ->
-			v1 == v2
-		| Binop(op1,lat11,lat12),Binop(op2,lat21,lat22) ->
-			op1 = op2 && equals lat11 lat21 && equals lat12 lat22
-		| _ ->
-			false
-
-	let lattice = Hashtbl.create 0
-
-	let get_cell i = try Hashtbl.find lattice i with Not_found -> top
-	let set_cell i ct = Hashtbl.replace lattice i ct
-
-	let rec transfer ctx bb e =
-		let rec eval e = match e.eexpr with
-			| TConst ct ->
-				Const ct
-			| TLocal v ->
-				Local v
-			| TBinop(op,e1,e2) ->
-				let lat1 = transfer ctx bb e1 in
-				let lat2 = transfer ctx bb e2 in
-				Binop(op,lat1,lat2)
-			| _ ->
-				raise Exit
-		in
-		try
-			(eval e,e.etype,e.epos)
-		with Exit | Not_found ->
-			bottom
-
-	let init ctx =
-		Hashtbl.clear lattice
-
-	let commit ctx =
-		let rec filter_loops lat loops = match lat with
-			| Local v,_,_ ->
-				let bb = match (get_var_info ctx.graph v).vi_writes with [bb] -> bb | _ -> raise Exit in
-				let loops2 = List.filter (fun i -> not (List.mem i bb.bb_loop_groups)) loops in
-				if loops2 = [] then filter_loops (get_cell v.v_id) loops else true,lat,loops2
-			| Const _,_,_ ->
-				false,lat,loops
-			| Binop(op,lat1,lat2),t,p ->
-				let has_local1,lat1,loops = filter_loops lat1 loops in
-				let has_local2,lat2,loops = filter_loops lat2 loops in
-				has_local1 || has_local2,(Binop(op,lat1,lat2),t,p),loops
-			| _ ->
-				raise Exit
-		in
-		let rec to_texpr (lat,t,p) =
-			let def = match lat with
-				| Local v -> TLocal v
-				| Const ct -> TConst ct
-				| Binop(op,lat1,lat2) -> TBinop(op,to_texpr lat1,to_texpr lat2)
-				| _ -> raise Exit
-			in
-			{ eexpr = def; etype = t; epos = p }
-		in
-		let cache = Hashtbl.create 0 in
-		let replace decl bb v =
-			let lat,t,p = get_cell v.v_id in
-			match lat with
-			| Binop(op,lat1,lat2) ->
-				let has_local1,lat1,loops = filter_loops lat1 bb.bb_loop_groups in
-				let has_local2,lat2,loops = filter_loops lat2 loops in
-				if loops = [] || not (has_local1 || has_local2) then raise Exit;
-				let lat = ((Binop(op,lat1,lat2)),t,p) in
-				let bb_loop_pre = IntMap.find (List.hd loops) ctx.graph.g_loops in
-				let v' = try
-					let l = Hashtbl.find cache bb_loop_pre.bb_id in
-					snd (List.find (fun (lat',e) -> equals lat lat') l)
-				with Not_found ->
-					let v' = if decl then begin
-						v
-					end else begin
-						let v' = alloc_var ctx.temp_var_name v.v_type v.v_pos in
-						declare_var ctx.graph v' bb_loop_pre;
-						v'.v_meta <- [Meta.CompilerGenerated,[],p];
-						v'
-					end in
-					let e = to_texpr lat in
-					let e = mk (TVar(v',Some e)) ctx.com.basic.tvoid p in
-					add_texpr bb_loop_pre e;
-					set_var_value ctx.graph v' bb_loop_pre false (DynArray.length bb_loop_pre.bb_el - 1);
-					Hashtbl.replace cache bb_loop_pre.bb_id ((lat,v') :: try Hashtbl.find cache bb_loop_pre.bb_id with Not_found -> []);
-					v'
-				in
-				let ev' = mk (TLocal v') v'.v_type p in
-				if decl then begin
-					if v == v' then
-						mk (TConst TNull) t p
-					else
-						mk (TVar(v,Some ev')) ctx.com.basic.tvoid p
-				end else begin
-					let ev = mk (TLocal v) v.v_type p in
-					mk (TBinop(OpAssign,ev,ev')) t p
-				end
-			| _ ->
-				raise Exit
-		in
-		let rec commit bb e = match e.eexpr with
-			| TBinop(OpAssign,({eexpr = TLocal v} as e1),e2) ->
-				begin try
-					replace false bb v
-				with Exit ->
-					{e with eexpr = TBinop(OpAssign,e1,commit bb e2)}
-				end
-			| TVar(v,Some e1) when Meta.has Meta.CompilerGenerated v.v_meta ->
-				begin try
-					replace true bb v
-				with Exit ->
-					{e with eexpr = TVar(v,Some (commit bb e1))}
-				end
-			| _ ->
-				Type.map_expr (commit bb) e
-		in
-		Graph.iter_dom_tree ctx.graph (fun bb ->
-			if bb.bb_loop_groups <> [] then dynarray_map (commit bb) bb.bb_el
-		);
-end)
-
-module LoopInductionVariables = struct
-	open Graph
-
-	type book = {
-		tvar : tvar;
-		index : int;
-		mutable lowlink : int;
-		mutable on_stack : bool
-	}
-
-	let find_cycles g =
-		let index = ref 0 in
-		let s = ref [] in
-		let book = ref IntMap.empty in
-		let add_book_entry v =
-			let entry = {
-				tvar = v;
-				index = !index;
-				lowlink = !index;
-				on_stack = true;
-			} in
-			incr index;
-			book := IntMap.add v.v_id entry !book;
-			entry
-		in
-		let rec strong_connect vi =
-			let v_entry = add_book_entry vi.vi_var in
-			s := v_entry :: !s;
-			List.iter (fun (bb,is_phi,i) ->
-				try
-					let e = BasicBlock.get_texpr bb is_phi i in
-					let w = match e.eexpr with
-						| TVar(v,_) | TBinop(OpAssign,{eexpr = TLocal v},_) -> v
-						| _ -> raise Exit
-					in
-					begin try
-						let w_entry = IntMap.find w.v_id !book in
-						if w_entry.on_stack then
-							v_entry.lowlink <- min v_entry.lowlink w_entry.index
-					with Not_found ->
-						let w_entry = strong_connect (get_var_info g w) in
-						v_entry.lowlink <- min v_entry.lowlink w_entry.lowlink;
-					end
-				with Exit ->
-					()
-			) vi.vi_ssa_edges;
-			if v_entry.lowlink = v_entry.index then begin
-				let rec loop acc entries = match entries with
-					| w_entry :: entries ->
-						w_entry.on_stack <- false;
-						if w_entry == v_entry then w_entry :: acc,entries
-						else loop (w_entry :: acc) entries
-					| [] ->
-						acc,[]
-				in
-				let scc,rest = loop [] !s in
-				begin match scc with
-					| [] | [_] ->
-						()
-					| _ ->
-						print_endline "SCC:";
-						List.iter (fun entry -> print_endline (Printf.sprintf "%s<%i>" entry.tvar.v_name entry.tvar.v_id)) scc;
-						(* now what? *)
-				end;
-				s := rest
-			end;
-			v_entry
-		in
-		DynArray.iter (fun vi -> match vi.vi_ssa_edges with
-			| [] ->
-				()
-			| _ ->
-				if not (IntMap.mem vi.vi_var.v_id !book) then
-					ignore(strong_connect vi)
-		) g.g_var_infos
-
-	let apply ctx =
-		find_cycles ctx.graph
-end
-
 (*
 	LocalDce implements a mark & sweep dead code elimination. The mark phase follows the CFG edges of the graphs to find
 	variable usages and marks variables accordingly. If ConstPropagation was run before, only CFG edges which are
@@ -927,7 +703,6 @@ module Debug = struct
 		let s_edge_flag = function
 			| FlagExecutable -> "exe"
 			| FlagDce -> "dce"
-			| FlagCodeMotion -> "motion"
 			| FlagCopyPropagation -> "copy"
 		in
 		let label = label ^ match edge.cfg_flags with
@@ -1103,8 +878,8 @@ module Run = struct
 	open AnalyzerConfig
 	open Graph
 
-	let with_timer actx s f =
-		let timer = timer (if actx.config.detail_times then ["analyzer";s] else ["analyzer"]) in
+	let with_timer detailed s f =
+		let timer = timer (if detailed then "analyzer" :: s else ["analyzer"]) in
 		let r = f() in
 		timer();
 		r
@@ -1132,9 +907,9 @@ module Run = struct
 
 	let there actx e =
 		if actx.com.debug then add_debug_expr actx "initial" e;
-		let e = with_timer actx "var-lazifier" (fun () -> VarLazifier.apply actx.com e) in
+		let e = with_timer actx.config.detail_times ["->";"var-lazifier"] (fun () -> VarLazifier.apply actx.com e) in
 		if actx.com.debug then add_debug_expr actx "after var-lazifier" e;
-		let e = with_timer actx "filter-apply" (fun () -> TexprFilter.apply actx.com e) in
+		let e = with_timer actx.config.detail_times ["->";"filter-apply"] (fun () -> TexprFilter.apply actx.com e) in
 		if actx.com.debug then add_debug_expr actx "after filter-apply" e;
 		let tf,t,is_real_function = match e.eexpr with
 			| TFunction tf ->
@@ -1145,18 +920,18 @@ module Run = struct
 				let tf = { tf_args = []; tf_type = e.etype; tf_expr = e; } in
 				tf,tfun [] e.etype,false
 		in
-		with_timer actx "from-texpr" (fun () -> AnalyzerTexprTransformer.from_tfunction actx tf t e.epos);
+		with_timer actx.config.detail_times ["->";"from-texpr"] (fun () -> AnalyzerTexprTransformer.from_tfunction actx tf t e.epos);
 		is_real_function
 
 	let back_again actx is_real_function =
-		let e = with_timer actx "to-texpr" (fun () -> AnalyzerTexprTransformer.to_texpr actx) in
+		let e = with_timer actx.config.detail_times ["<-";"to-texpr"] (fun () -> AnalyzerTexprTransformer.to_texpr actx) in
 		if actx.com.debug then add_debug_expr actx "after to-texpr" e;
 		DynArray.iter (fun vi ->
 			vi.vi_var.v_extra <- vi.vi_extra;
 		) actx.graph.g_var_infos;
-		let e = if actx.config.fusion then with_timer actx "fusion" (fun () -> Fusion.apply actx.com actx.config e) else e in
+		let e = if actx.config.fusion then with_timer actx.config.detail_times ["<-";"fusion"] (fun () -> Fusion.apply actx.com actx.config e) else e in
 		if actx.com.debug then add_debug_expr actx "after fusion" e;
-		let e = with_timer actx "cleanup" (fun () -> Cleanup.apply actx.com e) in
+		let e = with_timer actx.config.detail_times ["<-";"cleanup"] (fun () -> Cleanup.apply actx.com e) in
 		if actx.com.debug then add_debug_expr actx "after cleanup" e;
 		let e = if is_real_function then
 			e
@@ -1181,21 +956,21 @@ module Run = struct
 
 	let run_on_expr actx e =
 		let is_real_function = there actx e in
-		Graph.infer_immediate_dominators actx.graph;
-		Graph.infer_scopes actx.graph;
-		Graph.infer_var_writes actx.graph;
+		with_timer actx.config.detail_times ["->";"idom"] (fun () -> Graph.infer_immediate_dominators actx.graph);
+		with_timer actx.config.detail_times ["->";"infer_scopes"] (fun () -> Graph.infer_scopes actx.graph);
+		with_timer actx.config.detail_times ["->";"var writes"] (fun () -> Graph.infer_var_writes actx.graph);
 		if actx.com.debug then Graph.check_integrity actx.graph;
 		if actx.config.optimize && not actx.has_unbound then begin
-			with_timer actx "ssa-apply" (fun () -> Ssa.apply actx);
-			if actx.config.const_propagation then with_timer actx "const-propagation" (fun () -> ConstPropagation.apply actx);
-			if actx.config.copy_propagation then with_timer actx "copy-propagation" (fun () -> CopyPropagation.apply actx);
-			if actx.config.code_motion then with_timer actx "code-motion" (fun () -> CodeMotion.apply actx);
-			with_timer actx "local-dce" (fun () -> LocalDce.apply actx);
+			with_timer actx.config.detail_times ["optimize";"ssa-apply"] (fun () -> Ssa.apply actx);
+			if actx.config.const_propagation then with_timer actx.config.detail_times ["optimize";"const-propagation"] (fun () -> ConstPropagation.apply actx);
+			if actx.config.copy_propagation then with_timer actx.config.detail_times ["optimize";"copy-propagation"] (fun () -> CopyPropagation.apply actx);
+			with_timer actx.config.detail_times ["optimize";"local-dce"] (fun () -> LocalDce.apply actx);
 		end;
 		back_again actx is_real_function
 
 	let rec reduce_control_flow ctx e =
-		Type.map_expr (reduce_control_flow ctx) (Optimizer.reduce_control_flow ctx e)
+		let e = Type.map_expr (reduce_control_flow ctx) e in
+		Optimizer.reduce_control_flow ctx e
 
 	let run_on_field ctx config c cf = match cf.cf_expr with
 		| Some e when not (is_ignored cf.cf_meta) && not (Typecore.is_removable_field ctx cf) ->
@@ -1268,12 +1043,18 @@ module Run = struct
 	let run_on_types ctx types =
 		let com = ctx.Typecore.com in
 		let config = get_base_config com in
-		let cfl = if config.optimize && config.purity_inference then Purity.infer com else [] in
-		List.iter (run_on_type ctx config) types;
-		List.iter (fun cf -> cf.cf_meta <- List.filter (fun (m,_,_) -> m <> Meta.Pure) cf.cf_meta) cfl
+		with_timer config.detail_times ["other"] (fun () ->
+			let cfl = if config.optimize && config.purity_inference then with_timer config.detail_times ["optimize";"purity-inference"] (fun () -> Purity.infer com) else [] in
+			List.iter (run_on_type ctx config) types;
+			List.iter (fun cf -> cf.cf_meta <- List.filter (fun (m,_,_) -> m <> Meta.Pure) cf.cf_meta) cfl
+		)
 end
 ;;
 Typecore.analyzer_run_on_expr_ref := (fun com e ->
-	let actx = Run.create_analyzer_context com (AnalyzerConfig.get_base_config com) e in
+	let config = AnalyzerConfig.get_base_config com in
+	(* We always want to optimize because const propagation might be required to obtain
+	   a constant expression for inline field initializations (see issue #4977). *)
+	let config = {config with AnalyzerConfig.optimize = true} in
+	let actx = Run.create_analyzer_context com config e in
 	Run.run_on_expr actx e
 )

+ 26 - 25
src/optimization/analyzerConfig.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -31,7 +31,6 @@ type t = {
 	optimize : bool;
 	const_propagation : bool;
 	copy_propagation : bool;
-	code_motion : bool;
 	local_dce : bool;
 	fusion : bool;
 	purity_inference : bool;
@@ -41,12 +40,11 @@ type t = {
 	fusion_debug : bool;
 }
 
+let flag_optimize = "optimize"
 let flag_const_propagation = "const_propagation"
 let flag_copy_propagation = "copy_propagation"
-let flag_code_motion = "code_motion"
 let flag_local_dce = "local_dce"
 let flag_fusion = "fusion"
-let flag_purity_inference = "purity_inference"
 let flag_ignore = "ignore"
 let flag_dot_debug = "dot_debug"
 let flag_full_debug = "full_debug"
@@ -56,7 +54,7 @@ let flag_fusion_debug = "fusion_debug"
 let all_flags =
 	List.fold_left (fun acc flag ->
 		flag :: ("no_" ^ flag) :: acc
-	) [] [flag_const_propagation;flag_copy_propagation;flag_code_motion;flag_local_dce;flag_fusion;flag_purity_inference;flag_ignore;flag_dot_debug;flag_user_var_fusion]
+	) [] [flag_optimize;flag_const_propagation;flag_copy_propagation;flag_local_dce;flag_fusion;flag_ignore;flag_dot_debug;flag_user_var_fusion]
 
 let has_analyzer_option meta s =
 	try
@@ -84,10 +82,9 @@ let is_ignored meta =
 
 let get_base_config com =
 	{
-		optimize = not (Common.defined com Define.NoAnalyzer);
+		optimize = Common.raw_defined com "analyzer-optimize";
 		const_propagation = not (Common.raw_defined com "analyzer-no-const-propagation");
 		copy_propagation = not (Common.raw_defined com "analyzer-no-copy-propagation");
-		code_motion = Common.raw_defined com "analyzer-code-motion";
 		local_dce = not (Common.raw_defined com "analyzer-no-local-dce");
 		fusion = not (Common.raw_defined com "analyzer-no-fusion");
 		purity_inference = not (Common.raw_defined com "analyzer-no-purity-inference");
@@ -101,24 +98,28 @@ let update_config_from_meta com config meta =
 	List.fold_left (fun config meta -> match meta with
 		| (Meta.Analyzer,el,_) ->
 			List.fold_left (fun config e -> match fst e with
-				| EConst (Ident s) when s = "no_" ^ flag_const_propagation -> { config with const_propagation = false}
-				| EConst (Ident s) when s = flag_const_propagation -> { config with const_propagation = true}
-				| EConst (Ident s) when s = "no_" ^ flag_copy_propagation -> { config with copy_propagation = false}
-				| EConst (Ident s) when s = flag_copy_propagation -> { config with copy_propagation = true}
-				| EConst (Ident s) when s = "no_" ^ flag_code_motion -> { config with code_motion = false}
-				| EConst (Ident s) when s = flag_code_motion -> { config with code_motion = true}
-				| EConst (Ident s) when s = "no_" ^ flag_local_dce -> { config with local_dce = false}
-				| EConst (Ident s) when s = flag_local_dce -> { config with local_dce = true}
-				| EConst (Ident s) when s = "no_" ^ flag_fusion -> { config with fusion = false}
-				| EConst (Ident s) when s = flag_fusion -> { config with fusion = true}
-				| EConst (Ident s) when s = "no_" ^ flag_purity_inference -> { config with purity_inference = false}
-				| EConst (Ident s) when s = flag_purity_inference -> { config with purity_inference = true}
-				| EConst (Ident s) when s = flag_dot_debug -> {config with debug_kind = DebugDot}
-				| EConst (Ident s) when s = flag_full_debug -> {config with debug_kind = DebugFull}
-				| EConst (Ident s) when s = flag_user_var_fusion -> {config with user_var_fusion = true}
-				| EConst (Ident s) when s = "no_" ^ flag_user_var_fusion -> {config with user_var_fusion = false}
-				| EConst (Ident s) when s = flag_fusion_debug -> {config with fusion_debug = true}
-				| EConst (Ident s) when s = "as_var" -> config
+				| EConst (Ident s) ->
+					begin match s with
+						| "optimize" -> { config with optimize = true }
+						| "no_optimize" -> { config with optimize = false }
+						| "const_propagation" -> { config with const_propagation = true }
+						| "no_const_propagation" -> { config with const_propagation = false }
+						| "copy_propagation" -> { config with copy_propagation = true }
+						| "no_copy_propagation" -> { config with copy_propagation = false }
+						| "local_dce" -> { config with local_dce = true }
+						| "no_local_dce" -> { config with local_dce = false }
+						| "fusion" -> { config with fusion = true }
+						| "no_fusion" -> { config with fusion = false }
+						| "user_var_fusion" -> { config with user_var_fusion = true }
+						| "no_user_var_fusion" -> { config with user_var_fusion = false }
+						| "dot_debug" -> { config with debug_kind = DebugDot }
+						| "full_debug" -> { config with debug_kind = DebugFull }
+						| "fusion_debug" -> { config with fusion_debug = true }
+						| "as_var" -> config
+						| _ ->
+							com.warning (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);
+							config
+					end
 				| _ ->
 					let s = Ast.s_expr e in
 					com.warning (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);

+ 22 - 7
src/optimization/analyzerTexpr.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -123,7 +123,7 @@ let rec can_be_used_as_value com e =
 		(* | TCall _ | TNew _ when (match com.platform with Cpp | Php -> true | _ -> false) -> raise Exit *)
 		| TReturn _ | TThrow _ | TBreak | TContinue -> raise Exit
 		| TUnop((Increment | Decrement),_,_) when not (target_handles_unops com) -> raise Exit
-		| TNew _ when com.platform = Php && not (Common.php7 com) -> raise Exit
+		| TNew _ when com.platform = Php && not (Common.is_php7 com) -> raise Exit
 		| TFunction _ -> ()
 		| _ -> Type.iter loop e
 	in
@@ -151,6 +151,7 @@ let is_unbound_call_that_might_have_side_effects v el = match v.v_name,el with
 
 let is_ref_type = function
 	| TType({t_path = ["cs"],("Ref" | "Out")},_) -> true
+	| TType({t_path = path},_) when path = Genphp7.ref_type_path -> true
 	| TType({t_path = ["cpp"],("Reference")},_) -> true
 	| TAbstract({a_path=["hl";"types"],"Ref"},_) -> true
 	| _ -> false
@@ -368,13 +369,19 @@ module InterferenceReport = struct
 		let rec loop e = match e.eexpr with
 			(* vars *)
 			| TLocal v ->
-				set_var_read ir v
+				set_var_read ir v;
+				if v.v_capture then set_state_read ir;
 			| TBinop(OpAssign,{eexpr = TLocal v},e2) ->
 				set_var_write ir v;
+				if v.v_capture then set_state_write ir;
 				loop e2
 			| TBinop(OpAssignOp _,{eexpr = TLocal v},e2) ->
 				set_var_read ir v;
 				set_var_write ir v;
+				if v.v_capture then begin
+					set_state_read ir;
+					set_state_write ir;
+				end;
 				loop e2
 			| TUnop((Increment | Decrement),_,{eexpr = TLocal v}) ->
 				set_var_read ir v;
@@ -627,7 +634,15 @@ module Fusion = struct
 				let e1 = {e1 with eexpr = TVar(v1,Some e2)} in
 				state#dec_writes v1;
 				fuse (e1 :: acc) el
-			| ({eexpr = TVar(v1,None)} as e1) :: ({eexpr = TIf(eif,_,Some _)} as e2) :: el when can_be_used_as_value com e2 && not (ExtType.is_void e2.etype) && (match com.platform with Php -> false | Cpp when not (Common.defined com Define.Cppia) -> false | _ -> true) ->
+			| ({eexpr = TVar(v1,None)} as e1) :: ({eexpr = TIf(eif,_,Some _)} as e2) :: el
+				when
+					can_be_used_as_value com e2 &&
+					not (ExtType.is_void e2.etype) &&
+					(match com.platform with
+						| Php when not (Common.is_php7 com) -> false
+						| Cpp when not (Common.defined com Define.Cppia) -> false
+						| _ -> true)
+				->
 				begin try
 					let i = ref 0 in
 					let check_assign e = match e.eexpr with
@@ -682,7 +697,7 @@ module Fusion = struct
 							let el = List.map replace el in
 							let e2 = replace e2 in
 							e2,el
-						| Php | Cpp  when not (Common.defined com Define.Cppia) && not (Common.php7 com) ->
+						| Php | Cpp  when not (Common.defined com Define.Cppia) && not (Common.is_php7 com) ->
 							let is_php_safe e1 =
 								let rec loop e = match e.eexpr with
 									| TCall _ -> raise Exit
@@ -691,7 +706,7 @@ module Fusion = struct
 								in
 								try loop e1; true with Exit -> false
 							in
-							(* PHP doesn't like call()() expressions. *)
+							(* PHP5 doesn't like call()() expressions. *)
 							let e2 = if com.platform = Php && not (is_php_safe e1) then explore e2 else replace e2 in
 							let el = handle_el el in
 							e2,el
@@ -794,7 +809,7 @@ module Fusion = struct
 							let e3 = replace e3 in
 							if not !found && has_state_read ir then raise Exit;
 							{e with eexpr = TBinop(OpAssign,{ea with eexpr = TArray(e1,e2)},e3)}
-						| TBinop(op,e1,e2) when (match com.platform with Cpp | Php when not (Common.php7 com) -> true | _ -> false) ->
+						| TBinop(op,e1,e2) when (match com.platform with Cpp | Php when not (Common.is_php7 com) -> true | _ -> false) ->
 							let e1 = replace e1 in
 							let temp_found = !found in
 							found := false;

+ 1 - 1
src/optimization/analyzerTexprTransformer.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 1 - 2
src/optimization/analyzerTypes.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -46,7 +46,6 @@ module BasicBlock = struct
 	type cfg_edge_Flag =
 		| FlagExecutable      (* Used by constant propagation to handle live edges *)
 		| FlagDce             (* Used by DCE to keep track of handled edges *)
-		| FlagCodeMotion      (* Used by code motion to track handled edges *)
 		| FlagCopyPropagation (* Used by copy propagation to track handled eges *)
 
 	type cfg_edge_kind =

+ 26 - 2
src/optimization/dce.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -317,6 +317,27 @@ and mark_directly_used_mt mt =
 	| _ ->
 		()
 
+and mark_directly_used_t com p t =
+	match follow t with
+	| TInst({cl_kind = KNormal} as c,pl) ->
+		mark_directly_used_class c;
+		List.iter (mark_directly_used_t com p) pl
+	| TEnum(e,pl) ->
+		mark_directly_used_enum e;
+		List.iter (mark_directly_used_t com p) pl
+	| TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta ->
+		begin try (* this is copy-pasted from mark_t *)
+			mark_directly_used_t com p (snd (Typecore.AbstractCast.find_multitype_specialization com a pl p))
+		with Error.Error _ ->
+			()
+		end
+	| TAbstract(a,pl) ->
+		List.iter (mark_directly_used_t com p) pl;
+		if not (Meta.has Meta.CoreType a.a_meta) then
+			mark_directly_used_t com p (Abstract.get_underlying_type a pl)
+	| _ ->
+		()
+
 and check_dynamic_write dce fa =
 	let n = field_name fa in
 	check_and_add_feature dce ("dynamic_write");
@@ -441,7 +462,10 @@ and expr dce e =
 	| TTry(e, vl) ->
 		expr dce e;
 		List.iter (fun (v,e) ->
-			if v.v_type != t_dynamic then check_feature dce "typed_catch";
+			if v.v_type != t_dynamic then begin
+				check_feature dce "typed_catch";
+				mark_directly_used_t dce.com v.v_pos v.v_type;
+			end;
 			expr dce e;
 			mark_t dce e.epos v.v_type;
 		) vl;

+ 3 - 3
src/optimization/filters.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -901,7 +901,7 @@ let add_meta_field ctx t = match t with
 			f.cf_expr <- Some e;
 			let can_deal_with_interface_metadata () = match ctx.com.platform with
 				| Flash when Common.defined ctx.com Define.As3 -> false
-				| Php when not (Common.php7 ctx.com) -> false
+				| Php when not (Common.is_php7 ctx.com) -> false
 				| _ -> true
 			in
 			if c.cl_interface && not (can_deal_with_interface_metadata()) then begin
@@ -1129,7 +1129,7 @@ let run com tctx main =
 		apply_native_paths;
 		add_rtti;
 		(match com.platform with | Java | Cs -> (fun _ _ -> ()) | _ -> add_field_inits);
-		add_meta_field;
+		(match com.platform with Hl -> (fun _ _ -> ()) | _ -> add_meta_field);
 		check_void_field;
 		(match com.platform with | Cpp -> promote_first_interface_to_super | _ -> (fun _ _ -> ()) );
 		commit_features;

+ 16 - 6
src/optimization/optimizer.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -610,6 +610,15 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f
 		in
 		let e = List.fold_left inline_meta e cf.cf_meta in
 		let e = Display.Diagnostics.secure_generated_code ctx e in
+		if Meta.has (Meta.Custom ":inlineDebug") ctx.meta then begin
+			let se t = s_expr_pretty true t true (s_type (print_context())) in
+			print_endline (Printf.sprintf "Inline %s:\n\tArgs: %s\n\tExpr: %s\n\tResult: %s"
+				cf.cf_name
+				(String.concat "" (List.map (fun (i,e) -> Printf.sprintf "\n\t\t%s<%i> = %s" (i.i_subst.v_name) (i.i_subst.v_id) (se "\t\t" e)) inlined_vars))
+				(se "\t" f.tf_expr)
+				(se "\t" e)
+			);
+		end;
 		(* we need to replace type-parameters that were used in the expression *)
 		if not has_params then
 			Some e
@@ -1061,6 +1070,9 @@ let reduce_control_flow ctx e = match e.eexpr with
 		optimize_binop e op e1 e2
 	| TUnop (op,flag,esub) ->
 		optimize_unop e op flag esub
+	| TCall ({ eexpr = TField (o,FClosure (c,cf)) } as f,el) ->
+		let fmode = (match c with None -> FAnon cf | Some (c,tl) -> FInstance (c,tl,cf)) in
+		{ e with eexpr = TCall ({ f with eexpr = TField (o,fmode) },el) }
 	| _ ->
 		e
 
@@ -1079,9 +1091,6 @@ let rec reduce_loop ctx e =
 		(match inl with
 		| None -> reduce_expr ctx e
 		| Some e -> reduce_loop ctx e)
-	| TCall ({ eexpr = TField (o,FClosure (c,cf)) } as f,el) ->
-		let fmode = (match c with None -> FAnon cf | Some (c,tl) -> FInstance (c,tl,cf)) in
-		{ e with eexpr = TCall ({ f with eexpr = TField (o,fmode) },el) }
 	| _ ->
 		reduce_expr ctx (reduce_control_flow ctx e))
 
@@ -1235,11 +1244,12 @@ let inline_constructors ctx e =
 								e :: acc
 							| _ -> acc
 						) el_init c.cl_ordered_fields in
-						let e = match el_init with
+						let e' = match el_init with
 							| [] -> e
 							| _ -> mk (TBlock (List.rev (e :: el_init))) e.etype e.epos
 						in
-						add v e (IKCtor(cf,c.cl_extern || Meta.has Meta.Extern cf.cf_meta));
+						add v e' (IKCtor(cf,c.cl_extern || Meta.has Meta.Extern cf.cf_meta));
+						find_locals e
 					| None ->
 						()
 					end

+ 4 - 1
src/server.ml

@@ -430,7 +430,10 @@ let rec wait_loop process_params verbose accept =
 				incr compilation_step;
 				compilation_mark := !mark_loop;
 				List.iter (fun s -> write (s ^ "\n"); if verbose then print_endline ("> " ^ s)) (List.rev ctx.messages);
-				if ctx.has_error then write "\x02\n" else cache_context ctx.com;
+				if ctx.has_error then begin
+					measure_times := false;
+					write "\x02\n"
+				end else cache_context ctx.com;
 			);
 			ctx.setup <- (fun() ->
 				let sign = get_signature ctx.com in

+ 1 - 1
src/syntax/ast.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 1 - 1
src/syntax/lexer.mll

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 2 - 1
src/syntax/parser.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -745,6 +745,7 @@ and parse_using s p1 =
 			| [< '(Kwd Extern,p) >] ->
 				loop (("extern",p) :: acc)
 			| [< >] ->
+				if is_resuming p then type_path (List.map fst acc) false;
 				serror()
 			end
 		| [< '(Semicolon,p2) >] ->

+ 1 - 1
src/typing/matcher.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 1 - 1
src/typing/type.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 1 - 1
src/typing/typecore.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License

+ 11 - 5
src/typing/typeload.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -3511,19 +3511,25 @@ let type_module ctx mpath file ?(is_extern=false) tdecls p =
 
 let resolve_module_file com m remap p =
 	let forbid = ref false in
-	let file = (match m with
+	let compose_path no_rename =
+		(match m with
 		| [] , name -> name
 		| x :: l , name ->
 			let x = (try
 				match PMap.find x com.package_rules with
 				| Forbidden -> forbid := true; x
-				| Directory d -> d
+				| Directory d -> if no_rename then x else d
 				| Remap d -> remap := d :: l; d
 				with Not_found -> x
 			) in
 			String.concat "/" (x :: l) ^ "/" ^ name
-	) ^ ".hx" in
-	let file = Common.find_file com file in
+		) ^ ".hx"
+	in
+	let file = try
+			Common.find_file com (compose_path false)
+		with Not_found ->
+			Common.find_file com (compose_path true)
+	in
 	let file = (match String.lowercase (snd m) with
 	| "con" | "aux" | "prn" | "nul" | "com1" | "com2" | "com3" | "lpt1" | "lpt2" | "lpt3" when Sys.os_type = "Win32" ->
 		(* these names are reserved by the OS - old DOS legacy, such files cannot be easily created but are reported as visible *)

+ 28 - 21
src/typing/typer.ml

@@ -1,6 +1,6 @@
 (*
 	The Haxe Compiler
-	Copyright (C) 2005-2016  Haxe Foundation
+	Copyright (C) 2005-2017  Haxe Foundation
 
 	This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
@@ -1131,7 +1131,7 @@ let rec using_field ctx mode e i p =
 	| (c,pc) :: l ->
 		try
 			let cf = PMap.find i c.cl_statics in
-			if Meta.has Meta.NoUsing cf.cf_meta || not (can_access ctx c cf true) then raise Not_found;
+			if Meta.has Meta.NoUsing cf.cf_meta || not (can_access ctx c cf true) || (Meta.has Meta.Impl cf.cf_meta) then raise Not_found;
 			let monos = List.map (fun _ -> mk_mono()) cf.cf_params in
 			let map = apply_params cf.cf_params monos in
 			let t = map cf.cf_type in
@@ -1942,36 +1942,40 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p =
 		| AKAccess(a,tl,c,ebase,ekey) ->
 			let cf_get,tf_get,r_get,ekey,_ = AbstractCast.find_array_access ctx a tl ekey None p in
 			(* bind complex keys to a variable so they do not make it into the output twice *)
-			let ekey,l = match Optimizer.make_constant_expression ctx ekey with
-				| Some e -> e, fun () -> None
+			let save = save_locals ctx in
+			let maybe_bind_to_temp e = match Optimizer.make_constant_expression ctx e with
+				| Some e -> e,None
 				| None ->
-					let save = save_locals ctx in
-					let v = gen_local ctx ekey.etype p in
-					let e = mk (TLocal v) ekey.etype p in
-					e, fun () -> (save(); Some (mk (TVar (v,Some ekey)) ctx.t.tvoid p))
+					let v = gen_local ctx e.etype p in
+					let e' = mk (TLocal v) e.etype p in
+					e', Some (mk (TVar (v,Some e)) ctx.t.tvoid p)
 			in
+			let ekey,ekey' = maybe_bind_to_temp ekey in
+			let ebase,ebase' = maybe_bind_to_temp ebase in
 			let eget = mk_array_get_call ctx (cf_get,tf_get,r_get,ekey,None) c ebase p in
 			let eget = type_binop2 ctx op eget e2 true (WithType eget.etype) p in
 			unify ctx eget.etype r_get p;
 			let cf_set,tf_set,r_set,ekey,eget = AbstractCast.find_array_access ctx a tl ekey (Some eget) p in
 			let eget = match eget with None -> assert false | Some e -> e in
 			let et = type_module_type ctx (TClassDecl c) None p in
-			begin match cf_set.cf_expr,cf_get.cf_expr with
+			let e = match cf_set.cf_expr,cf_get.cf_expr with
 				| None,None ->
 					let ea = mk (TArray(ebase,ekey)) r_get p in
 					mk (TBinop(OpAssignOp op,ea,type_expr ctx e2 (WithType r_get))) r_set p
 				| Some _,Some _ ->
 					let ef_set = mk (TField(et,(FStatic(c,cf_set)))) tf_set p in
-					(match l() with
-					| None -> make_call ctx ef_set [ebase;ekey;eget] r_set p
-					| Some e ->
-						mk (TBlock [
-							e;
-							make_call ctx ef_set [ebase;ekey;eget] r_set p
-						]) r_set p)
+					let el = [make_call ctx ef_set [ebase;ekey;eget] r_set p] in
+					let el = match ebase' with None -> el | Some ebase -> ebase :: el in
+					let el = match ekey' with None -> el | Some ekey -> ekey :: el in
+					begin match el with
+						| [e] -> e
+						| el -> mk (TBlock el) r_set p
+					end
 				| _ ->
 					error "Invalid array access getter/setter combination" p
-			end;
+			in
+			save();
+			e
 		| AKInline _ | AKMacro _ ->
 			assert false)
 	| _ ->
@@ -2628,7 +2632,7 @@ and type_access ctx e p mode =
 					tf_args = List.map (fun v -> v,None) vl;
 					tf_type = t;
 					tf_expr = mk (TReturn (Some ec)) t p;
-				}) (tfun (List.map (fun v -> v.v_type) vl) t) p)
+				}) (TFun ((List.map (fun v -> v.v_name,false,v.v_type) vl),t)) p)
 			| _ -> error "Binding new is only allowed on class types" p
 		end;
 	| EField _ ->
@@ -3311,7 +3315,7 @@ and type_array_decl ctx el with_type p =
 		let t = try
 			unify_min_raise ctx el
 		with Error (Unify l,p) ->
-			if ctx.untyped then t_dynamic else begin
+			if ctx.untyped || ctx.com.display.dms_error_policy = EPIgnore then t_dynamic else begin
 				display_error ctx "Arrays of mixed types are only allowed if the type is forced to Array<Dynamic>" p;
 				raise (Error (Unify l, p))
 			end
@@ -3572,8 +3576,10 @@ and type_expr ctx (e,p) (with_type:with_type) =
 		let texpr = loop t in
 		mk (TCast (type_expr ctx e Value,Some texpr)) t p
 	| EDisplay (e,iscall) ->
-		if iscall then handle_signature_display ctx e with_type
-		else handle_display ctx e with_type
+		begin match ctx.com.display.dms_kind with
+			| DMField | DMSignature when iscall -> handle_signature_display ctx e with_type
+			| _ -> handle_display ctx e with_type
+		end
 	| EDisplayNew t ->
 		assert false
 		(*let t = Typeload.load_instance ctx t true p in
@@ -4102,6 +4108,7 @@ and type_call ctx e el (with_type:with_type) p =
 	| (EConst (Ident "$type"),_) , [e] ->
 		let e = type_expr ctx e Value in
 		ctx.com.warning (s_type (print_context()) e.etype) e.epos;
+		let e = Display.Diagnostics.secure_generated_code ctx e in
 		e
 	| (EField(e,"match"),p), [epat] ->
 		let et = type_expr ctx e Value in

+ 1 - 1
std/Any.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/Array.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/Class.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/Date.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/DateTools.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/EReg.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/Enum.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/EnumValue.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/IntIterator.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/Lambda.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/List.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/Map.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 2 - 2
std/Math.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -48,7 +48,7 @@ extern class Math
 	static var NEGATIVE_INFINITY(default, null) : Float;
 
 	/**
-		A special `Float` constant which denotes negative infinity.
+		A special `Float` constant which denotes positive infinity.
 
 		For example, this is the result of 1.0 / 0.0.
 

+ 1 - 1
std/Reflect.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/Std.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/StdTypes.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/String.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/StringBuf.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/StringTools.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/Sys.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/Type.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/UInt.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/Xml.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/ArrayBase.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/AutoCast.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/Callable.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/CastCharStar.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/Char.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/ConstCharStar.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/ConstPointer.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/FILE.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/FastIterator.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/Float32.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/Float64.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/Function.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/Int16.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/Int32.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/Int64.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/Int8.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 1 - 1
std/cpp/Lib.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),

+ 4 - 1
std/cpp/NativeArray.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -72,6 +72,9 @@ extern class NativeArray {
    @:nativeStaticExtension
 	public static function memcmp<T>( inArrayA:Array<T>, inArrayB:Array<T>) : Int { }
 
+   @:native("_hx_reslove_virtual_array")
+	public static function resolveVirtualArray( inArray:Array<Dynamic>) : Dynamic { }
+
 
    #if cppia
 	public static inline function unsafeGet<T>( inDestArray:Array<T>, inIndex:Int) : T {

+ 20 - 0
std/cpp/NativeSocket.hx

@@ -12,6 +12,9 @@ extern class NativeSocket
    @:extern @:native("_hx_std_socket_new")
    public static function socket_new(udp:Bool) : Dynamic return null;
 
+   @:extern @:native("_hx_std_socket_new")
+   public static function socket_new_ip(udp:Bool,ipv6:Bool) : Dynamic return null;
+
 
    @:extern @:native("_hx_std_socket_close")
    public static function socket_close(handle:Dynamic) : Void { }
@@ -20,6 +23,9 @@ extern class NativeSocket
    @:extern @:native("_hx_std_socket_bind")
    public static function socket_bind(o:Dynamic,host:Int,port:Int) : Void { }
 
+   @:extern @:native("_hx_std_socket_bind_ipv6")
+   public static function socket_bind_ipv6(o:Dynamic,host:haxe.io.BytesData,port:Int) : Void { }
+
 
    @:extern @:native("_hx_std_socket_send_char")
    public static function socket_send_char(o:Dynamic,c:Int) : Void { }
@@ -44,6 +50,9 @@ extern class NativeSocket
    @:extern @:native("_hx_std_socket_read")
    public static function socket_read(o:Dynamic) : haxe.io.BytesData return null;
 
+   @:extern @:native("_hx_std_host_resolve_ipv6")
+   public static function host_resolve_ipv6(host:String) : haxe.io.BytesData return null;
+
 
    @:extern @:native("_hx_std_host_resolve")
    public static function host_resolve(host:String) : Int return 0;
@@ -52,18 +61,29 @@ extern class NativeSocket
    @:extern @:native("_hx_std_host_to_string")
    public static function host_to_string(ip:Int) : String return null;
 
+   @:extern @:native("_hx_std_host_to_string_ipv6")
+   public static function host_to_string_ipv6(ipv6:haxe.io.BytesData) : String return null;
+
 
    @:extern @:native("_hx_std_host_reverse")
    public static function host_reverse(host:Int) : String return null;
 
+   @:extern @:native("_hx_std_host_reverse_ipv6")
+   public static function host_reverse_ipv6(ipv6:haxe.io.BytesData) : String return null;
+
 
    @:extern @:native("_hx_std_host_local")
    public static function host_local() : String return null;
 
+   inline public static function host_local_ipv6() : String return "::1";
+
 
    @:extern @:native("_hx_std_socket_connect")
    public static function socket_connect(o:Dynamic,host:Int,port:Int) : Void { }
 
+   @:extern @:native("_hx_std_socket_connect_ipv6")
+   public static function socket_connect_ipv6(o:Dynamic,host:haxe.io.BytesData,port:Int) : Void { }
+
 
    @:extern @:native("_hx_std_socket_listen")
    public static function socket_listen(o:Dynamic,n:Int) : Void { }

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно