Преглед на файлове

Merge pull request #4019 from HaxeFoundation/development

3.2.0-rc1
Simon Krajewski преди 10 години
родител
ревизия
9f852ce345
променени са 100 файла, в които са добавени 14193 реда и са изтрити 6962 реда
  1. 13 0
      .gitignore
  2. 39 28
      .travis.yml
  3. 11 0
      CONTRIBUTING.md
  4. 84 58
      Makefile
  5. 5 1
      Makefile.win
  6. 21 11
      README.md
  7. 1666 0
      analyzer.ml
  8. 64 0
      appveyor.yml
  9. 59 11
      ast.ml
  10. 408 198
      codegen.ml
  11. 135 41
      common.ml
  12. 216 54
      dce.ml
  13. 121 1
      extra/CHANGES.txt
  14. 3 2
      extra/ImportAll.hx
  15. 4 0
      extra/all.hxml
  16. 2 2
      extra/extract.hxml
  17. 15 5
      extra/extract.patch
  18. 1 1
      extra/haxelib_src
  19. 8 0
      extra/release-checklist.txt
  20. 363 328
      filters.ml
  21. 60 45
      genas3.ml
  22. 1221 1095
      gencommon.ml
  23. 413 117
      gencpp.ml
  24. 577 516
      gencs.ml
  25. 3458 2996
      genjava.ml
  26. 129 55
      genjs.ml
  27. 20 75
      genneko.ml
  28. 26 19
      genphp.ml
  29. 2405 0
      genpy.ml
  30. 22 17
      genswf.ml
  31. 0 1
      genswf8.ml
  32. 53 98
      genswf9.ml
  33. 108 54
      genxml.ml
  34. 14 0
      haxe.hxproj
  35. 272 135
      interp.ml
  36. 9 8
      lexer.mll
  37. 1 1
      libs
  38. 285 110
      main.ml
  39. 202 163
      matcher.ml
  40. 431 288
      optimizer.ml
  41. 148 63
      parser.ml
  42. 1 1
      std/Array.hx
  43. 4 2
      std/DateTools.hx
  44. 2 2
      std/EReg.hx
  45. 3 3
      std/IntIterator.hx
  46. 22 34
      std/List.hx
  47. 10 20
      std/Map.hx
  48. 39 48
      std/Math.hx
  49. 2 2
      std/Reflect.hx
  50. 6 3
      std/StdTypes.hx
  51. 1 1
      std/String.hx
  52. 4 2
      std/StringBuf.hx
  53. 69 28
      std/StringTools.hx
  54. 1 1
      std/Sys.hx
  55. 80 9
      std/UInt.hx
  56. 182 85
      std/Xml.hx
  57. 5 0
      std/cpp/Callable.hx
  58. 13 0
      std/cpp/CastCharStar.hx
  59. 3 0
      std/cpp/Char.hx
  60. 13 0
      std/cpp/ConstCharStar.hx
  61. 40 0
      std/cpp/ConstPointer.hx
  62. 3 0
      std/cpp/Float32.hx
  63. 3 0
      std/cpp/Float64.hx
  64. 22 0
      std/cpp/Function.hx
  65. 3 0
      std/cpp/Int16.hx
  66. 3 0
      std/cpp/Int32.hx
  67. 3 0
      std/cpp/Int64.hx
  68. 3 0
      std/cpp/Int8.hx
  69. 84 6
      std/cpp/Lib.hx
  70. 3 2
      std/cpp/NativeArray.hx
  71. 15 0
      std/cpp/NativeString.hx
  72. 9 6
      std/cpp/NativeXml.hx
  73. 16 0
      std/cpp/Object.hx
  74. 29 9
      std/cpp/Pointer.hx
  75. 6 0
      std/cpp/RawConstPointer.hx
  76. 6 0
      std/cpp/RawPointer.hx
  77. 3 0
      std/cpp/UInt16.hx
  78. 3 0
      std/cpp/UInt32.hx
  79. 3 0
      std/cpp/UInt64.hx
  80. 3 0
      std/cpp/UInt8.hx
  81. 5 0
      std/cpp/Void.hx
  82. 0 1
      std/cpp/_std/Date.hx
  83. 11 11
      std/cpp/_std/Reflect.hx
  84. 4 3
      std/cpp/_std/Sys.hx
  85. 3 2
      std/cpp/_std/Type.hx
  86. 139 0
      std/cpp/_std/haxe/Int64.hx2
  87. 21 18
      std/cpp/_std/haxe/ds/IntMap.hx
  88. 27 30
      std/cpp/_std/haxe/ds/ObjectMap.hx
  89. 28 31
      std/cpp/_std/haxe/ds/StringMap.hx
  90. 73 0
      std/cpp/_std/haxe/ds/WeakMap.hx
  91. 12 3
      std/cpp/_std/sys/FileSystem.hx
  92. 3 1
      std/cpp/_std/sys/db/Mysql.hx
  93. 3 1
      std/cpp/_std/sys/db/Sqlite.hx
  94. 4 0
      std/cpp/abi/Abi.hx
  95. 4 0
      std/cpp/abi/CDecl.hx
  96. 4 0
      std/cpp/abi/FastCall.hx
  97. 4 0
      std/cpp/abi/StdCall.hx
  98. 4 0
      std/cpp/abi/ThisCall.hx
  99. 4 0
      std/cpp/abi/Winapi.hx
  100. 28 0
      std/cpp/cppia/Host.hx

+ 13 - 0
.gitignore

@@ -41,6 +41,7 @@
 /tests/unit/cs
 /tests/unit/cs_unsafe
 /tests/unit/dump
+/tests/unit/db.db3
 
 /tests/unit/native_java/obj
 /tests/unit/native_java/cmd
@@ -51,9 +52,21 @@
 /tests/unit/native_cs/native_cs.csproj
 /tests/unit/unit.js.map
 /tests/unit/unit.n
+/tests/unit/node_modules/
 
 /haxe.sublime*
 build.bat
 tests/unit/compile.php.hxml
 /extra/*.xml
 tests/optimization/testopt.js
+tests/misc/pythonImport/native_python/__pycache__
+tests/unit/unit.py
+tests/unit/unit.py.res1.txt
+tests/unit/unit.py.res2.bin
+*.cmo
+tests/sys/bin/
+tests/optimization/dump/
+tests/misc/projects/*/*.n
+tests/unit/bin/
+tests/*.n
+tests/misc/projects/Issue3756/cpp/

+ 39 - 28
.travis.yml

@@ -1,4 +1,8 @@
-language: node_js
+language: cpp
+
+os:
+  - linux
+  - osx
 
 env:
   global:
@@ -7,39 +11,46 @@ env:
     # SAUCE_ACCESS_KEY
     - secure: sUvWUjCyPuWht4seNa4f2VG9DkvXkhZyLZfjJO9TUAHB2JndS16E2j/qrvKEjycyH6w8tU/B9vnjDRvvGrYXxEXcBEwsJVfkorFnRl9uwGCGIYrzjMhssEl3fMYZK7P304f+gAp5ULrDBX2gIaKeSa8lUNRtz2PsZOieE4kMdhk=
   matrix:
-    - TARGET=macro
-    - TARGET=neko
-    - TARGET=js
-    - TARGET=php
-    - TARGET=cpp
-    - TARGET=flash9
-    - TARGET=as3
-    - TARGET=java
-    - TARGET=cs
-    - TARGET=flash8
-    - TARGET=polygonal-ds
-    - TARGET=flambe
-    - TARGET=hxtemplo
-    - TARGET=munit
-    - TARGET=openfl-samples
+    - TEST=third-party
+    - TEST=macro
+    - TEST=neko
+    - TEST=js
+    - TEST=php
+    - TEST=cpp
+    - TEST=flash9
+    - TEST=as3
+    - TEST=java
+    - TEST=cs
+    - TEST=python
 
 matrix:
-  fast_finish: true
-  allow_failures:
-    - env: TARGET=flash8
+  # fast_finish: true #https://github.com/travis-ci/travis-ci/issues/1696
+
+before_script:
+  - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then mysql -u root -e "CREATE DATABASE haxe_test;"; fi
 
-before_install:
-  - travis_retry sudo apt-get update
-  - travis_retry sudo apt-get install ocaml zlib1g-dev libgc-dev -y
-  - travis_retry git clone https://github.com/HaxeFoundation/neko.git ~/neko
-  - cd ~/neko && make && sudo make install && cd $TRAVIS_BUILD_DIR
+install:
+  - if [ -z "${TRAVIS_OS_NAME}" ]; then export TRAVIS_OS_NAME=linux; fi; # for our forks that do not have mult-os enabled.
+  - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then travis_retry sudo apt-get update -qq; travis_retry sudo apt-get install ocaml zlib1g-dev libgc-dev -qq; fi
+  - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then travis_retry brew update; travis_retry brew install caskroom/cask/brew-cask; travis_retry brew install ocaml camlp4; fi
+  - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then travis_retry git clone https://github.com/HaxeFoundation/neko.git ~/neko && cd ~/neko && make os=${TRAVIS_OS_NAME} -s && sudo make install -s && cd $TRAVIS_BUILD_DIR; fi
+  - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then travis_retry brew install neko --HEAD; fi
 
 script:
-  - make
-  - make tools
-  - sudo make install
+  - make -s
+  - make tools -s
+  - sudo make install -s
   - cd tests/
   - mkdir ~/haxelib && haxelib setup ~/haxelib
   - haxelib git hx-yaml https://github.com/mikestead/hx-yaml master src
   - haxe -version
-  - haxe -main RunTravis -lib hx-yaml --interp
+  - haxe -neko RunCi.n -main RunCi -lib hx-yaml
+  - neko RunCi.n
+
+notifications:
+  webhooks:
+    urls:
+      - https://webhooks.gitter.im/e/95a5fa471c27beee8e7c
+    on_success: change  # options: [always|never|change] default: always
+    on_failure: always  # options: [always|never|change] default: always
+    on_start: false     # default: false

+ 11 - 0
CONTRIBUTING.md

@@ -0,0 +1,11 @@
+Things to check before/while filing an issue:
+
+- Reduce your code to a minimal example (see http://sscce.org/). In particular avoid library dependencies: If you cannot reproduce your issue without using a specific library, it might not be a Haxe issue to begin with.
+- Check if your problems are already resolved in the Haxe development version (for builds see http://builds.haxe.org/).
+- Most targets produce readable code. If you suspect the generated code to be wrong, try checking the output. Note that you can add `-D dump=pretty` to your compilation parameters and find the code which is passed to the generators in a `dump` sub directory.
+
+Other remarks:
+
+- Sometimes people try to be particularly helpful by not only including broken parts in their code, but also "similar" code which is working. More often than not this is more distracting than helpful. If you want to highlight something like this, consider adding the working code commented out.
+- We do not require a classic "What do you see/what do you expect?" form, but in some cases it is hard to figure out where you think the actual problem is otherwise.
+- We're keeping this page quite short so there's a higher chance that people actually read it.

+ 84 - 58
Makefile

@@ -2,7 +2,7 @@
 #
 #  - use 'make' to build all
 #  - use 'make haxe' to build only the compiler (not the libraries)
-#  - if you want to build quickly, install 'ocamlopt.opt' and change OCAMLOPT=ocamlopt.top
+#  - if you want to build quickly, install 'ocamlopt.opt' and change OCAMLOPT=ocamlopt.opt
 #
 #  Windows users :
 #  - use 'make -f Makefile.win' to build for Windows
@@ -18,31 +18,46 @@ OUTPUT=haxe
 EXTENSION=
 OCAMLOPT=ocamlopt
 OCAMLC=ocamlc
+LFLAGS=
 
 CFLAGS= -g -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
 
-CC_CMD = $(OCAMLOPT) $(CFLAGS) -c $<
-CC_PARSER_CMD = $(OCAMLOPT) -pp camlp4o $(CFLAGS) -c parser.ml
+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=unix.cmxa str.cmxa libs/extlib/extLib.cmxa libs/xml-light/xml-light.cmxa libs/swflib/swflib.cmxa \
-	libs/extc/extc.cmxa libs/neko/neko.cmxa libs/javalib/java.cmxa libs/ziplib/zip.cmxa \
-	libs/ttflib/ttf.cmxa libs/ilib/il.cmxa libs/objsize/objsize.cmxa
+NATIVE_LIBS=-cclib libs/extc/extc_stubs.o -cclib libs/extc/process_stubs.o -cclib -lz -cclib libs/objsize/c_objsize.o
 
-NATIVE_LIBS=-cclib libs/extc/extc_stubs.o -cclib -lz -cclib libs/objsize/c_objsize.o
+ifeq ($(BYTECODE),1)
+	TARGET_FLAG = bytecode
+	COMPILER = $(OCAMLC)
+	LIB_EXT = cma
+	MODULE_EXT = cmo
+	NATIVE_LIB_FLAG = -custom
+else
+	TARGET_FLAG = native
+	COMPILER = $(OCAMLOPT)
+	LIB_EXT = cmxa
+	MODULE_EXT = cmx
+endif
+
+CC_CMD = $(COMPILER) $(CFLAGS) -c $<
+
+CC_PARSER_CMD = $(COMPILER) -pp camlp4o $(CFLAGS) -c parser.ml
 
 RELDIR=../../..
 
 MODULES=ast type lexer common genxml parser typecore optimizer typeload \
-codegen gencommon genas3 gencpp genjs genneko genphp genswf8 \
-	genswf9 genswf genjava gencs interp dce filters typer matcher version main
+	codegen gencommon genas3 gencpp genjs genneko genphp genswf8 \
+	genswf9 genswf genjava gencs genpy interp dce analyzer filters typer matcher version main
 
 ADD_REVISION=0
 
 # using $(CURDIR) on Windows will not work since it might be a Cygwin path
 ifdef SYSTEMROOT
-EXTENSION=.exe
+	EXTENSION=.exe
 else
-export HAXE_STD_PATH=$(CURDIR)/std
+	export HAXE_STD_PATH=$(CURDIR)/std
 endif
 
 ifneq ($(ADD_REVISION),0)
@@ -53,24 +68,20 @@ endif
 
 all: libs haxe
 
-version.cmx:
-	echo $(VERSION_EXTRA) > version.ml
-	$(OCAMLOPT) $(CFLAGS) -c version.ml
-
 libs:
-	make -C libs/extlib opt OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/extc native OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/neko OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/javalib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/ilib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/ziplib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/swflib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/xml-light xml-light.cmxa OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/ttflib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-	make -C libs/objsize OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC)
-
-haxe: $(MODULES:=.cmx)
-	$(OCAMLOPT) -o $(OUTPUT) $(NATIVE_LIBS) $(LIBS) $(MODULES:=.cmx)
+	make -C libs/extlib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/extc OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/neko OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/javalib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/ilib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/ziplib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	make -C libs/swflib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG)
+	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)
+
+haxe: $(MODULES:=.$(MODULE_EXT))
+	$(COMPILER) -o $(OUTPUT) $(NATIVE_LIBS) $(NATIVE_LIB_FLAG) $(LFLAGS) $(LIBS:=.$(LIB_EXT)) $(MODULES:=.$(MODULE_EXT))
 
 haxelib:
 	(cd $(CURDIR)/extra/haxelib_src && $(CURDIR)/$(OUTPUT) haxelib.hxml && nekotools boot bin/haxelib.n)
@@ -103,61 +114,74 @@ install_tools: tools
 uninstall:
 	rm -rf $(INSTALL_BIN_DIR)/haxe $(INSTALL_BIN_DIR)/haxelib $(INSTALL_LIB_DIR)
 
-codegen.cmx: optimizer.cmx typeload.cmx typecore.cmx type.cmx genxml.cmx common.cmx ast.cmx
+# Modules
+
+analyzer.$(MODULE_EXT): ast.$(MODULE_EXT) type.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT)
 
-common.cmx: type.cmx ast.cmx
+codegen.$(MODULE_EXT): optimizer.$(MODULE_EXT) typeload.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) genxml.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-dce.cmx: ast.cmx common.cmx codegen.cmx type.cmx
+common.$(MODULE_EXT): type.$(MODULE_EXT) ast.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
 
-filters.cmx: ast.cmx common.cmx type.cmx dce.cmx codegen.cmx typecore.cmx
+dce.$(MODULE_EXT): ast.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) type.$(MODULE_EXT)
 
-genas3.cmx: type.cmx common.cmx codegen.cmx ast.cmx
+filters.$(MODULE_EXT): ast.$(MODULE_EXT) analyzer.$(MODULE_EXT) common.$(MODULE_EXT) type.$(MODULE_EXT) dce.$(MODULE_EXT) codegen.$(MODULE_EXT) typecore.$(MODULE_EXT)
 
-gencommon.cmx: type.cmx common.cmx codegen.cmx ast.cmx
+genas3.$(MODULE_EXT): type.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-gencpp.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+gencommon.$(MODULE_EXT): type.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
 
-gencs.cmx: type.cmx lexer.cmx gencommon.cmx common.cmx codegen.cmx ast.cmx
+gencpp.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) gencommon.$(MODULE_EXT)
 
-genjava.cmx: type.cmx gencommon.cmx common.cmx codegen.cmx ast.cmx
+gencs.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) gencommon.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
 
-genjs.cmx: type.cmx optimizer.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+genjava.$(MODULE_EXT): type.$(MODULE_EXT) gencommon.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genneko.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+genjs.$(MODULE_EXT): type.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genphp.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+genneko.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genswf.cmx: type.cmx genswf9.cmx genswf8.cmx common.cmx ast.cmx
+genphp.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genswf8.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx
+genpy.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genswf9.cmx: type.cmx lexer.cmx genswf8.cmx common.cmx codegen.cmx ast.cmx
+genswf.$(MODULE_EXT): type.$(MODULE_EXT) genswf9.$(MODULE_EXT) genswf8.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-genxml.cmx: type.cmx lexer.cmx common.cmx ast.cmx
+genswf8.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-interp.cmx: typecore.cmx type.cmx lexer.cmx genneko.cmx common.cmx codegen.cmx ast.cmx genswf.cmx genjava.cmx parser.cmx
+genswf9.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) genswf8.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-matcher.cmx: optimizer.cmx codegen.cmx typecore.cmx type.cmx typer.cmx common.cmx ast.cmx
+genxml.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-main.cmx: filters.cmx matcher.cmx typer.cmx typeload.cmx typecore.cmx type.cmx parser.cmx optimizer.cmx lexer.cmx interp.cmx genxml.cmx genswf.cmx genphp.cmx genneko.cmx genjs.cmx gencpp.cmx genas3.cmx common.cmx codegen.cmx ast.cmx gencommon.cmx genjava.cmx gencs.cmx version.cmx
+interp.$(MODULE_EXT): typecore.$(MODULE_EXT) type.$(MODULE_EXT) lexer.$(MODULE_EXT) genneko.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) genswf.$(MODULE_EXT) genjava.$(MODULE_EXT) gencs.$(MODULE_EXT) parser.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
 
-optimizer.cmx: typecore.cmx type.cmx parser.cmx common.cmx ast.cmx
+matcher.$(MODULE_EXT): optimizer.$(MODULE_EXT) codegen.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) typer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-parser.cmx: parser.ml lexer.cmx common.cmx ast.cmx
+main.$(MODULE_EXT): filters.$(MODULE_EXT) matcher.$(MODULE_EXT) typer.$(MODULE_EXT) typeload.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) interp.$(MODULE_EXT) genxml.$(MODULE_EXT) genswf.$(MODULE_EXT) genphp.$(MODULE_EXT) genneko.$(MODULE_EXT) genjs.$(MODULE_EXT) gencpp.$(MODULE_EXT) genas3.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) gencommon.$(MODULE_EXT) genjava.$(MODULE_EXT) gencs.$(MODULE_EXT) genpy.$(MODULE_EXT) version.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
+
+optimizer.$(MODULE_EXT): typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
+
+parser.$(MODULE_EXT): parser.ml lexer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 	$(CC_PARSER_CMD)
 
-type.cmx: ast.cmx
+type.$(MODULE_EXT): ast.$(MODULE_EXT)
+
+typecore.$(MODULE_EXT): type.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-typecore.cmx: type.cmx common.cmx ast.cmx
+typeload.$(MODULE_EXT): typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT)
 
-typeload.cmx: typecore.cmx type.cmx parser.cmx optimizer.cmx lexer.cmx common.cmx ast.cmx
+typer.$(MODULE_EXT): typeload.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) interp.$(MODULE_EXT) genneko.$(MODULE_EXT) genjs.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) filters.$(MODULE_EXT) gencommon.$(MODULE_EXT)
 
-typer.cmx: typeload.cmx typecore.cmx type.cmx parser.cmx optimizer.cmx lexer.cmx interp.cmx genneko.cmx genjs.cmx common.cmx codegen.cmx ast.cmx filters.cmx
+lexer.$(MODULE_EXT): lexer.ml
 
-lexer.cmx: lexer.ml
+lexer.$(MODULE_EXT): ast.$(MODULE_EXT)
 
-lexer.cmx: ast.cmx
+ast.$(MODULE_EXT):
 
+version.$(MODULE_EXT):
+	echo $(VERSION_EXTRA) > version.ml
+	$(COMPILER) $(CFLAGS) -c version.ml
+
+# Clean
 
 clean: clean_libs clean_haxe clean_tools
 
@@ -171,21 +195,23 @@ clean_libs:
 	make -C libs/swflib clean
 	make -C libs/xml-light clean
 	make -C libs/ttflib clean
+	make -C libs/objsize clean
 
 clean_haxe:
-	rm -f $(MODULES:=.obj) $(MODULES:=.o) $(MODULES:=.cmx) $(MODULES:=.cmi) lexer.ml $(OUTPUT)
+	rm -f $(MODULES:=.obj) $(MODULES:=.o) $(MODULES:=.cmx) $(MODULES:=.cmi) $(MODULES:=.cmo) lexer.ml $(OUTPUT)
 
 clean_tools:
 	rm -f $(OUTPUT) haxelib
 
 # SUFFIXES
+
 .ml.cmx:
 	$(CC_CMD)
 
-.mli.cmi:
+.ml.cmo:
 	$(CC_CMD)
 
 .mll.ml:
 	ocamllex $<
 
-.PHONY: haxe libs version.cmx haxelib
+.PHONY: haxe libs version.cmx version.cmo haxelib

+ 5 - 1
Makefile.win

@@ -17,10 +17,14 @@ kill:
 # allow Ocaml/Mingw as well
 NATIVE_LIBS += -I "c:/program files/mingw/lib/"
 
+ifdef WODI
+NATIVE_LIBS += -I "/opt/${WODI}/lib"
+endif
+
 # use make MSVC=1 -f Makefile.win to build for OCaml/MSVC
 
 ifeq (${MSVC}, 1)
-NATIVE_LIBS = shell32.lib libs/extc/extc_stubs.obj libs/extc/zlib/zlib.lib libs/objsize/c_objsize.obj
+NATIVE_LIBS = shell32.lib libs/extc/extc_stubs.obj libs/extc/process_stubs.obj libs/extc/zlib/zlib.lib libs/objsize/c_objsize.obj
 endif
 
 ifeq (${MSVC_OUTPUT}, 1)

+ 21 - 11
README.md

@@ -1,7 +1,9 @@
-![Haxe logo](http://haxe.org/img/haxe2/logo.png)
-# [Haxe - The Cross-Platform Toolkit](http://haxe.org)
 
-[![Build Status](https://travis-ci.org/HaxeFoundation/haxe.png?branch=development)](https://travis-ci.org/HaxeFoundation/haxe)
+# [<img src="http://haxe.org/img/haxe-logo-horizontal.svg" alt="Haxe logo" width="140">](http://haxe.org) - [The Cross-Platform Toolkit](http://haxe.org)
+[![TravisCI Build Status](https://travis-ci.org/HaxeFoundation/haxe.svg?branch=development)](https://travis-ci.org/HaxeFoundation/haxe)
+[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/HaxeFoundation/haxe?branch=development&svg=true)](https://ci.appveyor.com/project/Simn/haxe)
+[![SauceLabs Test Status](https://saucelabs.com/buildstatus/haxe)](https://saucelabs.com/u/haxe)
+[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/HaxeFoundation/haxe?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
 
 Haxe is an open source toolkit that allows you to easily build cross-platform tools and applications that target many mainstream platforms. The Haxe toolkit includes:
 
@@ -31,7 +33,7 @@ The Haxe project has several licenses, covering different parts of the projects.
  * The Haxe libraries are released under a "two-clause" BSD license.
  * The Neko runtime is licensed under the GNU Lesser General Public License version 2.1 or any later version.
 
-For the complete Haxe licenses, please see http://haxe.org/doc/license or [extra/LICENSE.txt](extra/LICENSE.txt).
+For the complete Haxe licenses, please see http://haxe.org/foundation/open-source.html or [extra/LICENSE.txt](extra/LICENSE.txt).
 
 ## Installing Haxe
 
@@ -53,20 +55,28 @@ Automated development builds are available from [build.haxe.org](http://build.ha
         git clone --recursive git://github.com/HaxeFoundation/haxe.git
         cd haxe
 
- 2. Follow the [documentation on building Haxe for your platform](http://haxe.org/doc/build).
+ 2. Follow the [documentation on building Haxe for your platform](http://haxe.org/documentation/introduction/building-haxe.html).
 
 ## Using Haxe
 
-For information on on using Haxe, consult the [Haxe documentation](http://haxe.org/doc):
+For information on on using Haxe, consult the [Haxe documentation](http://haxe.org/documentation):
 
- * [Haxe introduction](http://haxe.org/doc/intro), an introduction to the Haxe toolkit
- * [Haxe language reference](http://haxe.org/ref), an overview of the Haxe programming language
- * [Haxe API](http://api.haxe.org/), a reference for the Haxe standard and native APIs
- * [Haxelib](http://lib.haxe.org/), a repository of Haxe libraries for a variety of needs
+ * [Haxe Introduction](http://haxe.org/documentation/introduction), an introduction to the Haxe toolkit
+ * [The Haxe Manual](http://haxe.org/manual), the reference manual for the Haxe language
+ * [Haxe API](http://api.haxe.org), documentation for the Haxe standard and native APIs
+ * [Haxelib](http://lib.haxe.org), a repository of Haxe libraries for a variety of needs
 
 ## Community
 
 You can get help and talk with fellow Haxers from around the world via:
 
  * the [official Haxe Google Group](https://groups.google.com/forum/#!forum/haxelang)
- * the [Haxe IRC chatroom](http://unic0rn.github.io/tiramisu/haxe/), #haxe on chat.freenode.net
+ * the [Haxe IRC chatroom](http://unic0rn.github.io/tiramisu/haxe), #haxe on chat.freenode.net
+
+## Version compatibility
+
+Haxe   | neko
+----   | -----
+2.*    | 1.*
+3.0.0  | 2.0.0
+3.1.3  | 2.0.0

+ 1666 - 0
analyzer.ml

@@ -0,0 +1,1666 @@
+open Ast
+open Type
+open Common
+open Typecore
+
+let s_expr = s_expr (s_type (print_context()))
+let s_expr_pretty = s_expr_pretty "" (s_type (print_context()))
+let debug e = print_endline (s_expr e)
+let debug_pretty s e = Printf.printf "%s %s\n" s (s_expr_pretty e)
+
+let flag_no_check = "no_check"
+let flag_check = "check"
+let flag_no_const_propagation = "no_const_propagation"
+let flag_const_propagation = "const_propagation"
+let flag_no_local_dce = "no_local_dce"
+let flag_local_dce = "local_dce"
+let flag_ignore = "ignore"
+let flag_no_simplification = "no_simplification"
+let flag_check_has_effect = "check_has_effect"
+let flag_no_check_has_effect = "no_check_has_effect"
+
+let has_analyzer_option meta s =
+	try
+		let rec loop ml = match ml with
+			| (Meta.Analyzer,el,_) :: ml ->
+				if List.exists (fun (e,p) ->
+					match e with
+						| EConst(Ident s2) when s = s2 -> true
+						| _ -> false
+				) el then
+					true
+				else
+					loop ml
+			| _ :: ml ->
+				loop ml
+			| [] ->
+				false
+		in
+		loop meta
+	with Not_found ->
+		false
+
+let is_ignored meta =
+	try
+		let rec loop ml = match ml with
+			| (Meta.Analyzer,el,_) :: ml ->
+				if List.exists (fun (e,p) ->
+					match e with
+						| EConst(Ident s2) when flag_ignore = s2 -> true
+						| _ -> false
+				) el then
+					true
+				else
+					loop ml
+			| (Meta.HasUntyped,_,_) :: _ ->
+				true
+			| _ :: ml ->
+				loop ml
+			| [] ->
+				false
+		in
+		loop meta
+	with Not_found ->
+		false
+
+let rec get_type_meta t = match t with
+	| TMono r ->
+		begin match !r with
+			| None -> raise Not_found
+			| Some t -> get_type_meta t
+		end
+	| TLazy f ->
+		get_type_meta (!f())
+	| TInst(c,_) ->
+		c.cl_meta
+	| TEnum(en,_) ->
+		en.e_meta
+	| TAbstract(a,_) ->
+		a.a_meta
+	| TType(t,_) ->
+		t.t_meta
+	| TAnon _ | TFun _ | TDynamic _ ->
+		raise Not_found
+
+let type_has_analyzer_option t s =
+	try
+		has_analyzer_option (get_type_meta t) s
+	with Not_found ->
+		false
+
+let is_enum_type t = match follow t with
+	| TEnum(_) -> true
+	| _ -> false
+
+let rec awkward_get_enum_index com e = match e.eexpr with
+	| TArray(e1,{eexpr = TConst(TInt i)}) when com.platform = Js && Int32.to_int i = 1 && is_enum_type e1.etype ->
+		e1
+	| TCall({eexpr = TField(e1, FDynamic "__Index")},[]) when com.platform = Cpp && is_enum_type e1.etype ->
+		e1
+	| TField(e1,FDynamic "index") when com.platform = Neko && is_enum_type e1.etype ->
+		e1
+	| TParenthesis e1 | TCast(e1,None) | TMeta(_,e1) ->
+		awkward_get_enum_index com e1
+	| _ ->
+		raise Not_found
+
+(*
+	This module simplifies the AST by introducing temporary variables for complex expressions in many places.
+	In particular, it ensures that no branching can occur in value-places so that we can later insert SSA PHI
+	nodes without worrying about their placement.
+*)
+module Simplifier = struct
+	let mk_block_context com =
+		let block_el = ref [] in
+		let push e = block_el := e :: !block_el in
+		let assign ev e =
+			let mk_assign e2 = match e2.eexpr with
+				| TBreak | TContinue | TThrow _ | TReturn _ -> e2
+				| _ -> mk (TBinop(OpAssign,ev,e2)) e2.etype e2.epos
+			in
+			let rec loop e = match e.eexpr with
+				| TBlock el ->
+					begin match List.rev el with
+						| e1 :: el ->
+							let el = List.rev ((loop e1) :: el) in
+							{e with eexpr = TBlock el}
+						| _ ->
+							mk_assign e
+					end
+				| TIf(e1,e2,eo) ->
+					let e2 = loop e2 in
+					let eo = match eo with None -> None | Some e3 -> Some (loop e3) in
+					{e with eexpr = TIf(e1,e2,eo)}
+				| TSwitch(e1,cases,edef) ->
+					let cases = List.map (fun (el,e) ->
+						let e = loop e in
+						el,e
+					) cases in
+					let edef = match edef with None -> None | Some edef -> Some (loop edef) in
+					{e with eexpr = TSwitch(e1,cases,edef)}
+				| TTry(e1,catches) ->
+					let e1 = loop e1 in
+					let catches = List.map (fun (v,e) ->
+						let e = loop e in
+						v,e
+					) catches in
+					{e with eexpr = TTry(e1,catches)}
+				| TParenthesis e1 | TMeta(_,e1) ->
+					loop e1 (* this is still weird, have to review *)
+(* 				| TBinop(OpAssign,({eexpr = TLocal _} as e1),e2) ->
+					push e;
+					mk_assign e1 *)
+(* 				| TBinop(OpAssignOp op,({eexpr = TLocal _} as e1),e2) ->
+					push e;
+					mk_assign e1 *)
+				| _ ->
+					mk_assign e
+			in
+			loop e
+		in
+		let declare_temp t eo p =
+			let v = alloc_var "tmp" t in
+			v.v_meta <- [Meta.CompilerGenerated,[],p];
+			let e_v = mk (TLocal v) t p in
+			let declare e_init =
+				let e = mk (TVar (v,e_init)) com.basic.tvoid p in
+				push e;
+			in
+			let e_v = match eo with
+				| None ->
+					declare None;
+					e_v
+				| Some e1 ->
+					begin match e1.eexpr with
+						| TThrow _ | TReturn _ | TBreak | TContinue ->
+							e1
+						| _ ->
+							let rec loop e_v e = match e.eexpr with
+								| TParenthesis e1 ->
+									loop {e_v with eexpr = TParenthesis e_v} e1
+								| TMeta(m,e1) ->
+									loop {e_v with eexpr = TMeta(m,e_v)} e1
+								| _ ->
+									e_v,e
+							in
+							let e_v',e1 = loop e_v e1 in
+							let e1 = assign e_v e1 in
+							begin match e1.eexpr with
+								| TBinop(OpAssign,{eexpr = TLocal v1},e2) when v == v1 ->
+									declare (Some e2)
+								| _ ->
+									declare None;
+									push e1
+							end;
+							e_v'
+					end
+			in
+			e_v
+		in
+		let rec push_block () =
+			let cur = !block_el in
+			block_el := [];
+			fun () ->
+				let added = !block_el in
+				block_el := cur;
+				List.rev added
+		and block f el =
+			let close = push_block() in
+			List.iter (fun e ->
+				push (f e)
+			) el;
+			close()
+		in
+		block,declare_temp,fun () -> !block_el
+
+	let apply com e =
+		let block,declare_temp,close_block = mk_block_context com in
+		let skip_binding ?(allow_tlocal=false) e =
+			let rec loop e =
+				match e.eexpr with
+				| TConst _ | TTypeExpr _ | TFunction _ -> ()
+				| TLocal _ when allow_tlocal -> ()
+				| TParenthesis e1 | TCast(e1,None) -> Type.iter loop e
+				| TField(_,(FStatic(c,cf) | FInstance(c,_,cf))) when has_analyzer_option cf.cf_meta flag_no_simplification || has_analyzer_option c.cl_meta flag_no_simplification -> ()
+				| TField({eexpr = TLocal _},_) when allow_tlocal -> ()
+				| TCall({eexpr = TField(_,(FStatic(c,cf) | FInstance(c,_,cf)))},el) when has_analyzer_option cf.cf_meta flag_no_simplification || has_analyzer_option c.cl_meta flag_no_simplification -> ()
+				| TCall({eexpr =  TLocal { v_name = "__cpp__" } },_) -> ()
+				| TField(_,FEnum _) -> ()
+				| TField(_,FDynamic _) -> ()
+				| _ when (try ignore(awkward_get_enum_index com e); true with Not_found -> false) -> ()
+				| _ -> raise Exit
+			in
+			try
+				loop e;
+				true
+			with Exit ->
+				begin match follow e.etype with
+					| TAbstract({a_path = [],"Void"},_) -> true
+					| _ -> false
+				end
+		in
+		let has_unbound = ref false in
+		let rec loop e = match e.eexpr with
+			| TCall({eexpr = TLocal v | TField({eexpr = TLocal v},_)},_) | TField({eexpr = TLocal v},_) | TLocal v when Meta.has Meta.Unbound v.v_meta && v.v_name <> "`trace" ->
+				has_unbound := true;
+				e
+			| TBlock el ->
+				{e with eexpr = TBlock (block loop el)}
+			| TCall({eexpr = TField(_,(FStatic(c,cf) | FInstance(c,_,cf)))},el) when has_analyzer_option cf.cf_meta flag_no_simplification || has_analyzer_option c.cl_meta flag_no_simplification ->
+				e
+			| TField(_,(FStatic(c,cf) | FInstance(c,_,cf))) when has_analyzer_option cf.cf_meta flag_no_simplification || has_analyzer_option c.cl_meta flag_no_simplification ->
+				e
+			| TCall(e1,el) ->
+				let rec is_valid_call_target e = match e.eexpr with
+					| TFunction _ | TField _ | TLocal _ | TConst (TSuper)  ->
+						true
+					| TParenthesis e1 | TCast(e1,None) | TMeta(_,e1) ->
+						is_valid_call_target e1
+					| _ ->
+						false
+				in
+				let e1 = if is_valid_call_target e1 then
+					loop e1
+				else
+					bind e1
+				in
+				let check e t =
+					if type_has_analyzer_option t flag_no_simplification then e
+					else bind e
+				in
+				let el = match e1.eexpr,follow e1.etype with
+					| TConst TSuper,_ when com.platform = Java || com.platform = Cs ->
+						(* they hate you if you mess up the super call *)
+						el
+					| _,TFun _ | TConst TSuper,_ ->
+						Codegen.UnificationCallback.check_call check el e1.etype
+					| _ ->
+						(* too dangerous *)
+						List.map loop el
+				in
+				{e with eexpr = TCall(e1,el)}
+			| TNew(c,tl,el) ->
+				{e with eexpr = TNew(c,tl,ordered_list el)}
+			| TArrayDecl el ->
+				{e with eexpr = TArrayDecl (ordered_list el)}
+			| TObjectDecl fl ->
+				let el = ordered_list (List.map snd fl) in
+				{e with eexpr = TObjectDecl (List.map2 (fun (n,_) e -> n,e) fl el)}
+			| TBinop(OpBoolAnd | OpBoolOr as op,e1,e2) ->
+				let e1 = loop e1 in
+				let e_then = mk (TBlock (block loop [e2])) e2.etype e2.epos in
+				let e_if,e_else = if op = OpBoolOr then
+					mk (TUnop(Not,Prefix,e1)) com.basic.tbool e.epos,mk (TConst (TBool(true))) com.basic.tbool e.epos
+				else
+					e1,mk (TConst (TBool(false))) com.basic.tbool e.epos
+				in
+				loop (mk (TIf(e_if,e_then,Some e_else)) com.basic.tbool e.epos)
+			| TBinop((OpAssign | OpAssignOp _) as op,{eexpr = TArray(e11,e12)},e2) ->
+				let e1 = match ordered_list [e11;e12] with
+					| [e1;e2] ->
+						{e with eexpr = TArray(e1,e2)}
+					| _ ->
+						assert false
+				in
+				let e2 = bind e2 in
+				{e with eexpr = TBinop(op,e1,e2)}
+			| TBinop((OpAssign | OpAssignOp _) as op,e1,e2) ->
+				let e2 = bind ~allow_tlocal:true e2 in
+				let e1 = loop e1 in
+				{e with eexpr = TBinop(op,e1,e2)}
+			| TBinop(op,e1,e2) ->
+				begin match ordered_list [e1;e2] with
+					| [e1;e2] ->
+						{e with eexpr = TBinop(op,e1,e2)}
+					| _ ->
+						assert false
+				end
+			| TArray(e1,e2) ->
+				begin match ordered_list [e1;e2] with
+					| [e1;e2] ->
+						{e with eexpr = TArray(e1,e2)}
+					| _ ->
+						assert false
+				end
+			| TWhile(e1,e2,flag) when (match e1.eexpr with TConst(TBool true) | TParenthesis {eexpr = TConst(TBool true)} -> false | _ -> true) ->
+				let p = e.epos in
+				let e_break = mk TBreak t_dynamic p in
+				let e_not = mk (TUnop(Not,Prefix,Codegen.mk_parent e1)) e1.etype e1.epos in
+				let e_if eo = mk (TIf(e_not,e_break,eo)) com.basic.tvoid p in
+				let rec map_continue e = match e.eexpr with
+					| TContinue ->
+						(e_if (Some e))
+					| TWhile _ | TFor _ ->
+						e
+					| _ ->
+						Type.map_expr map_continue e
+				in
+				let e2 = if flag = NormalWhile then e2 else map_continue e2 in
+				let e_if = e_if None in
+				let e_if = mk (TMeta((Meta.Custom ":whileCond",[],e_if.epos), e_if)) e_if.etype e_if.epos in
+				let e_block = if flag = NormalWhile then Type.concat e_if e2 else Type.concat e2 e_if in
+				let e_true = mk (TConst (TBool true)) com.basic.tbool p in
+				let e = mk (TWhile(Codegen.mk_parent e_true,e_block,NormalWhile)) e.etype p in
+				loop e
+			| TFor(v,e1,e2) ->
+				let e1 = bind e1 in
+				let e2 = loop e2 in
+				{e with eexpr = TFor(v,e1,e2)}
+			| TIf(e1,e2,eo) ->
+				let e1 = bind e1 in
+				let e2 = loop e2 in
+				let eo = match eo with None -> None | Some e -> Some (loop e) in
+				{e with eexpr = TIf(e1,e2,eo)}
+			| TSwitch (e1,cases,eo) ->
+				let e1 = bind e1 in
+				let cases = List.map (fun (el,e) ->
+					let el = List.map loop el in
+					let e = loop e in
+					el,e
+				) cases in
+				let eo = match eo with None -> None | Some e -> Some (loop e) in
+				{e with eexpr = TSwitch(e1,cases,eo)}
+			| TVar(v,Some e1) ->
+				let e1 = match e1.eexpr with
+					| TFunction _ -> loop e1
+					| TArrayDecl [{eexpr = TFunction _}] -> loop e1
+					| _ -> bind ~allow_tlocal:true e1
+				in
+				{e with eexpr = TVar(v,Some e1)}
+			| TUnop((Neg | NegBits | Not) as op,flag,e1) ->
+				let e1 = bind e1 in
+				{e with eexpr = TUnop(op,flag,e1)}
+			| TField(e1,fa) ->
+				let e1 = bind ~allow_tlocal:true e1 in
+				{e with eexpr = TField(e1,fa)}
+			| TReturn (Some ({eexpr = TThrow _ | TReturn _} as e1)) ->
+				loop e1 (* this is a bit hackish *)
+			| TReturn (Some e1) ->
+				let e1 = bind e1 in
+				{e with eexpr = TReturn (Some e1)}
+			| TThrow e1 ->
+				let e1 = bind e1 in
+				{e with eexpr = TThrow e1}
+			| TCast(e1,mto) ->
+				let e1 = bind ~allow_tlocal:true e1 in
+				{e with eexpr = TCast(e1,mto)}
+			| _ ->
+				Type.map_expr loop e
+		and bind ?(allow_tlocal=false) e =
+			let e = loop e in
+			if skip_binding ~allow_tlocal e then
+				e
+			else
+				declare_temp e.etype (Some e) e.epos
+		and ordered_list el =
+			if List.for_all (skip_binding ~allow_tlocal:true) el then
+				List.map loop el
+			else
+				List.map bind el
+		in
+		let e = loop e in
+		!has_unbound,match close_block() with
+			| [] ->
+				e
+			| el ->
+				mk (TBlock (List.rev (e :: el))) e.etype e.epos
+
+	let unapply com e =
+		let var_map = ref IntMap.empty in
+		let rec get_assignment_to v e = match e.eexpr with
+			| TBinop(OpAssign,{eexpr = TLocal v2},e2) when v == v2 -> Some e2
+			| TBlock [e] -> get_assignment_to v e
+			| TIf(e1,e2,Some e3) ->
+				begin match get_assignment_to v e2,get_assignment_to v e3 with
+				| Some e2,Some e3 -> Some ({e with eexpr = TIf(e1,e2,Some e3)})
+				| _ -> None
+				end
+			| _ -> None
+		in
+		let if_or_op e e1 e2 e3 = match e1.eexpr,e3.eexpr with
+			| TUnop(Not,Prefix,e1),TConst (TBool true) -> {e with eexpr = TBinop(OpBoolOr,e1,e2)}
+			| _,TConst (TBool false) -> {e with eexpr = TBinop(OpBoolAnd,e1,e2)}
+			| _ -> {e with eexpr = TIf(e1,e2,Some e3)}
+		in
+		let rec loop e = match e.eexpr with
+			| TBlock el ->
+				let rec loop2 el = match el with
+					| e :: el ->
+						begin match e.eexpr with
+							| TVar(v,Some e1) when Meta.has Meta.CompilerGenerated v.v_meta ->
+								if el = [] then
+									[loop e1]
+								else begin
+									var_map := IntMap.add v.v_id (loop e1) !var_map;
+									loop2 el
+								end
+							| TVar(v,None) when not (com.platform = Php) ->
+								begin match el with
+									| {eexpr = TBinop(OpAssign,{eexpr = TLocal v2},e2)} :: el when v == v2 ->
+										let e = {e with eexpr = TVar(v,Some e2)} in
+										loop2 (e :: el)
+									| ({eexpr = TIf(e1,e2,Some e3)} as e_if) :: el ->
+										let e1 = loop e1 in
+										let e2 = loop e2 in
+										let e3 = loop e3 in
+										begin match get_assignment_to v e2,get_assignment_to v e3 with
+											| Some e2,Some e3 ->
+												let e_if = if_or_op e_if (loop e1) (loop e2) (loop e3) in
+												let e = {e with eexpr = TVar(v,Some e_if)} in
+												loop2 (e :: el)
+											| _ ->
+												let e_if = {e_if with eexpr = TIf(e1,e2,Some e3)} in
+												e :: e_if :: loop2 el
+										end
+									| _ ->
+										let e = loop e in
+										e :: loop2 el
+								end
+							| TReturn (Some e1) when (match follow e1.etype with TAbstract({a_path=[],"Void"},_) -> true | _ -> false) ->
+								[(loop e1);{e with eexpr = TReturn None}]
+							| _ ->
+								let e = loop e in
+								e :: loop2 el
+						end
+					| [] ->
+						[]
+				in
+				let el = loop2 el in
+				{e with eexpr = TBlock el}
+			| TLocal v when Meta.has Meta.CompilerGenerated v.v_meta ->
+				begin try IntMap.find v.v_id !var_map
+				with Not_found -> e end
+			| TWhile(e1,e2,flag) ->
+				let e1 = loop e1 in
+				let e2 = loop e2 in
+				let extract_cond e = match e.eexpr with
+					| TIf({eexpr = TUnop(Not,_,e1)},_,_) -> e1
+					| TBreak -> raise Exit (* can happen due to optimization, not so easy to deal with because there might be other breaks/continues *)
+					| _ -> assert false
+				in
+				let e1,e2,flag = try
+					begin match e2.eexpr with
+						| TBlock el ->
+							begin match el with
+								| {eexpr = TMeta((Meta.Custom ":whileCond",_,_),e1)} :: el ->
+									let e1 = extract_cond e1 in
+									e1,{e2 with eexpr = TBlock el},NormalWhile
+								| _ ->
+									e1,e2,flag
+									(* issue 3844 *)
+(* 									begin match List.rev el with
+										| {eexpr = TMeta((Meta.Custom ":whileCond",_,_),e1)} :: el ->
+											let e1 = extract_cond e1 in
+											e1,{e2 with eexpr = TBlock (List.rev el)},DoWhile
+										| _ ->
+											e1,e2,flag
+									end *)
+							end
+						| _ ->
+							e1,e2,flag
+					end with Exit ->
+						e1,e2,flag
+				in
+				{e with eexpr = TWhile(e1,e2,flag)}
+			| TIf(e1,e2,Some e3) ->
+				let e1 = loop e1 in
+				let e2 = loop e2 in
+				let e3 = loop e3 in
+				if_or_op e e1 e2 e3
+			| _ ->
+				Type.map_expr loop e
+		in
+		loop e
+end
+
+module Ssa = struct
+
+	type var_map = tvar IntMap.t
+
+	type condition =
+		| Equal of tvar * texpr
+		| NotEqual of tvar * texpr
+
+	type node_data = {
+		nd_pos: pos;
+		mutable nd_var_map : var_map;
+		mutable nd_terminates : bool;
+	}
+
+	type join_node = {
+		mutable branches : node_data list;
+	}
+
+	type ssa_context = {
+		com : Common.context;
+		mutable cleanup : (unit -> unit) list;
+		mutable cur_data : node_data;
+		mutable var_conds : (condition list) IntMap.t;
+		mutable loop_stack : (join_node * join_node) list;
+		mutable exception_stack : join_node list;
+		mutable block_depth : int;
+	}
+
+	let s_cond = function
+		| Equal(v,e) -> Printf.sprintf "%s == %s" v.v_name (s_expr_pretty e)
+		| NotEqual(v,e) -> Printf.sprintf "%s != %s" v.v_name (s_expr_pretty e)
+
+	let s_conds conds =
+		String.concat " && " (List.map s_cond conds)
+
+	let mk_loc v p = mk (TLocal v) v.v_type p
+
+	let mk_phi =
+		let v_phi = alloc_var "__ssa_phi__" t_dynamic in
+		(fun vl p ->
+			let e = mk (TCall(mk_loc v_phi p,(List.map (fun (v,p) -> mk_loc v p) vl))) t_dynamic p in
+			e
+		)
+
+	(* TODO: make sure this is conservative *)
+	let can_throw e =
+		let rec loop e = match e.eexpr with
+			| TConst _ | TLocal _ | TTypeExpr _ | TFunction _ | TBlock _ -> ()
+			| TCall _ | TNew _ | TThrow _ | TCast(_,Some _) -> raise Exit
+			| _ -> Type.iter loop e
+		in
+		try
+			loop e; false
+		with Exit ->
+			true
+
+	let mk_join_node() = {
+		branches = []
+	}
+
+	let mk_node_data p = {
+		nd_pos = p;
+		nd_var_map = IntMap.empty;
+		nd_terminates = false;
+	}
+
+	let add_branch join branch p =
+		join.branches <- {branch with nd_pos = p} :: join.branches
+
+	let branch ctx p =
+		let old_map = ctx.cur_data.nd_var_map in
+		let old_term = ctx.cur_data.nd_terminates in
+		ctx.cur_data.nd_terminates <- false;
+		(fun join ->
+			add_branch join ctx.cur_data p;
+			ctx.cur_data.nd_var_map <- old_map;
+			ctx.cur_data.nd_terminates <- old_term;
+		)
+
+	let terminate ctx =
+		ctx.cur_data.nd_terminates <- true
+
+	let set_loop_join ctx join_top join_bottom =
+		ctx.loop_stack <- (join_top,join_bottom) :: ctx.loop_stack;
+		(fun () ->
+			ctx.loop_stack <- List.tl ctx.loop_stack
+		)
+
+	let set_exception_join ctx join =
+		ctx.exception_stack <- join :: ctx.exception_stack;
+		(fun () ->
+			ctx.exception_stack <- List.tl ctx.exception_stack;
+		)
+
+	let create_v_extra v =
+		match v.v_extra with
+		| Some (_,Some _) ->
+			()
+		| Some (tl,None) ->
+			let e_extra = mk (TObjectDecl []) t_dynamic null_pos in
+			v.v_extra <- Some (tl,Some e_extra)
+		| None ->
+			let e_extra = mk (TObjectDecl []) t_dynamic null_pos in
+			v.v_extra <- Some ([],Some e_extra)
+
+	let set_v_extra_value v s e = match v.v_extra with
+		| Some (tl, Some {eexpr = TObjectDecl fl}) ->
+			let rec loop fl = match fl with
+				| (s',_) :: fl when s' = s ->
+					(s,e) :: fl
+				| f1 :: fl ->
+					f1 :: loop fl
+				| [] ->
+					[s,e]
+			in
+			let e_extra = mk (TObjectDecl (loop fl)) t_dynamic null_pos in
+			v.v_extra <- Some (tl, Some e_extra)
+		| _ ->
+			assert false
+
+	let get_origin_var v = match v.v_extra with
+		| Some (_,Some {eexpr = TObjectDecl fl}) ->
+			begin match List.assoc "origin_var" fl with
+				| {eexpr = TLocal v'} -> v'
+				| _ -> raise Not_found
+			end
+		| _ ->
+			raise Not_found
+
+	let set_origin_var v v_origin p =
+		let ev = mk_loc v_origin p in
+		set_v_extra_value v "origin_var" ev
+
+	let get_var_value v = match v.v_extra with
+		| Some (_,Some {eexpr = TObjectDecl fl}) ->
+			List.assoc "var_value" fl
+		| _ ->
+			raise Not_found
+
+	let set_var_value v e =
+		set_v_extra_value v "var_value" e
+
+	let get_var_usage_count v = match v.v_extra with
+		| Some (_,Some {eexpr = TObjectDecl fl}) ->
+			begin try
+				begin match List.assoc "usage_count" fl with
+				| {eexpr = TConst (TInt i32)} -> Int32.to_int i32
+				| _ -> 0
+				end
+			with Not_found ->
+				0
+			end
+		| _ ->
+			raise Not_found
+
+	let set_var_usage_count v i =
+		let e = mk (TConst (TInt (Int32.of_int i))) t_dynamic null_pos in
+		set_v_extra_value v "usage_count" e
+
+	let declare_var ctx v p =
+		let old = v.v_extra in
+		ctx.cleanup <- (fun () ->
+			v.v_extra <- old
+		) :: ctx.cleanup;
+		ctx.cur_data.nd_var_map <- IntMap.add v.v_id v ctx.cur_data.nd_var_map;
+		v.v_meta <- ((Meta.Custom ":blockDepth",[EConst (Int (string_of_int ctx.block_depth)),p],p)) :: v.v_meta;
+		v.v_extra <- None;
+		create_v_extra v;
+		set_origin_var v v p
+
+	let assign_var ctx v e p =
+		if v.v_capture then
+			v
+		else begin
+			let i = match v.v_extra with
+				| Some (l,eo) ->
+					v.v_extra <- Some (("",t_dynamic) :: l,eo);
+					List.length l + 1
+				| _ ->
+					error "Something went wrong" p
+			in
+			let v' = alloc_var (Printf.sprintf "%s<%i>" v.v_name i) v.v_type in
+			create_v_extra v';
+			v'.v_meta <- [(Meta.Custom ":ssa"),[],p];
+			set_origin_var v' v p;
+			ctx.cur_data.nd_var_map <- IntMap.add v.v_id v' ctx.cur_data.nd_var_map;
+			set_var_value v' e;
+			v'
+		end
+
+	let get_var ctx v p =
+		try
+			IntMap.find v.v_id ctx.cur_data.nd_var_map
+		with Not_found ->
+			if not (has_meta Meta.Unbound v.v_meta) then
+				error (Printf.sprintf "Unbound variable %s" v.v_name) p;
+			v
+
+	let close_join_node ctx node p =
+		let terminates = ref true in
+		let branches = List.filter (fun branch ->
+			if branch.nd_terminates then false
+			else begin
+				terminates := false;
+				true
+			end
+		) node.branches in
+		match branches with
+			| [] ->
+				()
+			| branch :: branches ->
+				let vars = ref (IntMap.map (fun v -> [v,branch.nd_pos]) branch.nd_var_map) in
+				let rec handle_branch branch =
+					IntMap.iter (fun i v ->
+						try
+							let vl = IntMap.find i !vars in
+							if not (List.exists (fun (v',_) -> v == v') vl) then
+								vars := IntMap.add i ((v,p) :: vl) !vars
+						with Not_found ->
+							()
+					) branch.nd_var_map;
+				in
+				List.iter handle_branch branches;
+				ctx.cur_data.nd_terminates <- !terminates;
+				IntMap.iter (fun i vl -> match vl with
+					| [v,p] ->
+						ctx.cur_data.nd_var_map <- IntMap.add i v ctx.cur_data.nd_var_map;
+					| (v',_) :: _ ->
+						let v = get_origin_var v' in
+						ignore(assign_var ctx v (mk_phi vl p) p)
+					| _ ->
+						assert false
+				) !vars
+
+	let invert_cond = function
+		| Equal(v,e) -> NotEqual(v,e)
+		| NotEqual(v,e) -> Equal(v,e)
+
+	let invert_conds =
+		List.map invert_cond
+
+	let rec eval_cond ctx e = match e.eexpr with
+		| TBinop(OpNotEq,{eexpr = TLocal v},e1) ->
+			[NotEqual(v,e1)]
+		| TBinop(OpEq,{eexpr = TLocal v},e1) ->
+			[Equal(v,e1)]
+		| TUnop(Not,_,e1) ->
+			invert_conds (eval_cond ctx e1)
+		| TLocal v ->
+			begin try eval_cond ctx (get_var_value v)
+			with Not_found -> [] end
+		| _ ->
+			[]
+
+	let append_cond ctx v cond p =
+		begin try
+			let conds = IntMap.find v.v_id ctx.var_conds in
+			ctx.var_conds <- IntMap.add v.v_id (cond :: conds) ctx.var_conds
+		with Not_found ->
+			ctx.var_conds <- IntMap.add v.v_id [cond] ctx.var_conds
+		end
+
+(* 	let apply_cond ctx = function
+		| Equal({v_extra = Some(_,Some {eexpr = TLocal v})} as v0,e1) ->
+			let v' = assign_var ctx v (mk_loc v0 e1.epos) e1.epos in
+			append_cond ctx v' (Equal(v',e1)) e1.epos
+		| NotEqual({v_extra = Some(_,Some {eexpr = TLocal v})} as v0,e1) ->
+			let v' = assign_var ctx v (mk_loc v0 e1.epos) e1.epos in
+			append_cond ctx v' (NotEqual(v',e1)) e1.epos
+		| _ -> ()
+
+	let apply_not_null_cond ctx v p =
+		apply_cond ctx (NotEqual(v,(mk (TConst TNull) t_dynamic p))) *)
+
+	let apply com e =
+		let rec handle_if ctx f econd eif eelse =
+			let econd = loop ctx econd in
+			(* let cond = eval_cond ctx econd in *)
+			let join = mk_join_node() in
+			let close = branch ctx eif.epos in
+			(* List.iter (apply_cond ctx) cond; *)
+			let eif = loop ctx eif in
+			close join;
+			let eelse = match eelse with
+				| None ->
+					(* let cond = invert_conds cond in *)
+					(* List.iter (apply_cond ctx) cond; *)
+					add_branch join ctx.cur_data e.epos;
+					None
+				| Some e ->
+					let close = branch ctx e.epos in
+					(* let cond = invert_conds cond in *)
+					(* List.iter (apply_cond ctx) cond; *)
+					let eelse = loop ctx e in
+					close join;
+					Some eelse
+			in
+			close_join_node ctx join e.epos;
+			f econd eif eelse
+		and handle_loop_body ctx e =
+			let join_top = mk_join_node() in
+			let join_bottom = mk_join_node() in
+			let unset = set_loop_join ctx join_top join_bottom in
+			let close = branch ctx e.epos in
+			ignore(loop ctx e); (* TODO: I don't know if this is sane. *)
+			close join_top;
+			add_branch join_top ctx.cur_data e.epos;
+			close_join_node ctx join_top e.epos;
+			let ebody = loop ctx e in
+			ctx.cur_data.nd_terminates <- false;
+			unset();
+			close_join_node ctx join_bottom e.epos;
+			ebody
+		and loop ctx e = match e.eexpr with
+			(* var declarations *)
+			| TVar(v,eo) ->
+				declare_var ctx v e.epos;
+				let eo = match eo with
+					| None -> None
+					| Some e ->
+						let e = loop ctx e in
+						set_var_value v e;
+						Some e
+				in
+				{e with eexpr = TVar(v,eo)}
+			| TFunction tf ->
+				let close = branch ctx e.epos in
+				List.iter (fun (v,co) ->
+					declare_var ctx v e.epos;
+(* 					match co with
+						| Some TNull when (match v.v_type with TType({t_path=["haxe"],"PosInfos"},_) -> false | _ -> true) -> ()
+						| _ -> apply_not_null_cond ctx v e.epos *)
+				) tf.tf_args;
+				let e' = loop ctx tf.tf_expr in
+				close (mk_join_node());
+				{e with eexpr = TFunction {tf with tf_expr = e'}}
+			(* var modifications *)
+			| TBinop(OpAssign,({eexpr = TLocal v} as e1),e2) when v.v_name <> "this" ->
+				let e2 = loop ctx e2 in
+				let _ = assign_var ctx v e2 e1.epos in
+				{e with eexpr = TBinop(OpAssign,e1,e2)}
+			| TBinop(OpAssignOp op,({eexpr = TLocal v} as e1),e2) ->
+				let e1 = loop ctx e1 in
+				let e2 = loop ctx e2 in
+				let e_op = mk (TBinop(op,e1,e2)) e.etype e.epos in
+				let _ = assign_var ctx v e_op e1.epos in
+				{e with eexpr = TBinop(OpAssignOp op,e1,e2)}
+			| TUnop((Increment | Decrement as op),flag,({eexpr = TLocal v} as e1)) ->
+				let op = match op with Increment -> OpAdd | Decrement -> OpSub | _ -> assert false in
+				let e_one = mk (TConst (TInt (Int32.of_int 1))) com.basic.tint e.epos in
+				let e1 = loop ctx e1 in
+				let e_op = mk (TBinop(op,e1,e_one)) e.etype e.epos in
+				let _ = assign_var ctx v e_op e1.epos in
+				e
+			(* var user *)
+			| TLocal v ->
+				let v = get_var ctx v e.epos in
+				{e with eexpr = TLocal v}
+			(* control flow *)
+			| TIf(econd,eif,eelse) ->
+				let f econd eif eelse = {e with eexpr = TIf(econd,eif,eelse)} in
+				handle_if ctx f econd eif eelse
+			| TSwitch(e1,cases,edef) ->
+				let e1 = loop ctx e1 in
+				let join = mk_join_node() in
+				let cases = List.map (fun (el,e) ->
+					let close = branch ctx e.epos in
+					let el = List.map (loop ctx) el in
+					let e = loop ctx e in
+					close join;
+					el,e
+				) cases in
+				let edef = match edef with
+					| Some e ->
+						let close = branch ctx e.epos in
+						let e = loop ctx e in
+						close join;
+						Some e
+					| None ->
+						begin match e1.eexpr with
+							| TMeta((Meta.Exhaustive,_,_),_)
+							| TParenthesis({eexpr = TMeta((Meta.Exhaustive,_,_),_)}) ->
+								()
+							| _ ->
+								add_branch join ctx.cur_data e.epos;
+						end;
+						None
+				in
+				close_join_node ctx join e.epos;
+				let e = {e with eexpr = TSwitch(e1,cases,edef)} in
+				e
+			| TWhile(econd,ebody,mode) ->
+				let econd = loop ctx econd in
+				let ebody = handle_loop_body ctx ebody in
+				let e = {e with eexpr = TWhile(econd,ebody,mode)} in
+				e
+			| TFor(v,e1,ebody) ->
+				declare_var ctx v e.epos;
+				(* apply_not_null_cond ctx v e1.epos; *)
+				let v' = IntMap.find v.v_id ctx.cur_data.nd_var_map in
+				let e1 = loop ctx e1 in
+				let ebody = handle_loop_body ctx ebody in
+				let e = {e with eexpr = TFor(v',e1,ebody)} in
+				e
+			| TTry(e1,catches) ->
+				let join_ex = mk_join_node() in
+				let join_bottom = mk_join_node() in
+				let unset = set_exception_join ctx join_ex in
+				let e1 = loop ctx e1 in
+				unset();
+				add_branch join_bottom ctx.cur_data e.epos;
+				close_join_node ctx join_ex e.epos;
+				let catches = List.map (fun (v,e) ->
+					declare_var ctx v e.epos;
+					(* apply_not_null_cond ctx v e.epos; *)
+					let close = branch ctx e.epos in
+					let e = loop ctx e in
+					close join_bottom;
+					v,e
+				) catches in
+				close_join_node ctx join_bottom e.epos;
+				let e = {e with eexpr = TTry(e1,catches)} in
+				e
+			| TBreak ->
+				begin match ctx.loop_stack with
+					| [] -> error "Break outside loop" e.epos
+					| (_,join) :: _ -> add_branch join ctx.cur_data e.epos
+				end;
+				terminate ctx;
+				e
+			| TContinue ->
+				begin match ctx.loop_stack with
+					| [] -> error "Continue outside loop" e.epos
+					| (join,_) :: _ -> add_branch join ctx.cur_data e.epos
+				end;
+				terminate ctx;
+				e
+			| TThrow e1 ->
+				let e1 = loop ctx e1 in
+				begin match ctx.exception_stack with
+					| join :: _ -> add_branch join ctx.cur_data e.epos
+					| _ -> ()
+				end;
+				terminate ctx;
+				{e with eexpr = TThrow e1}
+			| TReturn eo ->
+				let eo = match eo with None -> None | Some e -> Some (loop ctx e) in
+				terminate ctx;
+				{e with eexpr = TReturn eo}
+			| TBlock el ->
+				let rec loop2 el = match el with
+					| [] ->
+						[]
+					| e :: el ->
+						if ctx.cur_data.nd_terminates then begin
+							(* ctx.com.warning (Printf.sprintf "Unreachable code: %s" (s_expr_pretty e)) e.epos; *)
+							[]
+						end else
+							let e = loop ctx e in
+							e :: (loop2 el)
+				in
+				ctx.block_depth <- ctx.block_depth + 1;
+				let el = loop2 el in
+				ctx.block_depth <- ctx.block_depth - 1;
+				{e with eexpr = TBlock(el)}
+			| _ ->
+				begin match ctx.exception_stack with
+					| join :: _ when can_throw e -> add_branch join ctx.cur_data e.epos
+					| _ -> ()
+				end;
+				Type.map_expr (loop ctx) e
+		in
+		let ctx = {
+			com = com;
+			cur_data = mk_node_data e.epos;
+			var_conds = IntMap.empty;
+			loop_stack = [];
+			exception_stack = [];
+			cleanup = [];
+			block_depth = 0;
+		} in
+		let e = loop ctx e in
+		e,ctx
+
+	let unapply com e =
+		let rec loop e = match e.eexpr with
+			| TFor(v,e1,e2) when Meta.has (Meta.Custom ":ssa") v.v_meta ->
+				let v' = get_origin_var v in
+				let e1 = loop e1 in
+				let e2 = loop e2 in
+				{e with eexpr = TFor(v',e1,e2)}
+			| TLocal v when Meta.has (Meta.Custom ":ssa") v.v_meta ->
+				let v' = get_origin_var v in
+				{e with eexpr = TLocal v'}
+			| TBlock el ->
+				let rec filter e = match e.eexpr with
+					| TMeta((Meta.Custom ":ssa",_,_),_) ->
+						false
+					| _ ->
+						true
+				in
+				let el = List.filter filter el in
+				let el = List.map loop el in
+				{e with eexpr = TBlock el}
+			| _ ->
+				Type.map_expr loop e
+		in
+		loop e
+end
+
+module ConstPropagation = struct
+	open Ssa
+
+	let expr_eq e1 e2 = match e1.eexpr,e2.eexpr with
+		| TConst ct1, TConst ct2 ->
+			ct1 = ct2
+		| _ ->
+			false
+
+	let get_block_depth v = try
+		let i = match Meta.get (Meta.Custom ":blockDepth") v.v_meta with
+			| _,[EConst(Int s),_],_ -> int_of_string s
+			| _ -> raise Not_found
+		in
+		i
+		with Not_found ->
+			-1
+
+	let can_be_inlined com v0 e = type_iseq v0.v_type e.etype && match e.eexpr with
+		| TConst ct ->
+			begin match ct with
+				| TThis | TSuper -> false
+				(* Some targets don't like seeing null in certain places and won't even compile. We have to detect `if (x != null)
+				   in order for this to work. *)
+				| TNull when (match com.platform with Php | Cpp -> true | _ -> false) -> false
+				| _ -> true
+			end
+		| TLocal v ->
+			not (Meta.has Meta.CompilerGenerated v.v_meta) &&
+			begin try
+				let v' = Ssa.get_origin_var v in
+				begin match v'.v_extra with
+					| Some ([],_) -> get_block_depth v <= get_block_depth v0
+					| _ -> false
+				end
+			with Not_found ->
+				false
+			end
+		| TEnumParameter _ when not (com.platform = Php) ->
+			Ssa.get_var_usage_count v0 <= 1
+		| _ ->
+			false
+
+	let semi_awkward_enum_value ssa e i = match e.eexpr with
+		| TCall({eexpr = TField(_,FEnum _)},el) -> (try List.nth el i with Failure _ -> raise Not_found)
+		| _ -> raise Not_found
+
+	let rec local ssa force v e =
+		begin try
+			if v.v_capture then raise Not_found;
+			if type_has_analyzer_option v.v_type flag_no_const_propagation then raise Not_found;
+			begin match follow v.v_type with
+				| TDynamic _ -> raise Not_found
+				| _ -> ()
+			end;
+			let e = Ssa.get_var_value v in
+			let old = v.v_extra in
+			v.v_extra <- None;
+			let e = value ssa force e in
+			v.v_extra <- old;
+			Ssa.set_var_value v e;
+			e
+		with Not_found ->
+			e
+		end
+
+	(* force must only be true if the value is not used in the output *)
+	and value ssa force e = match e.eexpr with
+		| TUnop((Increment | Decrement),_,_)
+		| TBinop(OpAssignOp _,_,_)
+		| TBinop(OpAssign,_,_) ->
+			e
+		| TBinop(op,e1,e2) ->
+			let e1 = value ssa force e1 in
+			let e2 = value ssa force e2 in
+			let e = {e with eexpr = TBinop(op,e1,e2)} in
+			let e' = Optimizer.optimize_binop e op e1 e2 in
+			if e == e' then
+				e
+			else
+				value ssa force e'
+		| TUnop(op,flag,e1) ->
+			let e1 = value ssa force e1 in
+			let e = {e with eexpr = TUnop(op,flag,e1)} in
+			let e' = Optimizer.optimize_unop e op flag e1 in
+			if e == e' then
+				e
+			else
+				value ssa force e'
+		| TCall (({eexpr = TLocal {v_name = "__ssa_phi__"}} as ephi),el) ->
+			let el = List.map (value ssa force) el in
+			begin match el with
+				| [] -> assert false
+				| e1 :: el ->
+					if List.for_all (fun e2 -> expr_eq e1 e2) el then
+						value ssa force e1
+					else
+						{e with eexpr = TCall(ephi, e1 :: el)}
+			end
+		| TParenthesis e1 | TMeta(_,e1) ->
+			value ssa force e1
+		| TLocal v ->
+			let e' = local ssa force v e in
+			if force || can_be_inlined ssa.com v e' then
+				e'
+			else
+				e
+ 		| TEnumParameter(e1,ef,i) ->
+			let ev = value ssa true e1 in
+			begin try
+				value ssa force (semi_awkward_enum_value ssa ev i)
+			with Not_found ->
+				e
+			end
+		| _ ->
+			e
+
+	(* TODO: the name is quite accurate *)
+	let awkward_get_enum_index ssa e =
+		let e = awkward_get_enum_index ssa.com e in
+		let ev = (value ssa true e) in
+		match ev.eexpr with
+			| TField(_,FEnum(_,ef)) -> TInt (Int32.of_int ef.ef_index)
+			| TCall({eexpr = TField(_,FEnum(_,ef))},_) -> TInt (Int32.of_int ef.ef_index)
+			| _ -> raise Not_found
+
+	let apply ssa e =
+		let rec loop e = match e.eexpr with
+			| TLocal v when not (Meta.has Meta.Unbound v.v_meta) ->
+				set_var_usage_count v (get_var_usage_count v + 1);
+			| _ ->
+				Type.iter loop e
+		in
+		loop e;
+		let had_function = ref false in
+		let rec loop e = match e.eexpr with
+			| TFunction _ when !had_function ->
+				e
+			| TFunction tf ->
+				had_function := true;
+				{e with eexpr = TFunction {tf with tf_expr = loop tf.tf_expr}}
+			| TLocal v ->
+				let e' = local ssa false v e in
+				if can_be_inlined ssa.com v e' then
+					e'
+				else
+					e
+			| TCall({eexpr = TField(_,(FStatic(_,cf) | FInstance(_,_,cf) | FAnon cf))},el) when has_analyzer_option cf.cf_meta flag_no_const_propagation ->
+				e
+			| TCall(e1,el) ->
+				let e1 = loop e1 in
+				let check e t =
+					if type_has_analyzer_option t flag_no_const_propagation then e
+					else loop e
+				in
+				let el = Codegen.UnificationCallback.check_call check el e1.etype in
+				{e with eexpr = TCall(e1,el)}
+(* 			| TField(e1,fa) ->
+				let e1' = loop e1 in
+				let fa = if e1' != e1 then
+					begin try quick_field e1'.etype (field_name fa)
+					with Not_found -> fa end
+				else
+					fa
+				in
+				{e with eexpr = TField(e1',fa)} *)
+			| TUnop((Increment | Decrement),_,_) ->
+				e
+			| TBinop(OpAssignOp op,e1,e2) ->
+				let e2 = loop e2 in
+				{e with eexpr = TBinop(OpAssignOp op,e1,e2)}
+			| TBinop(OpAssign,({eexpr = TLocal _} as e1),e2) ->
+				let e2 = loop e2 in
+				{e with eexpr = TBinop(OpAssign,e1,e2)}
+			| TBinop(op,e1,e2) ->
+				let e1 = loop e1 in
+				let e2 = loop e2 in
+				let e = {e with eexpr = TBinop(op,e1,e2)} in
+				let e' = Optimizer.optimize_binop e op e1 e2 in
+				e'
+			| TUnop(op,flag,e1) ->
+				let e1 = loop e1 in
+				let e = {e with eexpr = TUnop(op,flag,e1)} in
+				let e' = Optimizer.optimize_unop e op flag e1 in
+				e'
+			| TIf(e1,e2,eo) ->
+				let e1 = loop e1 in
+				let e2 = loop e2 in
+				let rec check_const e1 = match e1.eexpr with
+					| TConst (TBool true) ->
+						e2
+					| TConst (TBool false) ->
+						begin match eo with
+							| None ->
+								mk (TConst TNull) t_dynamic e.epos
+							| Some e ->
+								loop e
+						end
+					| TParenthesis e1 ->
+						check_const e1
+					| _ ->
+						let eo = match eo with None -> None | Some e -> Some (loop e) in
+						{e with eexpr = TIf(e1,e2,eo)}
+				in
+				check_const e1
+			| TSwitch(e1,cases,edef) ->
+				let e1 = loop e1 in
+				let rec check_constant e = match e.eexpr with
+					| TConst ct -> ct
+					| TParenthesis e1 | TCast(e1,None) | TMeta(_,e1) -> check_constant e1
+					| _ -> awkward_get_enum_index ssa e
+				in
+				begin try
+					let ct = check_constant e1 in
+					begin try
+						let _,e = List.find (fun (el,_) ->
+							List.exists (fun e -> match e.eexpr with
+								| TConst ct2 -> ct = ct2
+								| _ -> false
+							) el
+						) cases in
+						loop e
+					with Not_found ->
+						begin match edef with None -> raise Not_found | Some e -> loop e end
+					end
+				with Not_found ->
+					let cases = List.map (fun (el,e) -> el,loop e) cases in
+					let edef = match edef with None -> None | Some e -> Some (loop e) in
+					{e with eexpr = TSwitch(e1,cases,edef)}
+				end
+			| _ ->
+				Type.map_expr loop e
+		in
+		loop e
+end
+
+module EffectChecker = struct
+	let run com is_var_expression e =
+		let has_effect e = match e.eexpr with
+			| TVar _ -> true
+			| _ -> Optimizer.has_side_effect e
+		in
+		let e = if is_var_expression then
+			(* var initialization expressions are like assignments, so let's cheat a bit here *)
+			snd (Simplifier.apply com (Codegen.binop OpAssign (mk (TConst TNull) t_dynamic e.epos) e e.etype e.epos))
+		else e
+		in
+		let rec loop e = match e.eexpr with
+			| TBlock el ->
+				List.iter (fun e ->
+					if not (has_effect e) then com.warning "This expression has no effect" e.epos
+				) el
+			| _ ->
+				Type.iter loop e
+			in
+		loop e
+end
+
+module Checker = struct
+	open Ssa
+
+	let apply ssa e =
+		let given_warnings = ref PMap.empty in
+		let add_pos p =
+			given_warnings := PMap.add p true !given_warnings
+		in
+		let resolve_value v =
+			let e' = Ssa.get_var_value v in
+			begin match e'.eexpr with
+				| TLocal v' when v == v' -> e'
+				| _ -> e'
+			end
+		in
+		let rec is_null_expr e = match e.eexpr with
+			| TConst TNull ->
+				true
+			| TLocal v ->
+				(try is_null_expr (resolve_value v) with Not_found -> false)
+			| _ ->
+				false
+		in
+		let can_be_null v =
+			not (has_meta Meta.NotNull v.v_meta)
+			&& try not (List.exists (fun cond -> match cond with
+				| NotEqual(v',e) when v == v' && is_null_expr e -> true
+				| _ -> false
+			) (IntMap.find v.v_id ssa.var_conds)) with Not_found -> true
+		in
+		let return b p =
+			if b then add_pos p;
+			b
+		in
+		let rec can_be_null_expr vstack e =
+			if PMap.mem e.epos !given_warnings then
+				false
+			else match e.eexpr with
+			| TConst TNull ->
+				add_pos e.epos;
+				true
+			| TBinop((OpAssign | OpAssignOp _),_,e1) ->
+				can_be_null_expr vstack e1
+			| TBinop _ | TUnop _ ->
+				false
+			| TConst _ | TTypeExpr _ | TNew _ | TObjectDecl _ | TArrayDecl _ | TEnumParameter _ | TFunction _ | TVar _ ->
+				false
+			| TFor _ | TWhile _ | TIf _ | TSwitch _ | TTry _ | TReturn _ | TBreak | TContinue | TThrow _ ->
+				assert false
+			| TField _ | TBlock _ | TArray _ ->
+				false (* TODO *)
+			| TCall ({eexpr = TLocal {v_name = "__ssa_phi__"}},el) ->
+				List.exists (can_be_null_expr vstack) el
+			| TLocal v ->
+				if List.mem v.v_id vstack then
+					false (* not really, but let's not be a nuisance *)
+				else
+					return (can_be_null v && (try can_be_null_expr (v.v_id :: vstack) (resolve_value v) with Not_found -> true)) e.epos;
+			| TMeta(_,e1) | TParenthesis e1 | TCast(e1,_) ->
+				can_be_null_expr vstack e1
+			| TCall(e1,_) ->
+				begin match follow e1.etype with
+					| TFun(_,r) -> return (is_explicit_null r) e1.epos
+					| _ -> false
+				end
+		in
+		let check_null e p =
+			if can_be_null_expr [] e then begin
+				ssa.com.warning "Possible null exception" p;
+			end
+		in
+		let rec loop e = match e.eexpr with
+			| TField(e1,fa) ->
+				let e1 = loop e1 in
+				check_null e1 e.epos;
+				{e with eexpr = TField(e1,fa)}
+			| TMeta((Meta.Analyzer,[EConst(Ident "testIsNull"),_],_),e1) ->
+				if not (can_be_null_expr [] e) then error "Analyzer did not find a possible null exception" e.epos;
+				e
+			| TMeta((Meta.Analyzer,[EConst(Ident "testIsNotNull"),_],_),e1) ->
+				if (can_be_null_expr [] e) then error "Analyzer found a possible null exception" e.epos;
+				e
+			| _ ->
+				Type.map_expr loop e
+		in
+		loop e;
+end
+
+let rec lrev_iter f el = match el with
+	| e :: el ->
+		lrev_iter f el;
+		f e
+	| [] ->
+		()
+
+let rev_iter f e = match e.eexpr with
+	| TConst _
+	| TLocal _
+	| TBreak
+	| TContinue
+	| TTypeExpr _ ->
+		()
+	| TArray (e1,e2)
+	| TBinop (_,e1,e2)
+	| TFor (_,e1,e2)
+	| TWhile (e1,e2,_) ->
+		f e2;
+		f e1;
+	| TThrow e
+	| TField (e,_)
+	| TEnumParameter (e,_,_)
+	| TParenthesis e
+	| TCast (e,_)
+	| TUnop (_,_,e)
+	| TMeta(_,e) ->
+		f e
+	| TArrayDecl el
+	| TNew (_,_,el)
+	| TBlock el ->
+		lrev_iter f el
+	| TObjectDecl fl ->
+		lrev_iter (fun (_,e) -> f e) fl
+	| TCall (e,el) ->
+		f e;
+		lrev_iter f el
+	| TVar (v,eo) ->
+		(match eo with None -> () | Some e -> f e)
+	| TFunction fu ->
+		f fu.tf_expr
+	| TIf (e,e1,e2) ->
+		(match e2 with None -> () | Some e -> f e);
+		f e1;
+		f e;
+	| TSwitch (e,cases,def) ->
+		(match def with None -> () | Some e -> f e);
+		lrev_iter (fun (el,e2) -> lrev_iter f el; f e2) cases;
+		f e;
+	| TTry (e,catches) ->
+		lrev_iter (fun (_,e) -> f e) catches;
+		f e;
+	| TReturn eo ->
+		(match eo with None -> () | Some e -> f e)
+
+module LocalDce = struct
+	let apply e =
+		let is_used v = Meta.has Meta.Used v.v_meta || type_has_analyzer_option v.v_type flag_no_local_dce || v.v_capture in
+		let is_ref_type t = match t with
+			| TType({t_path = ["cs"],("Ref" | "Out")},_) -> true
+			| _ -> false
+		in
+		let rec use v =
+			if not (Meta.has Meta.Used v.v_meta) then begin
+				v.v_meta <- (Meta.Used,[],Ast.null_pos) :: v.v_meta;
+				try use (Ssa.get_origin_var v) with Not_found -> ()
+			end
+		in
+		let rec has_side_effect e =
+			let rec loop e =
+				match e.eexpr with
+				| TLocal v when Meta.has Meta.CompilerGenerated v.v_meta -> (try loop (Ssa.get_var_value v) with Not_found -> ())
+				| TBinop((OpAssign | OpAssignOp _),{eexpr = TLocal v},e2) when is_used v || has_side_effect e2 || is_ref_type v.v_type -> raise Exit
+				| TVar(v,None) when is_used v -> raise Exit
+				| TVar(v,Some e1) when is_used v || has_side_effect e1 -> raise Exit
+				| TConst _ | TLocal _ | TTypeExpr _ | TFunction _ -> ()
+				| TCall ({ eexpr = TField(_,FStatic({ cl_path = ([],"Std") },{ cf_name = "string" })) },args) -> Type.iter loop e
+				| TCall (({eexpr = TLocal {v_name = "__ssa_phi__"}}),el) -> ()
+				| TCall ({eexpr = TField(_,FEnum _)},_) -> Type.iter loop e
+				| TNew _ | TCall _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) -> raise Exit
+				| TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _) -> raise Exit
+				| TFor _ -> raise Exit
+				| TArray _ | TEnumParameter _ | TCast (_,None) | TBinop _ | TUnop _ | TParenthesis _ | TMeta _ | TWhile _
+				| TField _ | TIf _ | TTry _ | TSwitch _ | TArrayDecl _ | TBlock _ | TObjectDecl _ | TVar _ -> Type.iter loop e
+			in
+			try
+				loop e;
+				false
+			with Exit ->
+				true
+		in
+		let rec collect e = match e.eexpr with
+			| TLocal v ->
+				use v
+			| TVar(v,_) when not (is_used v) ->
+				(* TODO: this is probably dangerous *)
+				()
+			| _ ->
+				rev_iter collect e
+		in
+		let rec loop need_val e =
+			match e.eexpr with
+			| TLocal v ->
+				use v;
+				e
+			| TBinop(OpAssign,({eexpr = TLocal v} as e1),e2) ->
+				let e2 = loop false e2 in
+				if not (is_used v) && not (is_ref_type v.v_type) then
+					e2
+				else
+					{e with eexpr = TBinop(OpAssign,{e1 with eexpr = TLocal v},e2)}
+			| TVar(v,Some e1) when not (is_used v) ->
+				let e1 = if has_side_effect e1 then loop true e1 else e1 in
+				e1
+			| TWhile(e1,e2,flag) ->
+				collect e2;
+				let e2 = loop false e2 in
+				let e1 = loop false e1 in
+				{e with eexpr = TWhile(e1,e2,flag)}
+			| TFor(v,e1,e2) ->
+				collect e2;
+				let e2 = loop false e2 in
+				let e1 = loop false e1 in
+				{e with eexpr = TFor(v,e1,e2)}
+			| TBlock el ->
+				let rec block el = match el with
+					| e :: el ->
+						let el = block el in
+						if not need_val && not (has_side_effect e) then
+							el
+						else begin
+							let e = loop false e in
+							e :: el
+						end
+					| [] ->
+						[]
+				in
+				{e with eexpr = TBlock (block el)}
+			| TCall(e1, el) ->
+				let el = List.rev_map (loop true) (List.rev el) in
+				let e1 = loop false e1 in
+				{e with eexpr = TCall(e1,el)}
+			| TIf(e1,e2,e3) ->
+				let e3 = match e3 with None -> None | Some e -> Some (loop need_val e) in
+				let e2 = loop need_val e2 in
+				let e1 = loop false e1 in
+				{e with eexpr = TIf(e1,e2,e3)}
+			| TArrayDecl el ->
+				let el = List.rev_map (loop true) (List.rev el) in
+				{e with eexpr = TArrayDecl el}
+			| TObjectDecl fl ->
+				let fl = List.rev_map (fun (s,e) -> s,loop true e) (List.rev fl) in
+				{e with eexpr = TObjectDecl fl}
+			| _ ->
+				Type.map_expr (loop false) e
+		in
+		loop false e
+end
+
+module Config = struct
+
+	type analyzer_config = {
+		analyzer_use : bool;
+		simplifier_apply : bool;
+		ssa_apply : bool;
+		const_propagation : bool;
+		check : bool;
+		check_has_effect : bool;
+		local_dce : bool;
+		ssa_unapply : bool;
+		simplifier_unapply : bool;
+	}
+
+	let get_base_config com =
+		{
+			analyzer_use = true;
+			simplifier_apply = true;
+			ssa_apply = true;
+			const_propagation = not (Common.raw_defined com "analyzer-no-const-propagation");
+			check_has_effect = (Common.raw_defined com "analyzer-check-has-effect");
+			check = not (Common.raw_defined com "analyzer-no-check");
+			local_dce = not (Common.raw_defined com "analyzer-no-local-dce") && not (Common.defined com Define.As3);
+			ssa_unapply = not (Common.raw_defined com "analyzer-no-ssa-unapply");
+			simplifier_unapply = not (Common.raw_defined com "analyzer-no-simplify-unapply");
+		}
+
+	let update_config_from_meta 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 = flag_no_check -> { config with check = false}
+					| EConst (Ident s) when s = flag_check -> { config with check = true}
+					| EConst (Ident s) when s = flag_no_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 = flag_no_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 = flag_no_check_has_effect -> { config with check_has_effect = false}
+					| EConst (Ident s) when s = flag_check_has_effect -> { config with check_has_effect = true}
+					| _ -> config
+				) config el
+			| _ ->
+				config
+		) config meta
+
+	let get_class_config com c =
+		let config = get_base_config com in
+		update_config_from_meta config c.cl_meta
+
+	let get_field_config com c cf =
+		let config = get_class_config com c in
+		update_config_from_meta config cf.cf_meta
+end
+
+module Run = struct
+
+	open Config
+
+	let run_on_expr com config is_var_expression e =
+		let do_simplify = (not (Common.defined com Define.NoSimplify) ) && match com.platform with
+			| Cpp when Common.defined com Define.Cppia -> false
+			| Cpp | Flash8 | Python -> true
+			| _ -> false
+		in
+		let with_timer s f =
+			let timer = timer s in
+			let r = f() in
+			timer();
+			r
+		in
+		try
+			let has_unbound,e = if do_simplify || config.analyzer_use then
+				with_timer "analyzer-simplify-apply" (fun () -> Simplifier.apply com e)
+			else
+				false,e
+			in
+			let e = if config.analyzer_use && not has_unbound then begin
+					if config.check_has_effect then EffectChecker.run com is_var_expression e;
+					let e,ssa = with_timer "analyzer-ssa-apply" (fun () -> Ssa.apply com e) in
+					let e = if config.const_propagation then with_timer "analyzer-const-propagation" (fun () -> ConstPropagation.apply ssa e) else e in
+					(* let e = if config.check then with_timer "analyzer-checker" (fun () -> Checker.apply ssa e) else e in *)
+					let e = if config.local_dce && config.analyzer_use && not has_unbound && not is_var_expression then with_timer "analyzer-local-dce" (fun () -> LocalDce.apply e) else e in
+					let e = if config.ssa_unapply then with_timer "analyzer-ssa-unapply" (fun () -> Ssa.unapply com e) else e in
+					List.iter (fun f -> f()) ssa.Ssa.cleanup;
+					e
+			end else
+				e
+			in
+			let e = if not do_simplify && not (Common.raw_defined com "analyzer-no-simplify-unapply") then
+				with_timer "analyzer-simplify-unapply" (fun () -> Simplifier.unapply com e)
+			else
+				e
+			in
+			e
+		with Exit ->
+			e
+
+	let run_on_field ctx config cf =
+		match cf.cf_expr with
+		| Some e when not (is_ignored cf.cf_meta) && not (Codegen.is_removable_field ctx cf) ->
+			let config = update_config_from_meta config cf.cf_meta in
+			let is_var_expression = match cf.cf_kind with
+				| Var _ -> true
+				| _ -> false
+			in
+			cf.cf_expr <- Some (run_on_expr ctx.com config is_var_expression e);
+		| _ -> ()
+
+	let run_on_class ctx config c =
+		let config = update_config_from_meta config c.cl_meta in
+		let process_field cf = run_on_field ctx config cf in
+		List.iter process_field c.cl_ordered_fields;
+		List.iter process_field c.cl_ordered_statics;
+		(match c.cl_constructor with
+		| None -> ()
+		| Some f -> process_field f);
+		(match c.cl_init with
+		| None -> ()
+		| Some e ->
+			(* never optimize init expressions (too messy) *)
+			c.cl_init <- Some (run_on_expr ctx.com {config with analyzer_use = false} false e))
+
+	let run_on_type ctx config t =
+		match t with
+		| TClassDecl c when (is_ignored c.cl_meta) -> ()
+		| TClassDecl c -> run_on_class ctx config c
+		| TEnumDecl _ -> ()
+		| TTypeDecl _ -> ()
+		| TAbstractDecl _ -> ()
+
+	let run_on_types ctx types =
+		let com = ctx.com in
+		let config = get_base_config com in
+		List.iter (run_on_type ctx config) types
+
+end

+ 64 - 0
appveyor.yml

@@ -0,0 +1,64 @@
+version: "{build}"
+
+os: unstable #http://help.appveyor.com/discussions/suggestions/427-pre-install-cygwin
+
+platform:
+    - Win32
+
+clone_folder: C:/projects/haxe
+
+environment:
+    global:
+        NEKO_ROOT: C:/projects/neko
+        HAXELIB_ROOT: C:/projects/haxelib
+    matrix:
+        -   CYG_ARCH: x86
+            CYG_ROOT: C:/cygwin
+            CYG_SETUP: C:/cygwin/setup-x86.exe
+            WODI_ARCH: 32
+            MINGW_ARCH: i686
+        # -   CYG_ARCH: x86_64
+        #     CYG_ROOT: C:/cygwin64
+        #     WODI_ARCH: 64
+        #     MINGW_ARCH: x86_64
+
+init:
+    - 'echo System architecture: %PLATFORM%'
+
+install:
+    - 'git submodule update --init --recursive'
+    # Install ocaml using wodi
+    - '%CYG_ROOT%/setup-%CYG_ARCH%.exe -q -R "%CYG_ROOT%" -P dos2unix -P diffutils -P cpio -P make -P patch -P mingw64-%MINGW_ARCH%-gcc-core -P mingw64-%MINGW_ARCH%-gcc-g++ >NUL'
+    - '%CYG_ROOT%/bin/bash -lc "cygcheck -dc cygwin"'
+    - '%CYG_ROOT%/bin/bash -lc "wget -q http://ml.ignorelist.com/wodi/8/wodi%WODI_ARCH%.tar.xz -O /tmp/wodi%WODI_ARCH%.tar.xz"'
+    - '%CYG_ROOT%/bin/bash -lc "cd /tmp && rm -rf wodi%WODI_ARCH% && tar -xf wodi%WODI_ARCH%.tar.xz && bash wodi%WODI_ARCH%/install.sh"'
+    - '%CYG_ROOT%/bin/bash -lc "godi_add godi-zip"'
+    - 'set PATH=%PATH%;%CYG_ROOT%/opt/wodi%WODI_ARCH%/bin'
+    # Install neko
+    - cinst make
+    - 'git clone --recursive https://github.com/HaxeFoundation/neko.git %NEKO_ROOT%'
+    - 'cd %NEKO_ROOT%'
+    - set PATH=%PATH%;%NEKO_ROOT%/bin
+    - msbuild neko_vc10.sln /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
+    - msbuild libs/libs_vc10.sln /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
+    - copy /y libs\include\gc\gc.dll bin
+    - cd %NEKO_ROOT%/src
+    - neko ../boot/nekoc tools/install.neko
+    - neko tools/install -nolibs
+    - neko -version
+
+build_script:
+    - 'cd %APPVEYOR_BUILD_FOLDER%'
+    - 'set PATH=%PATH%;%APPVEYOR_BUILD_FOLDER%'
+    - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && make -f Makefile.win WODI=wodi%WODI_ARCH%"'
+    - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && make -f Makefile.win WODI=wodi%WODI_ARCH% tools"'
+    - cd %APPVEYOR_BUILD_FOLDER%/tests/
+    - mkdir "%HAXELIB_ROOT%"
+    - haxelib setup "%HAXELIB_ROOT%"
+    - haxelib git hx-yaml https://github.com/mikestead/hx-yaml master src
+
+test_script:
+    - cd %APPVEYOR_BUILD_FOLDER%/tests/
+    - haxe -version
+    - haxe -neko RunCi.n -main RunCi -lib hx-yaml
+    - neko RunCi.n

+ 59 - 11
ast.ml

@@ -26,20 +26,26 @@ type pos = {
 	pmax : int;
 }
 
+module IntMap = Map.Make(struct type t = int let compare a b = a - b end)
+
 module Meta = struct
 	type strict_meta =
+		| Abi
 		| Abstract
 		| Access
 		| Accessor
 		| Allow
+		| Analyzer
 		| Annotation
 		| ArrayAccess
 		| Ast
 		| AutoBuild
 		| Bind
 		| Bitmap
+		| BridgeProperties
 		| Build
 		| BuildXml
+		| Callable
 		| Class
 		| ClassCode
 		| Commutative
@@ -47,6 +53,7 @@ module Meta = struct
 		| CoreApi
 		| CoreType
 		| CppFileCode
+		| CppInclude
 		| CppNamespaceCode
 		| CsNative
 		| Dce
@@ -56,6 +63,7 @@ module Meta = struct
 		| Delegate
 		| Depend
 		| Deprecated
+		| DirectlyUsed
 		| DynamicObject
 		| Enum
 		| EnumConstructorParam
@@ -74,34 +82,45 @@ module Meta = struct
 		| FunctionTailCode
 		| Generic
 		| GenericBuild
+		| GenericInstance
 		| Getter
 		| Hack
+		| HasUntyped
 		| HaxeGeneric
 		| HeaderClassCode
 		| HeaderCode
+		| HeaderInclude
 		| HeaderNamespaceCode
 		| HxGen
 		| IfFeature
 		| Impl
+		| PythonImport
+		| ImplicitCast
 		| Include
 		| InitPackage
 		| Internal
 		| IsVar
+		| JavaCanonical
 		| JavaNative
+		| JsRequire
 		| Keep
 		| KeepInit
 		| KeepSub
+		| LibType
 		| Meta
 		| Macro
 		| MaybeUsed
 		| MergeBlock
 		| MultiType
 		| Native
+		| NativeChildren
 		| NativeGen
 		| NativeGeneric
+		| NativeProperty
 		| NoCompletion
 		| NoDebug
 		| NoDoc
+		| NoExpr
 		| NoImportGlobal
 		| NoPackageRestrict
 		| NoStack
@@ -116,20 +135,27 @@ module Meta = struct
 		| Protected
 		| Public
 		| PublicFields
+		| QuotedField
 		| ReadOnly
 		| RealPath
 		| Remove
 		| Require
 		| RequiresAssign
+		(* | Resolve *)
 		| ReplaceReflection
 		| Rtti
 		| Runtime
 		| RuntimeValue
+		| SelfCall
 		| Setter
 		| SkipCtor
 		| SkipReflection
 		| Sound
+		| SourceFile
+		| StoredTypedExpr
+		| Strict
 		| Struct
+		| StructAccess
 		| SuppressWarnings
 		| This
 		| Throws
@@ -144,6 +170,8 @@ module Meta = struct
 		| Unsafe
 		| Usage
 		| Used
+		| Value
+		| Void
 		| Last
 		(* do not put any custom metadata after Last *)
 		| Dollar of string
@@ -419,6 +447,8 @@ type type_decl = type_def * pos
 
 type package = string list * type_decl list
 
+exception Error of string * pos
+
 let is_lower_ident i =
 	let rec loop p =
 		match String.unsafe_get i p with
@@ -431,7 +461,7 @@ let is_lower_ident i =
 let pos = snd
 
 let rec is_postfix (e,_) op = match op with
-	| Increment | Decrement -> (match e with EConst _ | EField _ | EArray _ -> true | EMeta(_,e1) -> is_postfix e1 op | _ -> false)
+	| Increment | Decrement -> true
 	| Not | Neg | NegBits -> false
 
 let is_prefix = function
@@ -619,16 +649,17 @@ let unescape s =
 					inext := !inext + 2;
 				| 'u' ->
 					let (u, a) =
-					  (try
-					      (int_of_string ("0x" ^ String.sub s (i+1) 4), 4)
-					    with
-					      _ -> try
-						assert (s.[i+1] = '{');
-						let l = String.index_from s (i+3) '}' - (i+2) in
-						let u = int_of_string ("0x" ^ String.sub s (i+2) l) in
-						assert (u <= 0x10FFFF);
-						(u, l+2)
-					      with _ -> raise Exit) in
+						try
+							(int_of_string ("0x" ^ String.sub s (i+1) 4), 4)
+						with _ -> try
+							assert (s.[i+1] = '{');
+							let l = String.index_from s (i+3) '}' - (i+2) in
+							let u = int_of_string ("0x" ^ String.sub s (i+2) l) in
+							assert (u <= 0x10FFFF);
+							(u, l+2)
+						with _ ->
+							raise Exit
+					in
 					let ub = UTF8.Buf.create 0 in
 					UTF8.Buf.add_char ub (UChar.uchar_of_int u);
 					Buffer.add_string b (UTF8.Buf.contents ub);
@@ -719,4 +750,21 @@ let rec s_expr (e,_) =
 	| EArrayDecl el -> "[" ^ (String.concat "," (List.map s_expr el)) ^ "]"
 	| EObjectDecl fl -> "{" ^ (String.concat "," (List.map (fun (n,e) -> n ^ ":" ^ (s_expr e)) fl)) ^ "}"
 	| EBinop (op,e1,e2) -> s_expr e1 ^ s_binop op ^ s_expr e2
+	| ECall (e,el) -> s_expr e ^ "(" ^ (String.concat ", " (List.map s_expr el)) ^ ")"
+	| EField (e,f) -> s_expr e ^ "." ^ f
 	| _ -> "'???'"
+
+let get_value_meta meta =
+	try
+		begin match Meta.get Meta.Value meta with
+			| (_,[EObjectDecl values,_],_) -> List.fold_left (fun acc (s,e) -> PMap.add s e acc) PMap.empty values
+			| _ -> raise Not_found
+		end
+	with Not_found ->
+		PMap.empty
+
+let rec string_list_of_expr_path_raise (e,p) =
+	match e with
+	| EConst (Ident i) -> [i]
+	| EField (e,f) -> f :: string_list_of_expr_path_raise e
+	| _ -> raise Exit

Файловите разлики са ограничени, защото са твърде много
+ 408 - 198
codegen.ml


+ 135 - 41
common.ml

@@ -57,6 +57,7 @@ type platform =
 	| Cpp
 	| Cs
 	| Java
+	| Python
 
 (**
 	The capture policy tells which handling we make of captured locals
@@ -95,16 +96,18 @@ type platform_config = {
 	pf_pattern_matching : bool;
 	(** can the platform use default values for non-nullable arguments *)
 	pf_can_skip_non_nullable_argument : bool;
-	(** generator ignores TCast(_,None) *)
-	pf_ignore_unsafe_cast : bool;
+	(** type paths that are reserved on the platform *)
+	pf_reserved_type_paths : path list;
 }
 
 type display_mode =
 	| DMNone
 	| DMDefault
 	| DMUsage
-	| DMMetadata
 	| DMPosition
+	| DMToplevel
+	| DMResolve of string
+	| DMType
 
 type context = {
 	(* config *)
@@ -132,6 +135,7 @@ type context = {
 	mutable get_macros : unit -> context option;
 	mutable run_command : string -> int;
 	file_lookup_cache : (string,string option) Hashtbl.t;
+	mutable stored_typed_exprs : (int, texpr) PMap.t;
 	(* output *)
 	mutable file : string;
 	mutable flash_version : float;
@@ -149,6 +153,7 @@ type context = {
 	mutable net_libs : (string * bool * (unit -> path list) * (path -> IlData.ilclass option)) list; (* (path,std,all_files,lookup) *)
 	mutable net_std : string list;
 	net_path_map : (path,string list * string list * string) Hashtbl.t;
+	mutable c_args : string list;
 	mutable js_gen : (unit -> unit) option;
 	(* typing *)
 	mutable basic : basic_types;
@@ -164,9 +169,11 @@ module Define = struct
 	type strict_defined =
 		| AbsolutePath
 		| AdvancedTelemetry
+		| Analyzer
 		| As3
 		| CheckXmlProxy
 		| CoreApi
+		| CoreApiSerialize
 		| Cppia
 		| Dce
 		| DceDebug
@@ -177,9 +184,14 @@ module Define = struct
 		| DocGen
 		| Dump
 		| DumpDependencies
+		| DumpIgnoreVarIds
+		| EraseGenerics
 		| Fdb
+		| FileExtension
 		| FlashStrict
 		| FlashUseStage
+		| ForceLibCheck
+		| ForceNativeProperty
 		| FormatWarning
 		| GencommonDebug
 		| HaxeBoot
@@ -190,7 +202,9 @@ module Define = struct
 		| JavaVer
 		| JsClassic
 		| JsEs5
-		| JsFlatten
+		| JsUnflatten
+		| KeepOldOutput
+		| LoopUnrollMaxCost
 		| Macro
 		| MacroTimes
 		| NekoSource
@@ -207,6 +221,7 @@ module Define = struct
 		| NoOpt
 		| NoPatternMatching
 		| NoRoot
+		| NoSimplify
 		| NoSwfCompress
 		| NoTraces
 		| PhpPrefix
@@ -227,6 +242,7 @@ module Define = struct
 		| SwfScriptTimeout
 		| SwfUseDoAbc
 		| Sys
+		| Unity46LineNumbers
 		| Unsafe
 		| UseNekoc
 		| UseRttiDoc
@@ -237,9 +253,11 @@ module Define = struct
 	let infos = function
 		| AbsolutePath -> ("absolute_path","Print absolute file path in trace output")
 		| AdvancedTelemetry -> ("advanced-telemetry","Allow the SWF to be measured with Monocle tool")
+		| Analyzer -> ("analyzer","Use static analyzer for optimization (experimental)")
 		| As3 -> ("as3","Defined when outputing flash9 as3 source code")
 		| CheckXmlProxy -> ("check_xml_proxy","Check the used fields of the xml proxy")
 		| CoreApi -> ("core_api","Defined in the core api context")
+		| CoreApiSerialize -> ("core_api_serialize","Sets so some generated core api classes be marked with the Serializable attribute on C#")
 		| Cppia -> ("cppia", "Generate experimental cpp instruction assembly")
 		| Dce -> ("dce","The current DCE mode")
 		| DceDebug -> ("dce_debug","Show DCE log")
@@ -250,9 +268,15 @@ module Define = struct
 		| DocGen -> ("doc_gen","Do not perform any removal/change in order to correctly generate documentation")
 		| Dump -> ("dump","Dump the complete typed AST for internal debugging")
 		| DumpDependencies -> ("dump_dependencies","Dump the classes dependencies")
+		| DumpIgnoreVarIds -> ("dump_ignore_var_ids","Dump files do not contain variable IDs (helps with diff)")
+		| EraseGenerics -> ("erase_generics","Erase generic classes on C#")
 		| Fdb -> ("fdb","Enable full flash debug infos for FDB interactive debugging")
+		| FileExtension -> ("file_extension","Output filename extension for cpp source code")
 		| FlashStrict -> ("flash_strict","More strict typing for flash target")
 		| FlashUseStage -> ("flash_use_stage","Keep the SWF library initial stage")
+		(* force_lib_check is only here as a debug facility - compiler checking allows errors to be found more easily *)
+		| ForceLibCheck -> ("force_lib_check","Force the compiler to check -net-lib and -java-lib added classes (internal)")
+		| ForceNativeProperty -> ("force_native_property","Tag all properties with :nativeProperty metadata for 3.1 compatibility")
 		| FormatWarning -> ("format_warning","Print a warning for each formated string, for 2.x compatibility")
 		| GencommonDebug -> ("gencommon_debug","GenCommon internal")
 		| HaxeBoot -> ("haxe_boot","Given the name 'haxe' to the flash boot class instead of a generated name")
@@ -263,7 +287,9 @@ module Define = struct
 		| JavaVer -> ("java_ver", "<version:5-7> Sets the Java version to be targeted")
 		| JsClassic -> ("js_classic","Don't use a function wrapper and strict mode in JS output")
 		| JsEs5 -> ("js_es5","Generate JS for ES5-compliant runtimes")
-		| JsFlatten -> ("js_flatten","Generate classes to use fewer object property lookups")
+		| JsUnflatten -> ("js_unflatten","Generate nested objects for packages and types")
+		| KeepOldOutput -> ("keep_old_output","Keep old source files in the output directory (for C#/Java)")
+		| LoopUnrollMaxCost -> ("loop_unroll_max_cost","Maximum cost (number of expressions * iterations) before loop unrolling is canceled (default 250)")
 		| Macro -> ("macro","Defined when we compile code in the macro context")
 		| MacroTimes -> ("macro_times","Display per-macro timing when used with --times")
 		| NetVer -> ("net_ver", "<version:20-45> Sets the .NET version to be targeted")
@@ -271,7 +297,7 @@ 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")
-		| NoCompilation -> ("no-compilation","Disable CPP final compilation")
+		| 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")
 		| NoDeprecationWarnings -> ("no-deprecation-warnings","Do not warn if fields annotated with @:deprecated are used")
@@ -279,8 +305,9 @@ module Define = struct
 		| NoOpt -> ("no_opt","Disable optimizations")
 		| NoPatternMatching -> ("no_pattern_matching","Disable pattern matching")
 		| NoInline -> ("no_inline","Disable inlining")
-		| NoRoot -> ("no_root","GenCS internal")
+		| NoRoot -> ("no_root","Generate top-level types into haxe.root namespace")
 		| NoMacroCache -> ("no_macro_cache","Disable macro context caching")
+		| NoSimplify -> "no_simplify",("Disable simplification filter")
 		| NoSwfCompress -> ("no_swf_compress","Disable SWF output compression")
 		| NoTraces -> ("no_traces","Disable all trace calls")
 		| PhpPrefix -> ("php_prefix","Compiled with --php-prefix")
@@ -291,16 +318,18 @@ module Define = struct
 		| SourceMapContent -> ("source-map-content","Include the hx sources as part of the JS source map")
 		| Swc -> ("swc","Output a SWC instead of a SWF")
 		| SwfCompressLevel -> ("swf_compress_level","<level:1-9> Set the amount of compression for the SWF output")
-		| SwfDebugPassword -> ("swf_debug_password", "Set a password for debugging.")
+		| SwfDebugPassword -> ("swf_debug_password", "Set a password for debugging")
 		| SwfDirectBlit -> ("swf_direct_blit", "Use hardware acceleration to blit graphics")
 		| SwfGpu -> ("swf_gpu", "Use GPU compositing features when drawing graphics")
 		| SwfMark -> ("swf_mark","GenSWF8 internal")
-		| SwfMetadata -> ("swf_metadata", "=<file> Include contents of <file> as metadata in the swf.")
+		| SwfMetadata -> ("swf_metadata", "=<file> Include contents of <file> as metadata in the swf")
 		| SwfPreloaderFrame -> ("swf_preloader_frame", "Insert empty first frame in swf")
 		| SwfProtected -> ("swf_protected","Compile Haxe private as protected in the SWF instead of public")
 		| SwfScriptTimeout -> ("swf_script_timeout", "Maximum ActionScript processing time before script stuck dialog box displays (in seconds)")
 		| SwfUseDoAbc -> ("swf_use_doabc", "Use DoAbc swf-tag instead of DoAbcDefine")
 		| Sys -> ("sys","Defined for all system platforms")
+		(* see https://github.com/HaxeFoundation/haxe/issues/3759 *)
+		| Unity46LineNumbers -> ("unity46_line_numbers", "Fixes line numbers in generated C# files for Unity 4.6 Mono compiler")
 		| Unsafe -> ("unsafe","Allow unsafe code when targeting C#")
 		| UseNekoc -> ("use_nekoc","Use nekoc compiler instead of internal one")
 		| UseRttiDoc -> ("use_rtti_doc","Allows access to documentation during compilation")
@@ -329,38 +358,44 @@ module MetaInfo = struct
 		| Internal
 
 	let to_string = function
+		| Abi -> ":abi",("Function ABI/calling convention",[Platforms [Cpp]])
 		| Abstract -> ":abstract",("Sets the underlying class implementation as 'abstract'",[Platforms [Java;Cs]])
 		| Access -> ":access",("Forces private access to package, type or field",[HasParam "Target path";UsedOnEither [TClass;TClassField]])
 		| Accessor -> ":accessor",("Used internally by DCE to mark property accessors",[UsedOn TClassField;Internal])
 		| Allow -> ":allow",("Allows private access from package, type or field",[HasParam "Target path";UsedOnEither [TClass;TClassField]])
+		| Analyzer -> ":analyzer",("Used to configure the static analyzer",[])
 		| Annotation -> ":annotation",("Annotation (@interface) definitions on -java-lib imports will be annotated with this metadata. Has no effect on types compiled by Haxe",[Platform Java; UsedOn TClass])
 		| ArrayAccess -> ":arrayAccess",("Allows [] access on an abstract",[UsedOnEither [TAbstract;TAbstractField]])
 		| Ast -> ":ast",("Internally used to pass the AST source into the typed AST",[Internal])
 		| AutoBuild -> ":autoBuild",("Extends @:build metadata to all extending and implementing classes",[HasParam "Build macro call";UsedOn TClass])
 		| Bind -> ":bind",("Override Swf class declaration",[Platform Flash;UsedOn TClass])
 		| Bitmap -> ":bitmap",("Embeds given bitmap data into the class (must extend flash.display.BitmapData)",[HasParam "Bitmap file path";UsedOn TClass;Platform Flash])
+		| BridgeProperties -> ":bridgeProperties",("Creates native property bridges for all Haxe properties in this class",[UsedOn TClass;Platform Cs])
 		| Build -> ":build",("Builds a class or enum from a macro",[HasParam "Build macro call";UsedOnEither [TClass;TEnum]])
-		| BuildXml -> ":buildXml",("",[Platform Cpp])
+		| BuildXml -> ":buildXml",("Specify xml data to be injected into Build.xml",[Platform Cpp])
+		| Callable -> ":callable",("Abstract forwards call to its underlying type",[UsedOn TAbstract])
 		| Class -> ":class",("Used internally to annotate an enum that will be generated as a class",[Platforms [Java;Cs]; UsedOn TEnum; Internal])
 		| ClassCode -> ":classCode",("Used to inject platform-native code into a class",[Platforms [Java;Cs]; UsedOn TClass])
 		| Commutative -> ":commutative",("Declares an abstract operator as commutative",[UsedOn TAbstractField])
 		| CompilerGenerated -> ":compilerGenerated",("Marks a field as generated by the compiler. Shouldn't be used by the end user",[Platforms [Java;Cs]])
 		| CoreApi -> ":coreApi",("Identifies this class as a core api class (forces Api check)",[UsedOnEither [TClass;TEnum;TTypedef;TAbstract]])
 		| CoreType -> ":coreType",("Identifies an abstract as core type so that it requires no implementation",[UsedOn TAbstract])
-		| CppFileCode -> ":cppFileCode",("",[Platform Cpp])
+		| CppFileCode -> ":cppFileCode",("Code to be injected into generated cpp file",[Platform Cpp])
+		| CppInclude -> ":cppInclude",("File to be included in generated cpp file",[Platform Cpp])
 		| CppNamespaceCode -> ":cppNamespaceCode",("",[Platform Cpp])
 		| CsNative -> ":csNative",("Automatically added by -net-lib on classes generated from .NET DLL files",[Platform Cs; UsedOnEither[TClass;TEnum]; Internal])
-		| Dce -> ":dce",("Forces dead code elimination even when not -dce full is specified",[UsedOnEither [TClass;TEnum]])
+		| Dce -> ":dce",("Forces dead code elimination even when -dce full is not specified",[UsedOnEither [TClass;TEnum]])
 		| Debug -> ":debug",("Forces debug information to be generated into the Swf even without -debug",[UsedOnEither [TClass;TClassField]; Platform Flash])
 		| Decl -> ":decl",("",[Platform Cpp])
 		| DefParam -> ":defParam",("?",[])
 		| Delegate -> ":delegate",("Automatically added by -net-lib on delegates",[Platform Cs; UsedOn TAbstract])
 		| Depend -> ":depend",("",[Platform Cpp])
-		| Deprecated -> ":deprecated",("Automatically added by -java-lib on class fields annotated with @Deprecated annotation. Has no effect on types compiled by Haxe.",[Platform Java; UsedOnEither [TClass;TEnum;TClassField]])
+		| Deprecated -> ":deprecated",("Automatically added by -java-lib on class fields annotated with @Deprecated annotation. Has no effect on types compiled by Haxe",[Platform Java; UsedOnEither [TClass;TEnum;TClassField]])
+		| DirectlyUsed -> ":directlyUsed",("Marks types that are directly referenced by non-extern code",[Internal])
 		| DynamicObject -> ":dynamicObject",("Used internally to identify the Dynamic Object implementation",[Platforms [Java;Cs]; UsedOn TClass; Internal])
 		| Enum -> ":enum",("Used internally to annotate a class that was generated from an enum",[Platforms [Java;Cs]; UsedOn TClass; Internal])
 		| EnumConstructorParam -> ":enumConstructorParam",("Used internally to annotate GADT type parameters",[UsedOn TClass; Internal])
-		| Event -> ":event",("Automatically added by -net-lib on events. Has no effect on types compiled by Haxe.",[Platform Cs; UsedOn TClassField])
+		| Event -> ":event",("Automatically added by -net-lib on events. Has no effect on types compiled by Haxe",[Platform Cs; UsedOn TClassField])
 		| Exhaustive -> ":exhaustive",("",[Internal])
 		| Expose -> ":expose",("Makes the class available on the window object",[HasParam "?Name=Class path";UsedOn TClass;Platform Js])
 		| Extern -> ":extern",("Marks the field as extern so it is not generated",[UsedOn TClassField])
@@ -375,36 +410,47 @@ module MetaInfo = struct
 		| FunctionTailCode -> ":functionTailCode",("",[Platform Cpp])
 		| Generic -> ":generic",("Marks a class or class field as generic so each type parameter combination generates its own type/field",[UsedOnEither [TClass;TClassField]])
 		| GenericBuild -> ":genericBuild",("Builds instances of a type using the specified macro",[UsedOn TClass])
+		| GenericInstance -> ":genericInstance",("Internally used to mark instances of @:generic methods",[UsedOn TClassField;Internal])
 		| Getter -> ":getter",("Generates a native getter function on the given field",[HasParam "Class field name";UsedOn TClassField;Platform Flash])
 		| Hack -> ":hack",("Allows extending classes marked as @:final",[UsedOn TClass])
+		| HasUntyped -> (":has_untyped",("Used by the typer to mark fields that have untyped expressions",[Internal]))
 		| HaxeGeneric -> ":haxeGeneric",("Used internally to annotate non-native generic classes",[Platform Cs; UsedOnEither[TClass;TEnum]; Internal])
-		| HeaderClassCode -> ":headerClassCode",("",[Platform Cpp])
-		| HeaderCode -> ":headerCode",("",[Platform Cpp])
+		| HeaderClassCode -> ":headerClassCode",("Code to be injected into the generated class, in the header",[Platform Cpp])
+		| HeaderCode -> ":headerCode",("Code to be injected into the generated header file",[Platform Cpp])
+		| HeaderInclude -> ":headerInclude",("File to be included in generated header file",[Platform Cpp])
 		| HeaderNamespaceCode -> ":headerNamespaceCode",("",[Platform Cpp])
 		| HxGen -> ":hxGen",("Annotates that an extern class was generated by Haxe",[Platforms [Java;Cs]; UsedOnEither [TClass;TEnum]])
 		| IfFeature -> ":ifFeature",("Causes a field to be kept by DCE if the given feature is part of the compilation",[HasParam "Feature name";UsedOn TClassField])
 		| Impl -> ":impl",("Used internally to mark abstract implementation fields",[UsedOn TAbstractField; Internal])
+		| PythonImport -> ":pythonImport",("Generates python import statement for extern classes",[Platforms [Python]; UsedOn TClass])
+		| ImplicitCast -> ":implicitCast",("Generated automatically on the AST when an implicit abstract cast happens",[Internal; UsedOn TExpr])
 		| Include -> ":include",("",[Platform Cpp])
 		| InitPackage -> ":initPackage",("?",[])
 		| Meta.Internal -> ":internal",("Generates the annotated field/class with 'internal' access",[Platforms [Java;Cs]; UsedOnEither[TClass;TEnum;TClassField]])
 		| IsVar -> ":isVar",("Forces a physical field to be generated for properties that otherwise would not require one",[UsedOn TClassField])
+		| JavaCanonical -> ":javaCanonical",("Used by the Java target to annotate the canonical path of the type",[HasParam "Output type package";HasParam "Output type name";UsedOnEither [TClass;TEnum]; Platform Java])
 		| JavaNative -> ":javaNative",("Automatically added by -java-lib on classes generated from JAR/class files",[Platform Java; UsedOnEither[TClass;TEnum]; Internal])
+		| JsRequire -> ":jsRequire",("Generate javascript module require expression for given extern",[Platform Js; UsedOn TClass])
 		| Keep -> ":keep",("Causes a field or type to be kept by DCE",[])
 		| KeepInit -> ":keepInit",("Causes a class to be kept by DCE even if all its field are removed",[UsedOn TClass])
 		| KeepSub -> ":keepSub",("Extends @:keep metadata to all implementing and extending classes",[UsedOn TClass])
+		| LibType -> ":libType",("Used by -net-lib and -java-lib to mark a class that shouldn't be checked (overrides, interfaces, etc) by the type loader",[Internal; UsedOn TClass; Platforms [Java;Cs]])
 		| Meta -> ":meta",("Internally used to mark a class field as being the metadata field",[])
 		| Macro -> ":macro",("(deprecated)",[])
 		| MaybeUsed -> ":maybeUsed",("Internally used by DCE to mark fields that might be kept",[Internal])
-		| MergeBlock -> ":mergeBlock",("Internally used by typer to mark block that should be merged into the outer scope",[Internal])
+		| MergeBlock -> ":mergeBlock",("Merge the annotated block into the current scope",[UsedOn TExpr])
 		| MultiType -> ":multiType",("Specifies that an abstract chooses its this-type from its @:to functions",[UsedOn TAbstract; HasParam "Relevant type parameters"])
 		| Native -> ":native",("Rewrites the path of a class or enum during generation",[HasParam "Output type path";UsedOnEither [TClass;TEnum]])
-		| NativeGen -> ":nativeGen",("Annotates that a type should be treated as if it were an extern definition - platform native",[Platforms [Java;Cs]; UsedOnEither[TClass;TEnum]])
+		| NativeChildren -> ":nativeChildren",("Annotates that all children from a type should be treated as if it were an extern definition - platform native",[Platforms [Java;Cs]; UsedOn TClass])
+		| NativeGen -> ":nativeGen",("Annotates that a type should be treated as if it were an extern definition - platform native",[Platforms [Java;Cs;Python]; UsedOnEither[TClass;TEnum]])
 		| NativeGeneric -> ":nativeGeneric",("Used internally to annotate native generic classes",[Platform Cs; UsedOnEither[TClass;TEnum]; Internal])
+		| NativeProperty -> ":nativeProperty",("Use native properties which will execute even with dynamic usage",[Platform Cpp])
 		| NoCompletion -> ":noCompletion",("Prevents the compiler from suggesting completion on this field",[UsedOn TClassField])
 		| NoDebug -> ":noDebug",("Does not generate debug information into the Swf even if -debug is set",[UsedOnEither [TClass;TClassField];Platform Flash])
 		| NoDoc -> ":noDoc",("Prevents a type from being included in documentation generation",[])
+		| NoExpr -> ":noExpr",("Internally used to mark abstract fields which have no expression by design",[Internal])
 		| NoImportGlobal -> ":noImportGlobal",("Prevents a static field from being imported with import Class.*",[UsedOn TAnyField])
-		| NoPackageRestrict -> ":noPackageRestrict",("?",[])
+		| NoPackageRestrict -> ":noPackageRestrict",("Allows a module to be accessed across all targets if found on its first type",[Internal])
 		| NoStack -> ":noStack",("",[Platform Cpp])
 		| NotNull -> ":notNull",("Declares an abstract type as not accepting null values",[UsedOn TAbstract])
 		| NoUsing -> ":noUsing",("Prevents a field from being used with 'using'",[UsedOn TClassField])
@@ -414,6 +460,7 @@ module MetaInfo = struct
 		| Overload -> ":overload",("Allows the field to be called with different argument types",[HasParam "Function specification (no expression)";UsedOn TClassField])
 		| Public -> ":public",("Marks a class field as being public",[UsedOn TClassField])
 		| 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",[Internal])
 		| PrivateAccess -> ":privateAccess",("Allow private access to anything for the annotated expression",[UsedOn TExpr])
 		| Protected -> ":protected",("Marks a class field as being protected",[UsedOn TClassField])
 		| Property -> ":property",("Marks a property field to be compiled as a native C# property",[UsedOn TClassField;Platform Cs])
@@ -422,17 +469,23 @@ module MetaInfo = struct
 		| Remove -> ":remove",("Causes an interface to be removed from all implementing classes before generation",[UsedOn TClass])
 		| Require -> ":require",("Allows access to a field only if the specified compiler flag is set",[HasParam "Compiler flag to check";UsedOn TClassField])
 		| RequiresAssign -> ":requiresAssign",("Used internally to mark certain abstract operator overloads",[Internal])
+		(* | Resolve -> ":resolve",("Abstract fields marked with this metadata can be used to resolve unknown fields",[UsedOn TClassField]) *)
 		| ReplaceReflection -> ":replaceReflection",("Used internally to specify a function that should replace its internal __hx_functionName counterpart",[Platforms [Java;Cs]; UsedOnEither[TClass;TEnum]; Internal])
 		| Rtti -> ":rtti",("Adds runtime type informations",[UsedOn TClass])
 		| Runtime -> ":runtime",("?",[])
 		| RuntimeValue -> ":runtimeValue",("Marks an abstract as being a runtime value",[UsedOn TAbstract])
+		| SelfCall -> ":selfCall",("Translates method calls into calling object directly",[UsedOn TClassField; Platform Js])
 		| Setter -> ":setter",("Generates a native getter function on the given field",[HasParam "Class field name";UsedOn TClassField;Platform Flash])
+		| StoredTypedExpr -> ":storedTypedExpr",("Used internally to reference a typed expression returned from a macro",[Internal])
 		| SkipCtor -> ":skipCtor",("Used internally to generate a constructor as if it were a native type (no __hx_ctor)",[Platforms [Java;Cs]; Internal])
 		| SkipReflection -> ":skipReflection",("Used internally to annotate a field that shouldn't have its reflection data generated",[Platforms [Java;Cs]; UsedOn TClassField; Internal])
 		| Sound -> ":sound",( "Includes a given .wav or .mp3 file into the target Swf and associates it with the class (must extend flash.media.Sound)",[HasParam "File path";UsedOn TClass;Platform Flash])
-		| Struct -> ":struct",("Marks a class definition as a struct.",[Platform Cs; UsedOn TClass])
+		| SourceFile -> ":sourceFile",("Source code filename for external class",[Platform Cpp])
+		| Strict -> ":strict",("Used to declare a native C# attribute or a native Java metadata. Is type checked",[Platforms [Java;Cs]])
+		| Struct -> ":struct",("Marks a class definition as a struct",[Platform Cs; UsedOn TClass])
+		| StructAccess -> ":structAccess",("Marks an extern class as using struct access('.') not pointer('->')",[Platform Cpp; UsedOn TClass])
 		| SuppressWarnings -> ":suppressWarnings",("Adds a SuppressWarnings annotation for the generated Java class",[Platform Java; UsedOn TClass])
-		| Throws -> ":throws",("Adds a 'throws' declaration to the generated function.",[HasParam "Type as String"; Platform Java; UsedOn TClassField])
+		| Throws -> ":throws",("Adds a 'throws' declaration to the generated function",[HasParam "Type as String"; Platform Java; UsedOn TClassField])
 		| This -> ":this",("Internally used to pass a 'this' expression to macros",[Internal; UsedOn TExpr])
 		| To -> ":to",("Specifies that the field of the abstract is a cast operation to the type identified in the function",[UsedOn TAbstractField])
 		| ToString -> ":toString",("Internally used",[Internal])
@@ -445,6 +498,8 @@ module MetaInfo = struct
 		| Unsafe -> ":unsafe",("Declares a class, or a method with the C#'s 'unsafe' flag",[Platform Cs; UsedOnEither [TClass;TClassField]])
 		| Usage -> ":usage",("?",[])
 		| Used -> ":used",("Internally used by DCE to mark a class or field as used",[Internal])
+		| Value -> ":value",("Used to store default values for fields and function arguments",[UsedOn TClassField])
+		| Void -> ":void",("Use Cpp native 'void' return type",[Platform Cpp])
 		| Last -> assert false
 		(* do not put any custom metadata after Last *)
 		| Dollar s -> "$" ^ s,("",[])
@@ -492,7 +547,7 @@ let default_config =
 		pf_overload = false;
 		pf_pattern_matching = false;
 		pf_can_skip_non_nullable_argument = true;
-		pf_ignore_unsafe_cast = false;
+		pf_reserved_type_paths = [];
 	}
 
 let get_config com =
@@ -513,7 +568,7 @@ let get_config com =
 			pf_overload = false;
 			pf_pattern_matching = false;
 			pf_can_skip_non_nullable_argument = true;
-			pf_ignore_unsafe_cast = false;
+			pf_reserved_type_paths = [];
 		}
 	| Js ->
 		{
@@ -528,7 +583,7 @@ let get_config com =
 			pf_overload = false;
 			pf_pattern_matching = false;
 			pf_can_skip_non_nullable_argument = true;
-			pf_ignore_unsafe_cast = true;
+			pf_reserved_type_paths = [([],"Object")];
 		}
 	| Neko ->
 		{
@@ -543,7 +598,7 @@ let get_config com =
 			pf_overload = false;
 			pf_pattern_matching = false;
 			pf_can_skip_non_nullable_argument = true;
-			pf_ignore_unsafe_cast = true;
+			pf_reserved_type_paths = [];
 		}
 	| Flash when defined Define.As3 ->
 		{
@@ -558,7 +613,7 @@ let get_config com =
 			pf_overload = false;
 			pf_pattern_matching = false;
 			pf_can_skip_non_nullable_argument = false;
-			pf_ignore_unsafe_cast = false;
+			pf_reserved_type_paths = [];
 		}
 	| Flash ->
 		{
@@ -573,7 +628,7 @@ let get_config com =
 			pf_overload = false;
 			pf_pattern_matching = false;
 			pf_can_skip_non_nullable_argument = false;
-			pf_ignore_unsafe_cast = false;
+			pf_reserved_type_paths = [([],"Object")];
 		}
 	| Php ->
 		{
@@ -588,7 +643,7 @@ let get_config com =
 			pf_overload = false;
 			pf_pattern_matching = false;
 			pf_can_skip_non_nullable_argument = true;
-			pf_ignore_unsafe_cast = false;
+			pf_reserved_type_paths = [];
 		}
 	| Cpp ->
 		{
@@ -603,7 +658,7 @@ let get_config com =
 			pf_overload = false;
 			pf_pattern_matching = false;
 			pf_can_skip_non_nullable_argument = true;
-			pf_ignore_unsafe_cast = false;
+			pf_reserved_type_paths = [];
 		}
 	| Cs ->
 		{
@@ -618,7 +673,7 @@ let get_config com =
 			pf_overload = true;
 			pf_pattern_matching = false;
 			pf_can_skip_non_nullable_argument = true;
-			pf_ignore_unsafe_cast = false;
+			pf_reserved_type_paths = [];
 		}
 	| Java ->
 		{
@@ -633,7 +688,22 @@ let get_config com =
 			pf_overload = true;
 			pf_pattern_matching = false;
 			pf_can_skip_non_nullable_argument = true;
-			pf_ignore_unsafe_cast = false;
+			pf_reserved_type_paths = [];
+		}
+	| Python ->
+		{
+			pf_static = false;
+			pf_sys = true;
+			pf_locals_scope = false;
+			pf_captured_scope = false;
+			pf_unique_locals = false;
+			pf_capture_policy = CPLoopVars;
+			pf_pad_nulls = false;
+			pf_add_final_return = false;
+			pf_overload = false;
+			pf_pattern_matching = false;
+			pf_can_skip_non_nullable_argument = true;
+			pf_reserved_type_paths = [];
 		}
 
 let memory_marker = [|Unix.time()|]
@@ -673,6 +743,7 @@ let create v args =
 		net_libs = [];
 		net_std = [];
 		net_path_map = Hashtbl.create 0;
+		c_args = [];
 		neko_libs = [];
 		php_prefix = None;
 		js_gen = None;
@@ -691,6 +762,7 @@ let create v args =
 			tarray = (fun _ -> assert false);
 		};
 		file_lookup_cache = Hashtbl.create 0;
+		stored_typed_exprs = PMap.empty;
 		memory_marker = memory_marker;
 	}
 
@@ -737,6 +809,7 @@ let platforms = [
 	Cpp;
 	Cs;
 	Java;
+	Python;
 ]
 
 let platform_name = function
@@ -749,12 +822,13 @@ let platform_name = function
 	| Cpp -> "cpp"
 	| Cs -> "cs"
 	| Java -> "java"
+	| Python -> "python"
 
 let flash_versions = List.map (fun v ->
 	let maj = int_of_float v in
 	let min = int_of_float (mod_float (v *. 10.) 10.) in
 	v, string_of_int maj ^ (if min = 0 then "" else "_" ^ string_of_int min)
-) [9.;10.;10.1;10.2;10.3;11.;11.1;11.2;11.3;11.4;11.5;11.6;11.7;11.8;11.9;12.0;12.1;12.2;12.3;12.4;12.5]
+) [9.;10.;10.1;10.2;10.3;11.;11.1;11.2;11.3;11.4;11.5;11.6;11.7;11.8;11.9;12.0;13.0;14.0;15.0;16.0;17.0]
 
 let flash_version_tag = function
 	| 6. -> 6
@@ -775,11 +849,11 @@ let flash_version_tag = function
 	| 11.8 -> 21
 	| 11.9 -> 22
 	| 12.0 -> 23
-	| 12.1 -> 24
-	| 12.2 -> 25
-	| 12.3 -> 26
-	| 12.4 -> 27
-	| 12.5 -> 28
+	| 13.0 -> 24
+	| 14.0 -> 25
+	| 15.0 -> 26
+	| 16.0 -> 27
+	| 17.0 -> 28
 	| v -> failwith ("Invalid SWF version " ^ string_of_float v)
 
 let raw_defined ctx v =
@@ -827,6 +901,17 @@ let add_feature com f =
 let has_dce com =
 	(try defined_value com Define.Dce <> "no" with Not_found -> false)
 
+(*
+	TODO: The has_dce check is there because we mark types with @:directlyUsed in the DCE filter,
+	which is not run in dce=no and thus we can't know if a type is used directly or not,
+	so we just assume that they are.
+
+	If we had dce filter always running (even with dce=no), we would have types marked with @:directlyUsed
+	and we wouldn't need to generate unnecessary imports in dce=no, but that's good enough for now.
+*)
+let is_directly_used com meta =
+	not (has_dce com) || Ast.Meta.has Ast.Meta.DirectlyUsed meta
+
 let rec has_feature com f =
 	try
 		Hashtbl.find com.features f
@@ -878,16 +963,17 @@ let find_file ctx f =
 	with Exit ->
 		raise Not_found
 	| Not_found ->
-		let rec loop = function
-			| [] -> raise Not_found
+		let rec loop had_empty = function
+			| [] when had_empty -> raise Not_found
+			| [] -> loop true [""]
 			| p :: l ->
 				let file = p ^ f in
 				if Sys.file_exists file then
 					file
 				else
-					loop l
+					loop (had_empty || p = "") l
 		in
-		let r = (try Some (loop ctx.class_path) with Not_found -> None) in
+		let r = (try Some (loop false ctx.class_path) with Not_found -> None) in
 		Hashtbl.add ctx.file_lookup_cache f r;
 		(match r with
 		| None -> raise Not_found
@@ -920,6 +1006,14 @@ let rec mkdir_recursive base dir_list =
 				Unix.mkdir path 0o755;
 		mkdir_recursive (if (path = "") then "/" else path) remaining
 
+let mkdir_from_path path =
+	let parts = Str.split_delim (Str.regexp "[\\/]+") path in
+	match parts with
+		| [] -> (* path was "" *) ()
+		| _ ->
+			let dir_list = List.rev (List.tl (List.rev parts)) in
+			mkdir_recursive "" dir_list
+
 let mem_size v =
 	Objsize.size_with_headers (Objsize.objsize v [] [])
 

+ 216 - 54
dce.ml

@@ -30,6 +30,7 @@ type dce = {
 	std_dirs : string list;
 	debug : bool;
 	follow_expr : dce -> texpr -> unit;
+	mutable curclass : tclass;
 	mutable added_fields : (tclass * tclass_field * bool) list;
 	mutable marked_fields : tclass_field list;
 	mutable marked_maybe_fields : tclass_field list;
@@ -71,6 +72,7 @@ let keep_field dce cf =
 	Meta.has Meta.Keep cf.cf_meta
 	|| Meta.has Meta.Used cf.cf_meta
 	|| cf.cf_name = "__init__"
+	|| is_extern_field cf
 
 (* marking *)
 
@@ -84,6 +86,10 @@ let rec check_feature dce s =
 	with Not_found ->
 		()
 
+and check_and_add_feature dce s =
+	check_feature dce s;
+	Common.add_feature dce.com s;
+
 (* mark a field as kept *)
 and mark_field dce c cf stat =
 	let add cf =
@@ -129,16 +135,21 @@ let rec update_marked_class_fields dce c =
 (* mark a class as kept. If the class has fields marked as @:?keep, make sure to keep them *)
 and mark_class dce c = if not (Meta.has Meta.Used c.cl_meta) then begin
 	c.cl_meta <- (Meta.Used,[],c.cl_pos) :: c.cl_meta;
+	check_feature dce (Printf.sprintf "%s.*" (s_type_path c.cl_path));
 	update_marked_class_fields dce c;
 end
 
 let rec mark_enum dce e = if not (Meta.has Meta.Used e.e_meta) then begin
 	e.e_meta <- (Meta.Used,[],e.e_pos) :: e.e_meta;
+	check_and_add_feature dce "has_enum";
+	check_feature dce (Printf.sprintf "%s.*" (s_type_path e.e_path));
 	PMap.iter (fun _ ef -> mark_t dce ef.ef_pos ef.ef_type) e.e_constrs;
 end
 
-and mark_abstract dce a = if not (Meta.has Meta.Used a.a_meta) then
+and mark_abstract dce a = if not (Meta.has Meta.Used a.a_meta) then begin
+	check_feature dce (Printf.sprintf "%s.*" (s_type_path a.a_path));
 	a.a_meta <- (Meta.Used,[],a.a_pos) :: a.a_meta
+end
 
 (* mark a type as kept *)
 and mark_t dce p t =
@@ -162,14 +173,16 @@ and mark_t dce p t =
 			List.iter (mark_t dce p) pl
 		| TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta ->
 			begin try
-				mark_t dce p (snd (Codegen.Abstract.find_multitype_specialization a pl p))
+				mark_t dce p (snd (Codegen.AbstractCast.find_multitype_specialization dce.com a pl p))
 			with Typecore.Error _ ->
 				()
 			end
 		| TAbstract(a,pl) ->
 			mark_abstract dce a;
-			List.iter (mark_t dce p) pl
-		| TLazy _ | TDynamic _ | TAnon _ | TType _ | TMono _ -> ()
+			List.iter (mark_t dce p) pl;
+			if not (Meta.has Meta.CoreType a.a_meta) then
+				mark_t dce p (Abstract.get_underlying_type a pl)
+		| TLazy _ | TDynamic _ | TType _ | TAnon _ | TMono _ -> ()
 		end;
 		dce.t_stack <- List.tl dce.t_stack
 	end
@@ -219,13 +232,13 @@ let rec to_string dce t = match t with
 	| TType(tt,tl) ->
 		if not (List.exists (fun t2 -> Type.fast_eq t t2) dce.ts_stack) then begin
 			dce.ts_stack <- t :: dce.ts_stack;
-			to_string dce (apply_params tt.t_types tl tt.t_type)
+			to_string dce (apply_params tt.t_params tl tt.t_type)
 		end
 	| TAbstract({a_impl = Some c} as a,tl) ->
 		if Meta.has Meta.CoreType a.a_meta then
 			field dce c "toString" false
 		else
-			to_string dce (Codegen.Abstract.get_underlying_type a tl)
+			to_string dce (Abstract.get_underlying_type a tl)
 	| TMono r ->
 		(match !r with
 		| Some t -> to_string dce t
@@ -251,23 +264,6 @@ and field dce c n stat =
 	(try
 		let cf = find_field n in
 		mark_field dce c cf stat;
-	with Not_found -> try
-		(* me might have a property access on an interface *)
- 		let l = String.length n - 4 in
-		if l < 0 then raise Not_found;
-		let prefix = String.sub n 0 4 in
-		let pn = String.sub n 4 l in
-		let cf = find_field pn in
-		let keep () =
-			mark_dependent_fields dce c n stat;
-			field dce c pn stat
-		in
-		(match prefix,cf.cf_kind with
-			| "get_",Var {v_read = AccCall} when "get_" ^ cf.cf_name = n -> keep()
-			| "set_",Var {v_write = AccCall} when "set_" ^ cf.cf_name = n -> keep()
-			| _ -> raise Not_found
-		);
-		raise Not_found
 	with Not_found -> try
 		if c.cl_interface then begin
 			let rec loop cl = match cl with
@@ -292,11 +288,63 @@ and field dce c n stat =
 	with Not_found ->
 		if dce.debug then prerr_endline ("[DCE] Field " ^ n ^ " not found on " ^ (s_type_path c.cl_path)) else ())
 
+and mark_directly_used_class c =
+	if not (Meta.has Meta.DirectlyUsed c.cl_meta) then
+		c.cl_meta <- (Meta.DirectlyUsed,[],c.cl_pos) :: c.cl_meta
+
+and mark_directly_used_enum e =
+	if not (Meta.has Meta.DirectlyUsed e.e_meta) then
+		e.e_meta <- (Meta.DirectlyUsed,[],e.e_pos) :: e.e_meta
+
+and mark_directly_used_mt mt =
+	match mt with
+	| TClassDecl c ->
+		mark_directly_used_class c
+	| TEnumDecl e ->
+		mark_directly_used_enum e
+	| _ ->
+		()
+
+and check_dynamic_write dce fa =
+	let n = field_name fa in
+	check_and_add_feature dce ("dynamic_write");
+	check_and_add_feature dce ("dynamic_write." ^ n)
+
+and check_anon_optional_write dce fa =
+	let n = field_name fa in
+	check_and_add_feature dce ("anon_optional_write");
+	check_and_add_feature dce ("anon_optional_write." ^ n)
+
+and check_anon_write dce fa =
+	let n = field_name fa in
+	check_and_add_feature dce ("anon_write");
+	check_and_add_feature dce ("anon_write." ^ n)
+
+and is_array t = match follow t with
+	| TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> is_array (Abstract.get_underlying_type a tl)
+	| TInst({ cl_path = ([], "Array")},_) -> true
+	| _ -> false
+
+and is_dynamic t = match follow t with
+	| TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> is_dynamic (Abstract.get_underlying_type a tl)
+	| TDynamic _ -> true
+	| _ -> false
+
+and is_string t = match follow t with
+	| TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> is_string (Abstract.get_underlying_type a tl)
+	| TInst( { cl_path = ([], "String")}, _) -> true
+	| _ -> false
+
+and is_const_string e = match e.eexpr with
+	| TConst(TString(_)) -> true
+	| _ -> false
+
 and expr dce e =
 	mark_t dce e.epos e.etype;
 	match e.eexpr with
 	| TNew(c,pl,el) ->
 		mark_class dce c;
+		mark_directly_used_class c;
 		field dce c "new" false;
 		List.iter (expr dce) el;
 		List.iter (mark_t dce e.epos) pl;
@@ -306,9 +354,14 @@ and expr dce e =
 	| TCast(e, Some mt) ->
 		check_feature dce "typed_cast";
 		mark_mt dce mt;
+		mark_directly_used_mt mt;
 		expr dce e;
+	| TObjectDecl(vl) ->
+		check_and_add_feature dce "has_anon";
+		List.iter (fun (_,e) -> expr dce e) vl;
 	| TTypeExpr mt ->
-		mark_mt dce mt
+		mark_mt dce mt;
+		mark_directly_used_mt mt;
 	| TTry(e, vl) ->
 		expr dce e;
 		List.iter (fun (v,e) ->
@@ -316,10 +369,15 @@ and expr dce e =
 			expr dce e;
 			mark_t dce e.epos v.v_type;
 		) vl;
+	| TCall ({eexpr = TLocal ({v_name = "`trace"})},[p;{ eexpr = TObjectDecl(v)}]) ->
+		check_and_add_feature dce "has_anon_trace";
+		List.iter (fun (_,e) -> expr dce e) v;
+		expr dce p;
 	| TCall ({eexpr = TLocal ({v_name = "__define_feature__"})},[{eexpr = TConst (TString ft)};e]) ->
-		Common.add_feature dce.com ft;
+		Hashtbl.replace dce.curclass.cl_module.m_extra.m_features ft true;
 		check_feature dce ft;
-		expr dce e
+		expr dce e;
+
 	(* keep toString method when the class is argument to Std.string or haxe.Log.trace *)
 	| TCall ({eexpr = TField({eexpr = TTypeExpr (TClassDecl ({cl_path = (["haxe"],"Log")} as c))},FStatic (_,{cf_name="trace"}))} as ef, ((e2 :: el) as args))
 	| TCall ({eexpr = TField({eexpr = TTypeExpr (TClassDecl ({cl_path = ([],"Std")} as c))},FStatic (_,{cf_name="string"}))} as ef, ((e2 :: el) as args)) ->
@@ -345,16 +403,92 @@ and expr dce e =
 	| TCall ({eexpr = TConst TSuper} as e,el) ->
 		mark_t dce e.epos e.etype;
 		List.iter (expr dce) el;
+	| TBinop(OpAdd,e1,e2) when is_dynamic e1.etype || is_dynamic e2.etype ->
+		check_and_add_feature dce "add_dynamic";
+		expr dce e1;
+		expr dce e2;
+	| TBinop( (OpAdd | (OpAssignOp OpAdd)),e1,e2) when ((is_string e1.etype || is_string e2.etype) && not ( is_const_string e1 && is_const_string e2)) ->
+		check_and_add_feature dce "unsafe_string_concat";
+		expr dce e1;
+		expr dce e2;
+	| TArray(({etype = TDynamic t} as e1),e2) when t == t_dynamic ->
+		check_and_add_feature dce "dynamic_array_read";
+		expr dce e1;
+		expr dce e2;
+	| TBinop( (OpAssign | OpAssignOp _), ({eexpr = TArray({etype = TDynamic t},_)} as e1), e2) when t == t_dynamic ->
+		check_and_add_feature dce "dynamic_array_write";
+		expr dce e1;
+		expr dce e2;
+	| TArray(({etype = t} as e1),e2) when is_array t ->
+		check_and_add_feature dce "array_read";
+		expr dce e1;
+		expr dce e2;
+	| TBinop( (OpAssign | OpAssignOp _), ({eexpr = TArray({etype = t},_)} as e1), e2) when is_array t ->
+		check_and_add_feature dce "array_write";
+		expr dce e1;
+		expr dce e2;
+	| TBinop(OpAssign,({eexpr = TField(_,(FDynamic _ as fa) )} as e1),e2) ->
+		check_dynamic_write dce fa;
+		expr dce e1;
+		expr dce e2;
+	| TBinop(OpAssign,({eexpr = TField(_,(FAnon cf as fa) )} as e1),e2) ->
+		if Meta.has Meta.Optional cf.cf_meta then
+			check_anon_optional_write dce fa
+		else
+			check_anon_write dce fa;
+		expr dce e1;
+		expr dce e2;
+	| TBinop(OpAssignOp op,({eexpr = TField(_,(FDynamic _ as fa) )} as e1),e2) ->
+		check_dynamic_write dce fa;
+		expr dce e1;
+		expr dce e2;
+	| TBinop(OpAssignOp op,({eexpr = TField(_,(FAnon cf as fa) )} as e1),e2) ->
+		if Meta.has Meta.Optional cf.cf_meta then
+			check_anon_optional_write dce fa
+		else
+			check_anon_write dce fa;
+		expr dce e1;
+		expr dce e2;
+	| TBinop(OpEq,({ etype = t1} as e1), ({ etype = t2} as e2) ) when is_dynamic t1 || is_dynamic t2 ->
+		check_and_add_feature dce "dynamic_binop_==";
+		expr dce e1;
+		expr dce e2;
+	| TBinop(OpEq,({ etype = t1} as e1), ({ etype = t2} as e2) ) when is_dynamic t1 || is_dynamic t2 ->
+		check_and_add_feature dce "dynamic_binop_!=";
+		expr dce e1;
+		expr dce e2;
+	| TBinop(OpMod,e1,e2) ->
+		check_and_add_feature dce "binop_%";
+		expr dce e1;
+		expr dce e2;
+	| TBinop(OpUShr,e1,e2) ->
+		check_and_add_feature dce "binop_>>>";
+		expr dce e1;
+		expr dce e2;
 	| TField(e,fa) ->
 		begin match fa with
 			| FStatic(c,cf) ->
 				mark_class dce c;
 				mark_field dce c cf true;
-			| FInstance(c,cf) ->
+			| FInstance(c,_,cf) ->
 				mark_class dce c;
 				mark_field dce c cf false;
 			| _ ->
+
 				let n = field_name fa in
+				(match fa with
+				| FAnon cf ->
+					if Meta.has Meta.Optional cf.cf_meta then begin
+						check_and_add_feature dce "anon_optional_read";
+						check_and_add_feature dce ("anon_optional_read." ^ n);
+					end else begin
+						check_and_add_feature dce "anon_read";
+						check_and_add_feature dce ("anon_read." ^ n);
+					end
+				| FDynamic _ ->
+					check_and_add_feature dce "dynamic_read";
+					check_and_add_feature dce ("dynamic_read." ^ n);
+				| _ -> ());
 				begin match follow e.etype with
 					| TInst(c,_) ->
 						mark_class dce c;
@@ -365,16 +499,43 @@ and expr dce e =
 							mark_class dce c;
 							field dce c n true;
 						| _ -> ())
+
+
 					| _ -> ()
 				end;
 		end;
 		expr dce e;
 	| TThrow e ->
+		check_and_add_feature dce "has_throw";
 		to_string dce e.etype;
 		expr dce e
 	| _ ->
 		Type.iter (expr dce) e
 
+let fix_accessors com =
+	List.iter (fun mt -> match mt with
+		| (TClassDecl c) ->
+			let rec has_accessor c n stat =
+				PMap.mem n (if stat then c.cl_statics else c.cl_fields)
+				|| match c.cl_super with Some (csup,_) -> has_accessor csup n stat | None -> false
+			in
+			let check_prop stat cf =
+				(match cf.cf_kind with
+				| Var {v_read = AccCall; v_write = a} ->
+					let s = "get_" ^ cf.cf_name in
+					cf.cf_kind <- Var {v_read = if has_accessor c s stat then AccCall else AccNever; v_write = a}
+				| _ -> ());
+				(match cf.cf_kind with
+				| Var {v_write = AccCall; v_read = a} ->
+					let s = "set_" ^ cf.cf_name in
+					cf.cf_kind <- Var {v_write = if has_accessor c s stat then AccCall else AccNever; v_read = a}
+				| _ -> ())
+			in
+			List.iter (check_prop true) c.cl_ordered_statics;
+			List.iter (check_prop false) c.cl_ordered_fields;
+		| _ -> ()
+	) com.types
+
 let run com main full =
 	let dce = {
 		com = com;
@@ -388,6 +549,7 @@ let run com main full =
 		t_stack = [];
 		ts_stack = [];
 		features = Hashtbl.create 0;
+		curclass = null_class;
 	} in
 	begin match main with
 		| Some {eexpr = TCall({eexpr = TField(e,(FStatic(c,cf)))},_)} ->
@@ -399,7 +561,7 @@ let run com main full =
 		List.iter (fun (s,v) ->
 			if Hashtbl.mem dce.features s then Hashtbl.replace dce.features s (v :: Hashtbl.find dce.features s)
 			else Hashtbl.add dce.features s [v]
-		) m.m_extra.m_features;
+		) m.m_extra.m_if_feature;
 	) com.modules;
 	(* first step: get all entry points, which is the main method and all class methods which are marked with @:keep *)
 	List.iter (fun t -> match t with
@@ -413,7 +575,16 @@ let run com main full =
 			begin match c.cl_constructor with
 				| Some cf -> loop false cf
 				| None -> ()
-			end
+			end;
+			begin match c.cl_init with
+				| Some e when keep_class || Meta.has Meta.KeepInit c.cl_meta ->
+					(* create a fake field to deal with our internal logic (issue #3286) *)
+					let cf = mk_field "__init__" e.etype e.epos in
+					cf.cf_expr <- Some e;
+					loop true cf
+				| _ ->
+					()
+			end;
 		| TEnumDecl en when keep_whole_enum dce en ->
 			mark_enum dce en
 		| _ ->
@@ -435,12 +606,13 @@ let run com main full =
 			List.iter (fun (c,cf,stat) -> mark_dependent_fields dce c cf.cf_name stat) cfl;
 			(* mark fields as used *)
 			List.iter (fun (c,cf,stat) ->
-				mark_class dce c;
+				if not (is_extern_field cf) then mark_class dce c;
 				mark_field dce c cf stat;
 				mark_t dce cf.cf_pos cf.cf_type
 			) cfl;
 			(* follow expressions to new types/fields *)
-			List.iter (fun (_,cf,_) ->
+			List.iter (fun (c,cf,_) ->
+				dce.curclass <- c;
 				opt (expr dce) cf.cf_expr;
 				List.iter (fun cf -> if cf.cf_expr <> None then opt (expr dce) cf.cf_expr) cf.cf_overloads
 			) cfl;
@@ -499,8 +671,10 @@ let run com main full =
 				b
 			) c.cl_ordered_fields;
 			(match c.cl_constructor with Some cf when not (keep_field dce cf) -> c.cl_constructor <- None | _ -> ());
+			let inef cf = not (is_extern_field cf) in
+			let has_non_extern_fields = List.exists inef c.cl_ordered_fields || List.exists inef c.cl_ordered_statics in
 			(* we keep a class if it was used or has a used field *)
-			if Meta.has Meta.Used c.cl_meta || c.cl_ordered_statics <> [] || c.cl_ordered_fields <> [] then loop (mt :: acc) l else begin
+			if Meta.has Meta.Used c.cl_meta || has_non_extern_fields then loop (mt :: acc) l else begin
 				(match c.cl_init with
 				| Some f when Meta.has Meta.KeepInit c.cl_meta ->
 					(* it means that we only need the __init__ block *)
@@ -523,28 +697,7 @@ let run com main full =
 	com.types <- loop [] (List.rev com.types);
 
 	(* extra step to adjust properties that had accessors removed (required for Php and Cpp) *)
-	List.iter (fun mt -> match mt with
-		| (TClassDecl c) ->
-			let rec has_accessor c n stat =
-				PMap.mem n (if stat then c.cl_statics else c.cl_fields)
-				|| match c.cl_super with Some (csup,_) -> has_accessor csup n stat | None -> false
-			in
-			let check_prop stat cf =
-				(match cf.cf_kind with
-				| Var {v_read = AccCall; v_write = a} ->
-					let s = "get_" ^ cf.cf_name in
-					cf.cf_kind <- Var {v_read = if has_accessor c s stat then AccCall else AccNever; v_write = a}
-				| _ -> ());
-				(match cf.cf_kind with
-				| Var {v_write = AccCall; v_read = a} ->
-					let s = "set_" ^ cf.cf_name in
-					cf.cf_kind <- Var {v_write = if has_accessor c s stat then AccCall else AccNever; v_read = a}
-				| _ -> ())
-			in
-			List.iter (check_prop true) c.cl_ordered_statics;
-			List.iter (check_prop false) c.cl_ordered_fields;
-		| _ -> ()
-	) com.types;
+	fix_accessors com;
 
 	(* remove "override" from fields that do not override anything anymore *)
 	List.iter (fun mt -> match mt with
@@ -561,6 +714,15 @@ let run com main full =
 		| _ -> ()
 	) com.types;
 
+	(* mark extern classes as really used if they are extended by non-extern ones *)
+	List.iter (function
+		| TClassDecl ({cl_extern = false; cl_super = Some ({cl_extern = true} as csup, _)}) ->
+			mark_directly_used_class csup
+		| TClassDecl ({cl_extern = false} as c) when c.cl_implements <> [] ->
+			List.iter (fun (iface,_) -> if (iface.cl_extern) then mark_directly_used_class iface) c.cl_implements;
+		| _ -> ()
+	) com.types;
+
 	(* cleanup added fields metadata - compatibility with compilation server *)
 	let rec remove_meta m = function
 		| [] -> []

+ 121 - 1
extra/CHANGES.txt

@@ -1,3 +1,123 @@
+2015-03-15: 3.2.0-RC1
+
+	New features:
+
+	all : added --display mode for toplevel completion
+	all : added --display mode for position and usage information
+	all : allowed @:callable on abstracts to forward calls to their underlying type
+	all : allowed pattern matching on getters
+	all : allowed @:native on class fields
+	all : added static analyzer with constant propagation
+	all : added Haxe-based XML implementation
+	python : added python target
+	flash : flash player 12-14 support
+	js : added @:jsRequire and js.Lib.require
+	cs : added @:bridgeProperties
+	cs : added -D erase_generics
+	cs : added -D dll_import to import haxe-generated dlls
+	java/cs : added `sys.db` package
+	java/cs : clean unused files in output folder, unless `-D keep_old_output` is defined
+	java/cs : added `-c-arg` to add C#/Java compiler arguments
+	cpp : inititial implementation of cppia scripting
+
+	Bugfixes:
+
+	all : fixed nullability of abstracts over functions
+	all : fixed some equality checks between UInt and Int
+	all : fixed rare issue with abstract casts
+	all : fixed some internal code which relied on unspecified evaluation order
+	all : fixed exhaustiveness checks involving guards
+	all : fixed issue involving recursively constrained type parameters and @:generic
+	all : fixed type inference issue in map literals
+	all : fixed type inference issue when calling abstract method from within the abstract
+	all : fixed several abstract variance issues
+	all : fixed DCE issues with interface properties
+	all : fixed variance issue with function variables and dynamic methods on interfaces
+	all : fixed pattern matching on empty arrays that are typed as Dynamic
+	all : fixed various @:generic issues
+	all : fixed default cases on @:enum abstract being omitted
+	all : fixed various expression positions
+	all : disallowed break/continue in closures in loops
+	all : disallowed inline functions in value places
+	all : fixed parsing of cast followed by parentheses
+	all : fixed resource naming in case of invalid file system characters
+	all : fixed issue with inlined array declarations with field access
+	cpp : fixed issue with the side-effect handler
+	cpp : fixed issue with NativeArray in --no-inline mode
+	php : fixed issue with invalid references for closures in for-loops
+	php : fixed Reflect.compare and string comparison for numeric strings
+	cs/java : fixed various issues with -java-lib and -net-lib. 
+	cs/java : added @:libType to skip checking on -java-lib / -net-lib types
+	cs/java : compilation server now works with C#/Java [experimental support]
+	cs : fixed Type.enumIndex / switch on C# native enums
+	cs : fixed reflection on COM types
+	java : fixed sys.net.Socket server implementation
+	spod : various fixes - working now on cpp, java, neko, php and c#
+	cpp : improved boot order, with enums constants first
+
+	General improvements and optimizations:
+
+	all : disallowed using `super` in value positions
+	all : check exhaustiveness of explicit Null types
+	all : resolve unqualified identifiers to @:enum abstract constructors
+	all : determine @:generic type parameters from constructor call if possible
+	all : properly disallowed field redefinition in extending interface
+	all : properly disallowed leading zeroes for Int and Float literals
+	all : allowed variance on interface variables
+	all : allowed pattern matching on arrays if they are typed as Dynamic
+	all : allowed pattern matching on fields of parent classes
+	all : -D doc-gen no longer implies -dce no
+	all : allowed matching against null on any enum instance
+	flash/js: optimized haxe.ds.StringMap
+	neko : create output directory if it does not exist
+	js : inline Math methods and fields
+	cs/java : optimized Reflect.fields on dynamic structures
+	cs/java : haxe will now clear output directory of old files (use -D keep-old-output to keep them)
+	cs : optimized field lookup structure
+	cs : optimized casting of parametrized types
+	cs : beautify c# code output
+	cs : added `cs.Flags` to manipulate C# enums that can be also flags
+	xml : improved documentation generation and fixed missing entity escaping
+	cpp : property access via Dynamic variables now requires property to be declared with @:nativeProperty
+	cpp : allow injection of code from relative paths using @:sourceFile and @:cppInclude
+	cpp : stronger typing of native functions via cpp.Function + cpp.Callable
+	cpp : moved 'Class' implementation to hx namespace to improve objective C interaction
+	cpp : added file_extension define to change the output filename extension (eg, ".mm")
+	cpp : added pre-calculated hashes to string constants to allow faster lookups
+	cpp : map implementation allows strongly typed interactions in some cases (avoids boxing)
+	cpp : added native WeakMap implementation
+	cpp : put each resource into own cpp file to allow more data/smaller files
+
+	Standard Library:
+
+	all : added typed arrays to haxe.io package
+	all : added haxe.ds.Either
+	all : added haxe.extern.Rest type for representing "rest" arguments in extern method signatures
+	all : added haxe.extern.EitherType abstract type for dealing with externs for dynamic targets
+	all : added haxe.DynamicAccess type for working with dynamic anonymous structures using a Map-like interface
+	all : [breaking] changed haxe.ds.Vector.get to return T instead of Null<T>
+	all : added haxe.macro.Compiler.addGlobalMetadata
+	all : changed haxe.Int64 to be an abstract type instead of a class
+	js : updated HTML externs
+
+	Macro features and changes:
+
+	macro : added Context.getLocalTVars
+	macro : added TypedExprTools.iter
+	macro : added Context.getCallArguments
+	macro : changed @:genericBuild macros to prefer ComplexType returns
+	macro : [breaking] extended TAnonymous structures now have AExtend status instead of AClosed
+	macro : added Context.getDefines
+	macro : fixed file_seek from end (position was inversed)
+	macro : added Context.storeTypedExpr
+	macro : allowed type name reification
+
+	Deprecations:
+
+	all : deprecated structurally extending classes and interfaces
+	sys : Sys.command shell special chars (&|<>#;*?(){}$) are now properly escaped
+	java/cs : Lib.nativeType is now renamed to Lib.getNativeType
+
 2014-04-13: 3.1.3
 
 	Bugfixes:
@@ -601,7 +721,7 @@
 	php: minor optimization (removed foreach from std code)
 	php: implemented haxe.Stack
 	php: changed exception handler to use Haxe call stack
-	php: changed special vars to use the » prefix instead of __
+	php: changed special vars to use the '\xBB' prefix instead of __
 	php: fixed use of reserved keywords for var names
 	php: List iterator is now class based (faster)
 	php: fixed behavior of class variables having assigned functions

+ 3 - 2
extra/ImportAll.hx

@@ -44,14 +44,14 @@ class ImportAll {
 			if( !Context.defined("flash") || Context.defined("flash9") ) return;
 		case "flash":
 			if( !Context.defined("flash9") ) return;
-		case "mt","mtwin":
-			return;
 		case "sys":
 			if( !Context.defined("neko") && !Context.defined("php") && !Context.defined("cpp") ) return;
 		case "java":
 			if( !Context.defined("java") ) return;
 		case "cs":
 			if( !Context.defined("cs") ) return;
+		case "python":
+			if( !Context.defined("python") ) return;
 		case "tools":
 			return;
 		case "build-tool":
@@ -84,6 +84,7 @@ class ImportAll {
 					case "haxe.macro.ExampleJSGenerator","haxe.macro.Context", "haxe.macro.Compiler": if( !Context.defined("neko") ) continue;
 					case "haxe.remoting.SocketWrapper": if( !Context.defined("flash") ) continue;
 					case "haxe.remoting.SyncSocketConnection": if( !(Context.defined("neko") || Context.defined("php") || Context.defined("cpp")) ) continue;
+					case "sys.db.Sqlite" | "sys.db.Mysql" | "cs.db.AdoNet": continue;
 					}
 					Context.getModule(cl);
 				} else if( sys.FileSystem.isDirectory(p + "/" + file) )

+ 4 - 0
extra/all.hxml

@@ -47,6 +47,10 @@
 -xml cs.xml
 -D xmldoc
 
+--next
+-python all_python
+-xml python.xml
+
 --next
 
 -xml cross.xml

+ 2 - 2
extra/extract.hxml

@@ -1,6 +1,6 @@
 -debug
 -swf-lib library.swf
 -swf test.swf
--swf-version 11.8
---macro patchTypes("../doc/extract.patch")
+-swf-version 15
+--macro patchTypes("../extra/extract.patch")
 --gen-hx-classes

+ 15 - 5
extra/extract.patch

@@ -879,7 +879,7 @@ flash.globalization.StringTools.lastOperationStatus : LastOperationStatus;
 @:require(flash10_2) flash.media.Microphone.enhancedOptions;
 @:require(flash10_2) static flash.media.Microphone.getEnhancedMicrophone;
 
-@:require(flash11) static flash.system.Capabilities.allowsFullScreen;
+@:require(flash10_2) flash.system.Capabilities.allowsFullScreen;
 
 @:require(flash10_2) static flash.ui.Keyboard.AUDIO;
 @:require(flash10_2) static flash.ui.Keyboard.BACK;
@@ -937,7 +937,6 @@ enum flash.display.FocusDirection;
 
 @:require(flash11) flash.display.MovieClip.isPlaying;
 
-@:require(flash11) flash.display.Stage.allowsFullScreen;
 @:require(flash11) flash.display.Stage.displayContextInfo;
 @:require(flash11) flash.display.Stage.softKeyboardRect;
 @:require(flash11) flash.display.Stage.stage3Ds;
@@ -1073,15 +1072,15 @@ enum flash.display.BitmapCompressColorSpace;
 
 @:require(flash11_2) flash.display.StageWorker;
 @:require(flash11_2) flash.display.Worker;
-@:require(flash11_2) flash.events.GameInputEvent;
+@:require(flash11_8) flash.events.GameInputEvent;
 @:require(flash11_2) flash.events.ThrottleEvent;
 
 flash.events.ThrottleEvent.$type : ThrottleType;
 
 enum flash.events.ThrottleType;
 
-@:require(flash11_2) flash.ui.GameInput;
-@:require(flash11_2) flash.ui.GameInputDevice;
+@:require(flash11_8) flash.ui.GameInput;
+@:require(flash11_8) flash.ui.GameInputDevice;
 -flash.ui.GameInput.new;
 
 @:require(flash11_2) flash.utils.Telemetry;
@@ -1224,3 +1223,14 @@ flash.display3D.Context3D.$mipfilter : Context3DMipFilter;
 @:require(flash11_8) flash.display.DisplayObjectContainer.stopAllMovieClips
 @:require(flash11_8) flash.display3D.Context3D.createRectangleTexture
 
+@:require(flash12) flash.display.Stage3D.requestContext3DMatchingProfiles
+@:require(flash12) flash.display3D.Context3D.profile
+
+flash.display3D.Context3D.$bufferUsage : Context3DBufferUsage
+enum flash.display3D.Context3DBufferUsage
+
+@:native("flash.profiler.Telemetry") flash.utils.Telemetry
+
+@:require(flash12) flash.display3D.Context3DBufferUsage
+
+

+ 1 - 1
extra/haxelib_src

@@ -1 +1 @@
-Subproject commit 2d2252dc3ad44a62834a029b8bdcef84d72db8f4
+Subproject commit 0204aa984100c3da3a527865656917d888642b20

+ 8 - 0
extra/release-checklist.txt

@@ -1,3 +1,11 @@
+# Preparing related projects
+
+- Check that haxelib is working
+- Make sure to update the haxelib submodule
+- Check that the run-time haxelibs are ready for release: hxcpp, hxjava, hxcs
+
+# Making the release
+
 - Make sure CHANGES.txt has a proper date set!
 - Make sure `version` in main.ml has the correct value.
 - Merge development branch into master.

+ 363 - 328
filters.ml

@@ -5,6 +5,14 @@ open Typecore
 
 (* PASS 1 begin *)
 
+let rec verify_ast e = match e.eexpr with
+	| TField(_) ->
+		()
+	| TTypeExpr(TClassDecl {cl_kind = KAbstractImpl a}) when not (Meta.has Meta.RuntimeValue a.a_meta) ->
+		error "Cannot use abstract as value" e.epos
+	| _ ->
+		Type.iter verify_ast e
+
 (*
 	Wraps implicit blocks in TIf, TFor, TWhile, TFunction and TTry with real ones
 *)
@@ -19,132 +27,17 @@ let rec blockify_ast e =
 	| TFunction tf ->
 		{e with eexpr = TFunction {tf with tf_expr = mk_block (blockify_ast tf.tf_expr)}}
 	| TTry(e1,cl) ->
-		{e with eexpr = TTry(blockify_ast e1,List.map (fun (v,e) -> v,mk_block (blockify_ast e)) cl)}
+		{e with eexpr = TTry(mk_block (blockify_ast e1),List.map (fun (v,e) -> v,mk_block (blockify_ast e)) cl)}
+	| TSwitch(e1,cases,def) ->
+		let e1 = blockify_ast e1 in
+		let cases = List.map (fun (el,e) ->
+			el,mk_block (blockify_ast e)
+		) cases in
+		let def = match def with None -> None | Some e -> Some (mk_block (blockify_ast e)) in
+		{e with eexpr = TSwitch(e1,cases,def)}
 	| _ ->
 		Type.map_expr blockify_ast e
 
-(*
-	Generates a block context which can be used to add temporary variables. It returns a tuple:
-
-	- a mapping function for expression lists to be used on TBlock elements
-	- the function to be called for declaring temporary variables
-	- the function to be called for closing the block, returning the block elements
-*)
-let mk_block_context com gen_temp =
-	let block_el = ref [] in
-	let push e = block_el := e :: !block_el in
-	let declare_temp t eo p =
-		let v = gen_temp t in
-		let e = mk (TVar (v,eo)) com.basic.tvoid p in
-		push e;
-		mk (TLocal v) t p
-	in
-	let push_block () =
-		let cur = !block_el in
-		block_el := [];
-		fun () ->
-			let added = !block_el in
-			block_el := cur;
-			List.rev added
-	in
-	let rec block f el =
-		let close = push_block() in
-		List.iter (fun e ->
-			push (f e)
-		) el;
-		close()
-	in
-	block,declare_temp,fun () -> !block_el
-
-(*
-	Moves expressions to temporary variables in order to ensure correct evaluation order. This effects
-
-	- call arguments (from TCall and TNew)
-	- array declaration arguments
-	- object fields
-	- binary operators (respects boolean short-circuit)
-	- array access
-*)
-let handle_side_effects com gen_temp e =
-	let block,declare_temp,close_block = mk_block_context com gen_temp in
-	let rec loop e =
-		match e.eexpr with
-		| TBlock el ->
-			{e with eexpr = TBlock (block loop el)}
-		| TCall({eexpr = TLocal v},_) when Meta.has Meta.Unbound v.v_meta ->
-			e
-		| TCall(e1,el) ->
-			let e1 = loop e1 in
-			{e with eexpr = TCall(e1,ordered_list el)}
-		| TNew(c,tl,el) ->
-			{e with eexpr = TNew(c,tl,ordered_list el)}
-		| TArrayDecl el ->
-			{e with eexpr = TArrayDecl (ordered_list el)}
-		| TObjectDecl fl ->
-			let el = ordered_list (List.map snd fl) in
-			{e with eexpr = TObjectDecl (List.map2 (fun (n,_) e -> n,e) fl el)}
-		| TBinop(OpBoolAnd | OpBoolOr as op,e1,e2) when Optimizer.has_side_effect e1 || Optimizer.has_side_effect e2 ->
-			let e1 = loop e1 in
-			let e_then = mk (TBlock (block loop [e2])) e2.etype e2.epos in
-			let e_if,e_else = if op = OpBoolOr then
-				mk (TUnop(Not,Prefix,e1)) com.basic.tbool e.epos,mk (TConst (TBool(true))) com.basic.tbool e.epos
-			else
-				e1,mk (TConst (TBool(false))) com.basic.tbool e.epos
-			in
-			mk (TIf(e_if,e_then,Some e_else)) com.basic.tbool e.epos
-		| TBinop((OpAssign | OpAssignOp _) as op,{eexpr = TArray(e11,e12)},e2) ->
-			let e1 = match ordered_list [e11;e12] with
-				| [e1;e2] ->
-					{e with eexpr = TArray(e1,e2)}
-				| _ ->
-					assert false
-			in
-			let e2 = loop e2 in
-			{e with eexpr = TBinop(op,e1,e2)}
- 		| TBinop(op,e1,e2) ->
-			begin match ordered_list [e1;e2] with
-				| [e1;e2] ->
-					{e with eexpr = TBinop(op,e1,e2)}
-				| _ ->
-					assert false
-			end
-		| TArray(e1,e2) ->
-			begin match ordered_list [e1;e2] with
-				| [e1;e2] ->
-					{e with eexpr = TArray(e1,e2)}
-				| _ ->
-					assert false
-			end
-		| TWhile(e1,e2,flag) when (match e1.eexpr with TParenthesis {eexpr = TConst(TBool true)} -> false | _ -> true) ->
-			let p = e.epos in
-			let e_break = mk TBreak t_dynamic p in
-			let e_not = mk (TUnop(Not,Prefix,Codegen.mk_parent e1)) e1.etype e1.epos in
-			let e_if = mk (TIf(e_not,e_break,None)) com.basic.tvoid p in
-			let e_block = if flag = NormalWhile then Type.concat e_if e2 else Type.concat e2 e_if in
-			let e_true = mk (TConst (TBool true)) com.basic.tbool p in
-			let e = mk (TWhile(Codegen.mk_parent e_true,e_block,NormalWhile)) e.etype p in
-			loop e
-		| _ ->
-			Type.map_expr loop e
-	and ordered_list el =
-		let bind e =
-			declare_temp e.etype (Some (loop e)) e.epos
-		in
-		let rec no_side_effect e =
-			if Optimizer.has_side_effect e then
-				bind e
-			else
-				e
-		in
-		List.map no_side_effect el
-	in
-	let e = loop e in
-	match close_block() with
-		| [] ->
-			e
-		| el ->
-			mk (TBlock (List.rev (e :: el))) e.etype e.epos
-
 (*
 	Pushes complex right-hand side expression inwards.
 
@@ -152,11 +45,11 @@ let handle_side_effects com gen_temp e =
 	x = { exprs; value; } -> { exprs; x = value; }
 	var x = { exprs; value; } -> { var x; exprs; x = value; }
 *)
-let promote_complex_rhs ctx e =
+let promote_complex_rhs com e =
 	let rec is_complex e = match e.eexpr with
 		| TBlock _ | TSwitch _ | TIf _ | TTry _ | TCast(_,Some _) -> true
 		| TBinop(_,e1,e2) -> is_complex e1 || is_complex e2
-		| TParenthesis e | TMeta(_,e) | TCast(e, None) -> is_complex e
+		| TParenthesis e | TMeta(_,e) | TCast(e, None) | TField(e,_) -> is_complex e
 		| _ -> false
 	in
 	let rec loop f e = match e.eexpr with
@@ -166,19 +59,19 @@ let promote_complex_rhs ctx e =
 				| [] -> e
 			end
 		| TSwitch(es,cases,edef) ->
-			{e with eexpr = TSwitch(es,List.map (fun (el,e) -> List.map find el,loop f e) cases,match edef with None -> None | Some e -> Some (loop f e))}
+			{e with eexpr = TSwitch(es,List.map (fun (el,e) -> List.map find el,loop f e) cases,match edef with None -> None | Some e -> Some (loop f e)); }
 		| TIf(eif,ethen,eelse) ->
-			{e with eexpr = TIf(find eif, loop f ethen, match eelse with None -> None | Some e -> Some (loop f e))}
+			{e with eexpr = TIf(find eif, loop f ethen, match eelse with None -> None | Some e -> Some (loop f e)); }
 		| TTry(e1,el) ->
-			{e with eexpr = TTry(loop f e1, List.map (fun (el,e) -> el,loop f e) el)}
-		| TParenthesis e1 when not (Common.defined ctx Define.As3) ->
+			{e with eexpr = TTry(loop f e1, List.map (fun (el,e) -> el,loop f e) el); }
+		| TParenthesis e1 when not (Common.defined com Define.As3) ->
 			{e with eexpr = TParenthesis(loop f e1)}
 		| TMeta(m,e1) ->
 			{ e with eexpr = TMeta(m,loop f e1)}
 		| TReturn _ | TThrow _ ->
 			find e
-		| TCast(e1,None) when ctx.config.pf_ignore_unsafe_cast ->
-			loop f e1
+		| TContinue | TBreak ->
+			e
 		| _ ->
 			f (find e)
 	and block el =
@@ -188,18 +81,21 @@ let promote_complex_rhs ctx e =
 			| TVar(v,eo) ->
 				begin match eo with
 					| Some e when is_complex e ->
+						let e = find e in
 						r := (loop (fun e -> mk (TBinop(OpAssign,mk (TLocal v) v.v_type e.epos,e)) v.v_type e.epos) e)
-							:: ((mk (TVar (v,None)) ctx.basic.tvoid e.epos))
+							:: ((mk (TVar (v,None)) com.basic.tvoid e.epos))
 							:: !r
 					| Some e ->
-						r := (mk (TVar (v,Some (find e))) ctx.basic.tvoid e.epos) :: !r
-					| None -> r := (mk (TVar (v,None)) ctx.basic.tvoid e.epos) :: !r
+						r := (mk (TVar (v,Some (find e))) com.basic.tvoid e.epos) :: !r
+					| None -> r := (mk (TVar (v,None)) com.basic.tvoid e.epos) :: !r
 				end
+			| TReturn (Some e1) when (match follow e1.etype with TAbstract({a_path=[],"Void"},_) -> true | _ -> false) ->
+				r := ({e with eexpr = TReturn None}) :: e1 :: !r
 			| _ -> r := (find e) :: !r
 		) el;
 		List.rev !r
 	and find e = match e.eexpr with
-		| TReturn (Some e1) -> loop (fun e -> {e with eexpr = TReturn (Some e)}) e1
+		| TReturn (Some e1) -> loop (fun er -> {e with eexpr = TReturn (Some er)}) e1
 		| TBinop(OpAssign | OpAssignOp _ as op, ({eexpr = TLocal _ | TField _ | TArray _} as e1), e2) -> loop (fun er -> {e with eexpr = TBinop(op, e1, er)}) e2
 		| TBlock(el) -> {e with eexpr = TBlock (block el)}
 		| _ -> Type.map_expr find e
@@ -342,26 +238,6 @@ let check_local_vars_init e =
 			| Some e ->
 				loop vars e;
 				join vars cvars)
-		| TPatMatch dt ->
-			let cvars = ref [] in
-			let rec fdt dt = match dt with
-				| DTExpr e ->
-					let old = !vars in
-					loop vars e;
-					restore vars old [];
-					cvars := !vars :: !cvars
-				| DTSwitch(e,cl,dto) ->
-					loop vars e;
-					List.iter (fun (_,dt) -> fdt dt) cl;
-					(match dto with None -> () | Some dt -> fdt dt)
-				| DTGuard(e,dt1,dt2) ->
-					fdt dt1;
-					(match dt2 with None -> () | Some dt -> fdt dt)
-				| DTBind(_,dt) -> fdt dt
-				| DTGoto _ -> ()
-			in
-			Array.iter fdt dt.dt_dt_lookup;
-			join vars !cvars
 		(* mark all reachable vars as initialized, since we don't exit the block  *)
 		| TBreak | TContinue | TReturn None ->
 			vars := PMap.map (fun _ -> true) !vars
@@ -401,9 +277,15 @@ type usage =
 	| Function of ((usage -> unit) -> unit)
 	| Declare of tvar
 	| Use of tvar
+	| Assign of tvar
 
 let rec local_usage f e =
 	match e.eexpr with
+	| TBinop ((OpAssign | OpAssignOp _), { eexpr = TLocal v }, e2) ->
+		local_usage f e2;
+		f (Assign v)
+	| TUnop ((Increment | Decrement), _, { eexpr = TLocal v }) ->
+		f (Assign v)
 	| TLocal v ->
 		f (Use v)
 	| TVar (v,eo) ->
@@ -435,33 +317,6 @@ let rec local_usage f e =
 				local_usage f e;
 			))
 		) catchs;
-	| TPatMatch dt ->
-		List.iter (fun (v,eo) ->
-			f (Declare v);
-			match eo with None -> () | Some e -> local_usage f e
-		) dt.dt_var_init;
-		let rec fdt dt = match dt with
-			| DTBind(bl,dt) ->
-				List.iter (fun ((v,_),e) ->
-					f (Declare v);
-					local_usage f e
-				) bl;
-				fdt dt
-			| DTExpr e -> local_usage f e
-			| DTGuard(e,dt1,dt2) ->
-				local_usage f e;
-				fdt dt1;
-				(match dt2 with None -> () | Some dt -> fdt dt)
-			| DTSwitch(e,cl,dto) ->
-				local_usage f e;
-				List.iter (fun (e,dt) ->
-					local_usage f e;
-					fdt dt
-				) cl;
-				(match dto with None -> () | Some dt -> fdt dt)
-			| DTGoto _ -> ()
-		in
-		Array.iter fdt dt.dt_dt_lookup
 	| _ ->
 		iter (local_usage f) e
 
@@ -469,62 +324,83 @@ let captured_vars com e =
 
 	let t = com.basic in
 
-	let rec mk_init av v pos =
-		mk (TVar (av,Some (mk (TArrayDecl [mk (TLocal v) v.v_type pos]) av.v_type pos))) t.tvoid pos
+	let impl = match com.platform with
+	(* optimized version for C#/Java - use native arrays *)
+	| Cs | Java ->
+		let cnativearray =
+			match (List.find (fun md -> match md with
+					| TClassDecl ({ cl_path = ["cs"|"java"],"NativeArray" }) -> true
+					| _ -> false
+				) com.types)
+			with TClassDecl cl -> cl | _ -> assert false
+		in
+
+		object
+			method captured_type t = TInst (cnativearray,[t])
+
+			method mk_ref v ve p =
+				match ve with
+				| None ->
+					let eone = mk (TConst (TInt (Int32.of_int 1))) t.tint p in
+					let t = match v.v_type with TInst (_, [t]) -> t | _ -> assert false in
+					mk (TNew (cnativearray,[t],[eone])) v.v_type p
+				| Some e ->
+					{ (Optimizer.mk_untyped_call "__array__" p [e]) with etype = v.v_type }
+
+			method mk_ref_access e v =
+				mk (TArray ({ e with etype = v.v_type }, mk (TConst (TInt 0l)) t.tint e.epos)) e.etype e.epos
 
-	and mk_var v used =
+			method mk_init av v pos =
+				let elocal = mk (TLocal v) v.v_type pos in
+				let earray = { (Optimizer.mk_untyped_call "__array__" pos [elocal]) with etype = av.v_type } in
+				mk (TVar (av,Some earray)) t.tvoid pos
+		end
+	(* default implementation - use haxe array *)
+	| _ ->
+		object
+			method captured_type = t.tarray
+			method mk_ref v ve p =
+				mk (TArrayDecl (match ve with None -> [] | Some e -> [e])) v.v_type p
+			method mk_ref_access e v =
+				mk (TArray ({ e with etype = v.v_type }, mk (TConst (TInt 0l)) t.tint e.epos)) e.etype e.epos
+			method mk_init av v pos =
+				mk (TVar (av,Some (mk (TArrayDecl [mk (TLocal v) v.v_type pos]) av.v_type pos))) t.tvoid pos
+		end
+	in
+
+	let mk_var v used =
 		let v2 = alloc_var v.v_name (PMap.find v.v_id used) in
 		v2.v_meta <- v.v_meta;
 		v2
+	in
 
-	and wrap used e =
+	let rec wrap used e =
 		match e.eexpr with
 		| TVar (v,ve) ->
 			let v,ve =
 				if PMap.mem v.v_id used then
-					v, Some (mk (TArrayDecl (match ve with None -> [] | Some e -> [wrap used e])) v.v_type e.epos)
+					v, Some (impl#mk_ref v (Option.map (wrap used) ve) e.epos)
 				else
 					v, (match ve with None -> None | Some e -> Some (wrap used e))
 			 in
 			{ e with eexpr = TVar (v,ve) }
 		| TLocal v when PMap.mem v.v_id used ->
-			mk (TArray ({ e with etype = v.v_type },mk (TConst (TInt 0l)) t.tint e.epos)) e.etype e.epos
+			impl#mk_ref_access e v
 		| TFor (v,it,expr) when PMap.mem v.v_id used ->
 			let vtmp = mk_var v used in
 			let it = wrap used it in
 			let expr = wrap used expr in
-			mk (TFor (vtmp,it,Type.concat (mk_init v vtmp e.epos) expr)) e.etype e.epos
+			mk (TFor (vtmp,it,Type.concat (impl#mk_init v vtmp e.epos) expr)) e.etype e.epos
 		| TTry (expr,catchs) ->
 			let catchs = List.map (fun (v,e) ->
 				let e = wrap used e in
 				try
 					let vtmp = mk_var v used in
-					vtmp, Type.concat (mk_init v vtmp e.epos) e
+					vtmp, Type.concat (impl#mk_init v vtmp e.epos) e
 				with Not_found ->
 					v, e
 			) catchs in
 			mk (TTry (wrap used expr,catchs)) e.etype e.epos
-		(* TODO: find out this does *)
-(* 		| TMatch (expr,enum,cases,def) ->
-			let cases = List.map (fun (il,vars,e) ->
-				let pos = e.epos in
-				let e = ref (wrap used e) in
-				let vars = match vars with
-					| None -> None
-					| Some l ->
-						Some (List.map (fun v ->
-							match v with
-							| Some v when PMap.mem v.v_id used ->
-								let vtmp = mk_var v used in
-								e := concat (mk_init v vtmp pos) !e;
-								Some vtmp
-							| _ -> v
-						) l)
-				in
-				il, vars, !e
-			) cases in
-			let def = match def with None -> None | Some e -> Some (wrap used e) in
-			mk (TMatch (wrap used expr,enum,cases,def)) e.etype e.epos *)
 		| TFunction f ->
 			(*
 				list variables that are marked as used, but also used in that
@@ -534,7 +410,7 @@ let captured_vars com e =
 			let tmp_used = ref used in
 			let rec browse = function
 				| Block f | Loop f | Function f -> f browse
-				| Use v ->
+				| Use v | Assign v ->
 					if PMap.mem v.v_id !tmp_used then fused := PMap.add v.v_id v !fused;
 				| Declare v ->
 					tmp_used := PMap.remove v.v_id !tmp_used
@@ -547,7 +423,7 @@ let captured_vars com e =
 			let fargs = List.map (fun (v,o) ->
 				if PMap.mem v.v_id used then
 					let vtmp = mk_var v used in
-					fexpr := Type.concat (mk_init v vtmp e.epos) !fexpr;
+					fexpr := Type.concat (impl#mk_init v vtmp e.epos) !fexpr;
 					vtmp, o
 				else
 					v, o
@@ -577,7 +453,7 @@ let captured_vars com e =
 		else
 			let used = PMap.map (fun v ->
 				let vt = v.v_type in
-				v.v_type <- t.tarray vt;
+				v.v_type <- impl#captured_type vt;
 				v.v_capture <- true;
 				vt
 			) used in
@@ -607,7 +483,7 @@ let captured_vars com e =
 					decr depth;
 				| Declare v ->
 					if in_loop then vars := PMap.add v.v_id !depth !vars;
-				| Use v ->
+				| Use v | Assign v ->
 					try
 						let d = PMap.find v.v_id !vars in
 						if d <> !depth then used := PMap.add v.v_id v !used;
@@ -621,6 +497,7 @@ let captured_vars com e =
 	and all_vars e =
 		let vars = ref PMap.empty in
 		let used = ref PMap.empty in
+		let assigned = ref PMap.empty in
 		let depth = ref 0 in
 		let rec collect_vars = function
 		| Block f ->
@@ -638,17 +515,31 @@ let captured_vars com e =
 		| Declare v ->
 			vars := PMap.add v.v_id !depth !vars;
 		| Use v ->
-			try
+			(try
 				let d = PMap.find v.v_id !vars in
 				if d <> !depth then used := PMap.add v.v_id v !used;
-			with Not_found -> ()
+			with Not_found -> ())
+		| Assign v ->
+			(try
+				let d = PMap.find v.v_id !vars in
+				(* different depth - needs wrap *)
+				if d <> !depth then begin
+					used := PMap.add v.v_id v !used;
+					assigned := PMap.add v.v_id v !assigned;
+				end
+				(* same depth but assigned after being used on a different depth - needs wrap *)
+				else if PMap.mem v.v_id !used then
+					assigned := PMap.add v.v_id v !assigned;
+			with Not_found -> ())
 		in
 		local_usage collect_vars e;
-		!used
+
+		(* mark all capture variables - also used in rename_local_vars at later stage *)
+		PMap.iter (fun _ v -> v.v_capture <- true) !used;
+
+		!assigned
 	in
-	(* mark all capture variables - also used in rename_local_vars at later stage *)
 	let captured = all_vars e in
-	PMap.iter (fun _ v -> v.v_capture <- true) captured;
 	match com.config.pf_capture_policy with
 	| CPNone -> e
 	| CPWrapRef -> do_wrap captured e
@@ -657,8 +548,8 @@ let captured_vars com e =
 (* -------------------------------------------------------------------------- *)
 (* RENAME LOCAL VARS *)
 
-let rename_local_vars com e =
-	let cfg = com.config in
+let rename_local_vars ctx e =
+	let cfg = ctx.com.config in
 	let all_scope = (not cfg.pf_captured_scope) || (not cfg.pf_locals_scope) in
 	let vars = ref PMap.empty in
 	let all_vars = ref PMap.empty in
@@ -683,7 +574,7 @@ let rename_local_vars com e =
 			| TAbstract ({a_path = [],"Void"},_) -> error "Arguments and variables of type Void are not allowed" p
 			| _ -> ());
 		(* chop escape char for all local variables generated *)
-		if String.unsafe_get v.v_name 0 = String.unsafe_get gen_local_prefix 0 then v.v_name <- "_g" ^ String.sub v.v_name 1 (String.length v.v_name - 1);
+		if is_gen_local v then v.v_name <- "_g" ^ String.sub v.v_name 1 (String.length v.v_name - 1);
 		let look_vars = (if not cfg.pf_captured_scope && v.v_capture then !all_vars else !vars) in
 		(try
 			let v2 = PMap.find v.v_name look_vars in
@@ -738,6 +629,22 @@ let rename_local_vars com e =
 			old()
 		| TBlock el ->
 			let old = save() in
+			(* we have to look ahead for vars on these targets (issue #3344) *)
+			begin match ctx.com.platform with
+				| Js | Flash8 ->
+					let rec check_var e = match e.eexpr with
+						| TVar (v,eo) ->
+							(match eo with None -> () | Some e -> loop e);
+							declare v e.epos
+						| TBlock _ ->
+							()
+						| _ ->
+							Type.iter check_var e
+					in
+					List.iter check_var el
+				| _ ->
+					()
+			end;
 			List.iter loop el;
 			old()
 		| TFor (v,it,e1) ->
@@ -755,33 +662,6 @@ let rename_local_vars com e =
 				loop e;
 				old()
 			) catchs;
-		| TPatMatch dt ->
-			let rec fdt dt = match dt with
-				| DTSwitch(e,cl,dto) ->
-					loop e;
-					List.iter (fun (_,dt) ->
-						let old = save() in
-						fdt dt;
-						old();
-					) cl;
-					(match dto with None -> () | Some dt ->
-						let old = save() in
-						fdt dt;
-						old())
-				| DTBind(bl,dt) ->
-					List.iter (fun ((v,p),e) ->
-						declare v e.epos
-					) bl;
-					fdt dt
-				| DTExpr e -> loop e;
-				| DTGuard(e,dt1,dt2) ->
-					loop e;
-					fdt dt1;
-					(match dt2 with None -> () | Some dt -> fdt dt)
-				| DTGoto _ ->
-					()
-			in
-			Array.iter fdt dt.dt_dt_lookup
 		| TTypeExpr t ->
 			check t
 		| TNew (c,_,_) ->
@@ -790,17 +670,29 @@ let rename_local_vars com e =
 		| TCast (e,Some t) ->
 			loop e;
 			check t;
+		| TConst TSuper ->
+			check_type e.etype
 		| _ ->
 			Type.iter loop e
 	in
 	declare (alloc_var "this" t_dynamic) Ast.null_pos; (* force renaming of 'this' vars in abstract *)
+	begin match ctx.curclass.cl_path with
+		| s :: _,_ | [],s -> declare (alloc_var s t_dynamic) Ast.null_pos
+	end;
 	loop e;
 	e
 
-let check_unification com e t =
+let check_unification ctx e t =
 	begin match follow e.etype,follow t with
 		| TEnum _,TDynamic _ ->
-			add_feature com "may_print_enum";
+			Hashtbl.replace ctx.curclass.cl_module.m_extra.m_features "may_print_enum" true;
+		| _ ->
+			()
+	end;
+	begin match e.eexpr,t with
+		| TLocal v,TType({t_path = ["cs"],("Ref" | "Out")},_) ->
+			(* TODO: this smells of hack, but we have to deal with it somehow *)
+			v.v_capture <- true
 		| _ ->
 			()
 	end;
@@ -811,24 +703,44 @@ let check_unification com e t =
 (* Saves a class state so it can be restored later, e.g. after DCE or native path rewrite *)
 let save_class_state ctx t = match t with
 	| TClassDecl c ->
-		let meta = c.cl_meta and path = c.cl_path and ext = c.cl_extern in
-		let fl = c.cl_fields and ofl = c.cl_ordered_fields and st = c.cl_statics and ost = c.cl_ordered_statics in
-		let cst = c.cl_constructor and over = c.cl_overrides in
-		let oflk = List.map (fun f -> f.cf_kind,f.cf_expr,f.cf_type) ofl in
-		let ostk = List.map (fun f -> f.cf_kind,f.cf_expr,f.cf_type) ost in
+		let mk_field_restore f =
+			let rec mk_overload_restore f =
+				f.cf_kind,f.cf_expr,f.cf_type,f.cf_meta,f.cf_params
+			in
+			( f,mk_overload_restore f, List.map (fun f -> f,mk_overload_restore f) f.cf_overloads )
+		in
+		let restore_field (f,res,overloads) =
+			let restore_field (f,(kind,expr,t,meta,params)) =
+				f.cf_kind <- kind; f.cf_expr <- expr; f.cf_type <- t; f.cf_meta <- meta; f.cf_params <- params;
+				f
+			in
+			let f = restore_field (f,res) in
+			f.cf_overloads <- List.map restore_field overloads;
+			f
+		in
+		let mk_pmap lst =
+			List.fold_left (fun pmap f -> PMap.add f.cf_name f pmap) PMap.empty lst
+		in
+
+		let meta = c.cl_meta and path = c.cl_path and ext = c.cl_extern and over = c.cl_overrides in
+		let sup = c.cl_super and impl = c.cl_implements in
+		let csr = Option.map (mk_field_restore) c.cl_constructor in
+		let ofr = List.map (mk_field_restore) c.cl_ordered_fields in
+		let osr = List.map (mk_field_restore) c.cl_ordered_statics in
+		let init = c.cl_init in
 		c.cl_restore <- (fun() ->
+			c.cl_super <- sup;
+			c.cl_implements <- impl;
 			c.cl_meta <- meta;
 			c.cl_extern <- ext;
 			c.cl_path <- path;
-			c.cl_fields <- fl;
-			c.cl_ordered_fields <- ofl;
-			c.cl_statics <- st;
-			c.cl_ordered_statics <- ost;
-			c.cl_constructor <- cst;
+			c.cl_init <- init;
+			c.cl_ordered_fields <- List.map restore_field ofr;
+			c.cl_ordered_statics <- List.map restore_field osr;
+			c.cl_fields <- mk_pmap c.cl_ordered_fields;
+			c.cl_statics <- mk_pmap c.cl_ordered_statics;
+			c.cl_constructor <- Option.map restore_field csr;
 			c.cl_overrides <- over;
-			(* DCE might modify the cf_kind, so let's restore it as well *)
-			List.iter2 (fun f (k,e,t) -> f.cf_kind <- k; f.cf_expr <- e; f.cf_type <- t;) ofl oflk;
-			List.iter2 (fun f (k,e,t) -> f.cf_kind <- k; f.cf_expr <- e; f.cf_type <- t;) ost ostk;
 		)
 	| _ ->
 		()
@@ -845,23 +757,16 @@ let remove_generic_base ctx t = match t with
 
 (* Removes extern and macro fields, also checks for Void fields *)
 
-let is_removable_field ctx f =
-	Meta.has Meta.Extern f.cf_meta || Meta.has Meta.Generic f.cf_meta
-	|| (match f.cf_kind with
-		| Var {v_read = AccRequire (s,_)} -> true
-		| Method MethMacro -> not ctx.in_macro
-		| _ -> false)
-
 let remove_extern_fields ctx t = match t with
 	| TClassDecl c ->
 		if not (Common.defined ctx.com Define.DocGen) then begin
 			c.cl_ordered_fields <- List.filter (fun f ->
-				let b = is_removable_field ctx f in
+				let b = Codegen.is_removable_field ctx f in
 				if b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
 				not b
 			) c.cl_ordered_fields;
 			c.cl_ordered_statics <- List.filter (fun f ->
-				let b = is_removable_field ctx f in
+				let b = Codegen.is_removable_field ctx f in
 				if b then c.cl_statics <- PMap.remove f.cf_name c.cl_statics;
 				not b
 			) c.cl_ordered_statics;
@@ -883,17 +788,54 @@ let check_private_path ctx t = match t with
 
 (* Rewrites class or enum paths if @:native metadata is set *)
 let apply_native_paths ctx t =
-	let get_real_path meta path =
-		let (_,e,mp) = Meta.get Meta.Native meta in
+	let get_native_name meta =
+		let rec get_native meta = match meta with
+			| [] -> raise Not_found
+			| (Meta.Native,[v],p as meta) :: _ ->
+				meta
+			| _ :: meta ->
+				get_native meta
+		in
+		let (_,e,mp) = get_native meta in
 		match e with
 		| [Ast.EConst (Ast.String name),p] ->
-			(Meta.RealPath,[Ast.EConst (Ast.String (s_type_path path)),p],mp),parse_path name
+			name,p
+		| [] ->
+			raise Not_found
 		| _ ->
 			error "String expected" mp
 	in
+	let get_real_name meta name =
+		let name',p = get_native_name meta in
+		(Meta.RealPath,[Ast.EConst (Ast.String (name)), p], p), name'
+	in
+	let get_real_path meta path =
+		let name,p = get_native_name meta in
+		(Meta.RealPath,[Ast.EConst (Ast.String (s_type_path path)), p], p), parse_path name
+	in
 	try
 		(match t with
 		| TClassDecl c ->
+			let did_change = ref false in
+			let field cf = try
+				let meta,name = get_real_name cf.cf_meta cf.cf_name in
+				cf.cf_name <- name;
+				cf.cf_meta <- meta :: cf.cf_meta;
+				List.iter (fun cf -> cf.cf_name <- name) cf.cf_overloads;
+				did_change := true
+			with Not_found ->
+				()
+			in
+			let fields cfs old_map =
+				did_change := false;
+				List.iter field cfs;
+				if !did_change then
+					List.fold_left (fun map f -> PMap.add f.cf_name f map) PMap.empty cfs
+				else
+					old_map
+			in
+			c.cl_fields <- fields c.cl_ordered_fields c.cl_fields;
+			c.cl_statics <- fields c.cl_ordered_statics c.cl_statics;
 			let meta,path = get_real_path c.cl_meta c.cl_path in
 			c.cl_meta <- meta :: c.cl_meta;
 			c.cl_path <- path;
@@ -929,7 +871,7 @@ let add_rtti ctx t =
 let add_field_inits ctx t =
 	let is_as3 = Common.defined ctx.com Define.As3 && not ctx.in_macro in
 	let apply c =
-		let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_types)) c.cl_pos in
+		let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_params)) c.cl_pos in
 		(* TODO: we have to find a variable name which is not used in any of the functions *)
 		let v = alloc_var "_g" ethis.etype in
 		let need_this = ref false in
@@ -967,7 +909,7 @@ let add_field_inits ctx t =
 				match cf.cf_expr with
 				| None -> assert false
 				| Some e ->
-					let lhs = mk (TField(ethis,FInstance (c,cf))) cf.cf_type e.epos in
+					let lhs = mk (TField(ethis,FInstance (c,List.map snd c.cl_params,cf))) cf.cf_type e.epos in
 					cf.cf_expr <- None;
 					let eassign = mk (TBinop(OpAssign,lhs,e)) e.etype e.epos in
 					if is_as3 then begin
@@ -1034,19 +976,50 @@ let check_void_field ctx t = match t with
 	| _ ->
 		()
 
+(* Interfaces have no 'super', but can extend many other interfaces.
+   This makes the first extended (implemented) interface the super for efficiency reasons (you can get one for 'free')
+   and leaves the remaining ones as 'implemented' *)
+let promote_first_interface_to_super ctx t = match t with
+	| TClassDecl c when c.cl_interface ->
+		begin match c.cl_implements with
+		| ({ cl_path = ["cpp";"rtti"],_ },_ ) :: _ -> ()
+		| first_interface  :: remaining ->
+			c.cl_super <- Some first_interface;
+			c.cl_implements <- remaining
+		| _ -> ()
+		end
+	| _ ->
+		()
+
+let commit_features ctx t =
+	let m = (t_infos t).mt_module in
+	Hashtbl.iter (fun k v ->
+		Common.add_feature ctx.com k;
+	) m.m_extra.m_features
+
+let check_reserved_type_paths ctx t =
+	let m = t_infos t in
+	if List.mem m.mt_path ctx.com.config.pf_reserved_type_paths then
+		ctx.com.warning ("Type path " ^ (s_type_path m.mt_path) ^ " is reserved on this target") m.mt_pos
+
 (* PASS 3 end *)
 
 let run_expression_filters ctx filters t =
+	let run e =
+		List.fold_left (fun e f -> f e) e filters
+	in
 	match t with
 	| TClassDecl c when is_removable_class c -> ()
 	| TClassDecl c ->
-		let process_field f =
-			match f.cf_expr with
-			| Some e when not (is_removable_field ctx f) ->
-				Codegen.Abstract.cast_stack := f :: !Codegen.Abstract.cast_stack;
-				f.cf_expr <- Some (List.fold_left (fun e f -> f e) e filters);
-				Codegen.Abstract.cast_stack := List.tl !Codegen.Abstract.cast_stack;
-			| _ -> ()
+		ctx.curclass <- c;
+		let rec process_field f =
+			(match f.cf_expr with
+			| Some e when not (Codegen.is_removable_field ctx f) ->
+				Codegen.AbstractCast.cast_stack := f :: !Codegen.AbstractCast.cast_stack;
+				f.cf_expr <- Some (run e);
+				Codegen.AbstractCast.cast_stack := List.tl !Codegen.AbstractCast.cast_stack;
+			| _ -> ());
+			List.iter process_field f.cf_overloads
 		in
 		List.iter process_field c.cl_ordered_fields;
 		List.iter process_field c.cl_ordered_statics;
@@ -1056,69 +1029,129 @@ let run_expression_filters ctx filters t =
 		(match c.cl_init with
 		| None -> ()
 		| Some e ->
-			c.cl_init <- Some (List.fold_left (fun e f -> f e) e filters));
+			c.cl_init <- Some (run e));
 	| TEnumDecl _ -> ()
 	| TTypeDecl _ -> ()
 	| TAbstractDecl _ -> ()
 
 let pp_counter = ref 1
 
-let post_process ctx filters t =
-	(* ensure that we don't process twice the same (cached) module *)
+let is_cached t =
 	let m = (t_infos t).mt_module.m_extra in
 	if m.m_processed = 0 then m.m_processed <- !pp_counter;
-	if m.m_processed = !pp_counter then
-	run_expression_filters ctx filters t
+	m.m_processed <> !pp_counter
+
+let apply_filters_once ctx filters t =
+	if not (is_cached t) then run_expression_filters ctx filters t
 
-let post_process_end() =
+let next_compilation() =
 	incr pp_counter
 
+let iter_expressions fl mt =
+	match mt with
+	| TClassDecl c ->
+		let field cf = match cf.cf_expr with
+			| None -> ()
+			| Some e -> List.iter (fun f -> f e) fl
+		in
+		List.iter field c.cl_ordered_statics;
+		List.iter field c.cl_ordered_fields;
+		(match c.cl_constructor with None -> () | Some cf -> field cf)
+	| _ ->
+		()
+
 let run com tctx main =
-	if com.display = DMUsage then
-		Codegen.detect_usage com;
+	begin match com.display with
+		| DMUsage | DMPosition ->
+			Codegen.detect_usage com;
+		| _ ->
+			()
+	end;
 	if not (Common.defined com Define.NoDeprecationWarnings) then
 		Codegen.DeprecationCheck.run com;
-
-	(* PASS 1: general expression filters *)
- 	let filters = [
- 		Codegen.UnificationCallback.run (check_unification com);
-		Codegen.Abstract.handle_abstract_casts tctx;
-		blockify_ast;
-		(match com.platform with
-			| Cpp | Flash8 -> (fun e ->
-				let save = save_locals tctx in
-				let e = handle_side_effects com (Typecore.gen_local tctx) e in
-				save();
-				e)
-			| _ -> fun e -> e);
-		if com.foptimize then (fun e -> Optimizer.reduce_expression tctx (Optimizer.inline_constructors tctx e)) else Optimizer.sanitize tctx;
-		check_local_vars_init;
-		captured_vars com;
-	] in
-	List.iter (post_process tctx filters) com.types;
-	post_process_end();
-	List.iter (fun f -> f()) (List.rev com.filters);
-	(* save class state *)
-	List.iter (save_class_state tctx) com.types;
-	(* PASS 2: destructive type and expression filters *)
-	let filters = [
-		promote_complex_rhs com;
-		if com.config.pf_add_final_return then add_final_return else (fun e -> e);
-		rename_local_vars com; (* TODO: it shouldn't be necessary to have this here if promote_complex_rhs can generate proper variable names *)
-	] in
+	let use_static_analyzer = Common.defined com Define.Analyzer in
+	(* this part will be a bit messy until we make the analyzer the default *)
+	let new_types = List.filter (fun t -> not (is_cached t)) com.types in
+	if use_static_analyzer then begin
+		(* PASS 1: general expression filters *)
+		let filters = [
+			Codegen.UnificationCallback.run (check_unification tctx);
+			Codegen.AbstractCast.handle_abstract_casts tctx;
+			Optimizer.inline_constructors tctx;
+			Optimizer.reduce_expression tctx;
+			blockify_ast;
+			captured_vars com;
+		] in
+		List.iter (run_expression_filters tctx filters) new_types;
+		Analyzer.Run.run_on_types tctx new_types;
+		List.iter (iter_expressions [verify_ast]) new_types;
+		let filters = [
+			Optimizer.sanitize com;
+			if com.config.pf_add_final_return then add_final_return else (fun e -> e);
+			rename_local_vars tctx;
+		] in
+		List.iter (run_expression_filters tctx filters) new_types;
+	end else begin
+		(* PASS 1: general expression filters *)
+		let filters = [
+			Codegen.UnificationCallback.run (check_unification tctx);
+			Codegen.AbstractCast.handle_abstract_casts tctx;
+			blockify_ast;
+			( if (Common.defined com Define.NoSimplify) || (Common.defined com Define.Cppia) ||
+						( match com.platform with Cpp | Flash8 -> false | _ -> true ) then
+					fun e -> e
+				else
+					fun e ->
+						let save = save_locals tctx in
+						let timer = timer "analyzer-simplify-apply" in
+						let e = try snd (Analyzer.Simplifier.apply com e) with Exit -> e in
+						timer();
+						save();
+					e );
+			if com.foptimize then (fun e -> Optimizer.reduce_expression tctx (Optimizer.inline_constructors tctx e)) else Optimizer.sanitize com;
+			check_local_vars_init;
+			captured_vars com;
+			promote_complex_rhs com;
+			if com.config.pf_add_final_return then add_final_return else (fun e -> e);
+			rename_local_vars tctx;
+		] in
+		List.iter (run_expression_filters tctx filters) new_types;
+		List.iter (iter_expressions [verify_ast]) new_types;
+	end;
+	next_compilation();
+	List.iter (fun f -> f()) (List.rev com.filters); (* macros onGenerate etc. *)
+	List.iter (save_class_state tctx) new_types;
 	List.iter (fun t ->
 		remove_generic_base tctx t;
 		remove_extern_fields tctx t;
-		run_expression_filters tctx filters t;
 	) com.types;
 	(* update cache dependencies before DCE is run *)
 	Codegen.update_cache_dependencies com;
+	(* check @:remove metadata before DCE so it is ignored there (issue #2923) *)
+	List.iter (check_remove_metadata tctx) com.types;
 	(* DCE *)
-	let dce_mode = (try Common.defined_value com Define.Dce with _ -> "no") in
-	if not (Common.defined com Define.As3 || dce_mode = "no" || Common.defined com Define.DocGen) then Dce.run com main (dce_mode = "full" && not (Common.defined com Define.Interp));
+	let dce_mode = if Common.defined com Define.As3 then
+		"no"
+	else
+		(try Common.defined_value com Define.Dce with _ -> "no")
+	in
+	begin match dce_mode with
+		| "full" -> Dce.run com main (not (Common.defined com Define.Interp))
+		| "std" -> Dce.run com main false
+		| "no" -> Dce.fix_accessors com
+		| _ -> failwith ("Unknown DCE mode " ^ dce_mode)
+	end;
 	(* always filter empty abstract implementation classes (issue #1885) *)
 	List.iter (fun mt -> match mt with
-		| TClassDecl({cl_kind = KAbstractImpl _} as c) when c.cl_ordered_statics = [] && c.cl_ordered_fields = [] && not (Meta.has Meta.Used c.cl_meta) -> c.cl_extern <- true
+		| TClassDecl({cl_kind = KAbstractImpl _} as c) when c.cl_ordered_statics = [] && c.cl_ordered_fields = [] && not (Meta.has Meta.Used c.cl_meta) ->
+			c.cl_extern <- true
+		| TClassDecl({cl_kind = KAbstractImpl a} as c) when Meta.has Meta.Enum a.a_meta ->
+			let is_runtime_field cf =
+				not (Meta.has Meta.Enum cf.cf_meta)
+			in
+			(* also filter abstract implementation classes that have only @:enum fields (issue #2858) *)
+			if not (Meta.has Meta.Used c.cl_meta || Common.defined com Define.As3) || not (List.exists is_runtime_field c.cl_ordered_statics) then
+				c.cl_extern <- true
 		| _ -> ()
 	) com.types;
 	(* PASS 3: type filters *)
@@ -1128,7 +1161,9 @@ let run com tctx main =
 		add_rtti;
 		(match com.platform with | Java | Cs -> (fun _ _ -> ()) | _ -> add_field_inits);
 		add_meta_field;
-		check_remove_metadata;
 		check_void_field;
+		(match com.platform with | Cpp -> promote_first_interface_to_super | _ -> (fun _ _ -> ()) );
+		commit_features;
+		(if com.config.pf_reserved_type_paths <> [] then check_reserved_type_paths else (fun _ _ -> ()));
 	] in
-	List.iter (fun t -> List.iter (fun f -> f tctx t) type_filters) com.types
+	List.iter (fun t -> List.iter (fun f -> f tctx t) type_filters) com.types

+ 60 - 45
genas3.ml

@@ -45,10 +45,12 @@ type context = {
 	mutable block_inits : (unit -> unit) option;
 }
 
+let follow = Abstract.follow_with_abstracts
+
 let is_var_field f =
 	match f with
-	| FStatic (_,f) | FInstance (_,f) ->
-		(match f.cf_kind with Var _ -> true | _ -> false)
+	| FStatic (_,f) | FInstance (_,_,f) ->
+		(match f.cf_kind with Var _ | Method MethDynamic -> true | _ -> false)
 	| _ ->
 		false
 
@@ -57,7 +59,7 @@ let is_special_compare e1 e2 =
 	| TConst TNull, _  | _ , TConst TNull -> None
 	| _ ->
 	match follow e1.etype, follow e2.etype with
-	| TInst ({ cl_path = [],"Xml" } as c,_) , _ | _ , TInst ({ cl_path = [],"Xml" } as c,_) -> Some c
+	| TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) , _ | _ , TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) -> Some c
 	| _ -> None
 
 let protect name =
@@ -167,6 +169,12 @@ let init infos path =
 	}
 
 let close ctx =
+	begin match ctx.inf.com.main_class with
+		| Some tp when tp = ctx.curclass.cl_path ->
+			output_string ctx.ch "// Compile __main__.as instead\n";
+		| _ ->
+			()
+	end;
 	output_string ctx.ch (Printf.sprintf "package %s {\n" (String.concat "." (fst ctx.path)));
 	Hashtbl.iter (fun name paths ->
 		List.iter (fun pack ->
@@ -228,8 +236,8 @@ let rec type_str ctx t p =
 	match t with
 	| TEnum _ | TInst _ when List.memq t ctx.local_types ->
 		"*"
-	| TAbstract ({ a_impl = Some _ } as a,pl) ->
-		type_str ctx (Codegen.Abstract.get_underlying_type a pl) p
+	| TAbstract (a,pl) when not (Ast.Meta.has Ast.Meta.CoreType a.a_meta) ->
+		type_str ctx (Abstract.get_underlying_type a pl) p
 	| TAbstract (a,_) ->
 		(match a.a_path with
 		| [], "Void" -> "void"
@@ -285,14 +293,14 @@ let rec type_str ctx t p =
 				| TEnum ({ e_path = [],"Bool" },_) -> "*"
 				| _ -> type_str ctx t p)
 			| _ -> assert false);
-		| _ -> type_str ctx (apply_params t.t_types args t.t_type) p)
+		| _ -> type_str ctx (apply_params t.t_params args t.t_type) p)
 	| TLazy f ->
 		type_str ctx ((!f)()) p
 
 let rec iter_switch_break in_switch e =
 	match e.eexpr with
 	| TFunction _ | TWhile _ | TFor _ -> ()
-	| TSwitch _ | TPatMatch _ when not in_switch -> iter_switch_break true e
+	| TSwitch _ when not in_switch -> iter_switch_break true e
 	| TBreak when in_switch -> raise Exit
 	| _ -> iter (iter_switch_break in_switch) e
 
@@ -322,6 +330,7 @@ let generate_resources infos =
 		let dir = (infos.com.file :: ["__res"]) in
 		create_dir [] dir;
 		let add_resource name data =
+			let name = Base64.str_encode name in
 			let ch = open_out_bin (String.concat "/" (dir @ [name])) in
 			output_string ch data;
 			close_out ch
@@ -336,9 +345,9 @@ let generate_resources infos =
 		Hashtbl.iter (fun name _ ->
 			let varname = ("v" ^ (string_of_int !k)) in
 			k := !k + 1;
-			print ctx "\t\t[Embed(source = \"__res/%s\", mimeType = \"application/octet-stream\")]\n" name;
+			print ctx "\t\t[Embed(source = \"__res/%s\", mimeType = \"application/octet-stream\")]\n" (Base64.str_encode name);
 			print ctx "\t\tpublic static var %s:Class;\n" varname;
-			inits := ("list[\"" ^name^ "\"] = " ^ varname ^ ";") :: !inits;
+			inits := ("list[\"" ^ Ast.s_escape name ^ "\"] = " ^ varname ^ ";") :: !inits;
 		) infos.com.resources;
 		spr ctx "\t\tstatic public function __init__():void {\n";
 		spr ctx "\t\t\tlist = new Dictionary();\n";
@@ -387,14 +396,18 @@ let gen_function_header ctx name f params p =
 		" " ^ loop meta
 	);
 	concat ctx "," (fun (v,c) ->
-		let tstr = type_str ctx v.v_type p in
-		print ctx "%s : %s" (s_ident v.v_name) tstr;
-		match c with
-		| None ->
-			if ctx.constructor_block then print ctx " = %s" (default_value tstr);
-		| Some c ->
-			spr ctx " = ";
-			gen_constant ctx p c
+		match v.v_name with
+			| "__arguments__" ->
+				print ctx "...__arguments__"
+			| _ ->
+				let tstr = type_str ctx v.v_type p in
+				print ctx "%s : %s" (s_ident v.v_name) tstr;
+				match c with
+				| None ->
+					if ctx.constructor_block then print ctx " = %s" (default_value tstr);
+				| Some c ->
+					spr ctx " = ";
+					gen_constant ctx p c
 	) f.tf_args;
 	print ctx ") : %s " (type_str ctx f.tf_type p);
 	(fun () ->
@@ -495,6 +508,12 @@ let rec gen_call ctx e el r =
 				print ctx ")";
 			| _ -> assert false)
 		| _ -> assert false)
+	| TField(e1, (FAnon {cf_name = s} | FDynamic s)),[ef] when s = "map" || s = "filter" ->
+		spr ctx (s_path ctx true (["flash";],"Boot") e.epos);
+		gen_field_access ctx t_dynamic (s ^ "Dynamic");
+		spr ctx "(";
+		concat ctx "," (gen_value ctx) [e1;ef];
+		spr ctx ")"
 	| TField (ee,f), args when is_var_field f ->
 		spr ctx "(";
 		gen_value ctx e;
@@ -577,13 +596,18 @@ and gen_expr ctx e =
 		gen_field_access ctx e1.etype s;
 		print ctx " %s " (Ast.s_binop op);
 		gen_value_op ctx e2; *)
+	(* assignments to variable or dynamic methods fields on interfaces are generated as class["field"] = value *)
+	| TBinop (op,{eexpr = TField (ei, FInstance({cl_interface = true},_,{cf_kind = (Method MethDynamic | Var _); cf_name = s}))},e2) ->
+		gen_value ctx ei;
+		print ctx "[\"%s\"]" s;
+		print ctx " %s " (Ast.s_binop op);
+		gen_value_op ctx e2;
 	| TBinop (op,e1,e2) ->
 		gen_value_op ctx e1;
 		print ctx " %s " (Ast.s_binop op);
 		gen_value_op ctx e2;
-	(* variable fields on interfaces are generated as (class["field"] as class) *)
-	| TField ({etype = TInst({cl_interface = true} as c,_)} as ei,FInstance (_,{ cf_name = s }))
-		when (try (match (PMap.find s c.cl_fields).cf_kind with Var _ -> true | _ -> false) with Not_found -> false) ->
+	(* variable fields and dynamic methods on interfaces are generated as (class["field"] as class) *)
+	| TField (ei, FInstance({cl_interface = true},_,{cf_kind = (Method MethDynamic | Var _); cf_name = s})) ->
 		spr ctx "(";
 		gen_value ctx ei;
 		print ctx "[\"%s\"]" s;
@@ -597,7 +621,7 @@ and gen_expr ctx e =
 		gen_value ctx e;
 		print ctx ".params[%i]" i;
 	| TField (e,s) ->
-   		gen_value ctx e;
+		gen_value ctx e;
 		gen_field_access ctx e.etype (field_name s)
 	| TTypeExpr t ->
 		spr ctx (s_path ctx true (t_path t) e.epos)
@@ -642,10 +666,10 @@ and gen_expr ctx e =
 		end else begin
 			ctx.constructor_block <- false;
 			print ctx " if( !%s.skip_constructor ) {" (s_path ctx true (["flash"],"Boot") e.epos);
-            (fun() -> print ctx "}")
+			(fun() -> print ctx "}")
 		end) in
 		(match ctx.block_inits with None -> () | Some i -> i());
-		List.iter (fun e -> block_newline ctx; gen_expr ctx e) el;
+		List.iter (fun e -> gen_block_element ctx e) el;
 		bend();
 		newline ctx;
 		cb();
@@ -736,7 +760,6 @@ and gen_expr ctx e =
 			print ctx "catch( %s : %s )" (s_ident v.v_name) (type_str ctx v.v_type e.epos);
 			gen_expr ctx e;
 		) catchs;
-	| TPatMatch dt -> assert false
 	| TSwitch (e,cases,def) ->
 		spr ctx "switch";
 		gen_value ctx (parent e);
@@ -773,6 +796,13 @@ and gen_expr ctx e =
 	| TCast (e1,Some t) ->
 		gen_expr ctx (Codegen.default_cast ctx.inf.com e1 t e.etype e.epos)
 
+and gen_block_element ctx e = match e.eexpr with
+	| TObjectDecl fl ->
+		List.iter (fun (_,e) -> gen_block_element ctx e) fl
+	| _ ->
+		block_newline ctx;
+		gen_expr ctx e
+
 and gen_block ctx e =
 	newline ctx;
 	match e.eexpr with
@@ -852,7 +882,7 @@ and gen_value ctx e =
 		begin match s with
 		| "*" ->
 			gen_value ctx e1
-		| "Function" | "Array" ->
+		| "Function" | "Array" | "String" ->
 			spr ctx "((";
 			gen_value ctx e1;
 			print ctx ") as %s)" s;
@@ -910,7 +940,6 @@ and gen_value ctx e =
 			match def with None -> None | Some e -> Some (assign e)
 		)) e.etype e.epos);
 		v()
-	| TPatMatch dt -> assert false
 	| TTry (b,catchs) ->
 		let v = value true in
 		gen_expr ctx (mk (TTry (block (assign b),
@@ -949,8 +978,8 @@ let generate_field ctx static f =
 		| _ -> ()
 	) f.cf_meta;
 	let public = f.cf_public || Hashtbl.mem ctx.get_sets (f.cf_name,static) || (f.cf_name = "main" && static)
-	    || f.cf_name = "resolve" || Ast.Meta.has Ast.Meta.Public f.cf_meta
-	    (* consider all abstract methods public to avoid issues with inlined private access *)
+		|| f.cf_name = "resolve" || Ast.Meta.has Ast.Meta.Public f.cf_meta
+		(* consider all abstract methods public to avoid issues with inlined private access *)
 	    || (match ctx.curclass.cl_kind with KAbstractImpl _ -> true | _ -> false)
 	in
 	let rights = (if static then "static " else "") ^ (if public then "public" else "protected") in
@@ -976,7 +1005,7 @@ let generate_field ctx static f =
 		let is_getset = (match f.cf_kind with Var { v_read = AccCall } | Var { v_write = AccCall } -> true | _ -> false) in
 		if ctx.curclass.cl_interface then
 			match follow f.cf_type with
-			| TFun (args,r) ->
+			| TFun (args,r) when (match f.cf_kind with Method MethDynamic | Var _ -> false | _ -> true) ->
 				let rec loop = function
 					| [] -> f.cf_name
 					| (Ast.Meta.Getter,[Ast.EConst (Ast.String name),_],_) :: _ -> "get " ^ name
@@ -990,20 +1019,6 @@ let generate_field ctx static f =
 					if o then print ctx " = %s" (default_value tstr);
 				) args;
 				print ctx ") : %s " (type_str ctx r p);
-			| _ when is_getset ->
-				let t = type_str ctx f.cf_type p in
-				let id = s_ident f.cf_name in
-				(match f.cf_kind with
-				| Var v ->
-					(match v.v_read with
-					| AccNormal -> print ctx "function get %s() : %s;" id t;
-					| AccCall -> print ctx "function %s() : %s;" ("get_" ^ f.cf_name) t;
-					| _ -> ());
-					(match v.v_write with
-					| AccNormal -> print ctx "function set %s( __v : %s ) : void;" id t;
-					| AccCall -> print ctx "function %s( __v : %s ) : %s;" ("set_" ^ f.cf_name) t t;
-					| _ -> ());
-				| _ -> assert false)
 			| _ -> ()
 		else
 		let gen_init () = match f.cf_expr with
@@ -1059,7 +1074,7 @@ let generate_class ctx c =
 	ctx.curclass <- c;
 	define_getset ctx true c;
 	define_getset ctx false c;
-	ctx.local_types <- List.map snd c.cl_types;
+	ctx.local_types <- List.map snd c.cl_params;
 	let pack = open_block ctx in
 	print ctx "\tpublic %s%s%s %s " (final c.cl_meta) (match c.cl_dynamic with None -> "" | Some _ -> if c.cl_interface then "" else "dynamic ") (if c.cl_interface then "interface" else "class") (snd c.cl_path);
 	(match c.cl_super with
@@ -1120,7 +1135,7 @@ let generate_main ctx inits =
 	newline ctx
 
 let generate_enum ctx e =
-	ctx.local_types <- List.map snd e.e_types;
+	ctx.local_types <- List.map snd e.e_params;
 	let pack = open_block ctx in
 	let ename = snd e.e_path in
 	print ctx "\tpublic final class %s extends enum {" ename;

Файловите разлики са ограничени, защото са твърде много
+ 1221 - 1095
gencommon.ml


Файловите разлики са ограничени, защото са твърде много
+ 413 - 117
gencpp.ml


Файловите разлики са ограничени, защото са твърде много
+ 577 - 516
gencs.ml


+ 3458 - 2996
genjava.ml

@@ -24,103 +24,133 @@ open JData
 open Unix
 open Ast
 open Common
+open Type
 open Gencommon
 open Gencommon.SourceWriter
-open Type
 open Printf
 open Option
 open ExtString
+module SS = Set.Make(String)
 
 let is_boxed_type t = match follow t with
-  | TInst ({ cl_path = (["java";"lang"], "Boolean") }, [])
-  | TInst ({ cl_path = (["java";"lang"], "Double") }, [])
-  | TInst ({ cl_path = (["java";"lang"], "Integer") }, [])
-  | TInst ({ cl_path = (["java";"lang"], "Byte") }, [])
-  | TInst ({ cl_path = (["java";"lang"], "Short") }, [])
-  | TInst ({ cl_path = (["java";"lang"], "Character") }, [])
-  | TInst ({ cl_path = (["java";"lang"], "Float") }, []) -> true
-  | _ -> false
+	| TInst ({ cl_path = (["java";"lang"], "Boolean") }, [])
+	| TInst ({ cl_path = (["java";"lang"], "Double") }, [])
+	| TInst ({ cl_path = (["java";"lang"], "Integer") }, [])
+	| TInst ({ cl_path = (["java";"lang"], "Byte") }, [])
+	| TInst ({ cl_path = (["java";"lang"], "Short") }, [])
+	| TInst ({ cl_path = (["java";"lang"], "Character") }, [])
+	| TInst ({ cl_path = (["java";"lang"], "Float") }, []) -> true
+	| TAbstract ({ a_path = (["java";"lang"], "Boolean") }, [])
+	| TAbstract ({ a_path = (["java";"lang"], "Double") }, [])
+	| TAbstract ({ a_path = (["java";"lang"], "Integer") }, [])
+	| TAbstract ({ a_path = (["java";"lang"], "Byte") }, [])
+	| TAbstract ({ a_path = (["java";"lang"], "Short") }, [])
+	| TAbstract ({ a_path = (["java";"lang"], "Character") }, [])
+	| TAbstract ({ a_path = (["java";"lang"], "Float") }, []) -> true
+	| _ -> false
 
 let unboxed_type gen t tbyte tshort tchar tfloat = match follow t with
-  | TInst ({ cl_path = (["java";"lang"], "Boolean") }, []) -> gen.gcon.basic.tbool
-  | TInst ({ cl_path = (["java";"lang"], "Double") }, []) -> gen.gcon.basic.tfloat
-  | TInst ({ cl_path = (["java";"lang"], "Integer") }, []) -> gen.gcon.basic.tint
-  | TInst ({ cl_path = (["java";"lang"], "Byte") }, []) -> tbyte
-  | TInst ({ cl_path = (["java";"lang"], "Short") }, []) -> tshort
-  | TInst ({ cl_path = (["java";"lang"], "Character") }, []) -> tchar
-  | TInst ({ cl_path = (["java";"lang"], "Float") }, []) -> tfloat
-  | _ -> assert false
+	| TInst ({ cl_path = (["java";"lang"], "Boolean") }, []) -> gen.gcon.basic.tbool
+	| TInst ({ cl_path = (["java";"lang"], "Double") }, []) -> gen.gcon.basic.tfloat
+	| TInst ({ cl_path = (["java";"lang"], "Integer") }, []) -> gen.gcon.basic.tint
+	| TInst ({ cl_path = (["java";"lang"], "Byte") }, []) -> tbyte
+	| TInst ({ cl_path = (["java";"lang"], "Short") }, []) -> tshort
+	| TInst ({ cl_path = (["java";"lang"], "Character") }, []) -> tchar
+	| TInst ({ cl_path = (["java";"lang"], "Float") }, []) -> tfloat
+	| TAbstract ({ a_path = (["java";"lang"], "Boolean") }, []) -> gen.gcon.basic.tbool
+	| TAbstract ({ a_path = (["java";"lang"], "Double") }, []) -> gen.gcon.basic.tfloat
+	| TAbstract ({ a_path = (["java";"lang"], "Integer") }, []) -> gen.gcon.basic.tint
+	| TAbstract ({ a_path = (["java";"lang"], "Byte") }, []) -> tbyte
+	| TAbstract ({ a_path = (["java";"lang"], "Short") }, []) -> tshort
+	| TAbstract ({ a_path = (["java";"lang"], "Character") }, []) -> tchar
+	| TAbstract ({ a_path = (["java";"lang"], "Float") }, []) -> tfloat
+	| _ -> assert false
 
 let rec t_has_type_param t = match follow t with
-  | TInst({ cl_kind = KTypeParameter _ }, []) -> true
-  | TEnum(_, params)
-  | TInst(_, params) -> List.exists t_has_type_param params
-  | TFun(f,ret) -> t_has_type_param ret || List.exists (fun (_,_,t) -> t_has_type_param t) f
-  | _ -> false
+	| TInst({ cl_kind = KTypeParameter _ }, []) -> true
+	| TEnum(_, params)
+	| TAbstract(_, params)
+	| TInst(_, params) -> List.exists t_has_type_param params
+	| TFun(f,ret) -> t_has_type_param ret || List.exists (fun (_,_,t) -> t_has_type_param t) f
+	| _ -> false
 
 let is_type_param t = match follow t with
-  | TInst({ cl_kind = KTypeParameter _ }, _) -> true
-  | _ -> false
+	| TInst({ cl_kind = KTypeParameter _ }, _) -> true
+	| _ -> false
 
 let rec t_has_type_param_shallow last t = match follow t with
-  | TInst({ cl_kind = KTypeParameter _ }, []) -> true
-  | TEnum(_, params)
-  | TInst(_, params) when not last -> List.exists (t_has_type_param_shallow true) params
-  | TFun(f,ret) when not last -> t_has_type_param_shallow true ret  || List.exists (fun (_,_,t) -> t_has_type_param_shallow true t) f
-  | _ -> false
+	| TInst({ cl_kind = KTypeParameter _ }, []) -> true
+	| TEnum(_, params)
+	| TAbstract(_, params)
+	| TInst(_, params) when not last -> List.exists (t_has_type_param_shallow true) params
+	| TFun(f,ret) when not last -> t_has_type_param_shallow true ret	|| List.exists (fun (_,_,t) -> t_has_type_param_shallow true t) f
+	| _ -> false
+
+let rec replace_type_param t = match follow t with
+	| TInst({ cl_kind = KTypeParameter _ }, []) -> t_dynamic
+	| TEnum(e, params) -> TEnum(e, List.map replace_type_param params)
+	| TAbstract(a, params) -> TAbstract(a, List.map replace_type_param params)
+	| TInst(cl, params) -> TInst(cl, List.map replace_type_param params)
+	| _ -> t
 
 let is_java_basic_type t =
-  match follow t with
-    | TInst( { cl_path = (["haxe"], "Int32") }, [] )
-    | TInst( { cl_path = (["haxe"], "Int64") }, [] )
-    | TAbstract( { a_path = ([], "Single") }, [] )
-    | TAbstract( { a_path = (["java"], ("Int8" | "Int16" | "Char16")) }, [] )
-    | TInst( { cl_path = ([], "Int") }, [] ) | TAbstract( { a_path =  ([], "Int") }, [] )
-    | TInst( { cl_path = ([], "Float") }, [] ) | TAbstract( { a_path =  ([], "Float") }, [] )
-    | TEnum( { e_path = ([], "Bool") }, [] ) | TAbstract( { a_path =  ([], "Bool") }, [] ) ->
-      true
-    | _ -> false
+	match follow t with
+		| TInst( { cl_path = (["haxe"], "Int32") }, [] )
+		| TInst( { cl_path = (["haxe"], "Int64") }, [] )
+		| TAbstract( { a_path = ([], "Single") }, [] )
+		| TAbstract( { a_path = (["java"], ("Int8" | "Int16" | "Char16" | "Int64")) }, [] )
+		| TAbstract( { a_path =	([], "Int") }, [] )
+		| TAbstract( { a_path =	([], "Float") }, [] )
+		| TAbstract( { a_path =	([], "Bool") }, [] ) ->
+			true
+		| _ -> false
 
 let is_bool t =
-  match follow t with
-    | TEnum( { e_path = ([], "Bool") }, [] )
-    | TAbstract ({ a_path = ([], "Bool") },[]) ->
-      true
-    | _ -> false
+	match follow t with
+		| TAbstract ({ a_path = ([], "Bool") },[]) ->
+			true
+		| _ -> false
+
+let like_bool t =
+	match follow t with
+		| TAbstract ({ a_path = ([], "Bool") },[])
+		| TAbstract ({ a_path = (["java";"lang"],"Boolean") },[])
+		| TInst ({ cl_path = (["java";"lang"],"Boolean") },[]) ->
+			true
+		| _ -> false
 
 let is_int_float gen t =
-  match follow (gen.greal_type t) with
-    | TInst( { cl_path = (["haxe"], "Int64") }, [] )
-    | TInst( { cl_path = (["haxe"], "Int32") }, [] )
-    | TInst( { cl_path = ([], "Int") }, [] ) | TAbstract( { a_path =  ([], "Int") }, [] )
-    | TInst( { cl_path = ([], "Float") }, [] ) | TAbstract( { a_path =  ([], "Float") }, [] ) ->
-      true
-    | (TAbstract _ as t) when like_float t -> true
-    | _ -> false
+	match follow (gen.greal_type t) with
+		| TInst( { cl_path = (["haxe"], "Int32") }, [] )
+		| TAbstract( { a_path =	([], "Int") }, [] )
+		| TAbstract( { a_path =	([], "Float") }, [] ) ->
+			true
+		| (TAbstract _ as t) when like_float t && not (like_i64 t)-> true
+		| _ -> false
 
 let parse_explicit_iface =
-  let regex = Str.regexp "\\." in
-  let parse_explicit_iface str =
-    let split = Str.split regex str in
-    let rec get_iface split pack =
-      match split with
-        | clname :: fn_name :: [] -> fn_name, (List.rev pack, clname)
-        | pack_piece :: tl -> get_iface tl (pack_piece :: pack)
-        | _ -> assert false
-    in
-    get_iface split []
-  in parse_explicit_iface
+	let regex = Str.regexp "\\." in
+	let parse_explicit_iface str =
+		let split = Str.split regex str in
+		let rec get_iface split pack =
+			match split with
+				| clname :: fn_name :: [] -> fn_name, (List.rev pack, clname)
+				| pack_piece :: tl -> get_iface tl (pack_piece :: pack)
+				| _ -> assert false
+		in
+		get_iface split []
+	in parse_explicit_iface
 
 let is_string t =
-  match follow t with
-    | TInst( { cl_path = ([], "String") }, [] ) -> true
-    | _ -> false
+	match follow t with
+		| TInst( { cl_path = ([], "String") }, [] ) -> true
+		| _ -> false
 
 let is_cl t = match follow t with
-  | TInst({ cl_path = ["java";"lang"],"Class" },_)
-  | TAbstract({ a_path = [], ("Class"|"Enum") },_) -> true
-  | TAnon(a) when is_some (anon_class t) -> true
-  | _ -> false
+	| TInst({ cl_path = ["java";"lang"],"Class" },_)
+	| TAbstract({ a_path = [], ("Class"|"Enum") },_) -> true
+	| TAnon(a) when is_some (anon_class t) -> true
+	| _ -> false
 
 (* ******************************************* *)
 (* JavaSpecificESynf *)
@@ -128,3071 +158,3503 @@ let is_cl t = match follow t with
 
 (*
 
-  Some Java-specific syntax filters that must run before ExpressionUnwrap
+	Some Java-specific syntax filters that must run before ExpressionUnwrap
 
-  dependencies:
-    It must run before ExprUnwrap, as it may not return valid Expr/Statement expressions
-    It must run before ClassInstance, as it will detect expressions that need unchanged TTypeExpr
-    It must run after CastDetect, as it changes casts
-    It must run after TryCatchWrapper, to change Std.is() calls inside there
+	dependencies:
+		It must run before ExprUnwrap, as it may not return valid Expr/Statement expressions
+		It must run before ClassInstance, as it will detect expressions that need unchanged TTypeExpr
+		It must run after CastDetect, as it changes casts
+		It must run after TryCatchWrapper, to change Std.is() calls inside there
 
 *)
 module JavaSpecificESynf =
 struct
 
-  let name = "java_specific_e"
-
-  let priority = solve_deps name [ DBefore ExpressionUnwrap.priority; DBefore ClassInstance.priority; DAfter CastDetect.priority; DAfter TryCatchWrapper.priority ]
-
-  let get_cl_from_t t =
-    match follow t with
-      | TInst(cl,_) -> cl
-      | _ -> assert false
-
-  let traverse gen runtime_cl =
-    let basic = gen.gcon.basic in
-    let float_cl = get_cl ( get_type gen (["java";"lang"], "Double")) in
-    let i8_md  = ( get_type gen (["java";"lang"], "Byte")) in
-    let i16_md  = ( get_type gen (["java";"lang"], "Short")) in
-    let i64_md  = ( get_type gen (["java";"lang"], "Long")) in
-    let c16_md  = ( get_type gen (["java";"lang"], "Character")) in
-    let f_md  = ( get_type gen (["java";"lang"], "Float")) in
-    let bool_md = get_type gen (["java";"lang"], "Boolean") in
-
-    let is_var = alloc_var "__is__" t_dynamic in
-
-    let rec run e =
-      match e.eexpr with
-        (* Math changes *)
-        | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "NaN" }) ) ->
-          mk_static_field_access_infer float_cl "NaN" e.epos []
-        | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "NEGATIVE_INFINITY" }) ) ->
-          mk_static_field_access_infer float_cl "NEGATIVE_INFINITY" e.epos []
-        | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "POSITIVE_INFINITY" }) ) ->
-          mk_static_field_access_infer float_cl "POSITIVE_INFINITY" e.epos []
-        | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "isNaN"}) ) ->
-          mk_static_field_access_infer float_cl "_isNaN" e.epos []
-        | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("ffloor" as f) }) ) } as fe), p)
-        | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("fceil" as f) }) ) } as fe), p) ->
-            Type.map_expr run { e with eexpr = TCall({ fe with eexpr = TField(ef, FDynamic (String.sub f 1 (String.length f - 1)))  }, p) }
-        | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("fround") }) ) } as fe), p) ->
-            Type.map_expr run { e with eexpr = TCall({ fe with eexpr = TField(ef, FDynamic "rint")  }, p) }
-        | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "floor" }) ) }, _)
-        | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "round" }) ) }, _)
-        | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "ceil" }) ) }, _) ->
-            mk_cast basic.tint (Type.map_expr run { e with etype = basic.tfloat })
-        | TCall( ( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "isFinite" }) ) } as efield ), [v]) ->
-          { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "isFinite" efield.epos [], [run v] ) }
-        (* end of math changes *)
-
-        (* Std.is() *)
-        | TCall(
-            { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) },
-            [ obj; { eexpr = TTypeExpr(md) } ]
-          ) ->
-          let mk_is is_basic obj md =
-            let obj = if is_basic then mk_cast t_dynamic obj else obj in
-            { e with eexpr = TCall( { eexpr = TLocal is_var; etype = t_dynamic; epos = e.epos }, [
-              run obj;
-              { eexpr = TTypeExpr md; etype = t_dynamic (* this is after all a syntax filter *); epos = e.epos }
-            ] ) }
-          in
-          (match follow_module follow md with
-            | TClassDecl({ cl_path = ([], "Float") })
-            | TAbstractDecl({ a_path = ([], "Float") }) ->
-              {
-                eexpr = TCall(
-                  mk_static_field_access_infer runtime_cl "isDouble" e.epos [],
-                  [ run obj ]
-                );
-                etype = basic.tbool;
-                epos = e.epos
-              }
-            | TClassDecl{ cl_path = ([], "Int") }
-            | TAbstractDecl{ a_path = ([], "Int") } ->
-              {
-                eexpr = TCall(
-                  mk_static_field_access_infer runtime_cl "isInt" e.epos [],
-                  [ run obj ]
-                );
-                etype = basic.tbool;
-                epos = e.epos
-              }
-            | TAbstractDecl{ a_path = ([], "Bool") }
-            | TEnumDecl{ e_path = ([], "Bool") } ->
-              mk_is true obj bool_md
-            | TAbstractDecl{ a_path = ([], "Single") } ->
-              mk_is true obj f_md
-            | TAbstractDecl{ a_path = (["java"], "Int8") } ->
-              mk_is true obj i8_md
-            | TAbstractDecl{ a_path = (["java"], "Int16") } ->
-              mk_is true obj i16_md
-            | TAbstractDecl{ a_path = (["java"], "Char16") } ->
-              mk_is true obj c16_md
-            | TClassDecl{ cl_path = (["haxe"], "Int64") } ->
-              mk_is true obj i64_md
-            | TAbstractDecl{ a_path = ([], "Dynamic") }
-            | TClassDecl{ cl_path = ([], "Dynamic") } ->
-              (match obj.eexpr with
-                | TLocal _ | TConst _ -> { e with eexpr = TConst(TBool true) }
-                | _ -> { e with eexpr = TBlock([run obj; { e with eexpr = TConst(TBool true) }]) }
-              )
-            | _ ->
-              mk_is false obj md
-          )
-        (* end Std.is() *)
-        | _ -> Type.map_expr run e
-    in
-    run
-
-  let configure gen (mapping_func:texpr->texpr) =
-    let map e = Some(mapping_func e) in
-    gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map
+	let name = "java_specific_e"
+
+	let priority = solve_deps name [ DBefore ExpressionUnwrap.priority; DBefore ClassInstance.priority; DAfter CastDetect.priority; DAfter TryCatchWrapper.priority ]
+
+	let get_cl_from_t t =
+		match follow t with
+			| TInst(cl,_) -> cl
+			| _ -> assert false
+
+	let traverse gen runtime_cl =
+		let basic = gen.gcon.basic in
+		let float_cl = get_cl ( get_type gen (["java";"lang"], "Double")) in
+		let i8_md  = ( get_type gen (["java";"lang"], "Byte")) in
+		let i16_md	= ( get_type gen (["java";"lang"], "Short")) in
+		let i64_md	= ( get_type gen (["java";"lang"], "Long")) in
+		let c16_md	= ( get_type gen (["java";"lang"], "Character")) in
+		let f_md	= ( get_type gen (["java";"lang"], "Float")) in
+		let bool_md = get_type gen (["java";"lang"], "Boolean") in
+
+		let is_var = alloc_var "__is__" t_dynamic in
+
+		let rec run e =
+			match e.eexpr with
+				(* Math changes *)
+				| TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "NaN" }) ) ->
+					mk_static_field_access_infer float_cl "NaN" e.epos []
+				| TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "NEGATIVE_INFINITY" }) ) ->
+					mk_static_field_access_infer float_cl "NEGATIVE_INFINITY" e.epos []
+				| TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "POSITIVE_INFINITY" }) ) ->
+					mk_static_field_access_infer float_cl "POSITIVE_INFINITY" e.epos []
+				| TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "isNaN"}) ) ->
+					mk_static_field_access_infer float_cl "isNaN" e.epos []
+				| TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("ffloor" as f) }) ) } as fe), p)
+				| TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("fceil" as f) }) ) } as fe), p) ->
+						Type.map_expr run { e with eexpr = TCall({ fe with eexpr = TField(ef, FDynamic (String.sub f 1 (String.length f - 1)))	}, p) }
+				| TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("fround") }) ) } as fe), p) ->
+						Type.map_expr run { e with eexpr = TCall({ fe with eexpr = TField(ef, FDynamic "rint")	}, p) }
+				| TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "floor" }) ) }, _)
+				| TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "round" }) ) }, _)
+				| TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "ceil" }) ) }, _) ->
+						mk_cast basic.tint (Type.map_expr run { e with etype = basic.tfloat })
+				| TCall( ( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "isFinite" }) ) } as efield ), [v]) ->
+					{ e with eexpr = TCall( mk_static_field_access_infer runtime_cl "isFinite" efield.epos [], [run v] ) }
+				(* end of math changes *)
+
+				(* Std.is() *)
+				| TCall(
+						{ eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) },
+						[ obj; { eexpr = TTypeExpr(md) } ]
+					) ->
+					let mk_is is_basic obj md =
+						let obj = if is_basic then mk_cast t_dynamic obj else obj in
+						{ e with eexpr = TCall( { eexpr = TLocal is_var; etype = t_dynamic; epos = e.epos }, [
+							run obj;
+							{ eexpr = TTypeExpr md; etype = t_dynamic (* this is after all a syntax filter *); epos = e.epos }
+						] ) }
+					in
+					(match follow_module follow md with
+						| TAbstractDecl({ a_path = ([], "Float") }) ->
+							{
+								eexpr = TCall(
+									mk_static_field_access_infer runtime_cl "isDouble" e.epos [],
+									[ run obj ]
+								);
+								etype = basic.tbool;
+								epos = e.epos
+							}
+						| TAbstractDecl{ a_path = ([], "Int") } ->
+							{
+								eexpr = TCall(
+									mk_static_field_access_infer runtime_cl "isInt" e.epos [],
+									[ run obj ]
+								);
+								etype = basic.tbool;
+								epos = e.epos
+							}
+						| TAbstractDecl{ a_path = ([], "Bool") } ->
+							mk_is true obj bool_md
+						| TAbstractDecl{ a_path = ([], "Single") } ->
+							mk_is true obj f_md
+						| TAbstractDecl{ a_path = (["java"], "Int8") } ->
+							mk_is true obj i8_md
+						| TAbstractDecl{ a_path = (["java"], "Int16") } ->
+							mk_is true obj i16_md
+						| TAbstractDecl{ a_path = (["java"], "Char16") } ->
+							mk_is true obj c16_md
+						| TAbstractDecl{ a_path = (["java"], "Int64") } ->
+							mk_is true obj i64_md
+						| TClassDecl{ cl_path = (["haxe"], "Int64") } ->
+							mk_is true obj i64_md
+						| TAbstractDecl{ a_path = ([], "Dynamic") }
+						| TClassDecl{ cl_path = ([], "Dynamic") } ->
+							(match obj.eexpr with
+								| TLocal _ | TConst _ -> { e with eexpr = TConst(TBool true) }
+								| _ -> { e with eexpr = TBlock([run obj; { e with eexpr = TConst(TBool true) }]) }
+							)
+						| _ ->
+							mk_is false obj md
+					)
+				(* end Std.is() *)
+				| _ -> Type.map_expr run e
+		in
+		run
+
+	let configure gen (mapping_func:texpr->texpr) =
+		let map e = Some(mapping_func e) in
+		gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map
 
 end;;
 
-
 (* ******************************************* *)
 (* JavaSpecificSynf *)
 (* ******************************************* *)
 
 (*
 
-  Some Java-specific syntax filters that can run after ExprUnwrap
+	Some Java-specific syntax filters that can run after ExprUnwrap
 
-  dependencies:
-    Runs after ExprUnwarp
+	dependencies:
+		Runs after ExprUnwarp
 
 *)
 
 module JavaSpecificSynf =
 struct
 
-  let name = "java_specific"
-
-  let priority = solve_deps name [ DAfter ExpressionUnwrap.priority; DAfter ObjectDeclMap.priority; DAfter ArrayDeclSynf.priority; DBefore IntDivisionSynf.priority ]
-
-  let java_hash s =
-    let h = ref Int32.zero in
-    let thirtyone = Int32.of_int 31 in
-    for i = 0 to String.length s - 1 do
-      h := Int32.add (Int32.mul thirtyone !h) (Int32.of_int (int_of_char (String.unsafe_get s i)));
-    done;
-    !h
-
-  let rec is_final_return_expr is_switch e =
-    let is_final_return_expr = is_final_return_expr is_switch in
-    match e.eexpr with
-      | TReturn _
-      | TThrow _ -> true
-      (* this is hack to not use 'break' on switch cases *)
-      | TLocal { v_name = "__fallback__" } when is_switch -> true
-      | TCall( { eexpr = TLocal { v_name = "__goto__" } }, _ ) -> true
-      | TParenthesis p | TMeta (_,p) -> is_final_return_expr p
-      | TBlock bl -> is_final_return_block is_switch bl
-      | TSwitch (_, el_e_l, edef) ->
-        List.for_all (fun (_,e) -> is_final_return_expr e) el_e_l && Option.map_default is_final_return_expr false edef
-(*       | TMatch (_, _, il_vl_e_l, edef) ->
-        List.for_all (fun (_,_,e) -> is_final_return_expr e)il_vl_e_l && Option.map_default is_final_return_expr false edef *)
-      | TIf (_,eif, Some eelse) ->
-        is_final_return_expr eif && is_final_return_expr eelse
-      | TFor (_,_,e) ->
-        is_final_return_expr e
-      | TWhile (_,e,_) ->
-        is_final_return_expr e
-      | TFunction tf ->
-        is_final_return_expr tf.tf_expr
-      | TTry (e, ve_l) ->
-        is_final_return_expr e && List.for_all (fun (_,e) -> is_final_return_expr e) ve_l
-      | _ -> false
-
-  and is_final_return_block is_switch el =
-    match el with
-      | [] -> false
-      | final :: [] -> is_final_return_expr is_switch final
-      | hd :: tl -> is_final_return_block is_switch tl
-
-  let is_null e = match e.eexpr with | TConst(TNull) -> true | _ -> false
-
-  let rec is_equatable gen t =
-    match follow t with
-      | TInst(cl,_) ->
-        if cl.cl_path = (["haxe";"lang"], "IEquatable") then
-          true
-        else
-          List.exists (fun (cl,p) -> is_equatable gen (TInst(cl,p))) cl.cl_implements
-            || (match cl.cl_super with | Some(cl,p) -> is_equatable gen (TInst(cl,p)) | None -> false)
-      | _ -> false
-
-  (*
-    Changing string switch
-    will take an expression like
-    switch(str)
-    {
-      case "a":
-      case "b":
-    }
-
-    and modify it to:
-    {
-      var execute_def = true;
-      switch(str.hashCode())
-      {
-        case (hashcode of a):
-          if (str == "a")
-          {
-            execute_def = false;
-            ..code here
-          } //else if (str == otherVariableWithSameHashCode) {
-            ...
-          }
-        ...
-      }
-      if (execute_def)
-      {
-        ..default code
-      }
-    }
-
-    this might actually be slower in some cases than a if/else approach, but it scales well and as a bonus,
-    hashCode in java are cached, so we only have the performance hit once to cache it.
-  *)
-  let change_string_switch gen eswitch e1 ecases edefault =
-    let basic = gen.gcon.basic in
-    let is_final_ret = is_final_return_expr false eswitch in
-
-    let has_default = is_some edefault in
-    let block = ref [] in
-    let local = match e1.eexpr with
-      | TLocal _ -> e1
-      | _ ->
-        let var = mk_temp gen "svar" e1.etype in
-        let added = { e1 with eexpr = TVar(var, Some(e1)); etype = basic.tvoid } in
-        let local = mk_local var e1.epos in
-        block := added :: !block;
-        local
-    in
-    let execute_def_var = mk_temp gen "executeDef" gen.gcon.basic.tbool in
-    let execute_def = mk_local execute_def_var e1.epos in
-    let execute_def_set = { eexpr = TBinop(Ast.OpAssign, execute_def, { eexpr = TConst(TBool false); etype = basic.tbool; epos = e1.epos }); etype = basic.tbool; epos = e1.epos } in
-
-    let hash_cache = ref None in
-
-    let local_hashcode = ref { local with
-      eexpr = TCall({ local with
-        eexpr = TField(local, FDynamic "hashCode");
-        etype = TFun([], basic.tint);
-      }, []);
-      etype = basic.tint
-    } in
-
-    let get_hash_cache () =
-      match !hash_cache with
-        | Some c -> c
-        | None ->
-          let var = mk_temp gen "hash" basic.tint in
-          let cond = !local_hashcode in
-          block := { eexpr = TVar(var, Some cond); etype = basic.tvoid; epos = local.epos } :: !block;
-          let local = mk_local var local.epos in
-          local_hashcode := local;
-          hash_cache := Some local;
-          local
-    in
-
-    let has_case = ref false in
-    (* first we need to reorder all cases so all collisions are close to each other *)
-
-    let get_str e = match e.eexpr with | TConst(TString s) -> s | _ -> assert false in
-    let has_conflict = ref false in
-
-    let rec reorder_cases unordered ordered =
-      match unordered with
-        | [] -> ordered
-        | (el, e) :: tl ->
-          let current = Hashtbl.create 1 in
-          List.iter (fun e ->
-            let str = get_str e in
-            let hash = java_hash str in
-            Hashtbl.add current hash true
-          ) el;
-
-          let rec extract_fields cases found_cases ret_cases =
-            match cases with
-              | [] -> found_cases, ret_cases
-              | (el, e) :: tl ->
-                if List.exists (fun e -> Hashtbl.mem current (java_hash (get_str e)) ) el then begin
-                  has_conflict := true;
-                  List.iter (fun e -> Hashtbl.add current (java_hash (get_str e)) true) el;
-                  extract_fields tl ( (el, e) :: found_cases ) ret_cases
-                end else
-                  extract_fields tl found_cases ( (el, e) :: ret_cases )
-          in
-          let found, remaining = extract_fields tl [] [] in
-          let ret = if found <> [] then
-            let ret = List.sort (fun (e1,_) (e2,_) -> compare (List.length e2) (List.length e1) ) ( (el, e) :: found ) in
-            let rec loop ret acc =
-              match ret with
-                | (el, e) :: ( (_,_) :: _ as tl ) -> loop tl ( (true, el, e) :: acc )
-                | (el, e) :: [] -> ( (false, el, e) :: acc )
-                | _ -> assert false
-            in
-            List.rev (loop ret [])
-          else
-            (false, el, e) :: []
-          in
-
-          reorder_cases remaining (ordered @ ret)
-    in
-
-    let already_in_cases = Hashtbl.create 0 in
-    let change_case (has_fallback, el, e) =
-      let conds, el = List.fold_left (fun (conds,el) e ->
-        has_case := true;
-        match e.eexpr with
-          | TConst(TString s) ->
-            let hashed = java_hash s in
-            let equals_test = {
-              eexpr = TCall({ e with eexpr = TField(local, FDynamic "equals"); etype = TFun(["obj",false,t_dynamic],basic.tbool) }, [ e ]);
-              etype = basic.tbool;
-              epos = e.epos
-            } in
-
-            let hashed_expr = { eexpr = TConst(TInt hashed); etype = basic.tint; epos = e.epos } in
-            let hashed_exprs = if !has_conflict then begin
-              if Hashtbl.mem already_in_cases hashed then
-                el
-              else begin
-                Hashtbl.add already_in_cases hashed true;
-                hashed_expr :: el
-              end
-            end else hashed_expr :: el in
-
-            let conds = match conds with
-              | None -> equals_test
-              | Some c ->
-                (*
-                  if there is more than one case, we should test first if hash equals to the one specified.
-                  This way we can save a heavier string compare
-                *)
-                let equals_test = mk_paren {
-                  eexpr = TBinop(Ast.OpBoolAnd, { eexpr = TBinop(Ast.OpEq, get_hash_cache(), hashed_expr); etype = basic.tbool; epos = e.epos }, equals_test);
-                  etype = basic.tbool;
-                  epos = e.epos;
-                } in
-
-                { eexpr = TBinop(Ast.OpBoolOr, equals_test, c); etype = basic.tbool; epos = e1.epos }
-            in
-
-            Some conds, hashed_exprs
-          | _ -> assert false
-      ) (None,[]) el in
-      let e = if has_default then Type.concat execute_def_set e else e in
-      let e = if !has_conflict then Type.concat e { e with eexpr = TBreak; etype = basic.tvoid } else e in
-      let e = {
-        eexpr = TIf(get conds, e, None);
-        etype = basic.tvoid;
-        epos = e.epos
-      } in
-
-      let e = if has_fallback then { e with eexpr = TBlock([ e; mk_local (alloc_var "__fallback__" t_dynamic) e.epos]) } else e in
-
-      (el, e)
-    in
-
-    let switch = { eswitch with
-      eexpr = TSwitch(!local_hashcode, List.map change_case (reorder_cases ecases []), None);
-    } in
-    (if !has_case then begin
-      (if has_default then block := { e1 with eexpr = TVar(execute_def_var, Some({ e1 with eexpr = TConst(TBool true); etype = basic.tbool })); etype = basic.tvoid } :: !block);
-      block := switch :: !block
-    end);
-    (match edefault with
-      | None -> ()
-      | Some edef when not !has_case ->
-        block := edef :: !block
-      | Some edef ->
-        let eelse = if is_final_ret then Some { eexpr = TThrow { eexpr = TConst(TNull); etype = t_dynamic; epos = edef.epos }; etype = basic.tvoid; epos = edef.epos } else None in
-        block := { edef with eexpr = TIf(execute_def, edef, eelse); etype = basic.tvoid } :: !block
-    );
-    { eswitch with eexpr = TBlock(List.rev !block) }
-
-
-  let get_cl_from_t t =
-    match follow t with
-      | TInst(cl,_) -> cl
-      | _ -> assert false
-
-  let traverse gen runtime_cl =
-    let basic = gen.gcon.basic in
-    let tchar = mt_to_t_dyn ( get_type gen (["java"], "Char16") ) in
-    let tbyte = mt_to_t_dyn ( get_type gen (["java"], "Int8") ) in
-    let tshort = mt_to_t_dyn ( get_type gen (["java"], "Int16") ) in
-    let tsingle = mt_to_t_dyn ( get_type gen ([], "Single") ) in
-    let string_ext = get_cl ( get_type gen (["haxe";"lang"], "StringExt")) in
-
-    let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) -> true | _ -> false in
-
-    let rec run e =
-      match e.eexpr with
-        (* for new NativeArray<T> issues *)
-        | TNew(({ cl_path = (["java"], "NativeArray") } as cl), [t], el) when is_type_param t ->
-          mk_cast (TInst(cl,[t])) (mk_cast t_dynamic ({ e with eexpr = TNew(cl, [t_empty], List.map run el) }))
-
-        (* Std.int() *)
-        | TCall(
-            { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "int" })) },
-            [obj]
-          ) ->
-          run (mk_cast basic.tint obj)
-        (* end Std.int() *)
-
-        | TField( ef, FInstance({ cl_path = ([], "String") }, { cf_name = "length" }) ) ->
-          { e with eexpr = TCall(Type.map_expr run e, []) }
-        | TField( ef, field ) when field_name field = "length" && is_string ef.etype ->
-          { e with eexpr = TCall(Type.map_expr run e, []) }
-        | TCall( ( { eexpr = TField(ef, field) } as efield ), args ) when is_string ef.etype && String.get (field_name field) 0 = '_' ->
-          let field = field_name field in
-          { e with eexpr = TCall({ efield with eexpr = TField(run ef, FDynamic (String.sub field 1 ( (String.length field) - 1)) )}, List.map run args) }
-        | TCall( ( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, field )) } as efield ), args ) ->
-          let field = field.cf_name in
-          (match field with
-            | "charAt" | "charCodeAt" | "split" | "indexOf"
-            | "lastIndexOf" | "substring" | "substr" ->
-              { e with eexpr = TCall(mk_static_field_access_infer string_ext field e.epos [], [run ef] @ (List.map run args)) }
-            | _ ->
-              { e with eexpr = TCall(run efield, List.map run args) }
-          )
-(*         | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("toString") })) }, [] ) ->
-          run ef *)
-
-        | TCast(expr, m) when is_boxed_type e.etype ->
-          (* let unboxed_type gen t tbyte tshort tchar tfloat = match follow t with *)
-          run { e with etype = unboxed_type gen e.etype tbyte tshort tchar tsingle }
-
-        | TCast(expr, _) when is_bool e.etype ->
-          {
-            eexpr = TCall(
-              mk_static_field_access_infer runtime_cl "toBool" expr.epos [],
-              [ run expr ]
-            );
-            etype = basic.tbool;
-            epos = e.epos
-          }
-
-        | TCast(expr, _) when is_int_float gen e.etype && not (is_int_float gen expr.etype) ->
-          let needs_cast = match gen.gfollow#run_f e.etype with
-            | TInst _ -> false
-            | _ -> true
-          in
-
-          let fun_name = if like_int e.etype then "toInt" else "toDouble" in
-
-          let ret = {
-            eexpr = TCall(
-              mk_static_field_access_infer runtime_cl fun_name expr.epos [],
-              [ run expr ]
-            );
-            etype = if fun_name = "toDouble" then basic.tfloat else basic.tint;
-            epos = expr.epos
-          } in
-
-          if needs_cast then mk_cast e.etype ret else ret
-
-        (*| TCast(expr, c) when is_int_float gen e.etype ->
-          (* cases when float x = (float) (java.lang.Double val); *)
-          (* FIXME: this fix is broken since it will fail on cases where float x = (float) (java.lang.Float val) or similar. FIX THIS *)
-          let need_second_cast = match gen.gfollow#run_f e.etype with
-            | TInst _ -> false
-            | _ -> true
-          in
-          if need_second_cast then { e with eexpr = TCast(mk_cast (follow e.etype) (run expr), c) }  else Type.map_expr run e*)
-        | TBinop( (Ast.OpAssignOp OpAdd as op), e1, e2)
-        | TBinop( (Ast.OpAdd as op), e1, e2) when is_string e.etype || is_string e1.etype || is_string e2.etype ->
-            let is_assign = match op with Ast.OpAssignOp _ -> true | _ -> false in
-            let mk_to_string e = { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" e.epos [], [run e] ); etype = gen.gcon.basic.tstring  } in
-            let check_cast e = match gen.greal_type e.etype with
-              | TDynamic _
-              | TAbstract({ a_path = ([], "Float") }, [])
-              | TAbstract({ a_path = ([], "Single") }, []) ->
-                  mk_to_string e
-              | _ -> run e
-            in
-
-            { e with eexpr = TBinop(op, (if is_assign then run e1 else check_cast e1), check_cast e2) }
-        | TCast(expr, _) when is_string e.etype ->
-          { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" expr.epos [], [run expr] ) }
-
-        | TSwitch(cond, ecases, edefault) when is_string cond.etype ->
-          (*let change_string_switch gen eswitch e1 ecases edefault =*)
-          change_string_switch gen e (run cond) (List.map (fun (el,e) -> (el, run e)) ecases) (Option.map run edefault)
-
-        | TBinop( (Ast.OpNotEq as op), e1, e2)
-        | TBinop( (Ast.OpEq as op), e1, e2) when not (is_null e2 || is_null e1) && (is_string e1.etype || is_string e2.etype || is_equatable gen e1.etype || is_equatable gen e2.etype) ->
-          let static = mk_static_field_access_infer (runtime_cl) "valEq" e1.epos [] in
-          let eret = { eexpr = TCall(static, [run e1; run e2]); etype = gen.gcon.basic.tbool; epos=e.epos } in
-          if op = Ast.OpNotEq then { eret with eexpr = TUnop(Ast.Not, Ast.Prefix, eret) } else eret
-
-        | TBinop( (Ast.OpNotEq | Ast.OpEq as op), e1, e2) when is_cl e1.etype && is_cl e2.etype ->
-          { e with eexpr = TBinop(op, mk_cast t_empty (run e1), mk_cast t_empty (run e2)) }
-        | _ -> Type.map_expr run e
-    in
-    run
-
-  let configure gen (mapping_func:texpr->texpr) =
-    (if java_hash "Testing string hashCode implementation from haXe" <> (Int32.of_int 545883604) then assert false);
-    let map e = Some(mapping_func e) in
-    gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map
+	let name = "java_specific"
+
+	let priority = solve_deps name [ DAfter ExpressionUnwrap.priority; DAfter ObjectDeclMap.priority; DAfter ArrayDeclSynf.priority; DBefore IntDivisionSynf.priority ]
+
+	let java_hash s =
+		let h = ref Int32.zero in
+		let thirtyone = Int32.of_int 31 in
+		for i = 0 to String.length s - 1 do
+			h := Int32.add (Int32.mul thirtyone !h) (Int32.of_int (int_of_char (String.unsafe_get s i)));
+		done;
+		!h
+
+	let rec is_final_return_expr is_switch e =
+		let is_final_return_expr = is_final_return_expr is_switch in
+		match e.eexpr with
+			| TReturn _
+			| TThrow _ -> true
+			(* this is hack to not use 'break' on switch cases *)
+			| TLocal { v_name = "__fallback__" } when is_switch -> true
+			| TCall( { eexpr = TLocal { v_name = "__goto__" } }, _ ) -> true
+			| TParenthesis p | TMeta (_,p) -> is_final_return_expr p
+			| TBlock bl -> is_final_return_block is_switch bl
+			| TSwitch (_, el_e_l, edef) ->
+				List.for_all (fun (_,e) -> is_final_return_expr e) el_e_l && Option.map_default is_final_return_expr false edef
+(*			 | TMatch (_, _, il_vl_e_l, edef) ->
+				List.for_all (fun (_,_,e) -> is_final_return_expr e)il_vl_e_l && Option.map_default is_final_return_expr false edef *)
+			| TIf (_,eif, Some eelse) ->
+				is_final_return_expr eif && is_final_return_expr eelse
+			| TFor (_,_,e) ->
+				is_final_return_expr e
+			| TWhile (_,e,_) ->
+				is_final_return_expr e
+			| TFunction tf ->
+				is_final_return_expr tf.tf_expr
+			| TTry (e, ve_l) ->
+				is_final_return_expr e && List.for_all (fun (_,e) -> is_final_return_expr e) ve_l
+			| _ -> false
+
+	and is_final_return_block is_switch el =
+		match el with
+			| [] -> false
+			| final :: [] -> is_final_return_expr is_switch final
+			| hd :: tl -> is_final_return_block is_switch tl
+
+	let is_null e = match e.eexpr with | TConst(TNull) -> true | _ -> false
+
+	let rec is_equatable gen t =
+		match follow t with
+			| TInst(cl,_) ->
+				if cl.cl_path = (["haxe";"lang"], "IEquatable") then
+					true
+				else
+					List.exists (fun (cl,p) -> is_equatable gen (TInst(cl,p))) cl.cl_implements
+						|| (match cl.cl_super with | Some(cl,p) -> is_equatable gen (TInst(cl,p)) | None -> false)
+			| _ -> false
+
+	(*
+		Changing string switch
+		will take an expression like
+		switch(str)
+		{
+			case "a":
+			case "b":
+		}
+
+		and modify it to:
+		{
+			var execute_def = true;
+			switch(str.hashCode())
+			{
+				case (hashcode of a):
+					if (str == "a")
+					{
+						execute_def = false;
+						..code here
+					} //else if (str == otherVariableWithSameHashCode) {
+						...
+					}
+				...
+			}
+			if (execute_def)
+			{
+				..default code
+			}
+		}
+
+		this might actually be slower in some cases than a if/else approach, but it scales well and as a bonus,
+		hashCode in java are cached, so we only have the performance hit once to cache it.
+	*)
+	let change_string_switch gen eswitch e1 ecases edefault =
+		let basic = gen.gcon.basic in
+		let is_final_ret = is_final_return_expr false eswitch in
+
+		let has_default = is_some edefault in
+		let block = ref [] in
+		let local = match e1.eexpr with
+			| TLocal _ -> e1
+			| _ ->
+				let var = mk_temp gen "svar" e1.etype in
+				let added = { e1 with eexpr = TVar(var, Some(e1)); etype = basic.tvoid } in
+				let local = mk_local var e1.epos in
+				block := added :: !block;
+				local
+		in
+		let execute_def_var = mk_temp gen "executeDef" gen.gcon.basic.tbool in
+		let execute_def = mk_local execute_def_var e1.epos in
+		let execute_def_set = { eexpr = TBinop(Ast.OpAssign, execute_def, { eexpr = TConst(TBool false); etype = basic.tbool; epos = e1.epos }); etype = basic.tbool; epos = e1.epos } in
+
+		let hash_cache = ref None in
+
+		let local_hashcode = ref { local with
+			eexpr = TCall({ local with
+				eexpr = TField(local, FDynamic "hashCode");
+				etype = TFun([], basic.tint);
+			}, []);
+			etype = basic.tint
+		} in
+
+		let get_hash_cache () =
+			match !hash_cache with
+				| Some c -> c
+				| None ->
+					let var = mk_temp gen "hash" basic.tint in
+					let cond = !local_hashcode in
+					block := { eexpr = TVar(var, Some cond); etype = basic.tvoid; epos = local.epos } :: !block;
+					let local = mk_local var local.epos in
+					local_hashcode := local;
+					hash_cache := Some local;
+					local
+		in
+
+		let has_case = ref false in
+		(* first we need to reorder all cases so all collisions are close to each other *)
+
+		let get_str e = match e.eexpr with | TConst(TString s) -> s | _ -> assert false in
+		let has_conflict = ref false in
+
+		let rec reorder_cases unordered ordered =
+			match unordered with
+				| [] -> ordered
+				| (el, e) :: tl ->
+					let current = Hashtbl.create 1 in
+					List.iter (fun e ->
+						let str = get_str e in
+						let hash = java_hash str in
+						Hashtbl.add current hash true
+					) el;
+
+					let rec extract_fields cases found_cases ret_cases =
+						match cases with
+							| [] -> found_cases, ret_cases
+							| (el, e) :: tl ->
+								if List.exists (fun e -> Hashtbl.mem current (java_hash (get_str e)) ) el then begin
+									has_conflict := true;
+									List.iter (fun e -> Hashtbl.add current (java_hash (get_str e)) true) el;
+									extract_fields tl ( (el, e) :: found_cases ) ret_cases
+								end else
+									extract_fields tl found_cases ( (el, e) :: ret_cases )
+					in
+					let found, remaining = extract_fields tl [] [] in
+					let ret = if found <> [] then
+						let ret = List.sort (fun (e1,_) (e2,_) -> compare (List.length e2) (List.length e1) ) ( (el, e) :: found ) in
+						let rec loop ret acc =
+							match ret with
+								| (el, e) :: ( (_,_) :: _ as tl ) -> loop tl ( (true, el, e) :: acc )
+								| (el, e) :: [] -> ( (false, el, e) :: acc )
+								| _ -> assert false
+						in
+						List.rev (loop ret [])
+					else
+						(false, el, e) :: []
+					in
+
+					reorder_cases remaining (ordered @ ret)
+		in
+
+		let already_in_cases = Hashtbl.create 0 in
+		let change_case (has_fallback, el, e) =
+			let conds, el = List.fold_left (fun (conds,el) e ->
+				has_case := true;
+				match e.eexpr with
+					| TConst(TString s) ->
+						let hashed = java_hash s in
+						let equals_test = {
+							eexpr = TCall({ e with eexpr = TField(local, FDynamic "equals"); etype = TFun(["obj",false,t_dynamic],basic.tbool) }, [ e ]);
+							etype = basic.tbool;
+							epos = e.epos
+						} in
+
+						let hashed_expr = { eexpr = TConst(TInt hashed); etype = basic.tint; epos = e.epos } in
+						let hashed_exprs = if !has_conflict then begin
+							if Hashtbl.mem already_in_cases hashed then
+								el
+							else begin
+								Hashtbl.add already_in_cases hashed true;
+								hashed_expr :: el
+							end
+						end else hashed_expr :: el in
+
+						let conds = match conds with
+							| None -> equals_test
+							| Some c ->
+								(*
+									if there is more than one case, we should test first if hash equals to the one specified.
+									This way we can save a heavier string compare
+								*)
+								let equals_test = mk_paren {
+									eexpr = TBinop(Ast.OpBoolAnd, { eexpr = TBinop(Ast.OpEq, get_hash_cache(), hashed_expr); etype = basic.tbool; epos = e.epos }, equals_test);
+									etype = basic.tbool;
+									epos = e.epos;
+								} in
+
+								{ eexpr = TBinop(Ast.OpBoolOr, equals_test, c); etype = basic.tbool; epos = e1.epos }
+						in
+
+						Some conds, hashed_exprs
+					| _ -> assert false
+			) (None,[]) el in
+			let e = if has_default then Type.concat execute_def_set e else e in
+			let e = if !has_conflict then Type.concat e { e with eexpr = TBreak; etype = basic.tvoid } else e in
+			let e = {
+				eexpr = TIf(get conds, e, None);
+				etype = basic.tvoid;
+				epos = e.epos
+			} in
+
+			let e = if has_fallback then { e with eexpr = TBlock([ e; mk_local (alloc_var "__fallback__" t_dynamic) e.epos]) } else e in
+
+			(el, e)
+		in
+
+		let switch = { eswitch with
+			eexpr = TSwitch(!local_hashcode, List.map change_case (reorder_cases ecases []), None);
+		} in
+		(if !has_case then begin
+			(if has_default then block := { e1 with eexpr = TVar(execute_def_var, Some({ e1 with eexpr = TConst(TBool true); etype = basic.tbool })); etype = basic.tvoid } :: !block);
+			block := switch :: !block
+		end);
+		(match edefault with
+			| None -> ()
+			| Some edef when not !has_case ->
+				block := edef :: !block
+			| Some edef ->
+				let eelse = if is_final_ret then Some { eexpr = TThrow { eexpr = TConst(TNull); etype = t_dynamic; epos = edef.epos }; etype = basic.tvoid; epos = edef.epos } else None in
+				block := { edef with eexpr = TIf(execute_def, edef, eelse); etype = basic.tvoid } :: !block
+		);
+		{ eswitch with eexpr = TBlock(List.rev !block) }
+
+
+	let get_cl_from_t t =
+		match follow t with
+			| TInst(cl,_) -> cl
+			| _ -> assert false
+
+	let traverse gen runtime_cl =
+		let basic = gen.gcon.basic in
+		(* let tchar = mt_to_t_dyn ( get_type gen (["java"], "Char16") ) in *)
+		(* let tbyte = mt_to_t_dyn ( get_type gen (["java"], "Int8") ) in *)
+		(* let tshort = mt_to_t_dyn ( get_type gen (["java"], "Int16") ) in *)
+		(* let tsingle = mt_to_t_dyn ( get_type gen ([], "Single") ) in *)
+		let string_ext = get_cl ( get_type gen (["haxe";"lang"], "StringExt")) in
+
+		let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) -> true | _ -> false in
+
+		let rec run e =
+			match e.eexpr with
+				(* for new NativeArray<T> issues *)
+				| TNew(({ cl_path = (["java"], "NativeArray") } as cl), [t], el) when is_type_param t ->
+					mk_cast (TInst(cl,[t])) (mk_cast t_dynamic ({ e with eexpr = TNew(cl, [t_empty], List.map run el) }))
+
+				(* Std.int() *)
+				| TCall(
+						{ eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "int" })) },
+						[obj]
+					) ->
+					run (mk_cast basic.tint obj)
+				(* end Std.int() *)
+
+				| TField( ef, FInstance({ cl_path = ([], "String") }, _, { cf_name = "length" }) ) ->
+					{ e with eexpr = TCall(Type.map_expr run e, []) }
+				| TField( ef, field ) when field_name field = "length" && is_string ef.etype ->
+					{ e with eexpr = TCall(Type.map_expr run e, []) }
+				| TCall( ( { eexpr = TField(ef, field) } as efield ), args ) when is_string ef.etype && String.get (field_name field) 0 = '_' ->
+					let field = field_name field in
+					{ e with eexpr = TCall({ efield with eexpr = TField(run ef, FDynamic (String.sub field 1 ( (String.length field) - 1)) )}, List.map run args) }
+				| TCall( ( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, field )) } as efield ), args ) ->
+					let field = field.cf_name in
+					(match field with
+						| "charAt" | "charCodeAt" | "split" | "indexOf"
+						| "lastIndexOf" | "substring" | "substr" ->
+							{ e with eexpr = TCall(mk_static_field_access_infer string_ext field e.epos [], [run ef] @ (List.map run args)) }
+						| _ ->
+							{ e with eexpr = TCall(run efield, List.map run args) }
+					)
+(*				 | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("toString") })) }, [] ) ->
+					run ef *)
+
+				(* | TCast(expr, m) when is_boxed_type e.etype -> *)
+				(* 	(* let unboxed_type gen t tbyte tshort tchar tfloat = match follow t with *) *)
+				(* 	run { e with etype = unboxed_type gen e.etype tbyte tshort tchar tsingle } *)
+
+				| TCast(expr, _) when is_bool e.etype ->
+					{
+						eexpr = TCall(
+							mk_static_field_access_infer runtime_cl "toBool" expr.epos [],
+							[ run expr ]
+						);
+						etype = basic.tbool;
+						epos = e.epos
+					}
+
+				| TCast(expr, _) when is_int_float gen e.etype && not (is_int_float gen expr.etype) ->
+					let needs_cast = match gen.gfollow#run_f e.etype with
+						| TInst _ -> false
+						| _ -> true
+					in
+
+					let fun_name = if like_int e.etype then "toInt" else "toDouble" in
+
+					let ret = {
+						eexpr = TCall(
+							mk_static_field_access_infer runtime_cl fun_name expr.epos [],
+							[ run expr ]
+						);
+						etype = if fun_name = "toDouble" then basic.tfloat else basic.tint;
+						epos = expr.epos
+					} in
+
+					if needs_cast then mk_cast e.etype ret else ret
+
+				(*| TCast(expr, c) when is_int_float gen e.etype ->
+					(* cases when float x = (float) (java.lang.Double val); *)
+					(* FIXME: this fix is broken since it will fail on cases where float x = (float) (java.lang.Float val) or similar. FIX THIS *)
+					let need_second_cast = match gen.gfollow#run_f e.etype with
+						| TInst _ -> false
+						| _ -> true
+					in
+					if need_second_cast then { e with eexpr = TCast(mk_cast (follow e.etype) (run expr), c) }  else Type.map_expr run e*)
+				| TBinop( (Ast.OpAssignOp OpAdd as op), e1, e2)
+				| TBinop( (Ast.OpAdd as op), e1, e2) when is_string e.etype || is_string e1.etype || is_string e2.etype ->
+						let is_assign = match op with Ast.OpAssignOp _ -> true | _ -> false in
+						let mk_to_string e = { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" e.epos [], [run e] ); etype = gen.gcon.basic.tstring	} in
+						let check_cast e = match gen.greal_type e.etype with
+							| TDynamic _
+							| TAbstract({ a_path = ([], "Float") }, [])
+							| TAbstract({ a_path = ([], "Single") }, []) ->
+									mk_to_string e
+							| _ -> run e
+						in
+
+						{ e with eexpr = TBinop(op, (if is_assign then run e1 else check_cast e1), check_cast e2) }
+				| TCast(expr, _) when is_string e.etype ->
+					{ e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" expr.epos [], [run expr] ) }
+
+				| TSwitch(cond, ecases, edefault) when is_string cond.etype ->
+					(*let change_string_switch gen eswitch e1 ecases edefault =*)
+					change_string_switch gen e (run cond) (List.map (fun (el,e) -> (el, run e)) ecases) (Option.map run edefault)
+
+				| TBinop( (Ast.OpNotEq as op), e1, e2)
+				| TBinop( (Ast.OpEq as op), e1, e2) when not (is_null e2 || is_null e1) && (is_string e1.etype || is_string e2.etype || is_equatable gen e1.etype || is_equatable gen e2.etype) ->
+					let static = mk_static_field_access_infer (runtime_cl) "valEq" e1.epos [] in
+					let eret = { eexpr = TCall(static, [run e1; run e2]); etype = gen.gcon.basic.tbool; epos=e.epos } in
+					if op = Ast.OpNotEq then { eret with eexpr = TUnop(Ast.Not, Ast.Prefix, eret) } else eret
+
+				| TBinop( (Ast.OpNotEq | Ast.OpEq as op), e1, e2) when is_cl e1.etype && is_cl e2.etype ->
+					{ e with eexpr = TBinop(op, mk_cast t_empty (run e1), mk_cast t_empty (run e2)) }
+				| _ -> Type.map_expr run e
+		in
+		run
+
+	let configure gen (mapping_func:texpr->texpr) =
+		(if java_hash "Testing string hashCode implementation from haXe" <> (Int32.of_int 545883604) then assert false);
+		let map e = Some(mapping_func e) in
+		gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map
 
 end;;
 
+
+(* ******************************************* *)
+(* handle @:throws *)
+(* ******************************************* *)
+let rec is_checked_exc cl =
+	match cl.cl_path with
+		| ["java";"lang"],"RuntimeException" ->
+			false
+		| ["java";"lang"],"Throwable" ->
+			true
+		| _ -> match cl.cl_super with
+			| None -> false
+			| Some(c,_) -> is_checked_exc c
+
+let rec cls_any_super cl supers =
+	PMap.mem cl.cl_path supers || match cl.cl_super with
+		| None -> false
+		| Some(c,_) -> cls_any_super c supers
+
+let rec handle_throws gen cf =
+	List.iter (handle_throws gen) cf.cf_overloads;
+	match cf.cf_expr with
+	| Some ({ eexpr = TFunction(tf) } as e)  ->
+		let rec collect_throws acc = function
+			| (Meta.Throws, [Ast.EConst (Ast.String path), _],_) :: meta -> (try
+				collect_throws (get_cl ( get_type gen (parse_path path)) :: acc) meta
+			with | Not_found | TypeNotFound _ ->
+				collect_throws acc meta)
+			| [] ->
+				acc
+			| _ :: meta ->
+				collect_throws acc meta
+		in
+		let cf_throws = collect_throws [] cf.cf_meta in
+		let throws = ref (List.fold_left (fun map cl ->
+			PMap.add cl.cl_path cl map
+		) PMap.empty cf_throws) in
+		let rec iter e = match e.eexpr with
+			| TTry(etry,ecatches) ->
+				let old = !throws in
+				let needs_check_block = ref true in
+				List.iter (fun (v,e) ->
+					Type.iter iter e;
+					match follow (run_follow gen v.v_type) with
+						| TInst({ cl_path = ["java";"lang"],"Throwable" },_)
+						| TDynamic _ ->
+							needs_check_block := false
+						| TInst(c,_) when is_checked_exc c ->
+							throws := PMap.add c.cl_path c !throws
+						| _ ->()
+				) ecatches;
+				if !needs_check_block then Type.iter iter etry;
+				throws := old
+			| TField(e, (FInstance(_,_,f) | FStatic(_,f) | FClosure(_,f))) ->
+				let tdefs = collect_throws [] f.cf_meta in
+				if tdefs <> [] && not (List.for_all (fun c -> cls_any_super c !throws) tdefs) then
+					raise Exit;
+				Type.iter iter e
+			| TThrow e -> (match follow (run_follow gen e.etype) with
+				| TInst(c,_) when is_checked_exc c && not (cls_any_super c !throws) ->
+					raise Exit
+				| _ -> iter e)
+			| _ -> Type.iter iter e
+		in
+		(try
+			Type.iter iter e
+		with | Exit -> (* needs typed exception to be caught *)
+			let throwable = get_cl (get_type gen (["java";"lang"],"Throwable")) in
+			let catch_var = alloc_var "typedException" (TInst(throwable,[])) in
+			let rethrow = mk_local catch_var e.epos in
+			let hx_exception = get_cl (get_type gen (["haxe";"lang"], "HaxeException")) in
+			let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], t_dynamic)) rethrow.epos in
+			let wrapped = { rethrow with eexpr = TThrow { rethrow with eexpr = TCall(wrap_static, [rethrow]) }; } in
+			let map_throws cl =
+				let var = alloc_var "typedException" (TInst(cl,List.map (fun _ -> t_dynamic) cl.cl_params)) in
+				var, { tf.tf_expr with eexpr = TThrow (mk_local var e.epos) }
+			in
+			cf.cf_expr <- Some { e with
+				eexpr = TFunction({ tf with
+					tf_expr = mk_block { tf.tf_expr with eexpr = TTry(tf.tf_expr, List.map (map_throws) cf_throws @ [catch_var, wrapped]) }
+				})
+			})
+	| _ -> ()
+
+
 let connecting_string = "?" (* ? see list here http://www.fileformat.info/info/unicode/category/index.htm and here for C# http://msdn.microsoft.com/en-us/library/aa664670.aspx *)
-let default_package = "java" (* I'm having this separated as I'm still not happy with having a cs package. Maybe dotnet would be better? *)
+let default_package = "java"
 let strict_mode = ref false (* strict mode is so we can check for unexpected information *)
 
-(* reserved c# words *)
+(* reserved java words *)
 let reserved = let res = Hashtbl.create 120 in
-  List.iter (fun lst -> Hashtbl.add res lst ("_" ^ lst)) ["abstract"; "assert"; "boolean"; "break"; "byte"; "case"; "catch"; "char"; "class";
-    "const"; "continue"; "default"; "do"; "double"; "else"; "enum"; "extends"; "final";
-    "false"; "finally"; "float"; "for"; "goto"; "if"; "implements"; "import"; "instanceof"; "int";
-    "interface"; "long"; "native"; "new"; "null"; "package"; "private"; "protected"; "public"; "return"; "short";
-    "static"; "strictfp"; "super"; "switch"; "synchronized"; "this"; "throw"; "throws"; "transient"; "true"; "try";
-    "void"; "volatile"; "while"; ];
-  res
+	List.iter (fun lst -> Hashtbl.add res lst ("_" ^ lst)) ["abstract"; "assert"; "boolean"; "break"; "byte"; "case"; "catch"; "char"; "class";
+		"const"; "continue"; "default"; "do"; "double"; "else"; "enum"; "extends"; "final";
+		"false"; "finally"; "float"; "for"; "goto"; "if"; "implements"; "import"; "instanceof"; "int";
+		"interface"; "long"; "native"; "new"; "null"; "package"; "private"; "protected"; "public"; "return"; "short";
+		"static"; "strictfp"; "super"; "switch"; "synchronized"; "this"; "throw"; "throws"; "transient"; "true"; "try";
+		"void"; "volatile"; "while"; ];
+	res
 
 let dynamic_anon = TAnon( { a_fields = PMap.empty; a_status = ref Closed } )
 
 let rec get_class_modifiers meta cl_type cl_access cl_modifiers =
-  match meta with
-    | [] -> cl_type,cl_access,cl_modifiers
-    (*| (Meta.Struct,[],_) :: meta -> get_class_modifiers meta "struct" cl_access cl_modifiers*)
-    | (Meta.Protected,[],_) :: meta -> get_class_modifiers meta cl_type "protected" cl_modifiers
-    | (Meta.Internal,[],_) :: meta -> get_class_modifiers meta cl_type "" cl_modifiers
-    (* no abstract for now | (":abstract",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("abstract" :: cl_modifiers)
-    | (Meta.Static,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("static" :: cl_modifiers) TODO: support those types *)
-    | (Meta.Final,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("final" :: cl_modifiers)
-    | _ :: meta -> get_class_modifiers meta cl_type cl_access cl_modifiers
+	match meta with
+		| [] -> cl_type,cl_access,cl_modifiers
+		(*| (Meta.Struct,[],_) :: meta -> get_class_modifiers meta "struct" cl_access cl_modifiers*)
+		| (Meta.Protected,[],_) :: meta -> get_class_modifiers meta cl_type "protected" cl_modifiers
+		| (Meta.Internal,[],_) :: meta -> get_class_modifiers meta cl_type "" cl_modifiers
+		(* no abstract for now | (":abstract",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("abstract" :: cl_modifiers)
+		| (Meta.Static,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("static" :: cl_modifiers) TODO: support those types *)
+		| (Meta.Final,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("final" :: cl_modifiers)
+		| _ :: meta -> get_class_modifiers meta cl_type cl_access cl_modifiers
 
 let rec get_fun_modifiers meta access modifiers =
-  match meta with
-    | [] -> access,modifiers
-    | (Meta.Protected,[],_) :: meta -> get_fun_modifiers meta "protected" modifiers
-    | (Meta.Internal,[],_) :: meta -> get_fun_modifiers meta "" modifiers
-    (*| (Meta.ReadOnly,[],_) :: meta -> get_fun_modifiers meta access ("readonly" :: modifiers)*)
-    (*| (Meta.Unsafe,[],_) :: meta -> get_fun_modifiers meta access ("unsafe" :: modifiers)*)
-    | (Meta.Volatile,[],_) :: meta -> get_fun_modifiers meta access ("volatile" :: modifiers)
-    | (Meta.Transient,[],_) :: meta -> get_fun_modifiers meta access ("transient" :: modifiers)
-    | (Meta.Native,[],_) :: meta -> get_fun_modifiers meta access ("native" :: modifiers)
-    | _ :: meta -> get_fun_modifiers meta access modifiers
+	match meta with
+		| [] -> access,modifiers
+		| (Meta.Protected,[],_) :: meta -> get_fun_modifiers meta "protected" modifiers
+		| (Meta.Internal,[],_) :: meta -> get_fun_modifiers meta "" modifiers
+		| (Meta.ReadOnly,[],_) :: meta -> get_fun_modifiers meta access ("final" :: modifiers)
+		(*| (Meta.Unsafe,[],_) :: meta -> get_fun_modifiers meta access ("unsafe" :: modifiers)*)
+		| (Meta.Volatile,[],_) :: meta -> get_fun_modifiers meta access ("volatile" :: modifiers)
+		| (Meta.Transient,[],_) :: meta -> get_fun_modifiers meta access ("transient" :: modifiers)
+		| (Meta.Native,[],_) :: meta -> get_fun_modifiers meta access ("native" :: modifiers)
+		| _ :: meta -> get_fun_modifiers meta access modifiers
 
 (* this was the way I found to pass the generator context to be accessible across all functions here *)
 (* so 'configure' is almost 'top-level' and will have all functions needed to make this work *)
 let configure gen =
-  let basic = gen.gcon.basic in
-
-  let fn_cl = get_cl (get_type gen (["haxe";"lang"],"Function")) in
-
-  let runtime_cl = get_cl (get_type gen (["haxe";"lang"],"Runtime")) in
-
-  (*let string_ref = get_cl ( get_type gen (["haxe";"lang"], "StringRefl")) in*)
-
-  let ti64 = match ( get_type gen (["haxe";"_Int64"], "NativeInt64") ) with | TTypeDecl t -> TType(t,[]) | _ -> assert false in
-
-  let has_tdynamic params =
-    List.exists (fun e -> match run_follow gen e with | TDynamic _ -> true | _ -> false) params
-  in
-
-  (*
-    The type parameters always need to be changed to their boxed counterparts
-  *)
-  let change_param_type md params =
-    match md with
-      | TClassDecl( { cl_path = (["java"], "NativeArray") } ) -> params
-      | _ ->
-        match params with
-          | [] -> []
-          | _ ->
-            if has_tdynamic params then List.map (fun _ -> t_dynamic) params else
-              List.map (fun t ->
-                let f_t = gen.gfollow#run_f t in
-                match f_t  with
-                  | TEnum ({ e_path = ([], "Bool") }, [])
-                  | TAbstract ({ a_path = ([], "Bool") },[])
-                  | TInst ({ cl_path = ([],"Float") },[])
-                  | TAbstract ({ a_path = ([],"Float") },[])
-                  | TInst ({ cl_path = ["haxe"],"Int32" },[])
-                  | TInst ({ cl_path = ["haxe"],"Int64" },[])
-                  | TInst ({ cl_path = ([],"Int") },[])
-                  | TAbstract ({ a_path = ([],"Int") },[])
-                  | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[])
-                  | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[])
-                  | TType ({ t_path = ["java"],"Int8" },[])
-                  | TAbstract ({ a_path = ["java"],"Int8" },[])
-                  | TType ({ t_path = ["java"],"Int16" },[])
-                  | TAbstract ({ a_path = ["java"],"Int16" },[])
-                  | TType ({ t_path = ["java"],"Char16" },[])
-                  | TAbstract ({ a_path = ["java"],"Char16" },[])
-                  | TType ({ t_path = [],"Single" },[])
-                  | TAbstract ({ a_path = [],"Single" },[]) ->
-                      basic.tnull f_t
-                  (*| TType ({ t_path = [], "Null"*)
-                  | TInst (cl, ((_ :: _) as p)) ->
-                    TInst(cl, List.map (fun _ -> t_dynamic) p)
-                  | TEnum (e, ((_ :: _) as p)) ->
-                    TEnum(e, List.map (fun _ -> t_dynamic) p)
-                  | _ -> t
-              ) params
-  in
-
-  let change_clname name =
-    String.map (function | '$' -> '.' | c -> c) name
-  in
-  let change_id name = try Hashtbl.find reserved name with | Not_found -> name in
-  let rec change_ns ns = match ns with
-    | [] -> ["haxe"; "root"]
-    | _ -> List.map change_id ns
-  in
-  let change_field = change_id in
-
-  let write_id w name = write w (change_id name) in
-
-  let write_field w name = write w (change_field name) in
-
-  gen.gfollow#add ~name:"follow_basic" (fun t -> match t with
-      | TEnum ({ e_path = ([], "Bool") }, [])
-      | TAbstract ({ a_path = ([], "Bool") },[])
-      | TEnum ({ e_path = ([], "Void") }, [])
-      | TAbstract ({ a_path = ([], "Void") },[])
-      | TInst ({ cl_path = ([],"Float") },[])
-      | TAbstract ({ a_path = ([],"Float") },[])
-      | TInst ({ cl_path = ([],"Int") },[])
-      | TAbstract ({ a_path = ([],"Int") },[])
-      | TInst( { cl_path = (["haxe"], "Int32") }, [] )
-      | TInst( { cl_path = (["haxe"], "Int64") }, [] )
-      | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[])
-      | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[])
-      | TType ({ t_path = ["java"],"Int8" },[])
-      | TAbstract ({ a_path = ["java"],"Int8" },[])
-      | TType ({ t_path = ["java"],"Int16" },[])
-      | TAbstract ({ a_path = ["java"],"Int16" },[])
-      | TType ({ t_path = ["java"],"Char16" },[])
-      | TAbstract ({ a_path = ["java"],"Char16" },[])
-      | TType ({ t_path = [],"Single" },[])
-      | TAbstract ({ a_path = [],"Single" },[])
-      | TType ({ t_path = [],"Null" },[_]) -> Some t
-      | TAbstract ({ a_impl = Some _ } as a, pl) ->
-          Some (gen.gfollow#run_f ( Codegen.Abstract.get_underlying_type a pl) )
-	    | TAbstract( { a_path = ([], "EnumValue") }, _ )
-      | TInst( { cl_path = ([], "EnumValue") }, _  ) -> Some t_dynamic
-      | _ -> None);
-
-  let change_path path = (change_ns (fst path), change_clname (snd path)) in
-
-  let path_s path = match path with
-    | (ns,clname) -> path_s (change_ns ns, change_clname clname)
-  in
-
-  let cl_cl = get_cl (get_type gen (["java";"lang"],"Class")) in
-
-  let rec real_type t =
-    let t = gen.gfollow#run_f t in
-    match t with
-      | TAbstract ({ a_impl = Some _ } as a, pl) ->
-        real_type (Codegen.Abstract.get_underlying_type a pl)
-      | TInst( { cl_path = (["haxe"], "Int32") }, [] ) -> gen.gcon.basic.tint
-      | TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> ti64
-      | TAbstract( { a_path = ([], "Class") }, p  )
-      | TAbstract( { a_path = ([], "Enum") }, p  )
-      | TInst( { cl_path = ([], "Class") }, p  )
-      | TInst( { cl_path = ([], "Enum") }, p  ) -> TInst(cl_cl,p)
-      | TEnum(e,params) -> TEnum(e, List.map (fun _ -> t_dynamic) params)
-      | TInst(c,params) when Meta.has Meta.Enum c.cl_meta ->
-        TInst(c, List.map (fun _ -> t_dynamic) params)
-      | TInst _ -> t
-      | TType({ t_path = ([], "Null") }, [t]) when is_java_basic_type t -> t_dynamic
-      | TType({ t_path = ([], "Null") }, [t]) ->
-        (match follow t with
-          | TInst( { cl_kind = KTypeParameter _ }, []) ->
-              (* t_dynamic *)
-              real_type t
-          | _ -> real_type t
-        )
-      | TType _ | TAbstract _ -> t
-      | TAnon (anon) -> (match !(anon.a_status) with
-        | Statics _ | EnumStatics _ | AbstractStatics _ -> t
-        | _ -> t_dynamic)
-      | TFun _ -> TInst(fn_cl,[])
-      | _ -> t_dynamic
-  in
-
-  let scope = ref PMap.empty in
-  let imports = ref [] in
-
-  let clear_scope () =
-    scope := PMap.empty;
-    imports := [];
-  in
-
-  let add_scope name =
-    scope := PMap.add name () !scope
-  in
-
-  let add_import pos path =
-    let name = snd path in
-    let rec loop = function
-      | (pack, n) :: _ when name = n ->
-          if path <> (pack,n) then
-            gen.gcon.error ("This expression cannot be generated because " ^ path_s path ^ " is shadowed by the current scope and ") pos
-      | _ :: tl ->
-          loop tl
-      | [] ->
-          (* add import *)
-          imports := path :: !imports
-    in
-    loop !imports
-  in
-
-  let path_s_import pos path = match path with
-    | [], name when PMap.mem name !scope ->
-        gen.gcon.error ("This expression cannot be generated because " ^ name ^ " is shadowed by the current scope") pos;
-        name
-    | pack1 :: _, name when PMap.mem pack1 !scope -> (* exists in scope *)
-        add_import pos path;
-        (* check if name exists in scope *)
-        if PMap.mem name !scope then
-          gen.gcon.error ("This expression cannot be generated because " ^ pack1 ^ " and " ^ name ^ " are both shadowed by the current scope") pos;
-        name
-    | _ -> path_s path
-  in
-
-  let is_dynamic t = match real_type t with
-    | TMono _ | TDynamic _
-    | TInst({ cl_kind = KTypeParameter _ }, _) -> true
-    | TAnon anon ->
-      (match !(anon.a_status) with
-        | EnumStatics _ | Statics _ | AbstractStatics _ -> false
-        | _ -> true
-      )
-    | _ -> false
-  in
-
-  let rec t_s pos t =
-    match real_type t with
-      (* basic types *)
-      | TEnum ({ e_path = ([], "Bool") }, [])
-      | TAbstract ({ a_path = ([], "Bool") },[]) -> "boolean"
-      | TEnum ({ e_path = ([], "Void") }, [])
-      | TAbstract ({ a_path = ([], "Void") },[]) ->
-          path_s_import pos (["java";"lang"], "Object")
-      | TInst ({ cl_path = ([],"Float") },[])
-      | TAbstract ({ a_path = ([],"Float") },[]) -> "double"
-      | TInst ({ cl_path = ([],"Int") },[])
-      | TAbstract ({ a_path = ([],"Int") },[]) -> "int"
-      | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[])
-      | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[]) -> "long"
-      | TType ({ t_path = ["java"],"Int8" },[])
-      | TAbstract ({ a_path = ["java"],"Int8" },[]) -> "byte"
-      | TType ({ t_path = ["java"],"Int16" },[])
-      | TAbstract ({ a_path = ["java"],"Int16" },[]) -> "short"
-      | TType ({ t_path = ["java"],"Char16" },[])
-      | TAbstract ({ a_path = ["java"],"Char16" },[]) -> "char"
-      | TType ({ t_path = [],"Single" },[])
-      | TAbstract ({ a_path = [],"Single" },[]) -> "float"
-      | TInst ({ cl_path = ["haxe"],"Int32" },[])
-      | TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> "int"
-      | TInst ({ cl_path = ["haxe"],"Int64" },[])
-      | TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> "long"
-      | TInst({ cl_path = (["java"], "NativeArray") }, [param]) ->
-        let rec check_t_s t =
-          match real_type t with
-            | TInst({ cl_path = (["java"], "NativeArray") }, [param]) ->
-              (check_t_s param) ^ "[]"
-            | _ -> t_s pos (run_follow gen t)
-        in
-        (check_t_s param) ^ "[]"
-
-      (* end of basic types *)
-      | TInst ({ cl_kind = KTypeParameter _; cl_path=p }, []) -> snd p
-      | TAbstract ({ a_path = [], "Dynamic" },[]) ->
-          path_s_import pos (["java";"lang"], "Object")
-      | TMono r -> (match !r with | None -> "java.lang.Object" | Some t -> t_s pos (run_follow gen t))
-      | TInst ({ cl_path = [], "String" }, []) ->
-          path_s_import pos (["java";"lang"], "String")
-      | TAbstract ({ a_path = [], "Class" }, [p]) | TAbstract ({ a_path = [], "Enum" }, [p])
-      | TInst ({ cl_path = [], "Class" }, [p]) | TInst ({ cl_path = [], "Enum" }, [p]) ->
-          path_param_s pos (TClassDecl cl_cl) (["java";"lang"], "Class") [p]
-      | TAbstract ({ a_path = [], "Class" }, _) | TAbstract ({ a_path = [], "Enum" }, _)
-      | TInst ({ cl_path = [], "Class" }, _) | TInst ({ cl_path = [], "Enum" }, _) ->
-          path_s_import pos (["java";"lang"], "Class")
-      | TEnum ({e_path = p}, _) ->
-          path_s_import pos p
-      | TInst (({cl_path = p;} as cl), _) when Meta.has Meta.Enum cl.cl_meta ->
-          path_s_import pos p
-      | TInst (({cl_path = p;} as cl), params) -> (path_param_s pos (TClassDecl cl) p params)
-      | TType (({t_path = p;} as t), params) -> (path_param_s pos (TTypeDecl t) p params)
-      | TAnon (anon) ->
-        (match !(anon.a_status) with
-          | Statics _ | EnumStatics _ | AbstractStatics _ ->
-              path_s_import pos (["java";"lang"], "Class")
-          | _ ->
-              path_s_import pos (["java";"lang"], "Object"))
-        | TDynamic _ ->
-            path_s_import pos (["java";"lang"], "Object")
-      (* No Lazy type nor Function type made. That's because function types will be at this point be converted into other types *)
-      | _ -> if !strict_mode then begin trace ("[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"); assert false end else "[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"
-
-  and param_t_s pos t =
-    match run_follow gen t with
-      | TEnum ({ e_path = ([], "Bool") }, [])
-      | TAbstract ({ a_path = ([], "Bool") },[]) ->
-          path_s_import pos (["java";"lang"], "Boolean")
-      | TInst ({ cl_path = ([],"Float") },[])
-      | TAbstract ({ a_path = ([],"Float") },[]) ->
-          path_s_import pos (["java";"lang"], "Double")
-      | TInst ({ cl_path = ([],"Int") },[])
-      | TAbstract ({ a_path = ([],"Int") },[]) ->
-          path_s_import pos (["java";"lang"], "Integer")
-      | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[])
-      | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[]) ->
-          path_s_import pos (["java";"lang"], "Long")
-      | TInst ({ cl_path = ["haxe"],"Int64" },[])
-      | TAbstract ({ a_path = ["haxe"],"Int64" },[]) ->
-          path_s_import pos (["java";"lang"], "Long")
-      | TInst ({ cl_path = ["haxe"],"Int32" },[])
-      | TAbstract ({ a_path = ["haxe"],"Int32" },[]) ->
-          path_s_import pos (["java";"lang"], "Integer")
-      | TType ({ t_path = ["java"],"Int8" },[])
-      | TAbstract ({ a_path = ["java"],"Int8" },[]) ->
-          path_s_import pos (["java";"lang"], "Byte")
-      | TType ({ t_path = ["java"],"Int16" },[])
-      | TAbstract ({ a_path = ["java"],"Int16" },[]) ->
-          path_s_import pos (["java";"lang"], "Short")
-      | TType ({ t_path = ["java"],"Char16" },[])
-      | TAbstract ({ a_path = ["java"],"Char16" },[]) ->
-          path_s_import pos (["java";"lang"], "Character")
-      | TType ({ t_path = [],"Single" },[])
-      | TAbstract ({ a_path = [],"Single" },[]) ->
-          path_s_import pos (["java";"lang"], "Float")
-      | TDynamic _ -> "?"
-      | TInst (cl, params) -> t_s pos (TInst(cl, change_param_type (TClassDecl cl) params))
-      | TType (cl, params) -> t_s pos (TType(cl, change_param_type (TTypeDecl cl) params))
-      | TEnum (e, params) -> t_s pos (TEnum(e, change_param_type (TEnumDecl e) params))
-      | _ -> t_s pos t
-
-  and path_param_s pos md path params =
-      match params with
-        | [] -> path_s_import pos path
-        | _ when has_tdynamic (change_param_type md params) -> path_s_import pos path
-        | _ -> sprintf "%s<%s>" (path_s_import pos path) (String.concat ", " (List.map (fun t -> param_t_s pos t) (change_param_type md params)))
-  in
-
-  let rett_s pos t =
-    match t with
-      | TEnum ({e_path = ([], "Void")}, [])
-      | TAbstract ({ a_path = ([], "Void") },[]) -> "void"
-      | _ -> t_s pos t
-  in
-
-  let high_surrogate c = (c lsr 10) + 0xD7C0 in
-  let low_surrogate c = (c land 0x3FF) lor 0xDC00 in
-
-  let escape ichar b =
-    match ichar with
-      | 92 (* \ *) -> Buffer.add_string b "\\\\"
-      | 39 (* ' *) -> Buffer.add_string b "\\\'"
-      | 34 -> Buffer.add_string b "\\\""
-      | 13 (* \r *) -> Buffer.add_string b "\\r"
-      | 10 (* \n *) -> Buffer.add_string b "\\n"
-      | 9 (* \t *) -> Buffer.add_string b "\\t"
-      | c when c < 32 || (c >= 127 && c <= 0xFFFF) -> Buffer.add_string b (Printf.sprintf "\\u%.4x" c)
-      | c when c > 0xFFFF -> Buffer.add_string b (Printf.sprintf "\\u%.4x\\u%.4x" (high_surrogate c) (low_surrogate c))
-      | c -> Buffer.add_char b (Char.chr c)
-  in
-
-  let escape s =
-    let b = Buffer.create 0 in
-    (try
-      UTF8.validate s;
-      UTF8.iter (fun c -> escape (UChar.code c) b) s
-    with
-      UTF8.Malformed_code ->
-        String.iter (fun c -> escape (Char.code c) b) s
-    );
-    Buffer.contents b
-  in
-
-  let has_semicolon e =
-    match e.eexpr with
-      | TLocal { v_name = "__fallback__" }
-      | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt _) } ] ) -> false
-      | TBlock _ | TFor _ | TSwitch _ | TPatMatch _ | TTry _ | TIf _ -> false
-      | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false
-      | _ -> true
-  in
-
-  let in_value = ref false in
-
-  let rec md_s pos md =
-    let md = follow_module (gen.gfollow#run_f) md in
-    match md with
-      | TClassDecl (cl) ->
-        t_s pos (TInst(cl,[]))
-      | TEnumDecl (e) ->
-        t_s pos (TEnum(e,[]))
-      | TTypeDecl t ->
-        t_s pos (TType(t, []))
-      | TAbstractDecl a ->
-        t_s pos (TAbstract(a, []))
-  in
-
-  (*
-    it seems that Java doesn't like when you create a new array with the type parameter defined
-    so we'll just ignore all type parameters, and hope for the best!
-  *)
-  let rec transform_nativearray_t t = match real_type t with
-    | TInst( ({ cl_path = (["java"], "NativeArray") } as narr), [t]) ->
-      TInst(narr, [transform_nativearray_t t])
-    | TInst(cl, params) -> TInst(cl, List.map (fun _ -> t_dynamic) params)
-    | TEnum(e, params) -> TEnum(e, List.map (fun _ -> t_dynamic) params)
-    | TType(t, params) -> TType(t, List.map (fun _ -> t_dynamic) params)
-    | _ -> t
-  in
-
-  let expr_s w e =
-    in_value := false;
-    let rec expr_s w e =
-      let was_in_value = !in_value in
-      in_value := true;
-      match e.eexpr with
-        | TConst c ->
-          (match c with
-            | TInt i32 ->
-              print w "%ld" i32;
-              (match real_type e.etype with
-                | TType( { t_path = (["haxe";"_Int64"], "NativeInt64") }, [] ) -> write w "L";
-                | _ -> ()
-              )
-            | TFloat s ->
-              write w s;
-              (* fix for Int notation, which only fit in a Float *)
-              (if not (String.contains s '.' || String.contains s 'e' || String.contains s 'E') then write w ".0");
-              (match real_type e.etype with
-                | TType( { t_path = ([], "Single") }, [] ) -> write w "f"
-                | _ -> ()
-              )
-            | TString s -> print w "\"%s\"" (escape s)
-            | TBool b -> write w (if b then "true" else "false")
-            | TNull ->
-              (match real_type e.etype with
-                | TType( { t_path = (["haxe";"_Int64"], "NativeInt64") }, [] )
-                | TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> write w "0L"
-                | TInst( { cl_path = (["haxe"], "Int32") }, [] )
-                | TInst({ cl_path = ([], "Int") },[])
-                | TAbstract ({ a_path = ([], "Int") },[]) -> expr_s w ({ e with eexpr = TConst(TInt Int32.zero) })
-                | TInst({ cl_path = ([], "Float") },[])
-                | TAbstract ({ a_path = ([], "Float") },[]) -> expr_s w ({ e with eexpr = TConst(TFloat "0.0") })
-                | TEnum({ e_path = ([], "Bool") }, [])
-                | TAbstract ({ a_path = ([], "Bool") },[]) -> write w "false"
-                | TAbstract _ when like_int e.etype ->
-                  expr_s w { e with eexpr = TConst(TInt Int32.zero) }
-                | TAbstract _ when like_float e.etype ->
-                  expr_s w { e with eexpr = TConst(TFloat "0.0") }
-                | _ -> write w "null")
-            | TThis -> write w "this"
-            | TSuper -> write w "super")
-        | TLocal { v_name = "__fallback__" } -> ()
-        | TLocal { v_name = "__sbreak__" } -> write w "break"
-        | TLocal { v_name = "__undefined__" } ->
-          write w (t_s e.epos (TInst(runtime_cl, List.map (fun _ -> t_dynamic) runtime_cl.cl_types)));
-          write w ".undefined";
-        | TLocal var ->
-          write_id w var.v_name
-        | TField(_, FEnum(en,ef)) ->
-          let s = ef.ef_name in
-          print w "%s." (path_s_import e.epos en.e_path); write_field w s
-        | TArray (e1, e2) ->
-          expr_s w e1; write w "["; expr_s w e2; write w "]"
-        | TBinop ((Ast.OpAssign as op), e1, e2)
-        | TBinop ((Ast.OpAssignOp _ as op), e1, e2) ->
-          expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2
-        | TBinop (op, e1, e2) ->
-          write w "( ";
-          expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2;
-          write w " )"
-        | TField (e, FStatic(_, cf)) when Meta.has Meta.Native cf.cf_meta ->
-          let rec loop meta = match meta with
-            | (Meta.Native, [EConst (String s), _],_) :: _ ->
-              expr_s w e; write w "."; write_field w s
-            | _ :: tl -> loop tl
-            | [] -> expr_s w e; write w "."; write_field w (cf.cf_name)
-          in
-          loop cf.cf_meta
-        | TField (e, s) ->
-          expr_s w e; write w "."; write_field w (field_name s)
-        | TTypeExpr (TClassDecl { cl_path = (["haxe"], "Int32") }) ->
-          write w (path_s_import e.epos (["haxe"], "Int32"))
-        | TTypeExpr (TClassDecl { cl_path = (["haxe"], "Int64") }) ->
-          write w (path_s_import e.epos (["haxe"], "Int64"))
-        | TTypeExpr mt -> write w (md_s e.epos mt)
-        | TParenthesis e ->
-          write w "("; expr_s w e; write w ")"
-        | TMeta (_,e) ->
-          expr_s w e
-        | TArrayDecl el when t_has_type_param_shallow false e.etype ->
-          print w "( (%s) (new java.lang.Object[] " (t_s e.epos e.etype);
-          write w "{";
-          ignore (List.fold_left (fun acc e ->
-            (if acc <> 0 then write w ", ");
-            expr_s w e;
-            acc + 1
-          ) 0 el);
-          write w "}) )"
-        | TArrayDecl el ->
-          print w "new %s" (param_t_s e.epos (transform_nativearray_t e.etype));
-          let is_double = match follow e.etype with
-           | TInst(_,[ t ]) -> if like_float t && not (like_int t) then Some t else None
-           | _ -> None
-          in
-
-          write w "{";
-          ignore (List.fold_left (fun acc e ->
-            (if acc <> 0 then write w ", ");
-            (* this is a hack so we are able to convert ints to boxed Double / Float when needed *)
-            let e = if is_some is_double then mk_cast (get is_double) e else e in
-
-            expr_s w e;
-            acc + 1
-          ) 0 el);
-          write w "}"
-        | TCall( ( { eexpr = TField(_, FStatic({ cl_path = ([], "String") }, { cf_name = "fromCharCode" })) } ), [cc] ) ->
-            write w "Character.toString((char) ";
-            expr_s w cc;
-            write w ")"
-        | TCall ({ eexpr = TLocal( { v_name = "__is__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) ->
-          write w "( ";
-          expr_s w expr;
-          write w " instanceof ";
-          write w (md_s e.epos md);
-          write w " )"
-        | TCall ({ eexpr = TLocal( { v_name = "__java__" } ) }, [ { eexpr = TConst(TString(s)) } ] ) ->
-          write w s
-        | TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, [ eobj; eblock ] ) ->
-          write w "synchronized(";
-          expr_s w eobj;
-          write w ")";
-          (match eblock.eexpr with
-          | TBlock(_ :: _) ->
-            expr_s w eblock
-          | _ ->
-            begin_block w;
-            expr_s w eblock;
-            if has_semicolon eblock then write w ";";
-            end_block w;
-          )
-        | TCall ({ eexpr = TLocal( { v_name = "__goto__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
-          print w "break label%ld" v
-        | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
-          print w "label%ld:" v
-        | TCall ({ eexpr = TLocal( { v_name = "__typeof__" } ) }, [ { eexpr = TTypeExpr md } as expr ] ) ->
-          expr_s w expr;
-          write w ".class"
-        | TCall (e, el) ->
-          let rec extract_tparams params el =
-            match el with
-              | ({ eexpr = TLocal({ v_name = "$type_param" }) } as tp) :: tl ->
-                extract_tparams (tp.etype :: params) tl
-              | _ -> (params, el)
-          in
-          let params, el = extract_tparams [] el in
-
-          expr_s w e;
-
-          (*(match params with
-            | [] -> ()
-            | params ->
-              let md = match e.eexpr with
-                | TField(ef, _) -> t_to_md (run_follow gen ef.etype)
-                | _ -> assert false
-              in
-              write w "<";
-              ignore (List.fold_left (fun acc t ->
-                (if acc <> 0 then write w ", ");
-                write w (param_t_s (change_param_type md t));
-                acc + 1
-              ) 0 params);
-              write w ">"
-          );*)
-
-          write w "(";
-          ignore (List.fold_left (fun acc e ->
-            (if acc <> 0 then write w ", ");
-            expr_s w e;
-            acc + 1
-          ) 0 el);
-          write w ")"
-        | TNew (({ cl_path = (["java"], "NativeArray") } as cl), params, [ size ]) ->
-          let rec check_t_s t times =
-            match real_type t with
-              | TInst({ cl_path = (["java"], "NativeArray") }, [param]) ->
-                (check_t_s param (times+1))
-              | _ ->
-                print w "new %s[" (t_s e.epos (transform_nativearray_t t));
-                expr_s w size;
-                print w "]";
-                let rec loop i =
-                  if i <= 0 then () else (write w "[]"; loop (i-1))
-                in
-                loop (times - 1)
-          in
-          check_t_s (TInst(cl, params)) 0
-        | TNew ({ cl_path = ([], "String") } as cl, [], el) ->
-          write w "new ";
-          write w (t_s e.epos (TInst(cl, [])));
-          write w "(";
-          ignore (List.fold_left (fun acc e ->
-            (if acc <> 0 then write w ", ");
-            expr_s w e;
-            acc + 1
-          ) 0 el);
-          write w ")"
-        | TNew ({ cl_kind = KTypeParameter _ } as cl, params, el) ->
-          print w "null /* This code should never be reached. It was produced by the use of @:generic on a new type parameter instance: %s */" (path_param_s e.epos (TClassDecl cl) cl.cl_path params)
-        | TNew (cl, params, el) ->
-          write w "new ";
-          write w (path_param_s e.epos (TClassDecl cl) cl.cl_path params);
-          write w "(";
-          ignore (List.fold_left (fun acc e ->
-            (if acc <> 0 then write w ", ");
-            expr_s w e;
-            acc + 1
-          ) 0 el);
-          write w ")"
-        | TUnop ((Ast.Increment as op), flag, e)
-        | TUnop ((Ast.Decrement as op), flag, e) ->
-          (match flag with
-            | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " " ); expr_s w e
-            | Ast.Postfix -> expr_s w e; write w (Ast.s_unop op))
-        | TUnop (op, flag, e) ->
-          (match flag with
-            | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " (" ); expr_s w e; write w ") "
-            | Ast.Postfix -> write w "("; expr_s w e; write w (") " ^ Ast.s_unop op))
-        | TVar (var, eopt) ->
-          print w "%s " (t_s e.epos var.v_type);
-          write_id w var.v_name;
-          (match eopt with
-            | None ->
-              write w " = ";
-              expr_s w (null var.v_type e.epos)
-            | Some e ->
-              write w " = ";
-              expr_s w e
-          )
-        | TBlock [e] when was_in_value ->
-          expr_s w e
-        | TBlock el ->
-          begin_block w;
-          (*let last_line = ref (-1) in
-          let line_directive p =
-            let cur_line = Lexer.get_error_line p in
-            let is_relative_path = (String.sub p.pfile 0 1) = "." in
-            let file = if is_relative_path then "../" ^ p.pfile else p.pfile in
-            if cur_line <> ((!last_line)+1) then begin print w "//#line %d \"%s\"" cur_line (Ast.s_escape file); newline w end;
-            last_line := cur_line in*)
-          List.iter (fun e ->
-            (*line_directive e.epos;*)
-            in_value := false;
-            (match e.eexpr with
-            | TConst _ -> ()
-            | _ ->
-              expr_s w e;
-              (if has_semicolon e then write w ";");
-              newline w);
-          ) el;
-          end_block w
-        | TIf (econd, e1, Some(eelse)) when was_in_value ->
-          write w "( ";
-          expr_s w (mk_paren econd);
-          write w " ? ";
-          expr_s w (mk_paren e1);
-          write w " : ";
-          expr_s w (mk_paren eelse);
-          write w " )";
-        | TIf (econd, e1, eelse) ->
-          write w "if ";
-          expr_s w (mk_paren econd);
-          write w " ";
-          in_value := false;
-          expr_s w (mk_block e1);
-          (match eelse with
-            | None -> ()
-            | Some e ->
-              write w " else ";
-              in_value := false;
-              expr_s w (mk_block e)
-          )
-        | TWhile (econd, eblock, flag) ->
-          (match flag with
-            | Ast.NormalWhile ->
-              write w "while ";
-              expr_s w (mk_paren econd);
-              write w "";
-              in_value := false;
-              expr_s w (mk_block eblock)
-            | Ast.DoWhile ->
-              write w "do ";
-              in_value := false;
-              expr_s w (mk_block eblock);
-              write w "while ";
-              in_value := true;
-              expr_s w (mk_paren econd);
-          )
-        | TSwitch (econd, ele_l, default) ->
-          write w "switch ";
-          expr_s w (mk_paren econd);
-          begin_block w;
-          List.iter (fun (el, e) ->
-            List.iter (fun e ->
-              write w "case ";
-              in_value := true;
-              expr_s w e;
-              write w ":";
-            ) el;
-            newline w;
-            in_value := false;
-            expr_s w (mk_block e);
-            newline w;
-            newline w
-          ) ele_l;
-          if is_some default then begin
-            write w "default:";
-            newline w;
-            in_value := false;
-            expr_s w (get default);
-            newline w;
-          end;
-          end_block w
-        | TTry (tryexpr, ve_l) ->
-          write w "try ";
-          in_value := false;
-          expr_s w (mk_block tryexpr);
-          let pos = e.epos in
-          List.iter (fun (var, e) ->
-            print w "catch (%s %s)" (t_s pos var.v_type) (var.v_name);
-            in_value := false;
-            expr_s w (mk_block e);
-            newline w
-          ) ve_l
-        | TReturn eopt ->
-          write w "return ";
-          if is_some eopt then expr_s w (get eopt)
-        | TBreak -> write w "break"
-        | TContinue -> write w "continue"
-        | TThrow e ->
-          write w "throw ";
-          expr_s w e
-        | TCast (e1,md_t) ->
-          ((*match gen.gfollow#run_f e.etype with
-            | TType({ t_path = ([], "UInt") }, []) ->
-              write w "( unchecked ((uint) ";
-              expr_s w e1;
-              write w ") )"
-            | _ ->*)
-              (* FIXME I'm ignoring module type *)
-              print w "((%s) (" (t_s e.epos e.etype);
-              expr_s w e1;
-              write w ") )"
-          )
-        | TFor (_,_,content) ->
-          write w "[ for not supported ";
-          expr_s w content;
-          write w " ]";
-          if !strict_mode then assert false
-        | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then assert false
-        | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then assert false
-        | TPatMatch _ -> write w "[ match not supported ]"; if !strict_mode then assert false
-        | TEnumParameter _ -> write w "[ enum parameter not supported ]"; if !strict_mode then assert false
-    in
-    expr_s w e
-  in
-
-  let get_string_params cl_types =
-    match cl_types with
-      | [] ->
-        ("","")
-      | _ ->
-        let params = sprintf "<%s>" (String.concat ", " (List.map (fun (_, tcl) -> match follow tcl with | TInst(cl, _) -> snd cl.cl_path | _ -> assert false) cl_types)) in
-        let params_extends = List.fold_left (fun acc (name, t) ->
-          match run_follow gen t with
-            | TInst (cl, p) ->
-              (match cl.cl_implements with
-                | [] -> acc
-                | _ -> acc) (* TODO
-                | _ -> (sprintf " where %s : %s" name (String.concat ", " (List.map (fun (cl,p) -> path_param_s (TClassDecl cl) cl.cl_path p) cl.cl_implements))) :: acc ) *)
-            | _ -> trace (t_s Ast.null_pos t); assert false (* FIXME it seems that a cl_types will never be anything other than cl.cl_types. I'll take the risk and fail if not, just to see if that confirms *)
-        ) [] cl_types in
-        (params, String.concat " " params_extends)
-  in
-
-  let rec gen_class_field w ?(is_overload=false) is_static cl is_final cf =
-    let is_interface = cl.cl_interface in
-    let name, is_new, is_explicit_iface = match cf.cf_name with
-      | "new" -> snd cl.cl_path, true, false
-      | name when String.contains name '.' ->
-        let fn_name, path = parse_explicit_iface name in
-        (path_s path) ^ "." ^ fn_name, false, true
-      | name -> name, false, false
-    in
-    (match cf.cf_kind with
-      | Var _
-      | Method (MethDynamic) when not (Type.is_extern_field cf) ->
-        (if is_overload || List.exists (fun cf -> cf.cf_expr <> None) cf.cf_overloads then
-          gen.gcon.error "Only normal (non-dynamic) methods can be overloaded" cf.cf_pos);
-        if not is_interface then begin
-          let access, modifiers = get_fun_modifiers cf.cf_meta "public" [] in
-          print w "%s %s%s %s %s" access (if is_static then "static " else "") (String.concat " " modifiers) (t_s cf.cf_pos (run_follow gen cf.cf_type)) (change_field name);
-          (match cf.cf_expr with
-            | Some e ->
-                write w " = ";
-                expr_s w e;
-                write w ";"
-            | None -> write w ";"
-          )
-        end (* TODO see how (get,set) variable handle when they are interfaces *)
-      | Method _ when Type.is_extern_field cf || (match cl.cl_kind, cf.cf_expr with | KAbstractImpl _, None -> true | _ -> false) ->
-        List.iter (fun cf -> if cl.cl_interface || cf.cf_expr <> None then
-          gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf
-        ) cf.cf_overloads
-      | Var _ | Method MethDynamic -> ()
-      | Method mkind ->
-        List.iter (fun cf ->
-          if cl.cl_interface || cf.cf_expr <> None then
-            gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf
-        ) cf.cf_overloads;
-        let is_virtual = is_new || (not is_final && match mkind with | MethInline -> false | _ when not is_new -> true | _ -> false) in
-        let is_override = match cf.cf_name with
-          | "equals" when not is_static ->
-            (match cf.cf_type with
-              | TFun([_,_,t], ret) ->
-                (match (real_type t, real_type ret) with
-                  | TDynamic _, TEnum( { e_path = ([], "Bool") }, [])
-                  | TDynamic _, TAbstract ({ a_path = ([], "Bool") },[])
-                  | TAnon _, TEnum( { e_path = ([], "Bool") }, [])
-                  | TAnon _, TAbstract ({ a_path = ([], "Bool") },[]) -> true
-                  | _ -> List.memq cf cl.cl_overrides
-                )
-              | _ -> List.memq cf cl.cl_overrides)
-          | "toString" when not is_static ->
-            (match cf.cf_type with
-              | TFun([], ret) ->
-                (match real_type ret with
-                  | TInst( { cl_path = ([], "String") }, []) -> true
-                  | _ -> gen.gcon.error "A toString() function should return a String!" cf.cf_pos; false
-                )
-              | _ -> List.memq cf cl.cl_overrides
-            )
-          | "hashCode" when not is_static ->
-            (match cf.cf_type with
-              | TFun([], ret) ->
-                (match real_type ret with
-                  | TInst( { cl_path = ([], "Int") }, [])
-                  | TAbstract ({ a_path = ([], "Int") },[]) ->
-                    true
-                  | _ -> gen.gcon.error "A hashCode() function should return an Int!" cf.cf_pos; false
-                )
-              | _ -> List.memq cf cl.cl_overrides
-            )
-          | _ -> List.memq cf cl.cl_overrides
-        in
-        let visibility = if is_interface then "" else "public" in
-
-        let visibility, modifiers = get_fun_modifiers cf.cf_meta visibility [] in
-        let visibility, is_virtual = if is_explicit_iface then "",false else visibility, is_virtual in
-        let v_n = if is_static then "static " else if is_override && not is_interface then "" else if not is_virtual then "final " else "" in
-        let cf_type = if is_override && not is_overload && not (Meta.has Meta.Overload cf.cf_meta) then match field_access gen (TInst(cl, List.map snd cl.cl_types)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> assert false else cf.cf_type in
-
-        let params = List.map snd cl.cl_types in
-        let ret_type, args = match follow cf_type, follow cf.cf_type with
-          | TFun (strbtl, t), TFun(rargs, _) ->
-              (apply_params cl.cl_types params (real_type t), List.map2 (fun(_,_,t) (n,o,_) -> (n,o,apply_params cl.cl_types params (real_type t))) strbtl rargs)
-          | _ -> assert false
-        in
-
-        (if is_override && not is_interface then write w "@Override ");
-        (* public static void funcName *)
-        let params, _ = get_string_params cf.cf_params in
-        print w "%s %s%s %s %s %s" (visibility) v_n (String.concat " " modifiers) params (if is_new then "" else rett_s cf.cf_pos (run_follow gen ret_type)) (change_field name);
-
-        (* <T>(string arg1, object arg2) with T : object *)
-        (match cf.cf_expr with
-          | Some { eexpr = TFunction tf } ->
-              print w "(%s)" (String.concat ", " (List.map2 (fun (var,_) (_,_,t) -> sprintf "%s %s" (t_s cf.cf_pos (run_follow gen t)) (change_id var.v_name)) tf.tf_args args))
-          | _ ->
-              print w "(%s)" (String.concat ", " (List.map (fun (name, _, t) -> sprintf "%s %s" (t_s cf.cf_pos (run_follow gen t)) (change_id name)) args))
-        );
-        if is_interface || List.mem "native" modifiers then
-          write w ";"
-        else begin
-          let rec loop meta =
-            match meta with
-              | [] ->
-                let expr = match cf.cf_expr with
-                  | None -> mk (TBlock([])) t_dynamic Ast.null_pos
-                  | Some s ->
-                    match s.eexpr with
-                      | TFunction tf ->
-                        mk_block (tf.tf_expr)
-                      | _ -> assert false (* FIXME *)
-                in
-                (if is_new then begin
-                  (*let rec get_super_call el =
-                    match el with
-                      | ( { eexpr = TCall( { eexpr = TConst(TSuper) }, _) } as call) :: rest ->
-                        Some call, rest
-                      | ( { eexpr = TBlock(bl) } as block ) :: rest ->
-                        let ret, mapped = get_super_call bl in
-                        ret, ( { block with eexpr = TBlock(mapped) } :: rest )
-                      | _ ->
-                        None, el
-                  in*)
-                  expr_s w expr
-                end else begin
-                  expr_s w expr;
-                end)
-              | (Meta.Throws, [Ast.EConst (Ast.String t), _], _) :: tl ->
-                print w " throws %s" t;
-                loop tl
-              | (Meta.FunctionCode, [Ast.EConst (Ast.String contents),_],_) :: tl ->
-                begin_block w;
-                write w contents;
-                end_block w
-              | _ :: tl -> loop tl
-          in
-          loop cf.cf_meta
-
-        end);
-      newline w;
-      newline w
-  in
-
-  let gen_class w cl =
-    let should_close = match change_ns (fst cl.cl_path) with
-      | [] -> false
-      | ns ->
-        print w "package %s;" (String.concat "." (change_ns ns));
-        newline w;
-        false
-    in
-
-    let rec loop_meta meta acc =
-      match meta with
-        | (Meta.SuppressWarnings, [Ast.EConst (Ast.String w),_],_) :: meta -> loop_meta meta (w :: acc)
-        | _ :: meta -> loop_meta meta acc
-        | _ -> acc
-    in
-
-    let suppress_warnings = loop_meta cl.cl_meta [ "rawtypes"; "unchecked" ] in
-
-    write w "import haxe.root.*;";
-    newline w;
-    let w_header = w in
-    let w = new_source_writer () in
-    clear_scope();
-
-    (* add all haxe.root.* to imports *)
-    List.iter (function
-      | TClassDecl { cl_path = ([],c) } ->
-          imports := ([],c) :: !imports
-      | TEnumDecl { e_path = ([],c) } ->
-          imports := ([],c) :: !imports
-      | TAbstractDecl { a_path = ([],c) } ->
-          imports := ([],c) :: !imports
-      | _ -> ()
-    ) gen.gcon.types;
-
-    newline w;
-    write w "@SuppressWarnings(value={";
-    let first = ref true in
-    List.iter (fun s ->
-      (if !first then first := false else write w ", ");
-      print w "\"%s\"" (escape s)
-    ) suppress_warnings;
-    write w "})";
-    newline w;
-
-    let clt, access, modifiers = get_class_modifiers cl.cl_meta (if cl.cl_interface then "interface" else "class") "public" [] in
-    let is_final = Meta.has Meta.Final cl.cl_meta in
-
-    print w "%s %s %s %s" access (String.concat " " modifiers) clt (change_clname (snd cl.cl_path));
-    (* type parameters *)
-    let params, _ = get_string_params cl.cl_types in
-    let cl_p_to_string (c,p) =
-      let p = List.map (fun t -> match follow t with
-        | TMono _ | TDynamic _ -> t_empty
-        | _ -> t) p
-      in
-      path_param_s cl.cl_pos (TClassDecl c) c.cl_path p
-    in
-    print w "%s" params;
-    (if is_some cl.cl_super then print w " extends %s" (cl_p_to_string (get cl.cl_super)));
-    (match cl.cl_implements with
-      | [] -> ()
-      | _ -> print w " %s %s" (if cl.cl_interface then "extends" else "implements") (String.concat ", " (List.map cl_p_to_string cl.cl_implements))
-    );
-    (* class head ok: *)
-    (* public class Test<A> : X, Y, Z where A : Y *)
-    begin_block w;
-    (* our constructor is expected to be a normal "new" function *
-    if !strict_mode && is_some cl.cl_constructor then assert false;*)
-
-    let rec loop cl =
-      List.iter (fun cf -> add_scope cf.cf_name) cl.cl_ordered_fields;
-      List.iter (fun cf -> add_scope cf.cf_name) cl.cl_ordered_statics;
-      match cl.cl_super with
-        | Some(c,_) -> loop c
-        | None -> ()
-    in
-    loop cl;
-
-    let rec loop meta =
-      match meta with
-        | [] ->  ()
-        | (Meta.ClassCode, [Ast.EConst (Ast.String contents),_],_) :: tl ->
-          write w contents
-        | _ :: tl -> loop tl
-    in
-    loop cl.cl_meta;
-
-    (match gen.gcon.main_class with
-      | Some path when path = cl.cl_path ->
-        write w "public static void main(String[] args)";
-        begin_block w;
-        (try
-          let t = Hashtbl.find gen.gtypes ([], "Sys") in
-              match t with
-                | TClassDecl(cl) when PMap.mem "_args" cl.cl_statics ->
-                  write w "Sys._args = args;"; newline w
-                | _ -> ()
-        with | Not_found -> ()
-        );
-        write w "main();";
-        end_block w
-      | _ -> ()
-    );
-
-    (match cl.cl_init with
-      | None -> ()
-      | Some init ->
-        write w "static ";
-        expr_s w (mk_block init));
-    (if is_some cl.cl_constructor then gen_class_field w false cl is_final (get cl.cl_constructor));
-    (if not cl.cl_interface then
-      List.iter (gen_class_field w true cl is_final) cl.cl_ordered_statics);
-    List.iter (gen_class_field w false cl is_final) cl.cl_ordered_fields;
-    end_block w;
-    if should_close then end_block w;
-
-    (* add imports *)
-    List.iter (function
-      | ["haxe";"root"], _ | [], _ -> ()
-      | path ->
-          write w_header "import ";
-          write w_header (path_s path);
-          write w_header ";\n"
-    ) !imports;
-    add_writer w w_header
-  in
-
-
-  let gen_enum w e =
-    let should_close = match change_ns (fst e.e_path) with
-      | [] -> false
-      | ns ->
-        print w "package %s;" (String.concat "." (change_ns ns));
-        newline w;
-        false
-    in
-
-    print w "public enum %s" (change_clname (snd e.e_path));
-    begin_block w;
-    write w (String.concat ", " (List.map (change_id) e.e_names));
-    end_block w;
-
-    if should_close then end_block w
-  in
-
-  let module_type_gen w md_tp =
-    match md_tp with
-      | TClassDecl cl ->
-        if not cl.cl_extern then begin
-          gen_class w cl;
-          newline w;
-          newline w
-        end;
-        (not cl.cl_extern)
-      | TEnumDecl e ->
-        if not e.e_extern then begin
-          gen_enum w e;
-          newline w;
-          newline w
-        end;
-        (not e.e_extern)
-      | TTypeDecl e ->
-        false
-      | TAbstractDecl a ->
-        false
-  in
-
-  let module_gen w md =
-    module_type_gen w md
-  in
-
-  (* generate source code *)
-  init_ctx gen;
-
-  Hashtbl.add gen.gspecial_vars "__label__" true;
-  Hashtbl.add gen.gspecial_vars "__goto__" true;
-  Hashtbl.add gen.gspecial_vars "__is__" true;
-  Hashtbl.add gen.gspecial_vars "__typeof__" true;
-  Hashtbl.add gen.gspecial_vars "__java__" true;
-  Hashtbl.add gen.gspecial_vars "__lock__" true;
-
-  gen.greal_type <- real_type;
-  gen.greal_type_param <- change_param_type;
-
-  SetHXGen.run_filter gen SetHXGen.default_hxgen_func;
-
-  (* before running the filters, follow all possible types *)
-  (* this is needed so our module transformations don't break some core features *)
-  (* like multitype selection *)
-  let run_follow_gen = run_follow gen in
-  let rec type_map e = Type.map_expr_type (fun e->type_map e) (run_follow_gen)  (fun tvar-> tvar.v_type <- (run_follow_gen tvar.v_type); tvar) e in
-  let super_map (cl,tl) = (cl, List.map run_follow_gen tl) in
-  List.iter (function
-    | TClassDecl cl ->
-        let all_fields = (Option.map_default (fun cf -> [cf]) [] cl.cl_constructor) @ cl.cl_ordered_fields @ cl.cl_ordered_statics in
-        List.iter (fun cf ->
-          cf.cf_type <- run_follow_gen cf.cf_type;
-          cf.cf_expr <- Option.map type_map cf.cf_expr
-        ) all_fields;
-       cl.cl_dynamic <- Option.map run_follow_gen cl.cl_dynamic;
-       cl.cl_array_access <- Option.map run_follow_gen cl.cl_array_access;
-       cl.cl_init <- Option.map type_map cl.cl_init;
-       cl.cl_super <- Option.map super_map cl.cl_super;
-       cl.cl_implements <- List.map super_map cl.cl_implements
-    | _ -> ()
-    ) gen.gcon.types;
-
-  let closure_t = ClosuresToClass.DoubleAndDynamicClosureImpl.get_ctx gen 6 in
-
-  (*let closure_t = ClosuresToClass.create gen 10 float_cl
-    (fun l -> l)
-    (fun l -> l)
-    (fun args -> args)
-    (fun args -> [])
-  in
-  ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (fun e _ _ -> e));
-
-  StubClosureImpl.configure gen (StubClosureImpl.default_implementation gen float_cl 10 (fun e _ _ -> e));*)
-
-  FixOverrides.configure gen;
-  Normalize.configure gen ~metas:(Hashtbl.create 0);
-  AbstractImplementationFix.configure gen;
-
-  IteratorsInterface.configure gen (fun e -> e);
-
-  ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) ));
-
-  EnumToClass.configure gen (None) false true (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) false false;
-
-  InterfaceVarsDeleteModf.configure gen;
-
-  let dynamic_object = (get_cl (get_type gen (["haxe";"lang"],"DynamicObject")) ) in
-
-  let object_iface = get_cl (get_type gen (["haxe";"lang"],"IHxObject")) in
-
-  (*fixme: THIS IS A HACK. take this off *)
-  let empty_e = match (get_type gen (["haxe";"lang"], "EmptyObject")) with | TEnumDecl e -> e | _ -> assert false in
-  (*OverloadingCtor.set_new_create_empty gen ({eexpr=TEnumField(empty_e, "EMPTY"); etype=TEnum(empty_e,[]); epos=null_pos;});*)
-
-  let empty_expr = { eexpr = (TTypeExpr (TEnumDecl empty_e)); etype = (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics empty_e) }); epos = null_pos } in
-  let empty_ef =
-    try
-      PMap.find "EMPTY" empty_e.e_constrs
-    with Not_found -> gen.gcon.error "Required enum field EMPTY was not found" empty_e.e_pos; assert false
-  in
-  OverloadingConstructor.configure ~empty_ctor_type:(TEnum(empty_e, [])) ~empty_ctor_expr:({ eexpr=TField(empty_expr, FEnum(empty_e, empty_ef)); etype=TEnum(empty_e,[]); epos=null_pos; }) ~supports_ctor_inheritance:false gen;
-
-  let rcf_static_find = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "findHash" Ast.null_pos [] in
-  (*let rcf_static_lookup = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "lookupHash" Ast.null_pos [] in*)
-
-  let can_be_float t = like_float (real_type t) in
-
-  let rcf_on_getset_field main_expr field_expr field may_hash may_set is_unsafe =
-    let is_float = can_be_float (if is_none may_set then main_expr.etype else (get may_set).etype) in
-    let fn_name = if is_some may_set then "setField" else "getField" in
-    let fn_name = if is_float then fn_name ^ "_f" else fn_name in
-    let pos = field_expr.epos in
-
-    let is_unsafe = { eexpr = TConst(TBool is_unsafe); etype = basic.tbool; epos = pos } in
-
-    let should_cast = match main_expr.etype with | TInst({ cl_path = ([], "Float") }, []) -> false | _ -> true in
-    let infer = mk_static_field_access_infer runtime_cl fn_name field_expr.epos [] in
-    let first_args =
-      [ field_expr; { eexpr = TConst(TString field); etype = basic.tstring; epos = pos } ]
-      @ if is_some may_hash then [ { eexpr = TConst(TInt (get may_hash)); etype = basic.tint; epos = pos } ] else []
-    in
-    let args = first_args @ match is_float, may_set with
-      | true, Some(set) ->
-        [ if should_cast then mk_cast basic.tfloat set else set ]
-      | false, Some(set) ->
-        [ set ]
-      | _ ->
-        [ is_unsafe ]
-    in
-
-    let call = { main_expr with eexpr = TCall(infer,args) } in
-    let call = if is_float && should_cast then mk_cast main_expr.etype call else call in
-    call
-  in
-
-  let rcf_on_call_field ecall field_expr field may_hash args =
-    let infer = mk_static_field_access_infer runtime_cl "callField" field_expr.epos [] in
-
-    let hash_arg = match may_hash with
-      | None -> []
-      | Some h -> [ { eexpr = TConst(TInt h); etype = basic.tint; epos = field_expr.epos } ]
-    in
-
-    let arr_call = if args <> [] then
-      { eexpr = TArrayDecl args; etype = basic.tarray t_dynamic; epos = ecall.epos }
-    else
-      null (basic.tarray t_dynamic) ecall.epos
-    in
-
-
-    let call_args =
-      [field_expr; { field_expr with eexpr = TConst(TString field); etype = basic.tstring } ]
-        @ hash_arg
-        @ [ arr_call ]
-    in
-
-    mk_cast ecall.etype { ecall with eexpr = TCall(infer, call_args); etype = t_dynamic }
-  in
-
-  let rcf_ctx = ReflectionCFs.new_ctx gen closure_t object_iface false rcf_on_getset_field rcf_on_call_field (fun hash hash_array ->
-    { hash with eexpr = TCall(rcf_static_find, [hash; hash_array]); etype=basic.tint }
-  ) (fun hash -> hash ) false in
-
-  ReflectionCFs.UniversalBaseClass.default_config gen (get_cl (get_type gen (["haxe";"lang"],"HxObject")) ) object_iface dynamic_object;
-
-  ReflectionCFs.configure_dynamic_field_access rcf_ctx false;
-
-  (* let closure_func = ReflectionCFs.implement_closure_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"],"Closure")) ) in *)
-  let closure_cl = get_cl (get_type gen (["haxe";"lang"],"Closure")) in
-
-  let closure_func = ReflectionCFs.get_closure_func rcf_ctx closure_cl in
-
-  ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) );
-
-  let slow_invoke = mk_static_field_access_infer (runtime_cl) "slowCallField" Ast.null_pos [] in
-  ReflectionCFs.configure rcf_ctx ~slow_invoke:(fun ethis efield eargs -> {
-    eexpr = TCall(slow_invoke, [ethis; efield; eargs]);
-    etype = t_dynamic;
-    epos = ethis.epos;
-  } ) object_iface;
-
-  let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in
-
-  ObjectDeclMap.configure gen (ObjectDeclMap.traverse gen objdecl_fn);
-
-  InitFunction.configure gen true;
-  TArrayTransform.configure gen (TArrayTransform.default_implementation gen (
-  fun e _ ->
-    match e.eexpr with
-      | TArray ({ eexpr = TLocal { v_extra = Some( _ :: _, _) } }, _) -> (* captured transformation *)
-        false
-      | TArray(e1, e2) ->
-        ( match run_follow gen (follow e1.etype) with
-          | TInst({ cl_path = (["java"], "NativeArray") }, _) -> false
-          | _ -> true )
-      | _ -> assert false
-  ) "__get" "__set" );
-
-  let field_is_dynamic t field =
-    match field_access_esp gen (gen.greal_type t) field with
-      | FClassField (cl,p,_,_,_,t,_) ->
-        is_dynamic (apply_params cl.cl_types p t)
-      | FEnumField _ -> false
-      | _ -> true
-  in
-
-  let is_type_param e = match follow e with
-    | TInst( { cl_kind = KTypeParameter _ },[]) -> true
-    | _ -> false
-  in
-
-  let is_dynamic_expr e = is_dynamic e.etype || match e.eexpr with
-    | TField(tf, f) -> field_is_dynamic tf.etype f
-    | _ -> false
-  in
-
-  let may_nullable t = match gen.gfollow#run_f t with
-    | TType({ t_path = ([], "Null") }, [t]) ->
-      (match follow t with
-        | TInst({ cl_path = ([], "String") }, [])
-        | TInst({ cl_path = ([], "Float") }, [])
-        | TAbstract ({ a_path = ([], "Float") },[])
-        | TInst({ cl_path = (["haxe"], "Int32")}, [] )
-        | TInst({ cl_path = (["haxe"], "Int64")}, [] )
-        | TInst({ cl_path = ([], "Int") }, [])
-        | TAbstract ({ a_path = ([], "Int") },[])
-        | TEnum({ e_path = ([], "Bool") }, [])
-        | TAbstract ({ a_path = ([], "Bool") },[]) -> Some t
-        | _ -> None )
-    | _ -> None
-  in
-
-  let is_double t = like_float t && not (like_int t) in
-  let is_int t = like_int t in
-
-  DynamicOperators.configure gen
-    (DynamicOperators.abstract_implementation gen (fun e -> match e.eexpr with
-      | TBinop (Ast.OpEq, e1, e2)
-      | TBinop (Ast.OpAdd, e1, e2)
-      | TBinop (Ast.OpNotEq, e1, e2) -> is_dynamic e1.etype || is_dynamic e2.etype || is_type_param e1.etype || is_type_param e2.etype
-      | TBinop (Ast.OpLt, e1, e2)
-      | TBinop (Ast.OpLte, e1, e2)
-      | TBinop (Ast.OpGte, e1, e2)
-      | TBinop (Ast.OpGt, e1, e2) -> is_dynamic e.etype || is_dynamic_expr e1 || is_dynamic_expr e2 || is_string e1.etype || is_string e2.etype
-      | TBinop (_, e1, e2) -> is_dynamic e.etype || is_dynamic_expr e1 || is_dynamic_expr e2
-      | TUnop (_, _, e1) -> is_dynamic_expr e1
-      | _ -> false)
-    (fun e1 e2 ->
-      let is_null e = match e.eexpr with | TConst(TNull) | TLocal({ v_name = "__undefined__" }) -> true | _ -> false in
-
-      if is_null e1 || is_null e2 then
-        match e1.eexpr, e2.eexpr with
-          | TConst c1, TConst c2 ->
-            { e1 with eexpr = TConst(TBool (c1 = c2)); etype = basic.tbool }
-          | _ ->
-            { e1 with eexpr = TBinop(Ast.OpEq, e1, e2); etype = basic.tbool }
-      else begin
-        let is_ref = match follow e1.etype, follow e2.etype with
-          | TDynamic _, _
-          | _, TDynamic _
-          | TInst({ cl_path = ([], "Float") },[]), _
-          | TAbstract ({ a_path = ([], "Float") },[]) , _
-          | TInst( { cl_path = (["haxe"], "Int32") }, [] ), _
-          | TInst( { cl_path = (["haxe"], "Int64") }, [] ), _
-          | TInst({ cl_path = ([], "Int") },[]), _
-          | TAbstract ({ a_path = ([], "Int") },[]) , _
-          | TEnum({ e_path = ([], "Bool") },[]), _
-          | TAbstract ({ a_path = ([], "Bool") },[]) , _
-          | _, TInst({ cl_path = ([], "Float") },[])
-          | _, TAbstract ({ a_path = ([], "Float") },[])
-          | _, TInst({ cl_path = ([], "Int") },[])
-          | _, TAbstract ({ a_path = ([], "Int") },[])
-          | _, TInst( { cl_path = (["haxe"], "Int32") }, [] )
-          | _, TInst( { cl_path = (["haxe"], "Int64") }, [] )
-          | _, TEnum({ e_path = ([], "Bool") },[])
-          | _, TAbstract ({ a_path = ([], "Bool") },[])
-          | TInst( { cl_kind = KTypeParameter _ }, [] ), _
-          | _, TInst( { cl_kind = KTypeParameter _ }, [] ) -> false
-          | _, _ -> true
-        in
-
-        let static = mk_static_field_access_infer (runtime_cl) (if is_ref then "refEq" else "eq") e1.epos [] in
-        { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tbool; epos=e1.epos }
-      end
-    )
-    (fun e e1 e2 ->
-      match may_nullable e1.etype, may_nullable e2.etype with
-        | Some t1, Some t2 ->
-          let t1, t2 = if is_string t1 || is_string t2 then
-            basic.tstring, basic.tstring
-          else if is_double t1 || is_double t2 then
-            basic.tfloat, basic.tfloat
-          else if is_int t1 || is_int t2 then
-            basic.tint, basic.tint
-          else t1, t2 in
-          { eexpr = TBinop(Ast.OpAdd, mk_cast t1 e1, mk_cast t2 e2); etype = e.etype; epos = e1.epos }
-        | _ ->
-          let static = mk_static_field_access_infer (runtime_cl) "plus"  e1.epos [] in
-          mk_cast e.etype { eexpr = TCall(static, [e1; e2]); etype = t_dynamic; epos=e1.epos })
-    (fun e1 e2 ->
-      if is_string e1.etype then begin
-        { e1 with eexpr = TCall(mk_field_access gen e1 "compareTo" e1.epos, [ e2 ]); etype = gen.gcon.basic.tint }
-      end else begin
-        let static = mk_static_field_access_infer (runtime_cl) "compare" e1.epos [] in
-        { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos }
-      end));
-
-  FilterClosures.configure gen (FilterClosures.traverse gen (fun e1 s -> true) closure_func);
-
-  let base_exception = get_cl (get_type gen (["java"; "lang"], "Throwable")) in
-  let base_exception_t = TInst(base_exception, []) in
-
-  let hx_exception = get_cl (get_type gen (["haxe";"lang"], "HaxeException")) in
-  let hx_exception_t = TInst(hx_exception, []) in
-
-  let rec is_exception t =
-    match follow t with
-      | TInst(cl,_) ->
-        if cl == base_exception then
-          true
-        else
-          (match cl.cl_super with | None -> false | Some (cl,arg) -> is_exception (TInst(cl,arg)))
-      | _ -> false
-  in
-
-  TryCatchWrapper.configure gen
-  (
-    TryCatchWrapper.traverse gen
-      (fun t -> not (is_exception (real_type t)))
-      (fun throwexpr expr ->
-        let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], base_exception_t)) expr.epos in
-        { throwexpr with eexpr = TThrow { expr with eexpr = TCall(wrap_static, [expr]); etype = hx_exception_t }; etype = gen.gcon.basic.tvoid }
-      )
-      (fun v_to_unwrap pos ->
-        let local = mk_cast hx_exception_t { eexpr = TLocal(v_to_unwrap); etype = v_to_unwrap.v_type; epos = pos } in
-        mk_field_access gen local "obj" pos
-      )
-      (fun rethrow ->
-        let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], base_exception_t)) rethrow.epos in
-        { rethrow with eexpr = TThrow { rethrow with eexpr = TCall(wrap_static, [rethrow]) }; }
-      )
-      (base_exception_t)
-      (hx_exception_t)
-      (fun v e -> e)
-  );
-
-  let get_typeof e =
-    { e with eexpr = TCall( { eexpr = TLocal( alloc_var "__typeof__" t_dynamic ); etype = t_dynamic; epos = e.epos }, [e] ) }
-  in
-
-  ClassInstance.configure gen (ClassInstance.traverse gen (fun e mt -> get_typeof e));
-
-  (*let v = alloc_var "$type_param" t_dynamic in*)
-  TypeParams.configure gen (fun ecall efield params elist ->
-    { ecall with eexpr = TCall(efield, elist) }
-  );
-
-  CastDetect.configure gen (CastDetect.default_implementation gen ~native_string_cast:false (Some (TEnum(empty_e, []))) false);
-
-  (*FollowAll.configure gen;*)
-
-  SwitchToIf.configure gen (SwitchToIf.traverse gen (fun e ->
-    match e.eexpr with
-      | TSwitch(cond, cases, def) ->
-        (match gen.gfollow#run_f cond.etype with
-          | TInst( { cl_path = (["haxe"], "Int32") }, [] )
-          | TInst({ cl_path = ([], "Int") },[])
-          | TAbstract ({ a_path = ([], "Int") },[])
-          | TInst({ cl_path = ([], "String") },[]) ->
-            (List.exists (fun (c,_) ->
-              List.exists (fun expr -> match expr.eexpr with | TConst _ -> false | _ -> true ) c
-            ) cases)
-          | _ -> true
-        )
-      | _ -> assert false
-  ) true );
-
-  let native_arr_cl = get_cl ( get_type gen (["java"], "NativeArray") ) in
-
-  ExpressionUnwrap.configure gen (ExpressionUnwrap.traverse gen (fun e -> Some { eexpr = TVar(mk_temp gen "expr" e.etype, Some e); etype = gen.gcon.basic.tvoid; epos = e.epos }));
-
-  UnnecessaryCastsRemoval.configure gen;
-
-  IntDivisionSynf.configure gen (IntDivisionSynf.default_implementation gen true);
-
-  UnreachableCodeEliminationSynf.configure gen (UnreachableCodeEliminationSynf.traverse gen false true true true);
-
-  ArrayDeclSynf.configure gen (ArrayDeclSynf.default_implementation gen native_arr_cl);
-
-  let goto_special = alloc_var "__goto__" t_dynamic in
-  let label_special = alloc_var "__label__" t_dynamic in
-  SwitchBreakSynf.configure gen (SwitchBreakSynf.traverse gen
-    (fun e_loop n api ->
-      { e_loop with eexpr = TBlock( { eexpr = TCall( mk_local label_special e_loop.epos, [ mk_int gen n e_loop.epos ] ); etype = t_dynamic; epos = e_loop.epos } :: [e_loop] ) };
-    )
-    (fun e_break n api ->
-      { eexpr = TCall( mk_local goto_special e_break.epos, [ mk_int gen n e_break.epos ] ); etype = t_dynamic; epos = e_break.epos }
-    )
-  );
-
-  DefaultArguments.configure gen (DefaultArguments.traverse gen);
-
-  JavaSpecificSynf.configure gen (JavaSpecificSynf.traverse gen runtime_cl);
-  JavaSpecificESynf.configure gen (JavaSpecificESynf.traverse gen runtime_cl);
-
-  (* add native String as a String superclass *)
-  let str_cl = match gen.gcon.basic.tstring with | TInst(cl,_) -> cl | _ -> assert false in
-  str_cl.cl_super <- Some (get_cl (get_type gen (["haxe";"lang"], "NativeString")), []);
-
-  let mkdir dir = if not (Sys.file_exists dir) then Unix.mkdir dir 0o755 in
-  mkdir gen.gcon.file;
-  mkdir (gen.gcon.file ^ "/src");
-
-  (* add resources array *)
-  (try
-    let res = get_cl (Hashtbl.find gen.gtypes (["haxe"], "Resource")) in
-    let cf = PMap.find "content" res.cl_statics in
-    let res = ref [] in
-    Hashtbl.iter (fun name v ->
-      res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = Ast.null_pos } :: !res;
-
-      let full_path = gen.gcon.file ^ "/src/" ^ name in
-      let parts = Str.split_delim (Str.regexp "[\\/]+") full_path in
-      let dir_list = List.rev (List.tl (List.rev parts)) in
-
-      Common.mkdir_recursive "" dir_list;
-
-      let f = open_out full_path in
-      output_string f v;
-      close_out f
-    ) gen.gcon.resources;
-    cf.cf_expr <- Some ({ eexpr = TArrayDecl(!res); etype = gen.gcon.basic.tarray gen.gcon.basic.tstring; epos = Ast.null_pos })
-  with | Not_found -> ());
-
-  run_filters gen;
-
-  TypeParams.RenameTypeParameters.run gen;
+	let native_arr_cl = get_cl ( get_type gen (["java"], "NativeArray") ) in
+	gen.gclasses.nativearray <- (fun t -> TInst(native_arr_cl,[t]));
+	gen.gclasses.nativearray_type <- (function TInst(_,[t]) -> t | _ -> assert false);
+	gen.gclasses.nativearray_len <- (fun e p -> mk_field_access gen e "length" p);
+
+	let basic = gen.gcon.basic in
+
+	let fn_cl = get_cl (get_type gen (["haxe";"lang"],"Function")) in
+
+	let runtime_cl = get_cl (get_type gen (["haxe";"lang"],"Runtime")) in
+	let nulltdef = get_tdef (get_type gen ([],"Null")) in
+
+	(*let string_ref = get_cl ( get_type gen (["haxe";"lang"], "StringRefl")) in*)
+
+	let ti64 = match ( get_type gen (["java"], "Int64") ) with | TAbstractDecl a -> TAbstract(a,[]) | _ -> assert false in
+
+	let has_tdynamic params =
+		List.exists (fun e -> match run_follow gen e with | TDynamic _ -> true | _ -> false) params
+	in
+
+	(*
+		The type parameters always need to be changed to their boxed counterparts
+	*)
+	let change_param_type md params =
+		match md with
+			| TClassDecl( { cl_path = (["java"], "NativeArray") } ) -> params
+			| TAbstractDecl { a_path=[],("Class" | "Enum") } | TClassDecl { cl_path = (["java";"lang"],("Class"|"Enum")) } ->
+				List.map (fun _ -> t_dynamic) params
+			| _ ->
+				match params with
+					| [] -> []
+					| _ ->
+						if has_tdynamic params then List.map (fun _ -> t_dynamic) params else
+							List.map (fun t ->
+								let f_t = gen.gfollow#run_f t in
+								match f_t  with
+									| TAbstract ({ a_path = ([], "Bool") },[])
+									| TAbstract ({ a_path = ([],"Float") },[])
+									| TInst ({ cl_path = ["haxe"],"Int32" },[])
+									| TInst ({ cl_path = ["haxe"],"Int64" },[])
+									| TAbstract ({ a_path = ([],"Int") },[])
+									| TType ({ t_path = ["java"], "Int64" },[])
+									| TAbstract ({ a_path = ["java"], "Int64" },[])
+									| TType ({ t_path = ["java"],"Int8" },[])
+									| TAbstract ({ a_path = ["java"],"Int8" },[])
+									| TType ({ t_path = ["java"],"Int16" },[])
+									| TAbstract ({ a_path = ["java"],"Int16" },[])
+									| TType ({ t_path = ["java"],"Char16" },[])
+									| TAbstract ({ a_path = ["java"],"Char16" },[])
+									| TType ({ t_path = [],"Single" },[])
+									| TAbstract ({ a_path = [],"Single" },[]) ->
+										TType(nulltdef, [f_t])
+									(*| TType ({ t_path = [], "Null"*)
+									| TInst (cl, ((_ :: _) as p)) when cl.cl_path <> (["java"],"NativeArray") ->
+										(* TInst(cl, List.map (fun _ -> t_dynamic) p) *)
+										TInst(cl,p)
+									| TEnum (e, ((_ :: _) as p)) ->
+										TEnum(e, List.map (fun _ -> t_dynamic) p)
+									| _ -> t
+							) params
+	in
+
+	let change_clname name =
+		String.map (function | '$' -> '.' | c -> c) name
+	in
+	let change_id name = try Hashtbl.find reserved name with | Not_found -> name in
+	let rec change_ns ns = match ns with
+		| [] -> ["haxe"; "root"]
+		| _ -> List.map change_id ns
+	in
+	let change_field = change_id in
+
+	let write_id w name = write w (change_id name) in
+
+	let write_field w name = write w (change_field name) in
+
+	gen.gfollow#add ~name:"follow_basic" (fun t -> match t with
+			| TAbstract ({ a_path = ([], "Bool") },[])
+			| TAbstract ({ a_path = ([], "Void") },[])
+			| TAbstract ({ a_path = ([],"Float") },[])
+			| TAbstract ({ a_path = ([],"Int") },[])
+			| TInst( { cl_path = (["haxe"], "Int32") }, [] )
+			| TInst( { cl_path = (["haxe"], "Int64") }, [] )
+			| TType ({ t_path = ["java"], "Int64" },[])
+			| TAbstract ({ a_path = ["java"], "Int64" },[])
+			| TType ({ t_path = ["java"],"Int8" },[])
+			| TAbstract ({ a_path = ["java"],"Int8" },[])
+			| TType ({ t_path = ["java"],"Int16" },[])
+			| TAbstract ({ a_path = ["java"],"Int16" },[])
+			| TType ({ t_path = ["java"],"Char16" },[])
+			| TAbstract ({ a_path = ["java"],"Char16" },[])
+			| TType ({ t_path = [],"Single" },[])
+			| TAbstract ({ a_path = [],"Single" },[]) ->
+					Some t
+			| TType (({ t_path = [],"Null" } as tdef),[t2]) ->
+					Some (TType(tdef,[gen.gfollow#run_f t2]))
+			| TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) ->
+					Some (gen.gfollow#run_f ( Abstract.get_underlying_type a pl) )
+			| TAbstract( { a_path = ([], "EnumValue") }, _ )
+			| TInst( { cl_path = ([], "EnumValue") }, _  ) -> Some t_dynamic
+			| _ -> None);
+
+	let change_path path = (change_ns (fst path), change_clname (snd path)) in
+
+	let path_s path meta = try
+		match Meta.get Meta.JavaCanonical meta with
+			| (Meta.JavaCanonical, [EConst(String pack), _; EConst(String name), _], _) ->
+				if pack = "" then
+					name
+				else
+					pack ^ "." ^ name
+			| _ -> raise Not_found
+		with Not_found -> match path with
+			| (ns,clname) -> path_s (change_ns ns, change_clname clname)
+	in
+
+	let cl_cl = get_cl (get_type gen (["java";"lang"],"Class")) in
+
+	let rec real_type t =
+		let t = gen.gfollow#run_f t in
+		match t with
+			| TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) ->
+				real_type (Abstract.get_underlying_type a pl)
+			| TInst( { cl_path = (["haxe"], "Int32") }, [] ) -> gen.gcon.basic.tint
+			| TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> ti64
+			| TAbstract( { a_path = ([], "Class") }, p	)
+			| TAbstract( { a_path = ([], "Enum") }, p  )
+			| TInst( { cl_path = ([], "Class") }, p  )
+			| TInst( { cl_path = ([], "Enum") }, p	) -> TInst(cl_cl,[t_dynamic])
+			| TEnum(e,params) -> TEnum(e, List.map (fun _ -> t_dynamic) params)
+			| TInst(c,params) when Meta.has Meta.Enum c.cl_meta ->
+				TInst(c, List.map (fun _ -> t_dynamic) params)
+			| TInst _ -> t
+			| TType({ t_path = ([], "Null") }, [t]) when is_java_basic_type (gen.gfollow#run_f t) -> t_dynamic
+			| TType({ t_path = ([], "Null") }, [t]) ->
+				(match follow t with
+					| TInst( { cl_kind = KTypeParameter _ }, []) ->
+							t_dynamic
+							(* real_type t *)
+					| _ -> real_type t
+				)
+			| TType _ | TAbstract _ -> t
+			| TAnon (anon) -> (match !(anon.a_status) with
+				| Statics _ | EnumStatics _ | AbstractStatics _ -> t
+				| _ -> t_dynamic)
+			| TFun _ -> TInst(fn_cl,[])
+			| _ -> t_dynamic
+	in
+
+	let scope = ref PMap.empty in
+	let imports = ref [] in
+
+	let clear_scope () =
+		scope := PMap.empty;
+		imports := [];
+	in
+
+	let add_scope name =
+		scope := PMap.add name () !scope
+	in
+
+	let add_import pos path meta =
+		let name = snd path in
+		let rec loop = function
+			| (pack, n) :: _ when name = n ->
+					if path <> (pack,n) then
+						gen.gcon.error ("This expression cannot be generated because " ^ path_s path meta ^ " is shadowed by the current scope and ") pos
+			| _ :: tl ->
+					loop tl
+			| [] ->
+					(* add import *)
+					imports := path :: !imports
+		in
+		loop !imports
+	in
+
+	let path_s_import pos path meta = match path with
+		| [], name when PMap.mem name !scope ->
+				gen.gcon.error ("This expression cannot be generated because " ^ name ^ " is shadowed by the current scope") pos;
+				name
+		| pack1 :: _, name when PMap.mem pack1 !scope -> (* exists in scope *)
+				add_import pos path meta;
+				(* check if name exists in scope *)
+				if PMap.mem name !scope then
+					gen.gcon.error ("This expression cannot be generated because " ^ pack1 ^ " and " ^ name ^ " are both shadowed by the current scope") pos;
+				name
+		| _ -> path_s path meta
+	in
+
+	let is_dynamic t = match real_type t with
+		| TMono _ | TDynamic _
+		| TInst({ cl_kind = KTypeParameter _ }, _) -> true
+		| TAnon anon ->
+			(match !(anon.a_status) with
+				| EnumStatics _ | Statics _ | AbstractStatics _ -> false
+				| _ -> true
+			)
+		| _ -> false
+	in
+
+	let rec t_s pos t =
+		match real_type t with
+			(* basic types *)
+			| TAbstract ({ a_path = ([], "Bool") },[]) -> "boolean"
+			| TAbstract ({ a_path = ([], "Void") },[]) ->
+					path_s_import pos (["java";"lang"], "Object") []
+			| TAbstract ({ a_path = ([],"Float") },[]) -> "double"
+			| TAbstract ({ a_path = ([],"Int") },[]) -> "int"
+			| TType ({ t_path = ["java"], "Int64" },[])
+			| TAbstract ({ a_path = ["java"], "Int64" },[]) -> "long"
+			| TType ({ t_path = ["java"],"Int8" },[])
+			| TAbstract ({ a_path = ["java"],"Int8" },[]) -> "byte"
+			| TType ({ t_path = ["java"],"Int16" },[])
+			| TAbstract ({ a_path = ["java"],"Int16" },[]) -> "short"
+			| TType ({ t_path = ["java"],"Char16" },[])
+			| TAbstract ({ a_path = ["java"],"Char16" },[]) -> "char"
+			| TType ({ t_path = [],"Single" },[])
+			| TAbstract ({ a_path = [],"Single" },[]) -> "float"
+			| TInst ({ cl_path = ["haxe"],"Int32" },[])
+			| TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> "int"
+			| TInst ({ cl_path = ["haxe"],"Int64" },[])
+			| TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> "long"
+			| TInst({ cl_path = (["java"], "NativeArray") }, [param]) ->
+				let rec check_t_s t =
+					match real_type t with
+						| TInst({ cl_path = (["java"], "NativeArray") }, [param]) ->
+							(check_t_s param) ^ "[]"
+						| _ -> t_s pos (run_follow gen t)
+				in
+				(check_t_s param) ^ "[]"
+
+			(* end of basic types *)
+			| TInst ({ cl_kind = KTypeParameter _; cl_path=p }, []) -> snd p
+			| TAbstract ({ a_path = [], "Dynamic" },[]) ->
+					path_s_import pos (["java";"lang"], "Object") []
+			| TMono r -> (match !r with | None -> "java.lang.Object" | Some t -> t_s pos (run_follow gen t))
+			| TInst ({ cl_path = [], "String" }, []) ->
+					path_s_import pos (["java";"lang"], "String") []
+			| TAbstract ({ a_path = [], "Class" }, [p]) | TAbstract ({ a_path = [], "Enum" }, [p])
+			| TInst ({ cl_path = [], "Class" }, [p]) | TInst ({ cl_path = [], "Enum" }, [p]) ->
+					path_param_s pos (TClassDecl cl_cl) (["java";"lang"], "Class") [p] []
+			| TAbstract ({ a_path = [], "Class" }, _) | TAbstract ({ a_path = [], "Enum" }, _)
+			| TInst ({ cl_path = [], "Class" }, _) | TInst ({ cl_path = [], "Enum" }, _) ->
+					path_s_import pos (["java";"lang"], "Class") []
+			| TEnum ({e_path = p; e_meta = meta}, _) ->
+					path_s_import pos p meta
+			| TInst (({cl_path = p; cl_meta = meta} as cl), _) when Meta.has Meta.Enum cl.cl_meta ->
+					path_s_import pos p meta
+			| TInst (({cl_path = p; cl_meta = meta} as cl), params) -> (path_param_s pos (TClassDecl cl) p params meta)
+			| TType (({t_path = p; t_meta = meta} as t), params) -> (path_param_s pos (TTypeDecl t) p params meta)
+			| TAnon (anon) ->
+				(match !(anon.a_status) with
+					| Statics _ | EnumStatics _ | AbstractStatics _ ->
+							path_s_import pos (["java";"lang"], "Class") []
+					| _ ->
+							path_s_import pos (["java";"lang"], "Object") [])
+				| TDynamic _ ->
+						path_s_import pos (["java";"lang"], "Object") []
+			(* No Lazy type nor Function type made. That's because function types will be at this point be converted into other types *)
+			| _ -> if !strict_mode then begin trace ("[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"); assert false end else "[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"
+
+	and param_t_s pos t =
+		match run_follow gen t with
+			| TAbstract ({ a_path = ([], "Bool") },[]) ->
+					path_s_import pos (["java";"lang"], "Boolean") []
+			| TAbstract ({ a_path = ([],"Float") },[]) ->
+					path_s_import pos (["java";"lang"], "Double") []
+			| TAbstract ({ a_path = ([],"Int") },[]) ->
+					path_s_import pos (["java";"lang"], "Integer") []
+			| TType ({ t_path = ["java"], "Int64" },[])
+			| TAbstract ({ a_path = ["java"], "Int64" },[]) ->
+					path_s_import pos (["java";"lang"], "Long") []
+			| TInst ({ cl_path = ["haxe"],"Int64" },[])
+			| TAbstract ({ a_path = ["haxe"],"Int64" },[]) ->
+					path_s_import pos (["java";"lang"], "Long") []
+			| TInst ({ cl_path = ["haxe"],"Int32" },[])
+			| TAbstract ({ a_path = ["haxe"],"Int32" },[]) ->
+					path_s_import pos (["java";"lang"], "Integer") []
+			| TType ({ t_path = ["java"],"Int8" },[])
+			| TAbstract ({ a_path = ["java"],"Int8" },[]) ->
+					path_s_import pos (["java";"lang"], "Byte") []
+			| TType ({ t_path = ["java"],"Int16" },[])
+			| TAbstract ({ a_path = ["java"],"Int16" },[]) ->
+					path_s_import pos (["java";"lang"], "Short") []
+			| TType ({ t_path = ["java"],"Char16" },[])
+			| TAbstract ({ a_path = ["java"],"Char16" },[]) ->
+					path_s_import pos (["java";"lang"], "Character") []
+			| TType ({ t_path = [],"Single" },[])
+			| TAbstract ({ a_path = [],"Single" },[]) ->
+					path_s_import pos (["java";"lang"], "Float") []
+			| TDynamic _ -> "?"
+			| TInst (cl, params) -> t_s pos (TInst(cl, change_param_type (TClassDecl cl) params))
+			| TType (cl, params) -> t_s pos (TType(cl, change_param_type (TTypeDecl cl) params))
+			| TEnum (e, params) -> t_s pos (TEnum(e, change_param_type (TEnumDecl e) params))
+			| _ -> t_s pos t
+
+	and path_param_s pos md path params meta =
+			match params with
+				| [] -> path_s_import pos path meta
+				| _ when has_tdynamic (change_param_type md params) -> path_s_import pos path meta
+				| _ -> sprintf "%s<%s>" (path_s_import pos path meta) (String.concat ", " (List.map (fun t -> param_t_s pos t) (change_param_type md params)))
+	in
+
+	let rett_s pos t =
+		match t with
+			| TAbstract ({ a_path = ([], "Void") },[]) -> "void"
+			| _ -> t_s pos t
+	in
+
+	let high_surrogate c = (c lsr 10) + 0xD7C0 in
+	let low_surrogate c = (c land 0x3FF) lor 0xDC00 in
+
+	let escape ichar b =
+		match ichar with
+			| 92 (* \ *) -> Buffer.add_string b "\\\\"
+			| 39 (* ' *) -> Buffer.add_string b "\\\'"
+			| 34 -> Buffer.add_string b "\\\""
+			| 13 (* \r *) -> Buffer.add_string b "\\r"
+			| 10 (* \n *) -> Buffer.add_string b "\\n"
+			| 9 (* \t *) -> Buffer.add_string b "\\t"
+			| c when c < 32 || (c >= 127 && c <= 0xFFFF) -> Buffer.add_string b (Printf.sprintf "\\u%.4x" c)
+			| c when c > 0xFFFF -> Buffer.add_string b (Printf.sprintf "\\u%.4x\\u%.4x" (high_surrogate c) (low_surrogate c))
+			| c -> Buffer.add_char b (Char.chr c)
+	in
+
+	let escape s =
+		let b = Buffer.create 0 in
+		(try
+			UTF8.validate s;
+			UTF8.iter (fun c -> escape (UChar.code c) b) s
+		with
+			UTF8.Malformed_code ->
+				String.iter (fun c -> escape (Char.code c) b) s
+		);
+		Buffer.contents b
+	in
+
+	let has_semicolon e =
+		match e.eexpr with
+			| TLocal { v_name = "__fallback__" }
+			| TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt _) } ] ) -> false
+			| TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, _ ) -> false
+			| TBlock _ | TFor _ | TSwitch _ | TTry _ | TIf _ -> false
+			| TWhile (_,_,flag) when flag = Ast.NormalWhile -> false
+			| _ -> true
+	in
+
+	let in_value = ref false in
+
+	let rec md_s pos md =
+		let md = follow_module (gen.gfollow#run_f) md in
+		match md with
+			| TClassDecl (cl) ->
+				t_s pos (TInst(cl,[]))
+			| TEnumDecl (e) ->
+				t_s pos (TEnum(e,[]))
+			| TTypeDecl t ->
+				t_s pos (TType(t, []))
+			| TAbstractDecl a ->
+				t_s pos (TAbstract(a, []))
+	in
+
+	(*
+		it seems that Java doesn't like when you create a new array with the type parameter defined
+		so we'll just ignore all type parameters, and hope for the best!
+	*)
+	let rec transform_nativearray_t t = match real_type t with
+		| TInst( ({ cl_path = (["java"], "NativeArray") } as narr), [t]) ->
+			TInst(narr, [transform_nativearray_t t])
+		| TInst(cl, params) -> TInst(cl, List.map (fun _ -> t_dynamic) params)
+		| TEnum(e, params) -> TEnum(e, List.map (fun _ -> t_dynamic) params)
+		| TType(t, params) -> TType(t, List.map (fun _ -> t_dynamic) params)
+		| _ -> t
+	in
+
+	let rec extract_tparams params el =
+		match el with
+			| ({ eexpr = TLocal({ v_name = "$type_param" }) } as tp) :: tl ->
+				extract_tparams (tp.etype :: params) tl
+			| _ -> (params, el)
+	in
+
+	let line_directive =
+		if Common.defined gen.gcon Define.RealPosition then
+			fun w p -> ()
+		else fun w p ->
+			let cur_line = Lexer.get_error_line p in
+			let file = Common.get_full_path p.pfile in
+			print w "//line %d \"%s\"" cur_line (Ast.s_escape file); newline w
+	in
+
+	let extract_statements expr =
+		let ret = ref [] in
+		let rec loop expr = match expr.eexpr with
+			| TCall ({ eexpr = TLocal {
+					v_name = "__is__" | "__typeof__" | "__array__"
+				} }, el) ->
+				List.iter loop el
+			| TNew ({ cl_path = (["java"], "NativeArray") }, params, [ size ]) ->
+				()
+			| TUnop (Ast.Increment, _, _)
+			| TUnop (Ast.Decrement, _, _)
+			| TBinop (Ast.OpAssign, _, _)
+			| TBinop (Ast.OpAssignOp _, _, _)
+			| TLocal { v_name = "__fallback__" }
+			| TLocal { v_name = "__sbreak__" } ->
+				ret := expr :: !ret
+			| TConst _
+			| TLocal _
+			| TArray _
+			| TBinop _
+			| TField _
+			| TEnumParameter _
+			| TTypeExpr _
+			| TObjectDecl _
+			| TArrayDecl _
+			| TCast _
+			| TMeta _
+			| TParenthesis _
+			| TUnop _ ->
+				Type.iter loop expr
+			| TFunction _ -> () (* do not extract parameters from inside of it *)
+			| _ ->
+				ret := expr :: !ret
+		in
+		loop expr;
+		(* [expr] *)
+		List.rev !ret
+	in
+
+	let expr_s w e =
+		in_value := false;
+		let rec expr_s w e =
+			let was_in_value = !in_value in
+			in_value := true;
+			match e.eexpr with
+				| TConst c ->
+					(match c with
+						| TInt i32 ->
+							print w "%ld" i32;
+							(match real_type e.etype with
+								| TType( { t_path = (["java"], "Int64") }, [] ) -> write w "L";
+								| _ -> ()
+							)
+						| TFloat s ->
+							write w s;
+							(* fix for Int notation, which only fit in a Float *)
+							(if not (String.contains s '.' || String.contains s 'e' || String.contains s 'E') then write w ".0");
+							(match real_type e.etype with
+								| TType( { t_path = ([], "Single") }, [] ) -> write w "f"
+								| _ -> ()
+							)
+						| TString s -> print w "\"%s\"" (escape s)
+						| TBool b -> write w (if b then "true" else "false")
+						| TNull ->
+							(match real_type e.etype with
+								| TAbstract( { a_path = (["java"], "Int64") }, [] )
+								| TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> write w "0L"
+								| TInst( { cl_path = (["haxe"], "Int32") }, [] )
+								| TAbstract ({ a_path = ([], "Int") },[]) -> expr_s w ({ e with eexpr = TConst(TInt Int32.zero) })
+								| TAbstract ({ a_path = ([], "Float") },[]) -> expr_s w ({ e with eexpr = TConst(TFloat "0.0") })
+								| TAbstract ({ a_path = ([], "Bool") },[]) -> write w "false"
+								| TAbstract _ when like_int e.etype ->
+									expr_s w (mk_cast e.etype { e with eexpr = TConst(TInt Int32.zero) })
+								| TAbstract _ when like_float e.etype ->
+									expr_s w (mk_cast e.etype { e with eexpr = TConst(TFloat "0.0") } )
+								| t -> write w ("null") )
+						| TThis -> write w "this"
+						| TSuper -> write w "super")
+				| TLocal { v_name = "__fallback__" } -> ()
+				| TLocal { v_name = "__sbreak__" } -> write w "break"
+				| TLocal { v_name = "__undefined__" } ->
+					write w (t_s e.epos (TInst(runtime_cl, List.map (fun _ -> t_dynamic) runtime_cl.cl_params)));
+					write w ".undefined";
+				| TLocal var ->
+					write_id w var.v_name
+				| TField(_, FEnum(en,ef)) ->
+					let s = ef.ef_name in
+					print w "%s." (path_s_import e.epos en.e_path en.e_meta); write_field w s
+				| TArray (e1, e2) ->
+					expr_s w e1; write w "["; expr_s w e2; write w "]"
+				| TBinop ((Ast.OpAssign as op), e1, e2)
+				| TBinop ((Ast.OpAssignOp _ as op), e1, e2) ->
+					expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2
+				| TBinop (op, e1, e2) ->
+					write w "( ";
+					expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2;
+					write w " )"
+				| TField (e, FStatic(_, cf)) when Meta.has Meta.Native cf.cf_meta ->
+					let rec loop meta = match meta with
+						| (Meta.Native, [EConst (String s), _],_) :: _ ->
+							expr_s w e; write w "."; write_field w s
+						| _ :: tl -> loop tl
+						| [] -> expr_s w e; write w "."; write_field w (cf.cf_name)
+					in
+					loop cf.cf_meta
+				| TField (e, s) ->
+					expr_s w e; write w "."; write_field w (field_name s)
+				| TTypeExpr (TClassDecl { cl_path = (["haxe"], "Int32") }) ->
+					write w (path_s_import e.epos (["haxe"], "Int32") [])
+				| TTypeExpr (TClassDecl { cl_path = (["haxe"], "Int64") }) ->
+					write w (path_s_import e.epos (["haxe"], "Int64") [])
+				| TTypeExpr mt -> write w (md_s e.epos mt)
+				| TParenthesis e ->
+					write w "("; expr_s w e; write w ")"
+				| TMeta (_,e) ->
+					expr_s w e
+				| TCall ({ eexpr = TLocal { v_name = "__array__" } }, el)
+				| TCall ({ eexpr = TField(_, FStatic({ cl_path = (["java"],"NativeArray") }, { cf_name = "make" })) }, el)
+				| TArrayDecl el when t_has_type_param e.etype ->
+					let _, el = extract_tparams [] el in
+					print w "( (%s) (new %s " (t_s e.epos e.etype) (t_s e.epos (replace_type_param e.etype));
+					write w "{";
+					ignore (List.fold_left (fun acc e ->
+						(if acc <> 0 then write w ", ");
+						expr_s w e;
+						acc + 1
+					) 0 el);
+					write w "}) )"
+				| TCall ({ eexpr = TLocal { v_name = "__array__" } }, el)
+				| TCall ({ eexpr = TField(_, FStatic({ cl_path = (["java"],"NativeArray") }, { cf_name = "make" })) }, el)
+				| TArrayDecl el ->
+					let _, el = extract_tparams [] el in
+					print w "new %s" (param_t_s e.epos (transform_nativearray_t e.etype));
+					let is_double = match follow e.etype with
+					 | TInst(_,[ t ]) -> if like_float t && not (like_int t) then Some t else None
+					 | _ -> None
+					in
+
+					write w "{";
+					ignore (List.fold_left (fun acc e ->
+						(if acc <> 0 then write w ", ");
+						(* this is a hack so we are able to convert ints to boxed Double / Float when needed *)
+						let e = if is_some is_double then mk_cast (get is_double) e else e in
+
+						expr_s w e;
+						acc + 1
+					) 0 el);
+					write w "}"
+				| TCall( ( { eexpr = TField(_, FStatic({ cl_path = ([], "String") }, { cf_name = "fromCharCode" })) } ), [cc] ) ->
+						write w "Character.toString((char) ";
+						expr_s w cc;
+						write w ")"
+				| TCall ({ eexpr = TLocal( { v_name = "__is__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) ->
+					write w "( ";
+					expr_s w expr;
+					write w " instanceof ";
+					write w (md_s e.epos md);
+					write w " )"
+				| TCall ({ eexpr = TLocal( { v_name = "__java__" } ) }, [ { eexpr = TConst(TString(s)) } ] ) ->
+					write w s
+				| TCall ({ eexpr = TLocal( { v_name = "__java__" } ) }, { eexpr = TConst(TString(s)) } :: tl ) ->
+					Codegen.interpolate_code gen.gcon s tl (write w) (expr_s w) e.epos
+				| TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, [ eobj; eblock ] ) ->
+					write w "synchronized(";
+					let rec loop eobj = match eobj.eexpr with
+						| TTypeExpr md ->
+							expr_s w eobj;
+							write w ".class"
+						| TMeta(_,e) | TParenthesis(e) ->
+							loop e
+						| _ ->
+							expr_s w eobj
+					in
+					loop eobj;
+					write w ")";
+					(match eblock.eexpr with
+					| TBlock(_ :: _) ->
+						expr_s w eblock
+					| _ ->
+						begin_block w;
+						expr_s w eblock;
+						if has_semicolon eblock then write w ";";
+						end_block w;
+					)
+				| TCall ({ eexpr = TLocal( { v_name = "__goto__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
+					print w "break label%ld" v
+				| TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
+					print w "label%ld:" v
+				| TCall ({ eexpr = TLocal( { v_name = "__typeof__" } ) }, [ { eexpr = TTypeExpr md } as expr ] ) ->
+					expr_s w expr;
+					write w ".class"
+				| TCall (e, el) ->
+					let params, el = extract_tparams [] el in
+
+					expr_s w e;
+
+					(*(match params with
+						| [] -> ()
+						| params ->
+							let md = match e.eexpr with
+								| TField(ef, _) -> t_to_md (run_follow gen ef.etype)
+								| _ -> assert false
+							in
+							write w "<";
+							ignore (List.fold_left (fun acc t ->
+								(if acc <> 0 then write w ", ");
+								write w (param_t_s (change_param_type md t));
+								acc + 1
+							) 0 params);
+							write w ">"
+					);*)
+
+					write w "(";
+					ignore (List.fold_left (fun acc e ->
+						(if acc <> 0 then write w ", ");
+						expr_s w e;
+						acc + 1
+					) 0 el);
+					write w ")"
+				| TNew (({ cl_path = (["java"], "NativeArray") } as cl), params, [ size ]) ->
+					let rec check_t_s t times =
+						match real_type t with
+							| TInst({ cl_path = (["java"], "NativeArray") }, [param]) ->
+								(check_t_s param (times+1))
+							| _ ->
+								print w "new %s[" (t_s e.epos (transform_nativearray_t t));
+								expr_s w size;
+								print w "]";
+								let rec loop i =
+									if i <= 0 then () else (write w "[]"; loop (i-1))
+								in
+								loop (times - 1)
+					in
+					check_t_s (TInst(cl, params)) 0
+				| TNew ({ cl_path = ([], "String") } as cl, [], el) ->
+					write w "new ";
+					write w (t_s e.epos (TInst(cl, [])));
+					write w "(";
+					ignore (List.fold_left (fun acc e ->
+						(if acc <> 0 then write w ", ");
+						expr_s w e;
+						acc + 1
+					) 0 el);
+					write w ")"
+				| TNew ({ cl_kind = KTypeParameter _ } as cl, params, el) ->
+						print w "null /* This code should never be reached. It was produced by the use of @:generic on a new type parameter instance: %s */" (path_param_s e.epos (TClassDecl cl) cl.cl_path params cl.cl_meta)
+				| TNew (cl, params, el) ->
+					write w "new ";
+					write w (path_param_s e.epos (TClassDecl cl) cl.cl_path params cl.cl_meta);
+					write w "(";
+					ignore (List.fold_left (fun acc e ->
+						(if acc <> 0 then write w ", ");
+						expr_s w e;
+						acc + 1
+					) 0 el);
+					write w ")"
+				| TUnop ((Ast.Increment as op), flag, e)
+				| TUnop ((Ast.Decrement as op), flag, e) ->
+					(match flag with
+						| Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " " ); expr_s w e
+						| Ast.Postfix -> expr_s w e; write w (Ast.s_unop op))
+				| TUnop (op, flag, e) ->
+					(match flag with
+						| Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " (" ); expr_s w e; write w ") "
+						| Ast.Postfix -> write w "("; expr_s w e; write w (") " ^ Ast.s_unop op))
+				| TVar (var, eopt) ->
+					print w "%s " (t_s e.epos var.v_type);
+					write_id w var.v_name;
+					(match eopt with
+						| None ->
+							write w " = ";
+							expr_s w (null var.v_type e.epos)
+						| Some e ->
+							write w " = ";
+							expr_s w e
+					)
+				| TBlock [e] when was_in_value ->
+					expr_s w e
+				| TBlock el ->
+					begin_block w;
+					List.iter (fun e ->
+						List.iter (fun e ->
+							in_value := false;
+							line_directive w e.epos;
+							expr_s w e;
+							if has_semicolon e then write w ";";
+							newline w;
+						) (extract_statements e)
+					) el;
+					end_block w
+				| TIf (econd, e1, Some(eelse)) when was_in_value ->
+					write w "( ";
+					expr_s w (mk_paren econd);
+					write w " ? ";
+					expr_s w (mk_paren e1);
+					write w " : ";
+					expr_s w (mk_paren eelse);
+					write w " )";
+				| TIf (econd, e1, eelse) ->
+					write w "if ";
+					expr_s w (mk_paren econd);
+					write w " ";
+					in_value := false;
+					expr_s w (mk_block e1);
+					(match eelse with
+						| None -> ()
+						| Some e ->
+							write w "else";
+							in_value := false;
+							expr_s w (mk_block e)
+					)
+				| TWhile (econd, eblock, flag) ->
+					(match flag with
+						| Ast.NormalWhile ->
+							write w "while ";
+							expr_s w (mk_paren econd);
+							write w "";
+							in_value := false;
+							expr_s w (mk_block eblock)
+						| Ast.DoWhile ->
+							write w "do ";
+							in_value := false;
+							expr_s w (mk_block eblock);
+							write w "while ";
+							in_value := true;
+							expr_s w (mk_paren econd);
+					)
+				| TSwitch (econd, ele_l, default) ->
+					write w "switch ";
+					expr_s w (mk_paren econd);
+					begin_block w;
+					List.iter (fun (el, e) ->
+						List.iter (fun e ->
+							write w "case ";
+							in_value := true;
+							(match e.eexpr with
+								| TField(_,FEnum(e,ef)) ->
+									write w ef.ef_name
+								| _ ->
+									expr_s w e);
+							write w ":";
+							newline w;
+						) el;
+						in_value := false;
+						expr_s w (mk_block e);
+						newline w;
+						newline w
+					) ele_l;
+					if is_some default then begin
+						write w "default:";
+						newline w;
+						in_value := false;
+						expr_s w (get default);
+						newline w;
+					end;
+					end_block w
+				| TTry (tryexpr, ve_l) ->
+					write w "try ";
+					in_value := false;
+					expr_s w (mk_block tryexpr);
+					let pos = e.epos in
+					List.iter (fun (var, e) ->
+						print w "catch (%s %s)" (t_s pos var.v_type) (var.v_name);
+						in_value := false;
+						expr_s w (mk_block e);
+						newline w
+					) ve_l
+				| TReturn eopt ->
+					write w "return ";
+					if is_some eopt then expr_s w (get eopt)
+				| TBreak -> write w "break"
+				| TContinue -> write w "continue"
+				| TThrow e ->
+					write w "throw ";
+					expr_s w e
+				| TCast (e1,md_t) ->
+					((*match gen.gfollow#run_f e.etype with
+						| TType({ t_path = ([], "UInt") }, []) ->
+							write w "( unchecked ((uint) ";
+							expr_s w e1;
+							write w ") )"
+						| _ ->*)
+							(* FIXME I'm ignoring module type *)
+							print w "((%s) (" (t_s e.epos e.etype);
+							expr_s w e1;
+							write w ") )"
+					)
+				| TFor (_,_,content) ->
+					write w "[ for not supported ";
+					expr_s w content;
+					write w " ]";
+					if !strict_mode then assert false
+				| TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then assert false
+				| TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then assert false
+				| TEnumParameter _ -> write w "[ enum parameter not supported ]"; if !strict_mode then assert false
+		in
+		expr_s w e
+	in
+
+	let rec gen_fpart_attrib w = function
+		| EConst( Ident i ), _ ->
+			write w i
+		| EField( ef, f ), _ ->
+			gen_fpart_attrib w ef;
+			write w ".";
+			write w f
+		| _, p ->
+			gen.gcon.error "Invalid expression inside @:meta metadata" p
+	in
+
+	let rec gen_spart w = function
+		| EConst c, p -> (match c with
+			| Int s | Float s | Ident s ->
+				write w s
+			| String s ->
+				write w "\"";
+				write w (escape s);
+				write w "\""
+			| _ -> gen.gcon.error "Invalid expression inside @:meta metadata" p)
+		| EField( ef, f ), _ ->
+			gen_spart w ef;
+			write w ".";
+			write w f
+		| EBinop( Ast.OpAssign, (EConst (Ident s), _), e2 ), _ ->
+			write w s;
+			write w " = ";
+			gen_spart w e2
+		| EArrayDecl( el ), _ ->
+			write w "{";
+			let fst = ref true in
+			List.iter (fun e ->
+				if !fst then fst := false else write w ", ";
+				gen_spart w e
+			) el;
+			write w "}"
+		| ECall(fpart,args), _ ->
+			gen_fpart_attrib w fpart;
+			write w "(";
+			let fst = ref true in
+			List.iter (fun e ->
+				if !fst then fst := false else write w ", ";
+				gen_spart w e
+			) args;
+			write w ")"
+		| _, p ->
+			gen.gcon.error "Invalid expression inside @:meta metadata" p
+	in
+
+	let gen_annotations w ?(add_newline=true) metadata =
+		List.iter (function
+			| Meta.Meta, [meta], _ ->
+				write w "@";
+				gen_spart w meta;
+				if add_newline then newline w else write w " ";
+			| _ -> ()
+		) metadata
+	in
+
+	let argt_s p t =
+		let w = new_source_writer () in
+		let rec run t =
+			match t with
+				| TType (tdef,p) ->
+					gen_annotations w ~add_newline:false tdef.t_meta;
+					run (follow_once t)
+				| TMono r ->
+					(match !r with
+					| Some t -> run t
+					| _ -> () (* avoid infinite loop / should be the same in this context *))
+				| TLazy f ->
+					run (!f())
+				| _ -> ()
+		in
+		run t;
+		let ret = t_s p t in
+		let c = contents w in
+		if c <> "" then
+			c ^ " " ^ ret
+		else
+			ret
+	in
+
+	let get_string_params cl_params =
+		match cl_params with
+			| [] ->
+				("","")
+			| _ ->
+				let params = sprintf "<%s>" (String.concat ", " (List.map (fun (_, tcl) -> match follow tcl with | TInst(cl, _) -> snd cl.cl_path | _ -> assert false) cl_params)) in
+				let params_extends = List.fold_left (fun acc (name, t) ->
+					match run_follow gen t with
+						| TInst (cl, p) ->
+							(match cl.cl_implements with
+								| [] -> acc
+								| _ -> acc) (* TODO
+								| _ -> (sprintf " where %s : %s" name (String.concat ", " (List.map (fun (cl,p) -> path_param_s (TClassDecl cl) cl.cl_path p) cl.cl_implements))) :: acc ) *)
+						| _ -> trace (t_s Ast.null_pos t); assert false (* FIXME it seems that a cl_params will never be anything other than cl.cl_params. I'll take the risk and fail if not, just to see if that confirms *)
+				) [] cl_params in
+				(params, String.concat " " params_extends)
+	in
+
+	let write_parts w parts =
+		let parts = List.filter (fun s -> s <> "") parts in
+		write w (String.concat " " parts)
+	in
+
+	let rec gen_class_field w ?(is_overload=false) is_static cl is_final cf =
+		let is_interface = cl.cl_interface in
+		let name, is_new, is_explicit_iface = match cf.cf_name with
+			| "new" -> snd cl.cl_path, true, false
+			| name when String.contains name '.' ->
+				let fn_name, path = parse_explicit_iface name in
+				(path_s path cl.cl_meta) ^ "." ^ fn_name, false, true
+			| name -> name, false, false
+		in
+		(match cf.cf_kind with
+			| Var _
+			| Method (MethDynamic) when not (Type.is_extern_field cf) ->
+				(if is_overload || List.exists (fun cf -> cf.cf_expr <> None) cf.cf_overloads then
+					gen.gcon.error "Only normal (non-dynamic) methods can be overloaded" cf.cf_pos);
+				if not is_interface then begin
+					let access, modifiers = get_fun_modifiers cf.cf_meta "public" [] in
+					write_parts w (access :: (if is_static then "static" else "") :: modifiers @ [(t_s cf.cf_pos (run_follow gen cf.cf_type)); (change_field name)]);
+					(match cf.cf_expr with
+						| Some e ->
+								write w " = ";
+								expr_s w e;
+								write w ";"
+						| None -> write w ";"
+					)
+				end (* TODO see how (get,set) variable handle when they are interfaces *)
+			| Method _ when Type.is_extern_field cf || (match cl.cl_kind, cf.cf_expr with | KAbstractImpl _, None -> true | _ -> false) ->
+				List.iter (fun cf -> if cl.cl_interface || cf.cf_expr <> None then
+					gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf
+				) cf.cf_overloads
+			| Var _ | Method MethDynamic -> ()
+			| Method mkind ->
+				List.iter (fun cf ->
+					if cl.cl_interface || cf.cf_expr <> None then
+						gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf
+				) cf.cf_overloads;
+				let is_virtual = is_new || (not is_final && match mkind with | MethInline -> false | _ when not is_new -> true | _ -> false) in
+				let is_override = match cf.cf_name with
+					| "equals" when not is_static ->
+						(match cf.cf_type with
+							| TFun([_,_,t], ret) ->
+								(match (real_type t, real_type ret) with
+									| TDynamic _, TAbstract ({ a_path = ([], "Bool") },[])
+									| TAnon _, TAbstract ({ a_path = ([], "Bool") },[]) -> true
+									| _ -> List.memq cf cl.cl_overrides
+								)
+							| _ -> List.memq cf cl.cl_overrides)
+					| "toString" when not is_static ->
+						(match cf.cf_type with
+							| TFun([], ret) ->
+								(match real_type ret with
+									| TInst( { cl_path = ([], "String") }, []) -> true
+									| _ -> gen.gcon.error "A toString() function should return a String!" cf.cf_pos; false
+								)
+							| _ -> List.memq cf cl.cl_overrides
+						)
+					| "hashCode" when not is_static ->
+						(match cf.cf_type with
+							| TFun([], ret) ->
+								(match real_type ret with
+									| TAbstract ({ a_path = ([], "Int") },[]) ->
+										true
+									| _ -> gen.gcon.error "A hashCode() function should return an Int!" cf.cf_pos; false
+								)
+							| _ -> List.memq cf cl.cl_overrides
+						)
+					| _ -> List.memq cf cl.cl_overrides
+				in
+				let visibility = if is_interface then "" else "public" in
+
+				let visibility, modifiers = get_fun_modifiers cf.cf_meta visibility [] in
+				let visibility, is_virtual = if is_explicit_iface then "",false else visibility, is_virtual in
+				let v_n = if is_static then "static" else if is_override && not is_interface then "" else if not is_virtual then "final" else "" in
+				let cf_type = if is_override && not is_overload && not (Meta.has Meta.Overload cf.cf_meta) then match field_access gen (TInst(cl, List.map snd cl.cl_params)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> assert false else cf.cf_type in
+
+				let params = List.map snd cl.cl_params in
+				let ret_type, args = match follow cf_type, follow cf.cf_type with
+					| TFun (strbtl, t), TFun(rargs, _) ->
+							(apply_params cl.cl_params params (real_type t), List.map2 (fun(_,_,t) (n,o,_) -> (n,o,apply_params cl.cl_params params (real_type t))) strbtl rargs)
+					| _ -> assert false
+				in
+
+				(if is_override && not is_interface then write w "@Override ");
+				gen_annotations w cf.cf_meta;
+				(* public static void funcName *)
+				let params, _ = get_string_params cf.cf_params in
+
+				write_parts w (visibility :: v_n :: modifiers @ [params; (if is_new then "" else rett_s cf.cf_pos (run_follow gen ret_type)); (change_field name)]);
+
+				(* <T>(string arg1, object arg2) with T : object *)
+				(match cf.cf_expr with
+					| Some { eexpr = TFunction tf } ->
+							print w "(%s)" (String.concat ", " (List.map2 (fun (var,_) (_,_,t) -> sprintf "%s %s" (argt_s cf.cf_pos (run_follow gen t)) (change_id var.v_name)) tf.tf_args args))
+					| _ ->
+							print w "(%s)" (String.concat ", " (List.map (fun (name, _, t) -> sprintf "%s %s" (argt_s cf.cf_pos (run_follow gen t)) (change_id name)) args))
+				);
+				if is_interface || List.mem "native" modifiers then
+					write w ";"
+				else begin
+					let rec loop meta =
+						match meta with
+							| [] ->
+								let expr = match cf.cf_expr with
+									| None -> mk (TBlock([])) t_dynamic Ast.null_pos
+									| Some s ->
+										match s.eexpr with
+											| TFunction tf ->
+												mk_block (tf.tf_expr)
+											| _ -> assert false (* FIXME *)
+								in
+								(if is_new then begin
+									(*let rec get_super_call el =
+										match el with
+											| ( { eexpr = TCall( { eexpr = TConst(TSuper) }, _) } as call) :: rest ->
+												Some call, rest
+											| ( { eexpr = TBlock(bl) } as block ) :: rest ->
+												let ret, mapped = get_super_call bl in
+												ret, ( { block with eexpr = TBlock(mapped) } :: rest )
+											| _ ->
+												None, el
+									in*)
+									expr_s w expr
+								end else begin
+									expr_s w expr;
+								end)
+							| (Meta.Throws, [Ast.EConst (Ast.String t), _], _) :: tl ->
+								print w " throws %s" t;
+								loop tl
+							| (Meta.FunctionCode, [Ast.EConst (Ast.String contents),_],_) :: tl ->
+								begin_block w;
+								write w contents;
+								end_block w
+							| _ :: tl -> loop tl
+					in
+					loop cf.cf_meta
+
+				end);
+			newline w;
+			newline w
+	in
+
+	let gen_class w cl =
+		let cf_filters = [ handle_throws ] in
+		List.iter (fun f -> List.iter (f gen) cl.cl_ordered_fields) cf_filters;
+		List.iter (fun f -> List.iter (f gen) cl.cl_ordered_statics) cf_filters;
+		let should_close = match change_ns (fst cl.cl_path) with
+			| [] -> false
+			| ns ->
+				print w "package %s;" (String.concat "." (change_ns ns));
+				newline w;
+				newline w;
+				false
+		in
+
+		let rec loop_meta meta acc =
+			match meta with
+				| (Meta.SuppressWarnings, [Ast.EConst (Ast.String w),_],_) :: meta -> loop_meta meta (w :: acc)
+				| _ :: meta -> loop_meta meta acc
+				| _ -> acc
+		in
+
+		let suppress_warnings = loop_meta cl.cl_meta [ "rawtypes"; "unchecked" ] in
+
+		write w "import haxe.root.*;";
+		newline w;
+		let w_header = w in
+		let w = new_source_writer () in
+		clear_scope();
+
+		(* add all haxe.root.* to imports *)
+		List.iter (function
+			| TClassDecl { cl_path = ([],c) } ->
+					imports := ([],c) :: !imports
+			| TEnumDecl { e_path = ([],c) } ->
+					imports := ([],c) :: !imports
+			| TAbstractDecl { a_path = ([],c) } ->
+					imports := ([],c) :: !imports
+			| _ -> ()
+		) gen.gtypes_list;
+
+		newline w;
+		write w "@SuppressWarnings(value={";
+		let first = ref true in
+		List.iter (fun s ->
+			(if !first then first := false else write w ", ");
+			print w "\"%s\"" (escape s)
+		) suppress_warnings;
+		write w "})";
+		newline w;
+		gen_annotations w cl.cl_meta;
+
+		let clt, access, modifiers = get_class_modifiers cl.cl_meta (if cl.cl_interface then "interface" else "class") "public" [] in
+		let is_final = Meta.has Meta.Final cl.cl_meta in
+
+		write_parts w (access :: modifiers @ [clt; (change_clname (snd cl.cl_path))]);
+
+		(* type parameters *)
+		let params, _ = get_string_params cl.cl_params in
+		let cl_p_to_string (c,p) =
+			let p = List.map (fun t -> match follow t with
+				| TMono _ | TDynamic _ -> t_empty
+				| _ -> t) p
+			in
+			path_param_s cl.cl_pos (TClassDecl c) c.cl_path p c.cl_meta
+		in
+		print w "%s" params;
+		(if is_some cl.cl_super then print w " extends %s" (cl_p_to_string (get cl.cl_super)));
+		(match cl.cl_implements with
+			| [] -> ()
+			| _ -> print w " %s %s" (if cl.cl_interface then "extends" else "implements") (String.concat ", " (List.map cl_p_to_string cl.cl_implements))
+		);
+		(* class head ok: *)
+		(* public class Test<A> : X, Y, Z where A : Y *)
+		begin_block w;
+		(* our constructor is expected to be a normal "new" function *
+		if !strict_mode && is_some cl.cl_constructor then assert false;*)
+
+		let rec loop cl =
+			List.iter (fun cf -> add_scope cf.cf_name) cl.cl_ordered_fields;
+			List.iter (fun cf -> add_scope cf.cf_name) cl.cl_ordered_statics;
+			match cl.cl_super with
+				| Some(c,_) -> loop c
+				| None -> ()
+		in
+		loop cl;
+
+		let rec loop meta =
+			match meta with
+				| [] -> ()
+				| (Meta.ClassCode, [Ast.EConst (Ast.String contents),_],_) :: tl ->
+					write w contents
+				| _ :: tl -> loop tl
+		in
+		loop cl.cl_meta;
+
+		(match gen.gcon.main_class with
+			| Some path when path = cl.cl_path ->
+				write w "public static void main(String[] args)";
+				begin_block w;
+				(try
+					let t = Hashtbl.find gen.gtypes ([], "Sys") in
+							match t with
+								| TClassDecl(cl) when PMap.mem "_args" cl.cl_statics ->
+									write w "Sys._args = args;"; newline w
+								| _ -> ()
+				with | Not_found -> ()
+				);
+				write w "main();";
+				end_block w;
+				newline w
+			| _ -> ()
+		);
+
+		(match cl.cl_init with
+			| None -> ()
+			| Some init ->
+				write w "static";
+				expr_s w (mk_block init);
+				newline w
+		);
+
+		(if is_some cl.cl_constructor then gen_class_field w false cl is_final (get cl.cl_constructor));
+		(if not cl.cl_interface then List.iter (gen_class_field w true cl is_final) cl.cl_ordered_statics);
+		List.iter (gen_class_field w false cl is_final) cl.cl_ordered_fields;
+
+		end_block w;
+		if should_close then end_block w;
+
+		(* add imports *)
+		List.iter (function
+			| ["haxe";"root"], _ | [], _ -> ()
+			| path ->
+					write w_header "import ";
+					write w_header (path_s path []);
+					write w_header ";\n"
+		) !imports;
+		add_writer w w_header
+	in
+
+
+	let gen_enum w e =
+		let should_close = match change_ns (fst e.e_path) with
+			| [] -> false
+			| ns ->
+				print w "package %s;" (String.concat "." (change_ns ns));
+				newline w;
+				newline w;
+				false
+		in
+
+		gen_annotations w e.e_meta;
+		print w "public enum %s" (change_clname (snd e.e_path));
+		begin_block w;
+		write w (String.concat ", " (List.map (change_id) e.e_names));
+		end_block w;
+
+		if should_close then end_block w
+	in
+
+	let module_type_gen w md_tp =
+		match md_tp with
+			| TClassDecl cl ->
+				if not cl.cl_extern then begin
+					gen_class w cl;
+					newline w;
+					newline w
+				end;
+				(not cl.cl_extern)
+			| TEnumDecl e ->
+				if not e.e_extern && not (Meta.has Meta.Class e.e_meta) then begin
+					gen_enum w e;
+					newline w;
+					newline w
+				end;
+				(not e.e_extern)
+			| TTypeDecl e ->
+				false
+			| TAbstractDecl a ->
+				false
+	in
+
+	let module_gen w md =
+		module_type_gen w md
+	in
+
+	(* generate source code *)
+	init_ctx gen;
+
+	Hashtbl.add gen.gspecial_vars "__label__" true;
+	Hashtbl.add gen.gspecial_vars "__goto__" true;
+	Hashtbl.add gen.gspecial_vars "__is__" true;
+	Hashtbl.add gen.gspecial_vars "__typeof__" true;
+	Hashtbl.add gen.gspecial_vars "__java__" true;
+	Hashtbl.add gen.gspecial_vars "__lock__" true;
+	Hashtbl.add gen.gspecial_vars "__array__" true;
+
+	gen.greal_type <- real_type;
+	gen.greal_type_param <- change_param_type;
+
+	SetHXGen.run_filter gen SetHXGen.default_hxgen_func;
+
+	(* before running the filters, follow all possible types *)
+	(* this is needed so our module transformations don't break some core features *)
+	(* like multitype selection *)
+	let run_follow_gen = run_follow gen in
+	let rec type_map e = Type.map_expr_type (fun e->type_map e) (run_follow_gen)	(fun tvar-> tvar.v_type <- (run_follow_gen tvar.v_type); tvar) e in
+	let super_map (cl,tl) = (cl, List.map run_follow_gen tl) in
+	List.iter (function
+		| TClassDecl cl ->
+				let all_fields = (Option.map_default (fun cf -> [cf]) [] cl.cl_constructor) @ cl.cl_ordered_fields @ cl.cl_ordered_statics in
+				List.iter (fun cf ->
+					cf.cf_type <- run_follow_gen cf.cf_type;
+					cf.cf_expr <- Option.map type_map cf.cf_expr
+				) all_fields;
+			 cl.cl_dynamic <- Option.map run_follow_gen cl.cl_dynamic;
+			 cl.cl_array_access <- Option.map run_follow_gen cl.cl_array_access;
+			 cl.cl_init <- Option.map type_map cl.cl_init;
+			 cl.cl_super <- Option.map super_map cl.cl_super;
+			 cl.cl_implements <- List.map super_map cl.cl_implements
+		| _ -> ()
+		) gen.gtypes_list;
+
+	let closure_t = ClosuresToClass.DoubleAndDynamicClosureImpl.get_ctx gen 6 in
+
+	(*let closure_t = ClosuresToClass.create gen 10 float_cl
+		(fun l -> l)
+		(fun l -> l)
+		(fun args -> args)
+		(fun args -> [])
+	in
+	ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (fun e _ _ -> e));
+
+	StubClosureImpl.configure gen (StubClosureImpl.default_implementation gen float_cl 10 (fun e _ _ -> e));*)
+
+	let get_vmtype t = match real_type t with
+		| TInst({ cl_path = ["java"],"NativeArray" }, tl) -> t
+		| TInst(c,tl) -> TInst(c,List.map (fun _ -> t_dynamic) tl)
+		| TEnum(e,tl) -> TEnum(e, List.map (fun _ -> t_dynamic) tl)
+		| TType(t,tl) -> TType(t, List.map (fun _ -> t_dynamic) tl)
+		| TAbstract(a,tl) -> TAbstract(a, List.map (fun _ -> t_dynamic) tl)
+		| t -> t
+	in
+
+	FixOverrides.configure ~get_vmtype gen;
+	Normalize.configure gen ~metas:(Hashtbl.create 0);
+	AbstractImplementationFix.configure gen;
+
+	IteratorsInterface.configure gen (fun e -> e);
+
+	ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) ));
+
+	let enum_base = (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) in
+	let param_enum_base = (get_cl (get_type gen (["haxe";"lang"],"ParamEnum")) ) in
+	EnumToClass.configure gen (None) false true enum_base param_enum_base false false;
+
+	InterfaceVarsDeleteModf.configure gen;
+
+	let dynamic_object = (get_cl (get_type gen (["haxe";"lang"],"DynamicObject")) ) in
+
+	let object_iface = get_cl (get_type gen (["haxe";"lang"],"IHxObject")) in
+
+	(*fixme: THIS IS A HACK. take this off *)
+	let empty_e = match (get_type gen (["haxe";"lang"], "EmptyObject")) with | TEnumDecl e -> e | _ -> assert false in
+	(*OverloadingCtor.set_new_create_empty gen ({eexpr=TEnumField(empty_e, "EMPTY"); etype=TEnum(empty_e,[]); epos=null_pos;});*)
+
+	let empty_expr = { eexpr = (TTypeExpr (TEnumDecl empty_e)); etype = (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics empty_e) }); epos = null_pos } in
+	let empty_ef =
+		try
+			PMap.find "EMPTY" empty_e.e_constrs
+		with Not_found -> gen.gcon.error "Required enum field EMPTY was not found" empty_e.e_pos; assert false
+	in
+	OverloadingConstructor.configure ~empty_ctor_type:(TEnum(empty_e, [])) ~empty_ctor_expr:({ eexpr=TField(empty_expr, FEnum(empty_e, empty_ef)); etype=TEnum(empty_e,[]); epos=null_pos; }) ~supports_ctor_inheritance:false gen;
+
+	let rcf_static_find = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "findHash" Ast.null_pos [] in
+	(*let rcf_static_lookup = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "lookupHash" Ast.null_pos [] in*)
+	let get_specialized_postfix t = match t with
+		| TAbstract({a_path = [],"Float"}, _) -> "Float"
+		| TInst({cl_path = [],"String"},_) -> "String"
+		| TAnon _ | TDynamic _ -> "Dynamic"
+		| _ -> print_endline (debug_type t); assert false
+	in
+	let rcf_static_insert t = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) ("insert" ^ get_specialized_postfix t) Ast.null_pos [] in
+	let rcf_static_remove t = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) ("remove" ^ get_specialized_postfix t) Ast.null_pos [] in
+
+	let can_be_float t = like_float (real_type t) in
+
+	let rcf_on_getset_field main_expr field_expr field may_hash may_set is_unsafe =
+		let is_float = can_be_float (if is_none may_set then main_expr.etype else (get may_set).etype) in
+		let fn_name = if is_some may_set then "setField" else "getField" in
+		let fn_name = if is_float then fn_name ^ "_f" else fn_name in
+		let pos = field_expr.epos in
+
+		let is_unsafe = { eexpr = TConst(TBool is_unsafe); etype = basic.tbool; epos = pos } in
+
+		let should_cast = match main_expr.etype with | TAbstract({ a_path = ([], "Float") }, []) -> false | _ -> true in
+		let infer = mk_static_field_access_infer runtime_cl fn_name field_expr.epos [] in
+		let first_args =
+			[ field_expr; { eexpr = TConst(TString field); etype = basic.tstring; epos = pos } ]
+			@ if is_some may_hash then [ { eexpr = TConst(TInt (get may_hash)); etype = basic.tint; epos = pos } ] else []
+		in
+		let args = first_args @ match is_float, may_set with
+			| true, Some(set) ->
+				[ if should_cast then mk_cast basic.tfloat set else set ]
+			| false, Some(set) ->
+				[ set ]
+			| _ ->
+				[ is_unsafe ]
+		in
+
+		let call = { main_expr with eexpr = TCall(infer,args) } in
+		let call = if is_float && should_cast then mk_cast main_expr.etype call else call in
+		call
+	in
+
+	let rcf_on_call_field ecall field_expr field may_hash args =
+		let infer = mk_static_field_access_infer runtime_cl "callField" field_expr.epos [] in
+
+		let hash_arg = match may_hash with
+			| None -> []
+			| Some h -> [ { eexpr = TConst(TInt h); etype = basic.tint; epos = field_expr.epos } ]
+		in
+
+		let arr_call = if args <> [] then
+			{ eexpr = TArrayDecl args; etype = basic.tarray t_dynamic; epos = ecall.epos }
+		else
+			null (basic.tarray t_dynamic) ecall.epos
+		in
+
+
+		let call_args =
+			[field_expr; { field_expr with eexpr = TConst(TString field); etype = basic.tstring } ]
+				@ hash_arg
+				@ [ arr_call ]
+		in
+
+		mk_cast ecall.etype { ecall with eexpr = TCall(infer, call_args); etype = t_dynamic }
+	in
+
+	let rcf_ctx =
+		ReflectionCFs.new_ctx
+			gen
+			closure_t
+			object_iface
+			false
+			rcf_on_getset_field
+			rcf_on_call_field
+			(fun hash hash_array length -> { hash with eexpr = TCall(rcf_static_find, [hash; hash_array; length]); etype=basic.tint })
+			(fun hash -> hash)
+			(fun hash_array length pos value ->
+				{ hash_array with
+					eexpr = TBinop(OpAssign,
+								hash_array,
+								mk (TCall(rcf_static_insert value.etype, [hash_array; length; pos; value])) hash_array.etype hash_array.epos)
+			})
+			(fun hash_array length pos ->
+				let t = gen.gclasses.nativearray_type hash_array.etype in
+				{ hash_array with eexpr = TCall(rcf_static_remove t, [hash_array; length; pos]); etype = gen.gcon.basic.tvoid }
+			)
+			false
+		in
+
+	ReflectionCFs.UniversalBaseClass.default_config gen (get_cl (get_type gen (["haxe";"lang"],"HxObject")) ) object_iface dynamic_object;
+
+	ReflectionCFs.configure_dynamic_field_access rcf_ctx false;
+
+	(* let closure_func = ReflectionCFs.implement_closure_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"],"Closure")) ) in *)
+	let closure_cl = get_cl (get_type gen (["haxe";"lang"],"Closure")) in
+
+	let closure_func = ReflectionCFs.get_closure_func rcf_ctx closure_cl in
+
+	ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) );
+
+	let slow_invoke = mk_static_field_access_infer (runtime_cl) "slowCallField" Ast.null_pos [] in
+	ReflectionCFs.configure rcf_ctx ~slow_invoke:(fun ethis efield eargs -> {
+		eexpr = TCall(slow_invoke, [ethis; efield; eargs]);
+		etype = t_dynamic;
+		epos = ethis.epos;
+	} ) object_iface;
+
+	let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in
+
+	ObjectDeclMap.configure gen (ObjectDeclMap.traverse gen objdecl_fn);
+
+	InitFunction.configure gen true true;
+	TArrayTransform.configure gen (TArrayTransform.default_implementation gen (
+	fun e _ ->
+		match e.eexpr with
+			| TArray ({ eexpr = TLocal { v_extra = Some( _ :: _, _) } }, _) -> (* captured transformation *)
+				false
+			| TArray(e1, e2) ->
+				( match run_follow gen (follow e1.etype) with
+					| TInst({ cl_path = (["java"], "NativeArray") }, _) -> false
+					| _ -> true )
+			| _ -> assert false
+	) "__get" "__set" );
+
+	let field_is_dynamic t field =
+		match field_access_esp gen (gen.greal_type t) field with
+			| FClassField (cl,p,_,_,_,t,_) ->
+				let p = change_param_type (TClassDecl cl) p in
+				is_dynamic (apply_params cl.cl_params p t)
+			| FEnumField _ -> false
+			| _ -> true
+	in
+
+	let is_type_param e = match follow e with
+		| TInst( { cl_kind = KTypeParameter _ },[]) -> true
+		| _ -> false
+	in
+
+	let is_dynamic_expr e =
+		is_dynamic e.etype || match e.eexpr with
+		| TField(tf, f) ->
+			field_is_dynamic tf.etype f
+		| _ ->
+			false
+	in
+
+	let may_nullable t = match gen.gfollow#run_f t with
+		| TType({ t_path = ([], "Null") }, [t]) ->
+			(match follow t with
+				| TInst({ cl_path = ([], "String") }, [])
+				| TAbstract ({ a_path = ([], "Float") },[])
+				| TInst({ cl_path = (["haxe"], "Int32")}, [] )
+				| TInst({ cl_path = (["haxe"], "Int64")}, [] )
+				| TAbstract ({ a_path = ([], "Int") },[])
+				| TAbstract ({ a_path = ([], "Bool") },[]) -> Some t
+				| t when is_java_basic_type t -> Some t
+				| _ -> None )
+		| _ -> None
+	in
+
+	let is_double t = like_float t && not (like_int t) in
+	let is_int t = like_int t in
+
+	DynamicOperators.configure gen
+		(DynamicOperators.abstract_implementation gen (fun e -> match e.eexpr with
+			| TBinop (Ast.OpEq, e1, e2) ->
+				is_dynamic e1.etype || is_dynamic e2.etype || is_type_param e1.etype || is_type_param e2.etype
+			| TBinop (Ast.OpAdd, e1, e2)
+			| TBinop (Ast.OpNotEq, e1, e2) -> is_dynamic e1.etype || is_dynamic e2.etype || is_type_param e1.etype || is_type_param e2.etype
+			| TBinop (Ast.OpLt, e1, e2)
+			| TBinop (Ast.OpLte, e1, e2)
+			| TBinop (Ast.OpGte, e1, e2)
+			| TBinop (Ast.OpGt, e1, e2) -> is_dynamic e.etype || is_dynamic_expr e1 || is_dynamic_expr e2 || is_string e1.etype || is_string e2.etype
+			| TBinop (_, e1, e2) -> is_dynamic e.etype || is_dynamic_expr e1 || is_dynamic_expr e2
+			| TUnop (_, _, e1) ->
+				is_dynamic_expr e1
+			| _ -> false)
+		(fun e1 e2 ->
+			let is_null e = match e.eexpr with | TConst(TNull) | TLocal({ v_name = "__undefined__" }) -> true | _ -> false in
+
+			match e1.eexpr, e2.eexpr with
+				| TConst c1, TConst c2 when is_null e1 || is_null e2 ->
+					{ e1 with eexpr = TConst(TBool (c1 = c2)); etype = basic.tbool }
+				| _ when is_null e1 || is_null e2 && not (is_java_basic_type e1.etype || is_java_basic_type e2.etype) ->
+					{ e1 with eexpr = TBinop(Ast.OpEq, e1, e2); etype = basic.tbool }
+				| _ ->
+				let is_ref = match follow e1.etype, follow e2.etype with
+					| TDynamic _, _
+					| _, TDynamic _
+					| TAbstract ({ a_path = ([], "Float") },[]) , _
+					| TInst( { cl_path = (["haxe"], "Int32") }, [] ), _
+					| TInst( { cl_path = (["haxe"], "Int64") }, [] ), _
+					| TAbstract ({ a_path = ([], "Int") },[]) , _
+					| TAbstract ({ a_path = ([], "Bool") },[]) , _
+					| _, TAbstract ({ a_path = ([], "Float") },[])
+					| _, TAbstract ({ a_path = ([], "Int") },[])
+					| _, TInst( { cl_path = (["haxe"], "Int32") }, [] )
+					| _, TInst( { cl_path = (["haxe"], "Int64") }, [] )
+					| _, TAbstract ({ a_path = ([], "Bool") },[])
+					| TInst( { cl_kind = KTypeParameter _ }, [] ), _
+					| _, TInst( { cl_kind = KTypeParameter _ }, [] ) -> false
+					| _, _ -> true
+				in
+
+				let static = mk_static_field_access_infer (runtime_cl) (if is_ref then "refEq" else "eq") e1.epos [] in
+				{ eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tbool; epos=e1.epos }
+		)
+		(fun e e1 e2 ->
+			match may_nullable e1.etype, may_nullable e2.etype with
+				| Some t1, Some t2 ->
+					let t1, t2 = if is_string t1 || is_string t2 then
+						basic.tstring, basic.tstring
+					else if is_double t1 || is_double t2 then
+						basic.tfloat, basic.tfloat
+					else if is_int t1 || is_int t2 then
+						basic.tint, basic.tint
+					else t1, t2 in
+					{ eexpr = TBinop(Ast.OpAdd, mk_cast t1 e1, mk_cast t2 e2); etype = e.etype; epos = e1.epos }
+				| _ ->
+					let static = mk_static_field_access_infer (runtime_cl) "plus"  e1.epos [] in
+					mk_cast e.etype { eexpr = TCall(static, [e1; e2]); etype = t_dynamic; epos=e1.epos })
+		(fun e1 e2 ->
+			if is_string e1.etype then begin
+				{ e1 with eexpr = TCall(mk_field_access gen e1 "compareTo" e1.epos, [ e2 ]); etype = gen.gcon.basic.tint }
+			end else begin
+				let static = mk_static_field_access_infer (runtime_cl) "compare" e1.epos [] in
+				{ eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos }
+			end));
+
+	FilterClosures.configure gen (FilterClosures.traverse gen (fun e1 s -> true) closure_func);
+
+	let base_exception = get_cl (get_type gen (["java"; "lang"], "Throwable")) in
+	let base_exception_t = TInst(base_exception, []) in
+
+	let hx_exception = get_cl (get_type gen (["haxe";"lang"], "HaxeException")) in
+	let hx_exception_t = TInst(hx_exception, []) in
+
+	let rec is_exception t =
+		match follow t with
+			| TInst(cl,_) ->
+				if cl == base_exception then
+					true
+				else
+					(match cl.cl_super with | None -> false | Some (cl,arg) -> is_exception (TInst(cl,arg)))
+			| _ -> false
+	in
+
+	TryCatchWrapper.configure gen
+	(
+		TryCatchWrapper.traverse gen
+			(fun t -> not (is_exception (real_type t)))
+			(fun throwexpr expr ->
+				let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], hx_exception_t)) expr.epos in
+				{ throwexpr with eexpr = TThrow { expr with eexpr = TCall(wrap_static, [expr]); etype = hx_exception_t }; etype = gen.gcon.basic.tvoid }
+			)
+			(fun v_to_unwrap pos ->
+				let local = mk_cast hx_exception_t { eexpr = TLocal(v_to_unwrap); etype = v_to_unwrap.v_type; epos = pos } in
+				mk_field_access gen local "obj" pos
+			)
+			(fun rethrow ->
+				let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], hx_exception_t)) rethrow.epos in
+				{ rethrow with eexpr = TThrow { rethrow with eexpr = TCall(wrap_static, [rethrow]); etype = hx_exception_t }; }
+			)
+			(base_exception_t)
+			(hx_exception_t)
+			(fun v e ->
+
+				let exc_cl = get_cl (get_type gen (["haxe";"lang"],"Exceptions")) in
+				let exc_field = mk_static_field_access_infer exc_cl "setException" e.epos [] in
+				let esetstack = { eexpr = TCall(exc_field,[mk_local v e.epos]); etype = gen.gcon.basic.tvoid; epos = e.epos } in
+
+				Type.concat esetstack e;
+			)
+	);
+
+	let get_typeof e =
+		{ e with eexpr = TCall( { eexpr = TLocal( alloc_var "__typeof__" t_dynamic ); etype = t_dynamic; epos = e.epos }, [e] ) }
+	in
+
+	ClassInstance.configure gen (ClassInstance.traverse gen (fun e mt -> get_typeof e));
+
+	(*let v = alloc_var "$type_param" t_dynamic in*)
+	TypeParams.configure gen (fun ecall efield params elist ->
+		{ ecall with eexpr = TCall(efield, elist) }
+	);
+
+	CastDetect.configure gen (CastDetect.default_implementation gen ~native_string_cast:false (Some (TEnum(empty_e, []))) false);
+
+	(*FollowAll.configure gen;*)
+
+	SwitchToIf.configure gen (SwitchToIf.traverse gen (fun e ->
+		match e.eexpr with
+			| TSwitch(cond, cases, def) ->
+				(match gen.gfollow#run_f cond.etype with
+					| TInst( { cl_path = (["haxe"], "Int32") }, [] )
+					| TAbstract ({ a_path = ([], "Int") },[])
+					| TInst({ cl_path = ([], "String") },[]) ->
+						(List.exists (fun (c,_) ->
+							List.exists (fun expr -> match expr.eexpr with | TConst _ -> false | _ -> true ) c
+						) cases)
+					| _ -> true
+				)
+			| _ -> assert false
+	) true );
+
+	ExpressionUnwrap.configure gen (ExpressionUnwrap.traverse gen (fun e -> Some { eexpr = TVar(mk_temp gen "expr" e.etype, Some e); etype = gen.gcon.basic.tvoid; epos = e.epos }));
+
+	UnnecessaryCastsRemoval.configure gen;
+
+	IntDivisionSynf.configure gen (IntDivisionSynf.default_implementation gen true);
+
+	UnreachableCodeEliminationSynf.configure gen (UnreachableCodeEliminationSynf.traverse gen false true true true);
+
+	ArrayDeclSynf.configure gen (ArrayDeclSynf.default_implementation gen native_arr_cl);
+
+	let goto_special = alloc_var "__goto__" t_dynamic in
+	let label_special = alloc_var "__label__" t_dynamic in
+	SwitchBreakSynf.configure gen (SwitchBreakSynf.traverse gen
+		(fun e_loop n api ->
+			{ e_loop with eexpr = TBlock( { eexpr = TCall( mk_local label_special e_loop.epos, [ mk_int gen n e_loop.epos ] ); etype = t_dynamic; epos = e_loop.epos } :: [e_loop] ) };
+		)
+		(fun e_break n api ->
+			{ eexpr = TCall( mk_local goto_special e_break.epos, [ mk_int gen n e_break.epos ] ); etype = t_dynamic; epos = e_break.epos }
+		)
+	);
+
+	DefaultArguments.configure gen (DefaultArguments.traverse gen);
+	InterfaceMetas.configure gen;
+
+	JavaSpecificSynf.configure gen (JavaSpecificSynf.traverse gen runtime_cl);
+	JavaSpecificESynf.configure gen (JavaSpecificESynf.traverse gen runtime_cl);
+
+	(* add native String as a String superclass *)
+	let str_cl = match gen.gcon.basic.tstring with | TInst(cl,_) -> cl | _ -> assert false in
+	str_cl.cl_super <- Some (get_cl (get_type gen (["haxe";"lang"], "NativeString")), []);
+
+	let mkdir dir = if not (Sys.file_exists dir) then Unix.mkdir dir 0o755 in
+	mkdir gen.gcon.file;
+	mkdir (gen.gcon.file ^ "/src");
+
+	let out_files = ref [] in
+
+	(* add resources array *)
+	let res = ref [] in
+	Hashtbl.iter (fun name v ->
+		res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = Ast.null_pos } :: !res;
+		let name = Codegen.escape_res_name name true in
+		let full_path = gen.gcon.file ^ "/src/" ^ name in
+		mkdir_from_path full_path;
+
+		let f = open_out_bin full_path in
+		output_string f v;
+		close_out f;
+
+		out_files := (unique_full_path full_path) :: !out_files
+	) gen.gcon.resources;
+	(try
+		let c = get_cl (Hashtbl.find gen.gtypes (["haxe"], "Resource")) in
+		let cf = PMap.find "content" c.cl_statics in
+		cf.cf_expr <- Some ({ eexpr = TArrayDecl(!res); etype = gen.gcon.basic.tarray gen.gcon.basic.tstring; epos = Ast.null_pos })
+	with | Not_found -> ());
+
+	run_filters gen;
+
+	TypeParams.RenameTypeParameters.run gen;
 
-  let t = Common.timer "code generation" in
+	let t = Common.timer "code generation" in
 
-	generate_modules_t gen "java" "src" change_path module_gen;
+	let parts = Str.split_delim (Str.regexp "[\\/]+") gen.gcon.file in
+	mkdir_recursive "" parts;
+	generate_modules_t gen "java" "src" change_path module_gen out_files;
 
-  dump_descriptor gen ("hxjava_build.txt") path_s (fun md -> path_s (t_infos md).mt_path);
+	if not (Common.defined gen.gcon Define.KeepOldOutput) then
+		clean_files (gen.gcon.file ^ "/src") !out_files gen.gcon.verbose;
+
+	let path_s_desc path = path_s path [] in
+	dump_descriptor gen ("hxjava_build.txt") path_s_desc (fun md -> path_s_desc (t_infos md).mt_path);
 	if ( not (Common.defined gen.gcon Define.NoCompilation) ) then begin
 		let old_dir = Sys.getcwd() in
 		Sys.chdir gen.gcon.file;
-		let cmd = "haxelib run hxjava hxjava_build.txt --haxe-version " ^ (string_of_int gen.gcon.version) in
+		let cmd = "haxelib run hxjava hxjava_build.txt --haxe-version " ^ (string_of_int gen.gcon.version) ^ " --feature-level 1" in
 		print_endline cmd;
 		if gen.gcon.run_command cmd <> 0 then failwith "Build failed";
 		Sys.chdir old_dir;
 	end;
 
-  t()
+	t()
 
 (* end of configure function *)
 
 let before_generate con =
-  let java_ver = try
-      int_of_string (PMap.find "java_ver" con.defines)
-    with | Not_found ->
-      Common.define_value con Define.JavaVer "7";
-      7
-  in
+	let java_ver = try
+			int_of_string (PMap.find "java_ver" con.defines)
+		with | Not_found ->
+			Common.define_value con Define.JavaVer "7";
+			7
+	in
  if java_ver < 5 then failwith ("Java version is defined to target Java " ^ string_of_int java_ver ^ ", but the compiler can only output code to versions equal or superior to Java 5");
-  let rec loop i =
-    Common.raw_define con ("java" ^ (string_of_int i));
-    if i > 0 then loop (i - 1)
-  in
-  loop java_ver;
-  ()
+	let rec loop i =
+		Common.raw_define con ("java" ^ (string_of_int i));
+		if i > 0 then loop (i - 1)
+	in
+	loop java_ver;
+	()
 
 let generate con =
-  let exists = ref false in
-  con.java_libs <- List.map (fun (file,std,close,la,gr) ->
-    if String.ends_with file "hxjava-std.jar" then begin
-      exists := true;
-      (file,true,close,la,gr)
-    end else
-      (file,std,close,la,gr)) con.java_libs;
-  if not !exists then
-    failwith "Your version of hxjava is outdated. Please update it by running: `haxelib update hxjava`";
-  let gen = new_ctx con in
-  gen.gallow_tp_dynamic_conversion <- true;
-
-  let basic = con.basic in
-  (* make the basic functions in java *)
-  let basic_fns =
-  [
-    mk_class_field "equals" (TFun(["obj",false,t_dynamic], basic.tbool)) true Ast.null_pos (Method MethNormal) [];
-    mk_class_field "toString" (TFun([], basic.tstring)) true Ast.null_pos (Method MethNormal) [];
-    mk_class_field "hashCode" (TFun([], basic.tint)) true Ast.null_pos (Method MethNormal) [];
-    mk_class_field "wait" (TFun([], basic.tvoid)) true Ast.null_pos (Method MethNormal) [];
-    mk_class_field "notify" (TFun([], basic.tvoid)) true Ast.null_pos (Method MethNormal) [];
-    mk_class_field "notifyAll" (TFun([], basic.tvoid)) true Ast.null_pos (Method MethNormal) [];
-  ] in
-  List.iter (fun cf -> gen.gbase_class_fields <- PMap.add cf.cf_name cf gen.gbase_class_fields) basic_fns;
-
-  (try
-    configure gen
-  with | TypeNotFound path -> con.error ("Error. Module '" ^ (path_s path) ^ "' is required and was not included in build.")  Ast.null_pos);
-  debug_mode := false
+	let exists = ref false in
+	con.java_libs <- List.map (fun (file,std,close,la,gr) ->
+		if String.ends_with file "hxjava-std.jar" then begin
+			exists := true;
+			(file,true,close,la,gr)
+		end else
+			(file,std,close,la,gr)) con.java_libs;
+	if not !exists then
+		failwith "Your version of hxjava is outdated. Please update it by running: `haxelib update hxjava`";
+	let gen = new_ctx con in
+	gen.gallow_tp_dynamic_conversion <- true;
+
+	let basic = con.basic in
+	(* make the basic functions in java *)
+	let cl_cl = get_cl (get_type gen (["java";"lang"],"Class")) in
+	let basic_fns =
+	[
+		mk_class_field "equals" (TFun(["obj",false,t_dynamic], basic.tbool)) true Ast.null_pos (Method MethNormal) [];
+		mk_class_field "toString" (TFun([], basic.tstring)) true Ast.null_pos (Method MethNormal) [];
+		mk_class_field "hashCode" (TFun([], basic.tint)) true Ast.null_pos (Method MethNormal) [];
+		mk_class_field "getClass" (TFun([], (TInst(cl_cl,[t_dynamic])))) true Ast.null_pos (Method MethNormal) [];
+		mk_class_field "wait" (TFun([], basic.tvoid)) true Ast.null_pos (Method MethNormal) [];
+		mk_class_field "notify" (TFun([], basic.tvoid)) true Ast.null_pos (Method MethNormal) [];
+		mk_class_field "notifyAll" (TFun([], basic.tvoid)) true Ast.null_pos (Method MethNormal) [];
+	] in
+	List.iter (fun cf -> gen.gbase_class_fields <- PMap.add cf.cf_name cf gen.gbase_class_fields) basic_fns;
+
+	(try
+		configure gen
+	with | TypeNotFound path -> con.error ("Error. Module '" ^ (path_s path) ^ "' is required and was not included in build.")	Ast.null_pos);
+	debug_mode := false
 
 (** Java lib *)
 
 open JData
 
 type java_lib_ctx = {
-  jcom : Common.context;
-  (* current tparams context *)
-  mutable jtparams : jtypes list;
+	jcom : Common.context;
+	(* current tparams context *)
+	mutable jtparams : jtypes list;
 }
 
 exception ConversionError of string * pos
 
 let error s p = raise (ConversionError (s, p))
 
+let is_haxe_keyword = function
+	| "callback" | "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true
+	| _ -> false
+
 let jname_to_hx name =
-  let name =
-    if name <> "" && (String.get name 0 < 'A' || String.get name 0 > 'Z') then
-      Char.escaped (Char.uppercase (String.get name 0)) ^ String.sub name 1 (String.length name - 1)
-    else
-      name
-  in
-  (* handle non-inner classes with same final name as non-inner *)
-  let name = String.concat "__" (String.nsplit name "_") in
-  (* handle with inner classes *)
-  String.map (function | '$' -> '_' | c -> c) name
+	let name =
+		if name <> "" && (String.get name 0 < 'A' || String.get name 0 > 'Z') then
+			Char.escaped (Char.uppercase (String.get name 0)) ^ String.sub name 1 (String.length name - 1)
+		else
+			name
+	in
+	let name = String.concat "__" (String.nsplit name "_") in
+	String.map (function | '$' -> '_' | c -> c) name
 
 let normalize_pack pack =
-  List.map (function
-    | "" -> ""
-    | str when String.get str 0 >= 'A' && String.get str 0 <= 'Z' ->
-      String.lowercase str
-    | str -> str
-  ) pack
+	List.map (function
+		| "" -> ""
+		| str when String.get str 0 >= 'A' && String.get str 0 <= 'Z' ->
+			String.lowercase str
+		| str -> str
+	) pack
 
 let jpath_to_hx (pack,name) = match pack, name with
-  | ["haxe";"root"], name -> [], name
-  | "com" :: ("oracle" | "sun") :: _, _
-  | "javax" :: _, _
-  | "org" :: ("ietf" | "jcp" | "omg" | "w3c" | "xml") :: _, _
-  | "sun" :: _, _
-  | "sunw" :: _, _ -> "java" :: normalize_pack pack, jname_to_hx name
-  | pack, name -> normalize_pack pack, jname_to_hx name
-
-let hxname_to_j name =
-  let name = String.implode (List.rev (String.explode name)) in
-  let fl = String.nsplit name "__" in
-  let fl = List.map (String.map (fun c -> if c = '_' then '$' else c)) fl in
-  let ret = String.concat "_" fl in
-  String.implode (List.rev (String.explode ret))
-
-let hxpath_to_j (pack,name) = match pack, name with
-  | "java" :: "com" :: ("oracle" | "sun") :: _, _
-  | "java" :: "javax" :: _, _
-  | "java" :: "org" :: ("ietf" | "jcp" | "omg" | "w3c" | "xml") :: _, _
-  | "java" :: "sun" :: _, _
-  | "java" :: "sunw" :: _, _ -> List.tl pack, hxname_to_j name
-  | pack, name -> pack, hxname_to_j name
+	| ["haxe";"root"], name -> [], name
+	| "com" :: ("oracle" | "sun") :: _, _
+	| "javax" :: _, _
+	| "org" :: ("ietf" | "jcp" | "omg" | "w3c" | "xml") :: _, _
+	| "sun" :: _, _
+	| "sunw" :: _, _ -> "java" :: normalize_pack pack, jname_to_hx name
+	| pack, name -> normalize_pack pack, jname_to_hx name
 
 let real_java_path ctx (pack,name) =
-  path_s (pack, name)
+	path_s (pack, name)
 
 let lookup_jclass com path =
-  let path = jpath_to_hx path in
-  List.fold_right (fun (_,_,_,_,get_raw_class) acc ->
-    match acc with
-    | None -> get_raw_class path
-    | Some p -> Some p
-  ) com.java_libs None
+	let path = jpath_to_hx path in
+	List.fold_right (fun (_,_,_,_,get_raw_class) acc ->
+		match acc with
+		| None -> get_raw_class path
+		| Some p -> Some p
+	) com.java_libs None
 
 let mk_type_path ctx path params =
-  let name, sub = try
-    let p, _ = String.split (snd path) "$" in
-    jname_to_hx p, Some (jname_to_hx (snd path))
-  with | Invalid_string ->
-    jname_to_hx (snd path), None
-  in
-  CTPath {
-    tpackage = fst (jpath_to_hx path);
-    tname = name;
-    tparams = params;
-    tsub = sub;
-  }
+	let name, sub = try
+		let p, _ = String.split (snd path) "$" in
+		jname_to_hx p, Some (jname_to_hx (snd path))
+		with | Invalid_string ->
+			jname_to_hx (snd path), None
+	in
+	let pack = fst (jpath_to_hx path) in
+	let pack, sub, name = match path with
+		| [], ("Float" as c)
+		| [], ("Int" as c)
+		| [], ("Single" as c)
+		| [], ("Bool" as c)
+		| [], ("Dynamic" as c)
+		| [], ("Iterator" as c)
+		| [], ("ArrayAccess" as c)
+		| [], ("Iterable" as c) ->
+			[], Some c, "StdTypes"
+		| [], ("String" as c) ->
+			["std"], None, c
+		| _ ->
+			pack, sub, name
+	in
+	CTPath {
+		tpackage = pack;
+		tname = name;
+		tparams = params;
+		tsub = sub;
+	}
 
 let has_tparam name params = List.exists(fun (n,_,_) -> n = name) params
 
 let rec convert_arg ctx p arg =
-  match arg with
-  | TAny | TType (WSuper, _) -> TPType (mk_type_path ctx ([], "Dynamic") [])
-  | TType (_, jsig) -> TPType (convert_signature ctx p jsig)
+	match arg with
+	| TAny | TType (WSuper, _) -> TPType (mk_type_path ctx ([], "Dynamic") [])
+	| TType (_, jsig) -> TPType (convert_signature ctx p jsig)
 
 and convert_signature ctx p jsig =
-  match jsig with
-  | TByte -> mk_type_path ctx (["java"; "types"], "Int8") []
-  | TChar -> mk_type_path ctx (["java"; "types"], "Char16") []
-  | TDouble -> mk_type_path ctx ([], "Float") []
-  | TFloat -> mk_type_path ctx ([], "Single") []
-  | TInt -> mk_type_path ctx ([], "Int") []
-  | TLong -> mk_type_path ctx (["haxe"], "Int64") []
-  | TShort -> mk_type_path ctx (["java"; "types"], "Int16") []
-  | TBool -> mk_type_path ctx ([], "Bool") []
-  | TObject ( (["haxe";"root"], name), args ) -> mk_type_path ctx ([], name) (List.map (convert_arg ctx p) args)
-  (** nullable types *)
-  | TObject ( (["java";"lang"], "Integer"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Int") []) ]
-  | TObject ( (["java";"lang"], "Double"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Float") []) ]
-  | TObject ( (["java";"lang"], "Single"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Single") []) ]
-  | TObject ( (["java";"lang"], "Boolean"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Bool") []) ]
-  | TObject ( (["java";"lang"], "Byte"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int8") []) ]
-  | TObject ( (["java";"lang"], "Character"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Char16") []) ]
-  | TObject ( (["java";"lang"], "Short"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int16") []) ]
-  | TObject ( (["java";"lang"], "Long"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["haxe"], "Int64") []) ]
-  (** other std types *)
-  | TObject ( (["java";"lang"], "Object"), [] ) -> mk_type_path ctx ([], "Dynamic") []
-  | TObject ( (["java";"lang"], "String"), [] ) -> mk_type_path ctx ([], "String") []
-  (** other types *)
-  | TObject ( path, [] ) ->
-    (match lookup_jclass ctx.jcom path with
-    | Some (jcl, _, _) -> mk_type_path ctx path (List.map (fun _ -> convert_arg ctx p TAny) jcl.ctypes)
-    | None -> mk_type_path ctx path [])
-  | TObject ( path, args ) -> mk_type_path ctx path (List.map (convert_arg ctx p) args)
-  | TObjectInner (pack, (name, params) :: inners) ->
-      let actual_param = match List.rev inners with
-      | (_, p) :: _ -> p
-      | _ -> assert false in
-      mk_type_path ctx (pack, name ^ "$" ^ String.concat "$" (List.map fst inners)) (List.map (fun param -> convert_arg ctx p param) actual_param)
-  | TObjectInner (pack, inners) -> assert false
-  | TArray (jsig, _) -> mk_type_path ctx (["java"], "NativeArray") [ TPType (convert_signature ctx p jsig) ]
-  | TMethod _ -> JReader.error "TMethod cannot be converted directly into Complex Type"
-  | TTypeParameter s -> (match ctx.jtparams with
-    | cur :: others ->
-      if has_tparam s cur then
-        mk_type_path ctx ([], s) []
-      else begin
-        if ctx.jcom.verbose && not(List.exists (has_tparam s) others) then print_endline ("Type parameter " ^ s ^ " was not found while building type!");
-        mk_type_path ctx ([], "Dynamic") []
-      end
-    | _ ->
-      if ctx.jcom.verbose then print_endline ("Empty type parameter stack!");
-      mk_type_path ctx ([], "Dynamic") [])
+	match jsig with
+	| TByte -> mk_type_path ctx (["java"; "types"], "Int8") []
+	| TChar -> mk_type_path ctx (["java"; "types"], "Char16") []
+	| TDouble -> mk_type_path ctx ([], "Float") []
+	| TFloat -> mk_type_path ctx ([], "Single") []
+	| TInt -> mk_type_path ctx ([], "Int") []
+	| TLong -> mk_type_path ctx (["haxe"], "Int64") []
+	| TShort -> mk_type_path ctx (["java"; "types"], "Int16") []
+	| TBool -> mk_type_path ctx ([], "Bool") []
+	| TObject ( (["haxe";"root"], name), args ) -> mk_type_path ctx ([], name) (List.map (convert_arg ctx p) args)
+	(** nullable types *)
+	(* replaced from Null<Type> to the actual abstract type to fix #2738 *)
+	(* | TObject ( (["java";"lang"], "Integer"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Int") []) ] *)
+	(* | TObject ( (["java";"lang"], "Double"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Float") []) ] *)
+	(* | TObject ( (["java";"lang"], "Float"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Single") []) ] *)
+	(* | TObject ( (["java";"lang"], "Boolean"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Bool") []) ] *)
+	(* | TObject ( (["java";"lang"], "Byte"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int8") []) ] *)
+	(* | TObject ( (["java";"lang"], "Character"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Char16") []) ] *)
+	(* | TObject ( (["java";"lang"], "Short"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int16") []) ] *)
+	(* | TObject ( (["java";"lang"], "Long"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["haxe"], "Int64") []) ] *)
+	(** other std types *)
+	| TObject ( (["java";"lang"], "Object"), [] ) -> mk_type_path ctx ([], "Dynamic") []
+	| TObject ( (["java";"lang"], "String"), [] ) -> mk_type_path ctx ([], "String") []
+	| TObject ( (["java";"lang"], "Enum"), [_] ) -> mk_type_path ctx ([], "EnumValue") []
+	(** other types *)
+	| TObject ( path, [] ) ->
+		(match lookup_jclass ctx.jcom path with
+		| Some (jcl, _, _) -> mk_type_path ctx path (List.map (fun _ -> convert_arg ctx p TAny) jcl.ctypes)
+		| None -> mk_type_path ctx path [])
+	| TObject ( path, args ) -> mk_type_path ctx path (List.map (convert_arg ctx p) args)
+	| TObjectInner (pack, (name, params) :: inners) ->
+			let actual_param = match List.rev inners with
+			| (_, p) :: _ -> p
+			| _ -> assert false in
+			mk_type_path ctx (pack, name ^ "$" ^ String.concat "$" (List.map fst inners)) (List.map (fun param -> convert_arg ctx p param) actual_param)
+	| TObjectInner (pack, inners) -> assert false
+	| TArray (jsig, _) -> mk_type_path ctx (["java"], "NativeArray") [ TPType (convert_signature ctx p jsig) ]
+	| TMethod _ -> JReader.error "TMethod cannot be converted directly into Complex Type"
+	| TTypeParameter s -> (match ctx.jtparams with
+		| cur :: others ->
+			if has_tparam s cur then
+				mk_type_path ctx ([], s) []
+			else begin
+				if ctx.jcom.verbose && not(List.exists (has_tparam s) others) then print_endline ("Type parameter " ^ s ^ " was not found while building type!");
+				mk_type_path ctx ([], "Dynamic") []
+			end
+		| _ ->
+			if ctx.jcom.verbose then print_endline ("Empty type parameter stack!");
+			mk_type_path ctx ([], "Dynamic") [])
 
 let convert_constant ctx p const =
-  Option.map_default (function
-    | ConstString s -> Some (EConst (String s), p)
-    | ConstInt i -> Some (EConst (Int (Printf.sprintf "%ld" i)), p)
-    | ConstFloat f | ConstDouble f -> Some (EConst (Float (Printf.sprintf "%E" f)), p)
-    | _ -> None) None const
+	Option.map_default (function
+		| ConstString s -> Some (EConst (String s), p)
+		| ConstInt i -> Some (EConst (Int (Printf.sprintf "%ld" i)), p)
+		| ConstFloat f | ConstDouble f -> Some (EConst (Float (Printf.sprintf "%E" f)), p)
+		| _ -> None) None const
 
 let rec same_sig parent jsig =
-  match jsig with
-  | TObject (p,targs) -> parent = p || List.exists (function | TType (_,s) -> same_sig parent s | _ -> false) targs
-  | TObjectInner(p, ntargs) ->
-      parent = (p, String.concat "$" (List.map fst ntargs)) ||
-      List.exists (fun (_,targs) -> List.exists (function | TType(_,s) -> same_sig parent s | _ -> false) targs) ntargs
-  | TArray(s,_) -> same_sig parent s
-  | _ -> false
+	match jsig with
+	| TObject (p,targs) -> parent = p || List.exists (function | TType (_,s) -> same_sig parent s | _ -> false) targs
+	| TObjectInner(p, ntargs) ->
+			parent = (p, String.concat "$" (List.map fst ntargs)) ||
+			List.exists (fun (_,targs) -> List.exists (function | TType(_,s) -> same_sig parent s | _ -> false) targs) ntargs
+	| TArray(s,_) -> same_sig parent s
+	| _ -> false
 
 let convert_param ctx p parent param =
-  let name, constraints = match param with
-    | (name, Some extends_sig, implem_sig) ->
-      name, extends_sig :: implem_sig
-    | (name, None, implemem_sig) ->
-      name, implemem_sig
-    in
-    let constraints = List.map (fun s -> if same_sig parent s then (TObject( (["java";"lang"], "Object"), [])) else s) constraints in
-    {
-      tp_name = name;
-      tp_params = [];
-      tp_constraints = List.map (convert_signature ctx p) constraints;
-    }
+	let name, constraints = match param with
+		| (name, Some extends_sig, implem_sig) ->
+			name, extends_sig :: implem_sig
+		| (name, None, implemem_sig) ->
+			name, implemem_sig
+		in
+		let constraints = List.map (fun s -> if same_sig parent s then (TObject( (["java";"lang"], "Object"), [])) else s) constraints in
+		{
+			tp_name = name;
+			tp_params = [];
+			tp_constraints = List.map (convert_signature ctx p) constraints;
+		}
 
 let get_type_path ctx ct = match ct with | CTPath p -> p | _ -> assert false
 
 let is_override field =
-  List.exists (function | AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), _ ) }] -> true | _ -> false) field.jf_attributes
+	List.exists (function | AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), _ ) }] -> true | _ -> false) field.jf_attributes
 
 let mk_override field =
-  { field with jf_attributes = ((AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), [] ); ann_elements = [] }]) :: field.jf_attributes) }
+	{ field with jf_attributes = ((AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), [] ); ann_elements = [] }]) :: field.jf_attributes) }
 
 let del_override field =
-  { field with jf_attributes = List.filter (fun a -> not (is_override_attrib a)) field.jf_attributes }
+	{ field with jf_attributes = List.filter (fun a -> not (is_override_attrib a)) field.jf_attributes }
+
+let get_canonical ctx p pack name =
+	(Meta.JavaCanonical, [EConst (String (String.concat "." pack)), p; EConst (String name), p], p)
 
 let convert_java_enum ctx p pe =
-  let meta = ref [Meta.Native, [EConst (String (real_java_path ctx pe.cpath) ), p], p ] in
-  let data = ref [] in
-  List.iter (fun f ->
-    (* if List.mem JEnum f.jf_flags then *)
-    match f.jf_vmsignature with
-    | TObject( path, [] ) when path = pe.cpath && List.mem JStatic f.jf_flags && List.mem JFinal f.jf_flags ->
-      data := { ec_name = f.jf_name; ec_doc = None; ec_meta = []; ec_args = []; ec_pos = p; ec_params = []; ec_type = None; } :: !data;
-    | _ -> ()
-  ) pe.cfields;
-
-  EEnum {
-    d_name = jname_to_hx (snd pe.cpath);
-    d_doc = None;
-    d_params = []; (* enums never have type parameters *)
-    d_meta = !meta;
-    d_flags = [EExtern];
-    d_data = List.rev !data;
-  }
-
-  let convert_java_field ctx p jc field =
-    let p = { p with pfile =  p.pfile ^" (" ^field.jf_name ^")" } in
-    let cff_doc = None in
-    let cff_pos = p in
-    let cff_meta = ref [] in
-    let cff_access = ref [] in
-    let cff_name = match field.jf_name with
-      | "<init>" -> "new"
-      | "<clinit>"-> raise Exit (* __init__ field *)
-      | name when String.length name > 5 ->
-          (match String.sub name 0 5 with
-          | "__hx_" | "this$" -> raise Exit
-          | _ -> name)
-      | name -> name
-    in
-    let jf_constant = ref field.jf_constant in
-    let readonly = ref false in
-
-    List.iter (function
-      | JPublic -> cff_access := APublic :: !cff_access
-      | JPrivate -> raise Exit (* private instances aren't useful on externs *)
-      | JProtected -> cff_access := APrivate :: !cff_access
-      | JStatic -> cff_access := AStatic :: !cff_access
-      | JFinal ->
-        cff_meta := (Meta.Final, [], p) :: !cff_meta;
-        (match field.jf_kind, field.jf_vmsignature, field.jf_constant with
-        | JKField, TObject _, _ ->
-          jf_constant := None
-        | JKField, _, Some _ ->
-          readonly := true;
-          jf_constant := None;
-        | _ -> jf_constant := None)
-      (* | JSynchronized -> cff_meta := (Meta.Synchronized, [], p) :: !cff_meta *)
-      | JVolatile -> cff_meta := (Meta.Volatile, [], p) :: !cff_meta
-      | JTransient -> cff_meta := (Meta.Transient, [], p) :: !cff_meta
-      (* | JVarArgs -> cff_meta := (Meta.VarArgs, [], p) :: !cff_meta *)
-      | _ -> ()
-    ) field.jf_flags;
-
-    List.iter (function
-      | AttrDeprecated when jc.cpath <> (["java";"util"],"Date") -> cff_meta := (Meta.Deprecated, [], p) :: !cff_meta
-      (* TODO: pass anotations as @:meta *)
-      | AttrVisibleAnnotations ann ->
-        List.iter (function
-          | { ann_type = TObject( (["java";"lang"], "Override"), [] ) } ->
-            cff_access := AOverride :: !cff_access
-          | _ -> ()
-        ) ann
-      | _ -> ()
-    ) field.jf_attributes;
-
-    let kind = match field.jf_kind with
-      | JKField when !readonly ->
-        FProp ("default", "null", Some (convert_signature ctx p field.jf_signature), None)
-      | JKField ->
-        FVar (Some (convert_signature ctx p field.jf_signature), None)
-      | JKMethod ->
-        match field.jf_signature with
-        | TMethod (args, ret) ->
-          let old_types = ctx.jtparams in
-          (match ctx.jtparams with
-          | c :: others -> ctx.jtparams <- (c @ field.jf_types) :: others
-          | [] -> ctx.jtparams <- field.jf_types :: []);
-          let i = ref 0 in
-          let args = List.map (fun s ->
-            incr i;
-            "param" ^ string_of_int !i, false, Some(convert_signature ctx p s), None
-          ) args in
-          let t = Option.map_default (convert_signature ctx p) (mk_type_path ctx ([], "Void") []) ret in
-          cff_meta := (Meta.Overload, [], p) :: !cff_meta;
-
-          let types = List.map (function
-            | (name, Some ext, impl) ->
-              {
-                tp_name = name;
-                tp_params = [];
-                tp_constraints = List.map (convert_signature ctx p) (ext :: impl);
-              }
-            | (name, None, impl) ->
-              {
-                tp_name = name;
-                tp_params = [];
-                tp_constraints = List.map (convert_signature ctx p) (impl);
-              }
-          ) field.jf_types in
-          ctx.jtparams <- old_types;
-
-          FFun ({
-            f_params = types;
-            f_args = args;
-            f_type = Some t;
-            f_expr = None
-          })
-        | _ -> error "Method signature was expected" p
-    in
-    let cff_name, cff_meta =
-      if String.get cff_name 0 = '%' then
-        let name = (String.sub cff_name 1 (String.length cff_name - 1)) in
-        "_" ^ name,
-        (Meta.Native, [EConst (String (name) ), cff_pos], cff_pos) :: !cff_meta
-      else
-        cff_name, !cff_meta
-    in
-
-    {
-      cff_name = cff_name;
-      cff_doc = cff_doc;
-      cff_pos = cff_pos;
-      cff_meta = cff_meta;
-      cff_access = !cff_access;
-      cff_kind = kind
-    }
-
-  let rec japply_params params jsig = match params with
-  | [] -> jsig
-  | _ -> match jsig with
-    | TTypeParameter s -> (try
-      List.assoc s params
-    with | Not_found -> jsig)
-    | TObject(p,tl) ->
-      TObject(p, args params tl)
-    | TObjectInner(sl, stll) ->
-      TObjectInner(sl, List.map (fun (s,tl) -> (s, args params tl)) stll)
-    | TArray(s,io) ->
-      TArray(japply_params params s, io)
-    | TMethod(sl, sopt) ->
-      TMethod(List.map (japply_params params) sl, Option.map (japply_params params) sopt)
-    | _ -> jsig
-
-  and args params tl = match params with
-  | [] -> tl
-  | _ -> List.map (function
-    | TAny -> TAny
-    | TType(w,s) -> TType(w,japply_params params s)) tl
-
-  let mk_params jtypes = List.map (fun (s,_,_) -> (s,TTypeParameter s)) jtypes
-
-  let convert_java_class ctx p jc =
-    match List.mem JEnum jc.cflags with
-    | true -> (* is enum *)
-      convert_java_enum ctx p jc
-    | false ->
-      let flags = ref [HExtern] in
-      (* todo: instead of JavaNative, use more specific definitions *)
-      let meta = ref [Meta.JavaNative, [], p; Meta.Native, [EConst (String (real_java_path ctx jc.cpath) ), p], p] in
-
-      let is_interface = ref false in
-      List.iter (fun f -> match f with
-        | JFinal -> meta := (Meta.Final, [], p) :: !meta
-        | JInterface ->
-            is_interface := true;
-            flags := HInterface :: !flags
-        | JAbstract -> meta := (Meta.Abstract, [], p) :: !meta
-        | JAnnotation -> meta := (Meta.Annotation, [], p) :: !meta
-        | _ -> ()
-      ) jc.cflags;
-
-      (match jc.csuper with
-        | TObject( (["java";"lang"], "Object"), _ ) -> ()
-        | TObject( (["haxe";"lang"], "HxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta
-        | _ -> flags := HExtends (get_type_path ctx (convert_signature ctx p jc.csuper)) :: !flags
-      );
-
-      List.iter (fun i ->
-        match i with
-        | TObject ( (["haxe";"lang"], "IHxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta
-        | _ -> flags :=
-          if !is_interface then
-            HExtends (get_type_path ctx (convert_signature ctx p i)) :: !flags
-          else
-            HImplements (get_type_path ctx (convert_signature ctx p i)) :: !flags
-      ) jc.cinterfaces;
-
-      let fields = ref [] in
-      let jfields = ref [] in
-
-      if jc.cpath <> (["java";"lang"], "CharSequence") then
-        List.iter (fun f ->
-          try
-            if !is_interface && List.mem JStatic f.jf_flags then
-              ()
-            else begin
-              fields := convert_java_field ctx p jc f :: !fields;
-              jfields := f :: !jfields
-            end
-          with
-            | Exit -> ()
-        ) (jc.cfields @ jc.cmethods);
-
-      EClass {
-        d_name = jname_to_hx (snd jc.cpath);
-        d_doc = None;
-        d_params = List.map (convert_param ctx p jc.cpath) jc.ctypes;
-        d_meta = !meta;
-        d_flags = !flags;
-        d_data = !fields;
-      }
-
-  let create_ctx com =
-    {
-      jcom = com;
-      jtparams = [];
-    }
-
-  let rec has_type_param = function
-    | TTypeParameter _ -> true
-    | TMethod (lst, opt) -> List.exists has_type_param lst || Option.map_default has_type_param false opt
-    | TArray (s,_) -> has_type_param s
-    | TObjectInner (_, stpl) -> List.exists (fun (_,sigs) -> List.exists has_type_param_arg sigs) stpl
-    | TObject(_, pl) -> List.exists has_type_param_arg pl
-    | _ -> false
-
-  and has_type_param_arg = function | TType(_,s) -> has_type_param s | _ -> false
+	let meta = ref (get_canonical ctx p (fst pe.cpath) (snd pe.cpath) :: [Meta.Native, [EConst (String (real_java_path ctx pe.cpath) ), p], p ]) in
+	let data = ref [] in
+	List.iter (fun f ->
+		(* if List.mem JEnum f.jf_flags then *)
+		match f.jf_vmsignature with
+		| TObject( path, [] ) when path = pe.cpath && List.mem JStatic f.jf_flags && List.mem JFinal f.jf_flags ->
+			data := { ec_name = f.jf_name; ec_doc = None; ec_meta = []; ec_args = []; ec_pos = p; ec_params = []; ec_type = None; } :: !data;
+		| _ -> ()
+	) pe.cfields;
+
+	EEnum {
+		d_name = jname_to_hx (snd pe.cpath);
+		d_doc = None;
+		d_params = []; (* enums never have type parameters *)
+		d_meta = !meta;
+		d_flags = [EExtern];
+		d_data = List.rev !data;
+	}
+
+	let convert_java_field ctx p jc field =
+		let p = { p with pfile =	p.pfile ^" (" ^field.jf_name ^")" } in
+		let cff_doc = None in
+		let cff_pos = p in
+		let cff_meta = ref [] in
+		let cff_access = ref [] in
+		let cff_name = match field.jf_name with
+			| "<init>" -> "new"
+			| "<clinit>"-> raise Exit (* __init__ field *)
+			| name when String.length name > 5 ->
+					(match String.sub name 0 5 with
+					| "__hx_" | "this$" -> raise Exit
+					| _ -> name)
+			| name -> name
+		in
+		let jf_constant = ref field.jf_constant in
+		let readonly = ref false in
+
+		List.iter (function
+			| JPublic -> cff_access := APublic :: !cff_access
+			| JPrivate -> raise Exit (* private instances aren't useful on externs *)
+			| JProtected -> cff_access := APrivate :: !cff_access
+			| JStatic -> cff_access := AStatic :: !cff_access
+			| JFinal ->
+				cff_meta := (Meta.Final, [], p) :: !cff_meta;
+				(match field.jf_kind, field.jf_vmsignature, field.jf_constant with
+				| JKField, TObject _, _ ->
+					jf_constant := None
+				| JKField, _, Some _ ->
+					readonly := true;
+					jf_constant := None;
+				| _ -> jf_constant := None)
+			(* | JSynchronized -> cff_meta := (Meta.Synchronized, [], p) :: !cff_meta *)
+			| JVolatile -> cff_meta := (Meta.Volatile, [], p) :: !cff_meta
+			| JTransient -> cff_meta := (Meta.Transient, [], p) :: !cff_meta
+			(* | JVarArgs -> cff_meta := (Meta.VarArgs, [], p) :: !cff_meta *)
+			| _ -> ()
+		) field.jf_flags;
+
+		List.iter (function
+			| AttrDeprecated when jc.cpath <> (["java";"util"],"Date") -> cff_meta := (Meta.Deprecated, [], p) :: !cff_meta
+			(* TODO: pass anotations as @:meta *)
+			| AttrVisibleAnnotations ann ->
+				List.iter (function
+					| { ann_type = TObject( (["java";"lang"], "Override"), [] ) } ->
+						cff_access := AOverride :: !cff_access
+					| _ -> ()
+				) ann
+			| _ -> ()
+		) field.jf_attributes;
+
+		List.iter (fun jsig ->
+			match convert_signature ctx p jsig with
+				| CTPath path ->
+					cff_meta := (Meta.Throws, [Ast.EConst (Ast.String (path_s (path.tpackage,path.tname))), p],p) :: !cff_meta
+				| _ -> ()
+		) field.jf_throws;
+
+		let kind = match field.jf_kind with
+			| JKField when !readonly ->
+				FProp ("default", "null", Some (convert_signature ctx p field.jf_signature), None)
+			| JKField ->
+				FVar (Some (convert_signature ctx p field.jf_signature), None)
+			| JKMethod ->
+				match field.jf_signature with
+				| TMethod (args, ret) ->
+					let old_types = ctx.jtparams in
+					(match ctx.jtparams with
+					| c :: others -> ctx.jtparams <- (c @ field.jf_types) :: others
+					| [] -> ctx.jtparams <- field.jf_types :: []);
+					let i = ref 0 in
+					let args = List.map (fun s ->
+						incr i;
+						"param" ^ string_of_int !i, false, Some(convert_signature ctx p s), None
+					) args in
+					let t = Option.map_default (convert_signature ctx p) (mk_type_path ctx ([], "Void") []) ret in
+					cff_meta := (Meta.Overload, [], p) :: !cff_meta;
+
+					let types = List.map (function
+						| (name, Some ext, impl) ->
+							{
+								tp_name = name;
+								tp_params = [];
+								tp_constraints = List.map (convert_signature ctx p) (ext :: impl);
+							}
+						| (name, None, impl) ->
+							{
+								tp_name = name;
+								tp_params = [];
+								tp_constraints = List.map (convert_signature ctx p) (impl);
+							}
+					) field.jf_types in
+					ctx.jtparams <- old_types;
+
+					FFun ({
+						f_params = types;
+						f_args = args;
+						f_type = Some t;
+						f_expr = None
+					})
+				| _ -> error "Method signature was expected" p
+		in
+		let cff_name, cff_meta =
+			match String.get cff_name 0 with
+				| '%' ->
+					let name = (String.sub cff_name 1 (String.length cff_name - 1)) in
+					if not (is_haxe_keyword name) then
+						cff_meta := (Meta.Deprecated, [EConst(String(
+							"This static field `_" ^ name ^ "` is deprecated and will be removed in later versions. Please use `" ^ name ^ "` instead")
+						),p], p) :: !cff_meta;
+					"_" ^ name,
+					(Meta.Native, [EConst (String (name) ), cff_pos], cff_pos) :: !cff_meta
+				| _ ->
+					match String.nsplit cff_name "$" with
+						| [ no_dollar ] ->
+							cff_name, !cff_meta
+						| parts ->
+							String.concat "_" parts,
+							(Meta.Native, [EConst (String (cff_name) ), cff_pos], cff_pos) :: !cff_meta
+		in
+		if PMap.mem "java_loader_debug" ctx.jcom.defines then
+			Printf.printf "\t%s%sfield %s : %s\n" (if List.mem AStatic !cff_access then "static " else "") (if List.mem AOverride !cff_access then "override " else "") cff_name (s_sig field.jf_signature);
+
+		{
+			cff_name = cff_name;
+			cff_doc = cff_doc;
+			cff_pos = cff_pos;
+			cff_meta = cff_meta;
+			cff_access = !cff_access;
+			cff_kind = kind
+		}
+
+	let rec japply_params params jsig = match params with
+	| [] -> jsig
+	| _ -> match jsig with
+		| TTypeParameter s -> (try
+			List.assoc s params
+		with | Not_found -> jsig)
+		| TObject(p,tl) ->
+			TObject(p, args params tl)
+		| TObjectInner(sl, stll) ->
+			TObjectInner(sl, List.map (fun (s,tl) -> (s, args params tl)) stll)
+		| TArray(s,io) ->
+			TArray(japply_params params s, io)
+		| TMethod(sl, sopt) ->
+			TMethod(List.map (japply_params params) sl, Option.map (japply_params params) sopt)
+		| _ -> jsig
+
+	and args params tl = match params with
+	| [] -> tl
+	| _ -> List.map (function
+		| TAny -> TAny
+		| TType(w,s) -> TType(w,japply_params params s)) tl
+
+	let mk_params jtypes = List.map (fun (s,_,_) -> (s,TTypeParameter s)) jtypes
+
+	let convert_java_class ctx p jc =
+		match List.mem JEnum jc.cflags with
+		| true -> (* is enum *)
+				[convert_java_enum ctx p jc]
+		| false ->
+			let flags = ref [HExtern] in
+			if PMap.mem "java_loader_debug" ctx.jcom.defines then begin
+				let sup = jc.csuper :: jc.cinterfaces in
+				print_endline ("converting " ^ (if List.mem JAbstract jc.cflags then "abstract " else "") ^ JData.path_s jc.cpath ^ " : " ^ (String.concat ", " (List.map s_sig sup)));
+			end;
+			(* todo: instead of JavaNative, use more specific definitions *)
+			let meta = ref [Meta.JavaNative, [], p; Meta.Native, [EConst (String (real_java_path ctx jc.cpath) ), p], p; get_canonical ctx p (fst jc.cpath) (snd jc.cpath)] in
+			let force_check = Common.defined ctx.jcom Define.ForceLibCheck in
+			if not force_check then
+				meta := (Meta.LibType,[],p) :: !meta;
+
+			let is_interface = ref false in
+			List.iter (fun f -> match f with
+				| JFinal -> meta := (Meta.Final, [], p) :: !meta
+				| JInterface ->
+						is_interface := true;
+						flags := HInterface :: !flags
+				| JAbstract -> meta := (Meta.Abstract, [], p) :: !meta
+				| JAnnotation -> meta := (Meta.Annotation, [], p) :: !meta
+				| _ -> ()
+			) jc.cflags;
+
+			(match jc.csuper with
+				| TObject( (["java";"lang"], "Object"), _ ) -> ()
+				| TObject( (["haxe";"lang"], "HxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta
+				| _ -> flags := HExtends (get_type_path ctx (convert_signature ctx p jc.csuper)) :: !flags
+			);
+
+			List.iter (fun i ->
+				match i with
+				| TObject ( (["haxe";"lang"], "IHxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta
+				| _ -> flags :=
+					if !is_interface then
+						HExtends (get_type_path ctx (convert_signature ctx p i)) :: !flags
+					else
+						HImplements (get_type_path ctx (convert_signature ctx p i)) :: !flags
+			) jc.cinterfaces;
+
+			let fields = ref [] in
+			let jfields = ref [] in
+
+			if jc.cpath <> (["java";"lang"], "CharSequence") then
+				List.iter (fun f ->
+					try
+						if !is_interface && List.mem JStatic f.jf_flags then
+							()
+						else begin
+							fields := convert_java_field ctx p jc f :: !fields;
+							jfields := f :: !jfields
+						end
+					with
+						| Exit -> ()
+				) (jc.cfields @ jc.cmethods);
+
+			(* make sure the throws types are imported correctly *)
+			let imports = List.concat (List.map (fun f ->
+				List.map (fun jsig ->
+					match convert_signature ctx p jsig with
+						| CTPath path ->
+							let pos = { p with pfile = p.pfile ^ " (" ^ f.jf_name ^" @:throws)" } in
+							EImport( List.map (fun s -> s,pos) (path.tpackage @ [path.tname]), INormal )
+						| _ -> assert false
+				) f.jf_throws
+			) jc.cmethods) in
+
+			(EClass {
+				d_name = jname_to_hx (snd jc.cpath);
+				d_doc = None;
+				d_params = List.map (convert_param ctx p jc.cpath) jc.ctypes;
+				d_meta = !meta;
+				d_flags = !flags;
+				d_data = !fields;
+			}) :: imports
+
+	let create_ctx com =
+		{
+			jcom = com;
+			jtparams = [];
+		}
+
+	let rec has_type_param = function
+		| TTypeParameter _ -> true
+		| TMethod (lst, opt) -> List.exists has_type_param lst || Option.map_default has_type_param false opt
+		| TArray (s,_) -> has_type_param s
+		| TObjectInner (_, stpl) -> List.exists (fun (_,sigs) -> List.exists has_type_param_arg sigs) stpl
+		| TObject(_, pl) -> List.exists has_type_param_arg pl
+		| _ -> false
+
+	and has_type_param_arg = function | TType(_,s) -> has_type_param s | _ -> false
 
 let rec japply_params jparams jsig = match jparams with
-  | [] -> jsig
-  | _ ->
-    match jsig with
-    | TObject(path,p) ->
-      TObject(path, List.map (japply_params_tp jparams ) p)
-    | TObjectInner(sl,stargl) ->
-      TObjectInner(sl,List.map (fun (s,targ) -> (s, List.map (japply_params_tp jparams) targ)) stargl)
-    | TArray(jsig,io) ->
-      TArray(japply_params jparams jsig,io)
-    | TMethod(args,ret) ->
-      TMethod(List.map (japply_params jparams ) args, Option.map (japply_params jparams ) ret)
-    | TTypeParameter s -> (try
-      List.assoc s jparams
-    with | Not_found -> jsig)
-    | _ -> jsig
+	| [] -> jsig
+	| _ ->
+		match jsig with
+		| TObject(path,p) ->
+			TObject(path, List.map (japply_params_tp jparams ) p)
+		| TObjectInner(sl,stargl) ->
+			TObjectInner(sl,List.map (fun (s,targ) -> (s, List.map (japply_params_tp jparams) targ)) stargl)
+		| TArray(jsig,io) ->
+			TArray(japply_params jparams jsig,io)
+		| TMethod(args,ret) ->
+			TMethod(List.map (japply_params jparams ) args, Option.map (japply_params jparams ) ret)
+		| TTypeParameter s -> (try
+			List.assoc s jparams
+		with | Not_found -> jsig)
+		| _ -> jsig
 
 
 and japply_params_tp jparams jtype_argument = match jtype_argument with
-  | TAny -> TAny
-  | TType(w,jsig) -> TType(w,japply_params jparams jsig)
+	| TAny -> TAny
+	| TType(w,jsig) -> TType(w,japply_params jparams jsig)
 
 let mk_jparams jtypes params = match jtypes, params with
-  | [], [] -> []
-  | _, [] -> List.map (fun (s,_,_) -> s, TObject( (["java";"lang"], "Object"), [] ) ) jtypes
-  | _ -> List.map2 (fun (s,_,_) jt -> match jt with
-    | TAny -> s, TObject((["java";"lang"],"Object"),[])
-    | TType(_,jsig) -> s, jsig) jtypes params
+	| [], [] -> []
+	| _, [] -> List.map (fun (s,_,_) -> s, TObject( (["java";"lang"], "Object"), [] ) ) jtypes
+	| _ -> List.map2 (fun (s,_,_) jt -> match jt with
+		| TAny -> s, TObject((["java";"lang"],"Object"),[])
+		| TType(_,jsig) -> s, jsig) jtypes params
 
 let rec compatible_signature_arg ?arg_test f1 f2 =
-  let arg_test = match arg_test with
-    | None -> (fun _ _ -> true)
-    | Some a -> a
-  in
-  if f1 = f2 then
-    true
-  else match f1, f2 with
-  | TObject(p,a), TObject(p2,a2) -> p = p2 && arg_test a a2
-  | TObjectInner(sl, stal), TObjectInner(sl2, stal2) -> sl = sl2 && List.map fst stal = List.map fst stal2
-  | TArray(s,_) , TArray(s2,_) -> compatible_signature_arg s s2
-  | TTypeParameter t1 , TTypeParameter t2 -> t1 = t2
-  | _ -> false
+	let arg_test = match arg_test with
+		| None -> (fun _ _ -> true)
+		| Some a -> a
+	in
+	if f1 = f2 then
+		true
+	else match f1, f2 with
+	| TObject(p,a), TObject(p2,a2) -> p = p2 && arg_test a a2
+	| TObjectInner(sl, stal), TObjectInner(sl2, stal2) -> sl = sl2 && List.map fst stal = List.map fst stal2
+	| TArray(s,_) , TArray(s2,_) -> compatible_signature_arg s s2
+	| TTypeParameter t1 , TTypeParameter t2 -> t1 = t2
+	| _ -> false
 
 let rec compatible_param p1 p2 = match p1, p2 with
-  | TType (_,s1), TType(_,s2) -> compatible_signature_arg ~arg_test:compatible_tparams s1 s2
-  | TAny, TType(_, TObject( (["java";"lang"],"Object"), _ )) -> true
-  | TType(_, TObject( (["java";"lang"],"Object"), _ )), TAny -> true
-  | _ -> false
+	| TType (_,s1), TType(_,s2) -> compatible_signature_arg ~arg_test:compatible_tparams s1 s2
+	| TAny, TType(_, TObject( (["java";"lang"],"Object"), _ )) -> true
+	| TType(_, TObject( (["java";"lang"],"Object"), _ )), TAny -> true
+	| _ -> false
 
 and compatible_tparams p1 p2 = try match p1, p2 with
-  | [], [] -> true
-  | _, [] ->
-    let p2 = List.map (fun _ -> TAny) p1 in
-    List.for_all2 compatible_param p1 p2
-  | [], _ ->
-    let p1 = List.map (fun _ -> TAny) p2 in
-    List.for_all2 compatible_param p1 p2
-  | _, _ ->
-    List.for_all2 compatible_param p1 p2
-  with | Invalid_argument("List.for_all2") -> false
+	| [], [] -> true
+	| _, [] ->
+		let p2 = List.map (fun _ -> TAny) p1 in
+		List.for_all2 compatible_param p1 p2
+	| [], _ ->
+		let p1 = List.map (fun _ -> TAny) p2 in
+		List.for_all2 compatible_param p1 p2
+	| _, _ ->
+		List.for_all2 compatible_param p1 p2
+	with | Invalid_argument("List.for_all2") -> false
 
 let get_adapted_sig f f2 = match f.jf_types with
-  | [] ->
-    f.jf_signature
-  | _ ->
-    let jparams = mk_jparams f.jf_types (List.map (fun (s,_,_) -> TType(WNone, TTypeParameter s)) f2.jf_types) in
-    japply_params jparams f.jf_signature
+	| [] ->
+		f.jf_signature
+	| _ ->
+		let jparams = mk_jparams f.jf_types (List.map (fun (s,_,_) -> TType(WNone, TTypeParameter s)) f2.jf_types) in
+		japply_params jparams f.jf_signature
 
 let compatible_methods f1 f2 =
-  if List.length f1.jf_types <> List.length f2.jf_types then
-    false
-  else match (get_adapted_sig f1 f2), f2.jf_signature with
-  | TMethod(a1,_), TMethod(a2,_) when List.length a1 = List.length a2 ->
-    List.for_all2 compatible_signature_arg a1 a2
-  | _ -> false
+	if List.length f1.jf_types <> List.length f2.jf_types then
+		false
+	else match (get_adapted_sig f1 f2), f2.jf_signature with
+	| TMethod(a1,_), TMethod(a2,_) when List.length a1 = List.length a2 ->
+		List.for_all2 compatible_signature_arg a1 a2
+	| _ -> false
 
 let jcl_from_jsig com jsig =
-  let path, params = match jsig with
-  | TObject(path, params) ->
-    path,params
-  | TObjectInner(sl, stll) ->
-    let last_params = ref [] in
-    let real_path = sl, String.concat "$" (List.map (fun (s,p) -> last_params := p; s) stll) in
-    real_path, !last_params
-  | _ -> raise Not_found
-  in
-  match lookup_jclass com path with
-  | None -> raise Not_found
-  | Some(c,_,_) -> c,params
+	let path, params = match jsig with
+	| TObject(path, params) ->
+		path,params
+	| TObjectInner(sl, stll) ->
+		let last_params = ref [] in
+		let real_path = sl, String.concat "$" (List.map (fun (s,p) -> last_params := p; s) stll) in
+		real_path, !last_params
+	| _ -> raise Not_found
+	in
+	match lookup_jclass com path with
+	| None -> raise Not_found
+	| Some(c,_,_) -> c,params
 
 let jclass_with_params com cls params = try
-  match cls.ctypes with
-  | [] -> cls
-  | _ ->
-    let jparams = mk_jparams cls.ctypes params in
-    { cls with
-      cfields = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cfields;
-      cmethods = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cmethods;
-      csuper = japply_params jparams cls.csuper;
-      cinterfaces = List.map (japply_params jparams) cls.cinterfaces;
-    }
-  with Invalid_argument("List.map2") ->
-    if com.verbose then prerr_endline ("Differing parameters for class: " ^ path_s cls.cpath);
-    cls
+	match cls.ctypes with
+	| [] -> cls
+	| _ ->
+		let jparams = mk_jparams cls.ctypes params in
+		{ cls with
+			cfields = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cfields;
+			cmethods = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cmethods;
+			csuper = japply_params jparams cls.csuper;
+			cinterfaces = List.map (japply_params jparams) cls.cinterfaces;
+		}
+	with Invalid_argument("List.map2") ->
+		if com.verbose then prerr_endline ("Differing parameters for class: " ^ path_s cls.cpath);
+		cls
 
 let is_object = function | TObject( (["java";"lang"], "Object"), [] ) -> true | _ -> false
 
 let is_tobject = function | TObject _ | TObjectInner _ -> true | _ -> false
 
 let simplify_args args =
-  if List.for_all (function | TAny -> true | _ -> false) args then [] else args
+	if List.for_all (function | TAny -> true | _ -> false) args then [] else args
 
 let compare_type com s1 s2 =
-  if s1 = s2 then
-    0
-  else if not (is_tobject s1) then
-    if is_tobject s2 then (* Dynamic *)
-      1
-    else if compatible_signature_arg s1 s2 then
-      0
-    else
-      raise Exit
-  else if not (is_tobject s2) then
-    -1
-  else begin
-    let rec loop ?(first_error=true) s1 s2 : bool =
-      if is_object s1 then
-        s1 = s2
-      else if compatible_signature_arg s1 s2 then begin
-        let p1, p2 = match s1, s2 with
-        | TObject(_, p1), TObject(_,p2) ->
-          p1, p2
-        | TObjectInner(_, npl1), TObjectInner(_, npl2) ->
-          snd (List.hd (List.rev npl1)), snd (List.hd (List.rev npl2))
-        | _ -> assert false (* not tobject *)
-        in
-        let p1, p2 = simplify_args p1, simplify_args p2 in
-        let lp1 = List.length p1 in
-        let lp2 = List.length p2 in
-        if lp1 > lp2 then
-          true
-        else if lp2 > lp1 then
-          false
-        else begin
-          (* if compatible tparams, it's fine *)
-          if not (compatible_tparams p1 p2) then
-            raise Exit; (* meaning: found, but incompatible type parameters *)
-          true
-        end
-      end else try
-        let c, p = jcl_from_jsig com s1 in
-        let jparams = mk_jparams c.ctypes p in
-        let super = japply_params jparams c.csuper in
-        let implements = List.map (japply_params jparams) c.cinterfaces in
-        loop ~first_error:first_error super s2 || List.exists (fun super -> loop ~first_error:first_error super s2) implements
-      with | Not_found ->
-        if com.verbose then begin
-          prerr_endline ("-java-lib: The type " ^ (s_sig s1) ^ " is referred but was not found. Compilation may not occur correctly.");
-          prerr_endline "Did you forget to include a needed lib?"
-        end;
-        if first_error then
-          not (loop ~first_error:false s2 s1)
-        else
-          false
-    in
-    if loop s1 s2 then
-      if loop s2 s1 then
-        0
-      else
-        1
-    else
-      if loop s2 s1 then
-        -1
-      else
-        -2
-  end
+	if s1 = s2 then
+		0
+	else if not (is_tobject s1) then
+		if is_tobject s2 then (* Dynamic *)
+			1
+		else if compatible_signature_arg s1 s2 then
+			0
+		else
+			raise Exit
+	else if not (is_tobject s2) then
+		-1
+	else begin
+		let rec loop ?(first_error=true) s1 s2 : bool =
+			if is_object s1 then
+				s1 = s2
+			else if compatible_signature_arg s1 s2 then begin
+				let p1, p2 = match s1, s2 with
+				| TObject(_, p1), TObject(_,p2) ->
+					p1, p2
+				| TObjectInner(_, npl1), TObjectInner(_, npl2) ->
+					snd (List.hd (List.rev npl1)), snd (List.hd (List.rev npl2))
+				| _ -> assert false (* not tobject *)
+				in
+				let p1, p2 = simplify_args p1, simplify_args p2 in
+				let lp1 = List.length p1 in
+				let lp2 = List.length p2 in
+				if lp1 > lp2 then
+					true
+				else if lp2 > lp1 then
+					false
+				else begin
+					(* if compatible tparams, it's fine *)
+					if not (compatible_tparams p1 p2) then
+						raise Exit; (* meaning: found, but incompatible type parameters *)
+					true
+				end
+			end else try
+				let c, p = jcl_from_jsig com s1 in
+				let jparams = mk_jparams c.ctypes p in
+				let super = japply_params jparams c.csuper in
+				let implements = List.map (japply_params jparams) c.cinterfaces in
+				loop ~first_error:first_error super s2 || List.exists (fun super -> loop ~first_error:first_error super s2) implements
+			with | Not_found ->
+				prerr_endline ("-java-lib: The type " ^ (s_sig s1) ^ " is referred but was not found. Compilation may not occur correctly.");
+				prerr_endline "Did you forget to include a needed lib?";
+				if first_error then
+					not (loop ~first_error:false s2 s1)
+				else
+					false
+		in
+		if loop s1 s2 then
+			if loop s2 s1 then
+				0
+			else
+				1
+		else
+			if loop s2 s1 then
+				-1
+			else
+				-2
+	end
 
 (* given a list of same overload functions, choose the best (or none) *)
 let select_best com flist =
-  let rec loop cur_best = function
-    | [] ->
-      Some cur_best
-    | f :: flist -> match get_adapted_sig f cur_best, cur_best.jf_signature with
-      | TMethod(_,Some r), TMethod(_, Some r2) -> (try
-        match compare_type com r r2 with
-        | 0 -> (* same type - select any of them *)
-          loop cur_best flist
-        | 1 ->
-          loop f flist
-        | -1 ->
-          loop cur_best flist
-        | -2 -> (* error - no type is compatible *)
-          if com.verbose then prerr_endline (f.jf_name ^ ": The types " ^ (s_sig r) ^ " and " ^ (s_sig r2) ^ " are incompatible");
-          (* bet that the current best has "beaten" other types *)
-          loop cur_best flist
-        | _ -> assert false
-      with | Exit -> (* incompatible type parameters *)
-        (* error mode *)
-        if com.verbose then prerr_endline (f.jf_name ^ ": Incompatible argument return signatures: " ^ (s_sig r) ^ " and " ^ (s_sig r2));
-        None)
-      | TMethod _, _ -> (* select the method *)
-        loop f flist
-      | _ ->
-        loop cur_best flist
-  in
-  match loop (List.hd flist) (List.tl flist) with
-  | Some f ->
-    Some f
-  | None -> match List.filter (fun f -> not (is_override f)) flist with
-    (* error mode; take off all override methods *)
-    | [] -> None
-    | f :: [] -> Some f
-    | f :: flist -> Some f (* pick one *)
+	let rec loop cur_best = function
+		| [] ->
+			Some cur_best
+		| f :: flist -> match get_adapted_sig f cur_best, cur_best.jf_signature with
+			| TMethod(_,Some r), TMethod(_, Some r2) -> (try
+				match compare_type com r r2 with
+				| 0 -> (* same type - select any of them *)
+					loop cur_best flist
+				| 1 ->
+					loop f flist
+				| -1 ->
+					loop cur_best flist
+				| -2 -> (* error - no type is compatible *)
+					if com.verbose then prerr_endline (f.jf_name ^ ": The types " ^ (s_sig r) ^ " and " ^ (s_sig r2) ^ " are incompatible");
+					(* bet that the current best has "beaten" other types *)
+					loop cur_best flist
+				| _ -> assert false
+			with | Exit -> (* incompatible type parameters *)
+				(* error mode *)
+				if com.verbose then prerr_endline (f.jf_name ^ ": Incompatible argument return signatures: " ^ (s_sig r) ^ " and " ^ (s_sig r2));
+				None)
+			| TMethod _, _ -> (* select the method *)
+				loop f flist
+			| _ ->
+				loop cur_best flist
+	in
+	match loop (List.hd flist) (List.tl flist) with
+	| Some f ->
+		Some f
+	| None -> match List.filter (fun f -> not (is_override f)) flist with
+		(* error mode; take off all override methods *)
+		| [] -> None
+		| f :: [] -> Some f
+		| f :: flist -> Some f (* pick one *)
+
+(**** begin normalize_jclass helpers ****)
+
+let fix_overrides_jclass com cls =
+	let force_check = Common.defined com Define.ForceLibCheck in
+	let methods = if force_check then List.map (fun f -> del_override f) cls.cmethods else cls.cmethods in
+	let cmethods = methods in
+	let super_fields = [] in
+	let super_methods = [] in
+	let nonstatics = List.filter (fun f -> not (List.mem JStatic f.jf_flags)) (cls.cfields @ cls.cmethods) in
+
+	let is_pub = fun f -> List.exists (function | JPublic | JProtected -> true | _ -> false) f.jf_flags in
+	let cmethods, super_fields = if not (List.mem JInterface cls.cflags) then
+		List.filter is_pub cmethods,
+		List.filter is_pub super_fields
+	else
+		cmethods,super_fields
+	in
+
+	let rec loop cls super_methods super_fields cmethods nonstatics = try
+		match cls.csuper with
+		| TObject((["java";"lang"],"Object"),_) ->
+				super_methods,super_fields,cmethods,nonstatics
+		| _ ->
+			let cls, params = jcl_from_jsig com cls.csuper in
+			let cls = jclass_with_params com cls params in
+			let nonstatics = (List.filter (fun f -> (List.mem JStatic f.jf_flags)) (cls.cfields @ cls.cmethods)) @ nonstatics in
+			let super_methods = cls.cmethods @ super_methods in
+			let super_fields = cls.cfields @ super_fields in
+			let cmethods = if force_check then begin
+				let overriden = ref [] in
+				let cmethods = List.map (fun jm ->
+					(* TODO rewrite/standardize empty spaces *)
+					if not (is_override jm) && not (List.mem JStatic jm.jf_flags) && List.exists (fun msup ->
+						let ret = msup.jf_name = jm.jf_name && not(List.mem JStatic msup.jf_flags) && compatible_methods msup jm in
+						if ret then begin
+							let f = mk_override msup in
+							overriden := { f with jf_flags = jm.jf_flags } :: !overriden
+						end;
+						ret
+					) cls.cmethods then
+						mk_override jm
+					else
+						jm
+				) cmethods in
+				!overriden @ cmethods
+			end else
+				cmethods
+			in
+			loop cls super_methods super_fields cmethods nonstatics
+		with | Not_found ->
+			super_methods,super_fields,cmethods,nonstatics
+	in
+	loop cls super_methods super_fields cmethods nonstatics
 
 let normalize_jclass com cls =
-  (* search static / non-static name clash *)
-  let nonstatics = ref [] in
-  List.iter (fun f ->
-    if not(List.mem JStatic f.jf_flags) then nonstatics := f :: !nonstatics
-  ) (cls.cfields @ cls.cmethods);
-  (* we won't be able to deal correctly with field's type parameters *)
-  (* since java sometimes overrides / implements crude (ie no type parameters) versions *)
-  (* and interchanges between them *)
-  (* let methods = List.map (fun f -> let f = del_override f in  if f.jf_types <> [] then { f with jf_types = []; jf_signature = f.jf_vmsignature } else f ) cls.cmethods in *)
-  (* let pth = path_s cls.cpath in *)
-  let methods = List.map (fun f -> del_override f ) cls.cmethods in
-  (* take off duplicate overload signature class fields from current class *)
-  let cmethods = ref methods in
-  let all_methods = ref methods in
-  let all_fields = ref cls.cfields in
-  let super_fields = ref [] in
-  let super_methods = ref [] in
-  (* fix overrides *)
-  let rec loop cls = try
-    match cls.csuper with
-    | TObject((["java";"lang"],"Object"),_) -> ()
-    | _ ->
-      let cls, params = jcl_from_jsig com cls.csuper in
-      let cls = jclass_with_params com cls params in
-      List.iter (fun f -> if not (List.mem JStatic f.jf_flags) then nonstatics := f :: !nonstatics) (cls.cfields @ cls.cmethods);
-      super_methods := cls.cmethods @ !super_methods;
-      all_methods := cls.cmethods @ !all_methods;
-      all_fields := cls.cfields @ !all_fields;
-      super_fields := cls.cfields @ !super_fields;
-      let overriden = ref [] in
-      cmethods := List.map (fun jm ->
-        (* TODO rewrite/standardize empty spaces *)
-        if not (is_override jm) && not(List.mem JStatic jm.jf_flags) && List.exists (fun msup ->
-          let ret = msup.jf_name = jm.jf_name && not(List.mem JStatic msup.jf_flags) && compatible_methods msup jm in
-          if ret then begin
-            let f = mk_override msup in
-            overriden := { f with jf_flags = jm.jf_flags } :: !overriden
-          end;
-          ret
-        ) cls.cmethods then
-          mk_override jm
-        else
-          jm
-      ) !cmethods;
-      cmethods := !overriden @ !cmethods;
-      loop cls
-    with | Not_found -> ()
-  in
-  if not (List.mem JInterface cls.cflags) then begin
-    cmethods := List.filter (fun f -> List.exists (function | JPublic | JProtected -> true | _ -> false) f.jf_flags) !cmethods;
-    all_fields := List.filter (fun f -> List.exists (function | JPublic | JProtected -> true | _ -> false) f.jf_flags) !all_fields;
-    super_fields := List.filter (fun f -> List.exists (function | JPublic | JProtected -> true | _ -> false) f.jf_flags) !super_fields;
-  end;
-  loop cls;
-  (* look for interfaces and add missing implementations (may happen on abstracts or by vmsig differences *)
-  let added_interface_fields = ref [] in
-  let rec loop_interface abstract cls iface = try
-    match iface with
-      | TObject ((["java";"lang"],"Object"), _) -> ()
-      | TObject (path,_) when path = cls.cpath -> ()
-      | _ ->
-        let cif, params = jcl_from_jsig com iface in
-        let cif = jclass_with_params com cif params in
-        List.iter (fun jf ->
-          if not(List.mem JStatic jf.jf_flags) && not (List.exists (fun jf2 -> jf.jf_name = jf2.jf_name && not (List.mem JStatic jf2.jf_flags) && jf.jf_signature = jf2.jf_signature) !all_methods) then begin
-            let jf = if abstract then del_override jf else jf in
-            let jf = { jf with jf_flags = JPublic :: jf.jf_flags } in (* interfaces implementations are always public *)
-
-            added_interface_fields := jf :: !added_interface_fields;
-            cmethods := jf :: !cmethods;
-            all_methods := jf :: !all_methods;
-            nonstatics := jf :: !nonstatics;
-          end
-        ) cif.cmethods;
-        List.iter (loop_interface abstract cif) cif.cinterfaces;
-    with Not_found -> ()
-  in
-  (* another pass: *)
-  (* if List.mem JAbstract cls.cflags then List.iter loop_interface cls.cinterfaces; *)
-  (* if not (List.mem JInterface cls.cflags) then *)
-  List.iter (loop_interface (List.mem JAbstract cls.cflags) cls) cls.cinterfaces;
-  (* for each added field in the interface, lookup in super_methods possible methods to include *)
-  (* so we can choose the better method still *)
-
-  List.iter (fun im ->
-    let f = List.find_all (fun jf -> jf.jf_name = im.jf_name && compatible_methods jf im) !super_methods in
-    let f = List.map mk_override f in
-    cmethods := f @ !cmethods
-  ) !added_interface_fields;
-  (* take off equals, hashCode and toString from interface *)
-  if List.mem JInterface cls.cflags then cmethods := List.filter (fun jf -> match jf.jf_name, jf.jf_vmsignature with
-      | "equals", TMethod([TObject( (["java";"lang"],"Object"), _)],_)
-      | "hashCode", TMethod([], _)
-      | "toString", TMethod([], _) -> false
-      | _ -> true
-  ) !cmethods;
-  (* change field name to not collide with haxe keywords *)
-  let map_field f =
-    let change = match f.jf_name with
-    | "callback" | "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true
-    | _ when List.mem JStatic f.jf_flags && List.exists (fun f2 -> f.jf_name = f2.jf_name) !nonstatics -> true
-    | _ -> false
-    in
-    if change then
-      { f with jf_name = "%" ^ f.jf_name }
-    else
-      f
-  in
-  (* change static fields that have the same name as methods *)
-  let cfields = List.map map_field cls.cfields in
-  let cmethods = List.map map_field !cmethods in
-  (* take off variable fields that have the same name as methods *)
-  (* and take off variables that already have been declared *)
-  let filter_field f f2 = f != f2 && (List.mem JStatic f.jf_flags = List.mem JStatic f2.jf_flags) && f.jf_name = f2.jf_name && f2.jf_kind <> f.jf_kind in
-  let cfields = List.filter (fun f ->
-    if List.mem JStatic f.jf_flags then
-      not (List.exists (filter_field f) cmethods)
-    else
-      not (List.exists (filter_field f) !nonstatics) && not (List.exists (fun f2 -> f != f2 && f.jf_name = f2.jf_name && not (List.mem JStatic f2.jf_flags)) !all_fields) ) cfields
-  in
-  (* now filter any method that clashes with a field - on a superclass *)
-  let cmethods = List.filter (fun f ->
-    if List.mem JStatic f.jf_flags then
-      true
-    else
-      not (List.exists (filter_field f) !super_fields) ) cmethods
-  in
-  (* removing duplicate fields. They are there because of return type covariance in Java *)
-  (* Also, if a method overrides a previous definition, and changes a type parameters' variance, *)
-  (* we will take it off *)
-  (* this means that some rare codes will never compile on Haxe, but unless Haxe adds variance support *)
-  (* I can't see how this can be any different *)
-  let rec loop acc = function
-    | [] -> acc
-    | f :: cmeths ->
-      match List.partition (fun f2 -> f.jf_name = f2.jf_name && compatible_methods f f2) cmeths with
-      | [], cmeths ->
-        loop (f :: acc) cmeths
-      | flist, cmeths -> match select_best com (f :: flist) with
-        | None ->
-          loop acc cmeths
-        | Some f ->
-          loop (f :: acc) cmeths
-  in
-  (* last pass: take off all cfields that are internal / private (they won't be accessible anyway) *)
-  let cfields = List.filter(fun f -> List.exists (fun f -> f = JPublic || f = JProtected) f.jf_flags) cfields in
-  let cmethods = loop [] cmethods in
-  { cls with cfields = cfields; cmethods = cmethods }
-
-let rec get_classes_dir pack dir ret =
-  Array.iter (fun f -> match (Unix.stat (dir ^"/"^ f)).st_kind with
-    | S_DIR ->
-        get_classes_dir (pack @ [f]) (dir ^"/"^ f) ret
-    | _ when (String.sub (String.uncapitalize f) (String.length f - 6) 6) = ".class" ->
-        let path = jpath_to_hx (pack,f) in
-        ret := path :: !ret;
-    | _ -> ()
-  ) (Sys.readdir dir)
+	(* after adding the noCheck metadata, this option will annotate what changes were needed *)
+	(* and that are now deprecated *)
+	let force_check = Common.defined com Define.ForceLibCheck in
+	(* fix overrides *)
+	let super_methods, super_fields, cmethods, nonstatics = fix_overrides_jclass com cls in
+	let all_methods = cmethods @ super_methods in
+
+	(* look for interfaces and add missing implementations (may happen on abstracts or by vmsig differences *)
+	(* (libType): even with libType enabled, we need to add these missing fields - otherwise we won't be able to use them from Haxe *)
+	let added_interface_fields = ref [] in
+	let rec loop_interface abstract cls iface = try
+		match iface with
+			| TObject ((["java";"lang"],"Object"), _) -> ()
+			| TObject (path,_) when path = cls.cpath -> ()
+			| _ ->
+				let cif, params = jcl_from_jsig com iface in
+				let cif = jclass_with_params com cif params in
+				List.iter (fun jf ->
+					if not(List.mem JStatic jf.jf_flags) && not (List.exists (fun jf2 -> jf.jf_name = jf2.jf_name && not (List.mem JStatic jf2.jf_flags) && jf.jf_signature = jf2.jf_signature) all_methods) then begin
+						let jf = if abstract && force_check then del_override jf else jf in
+						let jf = { jf with jf_flags = JPublic :: jf.jf_flags } in (* interfaces implementations are always public *)
+
+						added_interface_fields := jf :: !added_interface_fields;
+					end
+				) cif.cmethods;
+				(* we don't need to loop again in the interface unless we are in an abstract class, since these interfaces are already normalized *)
+				if abstract then List.iter (loop_interface abstract cif) cif.cinterfaces;
+		with Not_found -> ()
+	in
+	List.iter (loop_interface (List.mem JAbstract cls.cflags) cls) cls.cinterfaces;
+	let nonstatics = !added_interface_fields @ nonstatics in
+	let cmethods = !added_interface_fields @ cmethods in
+
+	(* for each added field in the interface, lookup in super_methods possible methods to include *)
+	(* so we can choose the better method still *)
+	let cmethods = if not force_check then
+		cmethods
+	else
+		List.fold_left (fun cmethods im ->
+			(* see if any of the added_interface_fields need to be declared as override *)
+			let f = List.find_all (fun jf -> jf.jf_name = im.jf_name && compatible_methods jf im) super_methods in
+			let f = List.map mk_override f in
+			f @ cmethods
+		) cmethods !added_interface_fields;
+	in
+
+	(* take off equals, hashCode and toString from interface *)
+	let cmethods = if List.mem JInterface cls.cflags then List.filter (fun jf -> match jf.jf_name, jf.jf_vmsignature with
+			| "equals", TMethod([TObject( (["java";"lang"],"Object"), _)],_)
+			| "hashCode", TMethod([], _)
+			| "toString", TMethod([], _) -> false
+			| _ -> true
+	) cmethods
+	else
+		cmethods
+	in
+
+	(* change field name to not collide with haxe keywords and with static/non-static members *)
+	let fold_field acc f =
+		let change, both = match f.jf_name with
+		| _ when List.mem JStatic f.jf_flags && List.exists (fun f2 -> f.jf_name = f2.jf_name) nonstatics -> true, true
+		| _ -> is_haxe_keyword f.jf_name, false
+		in
+		let f2 = if change then
+				{ f with jf_name = "%" ^ f.jf_name }
+			else
+				f
+		in
+		if both then f :: f2 :: acc else f2 :: acc
+	in
+
+	(* change static fields that have the same name as methods *)
+	let cfields = List.fold_left fold_field [] cls.cfields in
+	let cmethods = List.fold_left fold_field [] cmethods in
+	(* take off variable fields that have the same name as methods *)
+	(* and take off variables that already have been declared *)
+	let filter_field f f2 = f != f2 && (List.mem JStatic f.jf_flags = List.mem JStatic f2.jf_flags) && f.jf_name = f2.jf_name && f2.jf_kind <> f.jf_kind in
+	let cfields = List.filter (fun f ->
+		if List.mem JStatic f.jf_flags then
+			not (List.exists (filter_field f) cmethods)
+		else
+			not (List.exists (filter_field f) nonstatics) && not (List.exists (fun f2 -> f != f2 && f.jf_name = f2.jf_name && not (List.mem JStatic f2.jf_flags)) super_fields) ) cfields
+	in
+	(* now filter any method that clashes with a field - on a superclass *)
+	let cmethods = if force_check then List.filter (fun f ->
+		if List.mem JStatic f.jf_flags then
+			true
+		else
+			not (List.exists (filter_field f) super_fields) ) cmethods
+	else
+		cmethods
+	in
+	(* removing duplicate fields. They are there because of return type covariance in Java *)
+	(* Also, if a method overrides a previous definition, and changes a type parameters' variance, *)
+	(* we will take it off *)
+	(* this means that some rare codes will never compile on Haxe, but unless Haxe adds variance support *)
+	(* I can't see how this can be any different *)
+	let rec loop acc = function
+		| [] -> acc
+		| f :: cmeths ->
+			match List.partition (fun f2 -> f.jf_name = f2.jf_name && compatible_methods f f2) cmeths with
+			| [], cmeths ->
+				loop (f :: acc) cmeths
+			| flist, cmeths -> match select_best com (f :: flist) with
+				| None ->
+					loop acc cmeths
+				| Some f ->
+					loop (f :: acc) cmeths
+	in
+	(* last pass: take off all cfields that are internal / private (they won't be accessible anyway) *)
+	let cfields = List.filter(fun f -> List.exists (fun f -> f = JPublic || f = JProtected) f.jf_flags) cfields in
+	let cmethods = loop [] cmethods in
+	{ cls with cfields = cfields; cmethods = cmethods }
+
+(**** end normalize_jclass helpers ****)
 
 let get_classes_zip zip =
-  let ret = ref [] in
-  List.iter (function
-    | { Zip.is_directory = false; Zip.filename = f } when (String.sub (String.uncapitalize f) (String.length f - 6) 6) = ".class" ->
-        (match List.rev (String.nsplit f "/") with
-        | clsname :: pack ->
-            let path = jpath_to_hx (List.rev pack, clsname) in
-            ret := path :: !ret
-        | _ ->
-            ret := ([], jname_to_hx f) :: !ret)
-    | _ -> ()
-  ) (Zip.entries zip);
-  !ret
+	let ret = ref [] in
+	List.iter (function
+		| { Zip.is_directory = false; Zip.filename = f } when (String.sub (String.uncapitalize f) (String.length f - 6) 6) = ".class" && not (String.exists f "$") ->
+				(match List.rev (String.nsplit f "/") with
+				| clsname :: pack ->
+					if not (String.contains clsname '$') then begin
+						let path = jpath_to_hx (List.rev pack, String.sub clsname 0 (String.length clsname - 6)) in
+						ret := path :: !ret
+					end
+				| _ ->
+						ret := ([], jname_to_hx f) :: !ret)
+		| _ -> ()
+	) (Zip.entries zip);
+	!ret
 
 let add_java_lib com file std =
-  let file = if Sys.file_exists file then
+	let file = if Sys.file_exists file then
 		file
 	else try Common.find_file com file with
-    | Not_found -> try Common.find_file com (file ^ ".jar") with
-    | Not_found ->
-      failwith ("Java lib " ^ file ^ " not found")
-  in
-  let hxpack_to_jpack = Hashtbl.create 16 in
-  let get_raw_class, close, list_all_files =
-    (* check if it is a directory or jar file *)
-    match (Unix.stat file).st_kind with
-    | S_DIR -> (* open classes directly from directory *)
-      let rec iter_files pack dir path = try
-        let file = Unix.readdir dir in
-        if String.ends_with file ".class" then
-          let file = String.sub file 0 (String.length file - 6) in
-          Hashtbl.add hxpack_to_jpack (jpath_to_hx(pack,file)) (pack,file)
-        else if (Unix.stat file).st_kind = S_DIR then
-          let path = path ^"/"^ file in
-          let pack = pack @ [file] in
-          iter_files (pack @ [file]) (Unix.opendir path) path
-      with | End_of_file | Unix.Unix_error _ ->
-        Unix.closedir dir
-      in
-      iter_files [] (Unix.opendir file) file;
-
-      (fun (pack, name) ->
-        (* let pack, name = hxpath_to_j (pack,name) in *)
-        let real_path = file ^ "/" ^ (String.concat "/" pack) ^ "/" ^ (name ^ ".class") in
-        try
-          let data = Std.input_file ~bin:true real_path in
-          Some(JReader.parse_class (IO.input_string data), real_path, real_path)
-        with
-          | _ -> None), (fun () -> ()), (fun () -> let ret = ref [] in get_classes_dir [] file ret; !ret)
-    | _ -> (* open zip file *)
-      let closed = ref false in
-      let zip = ref (Zip.open_in file) in
-      let check_open () =
-        if !closed then begin
-          prerr_endline ("JAR file " ^ file ^ " already closed"); (* if this happens, find when *)
-          zip := Zip.open_in file;
-          closed := false
-        end
-      in
-      List.iter (function
-        | { Zip.is_directory = false; Zip.filename = filename } when String.ends_with filename ".class" ->
-          let pack = String.nsplit filename "/" in
-          (match List.rev pack with
-            | [] -> ()
-            | name :: pack ->
-              let name = String.sub name 0 (String.length name - 6) in
-              let pack = List.rev pack in
-              Hashtbl.add hxpack_to_jpack (jpath_to_hx (pack,name)) (pack,name))
-        | _ -> ()
-      ) (Zip.entries !zip);
-      (fun (pack, name) ->
-        (* let pack, name = hxpath_to_j (pack,name) in *)
-        check_open();
-        try
-          let location = (String.concat "/" (pack @ [name]) ^ ".class") in
-          let entry = Zip.find_entry !zip location in
-          let data = Zip.read_entry !zip entry in
-          Some(JReader.parse_class (IO.input_string data), file, file ^ "@" ^ location)
-        with
-          | Not_found ->
-            None),
-      (fun () -> if not !closed then begin closed := true; Zip.close_in !zip end),
-      (fun () -> check_open(); get_classes_zip !zip)
-  in
-  let cached_types = Hashtbl.create 12 in
-  let get_raw_class path =
-    try
-      Hashtbl.find cached_types path
-    with | Not_found ->
-      let pack, name = hxpath_to_j path in
-      let try_file (pack,name) =
-        match get_raw_class (pack,name) with
-        | None ->
-            Hashtbl.add cached_types path None;
-            None
-        | Some (i, p1, p2) ->
-            Hashtbl.add cached_types path (Some(i,p1,p2)); (* type loop normalization *)
-            let ret = Some (normalize_jclass com i, p1, p2) in
-            Hashtbl.replace cached_types path ret;
-            ret
-      in
-      let ret = try_file (pack,name) in
-      if ret = None && Hashtbl.mem hxpack_to_jpack path then
-        try_file (Hashtbl.find hxpack_to_jpack path)
-      else
-        ret
-  in
-  let rec build ctx path p types =
-    try
-      if List.mem path !types then
-        None
-      else begin
-        types := path :: !types;
-        match get_raw_class path, path with
-        | None, ([], c) -> build ctx (["haxe";"root"], c) p types
-        | None, _ -> None
-        | Some (cls, real_path, pos_path), _ ->
-            if com.verbose then print_endline ("Parsed Java class " ^ (path_s cls.cpath));
-            let old_types = ctx.jtparams in
-            ctx.jtparams <- cls.ctypes :: ctx.jtparams;
-
-            let pos = { pfile = pos_path; pmin = 0; pmax = 0; } in
-
-            let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
-
-            let ppath = hxpath_to_j path in
-            let inner = List.fold_left (fun acc (path,out,_,_) ->
-              let path = jpath_to_hx path in
-              (if out <> Some ppath then
-                acc
-              else match build ctx path p types with
-                | Some(_,(_, classes)) ->
-                    classes @ acc
-                | _ -> acc);
-            ) [] cls.cinner_types in
-
-            (* build anonymous classes also *
-            let rec loop inner n =
-              match build ctx (fst path, snd path ^ "$" ^ (string_of_int n)) p types with
-              | Some(_,(_, classes)) ->
-                  loop (classes @ inner) (n + 1)
-              | _ -> inner
-            in
-            let inner = loop inner 1 in*)
-            (* add _Statics class *)
-            let inner = try
-              if not (List.mem JInterface cls.cflags) then raise Not_found;
-              let smethods = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cmethods in
-              let sfields = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cfields in
-              if not (smethods <> [] || sfields <> []) then raise Not_found;
-              let obj = TObject( (["java";"lang"],"Object"), []) in
-              let ncls = convert_java_class ctx pos { cls with cmethods = smethods; cfields = sfields; cflags = []; csuper = obj; cinterfaces = []; cinner_types = []; ctypes = [] } in
-              match ncls with
-              | EClass c ->
-                (EClass { c with d_name = c.d_name ^ "_Statics" }, pos) :: inner
-              | _ -> assert false
-            with | Not_found ->
-              inner
-            in
-            let ret = Some ( real_path, (pack, (convert_java_class ctx pos cls, pos) :: inner) ) in
-            ctx.jtparams <- old_types;
-            ret
-      end
-    with
-    | JReader.Error_message msg ->
-      if com.verbose then prerr_endline ("Class reader failed: " ^ msg);
-      None
-    | e ->
-      if com.verbose then begin
-        (* prerr_endline (Printexc.get_backtrace ()); requires ocaml 3.11 *)
-        prerr_endline (Printexc.to_string e)
-      end;
-      None
-  in
-  let build path p = build (create_ctx com) path p (ref [["java";"lang"], "String"]) in
-  let cached_files = ref None in
-  let list_all_files () = match !cached_files with
-    | None ->
-        let ret = list_all_files () in
-        cached_files := Some ret;
-        ret
-    | Some r -> r
-  in
-
-  (* TODO: add_dependency m mdep *)
-  com.load_extern_type <- com.load_extern_type @ [build];
-  com.java_libs <- (file, std, close, list_all_files, get_raw_class) :: com.java_libs
+		| Not_found -> try Common.find_file com (file ^ ".jar") with
+		| Not_found ->
+			failwith ("Java lib " ^ file ^ " not found")
+	in
+	let hxpack_to_jpack = Hashtbl.create 16 in
+	let get_raw_class, close, list_all_files =
+		(* check if it is a directory or jar file *)
+		match (Unix.stat file).st_kind with
+		| S_DIR -> (* open classes directly from directory *)
+			let all = ref [] in
+			let rec iter_files pack dir path = try
+				let file = Unix.readdir dir in
+				let filepath = path ^ "/" ^ file in
+				(if String.ends_with file ".class" && not (String.exists file "$") then
+					let file = String.sub file 0 (String.length file - 6) in
+					let path = jpath_to_hx (pack,file) in
+					all := path :: !all;
+					Hashtbl.add hxpack_to_jpack path (pack,file)
+				else if (Unix.stat filepath).st_kind = S_DIR && file <> "." && file <> ".." then
+					let pack = pack @ [file] in
+					iter_files (pack) (Unix.opendir filepath) filepath);
+				iter_files pack dir path
+			with | End_of_file | Unix.Unix_error _ ->
+				Unix.closedir dir
+			in
+			iter_files [] (Unix.opendir file) file;
+			let all = !all in
+
+			(fun (pack, name) ->
+				let real_path = file ^ "/" ^ (String.concat "/" pack) ^ "/" ^ (name ^ ".class") in
+				try
+					let data = Std.input_file ~bin:true real_path in
+					Some(JReader.parse_class (IO.input_string data), real_path, real_path)
+				with
+					| _ -> None), (fun () -> ()), (fun () -> all)
+		| _ -> (* open zip file *)
+			let closed = ref false in
+			let zip = ref (Zip.open_in file) in
+			let check_open () =
+				if !closed then begin
+					prerr_endline ("JAR file " ^ file ^ " already closed"); (* if this happens, find when *)
+					zip := Zip.open_in file;
+					closed := false
+				end
+			in
+			List.iter (function
+				| { Zip.is_directory = false; Zip.filename = filename } when String.ends_with filename ".class" ->
+					let pack = String.nsplit filename "/" in
+					(match List.rev pack with
+						| [] -> ()
+						| name :: pack ->
+							let name = String.sub name 0 (String.length name - 6) in
+							let pack = List.rev pack in
+							Hashtbl.add hxpack_to_jpack (jpath_to_hx (pack,name)) (pack,name))
+				| _ -> ()
+			) (Zip.entries !zip);
+			(fun (pack, name) ->
+				check_open();
+				try
+					let location = (String.concat "/" (pack @ [name]) ^ ".class") in
+					let entry = Zip.find_entry !zip location in
+					let data = Zip.read_entry !zip entry in
+					Some(JReader.parse_class (IO.input_string data), file, file ^ "@" ^ location)
+				with
+					| Not_found ->
+						None),
+			(fun () -> if not !closed then begin closed := true; Zip.close_in !zip end),
+			(fun () -> check_open(); get_classes_zip !zip)
+	in
+	let cached_types = Hashtbl.create 12 in
+	let get_raw_class path =
+		try
+			Hashtbl.find cached_types path
+		with | Not_found -> try
+			let pack, name = Hashtbl.find hxpack_to_jpack path in
+			let try_file (pack,name) =
+				match get_raw_class (pack,name) with
+				| None ->
+						Hashtbl.add cached_types path None;
+						None
+				| Some (i, p1, p2) ->
+						Hashtbl.add cached_types path (Some(i,p1,p2)); (* type loop normalization *)
+						let ret = Some (normalize_jclass com i, p1, p2) in
+						Hashtbl.replace cached_types path ret;
+						ret
+			in
+			try_file (pack,name)
+		with Not_found ->
+			None
+	in
+	let replace_canonical_name p pack name_original name_replace decl =
+		let mk_meta name = (Meta.JavaCanonical, [EConst (String (String.concat "." pack)), p; EConst(String name), p], p) in
+		let add_meta name metas =
+			if Meta.has Meta.JavaCanonical metas then
+				List.map (function
+					| (Meta.JavaCanonical,[EConst (String cpack), _; EConst(String cname), _],_) ->
+						let did_replace,name = String.replace cname name_original name_replace in
+						if not did_replace then print_endline (cname ^ " -> " ^ name_original ^ " -> " ^ name_replace);
+						mk_meta name
+					| m -> m
+				) metas
+			else
+				mk_meta name :: metas
+		in
+		match decl with
+			| EClass c ->
+				EClass { c with d_meta = add_meta c.d_name c.d_meta }
+			| EEnum e ->
+				EEnum { e with d_meta = add_meta e.d_name e.d_meta }
+			| EAbstract a ->
+				EAbstract { a with d_meta = add_meta a.d_name a.d_meta }
+			| d -> d
+	in
+	let rec build ctx path p types =
+		try
+			if List.mem path !types then
+				None
+			else begin
+				let first = match !types with
+					| [ ["java";"lang"], "String" ] | [] -> true
+					| p :: _ ->
+						false
+				in
+				types := path :: !types;
+				match get_raw_class path, path with
+				| None, ([], c) -> build ctx (["haxe";"root"], c) p types
+				| None, _ -> None
+				| Some (cls, real_path, pos_path), _ ->
+						let is_disallowed_inner = first && String.exists (snd cls.cpath) "$" in
+						let is_disallowed_inner = if is_disallowed_inner then begin
+								let outer, inner = String.split (snd cls.cpath) "$" in
+								match get_raw_class (fst path, outer) with
+									| None -> false
+									| _ -> true
+							end else
+								false
+						in
+						if is_disallowed_inner then
+							None
+						else begin
+							if com.verbose then print_endline ("Parsed Java class " ^ (path_s cls.cpath));
+							let old_types = ctx.jtparams in
+							ctx.jtparams <- cls.ctypes :: ctx.jtparams;
+
+							let pos = { pfile = pos_path; pmin = 0; pmax = 0; } in
+
+							let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
+
+							let ppath = Hashtbl.find hxpack_to_jpack path in
+							let inner = List.fold_left (fun acc (path,out,_,_) ->
+								let path = jpath_to_hx path in
+								(if out <> Some ppath then
+									acc
+								else match build ctx path p types with
+									| Some(_,(_, classes)) ->
+										let base = snd ppath ^ "$" in
+										(List.map (fun (def,p) ->
+											replace_canonical_name p (fst ppath) base (snd ppath ^ ".") def, p) classes) @ acc
+									| _ -> acc);
+							) [] cls.cinner_types in
+
+							(* add _Statics class *)
+							let inner = try
+								if not (List.mem JInterface cls.cflags) then raise Not_found;
+								let smethods = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cmethods in
+								let sfields = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cfields in
+								if not (smethods <> [] || sfields <> []) then raise Not_found;
+								let obj = TObject( (["java";"lang"],"Object"), []) in
+								let ncls = convert_java_class ctx pos { cls with cmethods = smethods; cfields = sfields; cflags = []; csuper = obj; cinterfaces = []; cinner_types = []; ctypes = [] } in
+								match ncls with
+								| EClass c :: imports ->
+									(EClass { c with d_name = c.d_name ^ "_Statics" }, pos) :: inner @ List.map (fun i -> i,pos) imports
+								| _ -> assert false
+							with | Not_found ->
+								inner
+							in
+							let inner_alias = ref SS.empty in
+							List.iter (fun x ->
+								match fst x with
+								| EClass c ->
+									inner_alias := SS.add c.d_name !inner_alias;
+								| _ -> ()
+							) inner;
+							let alias_list = ref [] in
+							List.iter (fun x ->
+								match x with
+								| (EClass c, pos) -> begin
+									let parts = String.nsplit c.d_name "_24" in
+									match parts with
+										| _ :: _ ->
+											let alias_name = String.concat "_" parts in
+											if (not (SS.mem alias_name !inner_alias)) && (not (String.exists (snd path) "_24")) then begin
+												let alias_def = ETypedef {
+													d_name = alias_name;
+													d_doc = None;
+													d_params = c.d_params;
+													d_meta = [];
+													d_flags = [];
+													d_data = CTPath {
+														tpackage = pack;
+														tname = snd path;
+														tparams = List.map (fun tp ->
+															TPType (CTPath {
+																tpackage = [];
+																tname = tp.tp_name;
+																tparams = [];
+																tsub = None;
+															})
+														) c.d_params;
+														tsub = Some(c.d_name);
+													};
+												} in
+												inner_alias := SS.add alias_name !inner_alias;
+												alias_list := (alias_def, pos) :: !alias_list;
+											end
+										| _ -> ()
+								end
+								| _ -> ()
+							) inner;
+							let inner = List.concat [!alias_list ; inner] in
+							let classes = List.map (fun t -> t,pos) (convert_java_class ctx pos cls) in
+							let imports, defs = List.partition (function | (EImport(_),_) -> true | _ -> false) (classes @ inner) in
+							let ret = Some ( real_path, (pack, imports @ defs) ) in
+							ctx.jtparams <- old_types;
+							ret
+						end
+			end
+		with
+		| JReader.Error_message msg ->
+			prerr_endline ("Class reader failed: " ^ msg);
+			None
+		| e ->
+			if com.verbose then begin
+				(* prerr_endline (Printexc.get_backtrace ()); requires ocaml 3.11 *)
+				prerr_endline (Printexc.to_string e)
+			end;
+			None
+	in
+	let build path p = build (create_ctx com) path p (ref [["java";"lang"], "String"]) in
+	let cached_files = ref None in
+	let list_all_files () = match !cached_files with
+		| None ->
+				let ret = list_all_files () in
+				cached_files := Some ret;
+				ret
+		| Some r -> r
+	in
+
+	(* TODO: add_dependency m mdep *)
+	com.load_extern_type <- com.load_extern_type @ [build];
+	com.java_libs <- (file, std, close, list_all_files, get_raw_class) :: com.java_libs

+ 129 - 55
genjs.ml

@@ -29,7 +29,7 @@ type pos = Ast.pos
 type sourcemap = {
 	sources : (string) DynArray.t;
 	sources_hash : (string, int) Hashtbl.t;
-	mappings : Buffer.t;
+	mappings : Rbuffer.t;
 
 	mutable source_last_line : int;
 	mutable source_last_col : int;
@@ -41,7 +41,7 @@ type sourcemap = {
 
 type ctx = {
 	com : Common.context;
-	buf : Buffer.t;
+	buf : Rbuffer.t;
 	packages : (string list,unit) Hashtbl.t;
 	smap : sourcemap;
 	js_modern : bool;
@@ -107,12 +107,12 @@ let kwds2 =
 		"Infinity"; "NaN"; "decodeURI"; "decodeURIComponent"; "encodeURI"; "encodeURIComponent";
 		"escape"; "eval"; "isFinite"; "isNaN"; "parseFloat"; "parseInt"; "undefined"; "unescape";
 
-		"JSON"; "Number"; "Object"; "console"; "window";
+		"JSON"; "Number"; "Object"; "console"; "window"; "require";
 	];
 	h
 
 let valid_js_ident s =
-	try
+	String.length s > 0 && try
 		for i = 0 to String.length s - 1 do
 			match String.unsafe_get s i with
 			| 'a'..'z' | 'A'..'Z' | '$' | '_' -> ()
@@ -123,7 +123,7 @@ let valid_js_ident s =
 	with Exit ->
 		false
 
-let field s = if Hashtbl.mem kwds s then "[\"" ^ s ^ "\"]" else "." ^ s
+let field s = if Hashtbl.mem kwds s || not (valid_js_ident s) then "[\"" ^ s ^ "\"]" else "." ^ s
 let ident s = if Hashtbl.mem kwds s then "$" ^ s else s
 let check_var_declaration v = if Hashtbl.mem kwds2 v.v_name then v.v_name <- "$" ^ v.v_name
 
@@ -141,7 +141,7 @@ let handle_newlines ctx str =
 		let rec loop from =
 			try begin
 				let next = String.index_from str from '\n' + 1 in
-				Buffer.add_char ctx.smap.mappings ';';
+				Rbuffer.add_char ctx.smap.mappings ';';
 				ctx.smap.output_last_col <- 0;
 				ctx.smap.print_comma <- false;
 				loop next
@@ -154,13 +154,13 @@ let handle_newlines ctx str =
 let spr ctx s =
 	ctx.separator <- false;
 	handle_newlines ctx s;
-	Buffer.add_string ctx.buf s
+	Rbuffer.add_string ctx.buf s
 
 let print ctx =
 	ctx.separator <- false;
 	Printf.kprintf (fun s -> begin
 		handle_newlines ctx s;
-		Buffer.add_string ctx.buf s
+		Rbuffer.add_string ctx.buf s
 	end)
 
 let unsupported p = error "This expression cannot be compiled to Javascript" p
@@ -182,7 +182,7 @@ let add_mapping ctx e =
 	let col = col - 1 in
 	if smap.source_last_file != file || smap.source_last_line != line || smap.source_last_col != col then begin
 		if smap.print_comma then
-			Buffer.add_char smap.mappings ','
+			Rbuffer.add_char smap.mappings ','
 		else
 			smap.print_comma <- true;
 
@@ -209,7 +209,7 @@ let add_mapping ctx e =
 				let continuation_bit = base in
 				let digit = vlq land mask in
 				let next = vlq asr shift in
-				Buffer.add_char smap.mappings (encode_digit (
+				Rbuffer.add_char smap.mappings (encode_digit (
 					if next > 0 then digit lor continuation_bit else digit));
 				if next > 0 then loop next else ()
 			in
@@ -227,14 +227,8 @@ let add_mapping ctx e =
 		smap.output_last_col <- smap.output_current_col
 	end
 
-let basename path =
-	try
-		let idx = String.rindex path '/' in
-		String.sub path (idx + 1) (String.length path - idx - 1)
-	with Not_found -> path
-
 let write_mappings ctx =
-	let basefile = basename ctx.com.file in
+	let basefile = Filename.basename ctx.com.file in
 	print ctx "\n//# sourceMappingURL=%s.map" basefile;
 	let channel = open_out_bin (ctx.com.file ^ ".map") in
 	let sources = DynArray.to_list ctx.smap.sources in
@@ -244,7 +238,7 @@ let write_mappings ctx =
 	output_string channel "{\n";
 	output_string channel "\"version\":3,\n";
 	output_string channel ("\"file\":\"" ^ (String.concat "\\\\" (ExtString.String.nsplit basefile "\\")) ^ "\",\n");
-	output_string channel ("\"sourceRoot\":\"file://\",\n");
+	output_string channel ("\"sourceRoot\":\"file:///\",\n");
 	output_string channel ("\"sources\":[" ^
 		(String.concat "," (List.map (fun s -> "\"" ^ to_url s ^ "\"") sources)) ^
 		"],\n");
@@ -255,23 +249,23 @@ let write_mappings ctx =
 	end;
 	output_string channel "\"names\":[],\n";
 	output_string channel "\"mappings\":\"";
-	Buffer.output_buffer channel ctx.smap.mappings;
+	Rbuffer.output_buffer channel ctx.smap.mappings;
 	output_string channel "\"\n";
 	output_string channel "}";
 	close_out channel
 
 let newline ctx =
-	match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with
+	match Rbuffer.nth ctx.buf (Rbuffer.length ctx.buf - 1) with
 	| '}' | '{' | ':' when not ctx.separator -> print ctx "\n%s" ctx.tabs
 	| _ -> print ctx ";\n%s" ctx.tabs
 
 let newprop ctx =
-	match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with
+	match Rbuffer.nth ctx.buf (Rbuffer.length ctx.buf - 1) with
 	| '{' -> print ctx "\n%s" ctx.tabs
 	| _ -> print ctx "\n%s," ctx.tabs
 
 let semicolon ctx =
-	match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with
+	match Rbuffer.nth ctx.buf (Rbuffer.length ctx.buf - 1) with
 	| '}' when not ctx.separator -> ()
 	| _ -> spr ctx ";"
 
@@ -306,7 +300,7 @@ let rec has_return e =
 let rec iter_switch_break in_switch e =
 	match e.eexpr with
 	| TFunction _ | TWhile _ | TFor _ -> ()
-	| TSwitch _ | TPatMatch _ when not in_switch -> iter_switch_break true e
+	| TSwitch _ when not in_switch -> iter_switch_break true e
 	| TBreak when in_switch -> raise Exit
 	| _ -> iter (iter_switch_break in_switch) e
 
@@ -402,6 +396,8 @@ let rec gen_call ctx e el in_value =
 		spr ctx (this ctx)
 	| TLocal { v_name = "__js__" }, [{ eexpr = TConst (TString code) }] ->
 		spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n"))
+	| TLocal { v_name = "__js__" }, { eexpr = TConst (TString code); epos = p } :: tl ->
+		Codegen.interpolate_code ctx.com code tl (spr ctx) (gen_expr ctx) p
 	| TLocal { v_name = "__instanceof__" },  [o;t] ->
 		spr ctx "(";
 		gen_value ctx o;
@@ -492,6 +488,12 @@ and gen_expr ctx e =
 		print ctx "$iterator(";
 		gen_value ctx x;
 		print ctx ")";
+	| TField (x,FClosure (Some ({cl_path=[],"Array"},_), {cf_name="push"})) ->
+		(* see https://github.com/HaxeFoundation/haxe/issues/1997 *)
+		add_feature ctx "use.$arrayPushClosure";
+		print ctx "$arrayPushClosure(";
+		gen_value ctx x;
+		print ctx ")"
 	| TField (x,FClosure (_,f)) ->
 		add_feature ctx "use.$bind";
 		(match x.eexpr with
@@ -510,6 +512,8 @@ and gen_expr ctx e =
 		print ctx "[%i]" (i + 2)
 	| TField ({ eexpr = TConst (TInt _ | TFloat _) } as x,f) ->
 		gen_expr ctx { e with eexpr = TField(mk (TParenthesis x) x.etype x.epos,f) }
+	| TField (x, (FInstance(_,_,f) | FStatic(_,f) | FAnon(f))) when Meta.has Meta.SelfCall f.cf_meta ->
+		gen_value ctx x;
 	| TField (x,f) ->
 		gen_value ctx x;
 		let name = field_name f in
@@ -571,8 +575,13 @@ and gen_expr ctx e =
 				spr ctx " = ";
 				gen_value ctx e
 		end
+	| TNew ({ cl_path = [],"Array" },_,[]) ->
+		print ctx "[]"
 	| TNew (c,_,el) ->
-		print ctx "new %s(" (ctx.type_accessor (TClassDecl c));
+		(match c.cl_constructor with
+		| Some cf when Meta.has Meta.SelfCall cf.cf_meta -> ()
+		| _ -> print ctx "new ");
+		print ctx "%s(" (ctx.type_accessor (TClassDecl c));
 		concat ctx "," (gen_value ctx) el;
 		spr ctx ")"
 	| TIf (cond,e,eelse) ->
@@ -612,7 +621,11 @@ and gen_expr ctx e =
 		handle_break();
 	| TObjectDecl fields ->
 		spr ctx "{ ";
-		concat ctx ", " (fun (f,e) -> print ctx "%s : " (anon_field f); gen_value ctx e) fields;
+		concat ctx ", " (fun (f,e) -> (match e.eexpr with
+			| TMeta((Meta.QuotedField,_,_),e) -> print ctx "'%s' : " f;
+			| _ -> print ctx "%s : " (anon_field f));
+			gen_value ctx e
+		) fields;
 		spr ctx "}";
 		ctx.separator <- true
 	| TFor (v,it,e) ->
@@ -698,7 +711,6 @@ and gen_expr ctx e =
 		bend();
 		newline ctx;
 		spr ctx "}";
-	| TPatMatch dt -> assert false
 	| TSwitch (e,cases,def) ->
 		spr ctx "switch";
 		gen_value ctx e;
@@ -756,6 +768,8 @@ and gen_block_element ?(after=false) ctx e =
 			| _ -> assert false)
 	| TFunction _ ->
 		gen_block_element ~after ctx (mk (TParenthesis e) e.etype e.epos)
+	| TObjectDecl fl ->
+		List.iter (fun (_,e) -> gen_block_element ~after ctx e) fl
 	| _ ->
 		if not after then newline ctx;
 		gen_expr ctx e;
@@ -849,7 +863,7 @@ and gen_value ctx e =
 	| TIf (cond,e,eo) ->
 		(* remove parenthesis unless it's an operation with higher precedence than ?: *)
 		let cond = (match cond.eexpr with
-			| TParenthesis { eexpr = TBinop ((Ast.OpAssign | Ast.OpAssignOp _),_,_) } -> cond
+			| TParenthesis { eexpr = TBinop ((Ast.OpAssign | Ast.OpAssignOp _),_,_) | TIf _ } -> cond
 			| TParenthesis e -> e
 			| _ -> cond
 		) in
@@ -867,7 +881,6 @@ and gen_value ctx e =
 			match def with None -> None | Some e -> Some (assign e)
 		)) e.etype e.epos);
 		v()
-	| TPatMatch dt -> assert false
 	| TTry (b,catchs) ->
 		let v = value() in
 		let block e = mk (TBlock [e]) e.etype e.epos in
@@ -922,9 +935,10 @@ let gen_class_static_field ctx c f =
 		match e.eexpr with
 		| TFunction _ ->
 			let path = (s_path ctx c.cl_path) ^ (static_field f.cf_name) in
+			let dot_path = (dot_path c.cl_path) ^ (static_field f.cf_name) in
 			ctx.id_counter <- 0;
 			print ctx "%s = " path;
-			(match (get_exposed ctx path f.cf_meta) with [s] -> print ctx "$hx_exports.%s = " s | _ -> ());
+			(match (get_exposed ctx dot_path f.cf_meta) with [s] -> print ctx "$hx_exports.%s = " s | _ -> ());
 			gen_value ctx e;
 			newline ctx;
 		| _ ->
@@ -977,10 +991,16 @@ let generate_class ctx c =
 		print ctx "%s = " p
 	else
 		print ctx "%s = $hxClasses[\"%s\"] = " p (dot_path c.cl_path);
-	(match (get_exposed ctx p c.cl_meta) with [s] -> print ctx "$hx_exports.%s = " s | _ -> ());
-	(match c.cl_constructor with
-	| Some { cf_expr = Some e } -> gen_expr ctx e
-	| _ -> (print ctx "function() { }"); ctx.separator <- true);
+	(match (get_exposed ctx (dot_path c.cl_path) c.cl_meta) with [s] -> print ctx "$hx_exports.%s = " s | _ -> ());
+	(match c.cl_kind with
+		| KAbstractImpl _ ->
+			(* abstract implementations only contain static members and don't need to have constructor functions *)
+			print ctx "{}"; ctx.separator <- true
+		| _ ->
+			(match c.cl_constructor with
+			| Some { cf_expr = Some e } -> gen_expr ctx e
+			| _ -> (print ctx "function() { }"); ctx.separator <- true)
+	);
 	newline ctx;
 	if ctx.js_modern && hxClasses then begin
 		print ctx "$hxClasses[\"%s\"] = %s" (dot_path c.cl_path) p;
@@ -990,7 +1010,7 @@ let generate_class ctx c =
 	(match c.cl_implements with
 	| [] -> ()
 	| l ->
-		print ctx "%s.__interfaces__ = [%s]" p (String.concat "," (List.map (fun (i,_) -> s_path ctx i.cl_path) l));
+		print ctx "%s.__interfaces__ = [%s]" p (String.concat "," (List.map (fun (i,_) -> ctx.type_accessor (TClassDecl i)) l));
 		newline ctx;
 	);
 
@@ -1015,7 +1035,7 @@ let generate_class ctx c =
 		(match c.cl_super with
 		| None -> print ctx "%s.prototype = {" p;
 		| Some (csup,_) ->
-			let psup = s_path ctx csup.cl_path in
+			let psup = ctx.type_accessor (TClassDecl csup) in
 			print ctx "%s.__super__ = %s" p psup;
 			newline ctx;
 			print ctx "%s.prototype = $extend(%s.prototype,{" p psup;
@@ -1105,6 +1125,25 @@ let generate_static ctx (c,f,e) =
 	gen_value ctx e;
 	newline ctx
 
+let generate_require ctx path meta =
+	let _, args, mp = Meta.get Meta.JsRequire meta in
+	let p = (s_path ctx path) in
+
+	if ctx.js_flatten then
+		spr ctx "var "
+	else
+		generate_package_create ctx path;
+
+	(match args with
+	| [(EConst(String(module_name)),_)] ->
+		print ctx "%s = require(\"%s\")" p module_name
+	| [(EConst(String(module_name)),_) ; (EConst(String(object_path)),_)] ->
+		print ctx "%s = require(\"%s\").%s" p module_name object_path
+	| _ ->
+		error "Unsupported @:jsRequire format" mp);
+
+	newline ctx
+
 let generate_type ctx = function
 	| TClassDecl c ->
 		(match c.cl_init with
@@ -1114,14 +1153,20 @@ let generate_type ctx = function
 		(* 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;
-		if not c.cl_extern then
+		(* Another special case for Std because we do not want to generate it if it's empty. *)
+		if p = "Std" && c.cl_ordered_statics = [] then
+			()
+		else if not c.cl_extern then
 			generate_class ctx c
+		else if Meta.has Meta.JsRequire c.cl_meta && is_directly_used ctx.com c.cl_meta then
+			generate_require ctx c.cl_path c.cl_meta
 		else if not ctx.js_flatten && Meta.has Meta.InitPackage c.cl_meta then
 			(match c.cl_path with
 			| ([],_) -> ()
 			| _ -> generate_package_create ctx c.cl_path)
 	| TEnumDecl e when e.e_extern ->
-		()
+		if Meta.has Meta.JsRequire e.e_meta && is_directly_used ctx.com e.e_meta then
+			generate_require ctx e.e_path e.e_meta
 	| TEnumDecl e -> generate_enum ctx e
 	| TTypeDecl _ | TAbstractDecl _ -> ()
 
@@ -1131,7 +1176,7 @@ let set_current_class ctx c =
 let alloc_ctx com =
 	let ctx = {
 		com = com;
-		buf = Buffer.create 16000;
+		buf = Rbuffer.create 16000;
 		packages = Hashtbl.create 0;
 		smap = {
 			source_last_line = 0;
@@ -1142,10 +1187,10 @@ let alloc_ctx com =
 			output_current_col = 0;
 			sources = DynArray.create();
 			sources_hash = Hashtbl.create 0;
-			mappings = Buffer.create 16;
+			mappings = Rbuffer.create 16;
 		};
 		js_modern = not (Common.defined com Define.JsClassic);
-		js_flatten = Common.defined com Define.JsFlatten;
+		js_flatten = not (Common.defined com Define.JsUnflatten);
 		statics = [];
 		inits = [];
 		current = null_class;
@@ -1161,16 +1206,17 @@ let alloc_ctx com =
 	ctx.type_accessor <- (fun t ->
 		let p = t_path t in
 		match t with
-		| TClassDecl { cl_extern = true }
-		| TEnumDecl { e_extern = true }
+		| TClassDecl ({ cl_extern = true } as c) when not (Meta.has Meta.JsRequire c.cl_meta)
+			-> dot_path p
+		| TEnumDecl ({ e_extern = true } as e) when not (Meta.has Meta.JsRequire e.e_meta)
 			-> dot_path p
 		| _ -> s_path ctx p);
 	ctx
 
 let gen_single_expr ctx e expr =
 	if expr then gen_expr ctx e else gen_value ctx e;
-	let str = Buffer.contents ctx.buf in
-	Buffer.reset ctx.buf;
+	let str = Rbuffer.unsafe_contents ctx.buf in
+	Rbuffer.reset ctx.buf;
 	ctx.id_counter <- 0;
 	str
 
@@ -1187,7 +1233,7 @@ let generate com =
 	let exposed = List.concat (List.map (fun t ->
 		match t with
 			| TClassDecl c ->
-				let path = s_path ctx c.cl_path in
+				let path = dot_path c.cl_path in
 				let class_exposed = get_exposed ctx path c.cl_meta in
 				let static_exposed = List.map (fun f ->
 					get_exposed ctx (path ^ static_field f.cf_name) f.cf_meta
@@ -1217,6 +1263,31 @@ let generate com =
 		in loop parts "";
 	)) exposed;
 
+
+	let closureArgs = [] in
+	let closureArgs = if (anyExposed && not (Common.defined com Define.ShallowExpose)) then
+		(
+			"$hx_exports",
+			(* TODO(bruno): Remove runtime branching when standard node haxelib is available *)
+			"typeof window != \"undefined\" ? window : exports"
+		) :: closureArgs
+	else
+		closureArgs
+	in
+	(* Provide console for environments that may not have it. *)
+	let closureArgs = if (not (Common.defined com Define.JsEs5)) then
+		(
+			"console",
+			"typeof console != \"undefined\" ? console : {log:function(){}}"
+		) :: closureArgs
+	else
+		closureArgs
+	in
+
+	if Common.raw_defined com "nodejs" then
+		(* Add node globals to pseudo-keywords, so they are not shadowed by local vars *)
+		List.iter (fun s -> Hashtbl.replace kwds2 s ()) [ "global"; "process"; "__filename"; "__dirname"; "module" ];
+
 	if ctx.js_modern then begin
 		(* Additional ES5 strict mode keywords. *)
 		List.iter (fun s -> Hashtbl.replace kwds s ()) [ "arguments"; "eval" ];
@@ -1227,9 +1298,7 @@ let generate com =
 			ctx.separator <- true;
 			newline ctx
 		);
-		print ctx "(function (";
-		if (anyExposed && not (Common.defined com Define.ShallowExpose)) then print ctx "$hx_exports";
-		print ctx ") { \"use strict\"";
+		print ctx "(function (%s) { \"use strict\"" (String.concat ", " (List.map fst closureArgs));
 		newline ctx;
 		let rec print_obj f root = (
 			let path = root ^ "." ^ f.os_name in
@@ -1242,6 +1311,10 @@ let generate com =
 		List.iter (fun f -> print_obj f "$hx_exports") exposedObject.os_fields;
 	end;
 
+	(* If ctx.js_modern, console is defined in closureArgs. *)
+	if (not ctx.js_modern) && (not (Common.defined com Define.JsEs5)) then
+		spr ctx "var console = Function(\"return typeof console != 'undefined' ? console : {log:function(){}}\")();\n";
+
 	(* TODO: fix $estr *)
 	let vars = [] in
 	let vars = (if has_feature ctx "Type.resolveClass" || has_feature ctx "Type.resolveEnum" then ("$hxClasses = " ^ (if ctx.js_modern then "{}" else "$hxClasses || {}")) :: vars else vars) in
@@ -1286,18 +1359,19 @@ let generate com =
 		print ctx "function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $fid++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; o.hx__closures__[m.__id__] = f; } return f; }";
 		newline ctx;
 	end;
+	if has_feature ctx "use.$arrayPushClosure" then begin
+		print ctx "function $arrayPushClosure(a) {";
+		print ctx " return function(x) { a.push(x); }; ";
+		print ctx "}";
+		newline ctx
+	end;
 	List.iter (gen_block_element ~after:true ctx) (List.rev ctx.inits);
 	List.iter (generate_static ctx) (List.rev ctx.statics);
 	(match com.main with
 	| None -> ()
 	| Some e -> gen_expr ctx e; newline ctx);
 	if ctx.js_modern then begin
-		print ctx "})(";
-		if (anyExposed && not (Common.defined com Define.ShallowExpose)) then (
-			(* TODO(bruno): Remove runtime branching when standard node haxelib is available *)
-			print ctx "typeof window != \"undefined\" ? window : exports"
-		);
-		print ctx ")";
+		print ctx "})(%s)" (String.concat ", " (List.map snd closureArgs));
 		newline ctx;
 		if (anyExposed && (Common.defined com Define.ShallowExpose)) then (
 			List.iter (fun f ->
@@ -1314,7 +1388,7 @@ let generate com =
 	end;
 	if com.debug then write_mappings ctx else (try Sys.remove (com.file ^ ".map") with _ -> ());
 	let ch = open_out_bin com.file in
-	output_string ch (Buffer.contents ctx.buf);
+	Rbuffer.output_buffer ch ctx.buf;
 	close_out ch);
 	t()
 

+ 20 - 75
genneko.ml

@@ -332,6 +332,7 @@ and gen_expr ctx e =
 				let path = (match follow v.v_type with
 					| TInst (c,_) -> Some c.cl_path
 					| TEnum (e,_) -> Some e.e_path
+					| TAbstract (a,_) -> Some a.a_path
 					| TDynamic _ -> None
 					| _ -> assert false
 				) in
@@ -369,74 +370,6 @@ and gen_expr ctx e =
 		gen_expr ctx e
 	| TCast (e1,Some t) ->
 		gen_expr ctx (Codegen.default_cast ~vtmp:"@tmp" ctx.com e1 t e.etype e.epos)
- 	| TPatMatch dt ->
-		let num_labels = Array.length dt.dt_dt_lookup in
-		let lc = ctx.label_count in
-		ctx.label_count <- ctx.label_count + num_labels + 1;
-		let get_label i ="label_" ^ (string_of_int (lc + i)) in
-		let goto i = call p (builtin p "goto") [ident p (get_label i)] in
-		let state = Hashtbl.create 0 in
-		let v_name v = "v" ^ (string_of_int v.v_id) in
-		let get_locals e =
-			let locals = Hashtbl.create 0 in
-			let rec loop e = match e.eexpr with
-				| TLocal v -> Hashtbl.replace locals v true
-				| _ -> Type.iter loop e
-			in
-			loop e;
-			Hashtbl.fold (fun v _ l -> if Hashtbl.mem locals v then (v.v_name, Some (field p (ident p "@state") (v_name v))) :: l else l) state []
-		in
-		let rec loop d = match d with
-			| DTGoto i ->
-				goto i
-			| DTBind (bl,dt) ->
-				let block = List.map (fun ((v,_),est) ->
-					let est = gen_expr ctx est in
-					let field = field p (ident p "@state") (v_name v) in
-					Hashtbl.replace state v field;
-					(EBinop ("=",field,est),p)
-				) bl in
-				EBlock (block @ [loop dt]),p
-			| DTExpr e ->
-				let block = [
-					(EBinop ("=",ident p "@ret",gen_expr ctx e),p);
-					goto num_labels;
-				] in
-				(match get_locals e with [] -> EBlock block,p | el -> EBlock ((EVars(el),p) :: block),p)
-			| DTGuard (e,dt1,dt2) ->
-				let eg = match dt2 with
- 					| None -> (EIf (gen_expr ctx e,loop dt1,None),p)
-					| Some dt -> (EIf (gen_expr ctx e,loop dt1,Some (loop dt)),p)
-				in
-				(match get_locals e with [] -> eg | el -> EBlock [(EVars(el),p);eg],p)
-			| DTSwitch (e,cl,dto) ->
-				let e = gen_expr ctx e in
-				let def = match dto with None -> None | Some dt -> Some (loop dt) in
-				let cases = List.map (fun (e,dt) -> gen_expr ctx e,loop dt) cl in
-				EBlock [
-					(ESwitch (e,cases,def),p);
-					goto num_labels;
-				],p
-		in
-		let acc = DynArray.create () in
-		for i = num_labels -1 downto 0 do
-			let e = loop dt.dt_dt_lookup.(i) in
-			DynArray.add acc (ELabel (get_label i),p);
-			DynArray.add acc e;
-		done;
-		DynArray.add acc (ELabel (get_label num_labels),p);
-		DynArray.add acc (ident p "@ret");
-		let el = DynArray.to_list acc in
-		let var_init = List.fold_left (fun acc (v,eo) -> (v.v_name,(match eo with None -> None | Some e -> Some (gen_expr ctx e))) :: acc) [] dt.dt_var_init in
-		let state_init = Hashtbl.fold (fun v _ l -> (v_name v,null p) :: l) state [] in
-		let init = match var_init,state_init with
-			| [], [] -> []
-			| el, [] -> el
-			| [], vl -> ["@state",Some (EObject vl,p)]
-			| el, vl -> ("@state",Some (EObject vl,p)) :: el
-		in
-		let el = match init with [] -> (goto dt.dt_first) :: el | _ -> (EVars init,p) :: (goto dt.dt_first) :: el in
-		EBlock el,p
 	| TSwitch (e,cases,eo) ->
 		let e = gen_expr ctx e in
 		let eo = (match eo with None -> None | Some e -> Some (gen_expr ctx e)) in
@@ -490,9 +423,9 @@ let gen_class ctx c =
 	let stpath = gen_type_path p c.cl_path in
 	let fnew = (match c.cl_constructor with
 	| Some f ->
-		(match follow f.cf_type with
-		| TFun (args,_) ->
-			let params = List.map (fun (n,_,_) -> n) args in
+		(match f.cf_expr with
+		| Some {eexpr = TFunction tf} ->
+			let params = List.map (fun (v,_) -> v.v_name) tf.tf_args in
 			gen_method ctx p f ["new",(EFunction (params,(EBlock [
 				(EVars ["@o",Some (call p (builtin p "new") [null p])],p);
 				(call p (builtin p "objsetproto") [ident p "@o"; clpath]);
@@ -730,9 +663,17 @@ let generate_libs_init = function
 			var @b = if( @s == "Windows" )
 				@env("HAXEPATH") + "\\lib\\"
 				else try $loader.loadprim("std@file_contents",1)(@env("HOME")+"/.haxelib") + "/"
-				catch e if( @s == "Linux" ) "/usr/lib/haxe/lib/" else "/usr/local/lib/haxe/lib/";
+				catch e
+					if( @s == "Linux" )
+						if( $loader(loadprim("std@sys_exists",1))("/usr/lib/haxe/lib") )
+							"/usr/lib/haxe/lib"
+						else
+							"/usr/share/haxe/lib/"
+					else
+						"/usr/local/lib/haxe/lib/";
+			if( try $loader.loadprim("std@sys_file_type",1)(".haxelib") == "dir" catch e false ) @b = $loader.loadprim("std@file_full_path",1)(".haxelib") + "/";
 			if( $loader.loadprim("std@sys_is64",0)() ) @s = @s + 64;
-			@s = @s + "/"
+			@b = @b + "/"
 		*)
 		let p = null_pos in
 		let es = ident p "@s" in
@@ -752,12 +693,15 @@ let generate_libs_init = function
 						op "+" (call p (loadp "file_contents" 1) [op "+" (call p (ident p "@env") [str p "HOME"]) (str p "/.haxelib")]) (str p "/"),
 						"e",
 						(EIf (op "==" es (str p "Linux"),
-							str p "/usr/lib/haxe/lib/",
+							(EIf (call p (loadp "sys_exists" 1) [ str p "/usr/lib/haxe/lib" ],
+								str p "/usr/lib/haxe/lib/",
+								Some (str p "/usr/share/haxe/lib/")),p),
 							Some (str p "/usr/local/lib/haxe/lib/")
 						),p)
 					),p)
 				),p);
 			],p);
+			(EIf ((ETry (op "==" (call p (loadp "sys_file_type" 1) [str p ".haxelib"]) (str p "dir"),"e",(EConst False,p)),p),op "=" (ident p "@b") (op "+" (call p (loadp "file_full_path" 1) [str p ".haxelib"]) (str p "/")), None),p);
 			(EIf (call p (loadp "sys_is64" 0) [],op "=" es (op "+" es (int p 64)),None),p);
 			op "=" es (op "+" es (str p "/"));
 		] in
@@ -767,7 +711,7 @@ let generate_libs_init = function
 			let dstr = str p dir in
 			(*
 				// for each lib dir
-				$loader.path = $array($loader.path,dir+@s);
+				$loader.path = $array($loader.path,@b+dir+@s);
 			*)
 			op "=" lpath (call p (builtin p "array") [op "+" (if full_path then dstr else op "+" (ident p "@b") dstr) (ident p "@s"); lpath])
 		) libs
@@ -848,6 +792,7 @@ let generate com =
 	let use_nekoc = Common.defined com Define.UseNekoc in
 	if not use_nekoc then begin
 		try
+			mkdir_from_path com.file;
 			let ch = IO.output_channel (open_out_bin com.file) in
 			Nbytecode.write ch (Ncompile.compile ctx.version e);
 			IO.close_out ch;

+ 26 - 19
genphp.ml

@@ -111,10 +111,6 @@ and type_string_suff suffix haxe_type =
 	| TAbstract ({ a_path = [],"Float" },[]) -> "double"
 	| TAbstract ({ a_path = [],"Bool" },[]) -> "bool"
 	| TAbstract ({ a_path = [],"Void" },[]) -> "Void"
-	| TEnum ({ e_path = ([],"Void") },[]) -> "Void"
-	| TEnum ({ e_path = ([],"Bool") },[]) -> "bool"
-	| TInst ({ cl_path = ([],"Float") },[]) -> "double"
-	| TInst ({ cl_path = ([],"Int") },[]) -> "int"
 	| TEnum (enum,params) ->  (join_class_path enum.e_path "::") ^ suffix
 	| TInst (klass,params) ->  (class_string klass suffix params)
 	| TAbstract (abs,params) ->  (join_class_path abs.a_path "::") ^ suffix
@@ -133,7 +129,7 @@ and type_string_suff suffix haxe_type =
 			(match params with
 			| [t] -> "Array<" ^ (type_string (follow t) ) ^ " >"
 			| _ -> assert false)
-		| _ ->  type_string_suff suffix (apply_params type_def.t_types params type_def.t_type)
+		| _ ->  type_string_suff suffix (apply_params type_def.t_params params type_def.t_type)
 		)
 	| TFun (args,haxe_type) -> "Dynamic"
 	| TAnon anon -> "Dynamic"
@@ -208,7 +204,7 @@ let rec is_string_type t =
 	   (match !(a.a_status) with
 	   | Statics ({cl_path = ([], "String")}) -> true
 	   | _ -> false)
-	| TAbstract (a,pl) -> is_string_type (Codegen.Abstract.get_underlying_type a pl)
+	| TAbstract (a,pl) -> is_string_type (Abstract.get_underlying_type a pl)
 	| _ -> false
 
 let is_string_expr e = is_string_type e.etype
@@ -336,14 +332,10 @@ let create_directory com ldir =
  	(List.iter (fun p -> atm_path := !atm_path ^ "/" ^ p; if not (Sys.file_exists !atm_path) then (Unix.mkdir !atm_path 0o755);) ldir)
 
 let write_resource dir name data =
-	let i = ref 0 in
-	String.iter (fun c ->
-		if c = '\\' || c = '/' || c = ':' || c = '*' || c = '?' || c = '"' || c = '<' || c = '>' || c = '|' then String.blit "_" 0 name !i 1;
-		incr i
-	) name;
 	let rdir = dir ^ "/res" in
 	if not (Sys.file_exists dir) then Unix.mkdir dir 0o755;
 	if not (Sys.file_exists rdir) then Unix.mkdir rdir 0o755;
+	let name = Codegen.escape_res_name name false in
 	let ch = open_out_bin (rdir ^ "/" ^ name) in
 	output_string ch data;
 	close_out ch
@@ -1227,13 +1219,29 @@ and gen_expr ctx e =
 				gen_field_op ctx e2;
 				spr ctx ")";
 			end
+		| Ast.OpGt | Ast.OpGte | Ast.OpLt | Ast.OpLte when is_string_expr e1 ->
+			spr ctx "(strcmp(";
+			gen_field_op ctx e1;
+			spr ctx ", ";
+			gen_field_op ctx e2;
+			spr ctx ")";
+			let op_str = match op with
+				| Ast.OpGt -> ">"
+				| Ast.OpGte -> ">="
+				| Ast.OpLt -> "<"
+				| Ast.OpLte -> "<="
+				| _ -> assert false
+			in
+			print ctx "%s 0)" op_str
 		| _ ->
 			leftside e1;
 			print ctx " %s " (Ast.s_binop op);
 			gen_value_op ctx e2;
 		));
 	| TEnumParameter(e1,_,i) ->
+		spr ctx "_hx_deref(";
 		gen_value ctx e1;
+		spr ctx ")";
 		print ctx "->params[%d]" i;
 	| TField (e1,s) ->
 		gen_tfield ctx e e1 (field_name s)
@@ -1270,7 +1278,7 @@ and gen_expr ctx e =
 	| TContinue ->
 		if ctx.in_loop then spr ctx "continue" else print ctx "continue %d" ctx.nested_loops
 	| TBlock [] ->
-		spr ctx ""
+		spr ctx "{}"
 	| TBlock el ->
 		let old_l = ctx.inv_locals in
 		let b = save_locals ctx in
@@ -1309,7 +1317,6 @@ and gen_expr ctx e =
 				| TThrow _
 				| TWhile _
 				| TFor _
-				| TPatMatch _
 				| TTry _
 				| TBreak
 				| TBlock _ ->
@@ -1323,7 +1330,6 @@ and gen_expr ctx e =
 					| TThrow _
 					| TWhile _
 					| TFor _
-					| TPatMatch _
 					| TTry _
 					| TBlock _ -> ()
 					| _ ->
@@ -1454,7 +1460,7 @@ and gen_expr ctx e =
 			);
 		| TField (e1,s) ->
 			spr ctx (Ast.s_unop op);
-			gen_field_access ctx true e1 (field_name s)
+			gen_tfield ctx e e1 (field_name s)
 		| _ ->
 			spr ctx (Ast.s_unop op);
 			gen_value ctx e)
@@ -1517,6 +1523,9 @@ and gen_expr ctx e =
 		print ctx "while($%s->hasNext()) {" tmp;
 		let bend = open_block ctx in
 		newline ctx;
+		(* unset loop variable (issue #2900) *)
+		print ctx "unset($%s)" v;
+		newline ctx;
 		print ctx "$%s = $%s->next()" v tmp;
 		gen_while_expr ctx e;
 		bend();
@@ -1587,7 +1596,6 @@ and gen_expr ctx e =
 		bend();
 		newline ctx;
 		spr ctx "}"
-	| TPatMatch dt -> assert false
 	| TSwitch (e,cases,def) ->
 		let old_loop = ctx.in_loop in
 		ctx.in_loop <- false;
@@ -1778,7 +1786,6 @@ and gen_value ctx e =
 	| TThrow _
 	| TSwitch _
 	| TFor _
-	| TPatMatch _
 	| TIf _
 	| TTry _ ->
 		inline_block ctx e
@@ -1990,7 +1997,7 @@ let generate_inline_method ctx c m =
 let generate_class ctx c =
 	let requires_constructor = ref true in
 	ctx.curclass <- c;
-	ctx.local_types <- List.map snd c.cl_types;
+	ctx.local_types <- List.map snd c.cl_params;
 
 	print ctx "%s %s " (if c.cl_interface then "interface" else "class") (s_path ctx c.cl_path c.cl_extern c.cl_pos);
 	(match c.cl_super with
@@ -2133,7 +2140,7 @@ let generate_main ctx c =
 		newline ctx
 
 let generate_enum ctx e =
-	ctx.local_types <- List.map snd e.e_types;
+	ctx.local_types <- List.map snd e.e_params;
 	let pack = open_block ctx in
 	let ename = s_path ctx e.e_path e.e_extern e.e_pos in
 

+ 2405 - 0
genpy.ml

@@ -0,0 +1,2405 @@
+(*
+ * Copyright (C)2005-2014 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *)
+
+open Ast
+open Type
+open Common
+
+module Utils = struct
+	let class_of_module_type mt = match mt with
+		| TClassDecl c -> c
+		| _ -> failwith ("Not a class: " ^ (s_type_path (t_infos mt).mt_path))
+
+	let find_type com path =
+		try
+			List.find (fun mt -> match mt with
+				| TAbstractDecl _ -> false
+				| _ -> (t_infos mt).mt_path = path
+			) com.types
+		with Not_found ->
+			error (Printf.sprintf "Could not find type %s\n" (s_type_path path)) null_pos
+
+	let mk_static_field c cf p =
+			let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in
+			let ethis = mk (TTypeExpr (TClassDecl c)) ta p in
+			let t = monomorphs cf.cf_params cf.cf_type in
+			mk (TField (ethis,(FStatic (c,cf)))) t p
+
+	let mk_static_call c cf el p =
+		let ef = mk_static_field c cf p in
+		let tr = match follow ef.etype with
+			| TFun(args,tr) -> tr
+			| _ -> assert false
+		in
+		mk (TCall(ef,el)) tr p
+
+	let resolve_static_field c n =
+		try
+			PMap.find n c.cl_statics
+		with Not_found ->
+			failwith (Printf.sprintf "Class %s has no field %s" (s_type_path c.cl_path) n)
+
+	let mk_static_field_2 c n p =
+		mk_static_field c (resolve_static_field c n) p
+
+	let mk_static_call_2 c n el p =
+		mk_static_call c (resolve_static_field c n) el p
+end
+
+module KeywordHandler = struct
+	let kwds =
+		let h = Hashtbl.create 0 in
+		List.iter (fun s -> Hashtbl.add h s ()) [
+			"and"; "as"; "assert"; "break"; "class"; "continue"; "def"; "del"; "elif"; "else"; "except"; "exec"; "finally"; "for";
+			"from"; "global"; "if"; "import"; "in"; "is"; "lambda"; "not"; "or"; "pass"; " raise"; "return"; "try"; "while";
+			"with"; "yield"; "None"; "True"; "False";
+		];
+		h
+
+	let kwds2 =
+		let h = Hashtbl.create 0 in
+		List.iter (fun s -> Hashtbl.add h s ()) [
+			"len"; "int"; "float"; "list"; "bool"; "str"; "isinstance"; "print"; "min"; "max";
+			"hasattr"; "getattr"; "setattr"; "delattr"; "callable"; "type"; "ord"; "chr"; "iter"; "map"; "filter";
+			"tuple"; "dict"; "set"; "bytes"; "bytearray"
+		];
+		h
+
+	let handle_keywords s =
+		let l = String.length s in
+		if Hashtbl.mem kwds s then
+			"_hx_" ^ s
+		(*
+			handle special __ underscore behaviour (creates private fields for objects) for fields but only if the field doesn't
+			end with at least one underscores like __iter__ because these are special fields
+		*)
+		else if l > 2 && String.sub s 0 2 = "__" && String.sub s (l - 1) 1 <> "_" then
+			"_hx_" ^ s
+		else s
+
+	let check_var_declaration v =
+		if Hashtbl.mem kwds2 v.v_name then v.v_name <- "_hx_" ^ v.v_name
+end
+
+module Transformer = struct
+	type adjusted_expr = {
+		a_expr : texpr;
+		a_blocks : texpr list;
+		a_next_id : unit -> string;
+		a_is_value : bool;
+	}
+
+	let como = ref None
+	let t_bool = ref t_dynamic
+	let t_void = ref t_dynamic
+	let t_string = ref t_dynamic
+	let t_int = ref t_dynamic
+	let c_reflect = ref (fun () -> null_class)
+
+	let init com =
+		como := Some com;
+		t_bool := com.basic.tbool;
+		t_void := com.basic.tvoid;
+		t_string := com.basic.tstring;
+		t_int := com.basic.tint;
+		c_reflect := fun () -> Utils.class_of_module_type (Utils.find_type com ([],"Reflect"))
+
+	and debug_expr e =
+		let s_type = Type.s_type (print_context()) in
+		let s = Type.s_expr_pretty "\t" s_type e in
+		Printf.printf "%s\n" s
+
+	and debug_expr_with_type e =
+		let s_type = Type.s_type (print_context()) in
+		let es = Type.s_expr_pretty "\t" s_type e in
+		let t = s_type e.etype in
+		Printf.printf "%s : %s\n" es t
+
+	and debug_type t =
+		let s_type = Type.s_type (print_context()) in
+		let t = s_type t in
+		Printf.printf "%s\n" t
+
+	let new_counter () =
+		let n = ref (-1) in
+		(fun () ->
+			incr n;
+			Printf.sprintf "_hx_local_%i" !n
+		)
+
+	let to_expr ae =
+		match ae.a_blocks with
+			| [] ->
+				ae.a_expr
+			| el ->
+				match ae.a_expr.eexpr with
+					| TBlock el2 ->
+						{ ae.a_expr with eexpr = TBlock (el @ el2) }
+					| _ ->
+						{ ae.a_expr with eexpr = TBlock (el @ [ae.a_expr])}
+
+	let lift_expr ?(is_value = false) ?(next_id = None) ?(blocks = []) e =
+		let next_id = match next_id with
+			| None ->
+				new_counter()
+			| Some f ->
+				f
+		in
+		{
+			a_expr = e;
+			a_blocks = blocks;
+			a_next_id = next_id;
+			a_is_value = is_value
+		}
+
+	let lift_expr1 is_value next_id blocks e =
+		lift_expr ~is_value:is_value ~next_id:(Some next_id) ~blocks:blocks e
+
+	let to_tvar ?(capture = false) n t =
+		alloc_var n t
+		(* { v_name = n; v_type = t; v_id = 0; v_capture = capture; v_extra = None; v_meta = [] } *)
+
+	let create_non_local n pos =
+		let s = "nonlocal " ^ (KeywordHandler.handle_keywords n) in
+		(* TODO: this is a hack... *)
+		let id = mk (TLocal (to_tvar "python_Syntax._pythonCode" t_dynamic ) ) !t_void pos in
+		let id2 = mk (TLocal( to_tvar s t_dynamic )) !t_void pos in
+		mk (TCall(id, [id2])) t_dynamic pos
+
+	let to_tlocal_expr ?(capture = false) n t p =
+		mk (TLocal (to_tvar ~capture:capture n t)) t p
+
+	let check_unification e t = match follow e.etype,follow t with
+		| TAnon an1, TAnon an2 ->
+			PMap.iter (fun s cf ->
+				if not (PMap.mem s an1.a_fields) then an1.a_fields <- PMap.add s cf an1.a_fields
+			) an2.a_fields;
+			e
+		| _ ->
+			e
+
+	let dynamic_field_read e s =
+		Utils.mk_static_call_2 ((!c_reflect)()) "field" [e;mk (TConst (TString s)) !t_string e.epos] e.epos
+
+	let dynamic_field_write e1 s e2 =
+		Utils.mk_static_call_2 ((!c_reflect)()) "setField" [e1;mk (TConst (TString s)) !t_string e1.epos;e2] e1.epos
+
+	let dynamic_field_read_write next_id e1 s op e2 =
+		let id = next_id() in
+		let temp_var = to_tvar id e1.etype in
+		let temp_var_def = mk (TVar(temp_var,Some e1)) e1.etype e1.epos in
+		let temp_local = mk (TLocal temp_var) e1.etype e1.epos in
+		let e_field = dynamic_field_read temp_local s in
+		let e_op = mk (TBinop(op,e_field,e2)) e_field.etype e_field.epos in
+		let e_set_field = dynamic_field_write temp_local s e_op in
+		mk (TBlock [
+			temp_var_def;
+			e_set_field;
+		]) e_set_field.etype e_set_field.epos
+
+	let add_non_locals_to_func e = match e.eexpr with
+		| TFunction tf ->
+			let cur = ref PMap.empty in
+			let save () =
+				let prev = !cur in
+				(fun () ->
+					cur := prev
+				)
+			in
+			let declare v =
+				cur := PMap.add v.v_id v !cur;
+			in
+			List.iter (fun (v,_) -> declare v) tf.tf_args;
+			let non_locals = Hashtbl.create 0 in
+			let rec it e = match e.eexpr with
+				| TVar(v,e1) ->
+					begin match e1 with
+						| Some e ->
+							maybe_continue e
+						| None ->
+							()
+					end;
+					declare v;
+				| TTry(e1,catches) ->
+					it e1;
+					List.iter (fun (v,e) ->
+						let restore = save() in
+						declare v;
+						it e;
+						restore()
+					) catches;
+				| TBinop( (OpAssign | OpAssignOp(_)), { eexpr = TLocal v }, e2) ->
+					if not (PMap.mem v.v_id !cur) then
+						Hashtbl.add non_locals v.v_id v;
+					maybe_continue e2;
+				| TFunction _ ->
+					()
+				| _ ->
+					Type.iter it e
+			and maybe_continue e = match e.eexpr with
+				| TFunction _ ->
+					()
+				| _ ->
+					it e
+			in
+			it tf.tf_expr;
+			let el = Hashtbl.fold (fun k v acc ->
+				(create_non_local v.v_name e.epos) :: acc
+			) non_locals [] in
+			let el = tf.tf_expr :: el in
+			let tf = { tf with tf_expr = { tf.tf_expr with eexpr = TBlock(List.rev el)}} in
+			{e with eexpr = TFunction tf}
+		| _ ->
+			assert false
+
+	let rec transform_function tf ae is_value =
+		let p = tf.tf_expr.epos in
+		let assigns = List.fold_left (fun acc (v,value) -> match value with
+			| None | Some TNull ->
+				acc
+			| Some ct ->
+				let a_local = mk (TLocal v) v.v_type p in
+				let a_null = mk (TConst TNull) v.v_type p in
+				let a_cmp = mk (TBinop(OpEq,a_local,a_null)) !t_bool p in
+				let a_value = mk (TConst(ct)) v.v_type p in
+				let a_assign = mk (TBinop(OpAssign,a_local,a_value)) v.v_type p in
+				let a_if = mk (TIf(a_cmp,a_assign,None)) !t_void p in
+				a_if :: acc
+		) [] tf.tf_args in
+		let body = match assigns with
+			| [] ->
+				tf.tf_expr
+			| _ ->
+				let eb = mk (TBlock (List.rev assigns)) t_dynamic p in
+				Type.concat eb tf.tf_expr
+		in
+		let e1 = to_expr (transform_expr ~next_id:(Some ae.a_next_id) body) in
+		let fn = mk (TFunction({
+			tf_expr = e1;
+			tf_args = tf.tf_args;
+			tf_type = tf.tf_type;
+		})) ae.a_expr.etype p in
+		let fn = add_non_locals_to_func fn in
+		if is_value then begin
+			let new_name = ae.a_next_id() in
+			let new_var = alloc_var new_name tf.tf_type in
+			let new_local = mk (TLocal new_var) fn.etype p in
+			let def = mk (TVar(new_var,Some fn)) fn.etype p in
+			lift_expr1 false ae.a_next_id [def] new_local
+		end else
+			lift_expr fn
+
+	and transform_var_expr ae eo v =
+		let b,new_expr = match eo with
+			| None ->
+				[],None
+			| Some e1 ->
+				let f = transform_expr1 true ae.a_next_id [] e1 in
+				let b = f.a_blocks in
+				b,Some(f.a_expr)
+		in
+		let e = mk (TVar(v,new_expr)) ae.a_expr.etype ae.a_expr.epos in
+		lift_expr ~next_id:(Some ae.a_next_id) ~blocks:b e
+
+	and transform_expr ?(is_value = false) ?(next_id = None) ?(blocks = []) (e : texpr) : adjusted_expr =
+		transform1 (lift_expr ~is_value ~next_id ~blocks e)
+
+	and transform_expr1 is_value next_id blocks e =
+		transform_expr ~is_value ~next_id:(Some next_id) ~blocks e
+
+	and transform_exprs_to_block el tb is_value p next_id =
+		match el with
+			| [e] ->
+				transform_expr ~is_value ~next_id:(Some next_id) e
+			| _ ->
+				let size = List.length el in
+				let res = DynArray.create () in
+				ExtList.List.iteri (fun i e ->
+					(* this removes len(x) calls which are reproduced by the inlined return
+					   of Array.push even if the value is not used *)
+					let is_removable_statement e = (not is_value || i < size-1) &&
+						match e.eexpr with
+						| TField(_, FInstance({cl_path = [],"list"},_,{ cf_name = "length" })) -> true
+						| _ -> false
+					in
+					if not (is_removable_statement e) then
+						let ae = transform_expr ~is_value ~next_id:(Some next_id) e in
+						List.iter (DynArray.add res) ae.a_blocks;
+						DynArray.add res ae.a_expr
+					else
+						()
+				) el;
+				lift_expr (mk (TBlock (DynArray.to_list res)) tb p)
+
+	and transform_switch ae is_value e1 cases edef =
+		let case_functions = ref [] in
+		let case_to_if (el,e) eelse =
+			let val_reversed = List.rev el in
+			let mk_eq e = mk (TBinop(OpEq,e1,e)) !t_bool (punion e1.epos e.epos) in
+			let cond = match val_reversed with
+				| [] ->
+					assert false
+				| [e] ->
+					mk_eq e
+				| e :: el ->
+					List.fold_left (fun eelse e -> mk (TBinop(OpBoolOr,eelse,mk_eq e)) !t_bool (punion eelse.epos e.epos)) (mk_eq e) el
+			in
+			let eif = if is_value then begin
+				let name = ae.a_next_id() in
+				let func = exprs_to_func [e] name ae in
+				case_functions := !case_functions @ func.a_blocks;
+				let call = func.a_expr in
+				mk (TIf(cond,call,eelse)) ae.a_expr.etype ae.a_expr.epos
+			end else
+				mk (TIf(cond,e,eelse)) ae.a_expr.etype e.epos
+			in
+			eif
+		in
+		let rev_cases = List.rev cases in
+		let edef = Some (match edef with
+			| None ->
+				mk (TBlock []) ae.a_expr.etype ae.a_expr.epos
+			| Some e ->
+				e)
+		in
+		let res = match rev_cases,edef with
+			| [],Some edef ->
+				edef
+			| [],None ->
+				(* I don't think that can happen? *)
+				assert false
+			| [case],_ ->
+				case_to_if case edef
+			| case :: cases,_ ->
+				List.fold_left (fun acc case -> case_to_if case (Some acc)) (case_to_if case edef) cases
+		in
+		let res = if is_value then
+			mk (TBlock ((List.rev (res :: !case_functions)))) res.etype res.epos
+		else
+			res
+		in
+		forward_transform res ae
+
+	and transform_string_switch ae is_value e1 cases edef =
+		let length_map = Hashtbl.create 0 in
+		List.iter (fun (el,e) ->
+			List.iter (fun es ->
+				match es.eexpr with
+				| TConst (TString s) ->
+					let l = String.length s in
+					let sl = try
+						Hashtbl.find length_map l
+					with Not_found ->
+						let sl = ref [] in
+						Hashtbl.replace length_map l sl;
+						sl
+					in
+					sl := ([es],e) :: !sl;
+				| _ ->
+					()
+			) el
+		) cases;
+		if Hashtbl.length length_map < 2 then
+			transform_switch ae is_value e1 cases edef
+		else
+			let mk_eq e1 e2 = mk (TBinop(OpEq,e1,e2)) !t_bool (punion e1.epos e2.epos) in
+			let mk_or e1 e2 = mk (TBinop(OpOr,e1,e2)) !t_bool (punion e1.epos e2.epos) in
+			let mk_if (el,e) eo =
+				let eif = List.fold_left (fun eacc e -> mk_or eacc (mk_eq e1 e)) (mk_eq e1 (List.hd el)) (List.tl el) in
+				mk (TIf(Codegen.mk_parent eif,e,eo)) e.etype e.epos
+			in
+			let cases = Hashtbl.fold (fun i el acc ->
+				let eint = mk (TConst (TInt (Int32.of_int i))) !t_int e1.epos in
+				let fs = match List.fold_left (fun eacc ec -> Some (mk_if ec eacc)) edef !el with Some e -> e | None -> assert false in
+				([eint],fs) :: acc
+			) length_map [] in
+			let c_string = match !t_string with TInst(c,_) -> c | _ -> assert false in
+			let cf_length = PMap.find "length" c_string.cl_fields in
+			let ef = mk (TField(e1,FInstance(c_string,[],cf_length))) !t_int e1.epos in
+			let res_var = alloc_var (ae.a_next_id()) ef.etype in
+			let res_local = {ef with eexpr = TLocal res_var} in
+			let var_expr = {ef with eexpr = TVar(res_var,Some ef)} in
+			let e = mk (TBlock [
+				var_expr;
+				mk (TSwitch(res_local,cases,edef)) ae.a_expr.etype e1.epos
+			]) ae.a_expr.etype e1.epos in
+			forward_transform e ae
+
+	and transform_op_assign_op ae e1 op one is_value post =
+		let e1_ = transform_expr e1 ~is_value:true ~next_id:(Some ae.a_next_id) in
+		let handle_as_local temp_local =
+			let ex = ae.a_expr in
+			let res_var = alloc_var (ae.a_next_id()) ex.etype in
+			let res_local = {ex with eexpr = TLocal res_var} in
+			let plus = {ex with eexpr = TBinop(op,temp_local,one)} in
+			let var_expr = {ex with eexpr = TVar(res_var,Some temp_local)} in
+			let assign_expr = {ex with eexpr = TBinop(OpAssign,e1_.a_expr,plus)} in
+			let blocks = if post then
+				[var_expr;assign_expr;res_local]
+			else
+				[assign_expr;temp_local]
+			in
+			(* TODO: block is ignored in the else case? *)
+			let block = e1_.a_blocks @ blocks in
+			if is_value then begin
+				let f = exprs_to_func block (ae.a_next_id()) ae in
+				lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks
+			end else begin
+				let block = e1_.a_blocks @ [assign_expr] in
+				transform_exprs_to_block block ex.etype false ex.epos ae.a_next_id
+			end
+		in
+		match e1_.a_expr.eexpr with
+			| TArray({eexpr = TLocal _},{eexpr = TLocal _})
+			| TField({eexpr = TLocal _},_)
+			| TLocal _ ->
+				handle_as_local e1_.a_expr
+			| TArray(e1,e2) ->
+				let id = ae.a_next_id() in
+				let temp_var_l = alloc_var id e1.etype in
+				let temp_local_l = {e1 with eexpr = TLocal temp_var_l} in
+				let temp_var_l = {e1 with eexpr = TVar(temp_var_l,Some e1)} in
+
+				let id = ae.a_next_id() in
+				let temp_var_r = alloc_var id e2.etype in
+				let temp_local_r = {e2 with eexpr = TLocal temp_var_r} in
+				let temp_var_r = {e2 with eexpr = TVar(temp_var_r,Some e2)} in
+
+				let id = ae.a_next_id() in
+				let temp_var = alloc_var id e1_.a_expr.etype in
+				let temp_local = {e1_.a_expr with eexpr = TLocal temp_var} in
+				let temp_var_expr = {e1_.a_expr with eexpr = TArray(temp_local_l,temp_local_r)} in
+				let temp_var = {e1_.a_expr with eexpr = TVar(temp_var,Some temp_var_expr)} in
+
+				let plus = {ae.a_expr with eexpr = TBinop(op,temp_local,one)} in
+				let assign_expr = {ae.a_expr with eexpr = TBinop(OpAssign,temp_var_expr,plus)} in
+				let block = e1_.a_blocks @ [temp_var_l;temp_var_r;temp_var;assign_expr;if post then temp_local else temp_var_expr] in
+				if is_value then begin
+					let f = exprs_to_func block (ae.a_next_id()) ae in
+					lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks
+				end else
+					transform_exprs_to_block block ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
+			| TField(e1,fa) ->
+				let temp_var_l = alloc_var (ae.a_next_id()) e1.etype in
+				let temp_local_l = {e1 with eexpr = TLocal temp_var_l} in
+				let temp_var_l = {e1 with eexpr = TVar(temp_var_l,Some e1)} in
+
+				let temp_var = alloc_var (ae.a_next_id()) e1_.a_expr.etype in
+				let temp_local = {e1_.a_expr with eexpr = TLocal temp_var} in
+				let temp_var_expr = {e1_.a_expr with eexpr = TField(temp_local_l,fa)} in
+				let temp_var = {e1_.a_expr with eexpr = TVar(temp_var,Some temp_var_expr)} in
+
+				let plus = {ae.a_expr with eexpr = TBinop(op,temp_local,one)} in
+				let assign_expr = {ae.a_expr with eexpr = TBinop(OpAssign,temp_var_expr,plus)} in
+				let block = e1_.a_blocks @ [temp_var_l;temp_var;assign_expr;if post then temp_local else temp_var_expr] in
+				if is_value then begin
+					let f = exprs_to_func block (ae.a_next_id()) ae in
+					lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks
+				end else
+					transform_exprs_to_block block ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
+			| _ ->
+				debug_expr e1_.a_expr;
+				assert false
+
+	and var_to_treturn_expr ?(capture = false) n t p =
+		let x = mk (TLocal (to_tvar ~capture:capture n t)) t p in
+		mk (TReturn (Some x)) t p
+
+	and exprs_to_func exprs name base =
+		let convert_return_expr (expr:texpr) =
+			match expr.eexpr with
+			| TWhile(_,_,_) ->
+				let ret = { expr with eexpr = TReturn (None) } in
+				[expr; ret]
+			| TFunction(f) ->
+				let ret = var_to_treturn_expr name f.tf_type f.tf_expr.epos in
+				[expr;ret]
+			| TBinop(OpAssign, l, r) ->
+				let r = { l with eexpr = TReturn(Some l) } in
+				[expr; r]
+			| x ->
+				let ret_expr = { expr with eexpr = TReturn( Some(expr) )} in
+				[ret_expr]
+		in
+		let def =
+			(let ex = match exprs with
+			| [] -> assert false
+			| [x] ->
+				(let exs = convert_return_expr x in
+				match exs with
+				| [] -> assert false
+				| [x] -> x
+				| x ->
+					match List.rev x with
+					| x::xs ->
+						mk (TBlock exs) x.etype base.a_expr.epos
+					| _ -> assert false)
+
+			| x ->
+				match List.rev x with
+				| x::xs ->
+					(let ret = x in
+					let tail = List.rev xs in
+					let block = tail @ (convert_return_expr ret) in
+					match List.rev block with
+					| x::_ ->
+						mk (TBlock block) x.etype base.a_expr.epos
+					| _ -> assert false)
+				| _ -> assert false
+			in
+			let f1 = { tf_args = []; tf_type = TFun([],ex.etype); tf_expr = ex} in
+			let fexpr = mk (TFunction f1) ex.etype ex.epos in
+			let fvar = to_tvar name fexpr.etype in
+			let f = add_non_locals_to_func fexpr in
+			let assign = { ex with eexpr = TVar(fvar, Some(f))} in
+			let call_expr = (mk (TLocal fvar) fexpr.etype ex.epos ) in
+			let substitute = mk (TCall(call_expr, [])) ex.etype ex.epos in
+			lift_expr ~blocks:[assign] substitute)
+		in
+		match exprs with
+		| [{ eexpr = TFunction({ tf_args = []} as f) } as x] ->
+			let l = to_tlocal_expr name f.tf_type f.tf_expr.epos in
+			let substitute = mk (TCall(l, [])) f.tf_type f.tf_expr.epos in
+			lift_expr ~blocks:[x] substitute
+		| _ -> def
+
+	and transform_call is_value e params ae =
+		let trans is_value blocks e = transform_expr1 is_value ae.a_next_id blocks e in
+		let trans1 e params =
+			let e = trans true [] e in
+			let blocks = e.a_blocks @ (List.flatten (List.map (fun (p) -> p.a_blocks) params)) in
+			let params = List.map (fun (p) -> p.a_expr) params in
+			let e = { ae.a_expr with eexpr = TCall(e.a_expr, params) } in
+			lift_expr ~blocks:blocks e
+		in
+		match e, params with
+		(* the foreach block should not be handled as a value *)
+		| ({ eexpr = TField(_, FStatic({cl_path = ["python";],"Syntax"},{ cf_name = "_foreach" }))} as e, [e1;e2;e3]) ->
+			trans1 e [trans true [] e1; trans true [] e2; trans false [] e3]
+		| (e, params) ->
+			trans1 e (List.map (trans true []) params)
+
+
+	and transform1 ae : adjusted_expr =
+
+		let trans is_value blocks e = transform_expr1 is_value ae.a_next_id blocks e in
+		let lift is_value blocks e = lift_expr1 is_value ae.a_next_id blocks e in
+		let a_expr = ae.a_expr in
+		match ae.a_is_value,ae.a_expr.eexpr with
+		| (is_value,TBlock [x]) ->
+			trans is_value [] x
+		| (false,TBlock []) ->
+			lift_expr a_expr
+		| (true,TBlock []) ->
+			lift_expr (mk (TConst TNull) ae.a_expr.etype ae.a_expr.epos)
+		| (false,TBlock el) ->
+			transform_exprs_to_block el ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
+		| (true,TBlock el) ->
+			let name = ae.a_next_id() in
+			let block,tr = match List.rev el with
+				| e :: el ->
+					List.rev ((mk (TReturn (Some e)) t_dynamic e.epos) :: el),e.etype
+				| [] ->
+					assert false
+			in
+			let my_block = transform_exprs_to_block block tr false ae.a_expr.epos ae.a_next_id in
+			let fn = mk (TFunction {
+				tf_args = [];
+				tf_type = tr;
+				tf_expr = my_block.a_expr;
+			}) ae.a_expr.etype ae.a_expr.epos in
+			let t_var = alloc_var name ae.a_expr.etype in
+			let f = add_non_locals_to_func fn in
+			let fn_assign = mk (TVar (t_var,Some f)) ae.a_expr.etype ae.a_expr.epos in
+			let ev = mk (TLocal t_var) ae.a_expr.etype ae.a_expr.epos in
+			let substitute = mk (TCall(ev,[])) ae.a_expr.etype ae.a_expr.epos in
+			lift_expr ~blocks:[fn_assign] substitute
+		| (is_value,TFunction(f)) ->
+			transform_function f ae is_value
+		| (_,TVar(v,None)) ->
+
+			transform_var_expr ae None v
+
+ 		| (false, TVar(v,Some({ eexpr = TUnop((Increment | Decrement as unop),post_fix,({eexpr = TLocal _ | TField({eexpr = TConst TThis},_)} as ve))} as e1))) ->
+			let one = {e1 with eexpr = TConst (TInt (Int32.of_int 1))} in
+			let op = if unop = Increment then OpAdd else OpSub in
+			let inc = {e1 with eexpr = TBinop(op,ve,one)} in
+			let inc_assign = {e1 with eexpr = TBinop(OpAssign,ve,inc)} in
+			let var_assign = {e1 with eexpr = TVar(v,Some ve)} in
+			if post_fix = Postfix then
+				lift true [var_assign] inc_assign
+			else
+				lift true [inc_assign] var_assign
+		| (_,TVar(v,eo)) ->
+			transform_var_expr ae eo v
+		| (_,TFor(v,e1,e2)) ->
+			let a1 = trans true [] e1 in
+			let a2 = to_expr (trans false [] e2) in
+
+			let name = (ae.a_next_id ()) in
+			let t_var = alloc_var name e1.etype in
+
+			let mk_local v p = { eexpr = TLocal v; etype = v.v_type; epos = p } in
+
+			let ev = mk_local t_var e1.epos in
+			let ehasnext = mk (TField(ev,quick_field e1.etype "hasNext")) (tfun [] (!t_bool) ) e1.epos in
+			let ehasnext = mk (TCall(ehasnext,[])) ehasnext.etype ehasnext.epos in
+
+			let enext = mk (TField(ev,quick_field e1.etype "next")) (tfun [] v.v_type) e1.epos in
+			let enext = mk (TCall(enext,[])) v.v_type e1.epos in
+
+			let var_assign = mk (TVar (v,Some enext)) v.v_type a_expr.epos in
+
+			let ebody = Type.concat var_assign (a2) in
+
+			let var_decl = mk (TVar (t_var,Some a1.a_expr)) (!t_void) e1.epos in
+			let twhile = mk (TWhile((mk (TParenthesis ehasnext) ehasnext.etype ehasnext.epos),ebody,NormalWhile)) (!t_void) e1.epos in
+
+			let blocks = a1.a_blocks @ [var_decl] in
+
+			lift_expr ~blocks: blocks twhile
+		| (_,TReturn None) ->
+			ae
+		| (_,TReturn (Some ({eexpr = TFunction f} as ef))) ->
+			let n = ae.a_next_id() in
+			let e1 = to_expr (trans false [] f.tf_expr) in
+			let f = mk (TFunction {
+				tf_args = f.tf_args;
+				tf_type = f.tf_type;
+				tf_expr = e1;
+			}) ef.etype ef.epos in
+			let f1 = add_non_locals_to_func f in
+			let var_n = alloc_var n ef.etype in
+			let f1_assign = mk (TVar(var_n,Some f1)) !t_void f1.epos in
+			let var_local = mk (TLocal var_n) ef.etype f1.epos in
+			let er = mk (TReturn (Some var_local)) t_dynamic  ae.a_expr.epos in
+			lift true [f1_assign] er
+
+		| (_,TReturn Some(x)) ->
+			let x1 = trans true [] x in
+			(match x1.a_blocks with
+				| [] ->
+					lift true [] { ae.a_expr with eexpr = TReturn(Some x1.a_expr) }
+				| blocks ->
+					let f = exprs_to_func (blocks @ [x1.a_expr]) (ae.a_next_id()) ae in
+					lift true f.a_blocks {a_expr with eexpr = TReturn (Some f.a_expr)})
+		| (_, TParenthesis(e1)) ->
+			let e1 = trans true [] e1 in
+			let p = { ae.a_expr with eexpr = TParenthesis(e1.a_expr)} in
+			lift true e1.a_blocks p
+		| (_, TEnumParameter(e1,ef,i)) ->
+			let e1 = trans true [] e1 in
+			let p = { ae.a_expr with eexpr = TEnumParameter(e1.a_expr,ef,i)} in
+			lift true e1.a_blocks p
+		| (true, TIf(econd, eif, eelse)) ->
+			(let econd1 = trans true [] econd in
+			let eif1 = trans true [] eif in
+			let eelse1 = match eelse with
+				| Some x -> Some(trans true [] x)
+				| None -> None
+			in
+			let blocks = [] in
+			let eif2, blocks =
+				match eif1.a_blocks with
+				| [] -> eif1.a_expr, blocks
+				| x ->
+					let regular =
+						let fname = eif1.a_next_id () in
+						let f = exprs_to_func (List.append eif1.a_blocks [eif1.a_expr]) fname ae in
+						f.a_expr, List.append blocks f.a_blocks
+					in
+					match eif1.a_blocks with
+					| [{ eexpr = TVar(_, Some({ eexpr = TFunction(_)}))} as b] ->
+						eif1.a_expr, List.append blocks [b]
+					| _ -> regular
+			in
+			let eelse2, blocks =
+				match eelse1 with
+				| None -> None, blocks
+				| Some({ a_blocks = []} as x) -> Some(x.a_expr), blocks
+				| Some({ a_blocks = b} as eelse1) ->
+					let regular =
+						let fname = eelse1.a_next_id () in
+						let f = exprs_to_func (List.append eelse1.a_blocks [eelse1.a_expr]) fname ae in
+						Some(f.a_expr), List.append blocks f.a_blocks
+					in
+					match b with
+					| [{ eexpr = TVar(_, Some({ eexpr = TFunction(f)}))} as b] ->
+						Some(eelse1.a_expr), List.append blocks [b]
+					| _ -> regular
+			in
+			let blocks = List.append econd1.a_blocks blocks in
+			let new_if = { ae.a_expr with eexpr = TIf(econd1.a_expr, eif2, eelse2) } in
+			match blocks with
+			| [] ->
+				let meta = Meta.Custom(":ternaryIf"), [], ae.a_expr.epos in
+				let ternary = { ae.a_expr with eexpr = TMeta(meta, new_if) } in
+				lift_expr ~blocks:blocks ternary
+			| b ->
+				let f = exprs_to_func (List.append blocks [new_if]) (ae.a_next_id ()) ae in
+				lift_expr ~blocks:f.a_blocks f.a_expr)
+		| (false, TIf(econd, eif, eelse)) ->
+			let econd = trans true [] econd in
+			let eif = to_expr (trans false [] eif) in
+			let eelse = match eelse with
+			| Some(x) -> Some(to_expr (trans false [] x))
+			| None -> None
+			in
+			let new_if = { ae.a_expr with eexpr = TIf(econd.a_expr, eif, eelse) } in
+			lift false econd.a_blocks new_if
+		| (false, TWhile(econd, e1, NormalWhile)) ->
+			let econd1 = trans true [] econd in
+			let e11 = to_expr (trans false [] e1) in
+			let new_while = mk (TWhile(econd1.a_expr,e11,NormalWhile)) a_expr.etype a_expr.epos in
+			lift false econd1.a_blocks new_while
+		| (true, TWhile(econd, ebody, NormalWhile)) ->
+			let econd = trans true [] econd in
+			let ebody = to_expr (trans false [] ebody) in
+			let ewhile = { ae.a_expr with eexpr = TWhile(econd.a_expr, ebody, NormalWhile) } in
+			let eval = { ae.a_expr with eexpr = TConst(TNull) } in
+			let f = exprs_to_func (List.append econd.a_blocks [ewhile; eval]) (ae.a_next_id ()) ae in
+			lift true f.a_blocks f.a_expr
+		| (false, TWhile(econd, ebody, DoWhile)) ->
+			let not_expr = { econd with eexpr = TUnop(Not, Prefix, econd) } in
+			let break_expr = mk TBreak !t_void econd.epos in
+			let if_expr = mk (TIf(not_expr, break_expr, None)) (!t_void) econd.epos in
+			let new_e = match ebody.eexpr with
+				| TBlock(exprs) -> { econd with eexpr = TBlock( List.append exprs [if_expr]) }
+				| _ -> { econd with eexpr = TBlock( List.append [ebody] [if_expr]) }
+			in
+			let true_expr = mk (TConst(TBool(true))) econd.etype ae.a_expr.epos in
+			let new_expr = { ae.a_expr with eexpr = TWhile( true_expr, new_e, NormalWhile) } in
+			forward_transform new_expr ae
+
+		| (is_value, TSwitch(e, cases, edef)) ->
+			begin match follow e.etype with
+				| TInst({cl_path = [],"str"},_) ->
+					transform_string_switch ae is_value e cases edef
+				| _ ->
+					transform_switch ae is_value e cases edef
+			end
+		(* anon field access on optional params *)
+		| (is_value, TField(e,FAnon cf)) when Meta.has Meta.Optional cf.cf_meta ->
+			let e = dynamic_field_read e cf.cf_name in
+			transform_expr ~is_value:is_value e
+		| (is_value, TBinop(OpAssign,{eexpr = TField(e1,FAnon cf)},e2)) when Meta.has Meta.Optional cf.cf_meta ->
+			let e = dynamic_field_write e1 cf.cf_name e2 in
+			transform_expr ~is_value:is_value e
+		| (is_value, TBinop(OpAssignOp op,{eexpr = TField(e1,FAnon cf)},e2)) when Meta.has Meta.Optional cf.cf_meta ->
+			let e = dynamic_field_read_write ae.a_next_id e1 cf.cf_name op e2 in
+			transform_expr ~is_value:is_value e
+		(* TODO we need to deal with Increment, Decrement too!
+
+		| (_, TUnop( (Increment | Decrement) as unop, op,{eexpr = TField(e1,FAnon cf)})) when Meta.has Meta.Optional cf.cf_meta  ->
+			let  = dynamic_field_read e cf.cf_name in
+
+			let e = dynamic_field_read_write_unop ae.a_next_id e1 cf.cf_name unop op in
+			Printf.printf "dyn read write\n";
+			transform_expr e
+		*)
+		(*
+			anon field access with non optional members like iterator, length, split must be handled too, we need to Reflect on them too when it's a runtime method
+		*)
+		| (is_value, TUnop( (Increment | Decrement) as unop, op, e)) ->
+			let one = { ae.a_expr with eexpr = TConst(TInt(Int32.of_int(1)))} in
+			let is_postfix = match op with
+			| Postfix -> true
+			| Prefix -> false in
+			let op = match unop with
+			| Increment -> OpAdd
+			| Decrement -> OpSub
+			| _ -> assert false in
+			transform_op_assign_op ae e op one is_value is_postfix
+		| (_, TUnop(op, Prefix, e)) ->
+			let e1 = trans true [] e in
+			let r = { a_expr with eexpr = TUnop(op, Prefix, e1.a_expr) } in
+			lift_expr ~blocks:e1.a_blocks r
+
+		| (is_value, TField(e,FDynamic s)) ->
+			let e = dynamic_field_read e s in
+			transform_expr ~is_value:is_value e
+		| (is_value, TBinop(OpAssign,{eexpr = TField(e1,FDynamic s)},e2)) ->
+			let e = dynamic_field_write e1 s e2 in
+			transform_expr ~is_value:is_value e
+		| (is_value, TBinop(OpAssignOp op,{eexpr = TField(e1,FDynamic s)},e2)) ->
+			let e = dynamic_field_read_write ae.a_next_id e1 s op e2 in
+			transform_expr ~is_value:is_value e
+		| (is_value, TField(e1, FClosure(Some ({cl_path = [],("str" | "list")},_),cf))) ->
+			let e = dynamic_field_read e1 cf.cf_name in
+			transform_expr ~is_value:is_value e
+		| (is_value, TBinop(OpAssign, left, right))->
+			(let left = trans true [] left in
+			let right = trans true [] right in
+			let r = { a_expr with eexpr = TBinop(OpAssign, left.a_expr, right.a_expr)} in
+			if is_value then
+				(let blocks = List.concat [left.a_blocks; right.a_blocks; [r]] in
+				let f = exprs_to_func blocks (ae.a_next_id ()) ae in
+				lift true f.a_blocks f.a_expr)
+			else
+				lift false (List.append left.a_blocks right.a_blocks) r)
+		| (is_value, TBinop(OpAssignOp(x), left, right)) ->
+			let right = trans true [] right in
+			let v = right.a_expr in
+			let res = transform_op_assign_op ae left x v is_value false in
+			lift true (List.append right.a_blocks res.a_blocks) res.a_expr
+		| (_, TBinop(op, left, right))->
+			(let left = trans true [] left in
+			let right = trans true [] right in
+			let r = { a_expr with eexpr = TBinop(op, left.a_expr, right.a_expr)} in
+			lift false (List.append left.a_blocks right.a_blocks) r)
+
+		| (true, TThrow(x)) ->
+			let block = TBlock([a_expr; { a_expr with eexpr = TConst(TNull) }]) in
+			let r = { a_expr with eexpr = block } in
+			forward_transform r ae
+		| (false, TThrow(x)) ->
+			let x = trans true [] x in
+			let r = { a_expr with eexpr = TThrow(x.a_expr)} in
+			lift false x.a_blocks r
+		| (_, TNew(c, tp, params)) ->
+			let params = List.map (trans true []) params in
+			let blocks = List.flatten (List.map (fun (p) -> p.a_blocks) params) in
+			let params = List.map (fun (p) -> p.a_expr) params in
+			let e = { a_expr with eexpr = TNew(c, tp, params) } in
+			lift false blocks e
+		| (is_value, TCall(e,params)) ->
+			transform_call is_value e params ae
+		| (_, TArray(e1, e2)) ->
+			let e1 = trans true [] e1 in
+			let e2 = trans true [] e2 in
+			let r = { a_expr with eexpr = TArray(e1.a_expr, e2.a_expr)} in
+			let blocks = List.append e1.a_blocks e2.a_blocks in
+			lift_expr ~blocks:blocks r
+		| (false, TTry(etry, catches)) ->
+			let etry = trans false [] etry in
+			let catches = List.map (fun(v,e) -> v, trans false [] e) catches in
+			let blocks = List.flatten (List.map (fun (_,e) -> e.a_blocks) catches) in
+			let catches = List.map (fun(v,e) -> v, e.a_expr) catches in
+			let r = { a_expr with eexpr = TTry(etry.a_expr, catches)} in
+			let blocks = List.append etry.a_blocks blocks in
+			lift false blocks r
+		| (true, TTry(etry, catches)) ->
+
+			let id = ae.a_next_id () in
+			let temp_var = to_tvar id a_expr.etype in
+			let temp_var_def = { a_expr with eexpr = TVar(temp_var, None) } in
+			let temp_local = { a_expr with eexpr = TLocal(temp_var)} in
+			let mk_temp_assign right = { a_expr with eexpr = TBinop(OpAssign, temp_local, right)} in
+			let etry = mk_temp_assign etry in
+			let catches = List.map (fun (v,e)-> v, mk_temp_assign e) catches in
+			let new_try = { a_expr with eexpr = TTry(etry, catches)} in
+			let block = [temp_var_def; new_try; temp_local] in
+			let new_block = { a_expr with eexpr = TBlock(block)} in
+			forward_transform new_block ae
+		| (_, TObjectDecl(fields)) ->
+			let fields = List.map (fun (name,ex) -> name, trans true [] ex) fields in
+			let blocks = List.flatten (List.map (fun (_,ex) -> ex.a_blocks) fields) in
+			let fields = List.map (fun (name,ex) -> name, ex.a_expr) fields in
+			let r = { a_expr with eexpr = (TObjectDecl(fields) )} in
+			lift_expr ~blocks r
+		| (_, TArrayDecl(values)) ->
+			let values = List.map (trans true []) values in
+			let blocks = List.flatten (List.map (fun (v) -> v.a_blocks) values) in
+			let exprs = List.map (fun (v) -> v.a_expr) values in
+			let r = { a_expr with eexpr = TArrayDecl exprs } in
+			lift_expr ~blocks:blocks r
+		| (is_value, TCast(e1,Some mt)) ->
+			let e = Codegen.default_cast ~vtmp:(ae.a_next_id()) (match !como with Some com -> com | None -> assert false) e1 mt ae.a_expr.etype ae.a_expr.epos in
+			transform_expr ~is_value:is_value e
+		| (is_value, TCast(e,None)) ->
+			let e = trans is_value [] e in
+			let r = { a_expr with eexpr = TCast(e.a_expr, None)} in
+			lift_expr ~blocks:e.a_blocks r
+		| (_, TField(e,f)) ->
+			let e = trans true [] e in
+			let r = { a_expr with eexpr = TField(e.a_expr, f) } in
+			lift_expr ~blocks:e.a_blocks r
+		| (is_value, TMeta(m, e)) ->
+			let e = trans is_value [] e in
+			let r = { a_expr with eexpr = TMeta(m, e.a_expr); etype = e.a_expr.etype } in
+			lift_expr ~blocks:e.a_blocks r
+		| ( _, TLocal _ ) -> lift_expr a_expr
+
+		| ( _, TConst _ ) -> lift_expr a_expr
+		| ( _, TTypeExpr _ ) -> lift_expr a_expr
+		| ( _, TUnop _ ) -> assert false
+		| ( true, TWhile(econd, ebody, DoWhile) ) ->
+			let new_expr = trans false [] a_expr in
+			let f = exprs_to_func (new_expr.a_blocks @ [new_expr.a_expr]) (ae.a_next_id()) ae in
+			lift_expr ~is_value:true ~blocks:f.a_blocks f.a_expr
+
+		| ( _, TBreak ) | ( _, TContinue ) ->
+			lift_expr a_expr
+
+	and transform e =
+		to_expr (transform1 (lift_expr e))
+
+	and forward_transform e base =
+		transform1 (lift_expr1 base.a_is_value base.a_next_id base.a_blocks e)
+
+	let transform_to_value e =
+		to_expr (transform1 (lift_expr e ~is_value:true))
+
+end
+
+module Printer = struct
+
+	type print_context = {
+		pc_indent : string;
+		pc_next_anon_func : unit -> string;
+		pc_debug : bool;
+		pc_com : Common.context;
+	}
+
+	let has_feature pctx = Common.has_feature pctx.pc_com
+
+	let add_feature pctx = Common.add_feature pctx.pc_com
+
+	let create_context =
+		let n = ref (-1) in
+		(fun indent com debug -> {
+				pc_indent = indent;
+				pc_next_anon_func = (fun () -> incr n; Printf.sprintf "anon_%i" !n);
+				pc_debug = debug;
+				pc_com = com;
+			}
+		)
+
+	let tabs = ref ""
+
+	let opt o f s = match o with
+		| None -> ""
+		| Some v -> s ^ (f v)
+
+	(* TODO: both of these are crazy *)
+
+	let is_type p t =
+		(fun r ->
+			let x = t_infos r in
+			(String.concat "." (fst x.mt_path)) = p && (snd x.mt_path) = t
+		)
+
+	let is_type1 p s =
+		(fun t -> match follow t with
+			| TInst(c,_) -> (is_type p s)(TClassDecl c)
+			| TAbstract(a,_) -> (is_type p s)(TAbstractDecl a)
+			| TEnum(en,_) -> (is_type p s)(TEnumDecl en)
+			| _ -> false
+		)
+
+	let is_underlying_string t = match follow t with
+		| TAbstract(a,tl) -> (is_type1 "" "str")(Abstract.get_underlying_type a tl)
+		| _ -> false
+	let is_underlying_array t = match follow t with
+		| TAbstract(a,tl) -> (is_type1 "" "list")(Abstract.get_underlying_type a tl)
+		| _ -> false
+
+	let rec is_anon_or_dynamic t = match follow t with
+		| TAbstract(a,tl) ->
+			is_anon_or_dynamic (Abstract.get_underlying_type a tl)
+		| TAnon _ | TDynamic _ -> true
+		| _ -> false
+
+	let handle_keywords s =
+		KeywordHandler.handle_keywords s
+
+	let print_unop = function
+		| Increment | Decrement -> assert false
+		| Not -> "not "
+		| Neg -> "-";
+		| NegBits -> "~"
+
+	let print_binop = function
+		| OpAdd -> "+"
+		| OpSub -> "-"
+		| OpMult -> "*"
+		| OpDiv -> "/"
+		| OpAssign -> "="
+		| OpEq -> "=="
+		| OpNotEq -> "!="
+		| OpGt -> ">"
+		| OpGte -> ">="
+		| OpLt -> "<"
+		| OpLte -> "<="
+		| OpAnd -> "&"
+		| OpOr -> "|"
+		| OpXor -> "^"
+		| OpBoolAnd -> "and"
+		| OpBoolOr -> "or"
+		| OpShl -> "<<"
+		| OpShr -> ">>"
+		| OpUShr -> ">>"
+		| OpMod -> "%"
+		| OpInterval | OpArrow | OpAssignOp _ -> assert false
+
+	let print_string s =
+		Printf.sprintf "\"%s\"" (Ast.s_escape s)
+
+	let print_constant = function
+		| TThis -> "self"
+		| TNull -> "None"
+		| TBool(true) -> "True"
+		| TBool(false) -> "False"
+		| TString(s) -> print_string s
+		| TInt(i) -> Int32.to_string i
+		| TFloat s -> s
+		| TSuper -> "super"
+
+	let print_base_type tp =
+		try
+			begin match Meta.get Meta.Native tp.mt_meta with
+				| _,[EConst(String s),_],_ -> s
+				| _ -> raise Not_found
+			end
+		with Not_found ->
+			let pack,name = tp.mt_path in
+			(String.concat "_" pack) ^ (if pack = [] then name else "_" ^ name)
+
+	let print_module_type mt = print_base_type (t_infos mt)
+
+	let print_metadata (name,_,_) =
+		Printf.sprintf "@%s" name
+
+	let rec remove_outer_parens e = match e.eexpr with
+		| TParenthesis(e) -> remove_outer_parens e
+		| TMeta((Meta.Custom ":ternaryIf",_,_),_) -> e
+		| TMeta(_,e) -> remove_outer_parens e
+		| _ -> e
+
+	let print_args args p =
+		let had_value = ref false in
+		let had_var_args = ref false in
+		let had_kw_args = ref false in
+		let sl = List.map (fun (v,cto) ->
+			let check_err () = if !had_var_args || !had_kw_args then error "Arguments after KwArgs/VarArgs are not allowed" p in
+			KeywordHandler.check_var_declaration v;
+			let name = handle_keywords v.v_name in
+			match follow v.v_type with
+				| TAbstract({a_path = ["python"],"KwArgs"},_) ->
+					if !had_kw_args then error "Arguments after KwArgs are not allowed" p;
+					had_kw_args := true;
+					"**" ^ name
+				| TAbstract({a_path = ["python"],"VarArgs"},_) ->
+					check_err ();
+					had_var_args := true;
+					"*" ^ name
+				| _ ->
+					check_err ();
+					name ^ match cto with
+						| None when !had_value -> " = None"
+						| None -> ""
+						| Some ct ->
+							had_value := true;
+							Printf.sprintf " = %s" (print_constant ct)
+		) args in
+		String.concat "," sl
+
+	let rec print_op_assign_right pctx e =
+		match e.eexpr with
+			| TIf({eexpr = TParenthesis econd},eif,Some eelse)
+			| TIf(econd,eif,Some eelse) ->
+				Printf.sprintf "%s if %s else %s" (print_expr pctx eif) (print_expr pctx econd) (print_expr pctx eelse)
+			| _ ->
+				print_expr pctx (remove_outer_parens e)
+
+	and print_var pctx v eo =
+		match eo with
+			| Some ({eexpr = TFunction tf} as e) ->
+				print_function pctx tf (Some v.v_name) e.epos
+			| _ ->
+				let s_init = match eo with
+					| None -> "None"
+					| Some e -> print_op_assign_right pctx e
+				in
+				Printf.sprintf "%s = %s" (handle_keywords v.v_name) s_init
+
+	and print_function pctx tf name p =
+		let s_name = match name with
+			| None -> pctx.pc_next_anon_func()
+			| Some s -> handle_keywords s
+		in
+		let s_args = print_args tf.tf_args p in
+		let s_expr = print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} tf.tf_expr in
+		Printf.sprintf "def %s(%s):\n%s\t%s" s_name s_args pctx.pc_indent s_expr
+
+	and print_tarray_list pctx e1 e2 =
+		let s1 = (print_expr pctx e1) in
+		let s2 = (print_expr pctx e2) in
+		let default = Printf.sprintf "python_internal_ArrayImpl._get(%s, %s)" s1 s2 in
+
+		let handle_index =
+			match e2.eexpr with
+			| TConst TInt index ->
+				if Int32.to_int index >= 0 then
+					Printf.sprintf "(%s[%s] if %s < len(%s) else None)" s1 s2 s2 s1
+				else
+					"None"
+			| TLocal _ ->
+				Printf.sprintf "(%s[%s] if %s >= 0 and %s < len(%s) else None)" s1 s2 s2 s2 s1
+			| _ ->
+				default
+		in
+		match e1.eexpr with
+		| TLocal _ -> handle_index
+		| TField ({eexpr=(TConst TThis | TLocal _)},_) -> handle_index
+		| _ -> default
+
+	and print_expr pctx e =
+		let indent = pctx.pc_indent in
+		let print_expr_indented e = print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} e in
+		match e.eexpr with
+			| TConst ct ->
+				print_constant ct
+			| TTypeExpr mt ->
+				print_module_type mt
+			| (TLocal v | TParenthesis({ eexpr = (TLocal v) })) ->
+				handle_keywords v.v_name
+			| TEnumParameter(e1,_,index) ->
+				Printf.sprintf "%s.params[%i]" (print_expr pctx e1) index
+			| TArray(e1,e2) when (is_type1 "" "list")(e1.etype) || is_underlying_array e1.etype ->
+				print_tarray_list pctx e1 e2
+			| TArray({etype = t} as e1,e2) when is_anon_or_dynamic t ->
+				Printf.sprintf "HxOverrides.arrayGet(%s, %s)" (print_expr pctx e1) (print_expr pctx e2)
+			| TArray(e1,e2) ->
+				Printf.sprintf "%s[%s]" (print_expr pctx e1) (print_expr pctx e2)
+			| TBinop(OpAssign, {eexpr = TArray(e1,e2)}, e3) when (is_type1 "" "list")(e1.etype) || is_underlying_array e1.etype ->
+				Printf.sprintf "python_internal_ArrayImpl._set(%s, %s, %s)" (print_expr pctx e1) (print_expr pctx e2) (print_expr pctx e3)
+			| TBinop(OpAssign,{eexpr = TArray({etype = t} as e1,e2)},e3) when is_anon_or_dynamic t ->
+				Printf.sprintf "HxOverrides.arraySet(%s,%s,%s)" (print_expr pctx e1) (print_expr pctx e2) (print_expr pctx e3)
+			| TBinop(OpAssign,{eexpr = TArray(e1,e2)},e3) ->
+				Printf.sprintf "%s[%s] = %s" (print_expr pctx e1) (print_expr pctx e2) (print_expr pctx (remove_outer_parens e3) )
+			| TBinop(OpAssign,{eexpr = TField(ef1,fa)},e2) ->
+				Printf.sprintf "%s = %s" (print_field pctx ef1 fa true) (print_op_assign_right pctx e2)
+			| TBinop(OpAssign,e1,e2) ->
+				Printf.sprintf "%s = %s" (print_expr pctx e1) (print_expr pctx (remove_outer_parens e2))
+			| TBinop(op,e1,({eexpr = TBinop(_,_,_)} as e2)) ->
+				print_expr pctx { e with eexpr = TBinop(op, e1, { e2 with eexpr = TParenthesis(e2) })}
+			| TBinop(OpEq,{eexpr = TCall({eexpr = TLocal {v_name = "__typeof__"}},[e1])},e2) ->
+				begin match e2.eexpr with
+					| TConst(TString s) ->
+						begin match s with
+							| "string" -> Printf.sprintf "Std._hx_is(%s, str)" (print_expr pctx e1)
+							| "boolean" -> Printf.sprintf "Std._hx_is(%s, bool)" (print_expr pctx e1)
+							| "number" -> Printf.sprintf "Std._hx_is(%s, float)" (print_expr pctx e1)
+							| _ -> assert false
+						end
+					| _ ->
+						assert false
+				end
+			| TBinop(OpEq,e1,({eexpr = TConst TNull} as e2)) ->
+				Printf.sprintf "(%s is %s)" (print_expr pctx e1) (print_expr pctx e2)
+			| TBinop(OpNotEq,e1,({eexpr = TConst TNull} as e2)) ->
+				Printf.sprintf "(%s is not %s)" (print_expr pctx e1) (print_expr pctx e2)
+			| TBinop(OpEq|OpNotEq as op,e1, e2) ->
+				let ops = match op with
+					| OpEq -> "is", "==", "HxOverrides.eq"
+					| OpNotEq -> "is not", "!=", "not HxOverrides.eq"
+					| _ -> assert false
+				in
+				let third (_,_,x) = x in
+				let fst (x,_,_) = x in
+				let snd (_,x,_) = x in
+				let is_list_or_anon x = begin match x with
+					| TInst({cl_path = [],("list")},_) -> true
+					| TAnon _ -> true
+					| _ -> false
+				end in
+				let is_const_byte x =
+					match x.eexpr with
+					| TConst TInt x ->
+						let x = Int32.to_int x in
+						x >= 0 && x <= 256
+					| _ -> false
+				in
+				(match follow e1.etype, follow e2.etype with
+				| TAbstract({a_path = [],("Int")}, _),TAbstract({a_path = [],("Int")}, _) when is_const_byte e2 || is_const_byte e1 ->
+					Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (snd ops) (print_expr pctx e2)
+					(* the following optimization causes a problem with polygonal unit tests
+					   see: https://github.com/HaxeFoundation/haxe/issues/2952
+					*)
+					(* Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (fst ops) (print_expr pctx e2) *)
+				| TInst({cl_path = [],("list")},_), _ ->
+					Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (fst ops) (print_expr pctx e2)
+				| TDynamic _, TDynamic _ ->
+					Printf.sprintf "%s(%s,%s)" (third ops) (print_expr pctx e1) (print_expr pctx e2)
+				| TDynamic _, x | x, TDynamic _ when is_list_or_anon x ->
+					Printf.sprintf "%s(%s,%s)" (third ops) (print_expr pctx e1) (print_expr pctx e2)
+				| _,_ -> Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (snd ops) (print_expr pctx e2))
+			| TBinop(OpMod,e1,e2) when (is_type1 "" "Int")(e1.etype) && (is_type1 "" "Int")(e2.etype) ->
+				Printf.sprintf "(%s %% %s)" (print_expr pctx e1) (print_expr pctx e2)
+			| TBinop(OpMod,e1,e2) ->
+				Printf.sprintf "HxOverrides.modf(%s, %s)" (print_expr pctx e1) (print_expr pctx e2)
+			| TBinop(OpUShr,e1,e2) ->
+				Printf.sprintf "HxOverrides.rshift(%s, %s)" (print_expr pctx e1) (print_expr pctx e2)
+			| TBinop(OpAdd,e1,e2) when (is_type1 "" "str")(e.etype) || is_underlying_string e.etype ->
+				let follow_parens e = match e.eexpr with
+					| TParenthesis e -> e
+					| _ -> e
+				in
+				let rec is_safe_string x =
+					match (follow_parens x).eexpr with
+					| TBinop(OpAdd, e1, e2) -> is_safe_string e1 && is_safe_string e2
+					| TCall (e1,_) ->
+						let id = print_expr pctx (follow_parens e1) in
+						(match id with
+						| "Std.string" -> true
+						| _ -> false)
+					| TConst (TString s) -> true
+					| _ -> false
+				in
+				let rec safe_string ex =
+					match ex.eexpr, ex.etype with
+						| e, _ when is_safe_string ex -> print_expr pctx ex
+						| TBinop(OpAdd, e1, e2), x when (is_type1 "" "str")(x) -> Printf.sprintf "(%s + %s)" (safe_string e1) (safe_string e2)
+						| (TLocal(_)),x when (is_type1 "" "str")(x) ->
+							(*
+								we could add this pattern too, but is it sideeffect free??
+								| TField({ eexpr = TLocal(_)},_)
+							*)
+							let s = (print_expr pctx ex) in
+							Printf.sprintf "(\"null\" if %s is None else %s)" s s
+						| _,x when (is_type1 "" "str")(x) -> Printf.sprintf "HxOverrides.stringOrNull(%s)" (print_expr pctx ex)
+						| _,_ ->
+							if has_feature pctx "Std.string" then
+								Printf.sprintf "Std.string(%s)" (print_expr pctx ex)
+							else
+								Printf.sprintf "str(%s)" (print_expr pctx ex)
+				in
+				let e1_str = safe_string e1 in
+				let e2_str = safe_string e2 in
+				Printf.sprintf "(%s + %s)" e1_str e2_str
+			| TBinop(OpAdd,e1,e2) when (match follow e.etype with TDynamic _ -> true | _ -> false) ->
+				Printf.sprintf "python_Boot._add_dynamic(%s,%s)" (print_expr pctx e1) (print_expr pctx e2)
+			| TBinop(op,e1,e2) ->
+				Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (print_binop op) (print_expr pctx e2)
+			| TField(e1,fa) ->
+				print_field pctx e1 fa false
+			| TParenthesis e1 ->
+				Printf.sprintf "(%s)" (print_expr pctx e1)
+			| TObjectDecl fl ->
+				let fl2 = ref fl in
+				begin match follow e.etype with
+					| TAnon an ->
+						PMap.iter (fun s cf ->
+							if not (List.mem_assoc s fl) then fl2 := (s,null cf.cf_type cf.cf_pos) :: !fl2
+						) an.a_fields
+					| _ ->
+						()
+				end;
+				Printf.sprintf "_hx_AnonObject(%s)" (print_exprs_named pctx ", " !fl2)
+			| TArrayDecl el ->
+				Printf.sprintf "[%s]" (print_exprs pctx ", " el)
+			| TCall(e1,el) ->
+				print_call pctx e1 el e
+			| TNew(c,_,el) ->
+				let id = print_base_type (t_infos (TClassDecl c)) in
+				Printf.sprintf "%s(%s)" id (print_exprs pctx ", " el)
+			| TUnop(Not,Prefix,e1) ->
+				Printf.sprintf "(%s%s)" (print_unop Not) (print_expr pctx e1)
+			| TUnop(op,Prefix,e1) ->
+				Printf.sprintf "%s%s" (print_unop op) (print_expr pctx e1)
+			| TFunction tf ->
+				print_function pctx tf None e.epos
+			| TVar (v,eo) ->
+				KeywordHandler.check_var_declaration v;
+				print_var pctx v eo
+			| TBlock [] ->
+				Printf.sprintf "pass"
+			| TBlock [{ eexpr = TBlock _} as b] ->
+				print_expr pctx b
+			| TBlock el ->
+				let old = !tabs in
+				tabs := pctx.pc_indent;
+				let s = print_block_exprs pctx ("\n" ^ !tabs) pctx.pc_debug el in
+				tabs := old;
+				Printf.sprintf "%s" s
+			| TIf(econd,eif,(Some {eexpr = TIf _} as eelse)) ->
+				print_if_else pctx econd eif eelse true
+			| TIf(econd,eif,eelse) ->
+				print_if_else pctx econd eif eelse false
+			| TWhile(econd,e1,NormalWhile) ->
+				Printf.sprintf "while %s:\n%s\t%s" (print_expr pctx (remove_outer_parens econd)) indent (print_expr_indented e1)
+			| TWhile(econd,e1,DoWhile) ->
+				error "Currently not supported" e.epos
+			| TTry(e1,catches) ->
+				print_try pctx e1 catches
+			| TReturn eo ->
+				Printf.sprintf "return%s" (opt eo (print_op_assign_right pctx) " ")
+			| TBreak ->
+				"break"
+			| TContinue ->
+				"continue"
+			| TThrow e1 ->
+				let rec is_native_exception t =
+					match Abstract.follow_with_abstracts t with
+					| TInst ({ cl_path = [],"BaseException" }, _) ->
+						true
+					| TInst ({ cl_super = Some csup }, _) ->
+						is_native_exception (TInst(fst csup, snd csup))
+					| _ ->
+						false
+				in
+				if is_native_exception e1.etype then
+					Printf.sprintf "raise %s" (print_expr pctx e1)
+				else
+					Printf.sprintf "raise _HxException(%s)" (print_expr pctx e1)
+			| TCast(e1,None) ->
+				print_expr pctx e1
+			| TMeta((Meta.Custom ":ternaryIf",_,_),{eexpr = TIf(econd,eif,Some eelse)}) ->
+				Printf.sprintf "(%s if %s else %s)" (print_expr pctx eif) (print_expr pctx econd) (print_expr pctx eelse)
+			| TMeta(_,e1) ->
+				print_expr pctx e1
+			| TSwitch _ | TCast(_, Some _) | TFor _ | TUnop(_,Postfix,_) ->
+				assert false
+
+	and print_if_else pctx econd eif eelse as_elif =
+		let econd1 = match econd.eexpr with
+			| TParenthesis e -> e
+			| _ -> econd
+		in
+		let if_str = print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} eif in
+		let indent = pctx.pc_indent in
+		let else_str = if as_elif then
+			opt eelse (print_expr pctx) "el"
+		else
+			opt eelse (print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent}) (Printf.sprintf "else:\n%s\t" indent)
+		in
+		let else_str = if else_str = "" then "" else "\n" ^ indent ^ else_str in
+		Printf.sprintf "if %s:\n%s\t%s%s" (print_expr pctx (remove_outer_parens econd1)) indent if_str else_str
+
+	and print_field pctx e1 fa is_assign =
+		let obj = match e1.eexpr with
+			| TConst TSuper -> "super()"
+			| _ -> print_expr pctx e1
+		in
+		let name = field_name fa in
+		let is_extern = (match fa with
+		| FInstance(c,_,_) -> c.cl_extern
+		| FStatic(c,_) -> c.cl_extern
+		| _ -> false)
+		in
+		let do_default () =
+			Printf.sprintf "%s.%s" obj (if is_extern then name else (handle_keywords name))
+		in
+		let call_override s =
+			match s with
+			| "iterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift" | "join" | "push" | "map" | "filter" -> true
+			| _ -> false
+		in
+		match fa with
+			(* we need to get rid of these cases in the transformer, how is this handled in js *)
+			| FInstance(c,_,{cf_name = "length"}) when (is_type "" "list")(TClassDecl c) ->
+				Printf.sprintf "len(%s)" (print_expr pctx e1)
+			| FInstance(c,_,{cf_name = "length"}) when (is_type "" "str")(TClassDecl c) ->
+				Printf.sprintf "len(%s)" (print_expr pctx e1)
+			| FStatic(c,{cf_name = "fromCharCode"}) when (is_type "" "str")(TClassDecl c) ->
+				Printf.sprintf "HxString.fromCharCode"
+			| FStatic({cl_path = ["python";"internal"],"UBuiltins"},{cf_name = s}) ->
+				s
+			| FInstance _ | FStatic _ ->
+				do_default ()
+			| FAnon cf when is_assign && call_override(name) ->
+				begin match follow cf.cf_type with
+					| TFun([],_) ->
+						Printf.sprintf "python_lib_FuncTools.partial(HxOverrides.%s, %s)" name obj
+					| _ ->
+						do_default()
+				end
+			| _ ->
+				do_default()
+
+	and print_try pctx e1 catches =
+		let has_catch_all = List.exists (fun (v,_) -> match v.v_type with
+			| TDynamic _ -> true
+			| _ -> false
+		) catches in
+		let has_only_catch_all = has_catch_all && begin match catches with
+			| [_] -> true
+			| _ -> false
+		end in
+		let print_catch pctx i (v,e) =
+			KeywordHandler.check_var_declaration v;
+			let is_empty_expr = begin match e.eexpr with
+				| TBlock [] -> true
+				| _ -> false
+			end in
+			let indent = pctx.pc_indent in
+			(* Don't generate assignment to catch variable when catch expression is an empty block *)
+			let assign = if is_empty_expr then "" else Printf.sprintf "%s = _hx_e1\n%s" v.v_name indent in
+			let handle_base_type bt =
+				let t = print_base_type bt in
+				let print_type_check t_str =
+					Printf.sprintf "if isinstance(_hx_e1, %s):\n%s\t%s\t%s" t_str indent assign (print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} e)
+				in
+				let res = match t with
+				| "str" -> print_type_check "str"
+				| "Bool" -> print_type_check "bool"
+				| "Int" -> print_type_check "int"
+				| "Float" -> print_type_check "float"
+				| t -> print_type_check t
+				in
+				if i > 0 then
+					indent ^ "el" ^ res
+				else
+					res
+			in
+			match follow v.v_type with
+				| TDynamic _ ->
+					begin if has_only_catch_all then
+						Printf.sprintf "%s%s" assign (print_expr pctx e)
+					else
+						(* Dynamic is always the last block *)
+						Printf.sprintf "%selse:\n\t%s%s\t%s" indent indent assign (print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} e)
+					end
+				| TInst(c,_) ->
+					handle_base_type (t_infos (TClassDecl c))
+				| TEnum(en,_) ->
+					handle_base_type (t_infos (TEnumDecl en))
+				| TAbstract(a,_) ->
+					handle_base_type (t_infos (TAbstractDecl a))
+				| _ ->
+					assert false
+		in
+		let indent = pctx.pc_indent in
+		let print_expr_indented e = print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} e in
+		let try_str = Printf.sprintf "try:\n%s\t%s\n%s" indent (print_expr_indented e1) indent in
+		let except = if has_feature pctx "has_throw" then
+			Printf.sprintf "except Exception as _hx_e:\n%s\t_hx_e1 = _hx_e.val if isinstance(_hx_e, _HxException) else _hx_e\n%s\t" indent indent
+		else
+			Printf.sprintf "except Exception as _hx_e:\n%s\t_hx_e1 = _hx_e\n%s\t" indent indent
+		in
+		let catch_str = String.concat (Printf.sprintf "\n") (ExtList.List.mapi (fun i catch -> print_catch {pctx with pc_indent = "\t" ^ pctx.pc_indent} i catch) catches) in
+		let except_end = if not has_catch_all then Printf.sprintf "\n%s\telse:\n%s\t\traise _hx_e" indent indent else "" in
+		Printf.sprintf "%s%s%s%s" try_str except catch_str except_end
+
+	and print_call2 pctx e1 el =
+		let id = print_expr pctx e1 in
+		match id,el with
+			| "__define_feature__",[_;e] ->
+				print_expr pctx e
+			| "super",_ ->
+				let s_el = (print_call_args pctx e1 el) in
+				Printf.sprintf "super().__init__(%s)" s_el
+			| ("python_Syntax._pythonCode"),[({ eexpr = TConst (TString code) } as ecode); {eexpr = TArrayDecl tl}] ->
+				let exprs = Array.of_list tl in
+				let i = ref 0 in
+				let err msg =
+					let pos = { ecode.epos with pmin = ecode.epos.pmin + !i } in
+					error msg pos
+				in
+				let regex = Str.regexp "[{}]" in
+				let rec loop m = match m with
+					| [] -> ""
+					| Str.Text txt :: tl ->
+						i := !i + String.length txt;
+						txt ^ (loop tl)
+					| Str.Delim a :: Str.Delim b :: tl when a = b ->
+						i := !i + 2;
+						a ^ (loop tl)
+					| Str.Delim "{" :: Str.Text n :: Str.Delim "}" :: tl ->
+						(try
+						let expr = Array.get exprs (int_of_string n) in
+						let txt = print_expr pctx expr in
+						i := !i + 2 + String.length n;
+						txt ^ (loop tl)
+					with | Failure "int_of_string" ->
+						err ("Index expected. Got " ^ n)
+					| Invalid_argument _ ->
+						err ("Out-of-bounds pythonCode special parameter: " ^ n))
+					| Str.Delim x :: _ ->
+						err ("Unexpected " ^ x)
+				in
+				loop (Str.full_split regex code)
+			| ("python_Syntax._pythonCode"), [e] ->
+				print_expr pctx e
+			| "python_Syntax._callNamedUntyped",el ->
+				let res,fields = match List.rev el with
+					| {eexpr = TObjectDecl fields} :: el ->
+						List.rev el,fields
+					| _ ->
+						assert false
+				in
+				begin match res with
+					| e1 :: [] ->
+						Printf.sprintf "%s(%s)" (print_expr pctx e1) (print_params_named pctx ", " fields)
+					| e1 :: el ->
+						Printf.sprintf "%s(%s, %s)" (print_expr pctx e1) (print_exprs pctx ", " el) (print_params_named pctx ", " fields)
+					| [] ->
+						Printf.sprintf "%s(%s)" (print_expr pctx e1) (print_params_named pctx ", " fields)
+				end
+			| "python_Syntax.varArgs",[e1] ->
+				"*" ^ (print_expr pctx e1)
+			| "python_Syntax.call" ,e1 :: [{eexpr = TArrayDecl el}]->
+				Printf.sprintf "%s(%s)" (print_expr pctx e1) (print_exprs pctx ", " el)
+			| "python_Syntax.field",[e1;{eexpr = TConst(TString id)}] ->
+				Printf.sprintf "%s.%s" (print_expr pctx e1) id
+			| "python_Syntax._tuple", [{eexpr = TArrayDecl el}] ->
+				(match el with
+				| [e] ->
+					Printf.sprintf "(%s,)" (print_expr pctx e)
+				| _ ->
+					Printf.sprintf "(%s)" (print_exprs pctx ", " el))
+			| "python_Syntax._arrayAccess", e1 :: {eexpr = TArrayDecl el} :: etrail ->
+				let trailing_colon = match etrail with
+					| [{eexpr = TConst(TBool(true))}] -> true
+					| _ -> false
+				in
+				Printf.sprintf "%s[%s%s]" (print_expr pctx e1) (print_exprs pctx ":" el) (if trailing_colon then ":" else "")
+			| "python_Syntax.isIn",[e1;e2] ->
+				Printf.sprintf "%s in %s" (print_expr pctx e1) (print_expr pctx e2)
+			| "python_Syntax.delete",[e1] ->
+				Printf.sprintf "del %s" (print_expr pctx e1)
+			| "python_Syntax.binop",[e0;{eexpr = TConst(TString id)};e2] ->
+				Printf.sprintf "(%s %s %s)" (print_expr pctx e0) id (print_expr pctx e2)
+			| "python_Syntax.assign",[e0;e1] ->
+				Printf.sprintf "%s = %s" (print_expr pctx e0) (print_expr pctx e1)
+			| "python_Syntax.arraySet",[e1;e2;e3] ->
+				Printf.sprintf "%s[%s] = %s" (print_expr pctx e1) (print_expr pctx e2) (print_expr pctx e3)
+			| "python_Syntax._newInstance", e1 :: [{eexpr = TArrayDecl el}] ->
+				Printf.sprintf "%s(%s)" (print_expr pctx e1) (print_exprs pctx ", " el)
+			| "python_Syntax.opPow", [e1;e2] ->
+				Printf.sprintf "(%s ** %s)" (print_expr pctx e1) (print_expr pctx e2)
+ 			| "python_Syntax._foreach",[e1;e2;e3] ->
+				let pctx = {pctx with pc_indent = "\t" ^ pctx.pc_indent} in
+				let i = pctx.pc_indent in
+				Printf.sprintf "for %s in %s:\n%s%s" (print_expr pctx e1) (print_expr pctx e2) i (print_expr pctx e3)
+			| _,el ->
+				Printf.sprintf "%s(%s)" id (print_call_args pctx e1 el)
+
+	and print_call pctx e1 el call_expr =
+		let get_native_fields t = match follow t with
+			| TAnon(a) ->
+				let fold f cf acc =
+					if Meta.has Meta.Native cf.cf_meta then begin
+						let _, args, mp = Meta.get Meta.Native cf.cf_meta in
+						match args with
+						| [( EConst(String s),_)] -> PMap.add f s acc
+						| _ -> acc
+					end else acc
+				in
+				let mapping = PMap.foldi fold a.a_fields PMap.empty in
+				mapping
+			| _ -> PMap.empty
+		in
+		let native_fields_str native_fields =
+			let fold_dict k v acc =
+				let prefix = if acc = "" then "" else "," in
+				Printf.sprintf "%s%s\"%s\":\"%s\"" acc prefix (handle_keywords k) v
+			in
+			PMap.foldi fold_dict native_fields ""
+		in
+		match e1.eexpr, el with
+			| TLocal { v_name = "`trace" }, [e;infos] ->
+				if has_feature pctx "haxe.Log.trace" then begin
+					"haxe_Log.trace(" ^ (print_expr pctx e) ^ "," ^ (print_expr pctx infos) ^ ")"
+				end else begin
+					"print(str(" ^ (print_expr pctx e) ^ "))"
+				end
+			| TField(e1,((FAnon {cf_name = (("join" | "push" | "map" | "filter") as s)}) | FDynamic (("join" | "push" | "map" | "filter") as s))), [x] ->
+				Printf.sprintf "HxOverrides.%s(%s, %s)" s (print_expr pctx e1) (print_expr pctx x)
+			| TField(e1,((FAnon {cf_name = (("iterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift") as s)}) | FDynamic (("iterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift") as s))), [] ->
+				Printf.sprintf "HxOverrides.%s(%s)" s (print_expr pctx e1)
+			| TField(_, (FStatic({cl_path = ["python"; "_KwArgs"], "KwArgs_Impl_"},{ cf_name="fromT" }))), [e2]  ->
+				let t = match follow call_expr.etype with
+				| TAbstract(_, [t]) -> t
+				| _ -> assert false
+				in
+				let native_fields = get_native_fields t in
+				if PMap.is_empty native_fields then
+					print_call2 pctx e1 el
+				else
+					let s1 = native_fields_str native_fields in
+					Printf.sprintf "python__KwArgs_KwArgs_Impl_.fromT(HxOverrides.mapKwArgs(%s, {%s}))" (print_expr pctx e2) s1
+			| TField(_, (FStatic({cl_path = ["python"; "_KwArgs"], "KwArgs_Impl_"},{ cf_name="toDictHelper" }))), [e2; et]  ->
+				let native_fields = get_native_fields et.etype in
+				if PMap.is_empty native_fields then
+					print_call2 pctx e1 el
+				else
+					let s1 = native_fields_str native_fields in
+					Printf.sprintf "python__KwArgs_KwArgs_Impl_.toDictHelper(HxOverrides.reverseMapKwArgs(%s, {%s}), None)" (print_expr pctx e2) s1
+			| _,_ ->
+				print_call2 pctx e1 el
+
+	and print_call_args pctx e1 el =
+		let print_arg pctx i x =
+			let e = match x.eexpr, follow x.etype with
+				| TConst TNull, TAbstract({a_path = ["python"],"KwArgs"},_) -> "{}"
+				| TConst TNull, TAbstract({a_path = ["python"],"VarArgs"},_) -> "[]"
+				| _ -> (print_expr pctx x)
+			in
+			let prefix = match e1.eexpr, follow x.etype with
+				(* the should not apply for the instance methods of the abstract itself *)
+				| TField(_, FStatic({cl_path = ["python"; "_KwArgs"],"KwArgs_Impl_"},f)), _ when i == 0 && Meta.has Meta.Impl f.cf_meta -> ""
+				| TField(_, FStatic({cl_path = ["python"; "_VarArgs"],"VarArgs_Impl_"},f)), _ when i == 0 && Meta.has Meta.Impl f.cf_meta -> ""
+				| _, TAbstract({a_path = ["python"],"KwArgs"},_) -> "**"
+				| _, TAbstract({a_path = ["python"],"VarArgs"},_) -> "*"
+				| _, _ -> ""
+			in
+			prefix ^ e
+		in
+		String.concat "," (ExtList.List.mapi (print_arg pctx) el)
+
+	and print_exprs pctx sep el =
+		String.concat sep (List.map (print_expr pctx) el)
+
+	and last_debug_comment = ref ("")
+
+	and print_block_exprs pctx sep print_debug_comment el =
+		if print_debug_comment then begin
+			let el = List.fold_left (fun acc e ->
+				let line = Lexer.get_error_line e.epos in
+				let debug_line = (Printf.sprintf "# %s:%i" e.epos.pfile line) in
+				let res = if (!last_debug_comment) <> debug_line then
+					(print_expr pctx e) :: debug_line :: acc
+				else
+					(print_expr pctx e) :: acc
+				in
+				last_debug_comment := debug_line;
+				res
+			) [] el in
+			String.concat sep (List.rev el)
+		end else
+			print_exprs pctx sep el
+
+	and print_exprs_named pctx sep fl =
+		let args = String.concat sep (List.map (fun (s,e) -> Printf.sprintf "'%s': %s" (handle_keywords s) (print_expr pctx e)) fl) in
+		Printf.sprintf "{%s}" args
+	and print_params_named pctx sep fl =
+		let args = String.concat sep (List.map (fun (s,e) -> Printf.sprintf "%s= %s" (handle_keywords s) (print_expr pctx e)) fl) in
+		Printf.sprintf "%s" args
+	let handle_keywords s =
+		KeywordHandler.handle_keywords s
+end
+
+module Generator = struct
+	type context = {
+		com : Common.context;
+		buf : Buffer.t;
+		packages : (string,int) Hashtbl.t;
+		mutable static_inits : (unit -> unit) list;
+		mutable class_inits : (unit -> unit) list;
+		mutable indent_count : int;
+		transform_time : float;
+		print_time : float;
+	}
+
+	let has_feature ctx = Common.has_feature ctx.com
+	let add_feature ctx = Common.add_feature ctx.com
+
+	type class_field_infos = {
+		cfd_fields : string list;
+		cfd_props : string list;
+		cfd_methods : string list;
+	}
+
+	type import_type =
+		| IModule of string
+		| IObject of string * string
+
+	let mk_context com = {
+		com = com;
+		buf = Buffer.create 16000;
+		packages = Hashtbl.create 0;
+		static_inits = [];
+		class_inits = [];
+		indent_count = 0;
+		transform_time = 0.;
+		print_time = 0.;
+	}
+
+	(* Transformer interface *)
+
+	let transform_expr e =
+		(* let e = Codegen.UnificationCallback.run Transformer.check_unification e in *)
+		Transformer.transform e
+
+	let transform_to_value e =
+		(* let e = Codegen.UnificationCallback.run Transformer.check_unification e in *)
+		Transformer.transform_to_value e
+
+	(* Printer interface *)
+
+	let get_path mt =
+		Printer.print_base_type mt
+
+	let tfunc_str f pctx name p =
+		Printer.print_function pctx f name p
+
+	let texpr_str e pctx =
+		Printer.print_expr pctx e
+
+	let handle_keywords s =
+		Printer.handle_keywords s
+
+	(* Helper *)
+
+	let get_full_name mt =
+		(* TODO: haxe source is crazy *)
+		s_type_path mt.mt_path
+
+	let collect_class_field_data cfl =
+		let fields = DynArray.create () in
+		let props = DynArray.create () in
+		let methods = DynArray.create () in
+		List.iter (fun cf ->
+			match cf.cf_kind with
+				| Var({v_read = AccResolve}) ->
+					()
+				| Var _ when is_extern_field cf ->
+					()
+				| Var({v_read = AccCall}) ->
+					if Meta.has Meta.IsVar cf.cf_meta then
+						DynArray.add fields cf.cf_name
+					else
+						DynArray.add props cf.cf_name
+				| Var _ ->
+					DynArray.add fields cf.cf_name
+				| _ ->
+					DynArray.add methods cf.cf_name
+		) cfl;
+		{
+			cfd_fields = DynArray.to_list fields;
+			cfd_props = DynArray.to_list props;
+			cfd_methods = DynArray.to_list methods;
+		}
+
+	let collect_class_statics_data cfl =
+		let fields = DynArray.create () in
+		List.iter (fun cf ->
+			if not (is_extern_field cf) then
+				DynArray.add fields cf.cf_name
+		) cfl;
+		DynArray.to_list fields
+
+	let filter_py_metas metas =
+		List.filter (fun (n,_,_) -> match n with Meta.Custom ":python" -> true | _ -> false) metas
+
+	let get_members_with_init_expr c =
+		List.filter (fun cf -> match cf.cf_kind with
+			| Var _ when is_extern_field cf -> false
+			| Var _ when cf.cf_expr = None -> true
+			| _ -> false
+		) c.cl_ordered_fields
+
+	(* Printing *)
+
+	let spr ctx s =
+		Buffer.add_string ctx.buf s
+
+	let spr_line ctx s =
+		Buffer.add_string ctx.buf s;
+		Buffer.add_string ctx.buf "\n"
+
+	let print ctx =
+		Printf.kprintf (fun s -> begin
+			Buffer.add_string ctx.buf s
+		end)
+
+	let newline ctx =
+		if not (Buffer.length ctx.buf = 0) then spr ctx "\n"
+
+
+	(* Generating functions *)
+
+	let gen_py_metas ctx metas indent =
+		List.iter (fun (n,el,_) ->
+			match el with
+				| [EConst(String s),_] ->
+					print ctx "%s@%s\n" indent s
+				| _ ->
+					assert false
+		) metas
+
+	let gen_expr ctx e field indent =
+		let pctx = Printer.create_context ("\t" ^ indent) ctx.com ctx.com.debug in
+		let e = match e.eexpr with
+			| TFunction(f) ->
+				{e with eexpr = TBlock [e]}
+			| _ ->
+				e
+		in
+		let expr2 = transform_to_value e in
+		let name = "_hx_init_" ^ (String.concat "_" (ExtString.String.nsplit field ".")) in
+		let maybe_split_expr expr2 = match expr2.eexpr with
+			| TBlock es when es <> [] && field <> "" ->
+				begin match List.rev es with
+					| e_last :: el ->
+						let new_last = {e_last with eexpr = TReturn (Some e_last)} in
+						let new_block = {expr2 with eexpr = TBlock (List.rev (new_last :: el))} in
+						let v_name = alloc_var name (tfun [] e_last.etype) in
+						let f_name = mk (TLocal v_name) v_name.v_type e_last.epos in
+						let call_f = mk (TCall(f_name,[])) e_last.etype e_last.epos in
+						Some new_block,call_f
+					| _ ->
+						assert false
+				end
+			| _ ->
+				None,expr2
+		in
+		let r = maybe_split_expr expr2 in
+		match r with
+			| Some e1,e2 ->
+				let expr_string_1 = texpr_str e1 pctx in
+				let expr_string_2 = texpr_str e2 pctx in
+				print ctx "%sdef %s():\n\t%s" indent name expr_string_1;
+				newline ctx;
+				print ctx "%s%s = %s" indent field expr_string_2;
+			| None,e2 ->
+				let expr_string_2 = texpr_str e2 pctx in
+				if field = "" then
+					spr ctx expr_string_2
+				else
+					print ctx "%s%s = %s" indent field expr_string_2
+
+	let gen_func_expr ctx e c name metas extra_args indent stat p =
+		let pctx = Printer.create_context indent ctx.com ctx.com.debug in
+		let e = match e.eexpr with
+			| TFunction(f) ->
+				let args = List.map (fun s ->
+					alloc_var s t_dynamic,None
+				) extra_args in
+				{e with eexpr = TFunction {f with tf_args = args @ f.tf_args}}
+			| _ ->
+				e
+		in
+		if stat then begin
+			newline ctx;
+			spr ctx indent;
+			spr ctx "@staticmethod\n"
+		end;
+		let expr1 = transform_expr e in
+		let expr_string = match expr1.eexpr with
+			| TFunction f ->
+				tfunc_str f pctx (Some name) p
+			| _ ->
+				Printf.sprintf "%s = %s" name (texpr_str expr1 pctx)
+		in
+		gen_py_metas ctx metas indent;
+		spr ctx indent;
+		spr ctx expr_string
+
+	let gen_class_constructor ctx c cf =
+		let member_inits = get_members_with_init_expr c in
+		let py_metas = filter_py_metas cf.cf_meta in
+		begin match cf.cf_expr with
+			| Some ({eexpr = TFunction f} as ef) ->
+				let ethis = mk (TConst TThis) (TInst(c,List.map snd c.cl_params)) cf.cf_pos in
+				let member_data = List.map (fun cf ->
+					let ef = mk (TField(ethis,FInstance(c,[],cf))) cf.cf_type cf.cf_pos in (* TODO *)
+					mk (TBinop(OpAssign,ef,null ef.etype ef.epos)) ef.etype ef.epos
+				) member_inits in
+				let e = concat (mk (TBlock member_data) ctx.com.basic.tvoid cf.cf_pos) f.tf_expr in
+				let ef = {ef with eexpr = TFunction {f with tf_expr = e}} in
+				cf.cf_expr <- Some ef;
+
+				newline ctx;
+				newline ctx;
+				gen_func_expr ctx ef c "__init__" py_metas ["self"] "\t" false cf.cf_pos
+			| _ ->
+				assert false
+		end
+
+	let gen_class_field ctx c p cf =
+		let field = handle_keywords cf.cf_name in
+		begin match cf.cf_expr with
+			| None ->
+				()(* print ctx "\t# var %s" field *)
+			| Some e ->
+				newline ctx;
+				newline ctx;
+				begin match cf.cf_kind with
+					| Method _ ->
+						let py_metas = filter_py_metas cf.cf_meta in
+						gen_func_expr ctx e c field py_metas ["self"] "\t" false cf.cf_pos;
+
+					| _ ->
+						gen_expr ctx e (Printf.sprintf "# var %s" field) "\t";
+				end
+		end
+
+	let gen_class_empty_constructor ctx p cfl =
+		if has_feature ctx "Type.createEmptyInstance" then begin
+			newline ctx;
+			newline ctx;
+			print ctx "\t@staticmethod\n\tdef _hx_empty_init(_hx_o):";
+			let found_fields = ref false in
+			List.iter (fun cf -> match cf.cf_kind with
+					| Var ({v_read = AccResolve | AccCall}) ->
+						()
+					| Var _ ->
+						found_fields := true;
+						newline ctx;
+						print ctx "\t\t_hx_o.%s = None" (handle_keywords cf.cf_name)
+					| _ ->
+						()
+			) cfl;
+			if not !found_fields then
+				spr ctx "\t\tpass"
+		end else begin
+			newline ctx
+		end
+
+	let gen_class_statics ctx c p =
+		let methods, other = List.partition (fun cf ->
+			match cf.cf_kind with
+			| Method _ -> (match cf.cf_expr with Some _ -> true | _ -> false)
+			| _ -> false
+		) c.cl_ordered_statics in
+
+		(* generate non methods *)
+		let has_empty_static_vars = ref false in
+		List.iter (fun cf ->
+			let p = get_path (t_infos (TClassDecl c)) in
+			let field = handle_keywords cf.cf_name in
+			match cf.cf_expr with
+			| None ->
+				has_empty_static_vars := true;
+				newline ctx;
+				print ctx "\t%s = None" field
+			| Some e ->
+				(let f = fun () ->
+					newline ctx;
+					gen_expr ctx e (Printf.sprintf "%s.%s" p field) "";
+				in
+				ctx.static_inits <- f :: ctx.static_inits)
+		) other;
+
+		(* generate static methods *)
+		let has_static_methods = ref false in
+		List.iter (fun cf ->
+			has_static_methods := true;
+			let field = handle_keywords cf.cf_name in
+			let py_metas = filter_py_metas cf.cf_meta in
+			let e = match cf.cf_expr with Some e -> e | _ -> assert false in
+			newline ctx;
+			gen_func_expr ctx e c field py_metas [] "\t" true cf.cf_pos;
+		) methods;
+
+		!has_static_methods || !has_empty_static_vars
+
+	let gen_class_init ctx c =
+		match c.cl_init with
+			| None ->
+				()
+			| Some e ->
+				let is_math = c.cl_path = ([], "Math") in
+				let math_feature = has_feature ctx "Math" in
+				let f = if is_math && not math_feature then
+					fun () -> ()
+				else fun () ->
+					let e = transform_expr e in
+					newline ctx;
+					spr ctx (texpr_str e (Printer.create_context "" ctx.com ctx.com.debug));
+				in
+				ctx.class_inits <- f :: ctx.class_inits
+
+	let gen_class ctx c =
+		if not c.cl_extern then begin
+			let is_nativegen = Meta.has Meta.NativeGen c.cl_meta in
+			let mt = (t_infos (TClassDecl c)) in
+			let p = get_path mt in
+			let p_name = get_full_name mt in
+			let x = collect_class_field_data c.cl_ordered_fields in
+			let p_super = match c.cl_super with
+				| None ->
+					None
+				| Some (csup,_) ->
+					Some (get_path (t_infos (TClassDecl csup)))
+			in
+			let p_interfaces = List.map (fun (c,tl) ->
+				get_path (t_infos (TClassDecl c))
+			) c.cl_implements in
+
+			newline ctx;
+			newline ctx;
+			newline ctx;
+			print ctx "class %s" p;
+			(match p_super with Some p -> print ctx "(%s)" p | _ -> ());
+			spr ctx ":";
+
+			let use_pass = ref true in
+
+			if not is_nativegen then begin
+				if has_feature ctx "python._hx_class_name" then begin
+					use_pass := false;
+					print ctx "\n\t_hx_class_name = \"%s\"" p_name
+				end;
+
+				let print_field names field quote =
+					if has_feature ctx ("python." ^ field) then try
+						let q s = if quote then "\"" ^ s ^ "\"" else s in
+						let s = match names with
+							| [] when (match c.cl_super with Some _ -> false | _ -> true) ->
+								(* always overwrite parent's class fields *)
+								raise Exit
+							| _ ->
+								"[" ^ (String.concat ", " (List.map q names)) ^ "]"
+						in
+						use_pass := false;
+						print ctx "\n\t%s = %s" field s
+					with Exit -> ()
+				in
+
+				print_field x.cfd_fields "_hx_fields" true;
+				print_field x.cfd_methods "_hx_methods" true;
+				(* TODO: It seems strange to have a separation for member fields but a plain _hx_statics for static ones *)
+				print_field (collect_class_statics_data c.cl_ordered_statics) "_hx_statics" true;
+				print_field (p_interfaces) "_hx_interfaces" false;
+
+				if has_feature ctx "python._hx_super" then (match p_super with
+					| None -> ()
+					| Some ps ->
+						use_pass := false;
+						print ctx "\n\t_hx_super = %s\n" ps
+				);
+
+			end;
+
+			begin match c.cl_constructor with
+				| Some cf -> gen_class_constructor ctx c cf;
+				| None -> ()
+			end;
+			List.iter (fun cf -> gen_class_field ctx c p cf) c.cl_ordered_fields;
+
+			let has_inner_static = gen_class_statics ctx c p in
+
+			let has_empty_constructor = match ((Meta.has Meta.NativeGen c.cl_meta) || c.cl_interface), c.cl_ordered_fields with
+				| true,_
+				| _, [] ->
+					false
+				| _ ->
+					gen_class_empty_constructor ctx p c.cl_ordered_fields;
+					has_feature ctx "Type.createEmptyInstance"
+			in
+
+			let use_pass = !use_pass && (not has_inner_static) && (not has_empty_constructor) && match x.cfd_methods with
+				| [] -> c.cl_constructor = None
+				| _ -> c.cl_interface
+			in
+			if use_pass then spr ctx "\n\tpass";
+
+			if not is_nativegen then begin
+				if has_feature ctx "python._hx_class" then print ctx "\n%s._hx_class = %s" p p;
+				if has_feature ctx "python._hx_classes" then print ctx "\n_hx_classes[\"%s\"] = %s" p_name p;
+			end
+		end;
+		gen_class_init ctx c
+
+	let gen_enum_metadata ctx en p =
+		let meta = Codegen.build_metadata ctx.com (TEnumDecl en) in
+		match meta with
+			| None ->
+				()
+			| Some e ->
+				newline ctx;
+				print ctx "%s.__meta__ = " p;
+				gen_expr ctx e "" ""
+
+	let gen_enum ctx en =
+		let mt = (t_infos (TEnumDecl en)) in
+		let p = get_path mt in
+		let p_name = get_full_name mt in
+
+		let enum_constructs = PMap.foldi (fun k ef acc -> ef :: acc) en.e_constrs [] in
+		let enum_constructs = List.sort (fun a b -> if a.ef_index < b.ef_index then -1 else if a.ef_index > b.ef_index then 1 else 0) enum_constructs in
+
+		newline ctx;
+		newline ctx;
+		print ctx "class %s(Enum):" p;
+
+		let use_pass = ref true in
+
+		if has_feature ctx "python._hx_class_name" then begin
+			use_pass := false;
+			print ctx "\n\t_hx_class_name = \"%s\"" p_name
+		end;
+		if has_feature ctx "python._hx_constructs" then begin
+			let fix = match enum_constructs with [] -> "" | _ -> "\"" in
+			let enum_constructs_str = fix ^ (String.concat ("\", \"") (List.map (fun ef -> ef.ef_name) enum_constructs)) ^ fix in
+			use_pass := false;
+			print ctx "\n\t_hx_constructs = [%s]" enum_constructs_str;
+		end;
+
+		let const_constructors,param_constructors = List.partition (fun ef ->
+			match follow ef.ef_type with
+			| TFun(_,_) -> false
+			| _ -> true
+		) enum_constructs in
+
+		List.iter (fun ef ->
+			match follow ef.ef_type with
+			| TFun(args, _) ->
+				let print_args args =
+					let had_optional = ref false in
+					let sl = List.map (fun (n,o,_) ->
+						let name = handle_keywords n in
+						let arg_value = if !had_optional then
+							"= None"
+						else if o then begin
+							had_optional := true;
+							" = None"
+						end else
+							""
+						in
+						Printf.sprintf "%s%s" name arg_value
+					) args in
+					String.concat "," sl
+				in
+				let f = handle_keywords ef.ef_name in
+				let param_str = print_args args in
+				let args_str = String.concat "," (List.map (fun (n,_,_) -> handle_keywords n) args) in
+				newline ctx;
+				newline ctx;
+				print ctx "\t@staticmethod\n\tdef %s(%s):\n" f param_str;
+				print ctx "\t\treturn %s(\"%s\", %i, [%s])" p ef.ef_name ef.ef_index args_str;
+				use_pass := false;
+			| _ -> assert false
+		) param_constructors;
+
+		if !use_pass then spr ctx "\n\tpass";
+
+		List.iter (fun ef ->
+			(* TODO: haxe source has api.quoteString for ef.ef_name *)
+			let f = handle_keywords ef.ef_name in
+			newline ctx;
+			print ctx "%s.%s = %s(\"%s\", %i, list())" p f p ef.ef_name ef.ef_index
+		) const_constructors;
+
+		if has_feature ctx "python._hx_class" then print ctx "\n%s._hx_class = %s" p p;
+		if has_feature ctx "python._hx_classes" then print ctx "\n_hx_classes[\"%s\"] = %s" p_name p;
+
+		gen_enum_metadata ctx en p
+
+	let gen_abstract ctx a =
+		newline ctx;
+		newline ctx;
+		newline ctx;
+		let mt = (t_infos (TAbstractDecl a)) in
+		let p = get_path mt in
+		let p_name = get_full_name mt in
+		print ctx "class %s:" p;
+
+		let use_pass = ref true in
+
+		if has_feature ctx "python._hx_class_name" then begin
+			use_pass := false;
+			print ctx "\n\t_hx_class_name = \"%s\"" p_name
+		end;
+
+		(match a.a_impl with
+		| Some c ->
+			List.iter (fun cf ->
+				use_pass := false;
+				if cf.cf_name = "_new" then
+					gen_class_constructor ctx c cf
+				else
+					gen_class_field ctx c p cf
+			) c.cl_ordered_statics
+		| None -> ());
+
+		if !use_pass then spr ctx "\n\tpass";
+
+		if has_feature ctx "python._hx_class" then print ctx "\n%s._hx_class = %s" p p;
+		if has_feature ctx "python._hx_classes" then print ctx "\n_hx_classes[\"%s\"] = %s" p_name p
+
+
+	let gen_type ctx mt = match mt with
+		| TClassDecl c -> gen_class ctx c
+		| TEnumDecl en when not en.e_extern -> gen_enum ctx en
+		| TAbstractDecl {a_path = [],"UInt"} -> ()
+		| TAbstractDecl {a_path = [],"Enum"} -> ()
+		| TAbstractDecl {a_path = [],"EnumValue"} when not (has_feature ctx "has_enum") -> ()
+		| TAbstractDecl {a_path = [],"Void"} -> ()
+		| TAbstractDecl {a_path = [],"Int"} when not (has_feature ctx "Int.*") -> ()
+		| TAbstractDecl {a_path = [],"Float"} when not (has_feature ctx "Float.*") -> ()
+		| TAbstractDecl {a_path = [],"Class"} when not (has_feature ctx "Class.*") -> ()
+		| TAbstractDecl {a_path = [],"Dynamic"} when not (has_feature ctx "Dynamic.*") -> ()
+		| TAbstractDecl {a_path = [],"Bool"} when not (has_feature ctx "Bool.*") -> ()
+
+		| TAbstractDecl a when Meta.has Meta.CoreType a.a_meta -> gen_abstract ctx a
+		| _ -> ()
+
+	(* Generator parts *)
+
+	let gen_resources ctx =
+		if Hashtbl.length ctx.com.resources > 0 then begin
+			let slash_index = try (String.rindex ctx.com.file '/')+1 with Not_found -> 0 in
+			let len = String.length ctx.com.file - slash_index in
+			let file_name = String.sub ctx.com.file slash_index len in
+			newline ctx;
+			newline ctx;
+			newline ctx;
+			spr ctx "def _hx_resources__():";
+			spr ctx "\n\timport inspect";
+			spr ctx "\n\timport sys";
+			spr ctx "\n\tif not hasattr(sys.modules[__name__], '__file__'):";
+			print ctx "\n\t\t_file = '%s'" file_name;
+			spr ctx "\n\telse:";
+			spr ctx "\n\t\t_file = __file__";
+
+			spr ctx "\n\treturn {";
+			let first = ref true in
+			Hashtbl.iter (fun k v ->
+				let prefix = if !first then begin
+					first := false;
+					"";
+				end else
+					","
+				in
+				let k_enc = Codegen.escape_res_name k false in
+				print ctx "%s\"%s\": open('%%s.%%s'%%(_file,'%s'),'rb').read()" prefix (Ast.s_escape k) k_enc;
+				Std.output_file (ctx.com.file ^ "." ^ k_enc) v
+			) ctx.com.resources;
+			spr ctx "}"
+		end
+
+	let gen_imports ctx =
+		let import path meta =
+			if Meta.has Meta.PythonImport meta && is_directly_used ctx.com meta then begin
+				let _, args, mp = Meta.get Meta.PythonImport meta in
+
+				let class_name = match path with
+					| [],name -> name
+					| path,name -> (ExtString.String.join "_" path) ^ "_" ^ name
+				in
+
+				let import_type,ignore_error = match args with
+					| [(EConst(String(module_name)), _)]
+					| [(EConst(String(module_name)), _); (EBinop(OpAssign, (EConst(Ident("ignoreError")),_), (EConst(Ident("false")),_)),_)] ->
+						IModule module_name, false
+
+					| [(EConst(String(module_name)), _); (EBinop(OpAssign, (EConst(Ident("ignoreError")),_), (EConst(Ident("true")),_)),_)] ->
+						IModule module_name,true
+
+					| [(EConst(String(module_name)), _); (EConst(String(object_name)), _)]
+					| [(EConst(String(module_name)), _); (EConst(String(object_name)), _); (EBinop(OpAssign, (EConst(Ident("ignoreError")),_), (EConst(Ident("false")),_)),_)] ->
+						IObject (module_name,object_name), false
+
+					| [(EConst(String(module_name)), _); (EConst(String(object_name)), _); (EBinop(OpAssign, (EConst(Ident("ignoreError")),_), (EConst(Ident("true")),_)),_)] ->
+						IObject (module_name,object_name), true
+					| _ ->
+						error "Unsupported @:pythonImport format" mp
+				in
+
+				let import = match import_type with
+					| IModule module_name ->
+						(* importing whole module *)
+						"import " ^ module_name ^ " as " ^ class_name
+
+					| IObject (module_name,object_name) ->
+						if String.contains object_name '.' then
+							(* importing nested class *)
+							"import " ^ module_name ^ " as _hx_temp_import; " ^ class_name ^ " = _hx_temp_import." ^ object_name ^ "; del _hx_temp_import"
+						else
+							(* importing a class from a module *)
+							"from " ^ module_name ^ " import " ^ object_name ^ " as " ^ class_name
+				in
+				newline ctx;
+				if ignore_error then begin
+					spr ctx "try:\n\t";
+					spr_line ctx import;
+					spr ctx "except:\n\tpass"
+				end else
+					spr ctx import
+			end
+		in
+		List.iter (fun mt ->
+			match mt with
+			| TClassDecl c when c.cl_extern -> import c.cl_path c.cl_meta
+			| TEnumDecl e when e.e_extern -> import e.e_path e.e_meta
+			| _ -> ()
+		) ctx.com.types
+
+	let gen_types ctx =
+		let used_paths = Hashtbl.create 0 in
+		let find_type path =
+			Hashtbl.add used_paths path true;
+			Utils.find_type ctx.com path
+		in
+		let need_anon_for_trace = (has_feature ctx "has_anon_trace") && (has_feature ctx "haxe.Log.trace") in
+		if (has_feature ctx "has_anon") || (has_feature ctx "_hx_AnonObject") || need_anon_for_trace then begin
+			let with_body = (has_feature ctx "has_anon") || need_anon_for_trace in
+			newline ctx;
+			newline ctx;
+			newline ctx;
+			spr ctx "class _hx_AnonObject:\n";
+			if with_body then begin
+				spr ctx "\tdef __init__(self, fields):\n";
+				spr ctx "\t\tself.__dict__ = fields"
+			end else
+				spr ctx "\tpass";
+			Hashtbl.add used_paths ([],"_hx_AnonObject") true;
+		end;
+		if has_feature ctx "python._hx_classes" then begin
+			newline ctx;
+			newline ctx;
+			newline ctx;
+			spr ctx "_hx_classes = {}";
+		end;
+		if has_feature ctx "Boot.*" then
+			gen_type ctx (find_type (["python"],"Boot"));
+		if has_feature ctx "has_enum" || has_feature ctx "Enum.*" then
+			gen_type ctx (find_type ([],"Enum"));
+		if has_feature ctx "HxOverrides.*" then
+			gen_type ctx (find_type ([],"HxOverrides"));
+		List.iter (fun mt ->
+			if not (Hashtbl.mem used_paths (t_infos mt).mt_path) then
+				gen_type ctx mt
+		) ctx.com.types
+
+	let gen_static_inits ctx =
+		newline ctx;
+		List.iter (fun f -> f()) (List.rev ctx.static_inits)
+
+	let gen_class_inits ctx =
+		newline ctx;
+		List.iter (fun f -> f()) (List.rev ctx.class_inits)
+
+	let gen_main ctx =
+		match ctx.com.main with
+			| None ->
+				()
+			| Some e ->
+				newline ctx;
+				newline ctx;
+				gen_expr ctx e "" ""
+
+	(* Entry point *)
+
+	let run com =
+		Transformer.init com;
+		let ctx = mk_context com in
+		gen_imports ctx;
+		gen_resources ctx;
+		gen_types ctx;
+		gen_class_inits ctx;
+		gen_static_inits ctx;
+		gen_main ctx;
+
+		mkdir_from_path com.file;
+		let ch = open_out_bin com.file in
+		output_string ch (Buffer.contents ctx.buf);
+		close_out ch
+end
+
+let generate com =
+	Generator.run com

+ 22 - 17
genswf.ml

@@ -134,7 +134,7 @@ let build_class com c file =
 		} in
 		(path.tpackage, [(ETypedef inf,pos)])
 	| _ ->
-  (* make flags *)
+	(* make flags *)
 	let flags = [HExtern] in
 	let flags = if c.hlc_interface then HInterface :: flags else flags in
 	let flags = (match c.hlc_super with
@@ -157,7 +157,7 @@ let build_class com c file =
 		if c.hlc_interface then HExtends (make_tpath i) else HImplements (make_tpath i)
 	) (Array.to_list c.hlc_implements) @ flags in
 	let flags = if c.hlc_sealed || Common.defined com Define.FlashStrict then flags else HImplements (make_tpath (HMPath ([],"Dynamic"))) :: flags in
-  (* make fields *)
+	(* make fields *)
 	let getters = Hashtbl.create 0 in
 	let setters = Hashtbl.create 0 in
 	let override = Hashtbl.create 0 in
@@ -643,7 +643,7 @@ let build_dependencies t =
 			match follow t with
 			| TInst (c,_) -> List.iter add_inherit c.cl_implements
 			| _ -> ()
-		) c.cl_types;
+		) c.cl_params;
 		List.iter add_inherit c.cl_implements;
 	| TEnumDecl e when not e.e_extern ->
 		PMap.iter (fun _ f -> add_type f.ef_type) e.e_constrs;
@@ -1033,10 +1033,10 @@ let build_swf9 com file swc =
 	res @ bmp @ code @ clips
 
 let merge com file priority (h1,tags1) (h2,tags2) =
-  (* prioritize header+bgcolor for first swf *)
+	(* prioritize header+bgcolor for first swf *)
 	let header = if priority then { h2 with h_version = max h2.h_version (Common.flash_version_tag com.flash_version) } else h1 in
 	let tags1 = if priority then List.filter (function { tdata = TSetBgColor _ } -> false | _ -> true) tags1 else tags1 in
-  (* remove unused tags *)
+	(* remove unused tags *)
 	let use_stage = priority && Common.defined com Define.FlashUseStage in
 	let classes = ref [] in
 	let nframe = ref 0 in
@@ -1067,7 +1067,7 @@ let merge com file priority (h1,tags1) (h2,tags2) =
 			false
 		| _ -> true
 	) tags2 in
-  (* rebuild character ids *)
+(* rebuild character ids *)
 	let max_id = ref (-1) in
 	List.iter (SwfParser.scan (fun id -> if id > !max_id then max_id := id; id) (fun id -> id)) tags1;
 	incr max_id;
@@ -1079,7 +1079,7 @@ let merge com file priority (h1,tags1) (h2,tags2) =
 	in
 	List.iter loop tags2;
 	let classes = List.map (fun e -> match e.f9_cid with None -> e | Some id -> { e with f9_cid = Some (id + !max_id) }) !classes in
-  (* merge timelines *)
+	(* merge timelines *)
 	let rec loop l1 l2 =
 		match l1, l2 with
 		| ({ tdata = TSetBgColor _ } as t) :: l1, _
@@ -1112,7 +1112,7 @@ let generate com swf_header =
 	let swc = if Common.defined com Define.Swc then Some (ref "") else None in
 	if swc <> None && not isf9 then failwith "SWC support is only available for Flash9+";
 	let file , codeclip = (try let f , c = ExtString.String.split com.file "@" in f, Some c with _ -> com.file , None) in
-  (* list exports *)
+	(* list exports *)
 	let exports = Hashtbl.create 0 in
 	let toremove = ref [] in
 	List.iter (fun (file,lib,_) ->
@@ -1143,7 +1143,7 @@ let generate com swf_header =
 			| _ -> ()
 		) tags;
 	) com.swf_libs;
-  (* build haxe swf *)
+	(* build haxe swf *)
 	let tags = if isf9 then build_swf9 com file swc else build_swf8 com codeclip exports in
 	let header, bg = (match swf_header with None -> default_header com | Some h -> convert_header com h) in
 	let bg = tag (TSetBgColor { cr = bg lsr 16; cg = (bg lsr 8) land 0xFF; cb = bg land 0xFF }) in
@@ -1172,11 +1172,6 @@ let generate com swf_header =
 		})]
 	) in
 	let fattr = if Common.defined com Define.AdvancedTelemetry then fattr @ [tag (TUnknown (0x5D,"\x00\x00"))] else fattr in
-	let preframe, header =
-		if Common.defined com Define.SwfPreloaderFrame then
-			[tag TShowFrame], {h_version=header.h_version; h_size=header.h_size; h_frame_count=header.h_frame_count+1; h_fps=header.h_fps; h_compressed=header.h_compressed; }
-		else
-			[], header in
 	let swf_script_limits = try
 		let s = Common.defined_value com Define.SwfScriptTimeout in
 		let i = try int_of_string s with _ -> error "Argument to swf_script_timeout must be an integer" Ast.null_pos in
@@ -1184,16 +1179,26 @@ let generate com swf_header =
 	with Not_found ->
 		[]
 	in
-	let swf = header, fattr @ meta_data @ bg :: debug @ swf_script_limits @ preframe @ tags @ [tag TShowFrame] in
-  (* merge swf libraries *)
+	let swf = header, fattr @ meta_data @ bg :: debug @ swf_script_limits @ tags @ [tag TShowFrame] in
+	(* merge swf libraries *)
 	let priority = ref (swf_header = None) in
 	let swf = List.fold_left (fun swf (file,lib,cl) ->
 		let swf = merge com file !priority swf (remove_classes toremove lib cl) in
 		priority := false;
 		swf
 	) swf com.swf_libs in
+	let swf = match swf with
+	| header,tags when Common.defined com Define.SwfPreloaderFrame ->
+		let rec loop l =
+			match l with
+			| ({tdata = TFilesAttributes _ | TUnknown (0x5D,"\x00\x00") | TMetaData _ | TSetBgColor _ | TEnableDebugger2 _ | TScriptLimits _} as t) :: l -> t :: loop l
+			| t :: l -> tag TShowFrame :: t :: l
+			| [] -> []
+		in
+		{header with h_frame_count = header.h_frame_count + 1},loop tags
+	| _ -> swf in
 	t();
-  (* write swf/swc *)
+	(* write swf/swc *)
 	let t = Common.timer "write swf" in
 	let level = (try int_of_string (Common.defined_value com Define.SwfCompressLevel) with Not_found -> 9) in
 	SwfParser.init Extc.input_zip (Extc.output_zip ~level);

+ 0 - 1
genswf8.ml

@@ -1167,7 +1167,6 @@ and gen_expr_2 ctx retval e =
 		gen_expr ctx retval e
 	| TCast (e1,Some t) ->
 		gen_expr ctx retval (Codegen.default_cast ctx.com e1 t e.etype e.epos)
-	| TPatMatch dt -> assert false
 	| TFor (v,it,e) ->
 		gen_expr ctx true it;
 		let r = alloc_tmp ctx in

+ 53 - 98
genswf9.ml

@@ -104,6 +104,12 @@ type context = {
 	mutable for_call : bool;
 }
 
+let rec follow t = match Type.follow t with
+	| TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) ->
+		follow (Abstract.get_underlying_type a tl)
+	| t ->
+		t
+
 let invalid_expr p = error "Invalid expression" p
 let stack_error p = error "Stack error" p
 
@@ -119,7 +125,7 @@ let is_special_compare e1 e2 =
 	| TConst TNull, _  | _ , TConst TNull -> None
 	| _ ->
 	match follow e1.etype, follow e2.etype with
-	| TInst ({ cl_path = [],"Xml" } as c,_) , _ | _ , TInst ({ cl_path = [],"Xml" } as c,_) -> Some c
+	| TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) , _ | _ , TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) -> Some c
 	| _ -> None
 
 let write ctx op =
@@ -193,20 +199,16 @@ let rec follow_basic t =
 		| TAbstract ({ a_path = ([],"Float") },[])
 		| TAbstract ({ a_path = [],"UInt" },[])
 		| TAbstract ({ a_path = ([],"Bool") },[])
-		| TInst ({ cl_path = (["haxe"],"Int32") },[])
-		| TInst ({ cl_path = ([],"Int") },[])
-		| TInst ({ cl_path = ([],"Float") },[])
-		| TType ({ t_path = [],"UInt" },[])
-		| TEnum ({ e_path = ([],"Bool") },[]) -> t
+		| TInst ({ cl_path = (["haxe"],"Int32") },[]) -> t
 		| t -> t)
 	| TType ({ t_path = ["flash";"utils"],"Object" },[])
 	| TType ({ t_path = ["flash";"utils"],"Function" },[])
 	| TType ({ t_path = [],"UInt" },[]) ->
 		t
 	| TType (t,tl) ->
-		follow_basic (apply_params t.t_types tl t.t_type)
+		follow_basic (apply_params t.t_params tl t.t_type)
 	| TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
-		follow_basic (apply_params a.a_types pl a.a_this)
+		follow_basic (apply_params a.a_params pl a.a_this)
 	| _ -> t
 
 let rec type_id ctx t =
@@ -233,7 +235,7 @@ let rec type_id ctx t =
 		type_path ctx ([],"Function")
 	| TType ({ t_path = ([],"UInt") as path },_) ->
 		type_path ctx path
-	| TEnum ({ e_path = [],"XmlType"; e_extern = true },_) ->
+	| TEnum ({ e_path = ["flash"],"XmlType"; e_extern = true },_) ->
 		HMPath ([],"String")
 	| TEnum (e,_) ->
 		let rec loop = function
@@ -265,7 +267,7 @@ let classify ctx t =
 		KBool
 	| TAbstract ({ a_path = [],"Void" },_) | TEnum ({ e_path = [],"Void" },_) ->
 		KDynamic
-	| TEnum ({ e_path = [],"XmlType"; e_extern = true },_) ->
+	| TEnum ({ e_path = ["flash"],"XmlType"; e_extern = true },_) ->
 		KType (HMPath ([],"String"))
 	| TEnum (e,_) ->
 		let rec loop = function
@@ -348,7 +350,7 @@ let property ctx p t =
 		(* cast type when accessing an extension field *)
 		(try
 			let f = PMap.find p c.cl_fields in
-			ident p, Some (classify ctx (apply_params c.cl_types params f.cf_type)), false
+			ident p, Some (classify ctx (apply_params c.cl_params params f.cf_type)), false
 		with Not_found ->
 			ident p, None, false)
 	| TInst ({ cl_interface = true } as c,_) ->
@@ -356,7 +358,7 @@ let property ctx p t =
 		let rec loop c =
 			try
 				(match PMap.find p c.cl_fields with
-				| { cf_kind = Var _ } -> raise Exit (* no vars in interfaces in swf9 *)
+				| { cf_kind = Var _ | Method MethDynamic } -> raise Exit (* no vars in interfaces in swf9 *)
 				| _ -> c)
 			with Not_found ->
 				let rec loop2 = function
@@ -878,8 +880,8 @@ let rec gen_access ctx e (forset : 'a) : 'a access =
 		write ctx (HGetProp (ident "params"));
 		write ctx (HSmallInt i);
 		VArray
-	| TField (e1,f) ->
-		let f = field_name f in
+	| TField (e1,fa) ->
+		let f = field_name fa in
 		let id, k, closure = property ctx f e1.etype in
 		if closure && not ctx.for_call then error "In Flash9, this method cannot be accessed this way : please define a local function" e1.epos;
 		(match e1.eexpr with
@@ -893,9 +895,15 @@ let rec gen_access ctx e (forset : 'a) : 'a access =
 		| _ , TFun _ when not ctx.for_call -> VCast(id,classify ctx e.etype)
 		| TEnum _, _ -> VId id
 		| TInst (_,tl), et ->
+			let is_type_parameter_field = match fa with
+				| FInstance(_,_,cf) ->
+					(match follow cf.cf_type with TInst({cl_kind = KTypeParameter _},_) -> true | _ -> false)
+				| _ ->
+					List.exists (fun t -> follow t == et) tl
+			in
 			(* if the return type is one of the type-parameters, then we need to cast it *)
-			if List.exists (fun t -> follow t == et) tl then
-				VCast (id, classify ctx et)
+			if is_type_parameter_field then
+				VCast (id, classify ctx e.etype)
 			else if Codegen.is_volatile e.etype then
 				VVolatile (id,None)
 			else
@@ -1293,59 +1301,6 @@ let rec gen_expr_content ctx retval e =
 		);
 		List.iter (fun j -> j()) jend;
 		branch());
-(* 	| TMatch (e0,_,cases,def) ->
-		let t = classify ctx e.etype in
-		let rparams = alloc_reg ctx (KType (type_path ctx ([],"Array"))) in
-		let has_params = List.exists (fun (_,p,_) -> p <> None) cases in
-		gen_expr ctx true e0;
-		if has_params then begin
-			write ctx HDup;
-			write ctx (HGetProp (ident "params"));
-			set_reg ctx rparams;
-		end;
-		write ctx (HGetProp (ident "index"));
-		write ctx HToInt;
-		let switch,case = begin_switch ctx in
-		(match def with
-		| None ->
-			if retval then begin
-				write ctx HNull;
-				coerce ctx t;
-			end;
-		| Some e ->
-			gen_expr ctx retval e;
-			if retval && classify ctx e.etype <> t then coerce ctx t);
-		let jends = List.map (fun (cl,params,e) ->
-			let j = jump ctx J3Always in
-			List.iter case cl;
-			pop_value ctx retval;
-			let b = open_block ctx retval in
-			(match params with
-			| None -> ()
-			| Some l ->
-				let p = ref (-1) in
-				List.iter (fun v ->
-					incr p;
-					match v with
-					| None -> ()
-					| Some v ->
-						define_local ctx v e.epos;
-						let acc = gen_local_access ctx v e.epos Write in
-						write ctx (HReg rparams.rid);
-						write ctx (HSmallInt !p);
-						getvar ctx VArray;
-						setvar ctx acc None
-				) l
-			);
-			gen_expr ctx retval e;
-			b();
-			if retval && classify ctx e.etype <> t then coerce ctx t;
-			j
-		) cases in
-		switch();
-		List.iter (fun j -> j()) jends;
-		free_reg ctx rparams *)
-	| TPatMatch dt -> assert false
 	| TCast (e1,t) ->
 		gen_expr ctx retval e1;
 		if retval then begin
@@ -1691,10 +1646,15 @@ and gen_binop ctx retval op e1 e2 t p =
 		gen_expr ctx true e2;
 		write_op op;
 		setvar ctx wacc (if retval then Some (classify ctx e1.etype) else None)
-	| OpAdd | OpMult | OpDiv | OpSub | OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr | OpMod ->
+	| OpAdd | OpMult | OpDiv | OpSub | OpAnd | OpOr | OpXor | OpMod ->
 		gen_expr ctx true e1;
 		gen_expr ctx true e2;
 		write_op op
+	| OpShl | OpShr	| OpUShr ->
+		gen_expr ctx true e1;
+		gen_expr ctx true e2;
+		write_op op;
+		coerce ctx (classify ctx e1.etype)
 	| OpEq ->
 		gen_eq()
 	| OpNotEq ->
@@ -1737,7 +1697,7 @@ and generate_function ctx fdata stat =
 			| TReturn (Some e) ->
 				let rec inner_loop e =
 					match e.eexpr with
-					| TSwitch _ | TPatMatch _ | TFor _ | TWhile _ | TTry _ -> false
+					| TSwitch _ | TFor _ | TWhile _ | TTry _ -> false
 					| TIf _ -> loop e
 					| TParenthesis e | TMeta(_,e) -> inner_loop e
 					| _ -> true
@@ -1934,36 +1894,29 @@ let generate_enum_init ctx e hc meta =
 	write ctx (HGetLex (type_path ctx path));
 	write ctx (HClassDef hc);
 	write ctx HPopScope;
-	let r = alloc_reg ctx KDynamic in
-	write ctx HDup;
-	write ctx (HSetReg r.rid); (* needed for setslot *)
 	write ctx (HInitProp name_id);
-	let nslot = ref 0 in
 	PMap.iter (fun _ f ->
-		incr nslot;
 		match f.ef_type with
 		| TFun _ -> ()
 		| _ ->
-			write ctx (HReg r.rid);
+			write ctx (HGetLex name_id);
 			write ctx (HFindPropStrict name_id);
 			write ctx (HString f.ef_name);
 			write ctx (HInt f.ef_index);
 			write ctx HNull;
 			write ctx (HConstructProperty (name_id,3));
-			write ctx (HSetSlot !nslot);
+			write ctx (HInitProp (ident f.ef_name));
 	) e.e_constrs;
-	write ctx (HReg r.rid);
+	write ctx (HGetLex name_id);
 	List.iter (fun n -> write ctx (HString n)) e.e_names;
 	write ctx (HArray (List.length e.e_names));
-	write ctx (HSetProp (ident "__constructs__"));
-	(match meta with
+	write ctx (HInitProp (ident "__constructs__"));
+	match meta with
 	| None -> ()
 	| Some e ->
-		write ctx (HReg r.rid);
+		write ctx (HGetLex name_id);
 		gen_expr ctx true e;
-		write ctx (HSetProp (ident "__meta__"));
-	);
-	free_reg ctx r
+		write ctx (HInitProp (ident "__meta__"))
 
 let extract_meta meta =
 	let rec loop = function
@@ -2016,7 +1969,7 @@ let generate_field_kind ctx f c stat =
 			Some (HFMethod {
 				hlm_type = m;
 				hlm_final = stat || (Meta.has Meta.Final f.cf_meta);
-				hlm_override = not stat && loop c name;
+				hlm_override = not stat && (loop c name || loop c f.cf_name);
 				hlm_kind = kind;
 			})
 		);
@@ -2044,7 +1997,7 @@ let generate_field_kind ctx f c stat =
 			hlv_value = HVNone;
 			hlv_const = false;
 		})
-		
+
 let check_constructor ctx c f =
 	(*
 		check that we don't assign a super Float var before we call super() : will result in NaN
@@ -2053,7 +2006,7 @@ let check_constructor ctx c f =
 		Type.iter loop e;
 		match e.eexpr with
 		| TCall ({ eexpr = TConst TSuper },_) -> raise Exit
-		| TBinop (OpAssign,{ eexpr = TField({ eexpr = TConst TThis },FInstance (cc,cf)) },_) when c != cc && (match classify ctx cf.cf_type with KFloat | KDynamic -> true | _ -> false) ->
+		| TBinop (OpAssign,{ eexpr = TField({ eexpr = TConst TThis },FInstance (cc,_,cf)) },_) when c != cc && (match classify ctx cf.cf_type with KFloat | KDynamic -> true | _ -> false) ->
 			error "You cannot assign some super class vars before calling super() in flash, this will reset them to default value" e.epos
 		| _ -> ()
 	in
@@ -2061,7 +2014,7 @@ let check_constructor ctx c f =
 		loop f.tf_expr
 	with Exit ->
 		()
-		
+
 let generate_class ctx c =
 	let name = type_path ctx c.cl_path in
 	ctx.cur_class <- c;
@@ -2221,7 +2174,7 @@ let generate_class ctx c =
 let generate_enum ctx e meta =
 	let name_id = type_path ctx e.e_path in
 	let api = ctx.com.basic in
-	let f = begin_fun ctx [alloc_var "tag" api.tstring, None;alloc_var "index" api.tint, None;alloc_var "params" (mk_mono()), None] api.tvoid [ethis] false e.e_pos in
+	let f = begin_fun ctx [alloc_var "tag" api.tstring, None;alloc_var "index" api.tint, None;alloc_var "params" (api.tarray (mk_mono())), None] api.tvoid [ethis] false e.e_pos in
 	let tag_id = ident "tag" in
 	let index_id = ident "index" in
 	let params_id = ident "params" in
@@ -2242,8 +2195,10 @@ let generate_enum ctx e meta =
 	write ctx (HCallProperty (ident "enum_to_string",1));
 	write ctx HRet;
 	let tostring = f() in
-	let st_count = ref 0 in
+	let st_field_count = ref 0 in
+	let st_meth_count = ref 0 in
 	let constrs = PMap.fold (fun f acc ->
+		let st_count = (match f.ef_type with TFun _ -> st_meth_count | _ -> st_field_count) in
 		incr st_count;
 		{
 			hlf_name = ident f.ef_name;
@@ -2275,10 +2230,10 @@ let generate_enum ctx e meta =
 	let constrs = (match meta with
 		| None -> constrs
 		| Some _ ->
-			incr st_count;
+			incr st_field_count;
 			{
 				hlf_name = ident "__meta__";
-				hlf_slot = !st_count;
+				hlf_slot = !st_field_count;
 				hlf_kind = HFVar { hlv_type = None; hlv_value = HVNone; hlv_const = false; };
 				hlf_metas = None;
 			} :: constrs
@@ -2311,17 +2266,17 @@ let generate_enum ctx e meta =
 			};
 		|];
 		hlc_static_construct = empty_method ctx e.e_pos;
-		hlc_static_fields = Array.of_list ({
+		hlc_static_fields = Array.of_list (List.rev ({
 			hlf_name = ident "__isenum";
-			hlf_slot = !st_count + 2;
+			hlf_slot = !st_field_count + 2;
 			hlf_kind = HFVar { hlv_type = Some (HMPath ([],"Boolean")); hlv_value = HVBool true; hlv_const = true; };
 			hlf_metas = None;
 		} :: {
 			hlf_name = ident "__constructs__";
-			hlf_slot = !st_count + 1;
-			hlf_kind = HFVar { hlv_type = None; hlv_value = HVNone; hlv_const = false; };
+			hlf_slot = !st_field_count + 1;
+			hlf_kind = HFVar { hlv_type = Some (HMPath ([],"Array")); hlv_value = HVNone; hlv_const = false; };
 			hlf_metas = None;
-		} :: constrs);
+		} :: constrs));
 	}
 
 let rec generate_type ctx t =

+ 108 - 54
genxml.ml

@@ -23,6 +23,7 @@
 open Ast
 open Type
 open Common
+open ExtString
 
 type xml =
 	| Node of string * (string * string) list * xml list
@@ -77,7 +78,7 @@ let rec follow_param t =
 		| Some t -> follow_param t
 		| _ -> t)
 	| TType ({ t_path = [],"Null" } as t,tl) ->
-		follow_param (apply_params t.t_types tl t.t_type)
+		follow_param (apply_params t.t_params tl t.t_type)
 	| _ ->
 		t
 
@@ -91,7 +92,7 @@ let gen_meta meta =
 		) meta in
 		[node "meta" [] nodes]
 
-let rec gen_type ?(tfunc=None) t =
+let rec gen_type ?(values=None) t =
 	match t with
 	| TMono m -> (match !m with None -> tag "unknown" | Some t -> gen_type t)
 	| TEnum (e,params) -> gen_type_decl "e" (TEnumDecl e) params
@@ -99,29 +100,29 @@ let rec gen_type ?(tfunc=None) t =
 	| TAbstract (a,params) -> gen_type_decl "x" (TAbstractDecl a) params
 	| TType (t,params) -> gen_type_decl "t" (TTypeDecl t) params
 	| TFun (args,r) ->
-		let s_const ct = match ct with
-			| TString s -> Printf.sprintf "'%s'" (Ast.s_escape s)
-			| _ -> s_const ct
-		in
 		let names = String.concat ":" (List.map gen_arg_name args) in
-		let values = match tfunc with
-			| None ->
-				[]
-			| Some tfunc ->
+		let values = match values with
+			| None -> []
+			| Some values ->
 				let has_value = ref false in
-				let values = List.map (fun (_,cto) -> match cto with
-					| None ->
-						""
-					| Some ct ->
+				let values = List.map (fun (n,_,_) ->
+					try
+						let e = PMap.find n values in
 						has_value := true;
-						s_const ct
-				) tfunc.tf_args in
+						let s = Ast.s_expr e in
+						s
+					with Not_found ->
+						""
+				) args in
 				if !has_value then
 					["v",String.concat ":" values]
 				else
 					[]
 		in
-		node "f" (("a",names) :: values) (List.map gen_type (List.map (fun (_,opt,t) -> if opt then follow_param t else t) args @ [r]))
+		let args = List.map (fun (_,opt,t) ->
+			if opt then follow_param t else t
+		) args in
+		node "f" (("a",names) :: values) (List.map gen_type (args @ [r]))
 	| TAnon a -> node "a" [] (pmap (fun f -> gen_field [] { f with cf_public = false }) a.a_fields)
 	| TDynamic t2 -> node "d" [] (if t == t2 then [] else [gen_type t2])
 	| TLazy f -> gen_type (!f())
@@ -139,24 +140,40 @@ and gen_field att f =
 		| AccInline -> (name,"inline") :: att
 	in
 	let att = (match f.cf_expr with None -> att | Some e -> ("line",string_of_int (Lexer.get_error_line e.epos)) :: att) in
-	let att = (match f.cf_kind with
-		| Var v -> add_get_set v.v_read "get" (add_get_set v.v_write "set" att)
+	let att,values = (match f.cf_kind with
+		| Var v ->
+			let att = try
+				begin match Meta.get Meta.Value f.cf_meta with
+					| (_,[e],_) -> ("expr",Ast.s_expr e) :: att
+					| _ -> att
+				end
+			with Not_found ->
+				att
+			in
+			add_get_set v.v_read "get" (add_get_set v.v_write "set" att),PMap.empty
 		| Method m ->
-			(match m with
+			let att = match m with
 			| MethNormal | MethMacro -> ("set", "method") :: att
 			| MethDynamic -> ("set", "dynamic") :: att
-			| MethInline -> ("get", "inline") :: ("set","null") :: att)
+			| MethInline -> ("get", "inline") :: ("set","null") :: att
+			in
+			att,get_value_meta f.cf_meta
 	) in
 	let att = (match f.cf_params with [] -> att | l -> ("params", String.concat ":" (List.map (fun (n,_) -> n) l)) :: att) in
 	let overloads = match List.map (gen_field []) f.cf_overloads with
 		| [] -> []
 		| nl -> [node "overloads" [] nl]
 	in
-	let tfunc = match f.cf_expr with
-		| Some ({eexpr = TFunction tf}) -> Some tf
-		| _ -> None
+	let field_name cf =
+		try
+			begin match Meta.get Meta.RealPath cf.cf_meta with
+				| _,[EConst (String (s)),_],_ -> s
+				| _ -> raise Not_found
+			end;
+		with Not_found ->
+			cf.cf_name
 	in
-	node f.cf_name (if f.cf_public then ("public","1") :: att else att) (gen_type ~tfunc:tfunc f.cf_type :: gen_meta f.cf_meta @ gen_doc_opt f.cf_doc @ overloads)
+	node (field_name f) (if f.cf_public then ("public","1") :: att else att) (gen_type ~values:(Some values) f.cf_type :: gen_meta f.cf_meta @ gen_doc_opt f.cf_doc @ overloads)
 
 let gen_constr e =
 	let doc = gen_doc_opt e.ef_doc in
@@ -167,7 +184,7 @@ let gen_constr e =
 		| _ ->
 			[] , doc
 	) in
-	node e.ef_name args t
+	node e.ef_name args (t @ gen_meta e.ef_meta)
 
 let gen_ordered_constr e =
 	let rec loop el = match el with
@@ -197,10 +214,16 @@ let rec gen_type_decl com pos t =
 	let m = (t_infos t).mt_module in
 	match t with
 	| TClassDecl c ->
-		let stats = List.map (gen_field ["static","1"]) (List.filter (fun cf -> cf.cf_name <> "__meta__") c.cl_ordered_statics) in
+		let stats = List.filter (fun cf ->
+			cf.cf_name <> "__meta__" && not (Meta.has Meta.GenericInstance cf.cf_meta)
+		) c.cl_ordered_statics in
+		let stats = List.map (gen_field ["static","1"]) stats in
+		let fields = List.filter (fun cf ->
+			not (Meta.has Meta.GenericInstance cf.cf_meta)
+		) c.cl_ordered_fields in
 		let fields = (match c.cl_super with
-			| None -> List.map (fun f -> f,[]) c.cl_ordered_fields
-			| Some (csup,_) -> List.map (fun f -> if exists f csup then (f,["override","1"]) else (f,[])) c.cl_ordered_fields
+			| None -> List.map (fun f -> f,[]) fields
+			| Some (csup,_) -> List.map (fun f -> if exists f csup then (f,["override","1"]) else (f,[])) fields
 		) in
 		let fields = List.map (fun (f,att) -> gen_field att f) fields in
 		let constr = (match c.cl_constructor with None -> [] | Some f -> [gen_field [] f]) in
@@ -217,28 +240,32 @@ let rec gen_type_decl com pos t =
 			| None -> []
 			| Some t -> [node "haxe_dynamic" [] [gen_type t]]
 		) in
-		node "class" (gen_type_params pos c.cl_private (tpath t) c.cl_types c.cl_pos m @ ext @ interf) (tree @ stats @ fields @ constr @ doc @ meta @ dynamic)
+		node "class" (gen_type_params pos c.cl_private (tpath t) c.cl_params c.cl_pos m @ ext @ interf) (tree @ stats @ fields @ constr @ doc @ meta @ dynamic)
 	| TEnumDecl e ->
 		let doc = gen_doc_opt e.e_doc in
 		let meta = gen_meta e.e_meta in
-		node "enum" (gen_type_params pos e.e_private (tpath t) e.e_types e.e_pos m) (gen_ordered_constr e  @ doc @ meta)
+		node "enum" (gen_type_params pos e.e_private (tpath t) e.e_params e.e_pos m) (gen_ordered_constr e  @ doc @ meta)
 	| TTypeDecl t ->
 		let doc = gen_doc_opt t.t_doc in
 		let meta = gen_meta t.t_meta in
 		let tt = gen_type t.t_type in
-		node "typedef" (gen_type_params pos t.t_private t.t_path t.t_types t.t_pos m) (tt :: doc @ meta)
+		node "typedef" (gen_type_params pos t.t_private t.t_path t.t_params t.t_pos m) (tt :: doc @ meta)
 	| TAbstractDecl a ->
 		let doc = gen_doc_opt a.a_doc in
 		let meta = gen_meta a.a_meta in
-		let mk_cast (t,cfo) = node "icast" (match cfo with None -> [] | Some cf -> ["field",cf.cf_name]) [gen_type t] in
-		let sub = (match a.a_from with [] -> [] | l -> [node "from" [] (List.map mk_cast l)]) in
-		let super = (match a.a_to with [] -> [] | l -> [node "to" [] (List.map mk_cast l)]) in
+		let mk_cast t = node "icast" [] [gen_type t] in
+		let mk_field_cast (t,cf) = node "icast" ["field",cf.cf_name] [gen_type t] in
+		let sub = (match a.a_from,a.a_from_field with [],[] -> [] | l1,l2 -> [node "from" [] ((List.map mk_cast l1) @ (List.map mk_field_cast l2))]) in
+		let super = (match a.a_to,a.a_to_field with [],[] -> [] | l1,l2 -> [node "to" [] ((List.map mk_cast l1) @ (List.map mk_field_cast l2))]) in
 		let impl = (match a.a_impl with None -> [] | Some c -> [node "impl" [] [gen_type_decl com pos (TClassDecl c)]]) in
 		let this = [node "this" [] [gen_type a.a_this]] in
-		node "abstract" (gen_type_params pos a.a_private (tpath t) a.a_types a.a_pos m) (sub @ this @ super @ doc @ meta @ impl)
+		node "abstract" (gen_type_params pos a.a_private (tpath t) a.a_params a.a_pos m) (sub @ this @ super @ doc @ meta @ impl)
+
+let escape_entities s =
+	Xml.to_string (Xml.PCData s)
 
 let att_str att =
-	String.concat "" (List.map (fun (a,v) -> Printf.sprintf " %s=\"%s\"" a v) att)
+	String.concat "" (List.map (fun (a,v) -> Printf.sprintf " %s=\"%s\"" a (escape_entities v)) att)
 
 let rec write_xml ch tabs x =
 	match x with
@@ -292,9 +319,27 @@ let conv_path p =
 	| x :: l when x.[0] = '_' -> List.rev (("priv" ^ x) :: l), snd p
 	| _ -> p
 
+let get_real_path meta path =
+	try
+		let real_path = match Meta.get Meta.RealPath meta with
+			| (_,[(EConst(String s),_)],_) ->
+				s
+			| _ -> raise Not_found
+		in
+		match List.rev (String.nsplit real_path ".") with
+			| name :: pack ->
+				(List.rev pack), name
+			| _ -> raise Not_found
+	with | Not_found ->
+		path
+
+
 let generate_type com t =
 	let base_path = "hxclasses" in
-	let pack , name = conv_path (t_path t) in
+	let pack, name =
+		let info = t_infos t in
+		get_real_path info.mt_meta info.mt_path
+	in
 	create_dir "." (base_path :: pack);
 	match pack, name with
 	| ["flash";"net"], "NetStreamPlayTransitions"
@@ -318,8 +363,8 @@ let generate_type com t =
 		| _ ->
 			t
 	in
-	let rec path p tl =
-		let p = conv_path p in
+	let rec path meta p tl =
+		let p = conv_path (get_real_path meta p) in
 		(if fst p = pack then snd p else s_type_path p) ^ (match tl with [] -> "" | _ -> "<" ^ String.concat "," (List.map stype tl) ^ ">")
 	and stype t =
 		match t with
@@ -328,15 +373,15 @@ let generate_type com t =
 			| None -> "Unknown"
 			| Some t -> stype t)
 		| TInst ({ cl_kind = KTypeParameter _ } as c,tl) ->
-			path ([],snd c.cl_path) tl
+			path [] ([],snd c.cl_path) tl
 		| TInst (c,tl) ->
-			path c.cl_path tl
+			path c.cl_meta c.cl_path tl
 		| TEnum (e,tl) ->
-			path e.e_path tl
+			path e.e_meta e.e_path tl
 		| TType (t,tl) ->
-			path t.t_path tl
+			path t.t_meta t.t_path tl
 		| TAbstract (a,tl) ->
-			path a.a_path tl
+			path a.a_meta a.a_path tl
 		| TAnon a ->
 			let fields = PMap.fold (fun f acc -> (f.cf_name ^ " : " ^ stype f.cf_type) :: acc) a.a_fields [] in
 			"{" ^ String.concat ", " fields ^ "}"
@@ -380,7 +425,7 @@ let generate_type com t =
 	let print_meta ml =
 		List.iter (fun (m,pl,_) ->
 			match m with
-			| Meta.DefParam | Meta.CoreApi | Meta.Used | Meta.MaybeUsed | Meta.FlatEnum -> ()
+			| Meta.DefParam | Meta.CoreApi | Meta.Used | Meta.MaybeUsed | Meta.FlatEnum | Meta.Value | Meta.DirectlyUsed -> ()
 			| _ ->
 			match pl with
 			| [] -> p "@%s " (fst (MetaInfo.to_string m))
@@ -392,13 +437,21 @@ let generate_type com t =
 		| AccNever, "flash" :: _ -> "null"
 		| _ -> s_access is_read a
 	in
-	let print_field stat f =
+	let rec print_field stat f =
 		p "\t";
 		print_meta f.cf_meta;
 		if stat then p "static ";
+		let name = try (match Meta.get Meta.RealPath f.cf_meta with
+				| (Meta.RealPath, [EConst( String s ), _], _) ->
+					s
+				| _ ->
+					raise Not_found)
+			with Not_found ->
+				f.cf_name
+		in
 		(match f.cf_kind with
 		| Var v ->
-			p "var %s" f.cf_name;
+			p "var %s" name;
 			if v.v_read <> AccNormal || v.v_write <> AccNormal then p "(%s,%s)" (access true v.v_read) (access false v.v_write);
 			p " : %s" (stype f.cf_type);
 		| Method m ->
@@ -428,14 +481,15 @@ let generate_type com t =
 					assert false
 			) in
 			let tparams = (match f.cf_params with [] -> "" | l -> "<" ^ String.concat "," (List.map fst l) ^ ">") in
-			p "function %s%s(%s) : %s" f.cf_name tparams (String.concat ", " (List.map sparam params)) (stype ret);
+			p "function %s%s(%s) : %s" name tparams (String.concat ", " (List.map sparam params)) (stype ret);
 		);
-		p ";\n"
+		p ";\n";
+		if Meta.has Meta.Overload f.cf_meta then List.iter (fun f -> print_field stat f) f.cf_overloads
 	in
 	(match t with
 	| TClassDecl c ->
 		print_meta c.cl_meta;
-		p "extern %s %s" (if c.cl_interface then "interface" else "class") (stype (TInst (c,List.map snd c.cl_types)));
+		p "extern %s %s" (if c.cl_interface then "interface" else "class") (stype (TInst (c,List.map snd c.cl_params)));
 		let ext = (match c.cl_super with
 		| None -> []
 		| Some (c,pl) -> [" extends " ^ stype (TInst (c,pl))]
@@ -476,7 +530,7 @@ let generate_type com t =
 		p "}\n";
 	| TEnumDecl e ->
 		print_meta e.e_meta;
-		p "extern enum %s {\n" (stype (TEnum(e,List.map snd e.e_types)));
+		p "extern enum %s {\n" (stype (TEnum(e,List.map snd e.e_params)));
 		let sort l =
 			let a = Array.of_list l in
 			Array.sort compare a;
@@ -493,12 +547,12 @@ let generate_type com t =
 		p "}\n"
 	| TTypeDecl t ->
 		print_meta t.t_meta;
-		p "typedef %s = " (stype (TType (t,List.map snd t.t_types)));
+		p "typedef %s = " (stype (TType (t,List.map snd t.t_params)));
 		p "%s" (stype t.t_type);
 		p "\n";
 	| TAbstractDecl a ->
 		print_meta a.a_meta;
-		p "abstract %s {}" (stype (TAbstract (a,List.map snd a.a_types)));
+		p "abstract %s {}" (stype (TAbstract (a,List.map snd a.a_params)));
 	);
 	IO.close_out ch
 

+ 14 - 0
haxe.hxproj

@@ -21,6 +21,7 @@
   <build>
     <option directives="" />
     <option flashStrict="False" />
+    <option noInlineOnDebug="False" />
     <option mainClass="" />
     <option enabledebug="False" />
     <option additional="" />
@@ -136,6 +137,19 @@
     <hidden path="filters.obj" />
     <hidden path="filters.cmi" />
     <hidden path="filters.cmx" />
+    <hidden path="genpy.obj" />
+    <hidden path="genpy.cmi" />
+    <hidden path="genpy.cmx" />
+    <hidden path="analyzer.cmi" />
+    <hidden path="analyzer.cmx" />
+    <hidden path="analyzer.obj" />
+    <hidden path="CONTRIBUTING.md" />
+    <hidden path="README.md" />
+    <hidden path="Makefile" />
+    <hidden path="Makefile.win" />
+    <hidden path="appveyor.yml" />
+    <hidden path="version.ml" />
+    <hidden path="lib" />
   </hiddenPaths>
   <!-- Executed before build -->
   <preBuildCommand>make -j4 MSVC=1 FD_OUTPUT=1 -f Makefile.win kill haxe</preBuildCommand>

+ 272 - 135
interp.ml

@@ -47,12 +47,13 @@ and vobject = {
 }
 
 and vabstract =
+	| ADeallocated of int ref
 	| AKind of vabstract
 	| AHash of (value, value) Hashtbl.t
 	| ARandom of Random.State.t ref
 	| ABuffer of Buffer.t
 	| APos of Ast.pos
-	| AFRead of in_channel
+	| AFRead of (in_channel * bool ref)
 	| AFWrite of out_channel
 	| AReg of regexp
 	| AZipI of zlib
@@ -66,6 +67,8 @@ and vabstract =
 	| ANekoBuffer of value
 	| ACacheRef of value
 	| AInt32Kind
+	| ATls of value ref
+	| AProcess of Process.process
 
 and vfunction =
 	| Fun0 of (unit -> value)
@@ -103,6 +106,7 @@ type extern_api = {
 	on_type_not_found : (string -> value) -> unit;
 	parse_string : string -> Ast.pos -> bool -> Ast.expr;
 	type_expr : Ast.expr -> Type.texpr;
+	store_typed_expr : Type.texpr -> Ast.expr;
 	get_display : string -> string;
 	allow_package : string -> unit;
 	type_patch : string -> string -> bool -> string option -> unit;
@@ -110,18 +114,21 @@ type extern_api = {
 	set_js_generator : (value -> unit) -> unit;
 	get_local_type : unit -> t option;
 	get_expected_type : unit -> t option;
+	get_call_arguments : unit -> Ast.expr list option;
 	get_local_method : unit -> string;
 	get_local_using : unit -> tclass list;
 	get_local_vars : unit -> (string, Type.tvar) PMap.t;
 	get_build_fields : unit -> value;
 	get_pattern_locals : Ast.expr -> Type.t -> (string,Type.tvar * Ast.pos) PMap.t;
 	define_type : value -> unit;
-	define_module : string -> value list -> unit;
+	define_module : string -> value list -> ((string * Ast.pos) list * Ast.import_mode) list -> Ast.type_path list -> unit;
 	module_dependency : string -> string -> bool -> unit;
 	current_module : unit -> module_def;
 	delayed_macro : int -> (unit -> (unit -> value));
 	use_cache : unit -> bool;
 	format_string : string -> Ast.pos -> Ast.expr;
+	cast_or_unify : Type.t -> texpr -> Ast.pos -> Type.texpr;
+	add_global_metadata : string -> string -> (bool * bool * bool) -> unit;
 }
 
 type callstack = {
@@ -202,6 +209,9 @@ let dec_array_ref = ref (fun v -> assert false)
 let enc_string_ref = ref (fun s -> assert false)
 let make_ast_ref = ref (fun _ -> assert false)
 let make_complex_type_ref = ref (fun _ -> assert false)
+let encode_tvar_ref = ref (fun _ -> assert false)
+let decode_path_ref = ref (fun _ -> assert false)
+let decode_import_ref = ref (fun _ -> assert false)
 let get_ctx() = (!get_ctx_ref)()
 let enc_array (l:value list) : value = (!enc_array_ref) l
 let dec_array (l:value) : value list = (!dec_array_ref) l
@@ -217,6 +227,9 @@ let enc_hash (h:('a,'b) Hashtbl.t) : value = (!enc_hash_ref) h
 let make_ast (e:texpr) : Ast.expr = (!make_ast_ref) e
 let enc_string (s:string) : value = (!enc_string_ref) s
 let make_complex_type (t:Type.t) : Ast.complex_type = (!make_complex_type_ref) t
+let encode_tvar (v:tvar) : value = (!encode_tvar_ref) v
+let decode_path (v:value) : Ast.type_path = (!decode_path_ref) v
+let decode_import (v:value) : ((string * Ast.pos) list * Ast.import_mode) = (!decode_import_ref) v
 
 let to_int f = Int32.of_float (mod_float f 2147483648.0)
 let need_32_bits i = Int32.compare (Int32.logand (Int32.add i 0x40000000l) 0x80000000l) Int32.zero <> 0
@@ -258,7 +271,7 @@ let constants =
 	let h = Hashtbl.create 0 in
 	List.iter (fun f -> Hashtbl.add h (hash f) f)
 	["done";"read";"write";"min";"max";"file";"args";"loadprim";"loadmodule";"__a";"__s";"h";
-    "tag";"index";"length";"message";"pack";"name";"params";"sub";"doc";"kind";"meta";"access";
+	"tag";"index";"length";"message";"pack";"name";"params";"sub";"doc";"kind";"meta";"access";
 	"constraints";"opt";"type";"value";"ret";"expr";"field";"values";"get";"__string";"toString";
 	"$";"add";"remove";"has";"__t";"module";"isPrivate";"isPublic";"isExtern";"isInterface";"exclude";
 	"constructs";"names";"superClass";"interfaces";"fields";"statics";"constructor";"init";"t";
@@ -1005,17 +1018,17 @@ let builtins =
 			| CInf -> VInt (-1)
 		);
 		"pcompare", Fun2 (fun a b ->
-	 		assert false
-	 	);
-	 	"excstack", Fun0 (fun() ->
+			assert false
+		);
+		"excstack", Fun0 (fun() ->
 			build_stack (get_ctx()).exc
-	 	);
-	 	"callstack", Fun0 (fun() ->
-	 		build_stack (List.map (fun s -> s.cpos) (get_ctx()).callstack)
-	 	);
-	 	"version", Fun0 (fun() ->
-	 		VInt 200
-	 	);
+		);
+		"callstack", Fun0 (fun() ->
+			build_stack (List.map (fun s -> s.cpos) (get_ctx()).callstack)
+		);
+		"version", Fun0 (fun() ->
+			VInt 200
+		);
 	(* extra *)
 		"use_neko_dll", Fun0 (fun() ->
 			VBool (neko <> None)
@@ -1040,6 +1053,11 @@ let builtins =
 (* ---------------------------------------------------------------------- *)
 (* STD LIBRARY *)
 
+let free_abstract a =
+	match a with
+	| VAbstract vp -> Obj.set_tag (Obj.repr vp) 0 (* this will mute it as Deallocated *)
+	| _ -> assert false
+
 let std_lib =
 	let p = { psource = "<stdlib>"; pline = 0 } in
 	let error() =
@@ -1408,8 +1426,8 @@ let std_lib =
 			| VString f, VString r ->
 				let perms = 0o666 in
 				VAbstract (match r with
-					| "r" -> AFRead (open_in_gen [Open_rdonly] 0 f)
-					| "rb" -> AFRead (open_in_gen [Open_rdonly;Open_binary] 0 f)
+					| "r" -> AFRead (open_in_gen [Open_rdonly] 0 f,ref false)
+					| "rb" -> AFRead (open_in_gen [Open_rdonly;Open_binary] 0 f,ref false)
 					| "w" -> AFWrite (open_out_gen [Open_wronly;Open_creat;Open_trunc] perms f)
 					| "wb" -> AFWrite (open_out_gen [Open_wronly;Open_creat;Open_trunc;Open_binary] perms f)
 					| "a" -> AFWrite (open_out_gen [Open_append] perms f)
@@ -1417,10 +1435,10 @@ let std_lib =
 					| _ -> error())
 			| _ -> error()
 		);
-		"file_close", Fun1 (fun f ->
-			(match f with
-			| VAbstract (AFRead f) -> close_in f
-			| VAbstract (AFWrite f) -> close_out f
+		"file_close", Fun1 (fun vf ->
+			(match vf with
+			| VAbstract (AFRead (f,_)) -> close_in f; free_abstract vf;
+			| VAbstract (AFWrite f) -> close_out f; free_abstract vf;
 			| _ -> error());
 			VNull
 		);
@@ -1432,9 +1450,12 @@ let std_lib =
 		);
 		"file_read", Fun4 (fun f s p l ->
 			match f, s, p, l with
-			| VAbstract (AFRead f), VString s, VInt p, VInt l ->
+			| VAbstract (AFRead (f,r)), VString s, VInt p, VInt l ->
 				let n = input f s p l in
-				if n = 0 then exc (VArray [|VString "file_read"|]);
+				if n = 0 then begin
+					r := true;
+					exc (VArray [|VString "file_read"|]);
+				end;
 				VInt n
 			| _ -> error()
 		);
@@ -1445,34 +1466,30 @@ let std_lib =
 		);
 		"file_read_char", Fun1 (fun f ->
 			match f with
-			| VAbstract (AFRead f) -> VInt (int_of_char (try input_char f with _ -> exc (VArray [|VString "file_read_char"|])))
+			| VAbstract (AFRead (f,r)) -> VInt (int_of_char (try input_char f with _ -> r := true; exc (VArray [|VString "file_read_char"|])))
 			| _ -> error()
 		);
 		"file_seek", Fun3 (fun f pos mode ->
 			match f, pos, mode with
-			| VAbstract (AFRead f), VInt pos, VInt mode ->
-				seek_in f (match mode with 0 -> pos | 1 -> pos_in f + pos | 2 -> in_channel_length f - pos | _ -> error());
+			| VAbstract (AFRead (f,r)), VInt pos, VInt mode ->
+				r := false;
+				seek_in f (match mode with 0 -> pos | 1 -> pos_in f + pos | 2 -> in_channel_length f + pos | _ -> error());
 				VNull;
 			| VAbstract (AFWrite f), VInt pos, VInt mode ->
-				seek_out f (match mode with 0 -> pos | 1 -> pos_out f + pos | 2 -> out_channel_length f - pos | _ -> error());
+				seek_out f (match mode with 0 -> pos | 1 -> pos_out f + pos | 2 -> out_channel_length f + pos | _ -> error());
 				VNull;
 			| _ -> error()
 		);
 		"file_tell", Fun1 (fun f ->
 			match f with
-			| VAbstract (AFRead f) -> VInt (pos_in f)
+			| VAbstract (AFRead (f,_)) -> VInt (pos_in f)
 			| VAbstract (AFWrite f) -> VInt (pos_out f)
 			| _ -> error()
 		);
 		"file_eof", Fun1 (fun f ->
 			match f with
-			| VAbstract (AFRead f) ->
-				VBool (try
-					ignore(input_char f);
-					seek_in f (pos_in f - 1);
-					false
-				with End_of_file ->
-					true)
+			| VAbstract (AFRead (f,r)) ->
+				VBool !r
 			| _ -> error()
 		);
 		"file_flush", Fun1 (fun f ->
@@ -1486,7 +1503,7 @@ let std_lib =
 			| VString f -> VString (Std.input_file ~bin:true f)
 			| _ -> error()
 		);
-		"file_stdin", Fun0 (fun() -> VAbstract (AFRead Pervasives.stdin));
+		"file_stdin", Fun0 (fun() -> VAbstract (AFRead (Pervasives.stdin, ref false)));
 		"file_stdout", Fun0 (fun() -> VAbstract (AFWrite Pervasives.stdout));
 		"file_stderr", Fun0 (fun() -> VAbstract (AFWrite Pervasives.stderr));
 	(* serialize *)
@@ -1498,9 +1515,9 @@ let std_lib =
 			| VBool b -> VAbstract (ASocket (Unix.socket PF_INET (if b then SOCK_DGRAM else SOCK_STREAM) 0));
 			| _ -> error()
 		);
-		"socket_close", Fun1 (fun s ->
-			match s with
-			| VAbstract (ASocket s) -> Unix.close s; VNull
+		"socket_close", Fun1 (fun vs ->
+			match vs with
+			| VAbstract (ASocket s) -> Unix.close s; free_abstract vs; VNull
 			| _ -> error()
 		);
 		"socket_send_char", Fun2 (fun s c ->
@@ -1635,11 +1652,25 @@ let std_lib =
 			Unix.chdir (vstring s);
 			VNull;
 		);
-		"sys_string", Fun0 (fun() ->
-			VString (match Sys.os_type with
-			| "Unix" -> "Linux"
-			| "Win32" | "Cygwin" -> "Windows"
-			| s -> s)
+		"sys_string", (
+			let cached_sys_name = ref None in
+			Fun0 (fun() ->
+				VString (match Sys.os_type with
+				| "Unix" ->
+					(match !cached_sys_name with
+					| Some n -> n
+					| None ->
+						let ic = Unix.open_process_in "uname" in
+						let uname = (match input_line ic with
+							| "Darwin" -> "Mac"
+							| n -> n
+						) in
+						close_in ic;
+						cached_sys_name := Some uname;
+						uname)
+				| "Win32" | "Cygwin" -> "Windows"
+				| s -> s)
+			)
 		);
 		"sys_is64", Fun0 (fun() ->
 			VBool (Sys.word_size = 64)
@@ -1716,7 +1747,7 @@ let std_lib =
 			VString (try Extc.get_full_path (vstring file) with _ -> error())
 		);
 		"sys_exe_path", Fun0 (fun() ->
-			VString (Extc.executable_path())
+			VString (Sys.argv.(0))
 		);
 		"sys_env", Fun0 (fun() ->
 			let env = Unix.environment() in
@@ -1790,6 +1821,65 @@ let std_lib =
 		"utf8_compare", Fun2 (fun s1 s2 ->
 			VInt (UTF8.compare (vstring s1) (vstring s2))
 		);
+	(* thread *)
+		"thread_create", Fun2 (fun f p ->
+			exc (VString "Can't create thread from within a macro");
+		);
+		"tls_create", Fun0 (fun() ->
+			VAbstract (ATls (ref VNull))
+		);
+		"tls_get", Fun1 (fun t ->
+			match t with
+			| VAbstract (ATls r) -> !r
+			| _ -> error();
+		);
+		"tls_set", Fun2 (fun t v ->
+			match t with
+			| VAbstract (ATls r) -> r := v; VNull
+			| _ -> error();
+		);
+		(* lock, mutex, deque : not implemented *)
+	(* process *)
+		"process_run", (Fun2 (fun p args ->
+			match p, args with
+			| VString p, VArray args -> VAbstract (AProcess (Process.run p (Array.map vstring args)))
+			| _ -> error()
+		));
+		"process_stdout_read", (Fun4 (fun p str pos len ->
+			match p, str, pos, len with
+			| VAbstract (AProcess p), VString str, VInt pos, VInt len -> VInt (Process.read_stdout p str pos len)
+			| _ -> error()
+		));
+		"process_stderr_read", (Fun4 (fun p str pos len ->
+			match p, str, pos, len with
+			| VAbstract (AProcess p), VString str, VInt pos, VInt len -> VInt (Process.read_stderr p str pos len)
+			| _ -> error()
+		));
+		"process_stdin_write", (Fun4 (fun p str pos len ->
+			match p, str, pos, len with
+			| VAbstract (AProcess p), VString str, VInt pos, VInt len -> VInt (Process.write_stdin p str pos len)
+			| _ -> error()
+		));
+		"process_stdin_close", (Fun1 (fun p ->
+			match p with
+			| VAbstract (AProcess p) -> Process.close_stdin p; VNull
+			| _ -> error()
+		));
+		"process_exit", (Fun1 (fun p ->
+			match p with
+			| VAbstract (AProcess p) -> VInt (Process.exit p)
+			| _ -> error()
+		));
+		"process_pid", (Fun1 (fun p ->
+			match p with
+			| VAbstract (AProcess p) -> VInt (Process.pid p)
+			| _ -> error()
+		));
+		"process_close", (Fun1 (fun vp ->
+			match vp with
+			| VAbstract (AProcess p) -> Process.close p; free_abstract vp; VNull
+			| _ -> error()
+		));
 	(* xml *)
 		"parse_xml", (match neko with
 		| None -> Fun2 (fun str o ->
@@ -1829,30 +1919,14 @@ let std_lib =
 			let parse_xml = neko.load "std@parse_xml" 2 in
 			Fun2 (fun str o -> neko.call parse_xml [str;o])
 		);
-	(* memory, module, thread : not planned *)
+	(* memory, module : not planned *)
 	]
 	(* process *)
 	@ (match neko with
 	| None -> []
 	| Some neko ->
-		let p_run = neko.load "std@process_run" 2 in
-		let p_stdout_read = neko.load "std@process_stdout_read" 4 in
-		let p_stderr_read = neko.load "std@process_stderr_read" 4 in
-		let p_stdin_write = neko.load "std@process_stdin_write" 4 in
-		let p_stdin_close = neko.load "std@process_stdin_close" 1 in
-		let p_exit = neko.load "std@process_exit" 1 in
-		let p_pid = neko.load "std@process_pid" 1 in
-		let p_close = neko.load "std@process_close" 1 in
 		let win_ec = (try Some (neko.load "std@win_env_changed" 0) with _ -> None) in
 	[
-		"process_run", (Fun2 (fun a b -> neko.call p_run [a;b]));
-		"process_stdout_read", (Fun4 (fun a b c d -> neko.call p_stdout_read [a;VAbstract (ANekoBuffer b);c;d]));
-		"process_stderr_read", (Fun4 (fun a b c d -> neko.call p_stderr_read [a;VAbstract (ANekoBuffer b);c;d]));
-		"process_stdin_write", (Fun4 (fun a b c d -> neko.call p_stdin_write [a;b;c;d]));
-		"process_stdin_close", (Fun1 (fun p -> neko.call p_stdin_close [p]));
-		"process_exit", (Fun1 (fun p -> neko.call p_exit [p]));
-		"process_pid", (Fun1 (fun p -> neko.call p_pid [p]));
-		"process_close", (Fun1 (fun p -> neko.call p_close [p]));
 		"win_env_changed", (Fun0 (fun() -> match win_ec with None -> error() | Some f -> neko.call f []));
 	]))
 
@@ -1996,14 +2070,14 @@ let z_lib =
 			let z = Extc.zlib_deflate_init (match f with VInt i -> i | _ -> error()) in
 			VAbstract (AZipD { z = z; z_flush = Extc.Z_NO_FLUSH })
 		);
-		"deflate_end", Fun1 (fun z ->
-			match z with
-			| VAbstract (AZipD z) -> Extc.zlib_deflate_end z.z; VNull;
+		"deflate_end", Fun1 (fun vz ->
+			match vz with
+			| VAbstract (AZipD z) -> Extc.zlib_deflate_end z.z; free_abstract vz; VNull;
 			| _ -> error()
 		);
-		"inflate_end", Fun1 (fun z ->
-			match z with
-			| VAbstract (AZipI z) -> Extc.zlib_inflate_end z.z; VNull;
+		"inflate_end", Fun1 (fun vz ->
+			match vz with
+			| VAbstract (AZipI z) -> Extc.zlib_inflate_end z.z; free_abstract vz; VNull;
 			| _ -> error()
 		);
 		"set_flush_mode", Fun2 (fun z f ->
@@ -2053,16 +2127,16 @@ let z_lib =
 
 (* convert float value to haxe expression, handling inf/-inf/nan *)
 let haxe_float f p =
-    let std = (Ast.EConst (Ast.Ident "std"), p) in
-    let math = (Ast.EField (std, "Math"), p) in
-    if (f = infinity) then
-        (Ast.EField (math, "POSITIVE_INFINITY"), p)
-    else if (f = neg_infinity) then
-        (Ast.EField (math, "NEGATIVE_INFINITY"), p)
-    else if (f <> f) then
-        (Ast.EField (math, "NaN"), p)
-    else
-        (Ast.EConst (Ast.Float (float_repres f)), p)
+	let std = (Ast.EConst (Ast.Ident "std"), p) in
+	let math = (Ast.EField (std, "Math"), p) in
+	if (f = infinity) then
+		(Ast.EField (math, "POSITIVE_INFINITY"), p)
+	else if (f = neg_infinity) then
+		(Ast.EField (math, "NEGATIVE_INFINITY"), p)
+	else if (f <> f) then
+		(Ast.EField (math, "NaN"), p)
+	else
+		(Ast.EConst (Ast.Float (float_repres f)), p)
 
 let macro_lib =
 	let error() =
@@ -2116,6 +2190,12 @@ let macro_lib =
 			| VString s -> (try VString (Common.raw_defined_value (ccom()) s) with Not_found -> VNull)
 			| _ -> error();
 		);
+		"get_defines", Fun0 (fun() ->
+			let defines = (ccom()).defines in
+			let h = Hashtbl.create 0 in
+			PMap.iter (fun n v -> Hashtbl.replace h (VString n) (VString v)) defines;
+			enc_hash h
+		);
 		"get_type", Fun1 (fun s ->
 			match s with
 			| VString s ->
@@ -2164,7 +2244,8 @@ let macro_lib =
 		);
 		"parse", Fun3 (fun s p b ->
 			match s, p, b with
-			| VString s, VAbstract (APos p), VBool b -> encode_expr ((get_ctx()).curapi.parse_string s p b)
+			| VString s, VAbstract (APos p), VBool b when s <> "" ->
+				(try encode_expr ((get_ctx()).curapi.parse_string s p b) with Invalid_expr -> error())
 			| _ -> error()
 		);
 		"make_expr", Fun2 (fun v p ->
@@ -2316,8 +2397,9 @@ let macro_lib =
 			with Exit -> VNull
 		);
 		"unify", Fun2 (fun t1 t2 ->
-			try Type.unify (decode_type t1) (decode_type t2); VBool true
-			with Unify_error _ -> VBool false
+			let e1 = mk (TObjectDecl []) (decode_type t1) Ast.null_pos in
+			try ignore(((get_ctx()).curapi.cast_or_unify) (decode_type t2) e1 Ast.null_pos); VBool true
+			with Typecore.Error (Typecore.Unify _,_) -> VBool false
 		);
 		"typeof", Fun1 (fun v ->
 			encode_type ((get_ctx()).curapi.type_expr (decode_expr v)).etype
@@ -2329,7 +2411,7 @@ let macro_lib =
 			VString (Type.s_type (print_context()) (decode_type v))
 		);
 		"s_expr", Fun2 (fun v b ->
-			let f = match b with VBool true -> Type.s_expr_pretty "" | _ -> Type.s_expr in
+			let f = match b with VBool true -> Type.s_expr_pretty "" | _ -> Type.s_expr_ast true "" in
 			VString (f (Type.s_type (print_context())) (decode_texpr v))
 		);
 		"is_fmt_string", Fun1 (fun v ->
@@ -2371,6 +2453,14 @@ let macro_lib =
 			| _ -> error());
 			VNull
 		);
+		"add_global_metadata", Fun5 (fun v1 v2 v3 v4 v5 ->
+			match v1,v2,v3,v4,v5 with
+				| VString s1,VString s2,VBool b1,VBool b2,VBool b3 ->
+					(get_ctx()).curapi.add_global_metadata s1 s2 (b1,b2,b3);
+					VNull
+				| _ ->
+					error()
+		);
 		"custom_js", Fun1 (fun f ->
 			match f with
 			| VFunction (Fun1 _) ->
@@ -2400,7 +2490,7 @@ let macro_lib =
 				VNull
 			| _ -> error()
 		);
-        "get_resources", Fun0 (fun() ->
+		"get_resources", Fun0 (fun() ->
 			let res = (ccom()).resources in
 			let h = Hashtbl.create 0 in
 			Hashtbl.iter (fun n v -> Hashtbl.replace h (VString n) (VString v)) res;
@@ -2420,16 +2510,29 @@ let macro_lib =
 			| None -> VNull
 			| Some t -> encode_type t
 		);
+		"call_arguments", Fun0 (fun() ->
+			match (get_ctx()).curapi.get_call_arguments() with
+			| None -> VNull
+			| Some el -> enc_array (List.map encode_expr el)
+		);
 		"local_method", Fun0 (fun() ->
 			VString ((get_ctx()).curapi.get_local_method())
 		);
 		"local_using", Fun0 (fun() ->
 			enc_array (List.map encode_clref ((get_ctx()).curapi.get_local_using()))
 		);
-		"local_vars", Fun0 (fun() ->
+		"local_vars", Fun1 (fun as_var ->
+			let as_var = match as_var with
+				| VNull | VBool false -> false
+				| VBool true -> true
+				| _ -> error()
+			in
 			let vars = (get_ctx()).curapi.get_local_vars() in
 			let h = Hashtbl.create 0 in
-			PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_type v.v_type)) vars;
+			if as_var then
+				PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_tvar v)) vars
+			else
+				PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_type v.v_type)) vars;
 			enc_hash h
 		);
 		"follow", Fun2 (fun v once ->
@@ -2443,7 +2546,7 @@ let macro_lib =
 				| TAbstract _ | TEnum _ | TInst _ | TFun _ | TAnon _ | TDynamic _ ->
 					t
 				| TType (t,tl) ->
-					apply_params t.t_types tl t.t_type
+					apply_params t.t_params tl t.t_type
 				| TLazy f ->
 					(!f)()
 			in
@@ -2456,10 +2559,10 @@ let macro_lib =
 			(get_ctx()).curapi.define_type v;
 			VNull
 		);
-		"define_module", Fun2 (fun p v ->
-			match p, v with
-			| VString path, VArray vl ->
-				(get_ctx()).curapi.define_module path (Array.to_list vl);
+		"define_module", Fun4 (fun p v i u ->
+			match p, v, i, u with
+			| VString path, VArray vl, VArray ui, VArray ul ->
+				(get_ctx()).curapi.define_module path (Array.to_list vl) (List.map decode_import (Array.to_list ui)) (List.map decode_path (Array.to_list ul));
 				VNull
 			| _ ->
 				error()
@@ -2481,6 +2584,27 @@ let macro_lib =
 				(match com.platform with
 				| Flash -> Genswf.add_swf_lib com file false
 				| Java -> Genjava.add_java_lib com file false
+				| Cs ->
+					let file, is_std = match ExtString.String.nsplit file "@" with
+						| [file] ->
+							file,false
+						| [file;"std"] ->
+							file,true
+						| _ -> failwith ("unsupported file@`std` format: " ^ file)
+					in
+					Gencs.add_net_lib com file is_std
+				| _ -> failwith "Unsupported platform");
+				VNull
+			| _ ->
+				error()
+		);
+		"add_native_arg", Fun1 (fun v ->
+			match v with
+			| VString arg ->
+				let com = ccom() in
+				(match com.platform with
+				| Java | Cs | Cpp ->
+					com.c_args <- arg :: com.c_args
 				| _ -> failwith "Unsupported platform");
 				VNull
 			| _ ->
@@ -2504,6 +2628,10 @@ let macro_lib =
 			let e = decode_texpr e in
 			encode_expr (make_ast e)
 		);
+		"store_typed_expr", Fun1 (fun e ->
+			let e = try decode_texpr e with Invalid_expr -> error() in
+			encode_expr ((get_ctx()).curapi.store_typed_expr e)
+		);
 		"get_output", Fun0 (fun() ->
 			VString (ccom()).file
 		);
@@ -3449,8 +3577,9 @@ let create com api =
 
 
 
-let do_reuse ctx =
-	ctx.is_reused <- false
+let do_reuse ctx api =
+	ctx.is_reused <- false;
+	ctx.curapi <- api
 
 let can_reuse ctx types =
 	let has_old_version t =
@@ -3958,6 +4087,15 @@ let decode_unop op =
 	| 4, [] -> NegBits
 	| _ -> raise Invalid_expr
 
+let decode_import_mode t =
+	match decode_enum t with
+	| 0, [] -> INormal
+	| 1, [alias] -> IAsName (dec_string alias)
+	| 2, [] -> IAll
+	| _ -> raise Invalid_expr
+
+let decode_import t = (List.map (fun o -> ((dec_string (field o "name")), (decode_pos (field o "pos")))) (dec_array (field t "path")), decode_import_mode (field t "mode"))
+
 let rec decode_path t =
 	{
 		tpackage = List.map dec_string (dec_array (field t "pack"));
@@ -4183,6 +4321,10 @@ let encode_meta m set =
 				failwith "Invalid expression");
 			VNull
 		));
+		"extract", VFunction (Fun1 (fun k ->
+			let k = MetaInfo.from_string (try dec_string k with Invalid_expr -> raise Builtin_error) in
+			encode_array encode_meta_entry (List.filter (fun (m,_,_) -> m = k) (!meta))
+		));
 		"remove", VFunction (Fun1 (fun k ->
 			let k = MetaInfo.from_string (try dec_string k with Invalid_expr -> raise Builtin_error) in
 			meta := List.filter (fun (m,_,_) -> m <> k) (!meta);
@@ -4206,7 +4348,7 @@ let rec encode_mtype t fields =
 		"isPrivate", VBool i.mt_private;
 		"meta", encode_meta i.mt_meta (fun m -> i.mt_meta <- m);
 		"doc", null enc_string i.mt_doc;
-		"params", encode_type_params i.mt_types;
+		"params", encode_type_params i.mt_params;
 	] @ fields)
 
 and encode_type_params tl =
@@ -4226,8 +4368,8 @@ and encode_tabstract a =
 		"impl", (match a.a_impl with None -> VNull | Some c -> encode_clref c);
 		"binops", enc_array (List.map (fun (op,cf) -> enc_obj [ "op",encode_binop op; "field",encode_cfield cf]) a.a_ops);
 		"unops", enc_array (List.map (fun (op,postfix,cf) -> enc_obj [ "op",encode_unop op; "isPostfix",VBool (match postfix with Postfix -> true | Prefix -> false); "field",encode_cfield cf]) a.a_unops);
-		"from", enc_array (List.map (fun (t,cfo) -> enc_obj [ "t",encode_type t; "field",match cfo with None -> VNull | Some cf -> encode_cfield cf]) a.a_from);
-		"to", enc_array (List.map (fun (t,cfo) -> enc_obj [ "t",encode_type t; "field",match cfo with None -> VNull | Some cf -> encode_cfield cf]) a.a_to);
+		"from", enc_array ((List.map (fun t -> enc_obj [ "t",encode_type t; "field",VNull]) a.a_from) @ (List.map (fun (t,cf) -> enc_obj [ "t",encode_type t; "field",encode_cfield cf]) a.a_from_field));
+		"to", enc_array ((List.map (fun t -> enc_obj [ "t",encode_type t; "field",VNull]) a.a_to) @ (List.map (fun (t,cf) -> enc_obj [ "t",encode_type t; "field",encode_cfield cf]) a.a_to_field));
 		"array", enc_array (List.map encode_cfield a.a_array);
 	]
 
@@ -4298,7 +4440,7 @@ and encode_class_kind k =
 	enc_enum IClassKind tag pl
 
 and encode_tclass c =
-	c.cl_build();
+	ignore(c.cl_build());
 	encode_mtype (TClassDecl c) [
 		"kind", encode_class_kind c.cl_kind;
 		"isExtern", VBool c.cl_extern;
@@ -4334,9 +4476,10 @@ and encode_anon_status s =
 		| Closed -> 0, []
 		| Opened -> 1, []
 		| Type.Const -> 2, []
-		| Statics cl -> 3, [encode_clref cl]
-		| EnumStatics en -> 4, [encode_enref en]
-		| AbstractStatics ab -> 5, [encode_abref ab]
+		| Extend tl -> 3, [encode_ref tl (fun tl -> enc_array (List.map encode_type tl)) (fun() -> "<extended types>")]
+		| Statics cl -> 4, [encode_clref cl]
+		| EnumStatics en -> 5, [encode_enref en]
+		| AbstractStatics ab -> 6, [encode_abref ab]
 	)
 	in
 	enc_enum IAnonStatus tag pl
@@ -4436,7 +4579,7 @@ let vopt f v = match v with
 
 let rec encode_tconst c =
 	let tag, pl = match c with
-		| TInt i -> 0,[VInt (Int32.to_int i)]
+		| TInt i -> 0,[best_int i]
 		| TFloat f -> 1,[enc_string f]
 		| TString s -> 2,[enc_string s]
 		| TBool b -> 3,[VBool b]
@@ -4460,6 +4603,7 @@ and encode_tvar v =
 		"capture", VBool v.v_capture;
 		"extra", vopt f_extra v.v_extra;
 		"meta", encode_meta_content v.v_meta;
+		"$", VAbstract (AUnsafe (Obj.repr v));
 	]
 
 and encode_module_type mt =
@@ -4485,11 +4629,11 @@ and encode_tfunc func =
 
 and encode_field_access fa =
 	let tag,pl = match fa with
-		| FInstance(c,cf) -> 0,[encode_clref c;encode_cfref cf]
+		| FInstance(c,_,cf) -> 0,[encode_clref c;encode_cfref cf] (* TODO: breaking change, kind of *)
 		| FStatic(c,cf) -> 1,[encode_clref c;encode_cfref cf]
 		| FAnon(cf) -> 2,[encode_cfref cf]
 		| FDynamic(s) -> 3,[enc_string s]
-		| FClosure(co,cf) -> 4,[vopt encode_clref co;encode_cfref cf]
+		| FClosure(co,cf) -> 4,[(match co with Some (c,_) -> encode_clref c | None -> VNull);encode_cfref cf] (* TODO: breaking change, kind of, too *)
 		| FEnum(en,ef) -> 5,[encode_enref en;encode_efield ef]
 	in
 	enc_enum IFieldAccess tag pl
@@ -4524,9 +4668,7 @@ and encode_texpr e =
 				enc_array (List.map (fun (el,e) -> enc_obj ["values",encode_texpr_list el;"expr",loop e]) cases);
 				vopt encode_texpr edef
 				]
-			| TPatMatch _ ->
-				assert false
-			| TTry(e1,catches) -> 20,[
+			| TTry(e1,catches) -> 19,[
 				loop e1;
 				enc_array (List.map (fun (v,e) ->
 					enc_obj [
@@ -4534,13 +4676,13 @@ and encode_texpr e =
 						"expr",loop e
 					]) catches
 				)]
-			| TReturn e1 -> 21,[vopt encode_texpr e1]
-			| TBreak -> 22,[]
-			| TContinue -> 23,[]
-			| TThrow e1 -> 24,[loop e1]
-			| TCast(e1,mt) -> 25,[loop e1;match mt with None -> VNull | Some mt -> encode_module_type mt]
-			| TMeta(m,e1) -> 26,[encode_meta_entry m;loop e1]
-			| TEnumParameter(e1,ef,i) -> 27,[loop e1;encode_efield ef;VInt i]
+			| TReturn e1 -> 20,[vopt encode_texpr e1]
+			| TBreak -> 21,[]
+			| TContinue -> 22,[]
+			| TThrow e1 -> 23,[loop e1]
+			| TCast(e1,mt) -> 24,[loop e1;match mt with None -> VNull | Some mt -> encode_module_type mt]
+			| TMeta(m,e1) -> 25,[encode_meta_entry m;loop e1]
+			| TEnumParameter(e1,ef,i) -> 26,[loop e1;encode_efield ef;VInt i]
 		in
 		enc_obj [
 			"pos", encode_pos e.epos;
@@ -4558,7 +4700,7 @@ and encode_texpr_list el =
 
 let decode_tconst c =
 	match decode_enum c with
-	| 0, [s] -> TInt (match s with VInt i -> Int32.of_int i | _ -> raise Invalid_expr)
+	| 0, [s] -> TInt (match s with VInt i -> Int32.of_int i | VInt32 i -> i | _ -> raise Invalid_expr)
 	| 1, [s] -> TFloat (dec_string s)
 	| 2, [s] -> TString (dec_string s)
 	| 3, [s] -> TBool (dec_bool s)
@@ -4571,17 +4713,9 @@ let decode_type_params v =
 	List.map (fun v -> dec_string (field v "name"),decode_type (field v "t")) (dec_array v)
 
 let decode_tvar v =
-	let f_extra v =
-		decode_type_params (field v "params"),opt decode_texpr (field v "expr")
-	in
-	{
-		v_id = (match (field v "id") with VInt i -> i | _ -> raise Invalid_expr);
-		v_name = dec_string (field v "name");
-		v_type = decode_type (field v "t");
-		v_capture = dec_bool (field v "capture");
-		v_extra = opt f_extra (field v "extra");
-		v_meta = decode_meta_content (field v "meta")
-	}
+	match field v "$" with
+	| VAbstract (AUnsafe t) -> Obj.obj t
+	| _ -> raise Invalid_expr
 
 let decode_var_access v =
 	match decode_enum v with
@@ -4635,7 +4769,9 @@ let decode_efield v =
 
 let decode_field_access v =
 	match decode_enum v with
-	| 0, [c;cf] -> FInstance(decode_ref c,decode_ref cf)
+	| 0, [c;cf] ->
+		let c = decode_ref c in
+		FInstance(c,List.map snd c.cl_params,decode_ref cf) (* TODO: breaking change? *)
 	| 1, [c;cf] -> FStatic(decode_ref c,decode_ref cf)
 	| 2, [cf] -> FAnon(decode_ref cf)
 	| 3, [s] -> FDynamic(dec_string s)
@@ -4682,16 +4818,15 @@ let rec decode_texpr v =
 		| 16, [vif;vthen;velse] -> TIf(loop vif,loop vthen,opt loop velse)
 		| 17, [vcond;v1;b] -> TWhile(loop vcond,loop v1,if dec_bool b then NormalWhile else DoWhile)
 		| 18, [v1;cl;vdef] -> TSwitch(loop v1,List.map (fun v -> List.map loop (dec_array (field v "values")),loop (field v "expr")) (dec_array cl),opt loop vdef)
-		| 19, [dt] -> assert false
-		| 20, [v1;cl] -> TTry(loop v1,List.map (fun v -> decode_tvar (field v "v"),loop (field v "expr")) (dec_array cl))
-		| 21, [vo] -> TReturn(opt loop vo)
-		| 22, [] -> TBreak
-		| 23, [] -> TContinue
-		| 24, [v1] -> TThrow(loop v1)
-		| 25, [v1;mto] -> TCast(loop v1,opt decode_module_type mto)
-		| 26, [m;v1] -> TMeta(decode_meta_entry m,loop v1)
-		| 27, [v1;ef;i] -> TEnumParameter(loop v1,decode_efield ef,match i with VInt i -> i | _ -> raise Invalid_expr)
-		| _ -> raise Invalid_expr
+		| 19, [v1;cl] -> TTry(loop v1,List.map (fun v -> decode_tvar (field v "v"),loop (field v "expr")) (dec_array cl))
+		| 20, [vo] -> TReturn(opt loop vo)
+		| 21, [] -> TBreak
+		| 22, [] -> TContinue
+		| 23, [v1] -> TThrow(loop v1)
+		| 24, [v1;mto] -> TCast(loop v1,opt decode_module_type mto)
+		| 25, [m;v1] -> TMeta(decode_meta_entry m,loop v1)
+		| 26, [v1;ef;i] -> TEnumParameter(loop v1,decode_efield ef,match i with VInt i -> i | _ -> raise Invalid_expr)
+		| i,el -> Printf.printf "%i %i\n" i (List.length el); raise Invalid_expr
 	in
 	try
 		loop v
@@ -4919,7 +5054,6 @@ let rec make_ast e =
 		) cases in
 		let def = match eopt def with None -> None | Some (EBlock [],_) -> Some None | e -> Some e in
 		ESwitch (make_ast e,cases,def)
-	| TPatMatch _
 	| TEnumParameter _ ->
 		(* these are considered complex, so the AST is handled in TMeta(Meta.Ast) *)
 		assert false
@@ -4954,4 +5088,7 @@ encode_clref_ref := encode_clref;
 enc_string_ref := enc_string;
 enc_hash_ref := enc_hash;
 encode_texpr_ref := encode_texpr;
-decode_texpr_ref := decode_texpr
+decode_texpr_ref := decode_texpr;
+encode_tvar_ref := encode_tvar;
+decode_path_ref := decode_path;
+decode_import_ref := decode_import;

+ 9 - 8
lexer.mll

@@ -85,10 +85,10 @@ let keywords =
 		Inline;Using;Null;True;False;Abstract;Macro];
 	h
 
-let init file =
+let init file do_add =
 	let f = make_file file in
 	cur := f;
-	Hashtbl.replace all_files file f
+	if do_add then Hashtbl.replace all_files file f
 
 let save() =
 	!cur
@@ -220,6 +220,7 @@ let invalid_char lexbuf =
 
 let ident = ('_'* ['a'-'z'] ['_' 'a'-'z' 'A'-'Z' '0'-'9']* | '_'+ | '_'+ ['0'-'9'] ['_' 'a'-'z' 'A'-'Z' '0'-'9']* )
 let idtype = '_'* ['A'-'Z'] ['_' 'a'-'z' 'A'-'Z' '0'-'9']*
+let integer = ['1'-'9'] ['0'-'9']* | '0'
 
 rule skip_header = parse
 	| "\239\187\191" { skip_header lexbuf }
@@ -232,12 +233,12 @@ and token = parse
 	| "\r\n" { newline lexbuf; token lexbuf }
 	| '\n' | '\r' { newline lexbuf; token lexbuf }
 	| "0x" ['0'-'9' 'a'-'f' 'A'-'F']+ { mk lexbuf (Const (Int (lexeme lexbuf))) }
-	| ['0'-'9']+ { mk lexbuf (Const (Int (lexeme lexbuf))) }
-	| ['0'-'9']+ '.' ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) }
+	| integer { mk lexbuf (Const (Int (lexeme lexbuf))) }
+	| integer '.' ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) }
 	| '.' ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) }
-	| ['0'-'9']+ ['e' 'E'] ['+' '-']? ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) }
-	| ['0'-'9']+ '.' ['0'-'9']* ['e' 'E'] ['+' '-']? ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) }
-	| ['0'-'9']+ "..." {
+	| integer ['e' 'E'] ['+' '-']? ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) }
+	| integer '.' ['0'-'9']* ['e' 'E'] ['+' '-']? ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) }
+	| integer "..." {
 			let s = lexeme lexbuf in
 			mk lexbuf (IntInterval (String.sub s 0 (String.length s - 3)))
 		}
@@ -367,7 +368,7 @@ and string2 = parse
 		string2 lexbuf;
 	}
 	| [^'\'' '\\' '\r' '\n' '$']+ { store lexbuf; string2 lexbuf }
-	
+
 and code_string = parse
 	| eof { raise Exit }
 	| '\n' | '\r' | "\r\n" { newline lexbuf; store lexbuf; code_string lexbuf }

+ 1 - 1
libs

@@ -1 +1 @@
-Subproject commit 3a4b14d06216b5fe3aef666acc5cc436ce76dd86
+Subproject commit 371962aacc1bcd1b5578df62a1500f436d6f0c73

+ 285 - 110
main.ml

@@ -20,6 +20,31 @@
  * DEALINGS IN THE SOFTWARE.
  *)
 
+(*
+	Conventions:
+	- e: expression (typed or untyped)
+	- c: class
+	- en: enum
+	- td: typedef (tdef)
+	- a: abstract
+	- an: anon
+	- tf: tfunc
+	- cf: class_field
+	- ef: enum_field
+	- t: type (t)
+	- ct: complex_type
+	- v: local variable (tvar)
+	- m: module (module_def)
+	- mt: module_type
+	- p: pos
+
+	"param" refers to type parameters
+	"arg" refers to function arguments
+	leading s_ means function returns string
+	trailing l means list (but we also use natural plurals such as "metas")
+	semantic suffixes may be used freely (e.g. e1, e_if, e')
+*)
+
 open Printf
 open Ast
 open Genswf
@@ -45,7 +70,7 @@ exception Abort
 exception Completion of string
 
 
-let version = 3103
+let version = 3200
 let version_major = version / 1000
 let version_minor = (version mod 1000) / 100
 let version_revision = (version mod 100)
@@ -143,16 +168,28 @@ let htmlescape s =
 	s
 
 let reserved_flags = [
-	"cross";"flash8";"js";"neko";"flash";"php";"cpp";"cs";"java";
+	"cross";"flash8";"js";"neko";"flash";"php";"cpp";"cs";"java";"python";
 	"as3";"swc";"macro";"sys"
 	]
 
-let complete_fields fields =
+let complete_fields com fields =
 	let b = Buffer.create 0 in
+	let details = Common.raw_defined com "display-details" in
 	Buffer.add_string b "<list>\n";
-	List.iter (fun (n,t,d) ->
-		Buffer.add_string b (Printf.sprintf "<i n=\"%s\"><t>%s</t><d>%s</d></i>\n" n (htmlescape t) (htmlescape d))
-	) (List.sort (fun (a,_,_) (b,_,_) -> compare a b) fields);
+	List.iter (fun (n,t,k,d) ->
+		let s_kind = match k with
+			| Some k -> (match k with
+				| Typer.FKVar -> "var"
+				| Typer.FKMethod -> "method"
+				| Typer.FKType -> "type"
+				| Typer.FKPackage -> "package")
+			| None -> ""
+		in
+		if details then
+			Buffer.add_string b (Printf.sprintf "<i n=\"%s\" k=\"%s\"><t>%s</t><d>%s</d></i>\n" n s_kind (htmlescape t) (htmlescape d))
+		else
+			Buffer.add_string b (Printf.sprintf "<i n=\"%s\"><t>%s</t><d>%s</d></i>\n" n (htmlescape t) (htmlescape d))
+	) (List.sort (fun (a,_,ak,_) (b,_,bk,_) -> compare (ak,a) (bk,b)) fields);
 	Buffer.add_string b "</list>\n";
 	raise (Completion (Buffer.contents b))
 
@@ -173,32 +210,35 @@ let make_path f =
 		| ["hx";path] -> ExtString.String.nsplit path "/"
 		| _ -> cl
 	) in
-	let error() =
-		let msg = "Could not process argument " ^ f in
-		let msg = msg ^ "\n" ^
-			if String.length f == 0 then
-				"Class name must not be empty"
-			else match (List.hd (List.rev cl)).[0] with
-				| 'A'..'Z' -> "Invalid class name"
-				| _ -> "Class name must start with uppercase character"
-		in
+	let error msg =
+		let msg = "Could not process argument " ^ f ^ "\n" ^ msg in
 		failwith msg
 	in
 	let invalid_char x =
 		for i = 1 to String.length x - 1 do
 			match x.[i] with
 			| 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' -> ()
-			| _ -> error()
-		done;
-		false
+			| c -> error ("invalid character: " ^ (String.make 1 c))
+		done
 	in
 	let rec loop = function
-		| [] -> error()
-		| [x] -> if String.length x = 0 || not (x.[0] = '_' || (x.[0] >= 'A' && x.[0] <= 'Z')) || invalid_char x then error() else [] , x
+		| [] ->
+			error "empty part"
+		| [x] ->
+			if String.length x = 0 then
+				error "empty part"
+			else if not (x.[0] = '_' || (x.[0] >= 'A' && x.[0] <= 'Z')) then
+				error "Class name must start with uppercase character";
+			invalid_char x;
+			[],x
 		| x :: l ->
-			if String.length x = 0 || x.[0] < 'a' || x.[0] > 'z' || invalid_char x then error() else
-				let path , name = loop l in
-				x :: path , name
+			if String.length x = 0 then
+				error "empty part"
+			else if x.[0] < 'a' || x.[0] > 'z' then
+				error "Package name must start with a lower case character";
+			invalid_char x;
+			let path,name = loop l in
+			x :: path,name
 	in
 	loop cl
 
@@ -262,30 +302,30 @@ let rec read_type_path com p =
 			loop path p
 		) (extract());
 	) com.swf_libs;
-  List.iter (fun (path,std,close,all_files,lookup) ->
-    List.iter (fun (path, name) ->
-      if path = p then classes := name :: !classes else
-      let rec loop p1 p2 =
-        match p1, p2 with
-        | [], _ -> ()
-        | x :: _, [] -> packages := x :: !packages
-        | a :: p1, b :: p2 -> if a = b then loop p1 p2
-      in
-      loop path p
-    ) (all_files())
-  ) com.java_libs;
-  List.iter (fun (path,std,all_files,lookup) ->
-    List.iter (fun (path, name) ->
-      if path = p then classes := name :: !classes else
-      let rec loop p1 p2 =
-        match p1, p2 with
-        | [], _ -> ()
-        | x :: _, [] -> packages := x :: !packages
-        | a :: p1, b :: p2 -> if a = b then loop p1 p2
-      in
-      loop path p
-    ) (all_files())
-  ) com.net_libs;
+	List.iter (fun (path,std,close,all_files,lookup) ->
+		List.iter (fun (path, name) ->
+			if path = p then classes := name :: !classes else
+			let rec loop p1 p2 =
+				match p1, p2 with
+				| [], _ -> ()
+				| x :: _, [] -> packages := x :: !packages
+				| a :: p1, b :: p2 -> if a = b then loop p1 p2
+			in
+			loop path p
+		) (all_files())
+	) com.java_libs;
+	List.iter (fun (path,std,all_files,lookup) ->
+		List.iter (fun (path, name) ->
+			if path = p then classes := name :: !classes else
+			let rec loop p1 p2 =
+				match p1, p2 with
+				| [], _ -> ()
+				| x :: _, [] -> packages := x :: !packages
+				| a :: p1, b :: p2 -> if a = b then loop p1 p2
+			in
+		loop path p
+		) (all_files())
+	) com.net_libs;
 	unique !packages, unique !classes
 
 let delete_file f = try Sys.remove f with _ -> ()
@@ -325,7 +365,7 @@ let parse_hxml_data data =
 	) lines)
 
 let parse_hxml file =
-	let ch = IO.input_channel (try open_in_bin file with _ -> failwith ("File not found " ^ file)) in
+	let ch = IO.input_channel (try open_in_bin file with _ -> raise Not_found) in
 	let data = IO.read_all ch in
 	IO.close_in ch;
 	parse_hxml_data data
@@ -609,8 +649,8 @@ let rec process_params create pl =
 			loop [] l
 		| "--cwd" :: dir :: l ->
 			(* we need to change it immediately since it will affect hxml loading *)
-			(try Unix.chdir dir with _ -> ());
-			loop (dir :: "--cwd" :: acc) l
+			(try Unix.chdir dir with _ -> raise (Arg.Bad "Invalid directory"));
+			loop acc l
 		| "--connect" :: hp :: l ->
 			(match !global_cache with
 			| None ->
@@ -627,7 +667,9 @@ let rec process_params create pl =
 			ctx.flush()
 		| arg :: l ->
 			match List.rev (ExtString.String.nsplit arg ".") with
-			| "hxml" :: _ when (match acc with "-cmd" :: _ -> false | _ -> true) -> loop acc (parse_hxml arg @ l)
+			| "hxml" :: _ when (match acc with "-cmd" :: _ -> false | _ -> true) ->
+				let acc, l = (try acc, parse_hxml arg @ l with Not_found -> (arg ^ " (file not found)") :: acc, l) in
+				loop acc l
 			| _ -> loop (arg :: acc) l
 	in
 	(* put --display in front if it was last parameter *)
@@ -676,7 +718,10 @@ and wait_loop boot_com host port =
 		Hashtbl.replace cache.c_modules (m.m_path,m.m_extra.m_sign) m;
 	in
 	let check_module_path com m p =
-		m.m_extra.m_file = Common.unique_full_path (Typeload.resolve_module_file com m.m_path (ref[]) p)
+		if m.m_extra.m_file <> Common.unique_full_path (Typeload.resolve_module_file com m.m_path (ref[]) p) then begin
+			if verbose then print_endline ("Module path " ^ s_type_path m.m_path ^ " has been changed");
+			raise Not_found;
+		end
 	in
 	let compilation_step = ref 0 in
 	let compilation_mark = ref 0 in
@@ -699,13 +744,35 @@ and wait_loop boot_com host port =
 				if m.m_extra.m_mark <= start_mark then begin
 					(match m.m_extra.m_kind with
 					| MFake | MSub -> () (* don't get classpath *)
-					| MCode -> if not (check_module_path com2 m p) then raise Not_found;
-					| MMacro when ctx.Typecore.in_macro -> if not (check_module_path com2 m p) then raise Not_found;
+					| MExtern ->
+						(* if we have a file then this will override our extern type *)
+						let has_file = (try ignore(Typeload.resolve_module_file com2 m.m_path (ref[]) p); true with Not_found -> false) in
+						if has_file then begin
+							if verbose then print_endline ("A file is masking the library file " ^ s_type_path m.m_path);
+							raise Not_found;
+						end;
+						let rec loop = function
+							| [] ->
+								if verbose then print_endline ("No library file was found for " ^ s_type_path m.m_path);
+								raise Not_found (* no extern registration *)
+							| load :: l ->
+								match load m.m_path p with
+								| None -> loop l
+								| Some (file,_) ->
+									if Common.unique_full_path file <> m.m_extra.m_file then begin
+										if verbose then print_endline ("Library file was changed for " ^ s_type_path m.m_path);
+										raise Not_found;
+									end
+						in
+						loop com2.load_extern_type
+					| MCode -> check_module_path com2 m p
+					| MMacro when ctx.Typecore.in_macro -> check_module_path com2 m p
 					| MMacro ->
 						let _, mctx = Typer.get_macro_context ctx p in
-						if not (check_module_path mctx.Typecore.com m p) then raise Not_found;
+						check_module_path mctx.Typecore.com m p
 					);
 					if file_time m.m_extra.m_file <> m.m_extra.m_time then begin
+						if verbose then print_endline ("File " ^ m.m_extra.m_file ^ (if m.m_extra.m_time = -1. then " not cached (macro-in-macro)" else " has been modified"));
 						if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules m.m_extra.m_file;
 						raise Not_found;
 					end;
@@ -911,7 +978,7 @@ and do_connect host port args =
 
 and init ctx =
 	let usage = Printf.sprintf
-		"Haxe Compiler %s %s- (C)2005-2014 Haxe Foundation\n Usage : haxe%s -main <class> [-swf|-js|-neko|-php|-cpp|-as3] <output> [options]\n Options :"
+		"Haxe Compiler %s %s- (C)2005-2015 Haxe Foundation\n Usage : haxe%s -main <class> [-swf|-js|-neko|-php|-cpp|-as3] <output> [options]\n Options :"
 		s_version (match Version.version_extra with None -> "" | Some v -> v) (if Sys.os_type = "Win32" then ".exe" else "")
 	in
 	let com = ctx.com in
@@ -929,8 +996,9 @@ try
 	let pre_compilation = ref [] in
 	let interp = ref false in
 	let swf_version = ref false in
+	let evals = ref [] in
 	Common.define_value com Define.HaxeVer (float_repres (float_of_int version /. 1000.));
-	Common.define_value com Define.HxcppApiLevel "311";
+	Common.define_value com Define.HxcppApiLevel "321";
 	Common.raw_define com "haxe3";
 	Common.define_value com Define.Dce "std";
 	com.warning <- (fun msg p -> message ctx ("Warning : " ^ msg) p);
@@ -954,7 +1022,7 @@ try
 	with
 		Not_found ->
 			if Sys.os_type = "Unix" then
-				com.class_path <- ["/usr/lib/haxe/std/";"/usr/local/lib/haxe/std/";"/usr/lib/haxe/extraLibs/";"/usr/local/lib/haxe/extraLibs/";""]
+				com.class_path <- ["/usr/lib/haxe/std/";"/usr/share/haxe/std/";"/usr/local/lib/haxe/std/";"/usr/lib/haxe/extraLibs/";"/usr/local/lib/haxe/extraLibs/";""]
 			else
 				let base_path = normalize_path (get_real_path (try executable_path() with _ -> "./")) in
 				com.class_path <- [base_path ^ "std/";base_path ^ "extraLibs/";""]);
@@ -976,6 +1044,7 @@ try
 		| [] -> ()
 		| args -> (!process_ref) args
 	in
+	let arg_delays = ref [] in
 	let basic_args_spec = [
 		("-cp",Arg.String (fun path ->
 			process_libs();
@@ -996,7 +1065,7 @@ try
 		("-cpp",Arg.String (fun dir ->
 			set_platform Cpp dir;
 		),"<directory> : generate C++ code into target directory");
- 		("-cs",Arg.String (fun dir ->
+		("-cs",Arg.String (fun dir ->
 			cp_libs := "hxcs" :: !cp_libs;
 			set_platform Cs dir;
 		),"<directory> : generate C# code into target directory");
@@ -1004,6 +1073,9 @@ try
 			cp_libs := "hxjava" :: !cp_libs;
 			set_platform Java dir;
 		),"<directory> : generate Java code into target directory");
+		("-python",Arg.String (fun dir ->
+			set_platform Python dir;
+		),"<file> : generate Python code as target file");
 		("-xml",Arg.String (fun file ->
 			Parser.use_doc := true;
 			xml_out := Some file
@@ -1044,7 +1116,7 @@ try
 		("-swf-version",Arg.Float (fun v ->
 			if not !swf_version || com.flash_version < v then com.flash_version <- v;
 			swf_version := true;
-		),"<version> : change the SWF version (6 to 10)");
+		),"<version> : change the SWF version");
 		("-swf-header",Arg.String (fun h ->
 			try
 				swf_header := Some (match ExtString.String.nsplit h ":" with
@@ -1065,7 +1137,8 @@ try
 			Genswf.add_swf_lib com file true
 		),"<file> : use the SWF library for type checking");
 		("-java-lib",Arg.String (fun file ->
-			Genjava.add_java_lib com file false
+			let std = file = "lib/hxjava-std.jar" in
+			arg_delays := (fun () -> Genjava.add_java_lib com file std) :: !arg_delays;
 		),"<file> : add an external JAR or class directory library");
 		("-net-lib",Arg.String (fun file ->
 			let file, is_std = match ExtString.String.nsplit file "@" with
@@ -1075,11 +1148,14 @@ try
 					file,true
 				| _ -> raise Exit
 			in
-			Gencs.add_net_lib com file is_std
+			arg_delays := (fun () -> Gencs.add_net_lib com file is_std) :: !arg_delays;
 		),"<file>[@std] : add an external .NET DLL file");
 		("-net-std",Arg.String (fun file ->
 			Gencs.add_net_std com file
 		),"<file> : add a root std .NET DLL search path");
+		("-c-arg",Arg.String (fun arg ->
+			com.c_args <- arg :: com.c_args
+		),"<arg> : pass option <arg> to the native Java/C# compiler");
 		("-x", Arg.String (fun file ->
 			let neko_file = file ^ ".n" in
 			set_platform Neko neko_file;
@@ -1120,33 +1196,66 @@ try
 				List.iter (fun (_,_,extract) ->
 					Hashtbl.iter (fun n _ -> classes := n :: !classes) (extract())
 				) com.swf_libs;
+				List.iter (fun (_,std,_,all_files,_) ->
+					if not std then
+						List.iter (fun path -> if path <> (["java";"lang"],"String") then classes := path :: !classes) (all_files())
+				) com.java_libs;
+				List.iter (fun (_,std,all_files,_) ->
+					if not std then
+						List.iter (fun path -> classes := path :: !classes) (all_files())
+				) com.net_libs;
 			) :: !pre_compilation;
 			xml_out := Some "hx"
 		),": generate hx headers for all input classes");
 		("--next", Arg.Unit (fun() -> assert false), ": separate several haxe compilations");
+		("--each", Arg.Unit (fun() -> assert false), ": append preceding parameters to all haxe compilations separated by --next");
 		("--display", Arg.String (fun file_pos ->
 			match file_pos with
 			| "classes" ->
-				pre_compilation := (fun() -> raise (Parser.TypePath (["."],None))) :: !pre_compilation;
+				pre_compilation := (fun() -> raise (Parser.TypePath (["."],None,true))) :: !pre_compilation;
 			| "keywords" ->
-				complete_fields (Hashtbl.fold (fun k _ acc -> (k,"","") :: acc) Lexer.keywords [])
+				complete_fields com (Hashtbl.fold (fun k _ acc -> (k,"",None,"") :: acc) Lexer.keywords [])
 			| "memory" ->
 				did_something := true;
 				(try display_memory ctx with e -> prerr_endline (Printexc.get_backtrace ()));
 			| _ ->
 				let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format : " ^ file_pos) in
 				let file = unquote file in
-				let pos, mode = try ExtString.String.split pos "@" with _ -> pos,"" in
-				let mode = match mode with
-					| "position" -> DMPosition
-					| "usage" -> DMUsage
-					| "metadata" -> DMMetadata
-					| _ -> DMDefault
+				let pos, smode = try ExtString.String.split pos "@" with _ -> pos,"" in
+				let activate_special_display_mode () =
+					Common.define com Define.NoCOpt;
+					Parser.use_parser_resume := false
+				in
+				let mode = match smode with
+					| "position" ->
+						activate_special_display_mode();
+						DMPosition
+					| "usage" ->
+						activate_special_display_mode();
+						DMUsage
+					| "type" ->
+						activate_special_display_mode();
+						DMType
+					| "toplevel" ->
+						activate_special_display_mode();
+						DMToplevel
+					| "" ->
+						Parser.use_parser_resume := true;
+						DMDefault
+					| _ ->
+						let smode,arg = try ExtString.String.split smode "@" with _ -> pos,"" in
+						match smode with
+							| "resolve" ->
+								activate_special_display_mode();
+								DMResolve arg
+							| _ ->
+								Parser.use_parser_resume := true;
+								DMDefault
 				in
 				let pos = try int_of_string pos with _ -> failwith ("Invalid format : "  ^ pos) in
 				com.display <- mode;
 				Common.display_default := mode;
-				Common.define com Define.Display;
+				Common.define_value com Define.Display (if smode <> "" then smode else "1");
 				Parser.use_doc := true;
 				Parser.resume_display := {
 					Ast.pfile = Common.unique_full_path file;
@@ -1166,9 +1275,9 @@ try
 			com.php_front <- Some f;
 		),"<filename> : select the name for the php front file");
 		("--php-lib",Arg.String (fun f ->
- 			if com.php_lib <> None then raise (Arg.Bad "Multiple --php-lib");
- 			com.php_lib <- Some f;
- 		),"<filename> : select the name for the php lib folder");
+			if com.php_lib <> None then raise (Arg.Bad "Multiple --php-lib");
+			com.php_lib <- Some f;
+		),"<filename> : select the name for the php lib folder");
 		("--php-prefix", Arg.String (fun f ->
 			if com.php_prefix <> None then raise (Arg.Bad "Multiple --php-prefix");
 			com.php_prefix <- Some f;
@@ -1188,6 +1297,10 @@ try
 			force_typing := true;
 			config_macros := e :: !config_macros
 		)," : call the given macro before typing anything else");
+		("--eval", Arg.String (fun s ->
+			force_typing := true;
+			evals := s :: !evals;
+		), " : evaluates argument as Haxe module code");
 		("--wait", Arg.String (fun hp ->
 			let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in
 			wait_loop com host (try int_of_string port with _ -> raise (Arg.Bad "Invalid port"))
@@ -1196,7 +1309,7 @@ try
 			assert false
 		),"<[host:]port> : connect on the given port and run commands there)");
 		("--cwd", Arg.String (fun dir ->
-			(try Unix.chdir dir with _ -> raise (Arg.Bad "Invalid directory"))
+			assert false
 		),"<dir> : set current working directory");
 		("-version",Arg.Unit (fun() ->
 			message ctx s_version Ast.null_pos;
@@ -1261,8 +1374,9 @@ try
 	let all_args_spec = basic_args_spec @ adv_args_spec in
 	let process args =
 		let current = ref 0 in
-		try
-			Arg.parse_argv ~current (Array.of_list ("" :: List.map expand_env args)) all_args_spec args_callback usage
+		(try
+			Arg.parse_argv ~current (Array.of_list ("" :: List.map expand_env args)) all_args_spec args_callback usage;
+			List.iter (fun fn -> fn()) !arg_delays
 		with (Arg.Bad msg) as exc ->
 			let r = Str.regexp "unknown option `\\([-A-Za-z]+\\)'" in
 			try
@@ -1272,7 +1386,8 @@ try
 				let msg = Typecore.string_error_raise s sl (Printf.sprintf "Invalid command: %s" s) in
 				raise (Arg.Bad msg)
 			with Not_found ->
-				raise exc
+				raise exc);
+		arg_delays := []
 	in
 	process_ref := process;
 	process ctx.com.args;
@@ -1345,21 +1460,26 @@ try
 			Gencs.before_generate com;
 			add_std "cs"; "cs"
 		| Java ->
-      let old_flush = ctx.flush in
-      ctx.flush <- (fun () ->
-        List.iter (fun (_,_,close,_,_) -> close()) com.java_libs;
-        old_flush()
-      );
+			let old_flush = ctx.flush in
+			ctx.flush <- (fun () ->
+				List.iter (fun (_,_,close,_,_) -> close()) com.java_libs;
+				old_flush()
+			);
 			Genjava.before_generate com;
 			add_std "java"; "java"
+		| Python ->
+			add_std "python";
+			"python"
 	) in
 	(* if we are at the last compilation step, allow all packages accesses - in case of macros or opening another project file *)
-	if com.display <> DMNone && not ctx.has_next then com.package_rules <- PMap.foldi (fun p r acc -> match r with Forbidden -> acc | _ -> PMap.add p r acc) com.package_rules PMap.empty;
+	begin match com.display with
+		| DMNone | DMToplevel ->
+			()
+		| _ ->
+			if not ctx.has_next then com.package_rules <- PMap.foldi (fun p r acc -> match r with Forbidden -> acc | _ -> PMap.add p r acc) com.package_rules PMap.empty;
+	end;
 	com.config <- get_config com; (* make sure to adapt all flags changes defined after platform *)
 
-	(* check file extension. In case of wrong commandline, we don't want
-		to accidentaly delete a source file. *)
-	if not !no_output && file_extension com.file = ext then delete_file com.file;
 	List.iter (fun f -> f()) (List.rev (!pre_compilation));
 	if !classes = [([],"Std")] && not !force_typing then begin
 		let help_spec = basic_args_spec @ [
@@ -1378,12 +1498,13 @@ try
 		Typecore.type_expr_ref := (fun ctx e with_type -> Typer.type_expr ctx e with_type);
 		let tctx = Typer.create com in
 		List.iter (Typer.call_init_macro tctx) (List.rev !config_macros);
+		List.iter (Typer.eval tctx) !evals;
 		List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath Ast.null_pos)) (List.rev !classes);
 		Typer.finalize tctx;
 		t();
 		if ctx.has_error then raise Abort;
 		begin match com.display with
-			| DMNone | DMUsage ->
+			| DMNone | DMUsage | DMPosition | DMType | DMResolve _ ->
 				()
 			| _ ->
 				if ctx.has_next then raise Abort;
@@ -1396,18 +1517,27 @@ try
 		com.modules <- modules;
 		Filters.run com tctx main;
 		if ctx.has_error then raise Abort;
+		(* check file extension. In case of wrong commandline, we don't want
+			to accidentaly delete a source file. *)
+		if not !no_output && file_extension com.file = ext then delete_file com.file;
 		(match !xml_out with
 		| None -> ()
 		| Some "hx" ->
 			Genxml.generate_hx com
 		| Some file ->
 			Common.log com ("Generating xml : " ^ file);
+			Common.mkdir_from_path file;
 			Genxml.generate com file);
-		if com.platform = Java then List.iter (Codegen.promote_abstract_parameters com) com.types;
 		if com.platform = Flash || com.platform = Cpp then List.iter (Codegen.fix_overrides com) com.types;
 		if Common.defined com Define.Dump then Codegen.dump_types com;
 		if Common.defined com Define.DumpDependencies then Codegen.dump_dependencies com;
 		t();
+		if not !no_output then begin match com.platform with
+			| Neko when !interp -> ()
+			| Cpp when Common.defined com Define.Cppia -> ()
+			| Cpp | Cs | Java | Php -> Common.mkdir_from_path (com.file ^ "/.")
+			| _ -> Common.mkdir_from_path com.file
+		end;
 		(match com.platform with
 		| _ when !no_output ->
 			if !interp then begin
@@ -1443,11 +1573,14 @@ try
 		| Java ->
 			Common.log com ("Generating Java in : " ^ com.file);
 			Genjava.generate com;
+		| Python ->
+			Common.log com ("Generating python in : " ^ com.file);
+			Genpy.generate com;
 		);
 	end;
 	Sys.catch_break false;
+	List.iter (fun f -> f()) (List.rev com.final_filters);
 	if not !no_output then begin
-		List.iter (fun f -> f()) (List.rev com.final_filters);
 		List.iter (fun c ->
 			let r = run_command ctx c in
 			if r <> 0 then failwith ("Command failed with error " ^ string_of_int r)
@@ -1456,6 +1589,8 @@ try
 with
 	| Abort ->
 		()
+	| Ast.Error (m,p) ->
+		error ctx m p
 	| Typecore.Fatal_error (m,p) ->
 		error ctx m p
 	| Common.Abort (m,p) ->
@@ -1478,6 +1613,8 @@ with
 		message ctx msg p;
 		List.iter (message ctx "Called from") l;
 		error ctx "Aborted" Ast.null_pos;
+	| Codegen.Generic_Exception(m,p) ->
+		error ctx m p
 	| Arg.Bad msg ->
 		error ctx ("Error: " ^ msg) Ast.null_pos
 	| Failure msg when not (is_debug_run()) ->
@@ -1486,21 +1623,21 @@ with
 		message ctx msg Ast.null_pos
 	| Typer.DisplayFields fields ->
 		let ctx = print_context() in
-		let fields = List.map (fun (name,t,doc) -> name, s_type ctx t, (match doc with None -> "" | Some d -> d)) fields in
+		let fields = List.map (fun (name,t,kind,doc) -> name, s_type ctx t, kind, (match doc with None -> "" | Some d -> d)) fields in
 		let fields = if !measure_times then begin
 			close_times();
 			let tot = ref 0. in
 			Hashtbl.iter (fun _ t -> tot := !tot +. t.total) Common.htimers;
-			let fields = ("@TOTAL", Printf.sprintf "%.3fs" (get_time() -. !start_time), "") :: fields in
+			let fields = ("@TOTAL", Printf.sprintf "%.3fs" (get_time() -. !start_time), None, "") :: fields in
 			if !tot > 0. then
 				Hashtbl.fold (fun _ t acc ->
-					("@TIME " ^ t.name, Printf.sprintf "%.3fs (%.0f%%)" t.total (t.total *. 100. /. !tot), "") :: acc
+					("@TIME " ^ t.name, Printf.sprintf "%.3fs (%.0f%%)" t.total (t.total *. 100. /. !tot), None, "") :: acc
 				) Common.htimers fields
 			else fields
 		end else
 			fields
 		in
-		complete_fields fields
+		complete_fields com fields
 	| Typecore.DisplayTypes tl ->
 		let ctx = print_context() in
 		let b = Buffer.create 0 in
@@ -1513,38 +1650,52 @@ with
 	| Typecore.DisplayPosition pl ->
 		let b = Buffer.create 0 in
 		let error_printer file line = sprintf "%s:%d:" (Common.unique_full_path file) line in
+		Buffer.add_string b "<list>\n";
 		List.iter (fun p ->
 			let epos = Lexer.get_error_pos error_printer p in
-			Buffer.add_string b "<pos>\n";
+			Buffer.add_string b "<pos>";
 			Buffer.add_string b epos;
-			Buffer.add_string b "\n</pos>\n";
+			Buffer.add_string b "</pos>\n";
 		) pl;
+		Buffer.add_string b "</list>";
 		raise (Completion (Buffer.contents b))
-	| Typer.DisplayMetadata m ->
+	| Typer.DisplayToplevel il ->
 		let b = Buffer.create 0 in
-		List.iter (fun (m,el,p) ->
-			Buffer.add_string b ("<meta name=\"" ^ (fst (MetaInfo.to_string m)) ^ "\"");
-			if el = [] then Buffer.add_string b "/>" else begin
-				Buffer.add_string b ">\n";
-				List.iter (fun e -> Buffer.add_string b ((htmlescape (Ast.s_expr e)) ^ "\n")) el;
-				Buffer.add_string b "</meta>\n";
-			end
-		) m;
+		Buffer.add_string b "<il>\n";
+		let ctx = print_context() in
+		let s_type t = htmlescape (s_type ctx t) in
+		List.iter (fun id -> match id with
+			| Typer.ITLocal v -> Buffer.add_string b (Printf.sprintf "<i k=\"local\" t=\"%s\">%s</i>\n" (s_type v.v_type) v.v_name);
+			| Typer.ITMember(c,cf) -> Buffer.add_string b (Printf.sprintf "<i k=\"member\" t=\"%s\">%s</i>\n" (s_type cf.cf_type) cf.cf_name);
+			| Typer.ITStatic(c,cf) -> Buffer.add_string b (Printf.sprintf "<i k=\"static\" t=\"%s\">%s</i>\n" (s_type cf.cf_type) cf.cf_name);
+			| Typer.ITEnum(en,ef) -> Buffer.add_string b (Printf.sprintf "<i k=\"enum\" t=\"%s\">%s</i>\n" (s_type ef.ef_type) ef.ef_name);
+			| Typer.ITGlobal(mt,s,t) -> Buffer.add_string b (Printf.sprintf "<i k=\"global\" p=\"%s\" t=\"%s\">%s</i>\n" (s_type_path (t_infos mt).mt_path) (s_type t) s);
+			| Typer.ITType(mt) -> Buffer.add_string b (Printf.sprintf "<i k=\"type\" p=\"%s\">%s</i>\n" (s_type_path (t_infos mt).mt_path) (snd (t_infos mt).mt_path));
+			| Typer.ITPackage s -> Buffer.add_string b (Printf.sprintf "<i k=\"package\">%s</i>\n" s)
+		) il;
+		Buffer.add_string b "</il>";
 		raise (Completion (Buffer.contents b))
-	| Parser.TypePath (p,c) ->
+	| Parser.TypePath (p,c,is_import) ->
 		(match c with
 		| None ->
 			let packs, classes = read_type_path com p in
 			if packs = [] && classes = [] then
 				error ctx ("No classes found in " ^ String.concat "." p) Ast.null_pos
 			else
-				complete_fields (List.map (fun f -> f,"","") (packs @ classes))
+				complete_fields com (
+					let convert k f = (f,"",Some k,"") in
+					(List.map (convert Typer.FKPackage) packs) @ (List.map (convert Typer.FKType) classes)
+				)
 		| Some (c,cur_package) ->
 			try
+				let sl_pack,s_module = match List.rev p with
+					| s :: sl when s.[0] >= 'A' && s.[0] <= 'Z' -> List.rev sl,s
+					| _ -> p,c
+				in
 				let ctx = Typer.create com in
 				let rec lookup p =
 					try
-						Typeload.load_module ctx (p,c) Ast.null_pos
+						Typeload.load_module ctx (p,s_module) Ast.null_pos
 					with e ->
 						if cur_package then
 							match List.rev p with
@@ -1553,8 +1704,32 @@ with
 						else
 							raise e
 				in
-				let m = lookup p in
-				complete_fields (List.map (fun t -> snd (t_path t),"","") (List.filter (fun t -> not (t_infos t).mt_private) m.m_types))
+				let m = lookup sl_pack in
+				let statics = ref None in
+				let public_types = List.filter (fun t ->
+					let tinfos = t_infos t in
+					let is_module_type = snd tinfos.mt_path = c in
+					if is_import && is_module_type then begin match t with
+						| TClassDecl c ->
+							ignore(c.cl_build());
+							statics := Some c.cl_ordered_statics
+						| _ -> ()
+					end;
+					not tinfos.mt_private
+				) m.m_types in
+				let types = if c <> s_module then [] else List.map (fun t -> snd (t_path t),"",Some Typer.FKType,"") public_types in
+				let ctx = print_context() in
+				let make_field_doc cf =
+					cf.cf_name,
+					s_type ctx cf.cf_type,
+					Some (match cf.cf_kind with Method _ -> Typer.FKMethod | Var _ -> Typer.FKVar),
+					(match cf.cf_doc with Some s -> s | None -> "")
+				in
+				let types = match !statics with
+					| None -> types
+					| Some cfl -> types @ (List.map make_field_doc (List.filter (fun cf -> cf.cf_public) cfl))
+				in
+				complete_fields com types
 			with Completion c ->
 				raise (Completion c)
 			| _ ->

+ 202 - 163
matcher.ml

@@ -44,7 +44,7 @@ and con = {
 
 and st_def =
 	| SVar of tvar
-	| SField of st * string
+	| SField of st * tclass_field
 	| SEnum of st * tenum_field * int
 	| SArray of st * int
 	| STuple of st * int * int
@@ -110,6 +110,11 @@ type matcher = {
 	mutable is_exhaustive : bool;
 }
 
+type type_finiteness =
+	| Infinite (* type has inifite constructors (e.g. Int, String) *)
+	| CompileTimeFinite (* type is considered finite only at compile-time but has inifite possible run-time values (enum abstracts) *)
+	| RunTimeFinite (* type is truly finite (Bool, enums) *)
+
 exception Not_exhaustive of pat * st
 exception Unrecognized_pattern of Ast.expr
 
@@ -141,8 +146,8 @@ let mk_out mctx id e eg is_catch_all p =
 	out
 
 let clone_out mctx out p =
- 	let out = {out with o_pos = p; } in
- 	mctx.outcomes <- out :: mctx.outcomes;
+	let out = {out with o_pos = p; } in
+	mctx.outcomes <- out :: mctx.outcomes;
 	out
 
 let get_guard mctx id =
@@ -177,7 +182,7 @@ let mk_type_pat ctx mt t p =
 		| TEnumDecl _ -> "Enum"
 		| TAbstractDecl a when Meta.has Meta.RuntimeValue a.a_meta -> "Class"
 		| TTypeDecl t ->
-			begin match follow (monomorphs t.t_types t.t_type) with
+			begin match follow (monomorphs t.t_params t.t_type) with
 				| TInst(c,_) -> loop (TClassDecl c)
 				| TEnum(en,_) -> loop (TEnumDecl en)
 				| TAbstract(a,_) -> loop (TAbstractDecl a)
@@ -192,22 +197,22 @@ let mk_type_pat ctx mt t p =
 
 let mk_subs st con =
 	let map = match follow st.st_type with
-		| TInst(c,pl) -> apply_params c.cl_types pl
-		| TEnum(en,pl) -> apply_params en.e_types pl
-		| TAbstract(a,pl) -> apply_params a.a_types pl
+		| TInst(c,pl) -> apply_params c.cl_params pl
+		| TEnum(en,pl) -> apply_params en.e_params pl
+		| TAbstract(a,pl) -> apply_params a.a_params pl
 		| _ -> fun t -> t
 	in
 	match con.c_def with
-	| CFields (_,fl) -> List.map (fun (s,cf) -> mk_st (SField(st,s)) (map cf.cf_type) st.st_pos) fl
+	| CFields (_,fl) -> List.map (fun (s,cf) -> mk_st (SField(st,cf)) (map cf.cf_type) st.st_pos) fl
 	| CEnum (en,({ef_type = TFun _} as ef)) ->
 		let rec loop t = match follow t with
 			| TEnum(_,pl) -> pl
 			| TAbstract({a_path = [],"EnumValue"},[]) -> []
-			| TAbstract(a,pl) -> loop (Codegen.Abstract.get_underlying_type a pl)
+			| TAbstract(a,pl) -> loop (Abstract.get_underlying_type a pl)
 			| _ -> []
 		in
 		let pl = loop con.c_type in
-		begin match apply_params en.e_types pl (monomorphs ef.ef_params ef.ef_type) with
+		begin match apply_params en.e_params pl (monomorphs ef.ef_params ef.ef_type) with
 			| TFun(args,r) ->
 				ExtList.List.mapi (fun i (_,_,t) ->
 					mk_st (SEnum(st,ef,i)) t st.st_pos
@@ -217,12 +222,12 @@ let mk_subs st con =
 		end
 	| CArray 0 -> []
 	| CArray i ->
-		let t = match follow con.c_type with TInst({cl_path=[],"Array"},[t]) -> t | _ -> assert false in
+		let t = match follow con.c_type with TInst({cl_path=[],"Array"},[t]) -> t | TDynamic _ as t -> t | _ -> assert false in
 		ExtList.List.init i (fun i -> mk_st (SArray(st,i)) t st.st_pos)
 	| CEnum _ | CConst _ | CType _ | CExpr _ | CAny ->
 		[]
 
-let get_tuple_types t = match t with
+let get_tuple_params t = match t with
 	| TFun(tl,tr) when tr == fake_tuple_type -> Some tl
 	| _ -> None
 
@@ -265,7 +270,7 @@ let rec s_st st =
 	| SEnum (st,ef,i) -> s_st st ^ "." ^ ef.ef_name ^ "." ^ (string_of_int i)
 	| SArray (st,i) -> s_st st ^ "[" ^ (string_of_int i) ^ "]"
 	| STuple (st,i,a) -> "(" ^ (st_args i (a - i - 1) (s_st st)) ^ ")"
-	| SField (st,n) -> s_st st ^ "." ^ n)
+	| SField (st,cf) -> s_st st ^ "." ^ cf.cf_name)
 
 (* Pattern parsing *)
 
@@ -274,7 +279,7 @@ let unify_enum_field en pl ef t =
 		| TFun(_,r) -> r
 		| t2 -> t2
 	in
-	let t2 = (apply_params en.e_types pl (monomorphs ef.ef_params t2)) in
+	let t2 = (apply_params en.e_params pl (monomorphs ef.ef_params t2)) in
 	Type.unify t2 t
 
 let unify ctx a b p =
@@ -284,7 +289,7 @@ let rec is_value_type = function
 	| TMono r ->
 		(match !r with None -> false | Some t -> is_value_type t)
 	| TType (t,tl) ->
-		is_value_type (apply_params t.t_types tl t.t_type)
+		is_value_type (apply_params t.t_params tl t.t_type)
 	| TInst({cl_path=[],"String"},[]) ->
 		true
 	| TAbstract _ ->
@@ -292,8 +297,7 @@ let rec is_value_type = function
 	| _ ->
 		false
 
-(* 	Determines if a type allows null-matching. This is similar to is_nullable, but it infers Null<T> on monomorphs,
-	and enums are not considered nullable *)
+(* 	Determines if a type allows null-matching. This is similar to is_nullable, but it infers Null<T> on monomorphs *)
 let rec matches_null ctx t = match t with
 	| TMono r ->
 		(match !r with None -> r := Some (ctx.t.tnull (mk_mono())); true | Some t -> matches_null ctx t)
@@ -302,8 +306,8 @@ let rec matches_null ctx t = match t with
 	| TLazy f ->
 		matches_null ctx (!f())
 	| TType (t,tl) ->
-		matches_null ctx (apply_params t.t_types tl t.t_type)
-	| TFun _ | TEnum _ ->
+		matches_null ctx (apply_params t.t_params tl t.t_type)
+	| TFun _ ->
 		false
 	| TAbstract (a,_) -> not (Meta.has Meta.NotNull a.a_meta)
 	| _ ->
@@ -361,7 +365,7 @@ let to_pattern ctx e t =
 				mk_con_pat (CExpr e) [] cf.cf_type p
 			| TField(_, FEnum(en,ef)) ->
 				begin try
-					unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_types) ef t
+					unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_params) ef t
 				with Unify_error l ->
 					error (error_msg (Unify l)) p
 				end;
@@ -377,7 +381,7 @@ let to_pattern ctx e t =
 					| _ -> error ("Expected constructor for enum " ^ (s_type_path en.e_path)) p
 				in
 				let monos = List.map (fun _ -> mk_mono()) ef.ef_params in
-				let tl,r = match apply_params en.e_types pl (apply_params ef.ef_params monos ef.ef_type) with
+				let tl,r = match apply_params en.e_params pl (apply_params ef.ef_params monos ef.ef_type) with
 					| TFun(args,r) ->
 						unify ctx r t p;
 						List.map (fun (n,_,t) -> t) args,r
@@ -403,7 +407,7 @@ let to_pattern ctx e t =
 				mk_con_pat (CEnum(en,ef)) el r p
 			| _ -> perror p)
 		| EConst(Ident "_") ->
-			begin match get_tuple_types t with
+			begin match get_tuple_params t with
 			| Some tl ->
 				let pl = List.map (fun (_,_,t) -> mk_any t p) tl in
 				mk_pat (PTuple (Array.of_list pl)) t_dynamic p
@@ -429,7 +433,7 @@ let to_pattern ctx e t =
 								error msg p
 							| _ -> ());
 						let et = mk (TTypeExpr (TEnumDecl en)) (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics en) }) p in
-						mk (TField (et,FEnum (en,ef))) (apply_params en.e_types pl ef.ef_type) p
+						mk (TField (et,FEnum (en,ef))) (apply_params en.e_params pl ef.ef_type) p
 					| TAbstract({a_impl = Some c} as a,_) when Meta.has Meta.Enum a.a_meta ->
 						let cf = PMap.find s c.cl_statics in
 						Type.unify (follow cf.cf_type) t;
@@ -450,7 +454,7 @@ let to_pattern ctx e t =
 					| TField (_,FEnum (en,ef)) ->
 						begin try unify_raise ctx ec.etype t ec.epos with Error (Unify _,_) -> raise Not_found end;
 						begin try
-							unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_types) ef t;
+							unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_params) ef t;
 						with Unify_error l ->
 							error (error_msg (Unify l)) p
 						end;
@@ -458,13 +462,13 @@ let to_pattern ctx e t =
 					| TConst c | TCast({eexpr = TConst c},None) ->
 						begin try unify_raise ctx ec.etype t ec.epos with Error (Unify _,_) -> raise Not_found end;
 						unify ctx ec.etype t p;
-                        mk_con_pat (CConst c) [] t p
+						mk_con_pat (CConst c) [] t p
 					| TTypeExpr mt ->
 						mk_type_pat ctx mt t p
 					| _ ->
 						raise Not_found);
 			with Not_found ->
-				begin match get_tuple_types t with
+				begin match get_tuple_params t with
 					| Some tl ->
 						let s = String.concat "," (List.map (fun (_,_,t) -> s_type t) tl) in
 						error ("Pattern should be tuple [" ^ s ^ "]") p
@@ -475,11 +479,10 @@ let to_pattern ctx e t =
 				end
 			end
 		| (EObjectDecl fl) ->
-			let is_matchable cf = match cf.cf_kind with Method _ | Var {v_read = AccCall} -> false | _ -> true in
+			let is_matchable cf = match cf.cf_kind with Method _ -> false | _ -> true in
 			let is_valid_field_name fields co n p =
 				try
 					let cf = PMap.find n fields in
-					if not (is_matchable cf) then error ("Cannot match against method or property with getter " ^ n) p;
 					begin match co with
 					| Some c when not (Typer.can_access ctx c cf false) -> error ("Cannot match against private field " ^ n) p
 					| _ -> ()
@@ -488,43 +491,53 @@ let to_pattern ctx e t =
 					error ((s_type t) ^ " has no field " ^ n ^ " that can be matched against") p;
 			in
 			pctx.pc_is_complex <- true;
-			begin match follow t with
-			| TAnon {a_fields = fields} ->
-				List.iter (fun (n,(_,p)) -> is_valid_field_name fields None n p) fl;
+			let loop_fields fields =
 				let sl,pl,i = PMap.foldi (fun n cf (sl,pl,i) ->
 					if not (is_matchable cf) then
 						sl,pl,i
 					else
-						let pat =
-							try
-								if pctx.pc_reify && cf.cf_name = "pos" then raise Not_found;
-								loop pctx (List.assoc n fl) cf.cf_type
-							with Not_found ->
-								(mk_any cf.cf_type p)
+						let pat = try
+							if pctx.pc_reify && cf.cf_name = "pos" then raise Not_found;
+							loop pctx (List.assoc cf.cf_name fl) cf.cf_type
+						with Not_found ->
+							(mk_any cf.cf_type p)
 						in
 						(n,cf) :: sl,pat :: pl,i + 1
 				) fields ([],[],0) in
 				mk_con_pat (CFields(i,sl)) pl t p
-			| TInst(c,tl) ->
-				List.iter (fun (n,(_,p)) -> is_valid_field_name c.cl_fields (Some c) n p) fl;
-				let sl,pl,i = PMap.foldi (fun n cf (sl,pl,i) ->
-					if not (is_matchable cf) then
-						sl,pl,i
-					else
-						let t = apply_params c.cl_types tl (monomorphs cf.cf_params cf.cf_type) in
-						let pat = try loop pctx (List.assoc n fl) t with Not_found -> (mk_any t p) in
-						(n,cf) :: sl,pat :: pl,i + 1
-				) c.cl_fields ([],[],0) in
-				mk_con_pat (CFields(i,sl)) pl t p
-			| _ ->
-				error ((s_type t) ^ " should be { }") p
-			end
+			in
+			let fields = match follow t with
+				| TAnon {a_fields = fields} ->
+					fields
+				| TInst(c,tl) ->
+					let fields = ref PMap.empty in
+					let rec loop c tl =
+						begin match c.cl_super with
+							| Some (csup,tlsup) -> loop csup (List.map (apply_params c.cl_params tl) tlsup)
+							| None -> ()
+						end;
+						PMap.iter (fun n cf -> fields := PMap.add n {cf with cf_type = apply_params c.cl_params tl (monomorphs cf.cf_params cf.cf_type)} !fields) c.cl_fields
+					in
+					loop c tl;
+					!fields
+				| TAbstract({a_impl = Some c} as a,tl) ->
+					let fields = List.fold_left (fun acc cf ->
+						if Meta.has Meta.Impl cf.cf_meta then
+							PMap.add cf.cf_name cf acc
+						else acc
+					) PMap.empty c.cl_ordered_statics in
+					PMap.map (fun cf -> {cf with cf_type = apply_params a.a_params tl (monomorphs cf.cf_params cf.cf_type)}) fields
+				| _ ->
+					error ((s_type t) ^ " cannot be matched against a structure") p
+			in
+			List.iter (fun (n,(_,p)) -> is_valid_field_name fields None n p) fl;
+			loop_fields fields
 		| EArrayDecl [] ->
 			mk_con_pat (CArray 0) [] t p
 		| EArrayDecl el ->
 			pctx.pc_is_complex <- true;
 			begin match follow t with
-				| TInst({cl_path=[],"Array"},[t2]) ->
+				| TInst({cl_path=[],"Array"},[t2]) | (TDynamic _ as t2) ->
 					let pl = ExtList.List.mapi (fun i e ->
 						loop pctx e t2
 					) el in
@@ -535,7 +548,7 @@ let to_pattern ctx e t =
 					with Invalid_argument _ ->
 						error ("Invalid number of arguments: expected " ^ (string_of_int (List.length tl)) ^ ", found " ^ (string_of_int (List.length el))) p
 					in
-					mk_pat (PTuple (Array.of_list pl)) t_dynamic p
+					mk_pat (PTuple (Array.of_list pl)) t p
 				| _ ->
 					error ((s_type t) ^ " should be Array") p
 			end
@@ -634,7 +647,7 @@ let spec mctx con pmat =
 			loop2 (Array.append [|pat|] (array_tl pv)) out
 		| PTuple tl ->
 			loop2 tl out
- 		| POr _ ->
+		| POr _ ->
 			assert false
 	in
 	let rec loop pmat = match pmat with
@@ -661,10 +674,10 @@ let default mctx pmat =
 			loop2 (Array.append [|pat|] (array_tl pv)) out
 		| PTuple tl ->
 			loop2 tl out
- 		| POr _ ->
+		| POr _ ->
 			assert false
 	in
- 	let rec loop pmat = match pmat with
+	let rec loop pmat = match pmat with
 		| (pv,out) :: pl ->
 			loop2 pv out;
 			loop pl;
@@ -783,27 +796,14 @@ let column_sigma mctx st pmat =
 	loop pmat;
 	List.rev_map (fun con -> con,not (Hashtbl.mem unguarded con.c_def)) !acc,!bindings
 
-(* Determines if we have a Null<T>. Unlike is_null, this returns true even if the wrapped type is nullable itself. *)
-let rec is_explicit_null = function
-	| TMono r ->
-		(match !r with None -> false | Some t -> is_null t)
-	| TType ({ t_path = ([],"Null") },[t]) ->
-		true
-	| TLazy f ->
-		is_null (!f())
-	| TType (t,tl) ->
-		is_null (apply_params t.t_types tl t.t_type)
-	| _ ->
-		false
-
 let rec all_ctors mctx t =
 	let h = ref PMap.empty in
-	(* if is_explicit_null t then h := PMap.add (CConst TNull) Ast.null_pos !h; *)
+	if is_explicit_null t then h := PMap.add (CConst TNull) Ast.null_pos !h;
 	match follow t with
 	| TAbstract({a_path = [],"Bool"},_) ->
 		h := PMap.add (CConst(TBool true)) Ast.null_pos !h;
 		h := PMap.add (CConst(TBool false)) Ast.null_pos !h;
-		h,false
+		h,RunTimeFinite
 	| TAbstract({a_impl = Some c} as a,pl) when Meta.has Meta.Enum a.a_meta ->
 		List.iter (fun cf ->
 			ignore(follow cf.cf_type);
@@ -811,11 +811,11 @@ let rec all_ctors mctx t =
 				| Some {eexpr = TConst c | TCast ({eexpr = TConst c},None)} -> h := PMap.add (CConst c) cf.cf_pos !h
 				| _ -> ()
 		) c.cl_ordered_statics;
-		h,false
-	| TAbstract(a,pl) when not (Meta.has Meta.CoreType a.a_meta) -> all_ctors mctx (Codegen.Abstract.get_underlying_type a pl)
+		h,CompileTimeFinite
+	| TAbstract(a,pl) when not (Meta.has Meta.CoreType a.a_meta) -> all_ctors mctx (Abstract.get_underlying_type a pl)
 	| TInst({cl_path=[],"String"},_)
 	| TInst({cl_path=[],"Array"},_) ->
-		h,true
+		h,Infinite
 	| TEnum(en,pl) ->
 		PMap.iter (fun _ ef ->
 			let tc = monomorphs mctx.ctx.type_params t in
@@ -824,13 +824,13 @@ let rec all_ctors mctx t =
 			with Unify_error _ ->
 				()
 		) en.e_constrs;
-		h,false
+		h,RunTimeFinite
 	| TAnon a ->
-		h,true
+		h,CompileTimeFinite
 	| TInst(_,_) ->
-		h,false
+		h,CompileTimeFinite
 	| _ ->
-		h,true
+		h,Infinite
 
 let rec collapse_pattern pl = match pl with
 	| pat :: [] ->
@@ -882,14 +882,16 @@ let rec compile mctx stl pmat toplevel =
 			let all,inf = all_ctors mctx st.st_type in
 			let pl = PMap.foldi (fun cd p acc -> (mk_con_pat cd [] t_dynamic p) :: acc) !all [] in
 			begin match pl,inf with
-				| _,true
+				| _,Infinite
 				| [],_ ->
 					raise (Not_exhaustive(any,st))
 				| _ ->
 					raise (Not_exhaustive(collapse_pattern pl,st))
 			end
 		| _ ->
-			assert false)
+			(* This can happen in cases a value is required and all default cases are guarded (issue #3150).
+			   Not a particularly elegant solution, may want to revisit this later. *)
+			raise Exit)
 	| ([|{p_def = PTuple pt}|],out) :: pl ->
 		compile mctx stl ((pt,out) :: pl) toplevel
 	| (pv,out) :: pl ->
@@ -898,8 +900,16 @@ let rec compile mctx stl pmat toplevel =
 			out.o_num_paths <- out.o_num_paths + 1;
 			let bl = bind_remaining out pv stl in
 			let dt = match (get_guard mctx out.o_id) with
-				| None -> expr out.o_id
-				| Some _ -> guard out.o_id (expr out.o_id) (match pl with [] -> None | _ -> Some (compile mctx stl pl false))
+				| None ->
+					expr out.o_id
+				| Some _ ->
+					let dt = match pl,mctx.need_val with
+						| [],false ->
+							None
+						| _ ->
+							Some (compile mctx stl pl false)
+					in
+					guard out.o_id (expr out.o_id) dt
 			in
 			(if bl = [] then dt else bind bl dt)
 		end else if i > 0 then begin
@@ -910,7 +920,7 @@ let rec compile mctx stl pmat toplevel =
 			let st_head,st_tail = match stl with st :: stl -> st,stl | _ -> assert false in
 			let pmat = expand_or mctx pmat in
 			let sigma,bl = column_sigma mctx st_head pmat in
-			let all,inf = all_ctors mctx st_head.st_type in
+			let all,inf = all_ctors mctx pv.(0).p_type in
 			let cases = List.map (fun (c,g) ->
 				if not g then all := PMap.remove c.c_def !all;
 				let spec = spec mctx c pmat in
@@ -921,24 +931,35 @@ let rec compile mctx stl pmat toplevel =
 			) sigma in
 			let def = default mctx pmat in
 			let dt = match def,cases with
-			| _ when List.exists (fun (c,_) -> match c.c_def with CFields _ -> true | _ -> false) cases ->
+			| _ when inf = RunTimeFinite && PMap.is_empty !all ->
 				switch st_head cases
-			| _ when not inf && PMap.is_empty !all ->
+			| [],_ when inf = CompileTimeFinite && PMap.is_empty !all ->
 				switch st_head cases
-			| [],_ when inf && not mctx.need_val && toplevel ->
+			| [],_ when inf = Infinite && not mctx.need_val && toplevel ->
 				(* ignore exhaustiveness, but mark context so we do not generate @:exhaustive metadata *)
 				mctx.is_exhaustive <- false;
 				switch st_head cases
-			| [],_ when inf ->
+			| [],_ when inf = Infinite ->
 				raise (Not_exhaustive(any,st_head))
 			| [],_ ->
 				let pl = PMap.foldi (fun cd p acc -> (mk_con_pat cd [] t_dynamic p) :: acc) !all [] in
-				raise (Not_exhaustive(collapse_pattern pl,st_head))
+				(* toplevel null can be omitted because the French dig runtime errors (issue #3054) *)
+				if toplevel && (match pl with
+					| [{p_def = PCon ({c_def = (CConst TNull)},_)}] -> true
+					| _ -> false) then
+						switch st_head cases
+				else
+					raise (Not_exhaustive(collapse_pattern pl,st_head))
 			| def,[] ->
 				compile mctx st_tail def false
 			| def,_ ->
 				let cdef = mk_con CAny t_dynamic st_head.st_pos in
-				let cases = cases @ [cdef,compile mctx st_tail def false] in
+				let def = try
+					compile mctx st_tail def false
+				with Exit ->
+					raise (Not_exhaustive(any,st_head))
+				in
+				let cases = cases @ [cdef,def] in
 				switch st_head cases
 			in
 			if bl = [] then dt else bind bl dt
@@ -963,13 +984,12 @@ let mk_const ctx p = function
 
 let rec convert_st ctx st = match st.st_def with
 	| SVar v -> mk (TLocal v) v.v_type st.st_pos
-	| SField (sts,f) ->
+	| SField (sts,cf) ->
 		let e = convert_st ctx sts in
-		let fa = try quick_field e.etype f with Not_found -> FDynamic f in
-		mk (TField(e,fa)) st.st_type st.st_pos
+		Typer.acc_get ctx (Typer.type_field ctx e cf.cf_name st.st_pos Typer.MGet) st.st_pos
 	| SArray (sts,i) -> mk (TArray(convert_st ctx sts,mk_const ctx st.st_pos (TInt (Int32.of_int i)))) st.st_type st.st_pos
 	| STuple (st,_,_) -> convert_st ctx st
-	| SEnum(sts,ef,i) -> mk (TEnumParameter(convert_st ctx sts, ef, i)) st.st_type st.st_pos
+	| SEnum (sts,ef,i) -> mk (TEnumParameter(convert_st ctx sts, ef, i)) st.st_type st.st_pos
 
 let convert_con ctx con = match con.c_def with
 	| CConst c -> mk_const ctx con.c_pos c
@@ -1000,7 +1020,7 @@ let convert_switch mctx st cases loop =
 	let e = match follow st.st_type with
 	| TEnum(_) ->
 		wrap_exhaustive (mk_index_call())
-	| TAbstract(a,pl) when (match Codegen.Abstract.get_underlying_type a pl with TEnum(_) -> true | _ -> false) ->
+	| TAbstract(a,pl) when (match Abstract.get_underlying_type a pl with TEnum(_) -> true | _ -> false) ->
 		wrap_exhaustive (mk_index_call())
 	| TInst({cl_path = [],"Array"},_) as t ->
 		mk (TField (e_st,quick_field t "length")) ctx.t.tint p
@@ -1009,10 +1029,16 @@ let convert_switch mctx st cases loop =
 	| TAbstract({a_path = [],"Bool"},_) ->
 		wrap_exhaustive (e_st)
 	| _ ->
-		if List.exists (fun (con,_) -> match con.c_def with CEnum _ -> true | _ -> false) cases then
-			mk_index_call()
-		else
-			e_st
+		let rec loop cases = match cases with
+			| [] -> e_st
+			| (con,_) :: cases ->
+				begin match con.c_def with
+					| CEnum _ -> mk_index_call()
+					| CArray _ -> mk (TField (e_st,FDynamic "length")) ctx.t.tint p
+					| _ -> loop cases
+				end
+		in
+		loop cases
 	in
 	let null = ref None in
 	let def = ref None in
@@ -1032,9 +1058,18 @@ let convert_switch mctx st cases loop =
 		| _ -> DTSwitch(e, List.map (fun (c,dt) -> convert_con ctx c, loop dt) cases, !def)
 	in
 	match !null with
-	| None -> dt
+	| None when is_explicit_null st.st_type && (!def <> None || not mctx.need_val) ->
+		let econd = mk (TBinop(OpNotEq,e_st,mk (TConst TNull) st.st_type p)) ctx.t.tbool p in
+		DTGuard(econd,dt,!def)
+	| None ->
+		dt
 	| Some dt_null ->
-		let econd = mk (TBinop(OpEq,e_st,mk (TConst TNull) (mk_mono()) p)) ctx.t.tbool p in
+		let t = match ctx.t.tnull ctx.t.tint with
+			| TType(t,_) ->TType(t,[st.st_type])
+			| t -> t
+		in
+		let e_null = mk (TConst TNull) t p in
+		let econd = mk (TBinop(OpEq,e_st, e_null)) ctx.t.tbool p in
 		DTGuard(econd,dt_null,Some dt)
 
 (* Decision tree compilation *)
@@ -1097,7 +1132,8 @@ let transform_extractors eval cases p =
 		| [] ->
 			[]
 	in
-	loop cases,!has_extractor
+	let cases = loop cases in
+	cases,!has_extractor
 
 let extractor_depth = ref 0
 
@@ -1131,7 +1167,7 @@ let match_expr ctx e cases def with_type p =
 			let e = type_expr ctx e Value in
 			begin match follow e.etype with
 			(* TODO: get rid of the XmlType check *)
-			| TEnum(en,_) when (en.e_path = ([],"XmlType")) || Meta.has Meta.FakeEnum en.e_meta ->
+			| TEnum(en,_) when (match en.e_path with (["neko" | "php" | "flash" | "cpp"],"XmlType") -> true | _ -> Meta.has Meta.FakeEnum en.e_meta) ->
 				raise Exit
 			| TAbstract({a_path=[],("Int" | "Float" | "Bool")},_) | TInst({cl_path = [],"String"},_) when (Common.defined ctx.com Common.Define.NoPatternMatching) ->
 				raise Exit;
@@ -1194,29 +1230,27 @@ let match_expr ctx e cases def with_type p =
 	let pl = ExtList.List.mapi (fun i (ep,eg,e) ->
 		let save = save_locals ctx in
 		(* type case patterns *)
-		let pl,restore,with_type = try (match tl with
-				| [t] when not !array_match ->
-					(* context type parameters are turned into monomorphs until the pattern has been typed *)
-					let monos = List.map (fun _ -> mk_mono()) ctx.type_params in
-					let t = apply_params ctx.type_params monos t in
-					let pl = [add_pattern_locals (to_pattern ctx ep t)] in
-					let old_ret = ctx.ret in
-					ctx.ret <- apply_params ctx.type_params monos ctx.ret;
-					let restore = PMap.fold (fun v acc ->
-						(* apply context monomorphs to locals and replace them back after typing the case body *)
-						let t = v.v_type in
-						v.v_type <- apply_params ctx.type_params monos v.v_type;
-						(fun () -> v.v_type <- t) :: acc
-					) ctx.locals [fun() -> ctx.ret <- old_ret] in
-					(* turn any still unknown types back to type parameters *)
-					List.iter2 (fun m (_,t) -> match follow m with TMono _ -> Type.unify m t | _ -> ()) monos ctx.type_params;
-					pl,restore,(match with_type with
-						| WithType t -> WithType (apply_params ctx.type_params monos t)
-						| WithTypeResume t -> WithTypeResume (apply_params ctx.type_params monos t)
-						| _ -> with_type);
-				| tl ->
-					let t = monomorphs ctx.type_params (tfun tl fake_tuple_type) in
-					[add_pattern_locals (to_pattern ctx ep t)],[],with_type)
+		let pl,restore,with_type =
+			try
+				(* context type parameters are turned into monomorphs until the pattern has been typed *)
+				let monos = List.map (fun _ -> mk_mono()) ctx.type_params in
+				let t = match tl with [t] when not !array_match -> t | tl -> tfun tl fake_tuple_type in
+				let t = apply_params ctx.type_params monos t in
+				let pl = [add_pattern_locals (to_pattern ctx ep t)] in
+				let old_ret = ctx.ret in
+				ctx.ret <- apply_params ctx.type_params monos ctx.ret;
+				let restore = PMap.fold (fun v acc ->
+					(* apply context monomorphs to locals and replace them back after typing the case body *)
+					let t = v.v_type in
+					v.v_type <- apply_params ctx.type_params monos v.v_type;
+					(fun () -> v.v_type <- t) :: acc
+				) ctx.locals [fun() -> ctx.ret <- old_ret] in
+				(* turn any still unknown types back to type parameters *)
+				List.iter2 (fun m (_,t) -> match follow m with TMono _ -> Type.unify m t | _ -> ()) monos ctx.type_params;
+				pl,restore,(match with_type with
+					| WithType t -> WithType (apply_params ctx.type_params monos t)
+					| WithTypeResume t -> WithTypeResume (apply_params ctx.type_params monos t)
+					| _ -> with_type);
 			with Unrecognized_pattern (e,p) ->
 				error "Case expression must be a constant value or a pattern, not an arbitrary expression" p
 		in
@@ -1226,17 +1260,17 @@ let match_expr ctx e cases def with_type p =
 		in
 		(* type case body *)
 		let e = match e with
-			| None -> mk (TBlock []) ctx.com.basic.tvoid (pos ep)
+			| None ->
+				mk (TBlock []) ctx.com.basic.tvoid (pos ep)
 			| Some e ->
-				let e = type_expr ctx e with_type in
-				match with_type with
-				| WithType t ->
-					unify ctx e.etype t e.epos;
-					Codegen.Abstract.check_cast ctx t e e.epos;
-				| WithTypeResume t ->
-					(try unify_raise ctx e.etype t e.epos with Error (Unify l,p) -> raise (Typer.WithTypeError (l,p)));
-					Codegen.Abstract.check_cast ctx t e e.epos
-				| _ -> e
+				type_expr ctx e with_type
+		in
+		let e = match with_type with
+			| WithType t ->
+				Codegen.AbstractCast.cast_or_unify ctx t e e.epos;
+			| WithTypeResume t ->
+				(try Codegen.AbstractCast.cast_or_unify_raise ctx t e e.epos with Error (Unify l,p) -> raise (Typer.WithTypeError (l,p)));
+			| _ -> e
 		in
 		(* type case guard *)
 		let eg = match eg with
@@ -1254,9 +1288,9 @@ let match_expr ctx e cases def with_type p =
 	let check_unused () =
 		let unused p =
 			display_error ctx "This pattern is unused" p;
- 			let old_error = ctx.on_error in
+			let old_error = ctx.on_error in
 			ctx.on_error <- (fun ctx s p -> ctx.on_error <- old_error; raise Exit);
-	 		let check_expr e p =
+			let check_expr e p =
 				try begin match fst e with
 						| EConst(Ident ("null" | "true" | "false")) -> ()
 						| EConst(Ident _) ->
@@ -1276,10 +1310,10 @@ let match_expr ctx e cases def with_type p =
 			ctx.on_error <- old_error;
 		in
 		let had_catch_all = ref false in
- 		List.iter (fun out ->
- 			if out.o_catch_all && not !had_catch_all then
- 				had_catch_all := true
- 			else if out.o_num_paths = 0 then begin
+		List.iter (fun out ->
+			if out.o_catch_all && not !had_catch_all then
+				had_catch_all := true
+			else if out.o_num_paths = 0 then begin
 				unused out.o_pos;
 				if mctx.toplevel_or then begin match evals with
 					| [{etype = t}] when (match follow t with TAbstract({a_path=[],"Int"},[]) -> true | _ -> false) ->
@@ -1293,31 +1327,31 @@ let match_expr ctx e cases def with_type p =
 		(* compile decision tree *)
 		compile mctx stl pl true
 	with Not_exhaustive(pat,st) ->
- 		let rec s_st_r top pre st v = match st.st_def with
- 			| SVar v1 ->
- 				if not pre then v else begin try
- 					let e = match List.assoc v1 !var_inits with Some e -> e | None -> assert false in
- 					(Type.s_expr_pretty "" (Type.s_type (print_context())) e) ^ v
- 				with Not_found ->
- 					v1.v_name ^ v
- 				end
- 			| STuple(st,i,a) ->
- 				let r = a - i - 1 in
- 				Printf.sprintf "[%s]" (st_args i r (s_st_r top false st v))
- 			| SArray(st,i) ->
- 				s_st_r false true st (Printf.sprintf "[%i]%s" i (if top then " = " ^ v else v))
- 			| SField({st_def = SVar v1},f) when v1.v_name.[0] = '`' ->
- 				f ^ (if top then " = " ^ v else v)
-  			| SField(st,f) ->
- 				s_st_r false true st (Printf.sprintf ".%s%s" f (if top then " = " ^ v else v))
- 			| SEnum(st,ef,i) ->
- 				let len = match follow ef.ef_type with TFun(args,_) -> List.length args | _ -> 0 in
+		let rec s_st_r top pre st v = match st.st_def with
+			| SVar v1 ->
+				if not pre then v else begin try
+					let e = match List.assoc v1 !var_inits with Some e -> e | None -> assert false in
+					(Type.s_expr_pretty "" (Type.s_type (print_context())) e) ^ v
+				with Not_found ->
+					v1.v_name ^ v
+				end
+			| STuple(st,i,a) ->
+				let r = a - i - 1 in
+				Printf.sprintf "[%s]" (st_args i r (s_st_r top false st v))
+			| SArray(st,i) ->
+				s_st_r false true st (Printf.sprintf "[%i]%s" i (if top then " = " ^ v else v))
+			| SField({st_def = SVar v1},cf) when v1.v_name.[0] = '`' ->
+				cf.cf_name ^ (if top then " = " ^ v else v)
+			| SField(st,cf) ->
+				s_st_r false true st (Printf.sprintf ".%s%s" cf.cf_name (if top then " = " ^ v else v))
+			| SEnum(st,ef,i) ->
+				let len = match follow ef.ef_type with TFun(args,_) -> List.length args | _ -> 0 in
 				s_st_r false false st (Printf.sprintf "%s(%s)" ef.ef_name (st_args i (len - 1 - i) v))
 		in
 		let pat = match follow st.st_type with
 			| TAbstract({a_impl = Some cl} as a,_) when Meta.has Meta.Enum a.a_meta ->
 				let rec s_pat pat = match pat.p_def with
-					| PCon ({c_def = CConst c},[]) ->
+					| PCon ({c_def = CConst c},[]) when c <> TNull ->
 						let cf = List.find (fun cf ->
 							match cf.cf_expr with
 							| Some ({eexpr = TConst c2 | TCast({eexpr = TConst c2},None)}) -> c = c2
@@ -1336,7 +1370,12 @@ let match_expr ctx e cases def with_type p =
 			| _ ->
 				s_pat pat
 		in
-		error ("Unmatched patterns: " ^ (s_st_r true false st pat)) st.st_pos
+		let msg = "Unmatched patterns: " ^ (s_st_r true false st pat) in
+		if !extractor_depth > 0 then begin
+			display_error ctx msg st.st_pos;
+			error "Note: Patterns with extractors may require a default pattern" st.st_pos;
+		end else
+			error msg st.st_pos
 	in
 	save();
 	(* check for unused patterns *)
@@ -1381,7 +1420,7 @@ let match_expr ctx e cases def with_type p =
 				i + 1
 			end else i in
 			Array.set map c i;
-		 	loop i' (c + 1)
+			loop i' (c + 1)
 		end
 	in
 	loop 0 0;

Файловите разлики са ограничени, защото са твърде много
+ 431 - 288
optimizer.ml


+ 148 - 63
parser.ml

@@ -32,7 +32,7 @@ type error_msg =
 	| Custom of string
 
 exception Error of error_msg * pos
-exception TypePath of string list * (string * bool) option
+exception TypePath of string list * (string * bool) option * bool (* in import *)
 exception Display of expr
 
 let error_msg = function
@@ -50,7 +50,14 @@ let display_error : (error_msg -> pos -> unit) ref = ref (fun _ _ -> assert fals
 let quoted_ident_prefix = "@$__hx__"
 
 let quote_ident s =
-	try
+	quoted_ident_prefix ^ s
+
+let unquote_ident f =
+	let pf = quoted_ident_prefix in
+	let pflen = String.length pf in
+	let is_quoted = String.length f >= pflen && String.sub f 0 pflen = pf in
+	let s = if is_quoted then String.sub f pflen (String.length f - pflen) else f in
+	let is_valid = not is_quoted || try
 		for i = 0 to String.length s - 1 do
 			match String.unsafe_get s i with
 			| 'a'..'z' | 'A'..'Z' | '_' -> ()
@@ -58,18 +65,16 @@ let quote_ident s =
 			| _ -> raise Exit
 		done;
 		if Hashtbl.mem Lexer.keywords s then raise Exit;
-		s
+		true
 	with Exit ->
-		quoted_ident_prefix ^ s
-
-let unquote_ident f =
-	let pf = quoted_ident_prefix in
-	let pflen = String.length pf in
-	if String.length f >= pflen && String.sub f 0 pflen = pf then String.sub f pflen (String.length f - pflen), false else f, true
+		false
+	in
+	s,is_quoted,is_valid
 
 let cache = ref (DynArray.create())
 let last_doc = ref None
 let use_doc = ref false
+let use_parser_resume = ref true
 let resume_display = ref null_pos
 let in_macro = ref false
 
@@ -83,9 +88,13 @@ let do_resume() = !resume_display <> null_pos
 
 let display e = raise (Display e)
 
+let type_path sl in_import = match sl with
+	| n :: l when n.[0] >= 'A' && n.[0] <= 'Z' -> raise (TypePath (List.rev l,Some (n,false),in_import));
+	| _ -> raise (TypePath (List.rev sl,None,in_import))
+
 let is_resuming p =
 	let p2 = !resume_display in
-	p.pmax = p2.pmin && Common.unique_full_path p.pfile = p2.pfile
+	p.pmax = p2.pmin && !use_parser_resume && Common.unique_full_path p.pfile = p2.pfile
 
 let set_resume p =
 	resume_display := { p with pfile = Common.unique_full_path p.pfile }
@@ -369,7 +378,20 @@ let reify in_macro =
 				to_obj fields p
 			) vl p]
 		| EFunction (name,f) ->
-			expr "EFunction" [to_opt to_string name p; to_fun f p]
+			let name = match name with
+				| None ->
+					to_null p
+				| Some name ->
+					if ExtString.String.starts_with name "inline_$" then begin
+						let real_name = (String.sub name 7 (String.length name - 7)) in
+						let e_name = to_string real_name p in
+						let e_inline = to_string "inline_" p in
+						let e_add = (EBinop(OpAdd,e_inline,e_name),p) in
+						e_add
+					end else
+						to_string name p
+			in
+			expr "EFunction" [name; to_fun f p]
 		| EBlock el ->
 			expr "EBlock" [to_expr_array el p]
 		| EFor (e1,e2) ->
@@ -496,10 +518,12 @@ let dollar_ident_macro pack = parser
 	| [< '(Const (Ident i),p) >] -> i,p
 	| [< '(Dollar i,p) >] -> ("$" ^ i),p
 	| [< '(Kwd Macro,p) when pack <> [] >] -> "macro", p
+	| [< '(Kwd Extern,p) when pack <> [] >] -> "extern", p
 
 let lower_ident_or_macro = parser
 	| [< '(Const (Ident i),p) when is_lower_ident i >] -> i
 	| [< '(Kwd Macro,_) >] -> "macro"
+	| [< '(Kwd Extern,_) >] -> "extern"
 
 let any_enum_ident = parser
 	| [< i = ident >] -> i
@@ -552,17 +576,17 @@ and parse_type_decls pack acc s =
 		match s with parser
 		| [< v = parse_type_decl; l = parse_type_decls pack (v :: acc) >] -> l
 		| [< >] -> List.rev acc
-	with TypePath ([],Some (name,false)) ->
+	with TypePath ([],Some (name,false),b) ->
 		(* resolve imports *)
 		List.iter (fun d ->
 			match fst d with
 			| EImport (t,_) ->
 				(match List.rev t with
-				| (n,_) :: path when n = name && List.for_all (fun (i,_) -> is_lower_ident i) path -> raise (TypePath (List.map fst (List.rev path),Some (name,false)))
+				| (n,_) :: path when n = name && List.for_all (fun (i,_) -> is_lower_ident i) path -> raise (TypePath (List.map fst (List.rev path),Some (name,false),b))
 				| _ -> ())
 			| _ -> ()
 		) acc;
-		raise (TypePath (pack,Some(name,true)))
+		raise (TypePath (pack,Some(name,true),b))
 
 and parse_type_decl s =
 	match s with parser
@@ -629,23 +653,30 @@ and parse_import s p1 =
 	let rec loop acc =
 		match s with parser
 		| [< '(Dot,p) >] ->
-			if is_resuming p then raise (TypePath (List.rev (List.map fst acc),None));
+			let resume() =
+				type_path (List.map fst acc) true
+			in
+			if is_resuming p then resume();
 			(match s with parser
 			| [< '(Const (Ident k),p) >] ->
 				loop ((k,p) :: acc)
 			| [< '(Kwd Macro,p) >] ->
 				loop (("macro",p) :: acc)
+			| [< '(Kwd Extern,p) >] ->
+				loop (("extern",p) :: acc)
 			| [< '(Binop OpMult,_); '(Semicolon,p2) >] ->
 				p2, List.rev acc, IAll
 			| [< '(Binop OpOr,_) when do_resume() >] ->
 				set_resume p;
-				raise (TypePath (List.rev (List.map fst acc),None))
+				resume()
 			| [< >] ->
 				serror());
 		| [< '(Semicolon,p2) >] ->
 			p2, List.rev acc, INormal
 		| [< '(Kwd In,_); '(Const (Ident name),_); '(Semicolon,p2) >] ->
 			p2, List.rev acc, IAsName name
+		| [< '(Const (Ident "as"),_); '(Const (Ident name),_); '(Semicolon,p2) >] ->
+			p2, List.rev acc, IAsName name
 		| [< >] ->
 			serror()
 	in
@@ -748,8 +779,21 @@ and parse_common_flags = parser
 	| [< '(Kwd Extern,_); l = parse_common_flags >] -> (HExtern, EExtern) :: l
 	| [< >] -> []
 
+and parse_meta_argument_expr s =
+	try
+		expr s
+	with Display e -> match fst e with
+		| EDisplay(e,_) ->
+			begin try
+				type_path (string_list_of_expr_path_raise e) false
+			with Exit ->
+				e
+			end
+		| _ ->
+			e
+
 and parse_meta_params pname s = match s with parser
-	| [< '(POpen,p) when p.pmin = pname.pmax; params = psep Comma expr; '(PClose,_); >] -> params
+	| [< '(POpen,p) when p.pmin = pname.pmax; params = psep Comma parse_meta_argument_expr; '(PClose,_); >] -> params
 	| [< >] -> []
 
 and parse_meta_entry = parser
@@ -774,8 +818,11 @@ and parse_class_flags = parser
 	| [< '(Kwd Class,p) >] -> [] , p
 	| [< '(Kwd Interface,p) >] -> [HInterface] , p
 
+and parse_type_hint = parser
+	| [< '(DblDot,_); t = parse_complex_type >] -> t
+
 and parse_type_opt = parser
-	| [< '(DblDot,_); t = parse_complex_type >] -> Some t
+	| [< t = parse_type_hint >] -> Some t
 	| [< >] -> None
 
 and parse_complex_type s =
@@ -811,7 +858,7 @@ and parse_type_path1 pack = parser
 			(match s with parser
 			| [< '(Dot,p) >] ->
 				if is_resuming p then
-					raise (TypePath (List.rev (name :: pack),None))
+					raise (TypePath (List.rev (name :: pack),None,false))
 				else
 					parse_type_path1 (name :: pack) s
 			| [< '(Semicolon,_) >] ->
@@ -821,12 +868,12 @@ and parse_type_path1 pack = parser
 			let sub = (match s with parser
 				| [< '(Dot,p); s >] ->
 					(if is_resuming p then
-						raise (TypePath (List.rev pack,Some (name,false)))
+						raise (TypePath (List.rev pack,Some (name,false),false))
 					else match s with parser
 						| [< '(Const (Ident name),_) when not (is_lower_ident name) >] -> Some name
 						| [< '(Binop OpOr,_) when do_resume() >] ->
 							set_resume p;
-							raise (TypePath (List.rev pack,Some (name,false)))
+							raise (TypePath (List.rev pack,Some (name,false),false))
 						| [< >] -> serror())
 				| [< >] -> None
 			) in
@@ -841,7 +888,7 @@ and parse_type_path1 pack = parser
 				tsub = sub;
 			}
 	| [< '(Binop OpOr,_) when do_resume() >] ->
-		raise (TypePath (List.rev pack,None))
+		raise (TypePath (List.rev pack,None,false))
 
 and type_name = parser
 	| [< '(Const (Ident name),p) >] ->
@@ -849,6 +896,7 @@ and type_name = parser
 			error (Custom "Type name should start with an uppercase letter") p
 		else
 			name
+	| [< '(Dollar name,_) >] -> "$" ^ name
 
 and parse_type_path_or_const = parser
 	(* we can't allow (expr) here *)
@@ -869,7 +917,7 @@ and parse_complex_type_next t = parser
 
 and parse_type_anonymous opt = parser
 	| [< '(Question,_) when not opt; s >] -> parse_type_anonymous true s
-	| [< name, p1 = ident; '(DblDot,_); t = parse_complex_type; s >] ->
+	| [< name, p1 = ident; t = parse_type_hint; s >] ->
 		let next p2 acc =
 			{
 				cff_name = name;
@@ -898,10 +946,7 @@ and parse_enum s =
 		| [< '(POpen,_); l = psep Comma parse_enum_param; '(PClose,_) >] -> l
 		| [< >] -> []
 		) in
-		let t = (match s with parser
-		| [< '(DblDot,_); t = parse_complex_type >] -> Some t
-		| [< >] -> None
-		) in
+		let t = parse_type_opt s in
 		let p2 = (match s with parser
 			| [< p = semicolon >] -> p
 			| [< >] -> serror()
@@ -917,8 +962,8 @@ and parse_enum s =
 		}
 
 and parse_enum_param = parser
-	| [< '(Question,_); name, _ = ident; '(DblDot,_); t = parse_complex_type >] -> (name,true,t)
-	| [< name, _ = ident; '(DblDot,_); t = parse_complex_type >] -> (name,false,t)
+	| [< '(Question,_); name, _ = ident; t = parse_type_hint >] -> (name,true,t)
+	| [< name, _ = ident; t = parse_type_hint >] -> (name,false,t)
 
 and parse_class_field s =
 	let doc = get_doc s in
@@ -928,10 +973,7 @@ and parse_class_field s =
 		| [< '(Kwd Var,p1); name, _ = dollar_ident; s >] ->
 			(match s with parser
 			| [< '(POpen,_); i1 = property_ident; '(Comma,_); i2 = property_ident; '(PClose,_) >] ->
-				let t = (match s with parser
-					| [< '(DblDot,_); t = parse_complex_type >] -> Some t
-					| [< >] -> None
-				) in
+				let t = parse_type_opt s in
 				let e , p2 = (match s with parser
 				| [< '(Binop OpAssign,_); e = toplevel_expr; p2 = semicolon >] -> Some e , p2
 				| [< '(Semicolon,p2) >] -> None , p2
@@ -995,8 +1037,8 @@ and parse_fun_param_value = parser
 	| [< >] -> None
 
 and parse_fun_param_type = parser
-	| [< '(Question,_); name = ident; '(DblDot,_); t = parse_complex_type >] -> (name,true,t)
-	| [< name = ident; '(DblDot,_); t = parse_complex_type >] -> (name,false,t)
+	| [< '(Question,_); name = ident; t = parse_type_hint >] -> (name,true,t)
+	| [< name = ident; t = parse_type_hint >] -> (name,false,t)
 
 and parse_constraint_params = parser
 	| [< '(Binop OpLt,_); l = psep Comma parse_constraint_param; '(Binop OpGt,_) >] -> l
@@ -1056,12 +1098,14 @@ and block acc s =
 			let tk , pos = (match Stream.peek s with None -> last_token s | Some t -> t) in
 			(!display_error) (Unexpected tk) pos;
 			block acc s
-        | Error (e,p) ->
+		| Error (e,p) ->
 			(!display_error) e p;
 			block acc s
 
 and parse_block_elt = parser
-	| [< '(Kwd Var,p1); vl = psep Comma parse_var_decl; p2 = semicolon >] -> (EVars vl,punion p1 p2)
+	| [< '(Kwd Var,p1); vl = parse_var_decls p1; p2 = semicolon >] ->
+		(EVars vl,punion p1 p2)
+	| [< '(Kwd Inline,p1); '(Kwd Function,_); e = parse_function p1 true; _ = semicolon >] -> e
 	| [< e = expr; _ = semicolon >] -> e
 
 and parse_obj_decl = parser
@@ -1080,11 +1124,38 @@ and parse_array_decl = parser
 	| [< >] ->
 		[]
 
+and parse_var_decl_head = parser
+	| [< name, _ = dollar_ident; t = parse_type_opt >] -> (name,t)
+
+and parse_var_assignment = parser
+	| [< '(Binop OpAssign,p1); s >] ->
+		begin match s with parser
+		| [< e = expr >] -> Some e
+		| [< >] -> error (Custom "expression expected after =") p1
+		end
+	| [< >] -> None
+
+and parse_var_decls_next vl = parser
+	| [< '(Comma,p1); name,t = parse_var_decl_head; s >] ->
+		begin try
+			let eo = parse_var_assignment s in
+			parse_var_decls_next ((name,t,eo) :: vl) s
+		with Display e ->
+			let v = (name,t,Some e) in
+			let e = (EVars(List.rev (v :: vl)),punion p1 (pos e)) in
+			display e
+		end
+	| [< >] ->
+		vl
+
+and parse_var_decls p1 = parser
+	| [< name,t = parse_var_decl_head; s >] ->
+		let eo = parse_var_assignment s in
+		List.rev (parse_var_decls_next [name,t,eo] s)
+	| [< s >] -> error (Custom "Missing variable identifier") p1
+
 and parse_var_decl = parser
-	| [< name, _ = dollar_ident; t = parse_type_opt; s >] ->
-		match s with parser
-		| [< '(Binop OpAssign,_); e = expr >] -> (name,t,Some e)
-		| [< >] -> (name,t,None)
+	| [< name,t = parse_var_decl_head; eo = parse_var_assignment >] -> (name,t,eo)
 
 and inline_function = parser
 	| [< '(Kwd Inline,_); '(Kwd Function,p1) >] -> true, p1
@@ -1108,6 +1179,22 @@ and parse_macro_expr p = parser
 	| [< e = secure_expr >] ->
 		reify_expr e
 
+and parse_function p1 inl = parser
+	| [< name = popt dollar_ident; pl = parse_constraint_params; '(POpen,_); al = psep Comma parse_fun_param; '(PClose,_); t = parse_type_opt; s >] ->
+		let make e =
+			let f = {
+				f_params = pl;
+				f_type = t;
+				f_args = al;
+				f_expr = Some e;
+			} in
+			EFunction ((match name with None -> None | Some (name,_) -> Some (if inl then "inline_" ^ name else name)),f), punion p1 (pos e)
+		in
+		(try
+			expr_next (make (secure_expr s)) s
+		with
+			Display e -> display (make e))
+
 and expr = parser
 	| [< (name,params,p) = parse_meta_entry; s >] ->
 		(try
@@ -1129,10 +1216,15 @@ and expr = parser
 	| [< '(Kwd Null,p); s >] -> expr_next (EConst (Ident "null"),p) s
 	| [< '(Kwd Cast,p1); s >] ->
 		(match s with parser
-		| [< '(POpen,_); e = expr; s >] ->
+		| [< '(POpen,pp); e = expr; s >] ->
 			(match s with parser
 			| [< '(Comma,_); t = parse_complex_type; '(PClose,p2); s >] -> expr_next (ECast (e,Some t),punion p1 p2) s
-			| [< '(PClose,p2); s >] -> expr_next (ECast (e,None),punion p1 (pos e)) s
+			| [< t = parse_type_hint; '(PClose,p2); s >] ->
+				let ep = EParenthesis (ECheckType(e,t),punion p1 p2), punion p1 p2 in
+				expr_next (ECast (ep,None),punion p1 (pos ep)) s
+			| [< '(PClose,p2); s >] ->
+				let ep = expr_next (EParenthesis(e),punion pp p2) s in
+				expr_next (ECast (ep,None),punion p1 (pos ep)) s
 			| [< >] -> serror())
 		| [< e = secure_expr >] -> expr_next (ECast (e,None),punion p1 (pos e)) s)
 	| [< '(Kwd Throw,p); e = expr >] -> (EThrow e,p)
@@ -1143,22 +1235,10 @@ and expr = parser
 		| [< >] -> serror())
 	| [< '(POpen,p1); e = expr; s >] -> (match s with parser
 		| [< '(PClose,p2); s >] -> expr_next (EParenthesis e, punion p1 p2) s
-		| [< '(DblDot,_); t = parse_complex_type; '(PClose,p2); s >] -> expr_next (EParenthesis (ECheckType(e,t),punion p1 p2), punion p1 p2) s)
+		| [< t = parse_type_hint; '(PClose,p2); s >] -> expr_next (EParenthesis (ECheckType(e,t),punion p1 p2), punion p1 p2) s
+		| [< >] -> serror())
 	| [< '(BkOpen,p1); l = parse_array_decl; '(BkClose,p2); s >] -> expr_next (EArrayDecl l, punion p1 p2) s
-	| [< inl, p1 = inline_function; name = popt dollar_ident; pl = parse_constraint_params; '(POpen,_); al = psep Comma parse_fun_param; '(PClose,_); t = parse_type_opt; s >] ->
-		let make e =
-			let f = {
-				f_params = pl;
-				f_type = t;
-				f_args = al;
-				f_expr = Some e;
-			} in
-			EFunction ((match name with None -> None | Some (name,_) -> Some (if inl then "inline_" ^ name else name)),f), punion p1 (pos e)
-		in
-		(try
-			expr_next (make (secure_expr s)) s
-		with
-			Display e -> display (make e))
+	| [< '(Kwd Function,p1); e = parse_function p1 false; >] -> e
 	| [< '(Unop op,p1) when is_prefix op; e = expr >] -> make_unop op e p1
 	| [< '(Binop OpSub,p1); e = expr >] ->
 		let neg s =
@@ -1205,13 +1285,13 @@ and expr = parser
 			Display e -> display (EWhile (cond,e,NormalWhile),punion p1 (pos e)))
 	| [< '(Kwd Do,p1); e = expr; '(Kwd While,_); '(POpen,_); cond = expr; '(PClose,_); s >] -> (EWhile (cond,e,DoWhile),punion p1 (pos e))
 	| [< '(Kwd Switch,p1); e = expr; '(BrOpen,_); cases , def = parse_switch_cases e []; '(BrClose,p2); s >] -> (ESwitch (e,cases,def),punion p1 p2)
-	| [< '(Kwd Try,p1); e = expr; cl = plist (parse_catch e); s >] -> (ETry (e,cl),p1)
+	| [< '(Kwd Try,p1); e = expr; cl = plist (parse_catch e); >] -> (ETry (e,cl),p1)
 	| [< '(IntInterval i,p1); e2 = expr >] -> make_binop OpInterval (EConst (Int i),p1) e2
 	| [< '(Kwd Untyped,p1); e = expr >] -> (EUntyped e,punion p1 (pos e))
 	| [< '(Dollar v,p); s >] -> expr_next (EConst (Ident ("$"^v)),p) s
 
 and expr_next e1 = parser
- 	| [< '(BrOpen,p1) when is_dollar_ident e1; eparam = expr; '(BrClose,p2); s >] ->
+	| [< '(BrOpen,p1) when is_dollar_ident e1; eparam = expr; '(BrClose,p2); s >] ->
 		(match fst e1 with
 		| EConst(Ident n) -> expr_next (EMeta((Common.MetaInfo.from_string n,[],snd e1),eparam), punion p1 p2) s
 		| _ -> assert false)
@@ -1254,8 +1334,13 @@ and expr_next e1 = parser
 			make_binop OpGte e1 (secure_expr s)
 		| [< e2 = secure_expr >] ->
 			make_binop OpGt e1 e2)
-	| [< '(Binop op,_); e2 = expr >] ->
-		make_binop op e1 e2
+	| [< '(Binop op,_); s >] ->
+		(try
+			(match s with parser
+			| [< e2 = expr >] -> make_binop op e1 e2
+			| [< >] -> serror())
+		with Display e2 ->
+			raise (Display (make_binop op e1 e2)))
 	| [< '(Unop op,p) when is_postfix e1 op; s >] ->
 		expr_next (EUnop (op,Postfix,e1), punion (pos e1) p) s
 	| [< '(Question,_); e2 = expr; '(DblDot,_); e3 = expr >] ->
@@ -1295,7 +1380,7 @@ and parse_switch_cases eswitch cases = parser
 and parse_catch etry = parser
 	| [< '(Kwd Catch,p); '(POpen,_); name, _ = dollar_ident; s >] ->
 		match s with parser
-		| [< '(DblDot,_); t = parse_complex_type; '(PClose,_); s >] ->
+		| [< t = parse_type_hint; '(PClose,_); s >] ->
 			(try
 				(name,t,secure_expr s)
 			with

+ 1 - 1
std/Array.hx

@@ -138,7 +138,7 @@ extern class Array<T> {
 
 		The sort operation is not guaranteed to be stable, which means that the
 		order of equal elements may not be retained. For a stable Array sorting
-		algorithm, `haxe.ds.sort.MergeSort.sort()` can be used instead.
+		algorithm, `haxe.ds.ArraySort.sort()` can be used instead.
 
 		If `f` is null, the result is unspecified.
 	**/

+ 4 - 2
std/DateTools.hx

@@ -45,6 +45,8 @@ class DateTools {
 				__format(d,"%m/%d/%y");
 			case "e":
 				untyped Std.string(d.getDate());
+			case "F":
+				__format(d,"%Y-%m-%d");
 			case "H","k":
 				untyped StringTools.lpad(Std.string(d.getHours()),if( e == "H" ) "0" else " ",2);
 			case "I","l":
@@ -200,12 +202,12 @@ class DateTools {
 		return o.ms + 1000.0 * (o.seconds + 60.0 * (o.minutes + 60.0 * (o.hours + 24.0 * o.days)));
 	}
 
-	#if (js || flash || php || cpp)
+	#if (js || flash || php || cpp || python)
 	/**
 		Retrieve Unix timestamp value from Date components. Takes same argument sequence as the Date constructor.
 	**/
 	public static #if (js || flash || php) inline #end function makeUtc(year : Int, month : Int, day : Int, hour : Int, min : Int, sec : Int ):Float {
-	    #if (js || flash)
+	    #if (js || flash || python)
 		   return untyped Date.UTC(year, month, day, hour, min, sec);
 		#elseif php
 		   return untyped __call__("gmmktime", hour, min, sec, month + 1, day, year) * 1000;

+ 2 - 2
std/EReg.hx

@@ -34,7 +34,7 @@
 	its methods.
 
 	A detailed explanation of the supported operations is available at
-	http://haxe.org/doc/cross/regexp
+	http://haxe.org/manual/std-regex.html
 **/
 class EReg {
 
@@ -131,7 +131,7 @@ class EReg {
 
 		If `s` is null, the result is unspecified.
 	**/
-	public function matchSub( s : String, pos : Int, len : Int = 0):Bool {
+	public function matchSub( s : String, pos : Int, len : Int = -1):Bool {
 		return false;
 	}
 

+ 3 - 3
std/IntIterator.hx

@@ -41,7 +41,7 @@ class IntIterator {
 
 		If `max <= min`, the iterator will not act as a countdown.
 	**/
-	public function new( min : Int, max : Int ) {
+	public inline function new( min : Int, max : Int ) {
 		this.min = min;
 		this.max = max;
 	}
@@ -49,7 +49,7 @@ class IntIterator {
 	/**
 		Returns true if the iterator has other items, false otherwise.
 	**/
-	public function hasNext() {
+	public inline function hasNext() {
 		return min < max;
 	}
 
@@ -58,7 +58,7 @@ class IntIterator {
 
 		If this is called while hasNext() is false, the result is unspecified.
 	**/
-	public function next() {
+	public inline function next() {
 		return min++;
 	}
 

+ 22 - 34
std/List.hx

@@ -158,40 +158,8 @@ class List<T> {
 	/**
 		Returns an iterator on the elements of the list.
 	**/
-	public function iterator() : Iterator<T> {
-		#if (java || cs)
-		var h = h;
-		return cast {
-			hasNext : function() {
-				return (h != null);
-			},
-			next : function() {
-				{
-					if( h == null )
-						return null;
-					var x = h[0];
-					h = h[1];
-					return x;
-				}
-			}
-		}
-		#else
-		return cast {
-			h : h,
-			hasNext : function() {
-				return untyped (__this__.h != null);
-			},
-			next : function() {
-				untyped {
-					if( __this__.h == null )
-						return null;
-					var x = __this__.h[0];
-					__this__.h = __this__.h[1];
-					return x;
-				}
-			}
-		}
-		#end
+	public inline function iterator() : ListIterator<T> {
+		return new ListIterator<T>(h);
 	}
 
 	/**
@@ -268,3 +236,23 @@ class List<T> {
 	}
 
 }
+
+private class ListIterator<T> {
+	var head:Array<Dynamic>;
+	var val:Dynamic;
+
+	public inline function new(head:Array<Dynamic>) {
+		this.head = head;
+		this.val = null;
+	}
+
+	public inline function hasNext():Bool {
+		return head != null;
+	}
+
+	public inline function next():T {
+		val = head[0];
+		head = head[1];
+		return val;
+	}
+}

+ 10 - 20
std/Map.hx

@@ -26,6 +26,7 @@ import haxe.ds.HashMap;
 import haxe.ds.ObjectMap;
 import haxe.ds.WeakMap;
 import haxe.ds.EnumValueMap;
+import haxe.Constraints.IMap;
 
  /**
 	Map allows key to value mapping for arbitrary value types, and many key
@@ -133,45 +134,34 @@ abstract Map<K,V>(IMap<K,V> ) {
 		return v;
 	}
 
-	@:to static inline function toStringMap(t:IMap<String,V>):StringMap<V> {
+	@:to static inline function toStringMap<K:String,V>(t:IMap<K,V>):StringMap<V> {
 		return new StringMap<V>();
 	}
 
-	@:to static inline function toIntMap(t:IMap<Int,V>):IntMap<V> {
+	@:to static inline function toIntMap<K:Int,V>(t:IMap<K,V>):IntMap<V> {
 		return new IntMap<V>();
 	}
 
-	@:to static inline function toEnumValueMapMap<K:EnumValue>(t:IMap<K,V>):EnumValueMap<K,V> {
+	@:to static inline function toEnumValueMapMap<K:EnumValue,V>(t:IMap<K,V>):EnumValueMap<K,V> {
 		return new EnumValueMap<K, V>();
 	}
 
-	@:to static inline function toObjectMap<K:{ }>(t:IMap<K,V>):ObjectMap<K,V> {
+	@:to static inline function toObjectMap<K:{ },V>(t:IMap<K,V>):ObjectMap<K,V> {
 		return new ObjectMap<K, V>();
 	}
 
 	@:from static inline function fromStringMap<V>(map:StringMap<V>):Map< String, V > {
-		return map;
+		return cast map;
 	}
 
 	@:from static inline function fromIntMap<V>(map:IntMap<V>):Map< Int, V > {
-		return map;
+		return cast map;
 	}
 
 	@:from static inline function fromObjectMap<K:{ }, V>(map:ObjectMap<K,V>):Map<K,V> {
-		return map;
+		return cast map;
 	}
 }
 
-interface IMap<K,V> {
-	public function get(k:K):Null<V>;
-	public function set(k:K, v:V):Void;
-	public function exists(k:K):Bool;
-	public function remove(k:K):Bool;
-	public function keys():Iterator<K>;
-	public function iterator():Iterator<V>;
-	public function toString():String;
-}
-
-private typedef Hashable = {
-	function hashCode():Int;
-}
+@:deprecated
+typedef IMap<K, V> = haxe.Constraints.IMap<K, V>;

+ 39 - 48
std/Math.hx

@@ -22,11 +22,11 @@
 /**
 	This class defines mathematical functions and constants.
 **/
-#if cpp @:include("hxMath") #end
+#if cpp @:include("hxMath.h") #end
 extern class Math
 {
 	/**
-		Represents the ratio of the circumference of a circle to its diameter, 
+		Represents the ratio of the circumference of a circle to its diameter,
 		specified by the constant, π. `PI` is approximately 3.141592653589793.
 	**/
 	static var PI(default,null) : Float;
@@ -37,7 +37,7 @@ extern class Math
 		For example, this is the result of -1.0 / 0.0.
 
 		Operations with NEGATIVE_INFINITY as an operand may result in
-		NEGATIVE_INFINITY, POSITIVE_INFINITY or NaN. 
+		NEGATIVE_INFINITY, POSITIVE_INFINITY or NaN.
 
 		If this constant is converted to an Int, e.g. through Std.int(), the
 		result is unspecified.
@@ -50,7 +50,7 @@ extern class Math
 		For example, this is the result of 1.0 / 0.0.
 
 		Operations with POSITIVE_INFINITY as an operand may result in
-		NEGATIVE_INFINITY, POSITIVE_INFINITY or NaN. 
+		NEGATIVE_INFINITY, POSITIVE_INFINITY or NaN.
 
 		If this constant is converted to an Int, e.g. through Std.int(), the
 		result is unspecified.
@@ -72,7 +72,7 @@ extern class Math
 		In order to test if a value is NaN, you should use Math.isNaN() function.
 
 		@php In PHP versions prior to 5.3.1 VC 9 there may be unexpected
-		results when performing arithmetic operations with NaN on Windows, 
+		results when performing arithmetic operations with NaN on Windows,
 		see [https://bugs.php.net/bug.php?id=42143]
 	**/
 	static var NaN(default, null) : Float;
@@ -80,12 +80,12 @@ extern class Math
 	/**
 		Returns the absolute value of `v`.
 
-		If `v` is positive or 0, the result is unchanged. Otherwise the result 
+		If `v` is positive or 0, the result is unchanged. Otherwise the result
 		is -`v`.
-		
-		If `v` is NEGATIVE_INFINITY or POSITIVE_INFINITY, the result is 
+
+		If `v` is NEGATIVE_INFINITY or POSITIVE_INFINITY, the result is
 		POSITIVE_INFINITY.
-		
+
 		If `v` is NaN, the result is NaN.
 	**/
 	static function abs(v:Float):Float;
@@ -110,62 +110,62 @@ extern class Math
 
 	/**
 		Returns the trigonometric sine of the specified angle `v`, in radians.
-		
+
 		If `v` is NaN or infinite, the result is NaN.
 	**/
 	static function sin(v:Float):Float;
 
 	/**
 		Returns the trigonometric cosine of the specified angle `v`, in radians.
-		
+
 		If `v` is NaN or infinite, the result is NaN.
 	**/
 	static function cos(v:Float):Float;
 
 	/**
 		Returns the trigonometric tangent of the specified angle `v`, in radians.
-		
+
 		If `v` is NaN or infinite, the result is NaN.
 	**/
 	static function tan(v:Float):Float;
 
 	/**
 		Returns the trigonometric arc of the specified angle `v`, in radians.
-		
+
 		If `v` is NaN or infinite, the result is NaN.
 	**/
 	static function asin(v:Float):Float;
 
 	/**
-		Returns the trigonometric arc cosine of the specified angle `v`, 
+		Returns the trigonometric arc cosine of the specified angle `v`,
 		in radians.
-		
+
 		If `v` is NaN or infinite, the result is NaN.
 	**/
 	static function acos(v:Float):Float;
 
 	/**
-		Returns the trigonometric arc tangent of the specified angle `v`, 
+		Returns the trigonometric arc tangent of the specified angle `v`,
 		in radians.
-		
+
 		If `v` is NaN or infinite, the result is NaN.
 	**/
 	static function atan(v:Float):Float;
 
 	/**
-		Returns the trigonometric arc tangent whose tangent is the quotient of 
+		Returns the trigonometric arc tangent whose tangent is the quotient of
 		two specified numbers, in radians.
-		
-		If parameter `x` or `y`  is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY, 
+
+		If parameter `x` or `y`  is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY,
 		the result is NaN.
 	**/
 	static function atan2(y:Float, x:Float):Float;
 
 	/**
 		Returns Euler's number, raised to the power of `v`.
-		
+
 		exp(1.0) is approximately 2.718281828459.
-		
+
 		If `v` is POSITIVE_INFINITY, the result is POSITIVE_INFINITY.
 		If `v` is NEGATIVE_INFINITY, the result is 0.0.
 		If `v` is NaN, the result is NaN.
@@ -174,11 +174,11 @@ extern class Math
 
 	/**
 		Returns the natural logarithm of `v`.
-		
-		This is the mathematical inverse operation of exp, 
+
+		This is the mathematical inverse operation of exp,
 		i.e. `log(exp(v)) == v` always holds.
-		
-		If `v` is negative (including NEGATIVE_INFINITY) or NaN, the result 
+
+		If `v` is negative (including NEGATIVE_INFINITY) or NaN, the result
 		is NaN.
 		If `v` is POSITIVE_INFINITY, the result is POSITIVE_INFINITY.
 		If `v` is 0.0, the result is NEGATIVE_INFINITY.
@@ -192,8 +192,8 @@ extern class Math
 
 	/**
 		Returns the square root of `v`.
-		
-		If `v` is negative (including NEGATIVE_INFINITY) or NaN, the result 
+
+		If `v` is negative (including NEGATIVE_INFINITY) or NaN, the result
 		is NaN.
 		If `v` is POSITIVE_INFINITY, the result is POSITIVE_INFINITY.
 		If `v` is 0.0, the result is 0.0.
@@ -202,8 +202,8 @@ extern class Math
 
 	/**
 		Rounds `v` to the nearest integer value.
-		
-		If `v` is outside of the signed Int32 range, or is NaN, NEGATIVE_INFINITY 
+
+		If `v` is outside of the signed Int32 range, or is NaN, NEGATIVE_INFINITY
 		or POSITIVE_INFINITY, the result is unspecified.
 	**/
 	static function round(v:Float):Int;
@@ -211,7 +211,7 @@ extern class Math
 	/**
 		Returns the largest integer value that is not greater than `v`.
 
-		If `v` is outside of the signed Int32 range, or is NaN, NEGATIVE_INFINITY 
+		If `v` is outside of the signed Int32 range, or is NaN, NEGATIVE_INFINITY
 		or POSITIVE_INFINITY, the result is unspecified.
 	**/
 	static function floor(v:Float):Int;
@@ -219,13 +219,13 @@ extern class Math
 	/**
 		Returns the smallest integer value that is not less than `v`.
 
-		If `v` is outside of the signed Int32 range, or is NaN, NEGATIVE_INFINITY 
+		If `v` is outside of the signed Int32 range, or is NaN, NEGATIVE_INFINITY
 		or POSITIVE_INFINITY, the result is unspecified.
 	**/
 	static function ceil(v:Float):Int;
 
 	/**
-		Returns a pseudo-random number which is greater than or equal to 0.0, 
+		Returns a pseudo-random number which is greater than or equal to 0.0,
 		and less than 1.0.
 	**/
 	static function random() : Float;
@@ -234,7 +234,7 @@ extern class Math
 	/**
 		Returns the largest integer value that is not greater than `v`, as a Float.
 
-		If `v` is is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY, 
+		If `v` is is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY,
 		the result is unspecified.
 	**/
 	static function ffloor( v : Float ) : Float;
@@ -242,7 +242,7 @@ extern class Math
 	/**
 		Returns the smallest integer value that is not less than `v`, as a Float.
 
-		If `v` is is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY, 
+		If `v` is is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY,
 		the result is unspecified.
 	**/
 	static function fceil( v : Float ) : Float;
@@ -250,7 +250,7 @@ extern class Math
 	/**
 		Rounds `v` to the nearest integer value, as a Float.
 
-		If `v` is is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY, 
+		If `v` is is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY,
 		the result is unspecified.
 	**/
 	static function fround( v : Float ) : Float;
@@ -275,7 +275,7 @@ extern class Math
 	/**
 		Tells if `f` is a finite number.
 
-		If `f` is POSITIVE_INFINITY, NEGATIVE_INFINITY or NaN, the result 
+		If `f` is POSITIVE_INFINITY, NEGATIVE_INFINITY or NaN, the result
 		is false, otherwise the result is true.
 	**/
 	static function isFinite( f : Float ) : Bool;
@@ -283,7 +283,7 @@ extern class Math
 	/**
 		Tells if `f` is not a valid number.
 
-		If `f` is NaN, the result is true, otherwise the result is false. 
+		If `f` is NaN, the result is true, otherwise the result is false.
 		In particular, both POSITIVE_INFINITY and NEGATIVE_INFINITY are
 		not considered NaN.
 	**/
@@ -295,15 +295,10 @@ extern class Math
 		NEGATIVE_INFINITY = __global__["Number"].NEGATIVE_INFINITY;
 		POSITIVE_INFINITY = __global__["Number"].POSITIVE_INFINITY;
 	#else
-		#if !js // genjs.ml will insert this only if necessary.
-			Math.__name__ = ["Math"];
-		#end
+		Math.__name__ = ["Math"];
 		Math.NaN = Number["NaN"];
 		Math.NEGATIVE_INFINITY = Number["NEGATIVE_INFINITY"];
 		Math.POSITIVE_INFINITY = Number["POSITIVE_INFINITY"];
-	#end
-	#if js
-		__feature__("Type.resolveClass",$hxClasses['Math'] = Math);
 	#end
 		Math.isFinite = function(i) {
 			return
@@ -311,8 +306,6 @@ extern class Math
 			__global__["isFinite"](i);
 			#elseif flash
 			_global["isFinite"](i);
-			#elseif js
-			__js__("isFinite")(i);
 			#else
 			false;
 			#end
@@ -323,8 +316,6 @@ extern class Math
 			__global__["isNaN"](i);
 			#elseif flash
 			_global["isNaN"](i);
-			#elseif js
-			__js__("isNaN")(i);
 			#else
 			false;
 			#end

+ 2 - 2
std/Reflect.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 /**
-	The Reflect API is a way to manipulate values dynamicly through an
+	The Reflect API is a way to manipulate values dynamically through an
 	abstract interface in an untyped manner. Use with care.
 **/
 extern class Reflect {
@@ -89,7 +89,7 @@ extern class Reflect {
 	/**
 		Call a method with the given object and arguments.
 	**/
-	public static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic;
+	public static function callMethod( o : Dynamic, func : haxe.Constraints.Function, args : Array<Dynamic> ) : Dynamic;
 
 	/**
 		Returns the fields of structure `o`.

+ 6 - 3
std/StdTypes.hx

@@ -94,8 +94,11 @@ typedef Iterator<T> = {
 	/**
 		Returns the current item of the Iterator and advances to the next one.
 
-		This method is not required to check hasNext() first. A call to this
-		method while hasNext() is false yields unspecified behavior.
+		This method is not required to check `hasNext` first. A call to this
+		method while `hasNext` is false yields unspecified behavior.
+
+		On the other hand iterators should not require a call to `hasNext`
+		before the first call to `next` if an element is available.
 	**/
 	function next() : T;
 
@@ -111,6 +114,6 @@ typedef Iterable<T> = {
 
 /**
 	ArrayAccess is used to indicate a class that can be accessed using brackets.
-	The type parameter represent the type of the elements stored.
+	The type parameter represents the type of the elements stored.
 **/
 extern interface ArrayAccess<T> { }

+ 1 - 1
std/String.hx

@@ -141,7 +141,7 @@ extern class String {
 	function substr( pos : Int, ?len : Int ) : String;
 
 	/**
-		Returns the part of `this` String from `startIndex` to `endIndex`.
+		Returns the part of `this` String from `startIndex` to but not including `endIndex`.
 
 		If `startIndex` or `endIndex` are negative, 0 is used instead.
 

+ 4 - 2
std/StringBuf.hx

@@ -32,7 +32,7 @@
 **/
 class StringBuf {
 
-	var b:String = "";
+	var b:String;
 
 	/**
 		The length of `this` StringBuf in characters.
@@ -44,7 +44,9 @@ class StringBuf {
 
 		This may involve initialization of the internal buffer.
 	**/
-	public function new() {}
+	public inline function new() {
+		b = "";
+	}
 
 	inline function get_length() : Int {
 		return b.length;

+ 69 - 28
std/StringTools.hx

@@ -26,6 +26,9 @@
 	If the first argument to any of the methods is null, the result is
 	unspecified.
 **/
+#if cpp
+using cpp.NativeString;
+#end
 #if cs
 @:keep
 #end
@@ -33,23 +36,25 @@ class StringTools {
 	/**
 		Encode an URL by using the standard format.
 	**/
-	#if (!java && !cpp) inline #end public static function urlEncode( s : String ) : String untyped {
+	#if (!java && !cpp) inline #end public static function urlEncode( s : String ) : String {
 		#if flash9
-			return __global__["encodeURIComponent"](s);
+			return untyped __global__["encodeURIComponent"](s);
 		#elseif flash
-			return _global["escape"](s);
+			return untyped _global["escape"](s);
 		#elseif neko
-			return new String(_urlEncode(s.__s));
+			return untyped new String(_urlEncode(s.__s));
 		#elseif js
-			return encodeURIComponent(s);
+			return untyped encodeURIComponent(s);
 		#elseif cpp
-			return s.__URLEncode();
+			return untyped s.__URLEncode();
 		#elseif java
 			try
 				return untyped __java__("java.net.URLEncoder.encode(s, \"UTF-8\")")
 			catch (e:Dynamic) throw e;
 		#elseif cs
-			return cs.system.Uri.EscapeUriString(s);
+			return untyped cs.system.Uri.EscapeUriString(s);
+		#elseif python
+			return python.lib.urllib.Parse.quote(s);
 		#else
 			return null;
 		#end
@@ -58,23 +63,25 @@ class StringTools {
 	/**
 		Decode an URL using the standard format.
 	**/
-	#if (!java && !cpp) inline #end public static function urlDecode( s : String ) : String untyped {
+	#if (!java && !cpp) inline #end public static function urlDecode( s : String ) : String {
 		#if flash9
-			return __global__["decodeURIComponent"](s.split("+").join(" "));
+			return untyped __global__["decodeURIComponent"](s.split("+").join(" "));
 		#elseif flash
-			return _global["unescape"](s);
+			return untyped _global["unescape"](s);
 		#elseif neko
-			return new String(_urlDecode(s.__s));
+			return untyped new String(_urlDecode(s.__s));
 		#elseif js
-			return decodeURIComponent(s.split("+").join(" "));
+			return untyped decodeURIComponent(s.split("+").join(" "));
 		#elseif cpp
-			return s.__URLDecode();
+			return untyped s.__URLDecode();
 		#elseif java
 			try
 				return untyped __java__("java.net.URLDecoder.decode(s, \"UTF-8\")")
 			catch (e:Dynamic) throw e;
 		#elseif cs
-			return cs.system.Uri.UnescapeDataString(s);
+			return untyped cs.system.Uri.UnescapeDataString(s);
+		#elseif python
+			return python.lib.urllib.Parse.unquote(s);
 		#else
 			return null;
 		#end
@@ -129,6 +136,15 @@ class StringTools {
 		return untyped s.startsWith(start);
 		#elseif cs
 		return untyped s.StartsWith(start);
+		#elseif cpp
+		if (s.length<start.length)
+			return false;
+		var p0 = s.c_str();
+		var p1 = start.c_str();
+		for(i in 0...start.length)
+			if ( p0.at(i) != p1.at(i) )
+				return false;
+		return true;
 		#else
 		return( s.length >= start.length && s.substr(0, start.length) == start );
 		#end
@@ -146,6 +162,15 @@ class StringTools {
 		return untyped s.endsWith(end);
 		#elseif cs
 		return untyped s.EndsWith(end);
+		#elseif cpp
+		if (s.length<end.length)
+			return false;
+		var p0 = s.c_str().add( s.length-end.length );
+		var p1 = end.c_str();
+		for(i in 0...end.length)
+			if ( p0.at(i) != p1.at(i) )
+				return false;
+		return true;
 		#else
 		var elen = end.length;
 		var slen = s.length;
@@ -163,6 +188,9 @@ class StringTools {
 		`s`, the result is false.
 	**/
 	public static function isSpace( s : String, pos : Int ) : Bool {
+		#if python
+		if (s.length == 0 || pos < 0 || pos >= s.length) return false;
+		#end
 		var c = s.charCodeAt( pos );
 		return (c > 8 && c < 14) || c == 32;
 	}
@@ -323,43 +351,54 @@ class StringTools {
 				n >>>= 4;
 			} while( n > 0 );
 		#end
+		#if python
+		if (digits != null && s.length < digits) {
+			var diff = digits - s.length;
+			for (_ in 0...diff) {
+				s = "0" + s;
+			}
+		}
+		#else
 		if( digits != null )
 			while( s.length < digits )
 				s = "0"+s;
+		#end
 		return s;
 	}
 
 	/**
-		Returns the character code at position `index` of String `s`.
+		Returns the character code at position `index` of String `s`, or an
+		end-of-file indicator at if `position` equals `s.length`.
 
-		This method is faster than String.charCodeAt() on most platforms.
-		However, unlike String.charCodeAt(), the result is unspecified if
-		`index` is negative or exceeds `s.length`.
+		This method is faster than String.charCodeAt() on some platforms, but
+		the result is unspecified if `index` is negative or greater than
+		`s.length`.
+
+		End of file status can be checked by calling `StringTools.isEof` with
+		the returned value as argument.
 
 		This operation is not guaranteed to work if `s` contains the \0
 		character.
 	**/
-	public static inline function fastCodeAt( s : String, index : Int ) : Int untyped {
+	public static inline function fastCodeAt( s : String, index : Int ) : Int {
 		#if neko
 		return untyped __dollar__sget(s.__s, index);
 		#elseif cpp
-		return s.cca(index);
+		return untyped s.cca(index);
 		#elseif flash9
-		return s.cca(index);
+		return untyped s.cca(index);
 		#elseif flash
-		return s["cca"](index);
+		return untyped s["cca"](index);
 		#elseif java
 		return ( index < s.length ) ? cast(_charAt(s, index), Int) : -1;
 		#elseif cs
-		return ( cast(index, UInt) < s.length ) ? cast(untyped s[index], Int) : -1;
+		return ( cast(index, UInt) < s.length ) ? cast(s[index], Int) : -1;
 		#elseif js
-			#if mt
-		return (untyped s).cca(index);
-			#else
 		return (untyped s).charCodeAt(index);
-			#end
+		#elseif python
+		return if (index >= s.length) -1 else python.internal.UBuiltins.ord(python.Syntax.arrayAccess(s, index));
 		#else
-		return s.cca(index);
+		return untyped s.cca(index);
 		#end
 	}
 
@@ -379,6 +418,8 @@ class StringTools {
 		return c == -1;
 		#elseif java
 		return c == -1;
+		#elseif python
+		return c == -1;
 		#else
 		return false;
 		#end

+ 1 - 1
std/Sys.hx

@@ -53,7 +53,7 @@ extern class Sys {
 	/**
 		Returns the whole environement variables.
 	**/
-	static function environment() : haxe.ds.StringMap<String>;
+	static function environment() : Map<String,String>;
 
 	/**
 		Suspend the current execution for the given time (in seconds).

+ 80 - 9
std/UInt.hx

@@ -25,7 +25,71 @@
 	The unsigned Int type is only defined for Flash9 and C#. It's currently
 	handled the same as a normal Int.
 **/
-@:coreType @:notNull @:runtimeValue abstract UInt to Int from Int { }
+@:coreType
+@:notNull
+@:runtimeValue
+@:analyzer(no_const_propagation)
+abstract UInt to Int from Int
+{
+	@:commutative @:op(A+B) private static function addI(lhs:UInt, rhs:Int):UInt;
+	@:commutative @:op(A+B) private static function addF(lhs:UInt, rhs:Float):Float;
+	@:op(A+B) private static function add(lhs:UInt, rhs:UInt):UInt;
+
+	@:commutative @:op(A*B) private static function mulI(lhs:UInt, rhs:Int):UInt;
+	@:commutative @:op(A*B) private static function mulF(lhs:UInt, rhs:Float):Float;
+	@:op(A*B) private static function mul(lhs:UInt, rhs:UInt):UInt;
+
+	@:op(A%B) private static function modI(lhs:UInt, rhs:Int):UInt;
+	@:op(A%B) private static function modF(lhs:UInt, rhs:Float):Float;
+	@:op(A%B) private static function mod(lhs:UInt, rhs:UInt):UInt;
+
+	@:op(A-B) private static function subI(lhs:UInt, rhs:Int):UInt;
+	@:op(A-B) private static function subF(lhs:UInt, rhs:Float):Float;
+	@:op(A-B) private static function sub(lhs:UInt, rhs:UInt):UInt;
+
+	@:op(A/B) private static function divI(lhs:UInt, rhs:Int):Float;
+	@:op(A/B) private static function divF(lhs:UInt, rhs:Float):Float;
+	@:op(A/B) private static function div(lhs:UInt, rhs:UInt):Float;
+
+	@:commutative @:op(A|B) private static function orI(lhs:UInt, rhs:Int):UInt;
+	@:op(A|B) private static function or(lhs:UInt, rhs:UInt):UInt;
+
+	@:commutative @:op(A^B) private static function xorI(lhs:UInt, rhs:Int):UInt;
+	@:op(A^B) private static function xor(lhs:UInt, rhs:UInt):UInt;
+
+	@:commutative @:op(A&B) private static function andI(lhs:UInt, rhs:Int):UInt;
+	@:op(A&B) private static function and(lhs:UInt, rhs:UInt):UInt;
+
+	@:op(A<<B) private static function shl(lhs:UInt, rhs:Int):UInt;
+	@:op(A>>B) private static function shr(lhs:UInt, rhs:Int):UInt;
+	@:op(A>>>B) private static function ushr(lhs:UInt, rhs:Int):UInt;
+
+	@:op(A>B) private static function gt(lhs:UInt, rhs:UInt):Bool;
+	@:op(A>=B) private static function gte(lhs:UInt, rhs:UInt):Bool;
+	@:op(A<B) private static function lt(lhs:UInt, rhs:UInt):Bool;
+	@:op(A<=B) private static function lte(lhs:UInt, rhs:UInt):Bool;
+
+	@:op(A>B) private static function gtf(lhs:UInt, rhs:Float):Bool;
+	@:op(A>B) private static function gtf(lhs:Float, rhs:UInt):Bool;
+	@:op(A>=B) private static function gtef(lhs:UInt, rhs:Float):Bool;
+	@:op(A>=B) private static function gtef(lhs:Float, rhs:UInt):Bool;
+	@:op(A<B) private static function ltf(lhs:UInt, rhs:Float):Bool;
+	@:op(A<B) private static function ltf(lhs:Float, rhs:UInt):Bool;
+	@:op(A<=B) private static function ltef(lhs:UInt, rhs:Float):Bool;
+	@:op(A<=B) private static function ltef(lhs:Float, rhs:UInt):Bool;
+
+	@:op(~A) private static function bneg(t:UInt):UInt;
+
+	@:commutative @:op(A == B) private static function equalsInt<T:Int>(a:UInt, b:T):Bool;
+	@:commutative @:op(A != B) private static function notEqualsInt<T:Int>(a:UInt, b:T):Bool;
+	@:commutative @:op(A == B) private static function equalsFloat<T:Float>(a:UInt, b:T):Bool;
+	@:commutative @:op(A != B) private static function notEqualsFloat<T:Float>(a:UInt, b:T):Bool;
+
+	@:op(++A) private function prefixIncrement():UInt;
+	@:op(A++) private function postfixIncrement():UInt;
+	@:op(--A) private function prefixDecrement():UInt;
+	@:op(A--) private function postfixDecrement():UInt;
+}
 #else
 /**
 	The unsigned Int type is only defined for Flash9 and C#.
@@ -49,7 +113,7 @@ abstract UInt(Int) from Int to Int {
 		return a.toInt() - b.toInt();
 	}
 
-	@:op(A > B) private static inline function gt(a:UInt, b:UInt):Bool {
+	@:op(A > B) private static #if !js inline #end function gt(a:UInt, b:UInt):Bool {
 		var aNeg = a.toInt() < 0;
 		var bNeg = b.toInt() < 0;
 		return
@@ -57,7 +121,7 @@ abstract UInt(Int) from Int to Int {
 			else a.toInt() > b.toInt();
 	}
 
-	@:op(A >= B) private static inline function gte(a:UInt, b:UInt):Bool {
+	@:op(A >= B) private static #if !js inline #end function gte(a:UInt, b:UInt):Bool {
 		var aNeg = a.toInt() < 0;
 		var bNeg = b.toInt() < 0;
 		return
@@ -89,11 +153,11 @@ abstract UInt(Int) from Int to Int {
 		return a.toInt() << b;
 	}
 
-	@:op(A >> B) private static inline function shr(a:UInt, b:UInt):UInt {
+	@:op(A >> B) private static inline function shr(a:UInt, b:Int):UInt {
 		return a.toInt() >> b;
 	}
 
-	@:op(A >>> B) private static inline function ushr(a:UInt, b:UInt):UInt {
+	@:op(A >>> B) private static inline function ushr(a:UInt, b:Int):UInt {
 		return a.toInt() >>> b;
 	}
 
@@ -129,11 +193,19 @@ abstract UInt(Int) from Int to Int {
 		return a.toFloat() > b;
 	}
 
-	@:commutative @:op(A == B) private static inline function equalsFloat(a:UInt, b:Float):Bool {
+	@:commutative @:op(A == B) private static inline function equalsInt<T:Int>(a:UInt, b:T):Bool {
+		return a.toInt() == b;
+	}
+
+	@:commutative @:op(A != B) private static inline function notEqualsInt<T:Int>(a:UInt, b:T):Bool {
+		return a.toInt() != b;
+	}
+
+	@:commutative @:op(A == B) private static inline function equalsFloat<T:Float>(a:UInt, b:T):Bool {
         return a.toFloat() == b;
     }
 
-    @:commutative @:op(A != B) private static inline function notEqualsFloat(a:UInt, b:Float):Bool {
+    @:commutative @:op(A != B) private static inline function notEqualsFloat<T:Float>(a:UInt, b:T):Bool {
         return a.toFloat() != b;
     }
 
@@ -158,7 +230,6 @@ abstract UInt(Int) from Int to Int {
 		return a.toFloat() <= b;
 	}
 
-
 	@:op(A < B) private static inline function floatLt(a:Float, b:UInt):Bool {
 		return a < b.toFloat();
 	}
@@ -204,7 +275,7 @@ abstract UInt(Int) from Int to Int {
 		return this;
 	}
 
-	@:to private inline function toFloat():Float {
+	@:to private #if (!js || analyzer) inline #end function toFloat():Float {
 		var int = toInt();
 		if (int < 0) {
 			return 4294967296.0 + int;

+ 182 - 85
std/Xml.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2012 Haxe Foundation
+ * Copyright (C)2005-2015 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -19,201 +19,298 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-/**
-	An abstract type representing the type of the Xml
-	Node. You can compare it to `Xml` statics and can
-	use `Std.string` to get a string reprensation
-	of the type.
-**/
 
-
-
-enum XmlType {
+@:enum abstract XmlType(Int) {
+	var Element = 0;
+	var PCData = 1;
+	var CData = 2;
+	var Comment = 3;
+	var DocType = 4;
+	var ProcessingInstruction = 5;
+	var Document = 6;
 }
 
-/**
-	The standard Xml class and parsing.
-	More API to manipulate XML are available in the [haxe.xml] package.
-**/
+class Xml {
 
-extern class Xml {
+	static public var Element(default,null) = XmlType.Element;
+	static public var PCData(default,null) = XmlType.PCData;
+	static public var CData(default,null) = XmlType.CData;
+	static public var Comment(default,null) = XmlType.Comment;
+	static public var DocType(default,null) = XmlType.DocType;
+	static public var ProcessingInstruction(default,null) = XmlType.ProcessingInstruction;
+	static public var Document(default,null) = XmlType.Document;
 
-	/**
-		A type of Xml node.
-	**/
-	static var Element(default,null) : XmlType;
+	static public function parse( str : String ) : Xml {
+		return haxe.xml.Parser.parse(str);
+	}
 
 	/**
-		A type of Xml node.
+		Returns the type of the Xml Node. This should be used before
+		accessing other functions since some might raise an exception
+		if the node type is not correct.
 	**/
-	static var PCData(default,null) : XmlType;
+	public var nodeType(default, null) : XmlType;
 
 	/**
-		A type of Xml node.
+		Returns the node name of an Element.
 	**/
-	static var CData(default,null) : XmlType;
+	@:isVar public var nodeName(get, set) : String;
 
 	/**
-		A type of Xml node.
+		Returns the node value. Only works if the Xml node is not an Element or a Document.
 	**/
-	static var Comment(default,null) : XmlType;
+	@:isVar public var nodeValue(get, set) : String;
 
 	/**
-		A type of Xml node.
+		Returns the parent object in the Xml hierarchy.
+		The parent can be [null], an Element or a Document.
 	**/
-	static var DocType(default,null) : XmlType;
+	public var parent(default, null) : Xml;
 
-	/**
-		A type of Xml node.
-	**/
-	static var ProcessingInstruction(default,null) : XmlType;
+	var children:Array<Xml>;
+	var attributeMap:Map<String, String>;
 
-	/**
-		A type of Xml node.
-	**/
-	static var Document(default,null) : XmlType;
+	inline function get_nodeName() {
+		if (nodeType != Element) {
+			throw 'Bad node type, expected Element but found $nodeType';
+		}
+		return nodeName;
+	}
 
-	/**
-		Parse a String into an Xml object.
-	**/
-	static function parse( str : String ) : Xml;
+	inline function set_nodeName(v) {
+		if (nodeType != Element) {
+			throw 'Bad node type, expected Element but found $nodeType';
+		}
+		return this.nodeName = v;
+	}
 
-	/**
-		Creates a node of the given type.
-	**/
-	static function createElement( name : String ) : Xml;
+	inline function get_nodeValue() {
+		if (nodeType == Document || nodeType == Element) {
+			throw 'Bad node type, unexpected $nodeType';
+		}
+		return nodeValue;
+	}
 
-	/**
-		Creates a node of the given type.
-	**/
-	static function createPCData( data : String ) : Xml;
+	inline function set_nodeValue(v) {
+		if (nodeType == Document || nodeType == Element) {
+			throw 'Bad node type, unexpected $nodeType';
+		}
+		return this.nodeValue = v;
+	}
 
 	/**
 		Creates a node of the given type.
 	**/
-	static function createCData( data : String ) : Xml;
+	static public function createElement( name : String ) : Xml {
+		var xml = new Xml(Element);
+		xml.nodeName = name;
+		return xml;
+	}
 
 	/**
 		Creates a node of the given type.
 	**/
-	static function createComment( data : String ) : Xml;
+	static public function createPCData( data : String ) : Xml {
+		var xml = new Xml(PCData);
+		xml.nodeValue = data;
+		return xml;
+	}
 
 	/**
 		Creates a node of the given type.
 	**/
-	static function createDocType( data : String ) : Xml;
+	static public function createCData( data : String ) : Xml {
+		var xml = new Xml(CData);
+		xml.nodeValue = data;
+		return xml;
+	}
 
 	/**
 		Creates a node of the given type.
 	**/
-	static function createProcessingInstruction( data : String ) : Xml;
+	static public function createComment( data : String ) : Xml {
+		var xml = new Xml(Comment);
+		xml.nodeValue = data;
+		return xml;
+	}
 
 	/**
 		Creates a node of the given type.
 	**/
-	static function createDocument() : Xml;
-
-	/**
-		Returns the type of the Xml Node. This should be used before
-		accessing other functions since some might raise an exception
-		if the node type is not correct.
-	**/
-	var nodeType(default,null) : XmlType;
+	static public function createDocType( data : String ) : Xml {
+		var xml = new Xml(DocType);
+		xml.nodeValue = data;
+		return xml;
+	}
 
 	/**
-		Returns the node name of an Element.
+		Creates a node of the given type.
 	**/
-	var nodeName(get,set) : String;
+	static public function createProcessingInstruction( data : String ) : Xml {
+		var xml = new Xml(ProcessingInstruction);
+		xml.nodeValue = data;
+		return xml;
+	}
 
 	/**
-		Returns the node value. Only works if the Xml node is not an Element or a Document.
+		Creates a node of the given type.
 	**/
-	var nodeValue(get,set) : String;
+	static public function createDocument() : Xml {
+		return new Xml(Document);
+	}
 
 	/**
 		Get the given attribute of an Element node. Returns [null] if not found.
 		Attributes are case-sensitive.
 	**/
-	function get( att : String ) : String; // check case insensitivy
+	public function get( att : String ) : String {
+		if (nodeType != Element) {
+			throw 'Bad node type, expected Element but found $nodeType';
+		}
+		return attributeMap[att];
+	}
 
 	/**
 		Set the given attribute value for an Element node.
 		Attributes are case-sensitive.
 	**/
-	function set( att : String, value : String ) : Void;
+	public function set( att : String, value : String ) : Void {
+		if (nodeType != Element) {
+			throw 'Bad node type, expected Element but found $nodeType';
+		}
+		attributeMap.set(att, value);
+	}
 
 	/**
 		Removes an attribute for an Element node.
 		Attributes are case-sensitive.
 	**/
-	function remove( att : String ) : Void;
+	public function remove( att : String ) : Void {
+		if (nodeType != Element) {
+			throw 'Bad node type, expected Element but found $nodeType';
+		}
+		attributeMap.remove(att);
+	}
 
 	/**
 		Tells if the Element node has a given attribute.
 		Attributes are case-sensitive.
 	**/
-	function exists( att : String ) : Bool;
+	public function exists( att : String ) : Bool {
+		if (nodeType != Element) {
+			throw 'Bad node type, expected Element but found $nodeType';
+		}
+		return attributeMap.exists(att);
+	}
 
 	/**
 		Returns an [Iterator] on all the attribute names.
 	**/
-	function attributes() : Iterator<String>;
-
-	/**
-		Returns the parent object in the Xml hierarchy.
-		The parent can be [null], an Element or a Document.
-	**/
-	var parent(get,null) : Xml;
+	public function attributes() : Iterator<String> {
+		if (nodeType != Element) {
+			throw 'Bad node type, expected Element but found $nodeType';
+		}
+		return attributeMap.keys();
+	}
 
 	/**
 		Returns an iterator of all child nodes.
 		Only works if the current node is an Element or a Document.
 	**/
-	function iterator() : Iterator<Xml>;
+	public inline function iterator() : Iterator<Xml> {
+		ensureElementType();
+		return children.iterator();
+	}
 
 	/**
 		Returns an iterator of all child nodes which are Elements.
 		Only works if the current node is an Element or a Document.
 	**/
-	function elements() : Iterator<Xml>;
+	public function elements() : Iterator<Xml> {
+		ensureElementType();
+		var ret = [for (child in children) if (child.nodeType == Element) child];
+		return ret.iterator();
+	}
 
 	/**
 		Returns an iterator of all child nodes which are Elements with the given nodeName.
 		Only works if the current node is an Element or a Document.
 	**/
-	function elementsNamed( name : String ) : Iterator<Xml>;
+	public function elementsNamed( name : String ) : Iterator<Xml> {
+		ensureElementType();
+		var ret = [for (child in children) if (child.nodeType == Element && child.nodeName == name) child];
+		return ret.iterator();
+	}
 
 	/**
 		Returns the first child node.
 	**/
-	function firstChild() : Xml;
+	public inline function firstChild() : Xml {
+		ensureElementType();
+		return children[0];
+	}
 
 	/**
 		Returns the first child node which is an Element.
 	**/
-	function firstElement() : Xml;
-
+	public function firstElement() : Xml {
+		ensureElementType();
+		for (child in children) {
+			if (child.nodeType == Element) {
+				return child;
+			}
+		}
+		return null;
+	}
 
 	/**
 		Adds a child node to the Document or Element.
 		One node can only be inside one given node which is indicated by the [parent] property.
 	**/
-	function addChild( x : Xml ) : Void;
+	public function addChild( x : Xml ) : Void {
+		ensureElementType();
+		if (x.parent == this) {
+			return;
+		} else if (x.parent != null) {
+			x.parent.removeChild(x);
+		}
+		children.push(x);
+		x.parent = this;
+	}
 
 	/**
 		Removes a child from the Document or Element.
 		Returns true if the child was successfuly removed.
 	**/
-	function removeChild( x : Xml ) : Bool;
+	public function removeChild( x : Xml ) : Bool {
+		ensureElementType();
+		return children.remove(x);
+	}
 
 	/**
 		Inserts a child at the given position among the other childs.
 	**/
-	function insertChild( x : Xml, pos : Int ) : Void;
+	public function insertChild( x : Xml, pos : Int ) : Void {
+		ensureElementType();
+		children.insert(pos, x);
+	}
 
 	/**
 		Returns a String representation of the Xml node.
 	**/
-	function toString() : String;
-
+	public inline function toString() : String {
+		return haxe.xml.Printer.print(this);
+	}
+
+	function new(nodeType:XmlType) {
+		this.nodeType = nodeType;
+		children = [];
+		attributeMap = new Map();
+	}
+
+	inline function ensureElementType() {
+		if (nodeType != Document && nodeType != Element) {
+			throw 'Bad node type, expected Element or Document but found $nodeType';
+		}
+	}
 }

+ 5 - 0
std/cpp/Callable.hx

@@ -0,0 +1,5 @@
+package cpp;
+
+typedef Callable<T> = Function<T, cpp.abi.Abi >
+
+

+ 13 - 0
std/cpp/CastCharStar.hx

@@ -0,0 +1,13 @@
+package cpp;
+
+abstract CastCharStar( RawPointer<Char> ) to(RawPointer<Char>)
+{
+   inline function new(s:String) this = untyped s.__s;
+
+   @:from
+   static public inline function fromString(s:String) return new CastCharStar(s);
+
+    @:to
+    public inline function toPointer() return this;
+}
+

+ 3 - 0
std/cpp/Char.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract Char from Int to Int {}

+ 13 - 0
std/cpp/ConstCharStar.hx

@@ -0,0 +1,13 @@
+package cpp;
+
+abstract ConstCharStar( RawConstPointer<Char> ) to(RawConstPointer<Char>)
+{
+   inline function new(s:String) this = untyped s.__s;
+
+   @:from
+   static public inline function fromString(s:String) return new ConstCharStar(s);
+
+    @:to
+    public inline function toPointer() return this;
+}
+

+ 40 - 0
std/cpp/ConstPointer.hx

@@ -0,0 +1,40 @@
+package cpp;
+
+@:coreType @:include("cpp/Pointer.h") @:native("cpp.Pointer")
+@:analyzer(no_simplification)
+extern class ConstPointer<T>
+{
+   // ptr actually returns the pointer - not strictly a 'T' - for pointers to smart pointers
+   // Use value or ref to get dereferenced value
+	private var ptr:T;
+
+   @:analyzer(no_simplification)
+	public var value(get,never):T;
+	public var raw(get,never):RawConstPointer<T>;
+
+   @:analyzer(no_simplification)
+   public function get_value() : T;
+
+	public function lt(inOther:Pointer<T>):Bool;
+	public function leq(inOther:Pointer<T>):Bool;
+	public function gt(inOther:Pointer<T>):Bool;
+	public function geq(inOther:Pointer<T>):Bool;
+
+
+
+   public static function fromPointer<T>(inNativePointer:Dynamic) : ConstPointer<T>;
+
+	public function reinterpret<Other>():Pointer<Other>;
+
+   @:analyzer(no_simplification)
+	public function at(inIndex:Int):T;
+
+	public function inc():ConstPointer<T>;
+	public function dec():ConstPointer<T>;
+   @:analyzer(no_simplification)
+	public function postIncVal():T;
+	public function incBy(inT:Int):ConstPointer<T>;
+	public function add(inT:Int):ConstPointer<T>;
+
+}
+

+ 3 - 0
std/cpp/Float32.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract Float32 from Float to Float {}

+ 3 - 0
std/cpp/Float64.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract Float64 from Float to Float {}

+ 22 - 0
std/cpp/Function.hx

@@ -0,0 +1,22 @@
+package cpp;
+
+@:coreType @:structAccess @:include("cpp/Pointer.h")
+@:analyzer(no_simplification)
+extern class Function<T,ABI:cpp.abi.Abi>
+{
+   public function new(d:Dynamic);
+
+   // Actually a function pointer, but can be called using haxe notation
+	public var call(default,null):T;
+
+   public static function getProcAddress<T,ABI:cpp.abi.Abi>(inModule:String, inFunction:String) : Function<T,ABI>;
+   public static function fromStaticFunction<T>(inStaticFunction:T) : Callable<T>;
+
+	public function lt(inOther:Function<T,ABI>):Bool;
+	public function leq(inOther:Function<T,ABI>):Bool;
+	public function gt(inOther:Function<T,ABI>):Bool;
+	public function geq(inOther:Function<T,ABI>):Bool;
+}
+
+
+

+ 3 - 0
std/cpp/Int16.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract Int16 from Int to Int {}

+ 3 - 0
std/cpp/Int32.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract Int32 from Int to Int {}

+ 3 - 0
std/cpp/Int64.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract Int64 from Int to Int {}

+ 3 - 0
std/cpp/Int8.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract Int8 from Int to Int {}

+ 84 - 6
std/cpp/Lib.hx

@@ -21,8 +21,24 @@
  */
 package cpp;
 
+#if macro
+import haxe.macro.Context;
+import haxe.macro.Type;
+import haxe.macro.Expr;
+#else
+
+using cpp.NativeString;
+using cpp.RawConstPointer;
+using cpp.Char;
+
+#end
+
+#if macro
+@:noPackageRestrict
+#end
 class Lib {
 
+   #if !macro
 	/**
 		Load and return a Cpp primitive from a DLL library.
 	**/
@@ -34,13 +50,21 @@ class Lib {
 		#end
 	}
 
-	/**
-		Load and return a Cpp primitive from a DLL library.
-	**/
-	@:extern public static inline function getProcAddress( lib : String, prim : String ) : Dynamic {
-		return untyped __global__.__hxcpp_cast_get_proc_address(lib,prim);
+   @:analyzer(no_simplification)
+	public static function _loadPrime( lib : String, prim : String, signature : String, quietFail = false ) : Dynamic {
+		var factory:Callable< RawConstPointer<Char> -> RawPointer<Object> > =
+               untyped __global__.__hxcpp_cast_get_proc_address(lib, prim + "__prime", quietFail);
+      if (factory!=null)
+      {
+         var func:Dynamic = factory.call(signature.raw());
+         if (func==null && !quietFail)
+            throw '$prim does not have signature $signature';
+         return func;
+      }
+      return null;
 	}
 
+
 	/**
 		Tries to load, and always returns a valid function, but the function may throw
 		if called.
@@ -63,7 +87,24 @@ class Lib {
 
 	public static function rethrow(inExp:Dynamic) { throw inExp; }
 
-	public static function stringReference(inExp:Dynamic) { throw inExp; }
+	public static function stringReference(inBytes:haxe.io.Bytes) : String
+   {
+      var result:String = "";
+      untyped __global__.__hxcpp_string_of_bytes(inBytes.b, result, 0, 0, true);
+      return result;
+   }
+
+	/**
+		Returns bytes referencing the content of a string.
+      Use with extreme caution - changing constant strings will crash.
+      Changing one string can cause others to change unexpectedly.
+      Only really safe if you are using it read-only or if it comes from stringReference above
+	**/
+	public inline static function bytesReference( s : String ) : haxe.io.Bytes {
+      var bytes = new haxe.io.BytesData();
+      untyped bytes.__unsafeStringReference(s);
+		return haxe.io.Bytes.ofData(bytes);
+	}
 
 	/**
 		Print the specified value on the default output.
@@ -94,4 +135,41 @@ class Lib {
 		untyped __global__.__hxcpp_println(v);
 	}
 
+   #else
+   static function codeToType(code:String) : String
+   {
+      switch(code)
+      {
+         case "b" : return "Bool";
+         case "i" : return "Int";
+         case "d" : return "Float";
+         case "f" : return "cpp.Float32";
+         case "s" : return "String";
+         case "o" : return "cpp.Object";
+         case "v" : return "cpp.Void";
+         case "c" : return "cpp.ConstCharStar";
+         default:
+            throw "Unknown signature type :" + code;
+      }
+   }
+   #end
+
+   public static function setFloatFormat(inFormat:String):Void
+   {
+      untyped __global__.__hxcpp_set_float_format(inFormat);
+   }
+
+   public static macro function loadPrime(inModule:String, inName:String, inSig:String,inAllowFail:Bool = false)
+   {
+      var parts = inSig.split("");
+      if (parts.length<1)
+         throw "Invalid function signature " + inSig;
+      var typeString = parts.length==1 ? "Void" : codeToType(parts.shift());
+      for(p in parts)
+         typeString += "->" + codeToType(p);
+      typeString = "cpp.Callable<" + typeString + ">";
+      var expr = 'new $typeString(cpp.Lib._loadPrime("$inModule","$inName","$inSig",$inAllowFail))';
+      return Context.parse( expr, Context.currentPos() );
+   }
+
 }

+ 3 - 2
std/cpp/NativeArray.hx

@@ -1,6 +1,6 @@
 package cpp;
 
-class NativeArray {
+extern class NativeArray {
 
 	public static inline function blit<T>( ioDestArray:Array<T>,
 		inDestElement:Int, inSourceArray:Array<T>,
@@ -8,13 +8,14 @@ class NativeArray {
 	untyped ioDestArray.blit(inDestElement, inSourceArray, inSourceElement, inElementCount);
 	};
 
-	public static inline function zero<T>( ioDestArray:Array<T>, ?inFirst:Int, ?inElements:Int ) {
+	public static inline function zero<T>( ioDestArray:Array<T>, ?inFirst:Int, ?inElements:Int ) : Void {
 		untyped ioDestArray.zero(inFirst, inElements);
 	};
 
 	public static inline function unsafeGet<T>( inDestArray:Array<T>, inIndex:Int) : T {
 		return untyped inDestArray.__unsafe_get(inIndex);
 	}
+
 	public static inline function unsafeSet<T>( ioDestArray:Array<T>, inIndex:Int, inValue:T) : T {
 		return untyped ioDestArray.__unsafe_set(inIndex,inValue);
 	}

+ 15 - 0
std/cpp/NativeString.hx

@@ -0,0 +1,15 @@
+package cpp;
+
+extern class NativeString {
+
+	public static inline function raw( inString:String ) : RawConstPointer<Char> {
+      return untyped inString.__s;
+   }
+	public static inline function c_str( inString:String ) : ConstPointer<Char> {
+		return cpp.ConstPointer.fromPointer(untyped inString.__s);
+   }
+	public static inline function fromPointer(inPtr:ConstPointer<Char> ) : String {
+      return untyped __global__.String(inPtr.ptr);
+   }
+}
+

+ 9 - 6
std/cpp/_std/Xml.hx → std/cpp/NativeXml.hx

@@ -19,10 +19,14 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
+package cpp;
+
 enum XmlType {
 }
 
-@:coreApi class Xml {
+typedef NativeXml = Xml;
+
+class Xml {
 	public static var Element(default,null) : XmlType;
 	public static var PCData(default,null) : XmlType;
 	public static var CData(default,null) : XmlType;
@@ -43,7 +47,7 @@ enum XmlType {
 
 	private static var _parse = cpp.Lib.load("std","parse_xml",2);
 
-	public static function parse( str : String ) : Xml {
+	@:analyzer(ignore) public static function parse( str : String ) : Xml {
 		var x = new Xml();
 		x._children = new Array();
 		var parser = {
@@ -235,7 +239,7 @@ enum XmlType {
 	}
 
 
-	public function elements(): Iterator<Xml> {
+	@:analyzer(ignore) public function elements(): Iterator<Xml> {
 		if( _children == null )
 			throw "bad nodetype";
       var children = _children;
@@ -268,7 +272,7 @@ enum XmlType {
 		}
 	}
 
-	public function elementsNamed( name : String ) : Iterator<Xml> {
+	@:analyzer(ignore) public function elementsNamed( name : String ) : Iterator<Xml> {
 		if( _children == null )
 			throw "bad nodetype";
       var children = _children;
@@ -417,5 +421,4 @@ enum XmlType {
 		__global__.__hxcpp_enum_force(Document , "document", 6);
 	}
 
-}
-
+}

+ 16 - 0
std/cpp/Object.hx

@@ -0,0 +1,16 @@
+package cpp;
+
+@:native("::hx::Object *")
+extern class HxObjectPtr
+{
+   @:native("hx::DynamicPtr")
+   static function fromDynamic(x:Dynamic):Object;
+   @:native("Dynamic")
+   static function toDynamic(x:Object):Dynamic;
+}
+
+@:extern
+abstract Object(HxObjectPtr) {
+	@:from public inline static function from(x:Dynamic):Object return HxObjectPtr.fromDynamic(x);
+	@:to public inline static function to(inVal:HxObjectPtr):Dynamic return HxObjectPtr.toDynamic(inVal);
+}

+ 29 - 9
std/cpp/Pointer.hx

@@ -1,17 +1,37 @@
 package cpp;
 
-
-extern class Pointer<T> implements ArrayAccess<T>
+@:coreType
+@:analyzer(no_simplification)
+extern class Pointer<T> extends ConstPointer<T> implements ArrayAccess<T>
 {
-	public static function fromArray<T>(array:Array<T>, inIdx:Int):Pointer<T>;
+   @:analyzer(no_simplification)
+	public var ref(get,set):T;
+
+   @:analyzer(no_simplification)
+   public function get_ref() : T;
+   @:analyzer(no_simplification)
+   public function set_ref(t:T) : T;
+
+
+   public static function fromHandle<T>(inHandle:Dynamic,?inKind:String) : Pointer<T>;
+
+   public static function fromPointer<T>(inNativePointer:Dynamic) : Pointer<T>;
+
+   public static function addressOf<T>(inVariable:T) : Pointer<T>;
+
+	public static function arrayElem<T>(array:Array<T>, inElem:Int):Pointer<T>;
+
+   public function get_raw() : RawPointer<T>;
 
-	public function inc():Void;
-	public function dec():Void;
-	public function add(inT:Int):Void;
+	override public function inc():Pointer<T>;
+	override public function dec():Pointer<T>;
+	override public function incBy(inT:Int):Pointer<T>;
+	override public function add(inT:Int):Pointer<T>;
 
-   // ptr actually returns the pointer, so the ->member sysntax will work
-   // Use [0] for a reference to the item
-	public function ptr():T;
+   @:analyzer(no_simplification)
+	public function postIncRef():T;
 
+	public function destroy():Void;
+	public function destroyArray():Void;
 }
 

+ 6 - 0
std/cpp/RawConstPointer.hx

@@ -0,0 +1,6 @@
+package cpp;
+
+@:unreflective
+extern class RawConstPointer<T>
+{
+}

+ 6 - 0
std/cpp/RawPointer.hx

@@ -0,0 +1,6 @@
+package cpp;
+
+@:unreflective
+extern class RawPointer<T> extends RawConstPointer<T>
+{
+}

+ 3 - 0
std/cpp/UInt16.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract UInt16 from Int to Int {}

+ 3 - 0
std/cpp/UInt32.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract UInt32 from Int to Int {}

+ 3 - 0
std/cpp/UInt64.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract UInt64 from Int to Int {}

+ 3 - 0
std/cpp/UInt8.hx

@@ -0,0 +1,3 @@
+package cpp;
+
+@:coreType @:notNull @:runtimeValue abstract UInt8 from Int to Int {}

+ 5 - 0
std/cpp/Void.hx

@@ -0,0 +1,5 @@
+package cpp;
+
+@:native("void")
+extern class Void { }
+

+ 0 - 1
std/cpp/_std/Date.hx

@@ -78,7 +78,6 @@
 			default:
 				throw "Invalid date format : " + s;
 		}
-		return null;
 	}
 }
 

+ 11 - 11
std/cpp/_std/Reflect.hx

@@ -26,26 +26,26 @@
 	}
 
 	public static function field( o : Dynamic, field : String ) : Dynamic untyped {
-		return (o==null) ? null : o.__Field(field,false);
+		return (o==null) ? null : o.__Field(field,untyped __cpp__("hx::paccNever") );
 	}
 
-	public inline static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
+	public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
 		if (o!=null)
-			o.__SetField(field,value,false);
+			o.__SetField(field,value,untyped __cpp__("hx::paccNever") );
 	}
 
-	public static inline function getProperty( o : Dynamic, field : String ) : Dynamic {
-		return (o==null) ? null : o.__Field(field,true);
+	public static function getProperty( o : Dynamic, field : String ) : Dynamic {
+		return (o==null) ? null : o.__Field(field,untyped __cpp__("hx::paccAlways") );
 	}
 
-	public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void {
+	public static function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void {
 		if (o!=null)
-			o.__SetField(field,value,true);
+			o.__SetField(field,value,untyped __cpp__("hx::paccAlways") );
 	}
 
-	public static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic untyped {
+	public static function callMethod( o : Dynamic, func : haxe.Constraints.Function, args : Array<Dynamic> ) : Dynamic untyped {
 			if (func!=null && func.__GetType()==__global__.vtString)
-				func = o.__Field(func,true);
+				func = o.__Field(func,untyped __cpp__("hx::paccDynamic"));
 			untyped func.__SetThis(o);
          return untyped func.__Run(args);
 	}
@@ -62,7 +62,7 @@
 	}
 
 	public static function compare<T>( a : T, b : T ) : Int {
-		return ( a == b ) ? 0 : (((cast a) > (cast b)) ? 1 : -1);
+		return ( a == b ) ? 0 : (((a:Dynamic) > (b:Dynamic)) ? 1 : -1);
 	}
 
 	public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool {
@@ -93,7 +93,7 @@
 		if (o==null) return null;
 		if(untyped o.__GetType()==__global__.vtString ) return o;
 		if(untyped o.__GetType()==__global__.vtArray )
-			return untyped o.__Field("copy",true)();
+			return untyped o.__Field("copy", untyped __cpp__("hx::paccDynamic"))();
 		var o2 : Dynamic = {};
 		for( f in Reflect.fields(o) )
 			Reflect.setField(o2,f,Reflect.field(o,f));

+ 4 - 3
std/cpp/_std/Sys.hx

@@ -85,14 +85,14 @@
 		var ok = true;
 		for( i in 0...arg.length )
 			switch( arg.charCodeAt(i) ) {
-			case 32, 34: // [space] "
+			case ' '.code, '\t'.code, '"'.code, '&'.code, '|'.code, '<'.code, '>'.code, '#'.code , ';'.code, '*'.code, '?'.code, '('.code, ')'.code, '{'.code, '}'.code, '$'.code:
 				ok = false;
 			case 0, 13, 10: // [eof] [cr] [lf]
 				arg = arg.substr(0,i);
 			}
 		if( ok )
 			return arg;
-		return '"'+arg.split('"').join('\\"')+'"';
+		return '"'+arg.split('\\').join("\\\\").split('"').join('\\"')+'"';
 	}
 
 	public static function command( cmd : String, ?args : Array<String> ) : Int {
@@ -101,6 +101,7 @@
 			for( a in args )
 				cmd += " "+escapeArgument(a);
 		}
+		if (systemName() == "Windows") cmd = '"$cmd"';
 		return sys_command(cmd);
 	}
 
@@ -120,7 +121,7 @@
 		return new String(sys_exe_path());
 	}
 
-	public static function environment() : haxe.ds.StringMap<String> {
+	public static function environment() : Map<String,String> {
 		var vars:Array<String> = sys_env();
 		var result = new haxe.ds.StringMap<String>();
 		var i = 0;

+ 3 - 2
std/cpp/_std/Type.hx

@@ -148,8 +148,9 @@ enum ValueType {
       for(name in names)
       {
          try {
-            var result:T = untyped e.mConstructEnum(name,null);
-            enums.push( result );
+            var result:T = untyped e.ConstructEnum(name,null);
+            if (result!=null)
+               enums.push( result );
          } catch ( invalidArgCount:String) {
          }
       }

+ 139 - 0
std/cpp/_std/haxe/Int64.hx2

@@ -0,0 +1,139 @@
+/*
+ * Copyright (C)2005-2012 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package haxe;
+
+
+
+@:native("cpp::Struct< cpp::Int64 >")
+extern class Int64Struct { }
+
+abstract Int64( Int64Struct )
+{
+   public function toString() : String {
+		return untyped __cpp__("String( (cpp::Int64)({0}) )", this);
+  }
+
+	public static inline function make( high : Int, low : Int ) : Int64 {
+      return untyped __cpp__("cpp::Struct< cpp::Int64 >(( ( (cpp::Int64)((unsigned int){0}) ) << 32 ) | ((unsigned int){1}))",high, low);
+	}
+
+	public static inline function ofInt( x : Int ) : Int64 {
+		return untyped __cpp__("((cpp::Int64)({0}))", x);
+	}
+
+	public static function toInt( x : Int64 ) : Int {
+		var high = getHigh(x);
+		if( high != 0 ) {
+			if( high < 0 )
+				return -toInt(neg(x));
+			throw "Overflow";
+		}
+		return getLow(x);
+	}
+
+	public static inline function neg( a : Int64 ) : Int64 {
+		return untyped __cpp__("(-({0}))",a);
+	}
+
+
+	public static inline function getLow( x : Int64 ) : Int {
+		return untyped __cpp__("(int)(({0})&0xffffffff)",x);
+	}
+
+	public static function getHigh( x : Int64 ) : Int {
+		return  untyped __cpp__("((cpp::Int64)({0}))>>32",x);
+	}
+
+	public static inline function add( a : Int64, b : Int64 ) : Int64 {
+		return untyped __cpp__("(({0}) + ({1}))", a, b);
+	}
+
+	public static function sub( a : Int64, b : Int64 ) : Int64 {
+		return untyped __cpp__("(({0}) - ({1}))", a, b);
+	}
+
+	public static function mul( a : Int64, b : Int64 ) : Int64 {
+		return untyped __cpp__("(({0}) * ({1}))", a, b);
+	}
+
+	public static function div( a : Int64, b : Int64 ) : Int64 {
+		if (untyped __cpp__("(({0}) == 0)",b) )
+			throw "divide by zero";
+		return untyped __cpp__("(({0}) / ({1}))", a, b);
+	}
+
+	public static function mod( a : Int64, b : Int64 ) : Int64 {
+		if (untyped __cpp__("(({0}) == 0)",b) )
+			throw "divide by zero";
+		return untyped __cpp__("(({0}) % ({1}))", a, b);
+	}
+
+	public static inline function shl( a : Int64, b : Int ) : Int64 {
+		return untyped __cpp__("(({0}) << ({1}))", a, b);
+	}
+
+	public static inline function shr( a : Int64, b : Int ) : Int64 {
+		return untyped __cpp__("(({0}) << ({1}))", a, b);
+	}
+
+	public static inline function ushr( a : Int64, b : Int ) : Int64 {
+		return untyped __cpp__("(((cpp::UInt64)({0})) >> ({1}))", a, b);
+	}
+
+	public static inline function and( a : Int64, b : Int64 ) : Int64 {
+		return untyped __cpp__("(({0}) & ({1}))", a, b);
+	}
+
+	public static inline function or( a : Int64, b : Int64 ) : Int64 {
+		return untyped __cpp__("(({0}) | ({1}))", a, b);
+	}
+
+	public static inline function xor( a : Int64, b : Int64 ) : Int64 {
+		return untyped __cpp__("(({0}) ^ ({1}))", a, b);
+	}
+
+
+	public static inline function isNeg( a : Int64 ) : Bool {
+		return untyped __cpp__("(({0}) < 0)", a);
+	}
+
+	public static inline function isZero( a : Int64 ) : Bool {
+		return untyped __cpp__("(({0}) == 0)", a);
+	}
+
+	public static function compare( a : Int64, b : Int64 ) : Int {
+		return untyped __cpp__("( ({0}) < ({1}) ? -1 : ({0})==({1}) ? 0 : 1)", a, b, a, b);
+	}
+
+	/**
+		Compare two Int64 in unsigned mode.
+	**/
+	public static function ucompare( a : Int64, b : Int64 ) : Int {
+		return untyped __cpp__("( (cpp::UInt64)({0}) < (cpp::UInt64)({1}) ? -1 : ({0})==({1}) ? 0 : 1)", a, b, a, b);
+	}
+
+	public static function toStr( a : Int64 ) : String {
+		return untyped __cpp__("String( (cpp::Int64)({0}) )", a);
+	}
+
+}
+

+ 21 - 18
std/cpp/_std/haxe/ds/IntMap.hx

@@ -21,13 +21,28 @@
  */
 package haxe.ds;
 
-@:coreApi class IntMap<T> implements Map.IMap<Int,T> {
+@:headerClassCode("
+  inline void set(int key, ::null value) { __int_hash_set(h,key,value); }
+  inline void set(int key, bool value) { __int_hash_set(h,key,value); }
+  inline void set(int key, char value) { __int_hash_set_int(h,key,value); }
+  inline void set(int key, unsigned char value) { __int_hash_set_int(h,key,value); }
+  inline void set(int key, signed char value) { __int_hash_set_int(h,key,value); }
+  inline void set(int key, short value) { __int_hash_set_int(h,key,value); }
+  inline void set(int key, unsigned short value) { __int_hash_set_int(h,key,value); }
+  inline void set(int key, int value) { __int_hash_set_int(h,key,value); }
+  inline void set(int key, unsigned int value) { __int_hash_set_int(h,key,value); }
+  inline void set(int key, float value) { __int_hash_set_float(h,key,value); }
+  inline void set(int key, double value) { __int_hash_set_float(h,key,value); }
+  inline void set(int key, ::String value) { __int_hash_set_string(h,key,value); }
 
-	private var h : Dynamic;
+  template<typename VALUE>
+  inline Void set(Dynamic &key, const VALUE &value) { set( (int)key, value ); return null(); }
+")
+@:coreApi class IntMap<T> implements haxe.Constraints.IMap<Int,T> {
 
-	public function new() : Void {
-		h = untyped __global__.__int_hash_create();
-	}
+	@:ifFeature("haxe.ds.IntMap.*") private var h : Dynamic;
+
+	public function new() : Void { }
 
 	public function set( key : Int, value : T ) : Void {
 		untyped __global__.__int_hash_set(h,key,value);
@@ -56,18 +71,6 @@ package haxe.ds;
 	}
 
 	public function toString() : String {
-		var s = new StringBuf();
-		s.add("{");
-		var it = keys();
-		for( i in it ) {
-			s.add(i);
-			s.add(" => ");
-			s.add(Std.string(get(i)));
-			if( it.hasNext() )
-				s.add(", ");
-		}
-		s.add("}");
-		return s.toString();
+		return untyped __global__.__int_hash_to_string(h);
 	}
-
 }

+ 27 - 30
std/cpp/_std/haxe/ds/ObjectMap.hx

@@ -21,56 +21,53 @@
  */
 package haxe.ds;
 
+@:headerClassCode("
+  inline void set(Dynamic key, ::null value) { __object_hash_set(h,key,value); }
+  inline void set(Dynamic key, bool value) { __object_hash_set(h,key,value); }
+  inline void set(Dynamic key, char value) { __object_hash_set_int(h,key,value); }
+  inline void set(Dynamic key, unsigned char value) { __object_hash_set_int(h,key,value); }
+  inline void set(Dynamic key, signed char value) { __object_hash_set_int(h,key,value); }
+  inline void set(Dynamic key, short value) { __object_hash_set_int(h,key,value); }
+  inline void set(Dynamic key, unsigned short value) { __object_hash_set_int(h,key,value); }
+  inline void set(Dynamic key, int value) { __object_hash_set_int(h,key,value); }
+  inline void set(Dynamic key, unsigned int value) { __object_hash_set_int(h,key,value); }
+  inline void set(Dynamic key, float value) { __object_hash_set_float(h,key,value); }
+  inline void set(Dynamic key, double value) { __object_hash_set_float(h,key,value); }
+  inline void set(Dynamic key, ::String value) { __object_hash_set_string(h,key,value); }
+")
 @:coreApi
-class ObjectMap<K:{},V> implements Map.IMap<K,V> {
-	private var __Internal : IntMap<V>;
-	private var __KeyRefs : IntMap<K>;
+class ObjectMap<K:{},V> implements haxe.Constraints.IMap<K,V> {
+	private var h : Dynamic;
 
-	public function new() : Void {
-		__Internal = new IntMap<V>();
-		__KeyRefs = new IntMap<K>();
-	}
+	public function new() : Void { }
 
 	public function set( key : K, value : V ) : Void {
-		var id = untyped __global__.__hxcpp_obj_id(key);
-		__Internal.set( id, value );
-		__KeyRefs.set( id, key );
+		untyped __global__.__object_hash_set(h,key,value);
 	}
 
 	public function get( key : K ) : Null<V> {
-		return __Internal.get( untyped __global__.__hxcpp_obj_id(key) );
+		return untyped __global__.__object_hash_get(h,key);
 	}
 
-	public inline function exists( key : K ) : Bool {
-		return __Internal.exists( untyped __global__.__hxcpp_obj_id(key) );
+	public function exists( key : K ) : Bool {
+		return untyped __global__.__object_hash_exists(h,key);
 	}
 
 	public function remove( key : K ) : Bool {
-		var id = untyped __global__.__hxcpp_obj_id(key);
-		__Internal.remove(id);
-		return __KeyRefs.remove(id);
+		return untyped __global__.__object_hash_remove(h,key);
 	}
 
 	public function keys() : Iterator<K> {
-		return __KeyRefs.iterator();
+		var a:Array<K> = untyped __global__.__object_hash_keys(h);
+		return a.iterator();
 	}
 
 	public function iterator() : Iterator<V> {
-		return __Internal.iterator();
+		var a:Array<Dynamic> = untyped __global__.__object_hash_values(h);
+		return a.iterator();
 	}
 
 	public function toString() : String {
-		var s = new StringBuf();
-		s.add("{");
-		var it = __Internal.keys();
-		for( i in it ) {
-			s.add(Std.string(__KeyRefs.get(i)));
-			s.add(" => ");
-			s.add(Std.string(__Internal.get(i)));
-			if( it.hasNext() )
-				s.add(", ");
-		}
-		s.add("}");
-		return s.toString();
+		return untyped __global__.__object_hash_to_string(h);
 	}
 }

+ 28 - 31
std/cpp/_std/haxe/ds/StringMap.hx

@@ -21,58 +21,55 @@
  */
 package haxe.ds;
 
-@:coreApi class StringMap<T> implements Map.IMap<String,T> {
-	private var __Internal : Dynamic;
+@:headerClassCode("
+  inline void set(String key, ::null value) { __string_hash_set(h,key,value); }
+  inline void set(String key, bool value) { __string_hash_set(h,key,value); }
+  inline void set(String key, char value) { __string_hash_set_int(h,key,value); }
+  inline void set(String key, unsigned char value) { __string_hash_set_int(h,key,value); }
+  inline void set(String key, signed char value) { __string_hash_set_int(h,key,value); }
+  inline void set(String key, short value) { __string_hash_set_int(h,key,value); }
+  inline void set(String key, unsigned short value) { __string_hash_set_int(h,key,value); }
+  inline void set(String key, int value) { __string_hash_set_int(h,key,value); }
+  inline void set(String key, unsigned int value) { __string_hash_set_int(h,key,value); }
+  inline void set(String key, float value) { __string_hash_set_float(h,key,value); }
+  inline void set(String key, double value) { __string_hash_set_float(h,key,value); }
+  inline void set(String key, ::String value) { __string_hash_set_string(h,key,value); }
 
-	public function new() : Void {
-		__Internal = {};
-	}
+  template<typename VALUE>
+  inline Void set(Dynamic &key, const VALUE &value) { set( (String)key, value ); return null(); }
+")
+@:coreApi class StringMap<T> implements haxe.Constraints.IMap<String,T> {
+	private var h : Dynamic;
+
+	public function new() : Void { }
 
 	public function set( key : String, value : T ) : Void {
-		untyped __Internal.__SetField(key,value,true);
+		untyped __global__.__string_hash_set(h,key,value);
 	}
 
 	public function get( key : String ) : Null<T> {
-		return untyped __Internal.__Field(key,true);
+		return untyped __global__.__string_hash_get(h,key);
 	}
 
 	public function exists( key : String ) : Bool {
-		return untyped __Internal.__HasField(key);
+		return untyped __global__.__string_hash_exists(h,key);
 	}
 
 	public function remove( key : String ) : Bool {
-		return untyped __global__.__hxcpp_anon_remove(__Internal,key);
+		return untyped __global__.__string_hash_remove(h,key);
 	}
 
 	public function keys() : Iterator<String> {
-		var a:Array<String> = [];
-		untyped __Internal.__GetFields(a);
+		var a:Array<String> = untyped __global__.__string_hash_keys(h);
 		return a.iterator();
 	}
 
 	public function iterator() : Iterator<T> {
-		var a:Array<String> = [];
-		untyped __Internal.__GetFields(a);
-		var it = a.iterator();
-		var me = this;
-		return untyped {
-			hasNext : function() { return it.hasNext(); },
-			next : function() { return me.__Internal.__Field(it.next(),true); }
-		};
+		var a:Array<Dynamic> = untyped __global__.__string_hash_values(h);
+		return a.iterator();
 	}
 
 	public function toString() : String {
-		var s = new StringBuf();
-		s.add("{");
-		var it = keys();
-		for( i in it ) {
-			s.add(i);
-			s.add(" => ");
-			s.add(Std.string(get(i)));
-			if( it.hasNext() )
-				s.add(", ");
-		}
-		s.add("}");
-		return s.toString();
+		return untyped __global__.__string_hash_to_string(h);
 	}
 }

+ 73 - 0
std/cpp/_std/haxe/ds/WeakMap.hx

@@ -0,0 +1,73 @@
+/*
+ * Copyright (C)2005-2013 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package haxe.ds;
+
+@:headerClassCode("
+  inline void set(Dynamic key, ::null value) { __object_hash_set(h,key,value,true); }
+  inline void set(Dynamic key, bool value) { __object_hash_set(h,key,value,true); }
+  inline void set(Dynamic key, char value) { __object_hash_set_int(h,key,value,true); }
+  inline void set(Dynamic key, unsigned char value) { __object_hash_set_int(h,key,value,true); }
+  inline void set(Dynamic key, signed char value) { __object_hash_set_int(h,key,value,true); }
+  inline void set(Dynamic key, short value) { __object_hash_set_int(h,key,value,true); }
+  inline void set(Dynamic key, unsigned short value) { __object_hash_set_int(h,key,value,true); }
+  inline void set(Dynamic key, int value) { __object_hash_set_int(h,key,value,true); }
+  inline void set(Dynamic key, unsigned int value) { __object_hash_set_int(h,key,value,true); }
+  inline void set(Dynamic key, float value) { __object_hash_set_float(h,key,value,true); }
+  inline void set(Dynamic key, double value) { __object_hash_set_float(h,key,value,true); }
+  inline void set(Dynamic key, ::String value) { __object_hash_set_string(h,key,value,true); }
+")
+@:coreApi
+class WeakMap<K:{},V> implements haxe.Constraints.IMap<K,V> {
+	private var h : Dynamic;
+
+	public function new() : Void { }
+
+	public function set( key : K, value : V ) : Void {
+		untyped __global__.__object_hash_set(h,key,value,true);
+	}
+
+	public function get( key : K ) : Null<V> {
+		return untyped __global__.__object_hash_get(h,key);
+	}
+
+	public function exists( key : K ) : Bool {
+		return untyped __global__.__object_hash_exists(h,key);
+	}
+
+	public function remove( key : K ) : Bool {
+		return untyped __global__.__object_hash_remove(h,key);
+	}
+
+	public function keys() : Iterator<K> {
+		var a:Array<K> = untyped __global__.__object_hash_keys(h);
+		return a.iterator();
+	}
+
+	public function iterator() : Iterator<V> {
+		var a:Array<Dynamic> = untyped __global__.__object_hash_values(h);
+		return a.iterator();
+	}
+
+	public function toString() : String {
+		return untyped __global__.__object_hash_to_string(h);
+	}
+}

+ 12 - 3
std/cpp/_std/sys/FileSystem.hx

@@ -30,7 +30,7 @@ private enum FileKind {
 @:coreApi
 class FileSystem {
 
-	public static inline function exists( path : String ) : Bool {
+	public static function exists( path : String ) : Bool {
 		return sys_exists(haxe.io.Path.removeTrailingSlashes(path));
 	}
 
@@ -53,6 +53,11 @@ class FileSystem {
 		return new String(file_full_path(relPath));
 	}
 
+	public static function absolutePath ( relPath : String ) : String {
+		if (haxe.io.Path.isAbsolute(relPath)) return relPath;
+		return haxe.io.Path.join([Sys.getCwd(), relPath]);
+	}
+
 	static function kind( path : String ) : FileKind {
 		var k:String = sys_file_type(haxe.io.Path.removeTrailingSlashes(path));
 		return switch(k) {
@@ -68,8 +73,12 @@ class FileSystem {
 
 	public static function createDirectory( path : String ) : Void {
 		var path = haxe.io.Path.addTrailingSlash(path);
-		var parts = [while ((path = haxe.io.Path.directory(path)) != "") path];
-		parts.reverse();
+		var _p = null;
+		var parts = [];
+		while (path != (_p = haxe.io.Path.directory(path))) {
+			parts.unshift(path);
+			path = _p;
+		}
 		for (part in parts) {
 			if (part.charCodeAt(part.length - 1) != ":".code && !exists(part) && sys_create_dir( part, 493 )==null)
 				throw "Could not create directory:" + part;

+ 3 - 1
std/cpp/_std/sys/db/Mysql.hx

@@ -135,7 +135,9 @@ private class MysqlConnection implements sys.db.Connection {
 		if (v == null) {
 			s.add(v);
       }
-      else {
+      else if (Std.is(v,Bool)) {
+				s.add( v ? 1 : 0 );
+			} else {
 			var t:Int = untyped v.__GetType();
 			if( t == 0xff )
 				s.add(v);

+ 3 - 1
std/cpp/_std/sys/db/Sqlite.hx

@@ -55,7 +55,9 @@ private class SqliteConnection implements Connection {
 		if (v == null) {
 			s.add(v);
       }
-      else {
+      else if (Std.is(v,Bool)) {
+				s.add( v ? 1 : 0 );
+			} else {
 			var t:Int = untyped v.__GetType();
 			if( t == 0xff )
 				s.add(v);

+ 4 - 0
std/cpp/abi/Abi.hx

@@ -0,0 +1,4 @@
+package cpp.abi;
+
+// Base case, for calling conventions - means "use default"
+extern class Abi { }

+ 4 - 0
std/cpp/abi/CDecl.hx

@@ -0,0 +1,4 @@
+package cpp.abi;
+
+@:abi("__cdecl")
+extern class CDecl extends Abi { }

+ 4 - 0
std/cpp/abi/FastCall.hx

@@ -0,0 +1,4 @@
+package cpp.abi;
+
+@:abi("__fastcall")
+extern class FastCall extends Abi { }

+ 4 - 0
std/cpp/abi/StdCall.hx

@@ -0,0 +1,4 @@
+package cpp.abi;
+
+@:abi("__stdcall")
+extern class StdCall extends Abi { }

+ 4 - 0
std/cpp/abi/ThisCall.hx

@@ -0,0 +1,4 @@
+package cpp.abi;
+
+@:abi("__thiscall")
+extern class ThisCall extends Abi { }

+ 4 - 0
std/cpp/abi/Winapi.hx

@@ -0,0 +1,4 @@
+package cpp.abi;
+
+@:abi("__stdcall")
+extern class Winapi extends Abi { }

+ 28 - 0
std/cpp/cppia/Host.hx

@@ -0,0 +1,28 @@
+package cpp.cppia;
+
+
+@:build(cpp.cppia.HostClasses.include())
+class Host
+{
+   public static function run(source:String)
+   {
+      untyped __global__.__scriptable_load_cppia(source);
+   }
+
+   public static function main()
+   {
+      var script = Sys.args()[0];
+      #if (!scriptable && !doc_gen)
+      #error "Please define scriptable to use cppia"
+      #end
+      if (script==null)
+      {
+         Sys.println("Usage : Cppia scriptname");
+      }
+      else
+      {
+         var source = sys.io.File.getContent(script);
+         run(source);
+      }
+   }
+}

Някои файлове не бяха показани, защото твърде много файлове са промени