Browse Source

Merge remote-tracking branch 'origin/development' into mono-fix

frabbit 7 years ago
parent
commit
227f35ee2a
100 changed files with 3090 additions and 4941 deletions
  1. 6 0
      .gitignore
  2. 75 112
      .travis.yml
  3. 13 0
      .vscode/settings.json
  4. 1 1
      CONTRIBUTING.md
  5. 73 31
      Makefile
  6. 31 0
      Makefile.win
  7. 11 11
      README.md
  8. 28 18
      appveyor.yml
  9. 114 4
      extra/CHANGES.txt
  10. 21 15
      extra/ImportAll.hx
  11. 0 6
      extra/all.hxml
  12. 16 0
      extra/build-haxesetup.xml
  13. 1 1
      extra/choco/haxe.nuspec
  14. 60 0
      extra/doc.hxml
  15. 1 1
      extra/haxelib_src
  16. BIN
      extra/mac-installer/installer-structure.pkg
  17. 13 0
      extra/mac-installer/scripts/haxe-postinstall.sh
  18. 8 0
      extra/mac-installer/scripts/haxe-preinstall.sh
  19. 18 0
      extra/mac-installer/scripts/install.sh
  20. 19 0
      extra/mac-installer/scripts/neko-postinstall.sh
  21. 3 0
      extra/mac-installer/scripts/neko-preinstall.sh
  22. 10 24
      extra/release-checklist.txt
  23. 1 1
      libs
  24. 24 0
      opam
  25. 10 317
      src/codegen/codegen.ml
  26. 13 12
      src/codegen/dotnet.ml
  27. 0 0
      src/codegen/gencommon/abstractImplementationFix.ml
  28. 0 0
      src/codegen/gencommon/arrayDeclSynf.ml
  29. 3 3
      src/codegen/gencommon/castDetect.ml
  30. 0 0
      src/codegen/gencommon/classInstance.ml
  31. 9 8
      src/codegen/gencommon/closuresToClass.ml
  32. 0 0
      src/codegen/gencommon/dynamicFieldAccess.ml
  33. 7 6
      src/codegen/gencommon/dynamicOperators.ml
  34. 6 5
      src/codegen/gencommon/enumToClass.ml
  35. 14 14
      src/codegen/gencommon/enumToClass2.ml
  36. 1 1
      src/codegen/gencommon/expressionUnwrap.ml
  37. 0 0
      src/codegen/gencommon/filterClosures.ml
  38. 2 2
      src/codegen/gencommon/fixOverrides.ml
  39. 13 13
      src/codegen/gencommon/gencommon.ml
  40. 1 1
      src/codegen/gencommon/hardNullableSynf.ml
  41. 3 2
      src/codegen/gencommon/initFunction.ml
  42. 0 0
      src/codegen/gencommon/intDivisionSynf.ml
  43. 0 0
      src/codegen/gencommon/interfaceProps.ml
  44. 0 0
      src/codegen/gencommon/interfaceVarsDeleteModf.ml
  45. 1 1
      src/codegen/gencommon/normalize.ml
  46. 0 0
      src/codegen/gencommon/objectDeclMap.ml
  47. 2 2
      src/codegen/gencommon/overloadingConstructor.ml
  48. 6 5
      src/codegen/gencommon/realTypeParams.ml
  49. 18 17
      src/codegen/gencommon/reflectionCFs.ml
  50. 0 0
      src/codegen/gencommon/renameTypeParameters.ml
  51. 0 0
      src/codegen/gencommon/setHXGen.ml
  52. 1 1
      src/codegen/gencommon/switchToIf.ml
  53. 0 0
      src/codegen/gencommon/tArrayTransform.ml
  54. 0 0
      src/codegen/gencommon/unnecessaryCastsRemoval.ml
  55. 1 1
      src/codegen/gencommon/unreachableCodeEliminationSynf.ml
  56. 10 8
      src/codegen/genxml.ml
  57. 6 6
      src/codegen/java.ml
  58. 2 2
      src/codegen/overloads.ml
  59. 3 3
      src/codegen/swfLoader.ml
  60. 4 3
      src/compiler/displayOutput.ml
  61. 40 67
      src/compiler/main.ml
  62. 29 113
      src/compiler/server.ml
  63. 67 426
      src/context/common.ml
  64. 0 182
      src/context/display.ml
  65. 182 0
      src/context/displayToplevel.ml
  66. 0 0
      src/context/displayTypes.ml
  67. 0 0
      src/context/sourcemaps.ml
  68. 27 12
      src/context/typecore.ml
  69. 1 1
      src/core/abstract.ml
  70. 32 6
      src/core/ast.ml
  71. 291 0
      src/core/define.ml
  72. 0 0
      src/core/error.ml
  73. 0 0
      src/core/globals.ml
  74. 0 0
      src/core/json.ml
  75. 9 13
      src/core/meta.ml
  76. 74 0
      src/core/numeric.ml
  77. 47 1
      src/core/path.ml
  78. 388 0
      src/core/texpr.ml
  79. 167 0
      src/core/timer.ml
  80. 120 246
      src/core/type.ml
  81. 1 1
      src/filters/capturedVars.ml
  82. 2 2
      src/filters/defaultArguments.ml
  83. 6 118
      src/filters/filters.ml
  84. 70 0
      src/filters/filtersCommon.ml
  85. 209 0
      src/filters/jsExceptions.ml
  86. 4 4
      src/filters/tryCatchWrapper.ml
  87. 36 0
      src/filters/varLazifier.ml
  88. 4 4
      src/generators/genas3.ml
  89. 31 27
      src/generators/gencpp.ml
  90. 16 13
      src/generators/gencs.ml
  91. 55 66
      src/generators/genhl.ml
  92. 7 7
      src/generators/genjava.ml
  93. 197 217
      src/generators/genjs.ml
  94. 102 90
      src/generators/genlua.ml
  95. 4 4
      src/generators/genneko.ml
  96. 0 2437
      src/generators/genphp.ml
  97. 164 199
      src/generators/genphp7.ml
  98. 18 11
      src/generators/genpy.ml
  99. 2 2
      src/generators/genswf.ml
  100. 5 14
      src/generators/genswf9.ml

+ 6 - 0
.gitignore

@@ -9,6 +9,7 @@
 *.exe
 .*.swp
 /out
+/installer
 
 /extra/hxclasses
 /extra/*.swf
@@ -18,6 +19,7 @@
 /extra/deploy_key
 /extra/*_sec.gpg
 /extra/*_ssh
+/extra/doc/
 
 /src/version.ml
 /haxe
@@ -68,6 +70,7 @@ build.bat
 /.vscode
 tests/unit/compile.php.hxml
 /extra/*.xml
+!/extra/build-haxesetup.xml
 tests/optimization/testopt.js
 tests/misc/pythonImport/native_python/__pycache__
 tests/unit/unit.py
@@ -107,3 +110,6 @@ tests/server/test/cases/
 tests/server/test.js
 
 tests/unit/pypy3-*
+tmp.tmp
+
+dev-display.hxml

+ 75 - 112
.travis.yml

@@ -22,38 +22,17 @@ before_cache:
 
 env:
   global:
+    - OPAMYES=1
     # make variables
     - ADD_REVISION=1
     # nightly builds submit
     - secure: "UoGjYvQqt66GWmeLC4Pih1iue5AufVgW8XQOd2Bx839NN/2mQQ9bD1HuONJe+taWBJ+PHInkAjYROYYaiCQUA7B1SXs3oQD7Og6arVcR7kY7XOdAQ2t8ZkxJHTnuYGWW/2gNFBESv+3H17bkXG4rzaSn2LV5PJLOxSjw0ziBUMY="
     - secure: "ugpxt+zeYiAiMYKLK96f5TLSxbQAtmDWiumdwaLHl88fIUeefxJJPIF1Xm0AHeYEJE7sD8dLE1dMbRSzOpXFfTmJoQZv19Wjv+2N5B+DaabKjGj1nZG7q3blGa3nUYzWVfFNFiIpM9c5fvW8yiUFzacZE5itEY8+lZQeGsNh+WQ="
-    # SauceLabs
-    # - secure: SjyKefmjUEXi0IKHGGpcbLAajU0mLHONg8aA8LoY7Q9nAkSN6Aql+fzS38Boq7w1jWn+2FOpr+4jy0l6wVd/bftsF+huFfYpFJmdh8BlKmE0K71zZAral0H1c7YxkuQpPiJCIFGXqtkvev7SWTy0z31u7kuuQeEyW27boXe5cDA=
-    # - secure: sUvWUjCyPuWht4seNa4f2VG9DkvXkhZyLZfjJO9TUAHB2JndS16E2j/qrvKEjycyH6w8tU/B9vnjDRvvGrYXxEXcBEwsJVfkorFnRl9uwGCGIYrzjMhssEl3fMYZK7P304f+gAp5ULrDBX2gIaKeSa8lUNRtz2PsZOieE4kMdhk=
-    # Bintray
-    # - secure: "ETbwZaeRq8wIVZVyUk1IsNctYVuQa/U2biRkF9pQkz3MEXpaneynclVzNjm8rnm8JqfKcjUDUvQJBP1KYrJYq3tAJFhl31YUnS0FsF3sgLIcnHkhbRA24xJdIlCwHP6QUPoiyPbkec43NRwrF0071KOMD51vgUToXRtAe3o/15g="
-    # - secure: "Fcrrge2f4jFYDOopig2rwkQvgJw6Ra8UK6OwTVk08wecytzVaOJK1TcB22PSvZ+h0ZLJs34T+pXHFjlNuSWm4+CwGSvnltRD1/svjS8zOqK7RzuUdzHz87yruz9PFqV63HTas6qtmgLqp8n/Q6AhtDLF39BTZPyDzEbi9qkwRuI="
-    # - secure: "VBJDQNJ9uvdt0aszo7oU3txuRvjkuLmuHZGOkrd4wE/5B4sX5jzx/+dnrKcNTXJCmQ/rVLuMu9GyxqVjNHlzce678voxdQNOtNkNgpkr1qN9/A9rRnCp77hH27ErdthpWxbmcnE62hAJ83TIKSvn//5lAkx4sMCKS1NXEWQ5qec="
-    # PPA configs
-    - PPA="ppa:haxe/snapshots"
-    - DEBFULLNAME="Haxe CI Bot"
-    - DEBEMAIL="[email protected]"
 
 sudo: required
 dist: trusty
-addons: &addons
-  ssh_known_hosts:
-    - haxe.org
-    - api.haxe.org
 
 install_linux: &install_linux
-  - if [ ! -d "$HOME/neko" ]; then
-      export CACHE_AVAILABLE=0;
-    elif [ ! -d "$HOME/neko/.git" ]; then
-      export CACHE_AVAILABLE=0;
-    else
-      export CACHE_AVAILABLE=1;
-    fi
   # Install dependencies
   - export APT_CACHE_DIR=~/apt-cache && mkdir -pv $APT_CACHE_DIR
   - sudo apt-get install --reinstall ca-certificates # workaround for "Cannot add PPA: 'ppa:haxe/ocaml'. Please check that the PPA name or format is correct."
@@ -63,7 +42,6 @@ install_linux: &install_linux
       ocaml
       ocaml-native-compilers
       ocaml-findlib
-      camlp4
       libpcre3-dev
       zlib1g-dev
       libgtk2.0-dev
@@ -71,38 +49,36 @@ install_linux: &install_linux
       awscli
       $JOB_DEPENDENCIES
   - wget https://raw.github.com/ocaml/opam/master/shell/opam_installer.sh -O - | sh -s /usr/local/bin system
-  - export OPAMYES=1
-  - opam install sedlex xml-light extlib rope ptmap
-  # check if we need to install neko
-  - export REF_CHANGED=1;
-  - if [ ! -d "$HOME/neko" ]; then
-      mkdir $HOME/neko;
-      pushd $HOME/neko;
-      git clone https://github.com/HaxeFoundation/neko.git .;
-      git submodule update --init --recursive;
+  - opam update
+  - opam pin add haxe . --no-action
+  - opam install haxe --deps-only
+  # install neko
+  - if [ ! $DEPLOY_NIGHTLIES ]; then
+      sudo add-apt-repository ppa:haxe/snapshots -y;
+      sudo apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y neko neko-dev;
     else
-      pushd $HOME/neko;
-      if [ ! -d "$HOME/neko/.git" ]; then
+      if [ ! -d "$HOME/neko" ]; then
+        mkdir $HOME/neko;
+        pushd $HOME/neko;
         git clone https://github.com/HaxeFoundation/neko.git .;
         git submodule update --init --recursive;
       else
-        git fetch --all;
-        export REF_CUR=`git rev-list master | head -n 1`;
-        export REF_REMOTE=`git rev-list origin/master | head -n 1`;
-        export REF_CHANGED=`(test $REF_CUR != $REF_REMOTE && echo 1) || echo 0`;
-        if [ $REF_CHANGED = 1 ]; then
+        pushd $HOME/neko;
+        if [ ! -d "$HOME/neko/.git" ]; then
+          git clone https://github.com/HaxeFoundation/neko.git .;
+          git submodule update --init --recursive;
+        else
+          git fetch --all;
           git reset --hard origin/master;
           git submodule update --init --recursive;
         fi;
       fi;
-    fi;
-  - env
-  - test $REF_CHANGED = 0 || cmake . -DSTATIC_DEPS=all -G Ninja || (git clean -dfx && export CACHE_AVAILABLE=0 && cmake . -DSTATIC_DEPS=all -G Ninja)
-  # download static dependencies before actual build, with 3 chances to deal with network issues
-  - test $REF_CHANGED = 0 || ninja download_static_deps || ninja download_static_deps || ninja download_static_deps
-  - test $REF_CHANGED = 0 || (ninja -j 4)
-  - sudo cmake -P cmake_install.cmake
-  - popd
+      cmake . -DSTATIC_DEPS=all -G Ninja || (git clean -dfx && cmake . -DSTATIC_DEPS=all -G Ninja);
+      ninja download_static_deps || ninja download_static_deps || ninja download_static_deps;
+      ninja -j 4;
+      sudo ninja install;
+      popd;
+    fi
   # Setup JDK
   - jdk_switcher use oraclejdk7
   - java -version
@@ -119,58 +95,43 @@ install_linux: &install_linux
   - export HAXE_STD_PATH="$TRAVIS_BUILD_DIR/std"
 
 install_osx: &install_osx
-  - if [ ! -d "$HOME/neko" ]; then
-      export CACHE_AVAILABLE=0;
-    elif [ ! -d "$HOME/neko/.git" ]; then
-      export CACHE_AVAILABLE=0;
-    else
-      export CACHE_AVAILABLE=1;
-    fi
   # Install dependencies
   - travis_retry brew update --merge
   - brew uninstall --force brew-cask # https://github.com/caskroom/homebrew-cask/pull/15381
   - travis_retry brew tap Homebrew/bundle
   - travis_retry brew bundle --file=tests/Brewfile
-  - export OPAMYES=1
   - opam init
   - eval `opam config env`
-  - opam install camlp4 sedlex ocamlfind xml-light extlib rope
-  # Install a patched ptmap. See https://github.com/backtracking/ptmap/issues/3
-  - opam install obuild qtest
-  - git clone https://github.com/andyli/ptmap.git --branch 4.05 ~/ptmap
-  - pushd ~/ptmap
-  - make && sudo make install
-  - popd
-  # check if we need to install neko
-  - export REF_CHANGED=1;
-  - if [ ! -d "$HOME/neko" ]; then
-      mkdir $HOME/neko;
-      pushd $HOME/neko;
-      git clone https://github.com/HaxeFoundation/neko.git .;
-      git submodule update --init --recursive;
+  - opam update
+  - opam pin add ptmap https://github.com/andyli/ptmap.git#ocaml406 --no-action # https://github.com/backtracking/ptmap/pull/8
+  - opam pin add haxe . --no-action
+  - opam install haxe --deps-only
+  # install neko
+  - if [ ! $DEPLOY_NIGHTLIES ]; then
+      brew install neko --HEAD;
     else
-      pushd $HOME/neko;
-      if [ ! -d "$HOME/neko/.git" ]; then
+      if [ ! -d "$HOME/neko" ]; then
+        mkdir $HOME/neko;
+        pushd $HOME/neko;
         git clone https://github.com/HaxeFoundation/neko.git .;
         git submodule update --init --recursive;
       else
-        git fetch --all;
-        export REF_CUR=`git rev-list master | head -n 1`;
-        export REF_REMOTE=`git rev-list origin/master | head -n 1`;
-        export REF_CHANGED=`(test $REF_CUR != $REF_REMOTE && echo 1) || echo 0`;
-        if [ $REF_CHANGED = 1 ]; then
+        pushd $HOME/neko;
+        if [ ! -d "$HOME/neko/.git" ]; then
+          git clone https://github.com/HaxeFoundation/neko.git .;
+          git submodule update --init --recursive;
+        else
+          git fetch --all;
           git reset --hard origin/master;
           git submodule update --init --recursive;
         fi;
       fi;
+      cmake . -DSTATIC_DEPS=all -G Ninja || (git clean -dfx && cmake . -DSTATIC_DEPS=all -G Ninja);
+      ninja download_static_deps || ninja download_static_deps || ninja download_static_deps;
+      ninja -j 4;
+      sudo ninja install;
+      popd;
     fi
-  - env
-  - test $REF_CHANGED = 0 || cmake . -DSTATIC_DEPS=all -G Ninja || (git clean -dfx && export CACHE_AVAILABLE=0 && cmake . -DSTATIC_DEPS=all -G Ninja)
-  # download static dependencies before actual build, with 3 chances to deal with network issues
-  - test $REF_CHANGED = 0 || ninja download_static_deps || ninja download_static_deps || ninja download_static_deps
-  - test $REF_CHANGED = 0 || (ninja -j 4)
-  - sudo cmake -P cmake_install.cmake
-  - popd
   # Build haxe
   - make -s STATICLINK=1 "LIB_PARAMS=/usr/local/opt/zlib/lib/libz.a /usr/local/lib/libpcre.a" libs
   - make -s -j STATICLINK=1 "LIB_PARAMS=/usr/local/opt/zlib/lib/libz.a /usr/local/lib/libpcre.a" haxe
@@ -189,43 +150,57 @@ matrix:
     #########
     - os: linux
       env:
-        - TEST=macro,neko,js,php,php7,flash9,as3,java,cs,python,hl,lua
+        - TEST=neko
         - DEPLOY_API_DOCS=1
         - DEPLOY_NIGHTLIES=1
-        # - SAUCE=1
         # haxeci_decrypt (Deploy source package to ppa:haxe/snapshots.)
         - secure: "Mw3p6bDZuqVQ6u7GrwLQfje5hhIOA4+mdqqLXYHP79UKdhgqb91Dn6IbG9vQ1VXVe64W4YZbQAMBMMRX5kEPDl6JvTVGSBhg00Mi69oO5qrCMcBI6f9FntG72YaVvLf+PA7co+vKrnJzaP2M9pe4SH9Ztbhy0YNxULp7NQ8FLsM="
-        # deploy_key_decrypt (Deploy doc to api.haxe.org.)
-        - secure: "A75uYqU0Xz6plIgSewEs0QQWe472dCMb9kf3j7Hx0DS7dApXgx8++189sw9Sv0wam5KPtbcIM292MucjGCb5zocVj9xCUVgajhEA0QpTuDMBjk/cg3ClWCGjfybaCl2E5LLdUs7Zy4b4oNWtVikOWLWJ4sC1kaarR9p6kv8yYZg="
-      # addons:
-      #   <<: *addons
-      #  sauce_connect: true
+      addons:
+        ssh_known_hosts:
+          - haxe.org
+          - api.haxe.org
+      before_install:
+        - eval `ssh-agent -s` # for deployment to haxe.org
+      install: *install_linux
+
+    - os: linux
+      env:
+        - TEST=macro,js,php,flash9,as3,java,cs,python,lua
+        - SAUCE=1
+      addons:
+        sauce_connect: true
       before_install:
         - "export DISPLAY=:99.0"
         - "sh -e /etc/init.d/xvfb start"
         - "export AUDIODEV=null"
       install: *install_linux
+
     - os: linux
       env:
         - TEST=cpp
         - HXCPP_COMPILE_THREADS=4
         - HXCPP_COMPILE_CACHE=~/hxcache
-      before_install:
-        - export JOB_DEPENDENCIES="gcc-multilib g++-multilib"
+        - JOB_DEPENDENCIES="gcc-multilib g++-multilib"
       install: *install_linux
 
     #######
     # osx #
     #######
     - os: osx
-      osx_image: xcode6.4 # to compile binaries that support older versions of Mac
+      osx_image: xcode7.3 # to compile binaries that support older versions of Mac, and 10.11 is the min version that brew provides bottles
       env:
-        - TEST=macro,neko,js,php,python,hl,lua
+        - TEST=neko
         - DEPLOY_NIGHTLIES=1
       install: *install_osx
 
     - os: osx
-      osx_image: xcode8.3 # to compile C++ faster
+      osx_image: xcode9.1 # to compile faster
+      env:
+        - TEST=macro,java,cs,lua,js,php,flash9,python
+      install: *install_osx
+
+    - os: osx
+      osx_image: xcode9.1 # to compile faster
       env:
         - TEST=cpp
         - HXCPP_COMPILE_CACHE=~/hxcache
@@ -233,23 +208,11 @@ matrix:
       install: *install_osx
 
 script:
-  - eval `ssh-agent -s` # for deployment to haxe.org
-  - export CAN_BUILD=`(test $CACHE_AVAILABLE = 1 || test $TRAVIS_OS_NAME = 'linux') && echo 1`
-  - if [ ! $CAN_BUILD ]; then
-      echo "No cache available, but initial cache created, please try restarting this job";
-    fi
-  - test $CAN_BUILD && pushd tests
-  - test $CAN_BUILD && mkdir ~/haxelib && haxelib setup ~/haxelib
-  - test $CAN_BUILD && haxe -version
-  - test $CAN_BUILD && haxe RunCi.hxml
-  - test $CAN_BUILD && neko RunCi.n
-  - test $CAN_BUILD && popd
-
-branches:
-  except:
-    # A hack to prevent building for tags, assuming they all start with a number.
-    # https://github.com/travis-ci/travis-ci/issues/1532
-    - /^[0-9]/
+  - pushd tests
+  - mkdir ~/haxelib && haxelib setup ~/haxelib
+  - haxe -version
+  - haxe RunCi.hxml
+  - popd
 
 notifications:
   webhooks:

+ 13 - 0
.vscode/settings.json

@@ -0,0 +1,13 @@
+{
+	"files.associations": {
+		"*.mly": "ocaml",
+		"*.ml": "ocaml"
+	},
+	"[ocaml]": {
+		"editor.tabSize": 4
+	},
+	"files.exclude": {
+		"**/_build": true
+	},
+	"reason.server.languages": ["ocaml"]
+}

+ 1 - 1
CONTRIBUTING.md

@@ -12,7 +12,7 @@ This repository is about the Haxe compiler itself and the Haxe standard library.
 * The haxelib command line tool or lib.haxe.org: <https://github.com/HaxeFoundation/haxelib/issues>
 * Something on try.haxe.org: <https://github.com/clemos/try-haxe/issues>
 * Something under haxe.org/manual: <https://github.com/HaxeFoundation/HaxeManual/issues>
-* Something on api.haxe.org: For content this is probably the right repository. If it's about the representation, try <https://github.com/dpeek/dox/issues> instead.
+* Something on api.haxe.org: For content this is probably the right repository. If it's about the representation, try <https://github.com/HaxeFoundation/dox/issues> instead.
 * Something else on haxe.org: <https://github.com/HaxeFoundation/haxe.org/issues>
 
 ## Other remarks:

+ 73 - 31
Makefile

@@ -15,6 +15,7 @@ INSTALL_BIN_DIR=$(INSTALL_DIR)/bin
 INSTALL_LIB_DIR=$(INSTALL_DIR)/lib/haxe
 INSTALL_STD_DIR=$(INSTALL_DIR)/share/haxe/std
 PACKAGE_OUT_DIR=out
+INSTALLER_TMP_DIR=installer
 PACKAGE_SRC_EXTENSION=.tar.gz
 
 MAKEFILENAME?=Makefile
@@ -27,9 +28,13 @@ STATICLINK?=0
 
 # Configuration
 
-HAXE_DIRECTORIES=compiler context generators generators/gencommon macro filters macro/eval optimization syntax typing display
+HAXE_DIRECTORIES=core syntax context codegen codegen/gencommon generators optimization filters macro macro/eval typing compiler
 EXTLIB_LIBS=extlib-leftovers extc neko javalib swflib ttflib ilib objsize pcre ziplib
-FINDLIB_LIBS=unix str threads sedlex xml-light extlib rope ptmap dynlink
+OCAML_LIBS=unix str threads dynlink
+OPAM_LIBS=sedlex xml-light extlib rope ptmap
+
+FINDLIB_LIBS=$(OCAML_LIBS)
+FINDLIB_LIBS+=$(OPAM_LIBS)
 
 # Includes, packages and compiler
 
@@ -40,6 +45,8 @@ FINDLIB_PACKAGES=$(FINDLIB_LIBS:%=-package %)
 CFLAGS=
 ALL_CFLAGS=-bin-annot -safe-string -thread -g -w -3 $(CFLAGS) $(ALL_INCLUDES) $(FINDLIB_PACKAGES)
 
+MESSAGE_FILTER=sed -e 's/_build\/src\//src\//' tmp.tmp
+
 ifeq ($(BYTECODE),1)
 	TARGET_FLAG = bytecode
 	COMPILER = ocamlfind ocamlc
@@ -54,7 +61,7 @@ else
 	OCAMLDEP_FLAGS = -native
 endif
 
-CC_CMD = $(COMPILER) $(ALL_CFLAGS) -c $<
+CC_CMD = ($(COMPILER) $(ALL_CFLAGS) -c $< 2>tmp.tmp && $(MESSAGE_FILTER)) || ($(MESSAGE_FILTER) && exit 1)
 
 # Meta information
 
@@ -111,7 +118,7 @@ _build/%:%
 build_dirs:
 	@mkdir -p $(BUILD_DIRECTORIES)
 
-_build/src/syntax/parser.ml:src/syntax/parser.mly
+_build/src/syntax/grammar.ml:src/syntax/grammar.mly
 	camlp4o -impl $< -o $@
 
 _build/src/compiler/version.ml: FORCE
@@ -121,7 +128,7 @@ else
 	echo let version_extra = None > _build/src/compiler/version.ml
 endif
 
-build_src: | $(BUILD_SRC) _build/src/syntax/parser.ml _build/src/compiler/version.ml
+build_src: | $(BUILD_SRC) _build/src/syntax/grammar.ml _build/src/compiler/version.ml
 
 haxe: build_src
 	$(MAKE) -f $(MAKEFILENAME) build_pass_1
@@ -155,7 +162,7 @@ quickcpp: build_src build_pass_4 copy_haxetoolkit
 
 CPP_OS := $(shell uname)
 ifeq ($(CPP_OS),Linux)
-copy_haxetoolkit: 
+copy_haxetoolkit:
 	sudo cp haxe /usr/bin/haxe
 else
 copy_haxetoolkit: /cygdrive/c/HaxeToolkit/haxe/haxe.exe
@@ -196,6 +203,10 @@ uninstall:
 	else \
 		rm -rf $(INSTALL_LIB_DIR); \
 	fi
+	rm -rf  $(INSTALL_STD_DIR)
+
+opam_install:
+	opam install $(OPAM_LIBS) camlp4 ocamlfind --yes
 
 # Dependencies
 
@@ -222,32 +233,63 @@ package_unix:
 
 package_bin: package_$(PLATFORM)
 
-install_dox:
-	haxelib git hxparse https://github.com/Simn/hxparse master src
-	haxelib git hxtemplo https://github.com/Simn/hxtemplo
-	haxelib git hxargs https://github.com/Simn/hxargs
-	haxelib git markdown https://github.com/dpeek/haxe-markdown master src
-	haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp
-	haxelib git hxjava https://github.com/HaxeFoundation/hxjava
-	haxelib git hxcs https://github.com/HaxeFoundation/hxcs
-	haxelib git dox https://github.com/HaxeFoundation/dox
-
-package_doc:
-	mkdir -p $(PACKAGE_OUT_DIR)
-	$(eval OUTFILE := $(shell pwd)/$(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_doc.zip)
+xmldoc:
+	haxelib path hxcpp  || haxelib git hxcpp  https://github.com/HaxeFoundation/hxcpp
+	haxelib path hxjava || haxelib git hxjava https://github.com/HaxeFoundation/hxjava
+	haxelib path hxcs   || haxelib git hxcs   https://github.com/HaxeFoundation/hxcs
+	cd extra && haxe doc.hxml
+
+$(INSTALLER_TMP_DIR):
+	mkdir -p $(INSTALLER_TMP_DIR)
+
+$(INSTALLER_TMP_DIR)/neko-osx64.tar.gz: $(INSTALLER_TMP_DIR)
+	wget http://nekovm.org/media/neko-2.1.0-osx64.tar.gz -O installer/neko-osx64.tar.gz
+
+# Installer
+
+package_installer_mac: $(INSTALLER_TMP_DIR)/neko-osx64.tar.gz package_unix
+	$(eval OUTFILE := $(shell pwd)/$(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_installer.tar.gz)
+	$(eval PACKFILE := $(shell pwd)/$(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_bin.tar.gz)
 	$(eval VERSION := $(shell haxe -version 2>&1))
-	cd $$(haxelib path dox | head -n 1) && \
-		haxe run.hxml && \
-		haxe gen.hxml && \
-		haxe -lib hxtemplo -lib hxparse -lib hxargs -lib markdown \
-		-cp src -dce no --run dox.Dox -theme haxe_api -D website "http://haxe.org/" \
-		--title "Haxe API" -o $(OUTFILE) \
-		-D version "$(VERSION)" -i bin/xml -ex microsoft -ex javax -ex cs.internal \
-		-D source-path https://github.com/HaxeFoundation/haxe/blob/$(BRANCH)/std/
-
-deploy_doc:
-	scp $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_doc.zip [email protected]:/data/haxeapi/www/v/dev/api-latest.zip
-	ssh [email protected] "cd /data/haxeapi/www/v/dev && find . ! -name 'api-latest.zip' -maxdepth 1 -mindepth 1 -exec rm -rf {} + && unzip -q -o api-latest.zip"
+	$(eval NEKOVER := $(shell neko -version 2>&1))
+	bash -c "rm -rf $(INSTALLER_TMP_DIR)/{resources,pkg,tgz,haxe.tar.gz}"
+	mkdir $(INSTALLER_TMP_DIR)/resources
+	# neko - unpack to change the dir name
+	cd $(INSTALLER_TMP_DIR)/resources && tar -zxvf ../neko-osx64.tar.gz
+	mv $(INSTALLER_TMP_DIR)/resources/neko* $(INSTALLER_TMP_DIR)/resources/neko
+	cd $(INSTALLER_TMP_DIR)/resources && tar -zcvf neko.tar.gz neko
+	# haxe - unpack to change the dir name
+	cd $(INSTALLER_TMP_DIR)/resources && tar -zxvf $(PACKFILE)
+	mv $(INSTALLER_TMP_DIR)/resources/haxe* $(INSTALLER_TMP_DIR)/resources/haxe
+	cd $(INSTALLER_TMP_DIR)/resources && tar -zcvf haxe.tar.gz haxe
+	# scripts
+	cp -rf extra/mac-installer/* $(INSTALLER_TMP_DIR)/resources
+	cd $(INSTALLER_TMP_DIR)/resources && tar -zcvf scripts.tar.gz scripts
+	# installer structure
+	mkdir -p $(INSTALLER_TMP_DIR)/pkg
+	cd $(INSTALLER_TMP_DIR)/pkg && xar -xf ../resources/installer-structure.pkg .
+	mkdir $(INSTALLER_TMP_DIR)/tgz; mv $(INSTALLER_TMP_DIR)/resources/*.tar.gz $(INSTALLER_TMP_DIR)/tgz
+	cd $(INSTALLER_TMP_DIR)/tgz; find . | cpio -o --format odc | gzip -c > ../pkg/files.pkg/Payload
+	cd $(INSTALLER_TMP_DIR)/pkg/files.pkg && bash -c "INSTKB=$$(du -sk ../../tgz | awk '{print $$1;}'); \
+	du -sk ../../tgz; \
+	echo $$INSTKB ; \
+	INSTKBH=`expr $$INSTKB - 4`; \
+	echo $$INSTKBH ;\
+	sed -i '' 's/%%INSTKB%%/$$INSTKBH/g' PackageInfo ;\
+	sed -i '' 's/%%VERSION%%/$(VERSION)/g' PackageInfo ;\
+	sed -i '' 's/%%VERSTRING%%/$(VERSION)/g' PackageInfo ;\
+	sed -i '' 's/%%VERLONG%%/$(VERSION)/g' PackageInfo ;\
+	sed -i '' 's/%%NEKOVER%%/$(NEKOVER)/g' PackageInfo ;\
+	cd .. ;\
+	sed -i '' 's/%%VERSION%%/$(VERSION)/g' Distribution ;\
+	sed -i '' 's/%%VERSTRING%%/$(VERSION)/g' Distribution ;\
+	sed -i '' 's/%%VERLONG%%/$(VERSION)/g' Distribution ;\
+	sed -i '' 's/%%NEKOVER%%/$(NEKOVER)/g' Distribution ;\
+	sed -i '' 's/%%INSTKB%%/$$INSTKBH/g' Distribution"
+	# repackage
+	cd $(INSTALLER_TMP_DIR)/pkg; xar --compression none -cf ../$(PACKAGE_FILE_NAME).pkg *
+	# tar
+	cd $(INSTALLER_TMP_DIR); tar -zcvf $(OUTFILE) $(PACKAGE_FILE_NAME).pkg
 
 # Clean
 

+ 31 - 0
Makefile.win

@@ -60,3 +60,34 @@ package_choco:
 	cd out/choco && choco pack
 	mv out/choco/haxe.*.nupkg out
 	rm -rf out/choco
+
+$(INSTALLER_TMP_DIR)/neko-win.zip: $(INSTALLER_TMP_DIR)
+	wget http://nekovm.org/media/neko-2.1.0-win.zip -O installer/neko-win.zip
+
+package_installer_win: $(INSTALLER_TMP_DIR)/neko-win.zip package_win
+	$(eval OUTFILE := $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_installer.zip)
+	$(eval VERSION := $(shell haxe -version 2>&1 | cut -d ' ' -f1))
+	rm -rf $(INSTALLER_TMP_DIR)/resources
+	# neko
+	mkdir $(INSTALLER_TMP_DIR)/resources
+	cd $(INSTALLER_TMP_DIR) && 7z x -y neko-win.zip
+	rm $(INSTALLER_TMP_DIR)/neko-win.zip
+	mv $(INSTALLER_TMP_DIR)/neko* $(INSTALLER_TMP_DIR)/resources/neko
+	# haxe
+	7z x -y $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_bin.zip -o$(INSTALLER_TMP_DIR)/resources
+	mv $(INSTALLER_TMP_DIR)/resources/haxe* $(INSTALLER_TMP_DIR)/resources/haxe
+	# haxesetup.exe
+	haxelib path hxcpp || haxelib install hxcpp
+	cd extra; haxelib run hxcpp build-haxesetup.xml
+	cp extra/haxesetup.exe $(INSTALLER_TMP_DIR)/resources/haxe
+	# extra
+	cp extra/*.nsi $(INSTALLER_TMP_DIR)
+	cp extra/*.nsh $(INSTALLER_TMP_DIR)
+	cp -rf extra/images $(INSTALLER_TMP_DIR)
+	# nsis
+	sed -i "s/%%VERSION%%/$(VERSION)/g" $(INSTALLER_TMP_DIR)/installer.nsi
+	sed -i "s/%%VERSTRING%%/$(VERSION)/g" $(INSTALLER_TMP_DIR)/installer.nsi
+	sed -i "s/%%VERLONG%%/$(VERSION)/g" $(INSTALLER_TMP_DIR)/installer.nsi
+	cd $(INSTALLER_TMP_DIR) && makensis installer.nsi
+	7z a -r -tzip $(OUTFILE) $(INSTALLER_TMP_DIR)/*.exe
+	dir $(PACKAGE_OUT_DIR)

+ 11 - 11
README.md

@@ -13,17 +13,17 @@ Haxe is an open source toolkit that allows you to easily build cross-platform to
 
 Haxe allows you to compile for the following targets:
 
- * ActionScript 3
+ * JavaScript
  * C++
  * C#
- * Flash
  * [HashLink](http://hashlink.haxe.org/)
  * Java
- * JavaScript
  * Lua
- * [NekoVM](http://nekovm.org/)
  * PHP
  * Python 3
+ * [NekoVM](http://nekovm.org/)
+ * Flash
+ * ActionScript 3
 
 You can try Haxe directly from your browser at [try.haxe.org](https://try.haxe.org)!
 
@@ -68,20 +68,20 @@ For information on on using Haxe, consult the [Haxe documentation](https://haxe.
 
  * [Haxe Introduction](https://haxe.org/documentation/introduction/), an introduction to the Haxe toolkit
  * [The Haxe Manual](https://haxe.org/manual/), the reference manual for the Haxe language
- * [Haxe Code Cookbook](http://code.haxe.org), code snippets / learning resource
- * [Haxe API](http://api.haxe.org), documentation for the Haxe standard and native APIs
- * [Haxelib](https://lib.haxe.org), a repository of Haxe libraries for a variety of needs
+ * [Haxe Code Cookbook](https://code.haxe.org), code snippets / learning resource
+ * [Haxe API](https://api.haxe.org), documentation for the Haxe standard and native APIs
+ * [Haxelib](https://lib.haxe.org), Haxelib is the package manager for the Haxe Toolkit.
 
 ## Community
 
 You can get help and talk with fellow Haxers from around the world via:
 
+ * [Haxe Community Forum](http://community.haxe.org)
  * [Haxe on Stack Overflow](https://stackoverflow.com/questions/tagged/haxe)
- * the [official Haxe Google Group](https://groups.google.com/forum/#!forum/haxelang)
- * [#Haxe on Twitter](https://twitter.com/hashtag/haxe?src=hash)
- * the [Haxe IRC chatroom](https://unic0rn.github.io/tiramisu/haxe/), #haxe on chat.freenode.net
+ * [Haxe Gittr chatroom](https://gitter.im/HaxeFoundation/haxe/)
+ * [#haxe on Twitter](https://twitter.com/hashtag/haxe?src=hash)
 
-:+1: Get notified of the latest Haxe news, follow us on [Twitter](https://twitter.com/haxelang), [Facebook](https://www.facebook.com/haxe.org) or [Google+](https://plus.google.com/+HaxeOrg)
+:+1: Get notified of the latest Haxe news, follow us on [Twitter](https://twitter.com/haxelang), [Facebook](https://www.facebook.com/haxe.org) and don't forget to read the [Haxe roundups](https://haxe.io/).
 
 ## Version compatibility
 

+ 28 - 18
appveyor.yml

@@ -13,41 +13,52 @@ environment:
         HXBUILDS_AWS_SECRET_ACCESS_KEY:
           secure: ewwkKcjnSKl/Vtrz1SXmI6XKk1ENmJDyzm5YaR2wi03foRhTke29TvymB21rDTSl
     matrix:
-        - TEST: "neko,python,cs,java,php7,php,macro"
+        - ARCH: 64
+          TEST: "neko,python,cs,java,php,macro"
+          DEPLOY_NIGHTLIES: 1
+        - ARCH: 64
+          TEST: "cpp"
+        - ARCH: 32
+          TEST: "macro"
           DEPLOY_NIGHTLIES: 1
-        - TEST: "cpp"
-
-skip_tags: true
 
 cache:
-    - opam64.tar.xz -> appveyor.yml
+    - opam.tar.xz -> appveyor.yml
 
 install:
     - 'git submodule update --init --recursive'
     - '%CYG_ROOT%/bin/bash -lc "echo initialize"'
-    - choco install curl
+    # http://help.appveyor.com/discussions/problems/5616-not-able-to-build-due-to-problem-in-chocolateyinstallps1
+    - ps: Set-Service wuauserv -StartupType Manual
+    - choco install curl nsis.portable wget awscli -y
     # Install ocaml
     - curl -fsSL -o cygwin-setup.exe --retry 3 https://cygwin.com/setup-x86_64.exe
-    - 'cygwin-setup.exe -g -q -R "%CYG_ROOT%" -P make -P git -P mingw64-x86_64-zlib -P rsync -P patch -P diffutils -P curl -P unzip -P m4 -P perl -P mingw64-x86_64-gcc-core -P mingw64-x86_64-pcre'
-    - if not exist "opam64.tar.xz" (
-        curl -fsSL -o opam64.tar.xz --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.1/opam64.tar.xz
+    - 'cygwin-setup.exe -g -q -R "%CYG_ROOT%" -P make -P git -P mingw64-x86_64-zlib -P mingw64-i686-zlib -P rsync -P patch -P diffutils -P curl -P unzip -P m4 -P perl -P mingw64-x86_64-gcc-core -P mingw64-i686-gcc-core -P mingw64-x86_64-pcre -P mingw64-i686-pcre'
+    - if not exist "opam.tar.xz" (
+        curl -fsSL -o "opam.tar.xz" --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.1/opam%ARCH%.tar.xz
       )
-    - 7z x "opam64.tar.xz" -so | 7z x -aoa -si -ttar
-    - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && bash opam64/install.sh"'
-    - '%CYG_ROOT%/bin/bash -lc "opam init mingw \"https://github.com/fdopen/opam-repository-mingw.git\" --comp 4.02.3+mingw64c --switch 4.02.3+mingw64c --auto-setup --yes"'
-    - '%CYG_ROOT%/bin/bash -lc "opam install camlp4 sedlex ocamlfind xml-light extlib rope ptmap --yes"'
+    - 7z x "opam.tar.xz" -so | 7z x -aoa -si -ttar
+    - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && bash opam${ARCH}/install.sh"'
+    - '%CYG_ROOT%/bin/bash -lc "opam init mingw \"https://github.com/fdopen/opam-repository-mingw.git\" --comp 4.02.3+mingw${ARCH}c --switch 4.02.3+mingw${ARCH}c --auto-setup --yes"'
+    - '%CYG_ROOT%/bin/bash -lc "opam update --yes"'
+    - '%CYG_ROOT%/bin/bash -lc "opam pin add haxe \"$APPVEYOR_BUILD_FOLDER\" --no-action --yes"'
+    - '%CYG_ROOT%/bin/bash -lc "opam install haxe --deps-only --yes"'
     # Install neko
     - choco install neko --prerelease --ignore-dependencies -s 'https://ci.appveyor.com/nuget/neko' -y
-    - choco install chocolatey-core.extension php --ignore-dependencies -y
+    # Install php
+    - choco install php -y
     - echo extension=php_openssl.dll >> C:\tools\php71\php.ini
     - RefreshEnv
-    - neko -version
     # setup python
     - cmd: mklink C:\Python34-x64\python3.exe C:\Python34-x64\python.exe
     - set PATH=%PATH%;C:\Python34-x64
     # expose the dll files
-    - set "PATH=%CYG_ROOT%/usr/x86_64-w64-mingw32/sys-root/mingw/bin;%PATH%"
-    - choco install awscli
+    - if "%ARCH%" EQU "32" (
+        set "PATH=%CYG_ROOT%/usr/i686-w64-mingw32/sys-root/mingw/bin;%PATH%"
+      ) else (
+        set "PATH=%CYG_ROOT%/usr/x86_64-w64-mingw32/sys-root/mingw/bin;%PATH%"
+      )
+    - neko -version
 
 build_script:
     - 'cd %APPVEYOR_BUILD_FOLDER%'
@@ -66,7 +77,6 @@ test_script:
     - cd %APPVEYOR_BUILD_FOLDER%/tests/
     - haxe -version
     - haxe RunCi.hxml
-    - neko RunCi.n
 
 artifacts:
     - path: 'out/*.zip'

+ 114 - 4
extra/CHANGES.txt

@@ -1,4 +1,84 @@
-????-??-??: 4.0.0
+????-??-??: 4.0.0-preview.3
+
+	New features:
+
+	all : added new function type notation (#6645)
+
+	General improvements and optimizations:
+
+	all : made all non-warning/non-error compiler messages output to stdout (#4480)
+	php : implemented direct method comparison. No need to use `Reflect.compareMethods()`
+	php : added `php.Syntax.code()` instead of deprecated `untyped __php__()` (#6708)
+	php : added methods to `php.Syntax` for each php operator: `??`, `?:`, `**` etc. (#6708)
+
+	Removals:
+
+	php : removed `php.Syntax.binop()` (#6708)
+
+	Deprecations:
+
+	php : deprecated support for `untyped __php__`, `untyped __call__` etc. Use `php.Syntax` instead.
+
+	Bugfixes:
+
+	js : fixed saving setter to `tmp` var before invocation (#6672)
+	php : don't fail on generating import aliases for classes with the similar names (#6680)
+	php : fixed `Sys.environment()` to also return variables set by `Sys.putEnv()`
+	php : fixed `sys.net.Socket.bind()` (#6693)
+	php : fixed appending "sqlite:" prefix to the names of files created by `sys.db.Sqlite.open()` (#6692)
+	php : made php.Lib.objectOfAssociativeArray() recursive (#6698)
+	php : fixed php error on parsing expressions like `a == b == c` (#6720)
+
+2017-10-08: 4.0.0-preview.2
+
+	New features:
+
+	all : added final keyword (#6596)
+	all : added new function type notation (#6645)
+
+	General improvements and optimizations:
+
+	all : replaced some occurrences of List with Array
+	all : changed haxe.xml.Fast to an abstract
+	all : improved optimization when comparing against `null`
+	all : added support for `case var x` syntax and detect possible typos (#6608)
+	php : changed `--php-prefix`, `--php-front` and `--php-lib` to `-D php-prefix=`, `-D php-front=` and `-D php-lib=` respectively
+
+	Removals:
+
+	all : moved haxe.unit to hx3compat
+	all : moved haxe.web.Request to hx3compat
+	php : dropped php5 support; minimum supported php version is 7.0 now
+
+	Bugfixes:
+
+	all : fixed issue with various functions not being displayed in macro context (#6000)
+	all : fixed invalid  static extension lookup on `super` (#3607)
+	all : fixed typing error when constructing enums with abstracts over functions (#6609)
+	all : fixed bug that skipped checking @:from typing in some cases (#6564)
+	all : fixed Int64 parsing of negative numbers that end in a zero (#5493)
+	all : fixed top-down inference when constructing enums (#6606)
+	eval : fixed bug with equality handling
+	eval : fixed issue with file creation not defaulting to binary
+	eval : fixed invalid override detection (#6583)
+	eval : fixed infinite recursion when printing arrays/vectors
+	cs/java : fixed DCE bug that would lose toString method of thrown objects
+	php/python : fixed some bit operators for Int32 (#5938)
+	php : fixed accessing `static inline var` via reflection (#6630)
+	php : fixed Math.min() and Math.max() for NAN on PHP 7.1.9 and 7.1.10
+	js : fixed js syntax error for `value.iterator--` (#6637)
+
+	Standard Library:
+
+	macro : added have.display.Position and PositionTools.toRange (#6599)
+	all : moved List to haxe.ds (#6610)
+
+2017-09-12: 4.0.0-preview.1
+
+	New features:
+
+	all : reworked macro interpreter
+	all : added support for arrow functions
 
 	General improvements and optimizations:
 
@@ -35,6 +115,36 @@
 	all : added `EReg.escape` (#5098)
 	all : `BalancedTree implements `haxe.Constraints.IMap` (#6231)
 
+2017-10-08: 3.4.4
+
+	Bugfixes:
+
+	flash : fixed flash target broken when compiled with OCaml 4.05 (#6589)
+	php7 : fixed accessing `static inline var` via reflection (#6630)
+	js : fixed js syntax error for `value.iterator--` (#6637)
+	cpp : fixed evaluation order problem when constructing enums (#6643)
+
+2017-09-10: 3.4.3
+
+	Bugfixes:
+
+	all : fixed DCE issue with interface fields (#6502)
+	cpp : fixed return typing for embedded closures (#6121)
+	php7: fixed `@:enum abstract` generation  without `-dce full` (#6175)
+	php7: fixed using enum constructor with arguments as a call argument (#6177)
+	php7: fixed accessing methods on dynamic values (#6211)
+	php7: fixed `null` property access (#6281)
+	php7: fixed setting values in a map stored in another map (#6257)
+	php7: implemented `php.Lib.mail()`
+	php7: implemented `php.Lib.loadLib()`
+	php7: implemented `php.Lib.getClasses()` (#6384)
+	php7: fixed exception on `Reflect.getProperty(o, field)` if requested field does not exist (#6559)
+	php/php7: fixed accessing enum constructors on enum type stored to a variable (#6159)
+	php/php7: fixed "cannot implement previously implemented interface" (#6208)
+	php: fixed invoking functions stored in dynamic static vars (#6158)
+	php: fixed field access on `new MyClass()` expressions wrapped in a `cast` (#6294)
+	macro : fixed bug in addClassPath that overwrites macro class paths with context class paths
+
 2017-03-20: 3.4.2
 
 	Bugfixes:
@@ -908,7 +1018,7 @@
 	cpp : Fix socket sellect passing _s
 	cpp : Throw error when match count does not match regex
 	cpp : Improve register capture in GC
-	cpp : Fix Dynamic interger compare
+	cpp : Fix Dynamic integer compare
 	cpp : Implement makeVarArgs
 	cpp : Fix toString for nulls in Enums and Arrays
 	cpp : Added initial Android support
@@ -1142,7 +1252,7 @@
 	set all private+protected names from SWF lib to public (allow override+reflect)
 	flash9 : use findprop instead of findpropstrict for 'this' access (allow dynamic)
 	don't allow nullness changes in overrided/implemented
-	prevent typing hole with overriden polymorphic methods
+	prevent typing hole with overridden polymorphic methods
 	added neko.vm.Mutex and neko.vm.Deque (included in neko 1.7.1)
 	added package remapping using --remap
 
@@ -1399,7 +1509,7 @@
 2007-01-28: 1.11
 	changed StringBuf.add implementation
 	added haxe.Firebug
-	allowed variable return type for overriden/implemented methods
+	allowed variable return type for overridden/implemented methods
 	display error position in front of each error line
 	improved error messages when optional arguments not matched
 	added neko.io.Path

+ 21 - 15
extra/ImportAll.hx

@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2005-2016 Haxe Foundation
+ * Copyright (C)2005-2017 Haxe Foundation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -23,16 +23,23 @@ import haxe.macro.Context;
 
 class ImportAll {
 
+	static function isSysTarget() {
+		return Context.defined("neko") || Context.defined("php") || Context.defined("cpp") ||
+		       Context.defined("java") || Context.defined("python") ||
+		       Context.defined("lua") || Context.defined("hl") || Context.defined("eval"); // TODO: have to add cs here, SPOD gets in the way at the moment
+	}
+
 	public static function run( ?pack ) {
 		if( pack == null ) {
 			pack = "";
 			haxe.macro.Compiler.define("doc_gen");
 		}
+		if (Context.defined("interp")) {
+			haxe.macro.Compiler.define("macro");
+		}
 		switch( pack ) {
-		case "php7":
-			if( !Context.defined("php7") ) return;
 		case "php":
-			if( !Context.defined("php") || Context.defined("php7") ) return;
+			if( !Context.defined("php") ) return;
 		case "neko":
 			if( !Context.defined("neko") ) return;
 		case "js":
@@ -41,8 +48,10 @@ class ImportAll {
 			if( !Context.defined("cpp") ) 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;
+			if(!isSysTarget()) return;
 		case "java":
 			if( !Context.defined("java") ) return;
 		case "cs":
@@ -55,10 +64,9 @@ class ImportAll {
 			if( !Context.defined("lua") ) return;
 		case "eval":
 			if( !Context.defined("eval") ) return;
-		case "tools":
-			return;
-		case "build-tool":
-			return;
+		case "ssl":
+			if (!Context.defined("neko") && !Context.defined("cpp")) return;
+		case "tools", "build-tool": return;
 		}
 		for( p in Context.getClassPath() ) {
 			if( p == "/" )
@@ -80,15 +88,13 @@ class ImportAll {
 					switch( cl ) {
 					case "ImportAll", "neko.db.MacroManager": continue;
 					case "haxe.TimerQueue": if( Context.defined("neko") || Context.defined("php") || Context.defined("cpp") ) continue;
-					case "Sys": if( !(Context.defined("neko") || Context.defined("php") || Context.defined("cpp")) ) continue;
+					case "Sys": if(!isSysTarget()) continue;
 					case "haxe.web.Request": if( !(Context.defined("neko") || Context.defined("php") || Context.defined("js")) ) continue;
-					case "haxe.macro.ExampleJSGenerator","haxe.macro.Context", "haxe.macro.Compiler": if( !Context.defined("neko") ) continue;
+					case "haxe.macro.ExampleJSGenerator","haxe.macro.Context", "haxe.macro.Compiler": if( !Context.defined("eval") ) 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;
-					}
-					if( Context.defined("php7") && cl.indexOf("php7.") == 0 ) {
-						cl = "php." + cl.substr("php7.".length);
+					case "neko.vm.Ui" | "sys.db.Sqlite" | "sys.db.Mysql" if ( Context.defined("interp") ): continue;
+					case "sys.db.Sqlite" | "sys.db.Mysql" | "cs.db.AdoNet" if ( Context.defined("cs") ): continue;
 					}
 					Context.getModule(cl);
 				} else if( sys.FileSystem.isDirectory(p + "/" + file) )

+ 0 - 6
extra/all.hxml

@@ -19,12 +19,6 @@
 
 --next
 
--D php7
--php all_php7
--xml php7.xml
-
---next
-
 -php all_php
 -xml php.xml
 

+ 16 - 0
extra/build-haxesetup.xml

@@ -0,0 +1,16 @@
+<xml>
+
+<include name="${HXCPP}/build-tool/BuildCommon.xml"/>
+<set name="static_link" value="1" />
+<set name="no_console" value="1" />
+
+<files id="haxesetup">
+  <file name="setup.cpp" />
+</files>
+
+<target id="default" output="haxesetup" tool="linker" toolid="exe">
+  <lib name="advapi32.lib" />
+  <files id="haxesetup" />
+</target>
+
+</xml>

+ 1 - 1
extra/choco/haxe.nuspec

@@ -18,7 +18,7 @@
         <summary>Haxe is an open source toolkit based on a modern, high level, strictly typed programming language, a cross-compiler, a complete cross-platform standard library and ways to access each platform's native capabilities.</summary>
         <description>Haxe is an open source toolkit based on a modern, high level, strictly typed programming language, a cross-compiler, a complete cross-platform standard library and ways to access each platform's native capabilities.
  
-This package will install haxe and haxelib. After installation, you should run `haxelib setup &lt;path&gt;`, where `&lt;path&gt;` is the haxelib repository folder for placing third-party libraries. The folder should be created manually before running the command.</description>
+This package will install haxe and haxelib. After installation, you should run `haxelib setup %path%;`, where `%path%` is the haxelib repository folder for placing third-party libraries. The folder should be created manually before running the command.</description>
         <releaseNotes>https://github.com/HaxeFoundation/haxe/blob/master/extra/CHANGES.txt</releaseNotes>
         <tags>haxe programming development foss cross-platform</tags>
         <dependencies>

+ 60 - 0
extra/doc.hxml

@@ -0,0 +1,60 @@
+--no-output
+--macro ImportAll.run()
+-dce no
+-D doc-gen
+
+--each
+
+-neko all.n
+-xml doc/neko.xml
+
+--next
+
+-js all.js
+-xml doc/js.xml
+
+--next
+
+-swf all9.swf
+-xml doc/flash.xml
+-swf-version 11.4
+
+--next
+
+-php all_php
+-xml doc/php.xml
+
+--next
+
+-cpp all_cpp
+-xml doc/cpp.xml
+-D xmldoc
+-D HXCPP_MULTI_THREADED
+
+--next
+-java all_java
+-xml doc/java.xml
+-D xmldoc
+
+--next
+-cs all_cs
+-D unsafe
+-xml doc/cs.xml
+-D xmldoc
+
+--next
+-python all_py
+-xml doc/python.xml
+-D xmldoc
+
+--next
+--interp
+-xml doc/macro.xml
+
+--next
+-lua all_lua
+-xml doc/lua.xml
+
+--next
+-hl all_hl
+-xml doc/hl.xml

+ 1 - 1
extra/haxelib_src

@@ -1 +1 @@
-Subproject commit b0b6057d24cac4fc4464b259f269e6d80bd9bf9d
+Subproject commit 93f6a205bdf4012a2615957b766e7a34efe9f0b6

BIN
extra/mac-installer/installer-structure.pkg


+ 13 - 0
extra/mac-installer/scripts/haxe-postinstall.sh

@@ -0,0 +1,13 @@
+#!/bin/sh
+rm -f /usr/bin/haxe
+rm -f /usr/local/bin/haxe
+rm -f /usr/bin/haxedoc
+rm -f /usr/local/bin/haxedoc
+rm -f /usr/bin/haxelib
+rm -f /usr/local/bin/haxelib
+rm -f ~/.haxelib
+rm -f $HOME/.haxelib 
+ln -s /usr/local/lib/haxe/haxe /usr/local/bin/haxe
+cp /usr/local/lib/haxe/haxelib /usr/local/bin/haxelib
+mkdir -p /usr/local/lib/haxe/lib
+chmod 777 /usr/local/lib/haxe/lib

+ 8 - 0
extra/mac-installer/scripts/haxe-preinstall.sh

@@ -0,0 +1,8 @@
+#!/bin/sh
+
+#ensure no conflicting version is left there
+rm -rf /usr/lib/haxe/std
+rm -rf /usr/lib/haxe/doc
+rm -f /usr/lib/haxe/haxe
+rm -rf /usr/local/lib/haxe/std
+rm -rf /usr/local/lib/haxe/doc

+ 18 - 0
extra/mac-installer/scripts/install.sh

@@ -0,0 +1,18 @@
+#!/bin/sh
+cd $(dirname $0)
+# haxe
+chmod +x *
+./haxe-preinstall.sh
+rm -f /usr/lib/haxe
+rm -f /usr/local/lib/haxe
+mkdir -p /usr/local/lib/haxe
+mkdir -p /usr/local/bin
+cp -Rf ../haxe/* /usr/local/lib/haxe
+./haxe-postinstall.sh
+./neko-preinstall.sh
+rm -f /usr/local/lib/neko
+mkdir -p /usr/local/lib/neko
+cp -Rf ../neko/* /usr/local/lib/neko
+./neko-postinstall.sh
+cd ../
+rm -Rf /tmp/haxe

+ 19 - 0
extra/mac-installer/scripts/neko-postinstall.sh

@@ -0,0 +1,19 @@
+#!/bin/sh
+rm -f /usr/bin/neko
+rm -f /usr/bin/nekoc
+rm -f /usr/bin/nekoml
+rm -f /usr/bin/nekotools
+rm -f /usr/lib/libneko.dylib
+rm -f /usr/local/bin/neko
+rm -f /usr/local/bin/nekoc
+rm -f /usr/local/bin/nekoml
+rm -f /usr/local/bin/nekotools
+rm -f /usr/local/lib/libneko*.dylib
+
+ln -s /usr/local/lib/neko/neko /usr/local/bin/neko
+ln -s /usr/local/lib/neko/nekoc /usr/local/bin/nekoc
+ln -s /usr/local/lib/neko/nekoml /usr/local/bin/nekoml
+ln -s /usr/local/lib/neko/nekotools /usr/local/bin/nekotools
+ln -s /usr/local/lib/neko/libneko.dylib /usr/local/lib/libneko.dylib
+ln -s /usr/local/lib/neko/libneko.2.dylib /usr/local/lib/libneko.2.dylib
+ln -s /usr/local/lib/neko/libneko.2.1.0.dylib /usr/local/lib/libneko.2.1.0.dylib

+ 3 - 0
extra/mac-installer/scripts/neko-preinstall.sh

@@ -0,0 +1,3 @@
+#!/bin/sh
+rm -rf /usr/lib/neko
+rm -rf /usr/local/lib/neko

+ 10 - 24
extra/release-checklist.txt

@@ -4,32 +4,18 @@
 - Make sure to update the haxelib submodule
 - Check that the run-time haxelibs are ready for release: hxcpp, hxjava, hxcs
 
-# Building the binaries and installers
-
-- Make sure CHANGES.txt has a proper date set!
-- Make sure `version` in globals.ml has the correct value.
-- Update README.md:
-  - Version compatibility: add/update the Haxe/Neko version
-- Merge development branch into master.
-- Wait for Travis to greenlight master.
-- Tag master as MAJOR.MINOR.PATCH.
-- Wait for builds.haxe.org to build master.
-- Get https://github.com/waneck/hxbuilds/tree/master/release-helper
-- Run it with the fileName corresponding to the latest master file name on builds.haxe.org.
-
 # Making the release
 
-- Regenerate API documentation (check --title and -D version values).
-- Make a GitHub release in https://github.com/HaxeFoundation/haxe/releases with
-  - the generated binaries and installers
-  - the API documentation
-- Update haxe.org
-  - Copy relevant changelog part to downloads/$version/CHANGES.md.
-  - Write announcement post in downloads/$version/RELEASE.md.
-  - Update downloads/versions.json.
-  - Push to staging, check https://staging.haxe.org/.
-  - Merge staging to master, check https://haxe.org/.
+- Make sure CHANGES.txt has a proper date set!
+- Make sure `version` in globals.ml has the correct value
+- Wait for the CI to build (check https://builds.haxe.org)
+- Make an empty GitHub release in https://github.com/HaxeFoundation/haxe/releases
+- Get https://github.com/simn/hxgithub
+- Run it with something like this: `neko release.n -t personal_access_token -h 4.0.0-preview.2 -u -uw -ur -doc --dry`
+- Write the announcement to `./haxe-version/RELEASE.md`
+- If everything was working, run the command again without `--dry`
+- Update https://github.com/HaxeFoundation/haxe.org/blob/staging/downloads/versions.json
 
 # Announcing the release
 
-- Post announcement post to haxelang.
+- Post announcement post to haxelang

+ 1 - 1
libs

@@ -1 +1 @@
-Subproject commit ba1679cb1ed1e74ccd5068755642dc1353780ded
+Subproject commit c368bdc1c7b7dc4fb85613ffcc08578e23f40a6a

+ 24 - 0
opam

@@ -0,0 +1,24 @@
+opam-version: "1.2"
+name: "haxe"
+version: "4.0.0"
+maintainer: ["Haxe Foundation <[email protected]>" "Andy Li <[email protected]>"]
+author: "Haxe Foundation <[email protected]>"
+homepage: "https://haxe.org/"
+bug-reports: "https://github.com/HaxeFoundation/haxe/issues"
+license: ["GPL2+" "MIT"]
+dev-repo: "https://github.com/HaxeFoundation/haxe"
+build: [
+  [make]
+]
+install: [make "install" "INSTALL_DIR=%{prefix}%"]
+remove: [make "uninstall" "INSTALL_DIR=%{prefix}%"]
+depends: [
+  "ocamlfind" {build}
+  "camlp4"    {build}
+  "sedlex"    {build}
+  "xml-light" {build}
+  "extlib"    {build & >= "1.7"}
+  "rope"      {build}
+  "ptmap"     {build}
+]
+available: [ ocaml-version > "4.02" ]

+ 10 - 317
src/generators/codegen.ml → src/codegen/codegen.ml

@@ -26,110 +26,6 @@ open Globals
 (* -------------------------------------------------------------------------- *)
 (* TOOLS *)
 
-(* Collection of functions that return expressions *)
-module ExprBuilder = struct
-	let make_static_this c p =
-		let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in
-		mk (TTypeExpr (TClassDecl c)) ta p
-
-	let make_typeexpr mt pos =
-		let t =
-			match mt with
-			| TClassDecl c -> TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) }
-			| TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }
-			| TAbstractDecl a -> TAnon { a_fields = PMap.empty; a_status = ref (AbstractStatics a) }
-			| _ -> assert false
-		in
-		mk (TTypeExpr mt) t pos
-
-	let make_static_field c cf p =
-		let e_this = make_static_this c p in
-		mk (TField(e_this,FStatic(c,cf))) cf.cf_type p
-
-	let make_throw e p =
-		mk (TThrow e) t_dynamic p
-
-	let make_int com i p =
-		mk (TConst (TInt (Int32.of_int i))) com.basic.tint p
-
-	let make_float com f p =
-		mk (TConst (TFloat f)) com.basic.tfloat p
-
-	let make_bool com b p =
-		mk (TConst(TBool b)) com.basic.tbool p
-
-	let make_string com s p =
-		mk (TConst (TString s)) com.basic.tstring p
-
-	let make_null t p =
-		mk (TConst TNull) t p
-
-	let make_local v p =
-		mk (TLocal v) v.v_type p
-
-	let make_const_texpr com ct p = match ct with
-		| TString s -> mk (TConst (TString s)) com.basic.tstring p
-		| TInt i -> mk (TConst (TInt i)) com.basic.tint p
-		| TFloat f -> mk (TConst (TFloat f)) com.basic.tfloat p
-		| TBool b -> mk (TConst (TBool b)) com.basic.tbool p
-		| TNull -> mk (TConst TNull) (com.basic.tnull (mk_mono())) p
-		| _ -> error "Unsupported constant" p
-end
-
-let field e name t p =
-	mk (TField (e,try quick_field e.etype name with Not_found -> assert false)) t p
-
-let fcall e name el ret p =
-	let ft = tfun (List.map (fun e -> e.etype) el) ret in
-	mk (TCall (field e name ft p,el)) ret p
-
-let mk_parent e =
-	mk (TParenthesis e) e.etype e.epos
-
-let mk_return e =
-	mk (TReturn (Some e)) t_dynamic e.epos
-
-let binop op a b t p =
-	mk (TBinop (op,a,b)) t p
-
-let index com e index t p =
-	mk (TArray (e,mk (TConst (TInt (Int32.of_int index))) com.basic.tint p)) t p
-
-let maybe_cast e t =
-	try
-		type_eq EqDoNotFollowNull e.etype t;
-		e
-	with
-		Unify_error _ -> mk (TCast(e,None)) t e.epos
-
-let type_constant com c p =
-	let t = com.basic in
-	match c with
-	| Int s ->
-		if String.length s > 10 && String.sub s 0 2 = "0x" then error "Invalid hexadecimal integer" p;
-		(try mk (TConst (TInt (Int32.of_string s))) t.tint p
-		with _ -> mk (TConst (TFloat s)) t.tfloat p)
-	| Float f -> mk (TConst (TFloat f)) t.tfloat p
-	| String s -> mk (TConst (TString s)) t.tstring p
-	| Ident "true" -> mk (TConst (TBool true)) t.tbool p
-	| Ident "false" -> mk (TConst (TBool false)) t.tbool p
-	| Ident "null" -> mk (TConst TNull) (t.tnull (mk_mono())) p
-	| Ident t -> error ("Invalid constant :  " ^ t) p
-	| Regexp _ -> error "Invalid constant" p
-
-let rec type_constant_value com (e,p) =
-	match e with
-	| EConst c ->
-		type_constant com c p
-	| EParenthesis e ->
-		type_constant_value com e
-	| EObjectDecl el ->
-		mk (TObjectDecl (List.map (fun ((n,_),e) -> n, type_constant_value com e) el)) (TAnon { a_fields = PMap.empty; a_status = ref Closed }) p
-	| EArrayDecl el ->
-		mk (TArrayDecl (List.map (type_constant_value com) el)) (com.basic.tarray t_dynamic) p
-	| _ ->
-		error "Constant value expected" p
-
 let rec has_properties c =
 	List.exists (fun f ->
 		match f.cf_kind with
@@ -160,7 +56,7 @@ let add_property_field com c =
 	| _ ->
 		let fields,values = List.fold_left (fun (fields,values) (n,v) ->
 			let cf = mk_field n com.basic.tstring p null_pos in
-			PMap.add n cf fields,(n, ExprBuilder.make_string com v p) :: values
+			PMap.add n cf fields,((n,null_pos,NoQuotes),Texpr.Builder.make_string com.basic v p) :: values
 		) (PMap.empty,[]) props in
 		let t = mk_anon fields in
 		let e = mk (TObjectDecl values) t p in
@@ -178,48 +74,6 @@ let escape_res_name name allow_dirs =
 		else
 			"-x" ^ (string_of_int (Char.code chr))) name
 
-(* -------------------------------------------------------------------------- *)
-(* BUILD META DATA OBJECT *)
-
-let build_metadata com t =
-	let api = com.basic in
-	let p, meta, fields, statics = (match t with
-		| TClassDecl c ->
-			let fields = List.map (fun f -> f.cf_name,f.cf_meta) (c.cl_ordered_fields @ (match c.cl_constructor with None -> [] | Some f -> [{ f with cf_name = "_" }])) in
-			let statics =  List.map (fun f -> f.cf_name,f.cf_meta) c.cl_ordered_statics in
-			(c.cl_pos, ["",c.cl_meta],fields,statics)
-		| TEnumDecl e ->
-			(e.e_pos, ["",e.e_meta],List.map (fun n -> n, (PMap.find n e.e_constrs).ef_meta) e.e_names, [])
-		| TTypeDecl t ->
-			(t.t_pos, ["",t.t_meta],(match follow t.t_type with TAnon a -> PMap.fold (fun f acc -> (f.cf_name,f.cf_meta) :: acc) a.a_fields [] | _ -> []),[])
-		| TAbstractDecl a ->
-			(a.a_pos, ["",a.a_meta],[],[])
-	) in
-	let filter l =
-		let l = List.map (fun (n,ml) -> n, ExtList.List.filter_map (fun (m,el,p) -> match m with Meta.Custom s when String.length s > 0 && s.[0] <> ':' -> Some (s,el,p) | _ -> None) ml) l in
-		List.filter (fun (_,ml) -> ml <> []) l
-	in
-	let meta, fields, statics = filter meta, filter fields, filter statics in
-	let make_meta_field ml =
-		let h = Hashtbl.create 0 in
-		mk (TObjectDecl (List.map (fun (f,el,p) ->
-			if Hashtbl.mem h f then error ("Duplicate metadata '" ^ f ^ "'") p;
-			Hashtbl.add h f ();
-			f, mk (match el with [] -> TConst TNull | _ -> TArrayDecl (List.map (type_constant_value com) el)) (api.tarray t_dynamic) p
-		) ml)) t_dynamic p
-	in
-	let make_meta l =
-		mk (TObjectDecl (List.map (fun (f,ml) -> f,make_meta_field ml) l)) t_dynamic p
-	in
-	if meta = [] && fields = [] && statics = [] then
-		None
-	else
-		let meta_obj = [] in
-		let meta_obj = (if fields = [] then meta_obj else ("fields",make_meta fields) :: meta_obj) in
-		let meta_obj = (if statics = [] then meta_obj else ("statics",make_meta statics) :: meta_obj) in
-		let meta_obj = (try ("obj", make_meta_field (List.assoc "" meta)) :: meta_obj with Not_found -> meta_obj) in
-		Some (mk (TObjectDecl meta_obj) t_dynamic p)
-
 let update_cache_dependencies t =
 	let rec check_t m t = match t with
 		| TInst(c,tl) ->
@@ -244,7 +98,7 @@ let update_cache_dependencies t =
 			| Some t -> check_t m t
 			| _ -> ())
 		| TLazy f ->
-			check_t m (!f())
+			check_t m (lazy_type f)
 		| TDynamic t ->
 			if t == t_dynamic then
 				()
@@ -261,114 +115,12 @@ let update_cache_dependencies t =
 		| _ ->
 			()
 
-(* -------------------------------------------------------------------------- *)
-(* STACK MANAGEMENT EMULATION *)
-
-type stack_context = {
-	stack_var : string;
-	stack_exc_var : string;
-	stack_pos_var : string;
-	stack_pos : pos;
-	stack_expr : texpr;
-	stack_pop : texpr;
-	stack_save_pos : texpr;
-	stack_restore : texpr list;
-	stack_push : tclass -> string -> texpr;
-	stack_return : texpr -> texpr;
-}
-
-let stack_context_init com stack_var exc_var pos_var tmp_var use_add p =
-	let t = com.basic in
-	let st = t.tarray t.tstring in
-	let stack_var = alloc_var stack_var st p in
-	let exc_var = alloc_var exc_var st p in
-	let pos_var = alloc_var pos_var t.tint p in
-	let stack_e = mk (TLocal stack_var) st p in
-	let exc_e = mk (TLocal exc_var) st p in
-	let stack_pop = fcall stack_e "pop" [] t.tstring p in
-	let stack_push c m =
-		fcall stack_e "push" [
-			if use_add then
-				binop OpAdd (ExprBuilder.make_string com (s_type_path c.cl_path ^ "::") p) (ExprBuilder.make_string com m p) t.tstring p
-			else
-				ExprBuilder.make_string com (s_type_path c.cl_path ^ "::" ^ m) p
-		] t.tvoid p
-	in
-	let stack_return e =
-		let tmp = alloc_var tmp_var e.etype e.epos in
-		mk (TBlock [
-			mk (TVar (tmp, Some e)) t.tvoid e.epos;
-			stack_pop;
-			mk (TReturn (Some (mk (TLocal tmp) e.etype e.epos))) e.etype e.epos
-		]) e.etype e.epos
-	in
-	{
-		stack_var = stack_var.v_name;
-		stack_exc_var = exc_var.v_name;
-		stack_pos_var = pos_var.v_name;
-		stack_pos = p;
-		stack_expr = stack_e;
-		stack_pop = stack_pop;
-		stack_save_pos = mk (TVar (pos_var, Some (field stack_e "length" t.tint p))) t.tvoid p;
-		stack_push = stack_push;
-		stack_return = stack_return;
-		stack_restore = [
-			binop OpAssign exc_e (mk (TArrayDecl []) st p) st p;
-			mk (TWhile (
-				mk_parent (binop OpGte (field stack_e "length" t.tint p) (mk (TLocal pos_var) t.tint p) t.tbool p),
-				fcall exc_e "unshift" [fcall stack_e "pop" [] t.tstring p] t.tvoid p,
-				NormalWhile
-			)) t.tvoid p;
-			fcall stack_e "push" [index com exc_e 0 t.tstring p] t.tvoid p
-		];
-	}
-
-let stack_init com use_add =
-	stack_context_init com "$s" "$e" "$spos" "$tmp" use_add null_pos
-
-let rec stack_block_loop ctx e =
-	match e.eexpr with
-	| TFunction _ ->
-		e
-	| TReturn None | TReturn (Some { eexpr = TConst _ }) | TReturn (Some { eexpr = TLocal _ }) ->
-		mk (TBlock [
-			ctx.stack_pop;
-			e;
-		]) e.etype e.epos
-	| TReturn (Some e) ->
-		ctx.stack_return (stack_block_loop ctx e)
-	| TTry (v,cases) ->
-		let v = stack_block_loop ctx v in
-		let cases = List.map (fun (v,e) ->
-			let e = stack_block_loop ctx e in
-			let e = (match (mk_block e).eexpr with
-				| TBlock l -> mk (TBlock (ctx.stack_restore @ l)) e.etype e.epos
-				| _ -> assert false
-			) in
-			v , e
-		) cases in
-		mk (TTry (v,cases)) e.etype e.epos
-	| _ ->
-		map_expr (stack_block_loop ctx) e
-
-let stack_block ctx c m e =
-	match (mk_block e).eexpr with
-	| TBlock l ->
-		mk (TBlock (
-			ctx.stack_push c m ::
-			ctx.stack_save_pos ::
-			List.map (stack_block_loop ctx) l
-			@ [ctx.stack_pop]
-		)) e.etype e.epos
-	| _ ->
-		assert false
-
 (* -------------------------------------------------------------------------- *)
 (* FIX OVERRIDES *)
 
 (*
 	on some platforms which doesn't support type parameters, we must have the
-	exact same type for overriden/implemented function as the original one
+	exact same type for overridden/implemented function as the original one
 *)
 
 let rec find_field com c f =
@@ -499,68 +251,24 @@ let rec is_volatile t =
 		| Some t -> is_volatile t
 		| _ -> false)
 	| TLazy f ->
-		is_volatile (!f())
+		is_volatile (lazy_type f)
 	| TType (t,tl) ->
 		(match t.t_path with
 		| _ -> is_volatile (apply_params t.t_params tl t.t_type))
 	| _ ->
 		false
 
-let set_default ctx a c p =
-	let t = a.v_type in
-	let ve = mk (TLocal a) t p in
-	let cond =  TBinop (OpEq,ve,mk (TConst TNull) t p) in
-	mk (TIf (mk_parent (mk cond ctx.basic.tbool p), mk (TBinop (OpAssign,ve,mk (TConst c) t p)) t p,None)) ctx.basic.tvoid p
-
 let bytes_serialize data =
 	let b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" in
 	let tbl = Array.init (String.length b64) (fun i -> String.get b64 i) in
 	Bytes.unsafe_to_string (Base64.str_encode ~tbl data)
 
-(*
-	Tells if the constructor might be called without any issue whatever its parameters
-*)
-let rec constructor_side_effects e =
-	match e.eexpr with
-	| TBinop (op,_,_) when op <> OpAssign ->
-		true
-	| TField (_,FEnum _) ->
-		false
-	| TUnop _ | TArray _ | TField _ | TEnumParameter _ | TEnumIndex _ | TCall _ | TNew _ | TFor _ | TWhile _ | TSwitch _ | TReturn _ | TThrow _ ->
-		true
-	| TBinop _ | TTry _ | TIf _ | TBlock _ | TVar _
-	| TFunction _ | TArrayDecl _ | TObjectDecl _
-	| TParenthesis _ | TTypeExpr _ | TLocal _ | TMeta _
-	| TConst _ | TContinue | TBreak | TCast _ | TIdent _ ->
-		try
-			Type.iter (fun e -> if constructor_side_effects e then raise Exit) e;
-			false;
-		with Exit ->
-			true
-
 module Dump = struct
-	let make_valid_filename s =
-		let r = Str.regexp "[^A-Za-z0-9_\\-\\.,]" in
-		Str.global_substitute r (fun s -> "_") s
-
-	let rec create_file ext acc = function
-		| [] -> assert false
-		| d :: [] ->
-			let d = make_valid_filename d in
-			let maxlen = 200 - String.length ext in
-			let d = if String.length d > maxlen then String.sub d 0 maxlen else d in
-			let ch = open_out (String.concat "/" (List.rev (d :: acc)) ^ ext) in
-			ch
-		| d :: l ->
-			let dir = String.concat "/" (List.rev (d :: acc)) in
-			if not (Sys.file_exists dir) then Unix.mkdir dir 0o755;
-			create_file ext (d :: acc) l
-
 	(*
 		Make a dump of the full typed AST of all types
 	*)
 	let create_dumpfile acc l =
-		let ch = create_file ".dump" acc l in
+		let ch = Path.create_file false ".dump" acc l in
 		let buf = Buffer.create 0 in
 		buf, (fun () ->
 			output_string ch (Buffer.contents buf);
@@ -742,7 +450,7 @@ let default_cast ?(vtmp="$t") com e texpr t p =
 	let is = mk (TField (std,fis)) (tfun [t_dynamic;t_dynamic] api.tbool) p in
 	let is = mk (TCall (is,[vexpr;texpr])) api.tbool p in
 	let exc = mk (TThrow (mk (TConst (TString "Class cast error")) api.tstring p)) t p in
-	let check = mk (TIf (mk_parent is,mk (TCast (vexpr,None)) t p,Some exc)) t p in
+	let check = mk (TIf (Texpr.Builder.mk_parent is,mk (TCast (vexpr,None)) t p,Some exc)) t p in
 	mk (TBlock [var;check;vexpr]) t p
 
 module UnificationCallback = struct
@@ -801,14 +509,14 @@ module UnificationCallback = struct
 			| TObjectDecl fl ->
 				begin match follow e.etype with
 					| TAnon an ->
-						let fl = List.map (fun (n,e) ->
+						let fl = List.map (fun ((n,p,qs),e) ->
 							let e = try
 								let t = (PMap.find n an.a_fields).cf_type in
 								f e t
 							with Not_found ->
 								e
 							in
-							n,e
+							(n,p,qs),e
 						) fl in
 						{ e with eexpr = TObjectDecl fl }
 					| _ -> e
@@ -883,23 +591,8 @@ module ExtClass = struct
 			| Some e' -> c.cl_init <- Some (concat e' e)
 
 	let add_static_init c cf e p =
-		let ethis = ExprBuilder.make_static_this c p in
+		let ethis = Texpr.Builder.make_static_this c p in
 		let ef1 = mk (TField(ethis,FStatic(c,cf))) cf.cf_type p in
 		let e_assign = mk (TBinop(OpAssign,ef1,e)) e.etype p in
 		add_cl_init c e_assign
-end
-
-let for_remap com v e1 e2 p =
-	let v' = alloc_var v.v_name e1.etype e1.epos in
-	let ev' = mk (TLocal v') e1.etype e1.epos in
-	let t1 = (Abstract.follow_with_abstracts e1.etype) in
-	let ehasnext = mk (TField(ev',quick_field t1 "hasNext")) (tfun [] com.basic.tbool) e1.epos in
-	let ehasnext = mk (TCall(ehasnext,[])) com.basic.tbool ehasnext.epos in
-	let enext = mk (TField(ev',quick_field t1 "next")) (tfun [] v.v_type) e1.epos in
-	let enext = mk (TCall(enext,[])) v.v_type e1.epos in
-	let eassign = mk (TVar(v,Some enext)) com.basic.tvoid p in
-	let ebody = Type.concat eassign e2 in
-	mk (TBlock [
-		mk (TVar (v',Some e1)) com.basic.tvoid e1.epos;
-		mk (TWhile((mk (TParenthesis ehasnext) ehasnext.etype ehasnext.epos),ebody,NormalWhile)) com.basic.tvoid e1.epos;
-	]) com.basic.tvoid p
+end

+ 13 - 12
src/typing/dotnet.ml → src/codegen/dotnet.ml

@@ -318,7 +318,7 @@ let convert_ilfield ctx p field =
 		| CInitOnly | CLiteral -> true, acc
 		| _ -> readonly,acc
 	) (false,[cff_access]) field.fflags.ff_contract in
-	if PMap.mem "net_loader_debug" ctx.ncom.defines then
+	if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
 		Printf.printf "\t%sfield %s : %s\n" (if List.mem AStatic acc then "static " else "") cff_name (IlMetaDebug.ilsig_s field.fsig.ssig);
 	let kind = match readonly with
 		| true ->
@@ -358,7 +358,7 @@ let convert_ilevent ctx p ev =
 			else
 				acc
 	in
-	if PMap.mem "net_loader_debug" ctx.ncom.defines then
+	if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
 		Printf.printf "\tevent %s : %s\n" name (IlMetaDebug.ilsig_s ev.esig.ssig);
 	let acc = add_m acc ev.eadd in
 	let acc = add_m acc ev.eremove in
@@ -381,6 +381,7 @@ let convert_ilmethod ctx p m is_explicit_impl =
 	let cff_name = match m.mname with
 		| ".ctor" -> "new"
 		| ".cctor"-> raise Exit (* __init__ field *)
+		| "Finalize" -> raise Exit (* destructor (~ClassName) *)
 		| "Equals" | "GetHashCode" -> raise Exit
 		| name when String.length name > 5 ->
 				(match String.sub name 0 5 with
@@ -397,7 +398,7 @@ let convert_ilmethod ctx p m is_explicit_impl =
 			APrivate, meta
 		| FAPublic -> APublic, meta
 		| _ ->
-			if PMap.mem "net_loader_debug" ctx.ncom.defines then
+			if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
 				Printf.printf "\tmethod %s (skipped) : %s\n" cff_name (IlMetaDebug.ilsig_s m.msig.ssig);
 			raise Exit
 	in
@@ -408,7 +409,7 @@ let convert_ilmethod ctx p m is_explicit_impl =
 		| CMFinal -> acc, Some true
 		| _ -> acc, is_final
 	) ([acc],None) m.mflags.mf_contract in
-	if PMap.mem "net_loader_debug" ctx.ncom.defines then
+	if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
 		Printf.printf "\t%smethod %s : %s\n" (if !is_static then "static " else "") cff_name (IlMetaDebug.ilsig_s m.msig.ssig);
 
 	let meta = match is_final with
@@ -546,7 +547,7 @@ let convert_ilprop ctx p prop is_explicit_impl =
 			| _ -> "never");
 		| Some _ -> "set"
 	in
-	if PMap.mem "net_loader_debug" ctx.ncom.defines then
+	if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then
 		Printf.printf "\tproperty %s (%s,%s) : %s\n" prop.pname get set (IlMetaDebug.ilsig_s prop.psig.ssig);
 	let ilsig = match prop.psig.snorm with
 		| LMethod (_,ret,[]) -> ret
@@ -712,7 +713,7 @@ let convert_ilclass ctx p ?(delegate=false) ilcls = match ilcls.csuper with
 	| _ ->
 		let flags = ref [HExtern] in
 		(* todo: instead of CsNative, use more specific definitions *)
-		if PMap.mem "net_loader_debug" ctx.ncom.defines then begin
+		if PMap.mem "net_loader_debug" ctx.ncom.defines.Define.values then begin
 			let sup = match ilcls.csuper with | None -> [] | Some c -> [IlMetaDebug.ilsig_s c.ssig] in
 			let sup = sup @ List.map (fun i -> IlMetaDebug.ilsig_s i.ssig) ilcls.cimplements in
 			print_endline ("converting " ^ ilpath_s ilcls.cpath ^ " : " ^ (String.concat ", " sup))
@@ -1124,20 +1125,20 @@ let add_net_lib com file std =
 					failwith (".NET lib " ^ file ^ " not found")
 			in
 			real_file := file;
-			let r = PeReader.create_r (open_in_bin file) com.defines in
+			let r = PeReader.create_r (open_in_bin file) com.defines.Define.values in
 			let ctx = PeReader.read r in
 			let clr_header = PeReader.read_clr_header ctx in
 			let cache = IlMetaReader.create_cache () in
 			let meta = IlMetaReader.read_meta_tables ctx clr_header cache in
 			close_in (r.PeReader.ch);
-			if PMap.mem "net_loader_debug" com.defines then
+			if PMap.mem "net_loader_debug" com.defines.Define.values then
 				print_endline ("for lib " ^ file);
 			let il_typedefs = Hashtbl.copy meta.il_typedefs in
 			Hashtbl.clear meta.il_typedefs;
 
 			Hashtbl.iter (fun _ td ->
 				let path = IlMetaTools.get_path (TypeDef td) in
-				if PMap.mem "net_loader_debug" com.defines then
+				if PMap.mem "net_loader_debug" com.defines.Define.values then
 					Printf.printf "found %s\n" (s_type_path (netpath_to_hx path));
 				Hashtbl.replace com.net_path_map (netpath_to_hx path) path;
 				Hashtbl.replace meta.il_typedefs path td
@@ -1174,7 +1175,7 @@ let add_net_lib com file std =
 		let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
 		let cp = ref [] in
 		let rec build path = try
-			if PMap.mem "net_loader_debug" com.defines then
+			if PMap.mem "net_loader_debug" com.defines.Define.values then
 				Printf.printf "looking up %s\n" (s_type_path path);
 			match lookup path with
 			| Some({csuper = Some{snorm = LClass( (["System"],[],("Delegate"|"MulticastDelegate")),_)}} as cls)
@@ -1214,7 +1215,7 @@ let add_net_lib com file std =
 let before_generate com =
 	(* net version *)
 	let net_ver = try
-			int_of_string (PMap.find "net_ver" com.defines)
+			int_of_string (PMap.find "net_ver" com.defines.Define.values)
 		with | Not_found ->
 			Common.define_value com Define.NetVer "20";
 			20
@@ -1235,7 +1236,7 @@ let before_generate com =
 
 	(* net target *)
 	let net_target = try
-			String.lowercase (PMap.find "net_target" com.defines)
+			String.lowercase (PMap.find "net_target" com.defines.Define.values)
 		with | Not_found ->
 			"net"
 	in

+ 0 - 0
src/generators/gencommon/abstractImplementationFix.ml → src/codegen/gencommon/abstractImplementationFix.ml


+ 0 - 0
src/generators/gencommon/arrayDeclSynf.ml → src/codegen/gencommon/arrayDeclSynf.ml


+ 3 - 3
src/generators/gencommon/castDetect.ml → src/codegen/gencommon/castDetect.ml

@@ -81,10 +81,10 @@ struct
 				let ret_type = match !current_ret_type with | Some(s) -> s | None -> gen.gcon.error "Invalid return outside function declaration." e.epos; assert false in
 				(match eopt with
 				| None when not (ExtType.is_void ret_type) ->
-					mk_return (null ret_type e.epos)
+					Texpr.Builder.mk_return (null ret_type e.epos)
 				| None -> e
 				| Some eret ->
-					mk_return (handle (run eret) ret_type eret.etype))
+					Texpr.Builder.mk_return (handle (run eret) ret_type eret.etype))
 			| TFunction(tfunc) ->
 				let last_ret = !current_ret_type in
 				current_ret_type := Some(tfunc.tf_type);
@@ -623,7 +623,7 @@ let choose_ctor gen cl tparams etl maybe_empty_t p =
 			unify et t;
 			check_arg arglist elist
 		with | Unify_error el ->
-			(* List.iter (fun el -> gen.gcon.warning (Typecore.unify_error_msg (print_context()) el) p) el; *)
+			(* List.iter (fun el -> gen.gcon.warning (Error.unify_error_msg (print_context()) el) p) el; *)
 			false)
 		| _ ->
 			false

+ 0 - 0
src/generators/gencommon/classInstance.ml → src/codegen/gencommon/classInstance.ml


+ 9 - 8
src/generators/gencommon/closuresToClass.ml → src/codegen/gencommon/closuresToClass.ml

@@ -20,6 +20,7 @@ open Option
 open Common
 open Globals
 open Codegen
+open Texpr.Builder
 open Ast
 open Type
 open Gencommon
@@ -691,7 +692,7 @@ struct
 			if arity >= max_arity then begin
 				let varray = match changed_args with | [v,_] -> v | _ -> assert false in
 				let varray_local = mk_local varray pos in
-				let mk_varray i = { eexpr = TArray(varray_local, ExprBuilder.make_int gen.gcon i pos); etype = t_dynamic; epos = pos } in
+				let mk_varray i = { eexpr = TArray(varray_local, make_int gen.gcon.basic i pos); etype = t_dynamic; epos = pos } in
 				let el =
 					snd (List.fold_left (fun (count,acc) (v,const) ->
 						(count + 1, (mk (TVar(v, Some(mk_const const (mk_varray count) v.v_type))) basic.tvoid pos) :: acc)
@@ -794,8 +795,8 @@ struct
 			invoke_field.cf_expr <- Some invoke_fun;
 
 			invoke_field, [
-				ExprBuilder.make_int gen.gcon arity pos;
-				ExprBuilder.make_int gen.gcon type_number pos;
+				make_int gen.gcon.basic arity pos;
+				make_int gen.gcon.basic type_number pos;
 			]
 		in
 
@@ -1028,7 +1029,7 @@ struct
 			let pos = cl.cl_pos in
 
 			let rec mk_dyn_call arity api =
-				let zero = ExprBuilder.make_float gen.gcon "0.0" pos in
+				let zero = make_float gen.gcon.basic "0.0" pos in
 				let rec loop i acc =
 					if i = 0 then
 						acc
@@ -1046,7 +1047,7 @@ struct
 			let mk_invoke_switch i api =
 				let t = TFun (func_sig_i i, t_dynamic) in
 				(* case i: return this.invokeX_o(0, 0, 0, 0, 0, ... arg[0], args[1]....); *)
-				[ExprBuilder.make_int gen.gcon i pos], mk_return (mk (TCall(mk_this (iname i false) t, mk_dyn_call i api)) t_dynamic pos)
+				[make_int gen.gcon.basic i pos], mk_return (mk (TCall(mk_this (iname i false) t, mk_dyn_call i api)) t_dynamic pos)
 			in
 			let rec loop_cases api arity acc =
 				if arity < 0 then
@@ -1067,8 +1068,8 @@ struct
 				in
 				{
 					eexpr = TIf(
-						mk (TBinop (Ast.OpNotEq, mk_this type_name basic.tint, (ExprBuilder.make_int gen.gcon (if is_float then 0 else 1) pos))) basic.tbool pos,
-						ExprBuilder.make_throw (mk_arg_exception "Wrong number of arguments" pos) pos,
+						mk (TBinop (Ast.OpNotEq, mk_this type_name basic.tint, (make_int gen.gcon.basic (if is_float then 0 else 1) pos))) basic.tbool pos,
+						make_throw (mk_arg_exception "Wrong number of arguments" pos) pos,
 						Some (mk_return call_expr)
 					);
 					etype = t_dynamic;
@@ -1099,7 +1100,7 @@ struct
 						eexpr = TSwitch(
 							switch_cond,
 							loop_cases api !max_arity [],
-							Some(ExprBuilder.make_throw (mk_arg_exception "Too many arguments" pos) pos));
+							Some(make_throw (mk_arg_exception "Too many arguments" pos) pos));
 						etype = basic.tvoid;
 						epos = pos;
 					}

+ 0 - 0
src/generators/gencommon/dynamicFieldAccess.ml → src/codegen/gencommon/dynamicFieldAccess.ml


+ 7 - 6
src/generators/gencommon/dynamicOperators.ml → src/codegen/gencommon/dynamicOperators.ml

@@ -20,6 +20,7 @@ open Common
 open Ast
 open Type
 open Codegen
+open Texpr.Builder
 open Gencommon
 
 (* ******************************************* *)
@@ -65,9 +66,9 @@ open Gencommon
 let init com handle_strings (should_change:texpr->bool) (equals_handler:texpr->texpr->texpr) (dyn_plus_handler:texpr->texpr->texpr->texpr) (compare_handler:Ast.binop->texpr->texpr->texpr->texpr) =
 	let get_etype_one e =
 		if like_int e.etype then
-			ExprBuilder.make_int com 1 e.epos
+			make_int com.basic 1 e.epos
 		else
-			ExprBuilder.make_float com "1.0" e.epos
+			make_float com.basic "1.0" e.epos
 	in
 	let rec run e =
 		match e.eexpr with
@@ -144,21 +145,21 @@ let init com handle_strings (should_change:texpr->bool) (equals_handler:texpr->t
 					| TField (fexpr, field) ->
 						let tmp = mk_temp "getvar" fexpr.etype in
 						let var = mk (TVar (tmp, Some (run fexpr))) com.basic.tvoid e.epos in
-						([var], mk (TField (ExprBuilder.make_local tmp fexpr.epos, field)) etype e1.epos)
+						([var], mk (TField (make_local tmp fexpr.epos, field)) etype e1.epos)
 					| _ ->
 						([], e1)
 				in
 				match flag with
 				| Prefix ->
 					vars @ [
-						mk_cast etype { e with eexpr = TBinop(OpAssign, getvar, Codegen.binop op (mk_cast etype getvar) one etype e.epos); etype = getvar.etype }
+						mk_cast etype { e with eexpr = TBinop(OpAssign, getvar, binop op (mk_cast etype getvar) one etype e.epos); etype = getvar.etype }
 					]
 				| Postfix ->
 					let ret = mk_temp "ret" etype in
-					let retlocal = ExprBuilder.make_local ret e.epos in
+					let retlocal = make_local ret e.epos in
 					vars @ [
 						mk (TVar (ret, Some (mk_cast etype getvar))) com.basic.tvoid e.epos;
-						{ e with eexpr = TBinop (OpAssign, getvar, Codegen.binop op retlocal one getvar.etype e.epos) };
+						{ e with eexpr = TBinop (OpAssign, getvar, binop op retlocal one getvar.etype e.epos) };
 						retlocal
 					]
 			in

+ 6 - 5
src/generators/gencommon/enumToClass.ml → src/codegen/gencommon/enumToClass.ml

@@ -21,6 +21,7 @@ open Globals
 open Ast
 open Type
 open Codegen
+open Texpr.Builder
 open Gencommon
 
 (* ******************************************* *)
@@ -79,7 +80,7 @@ struct
 		let cl = mk_class en.e_module en.e_path pos in
 		Hashtbl.add t.ec_tbl en.e_path cl;
 
-		(match Codegen.build_metadata gen.gcon (TEnumDecl en) with
+		(match Texpr.build_metadata gen.gcon.basic (TEnumDecl en) with
 			| Some expr ->
 				let cf = mk_class_field "__meta__" expr.etype false expr.epos (Var { v_read = AccNormal; v_write = AccNormal }) [] in
 				cf.cf_expr <- Some expr;
@@ -143,7 +144,7 @@ struct
 						eexpr = TFunction({
 							tf_args = tf_args;
 							tf_type = ret;
-							tf_expr = mk_block ( mk_return { eexpr = TNew(cl,List.map snd dup_types, [ExprBuilder.make_int gen.gcon old_i pos; arr_decl] ); etype = TInst(cl, List.map snd dup_types); epos = pos } );
+							tf_expr = mk_block ( mk_return { eexpr = TNew(cl,List.map snd dup_types, [make_int gen.gcon.basic old_i pos; arr_decl] ); etype = TInst(cl, List.map snd dup_types); epos = pos } );
 						});
 						etype = ef_type;
 						epos = pos
@@ -157,9 +158,9 @@ struct
 					in
 					let cf = mk_class_field name actual_t true pos (Var { v_read = AccNormal; v_write = AccNever }) [] in
 					let args = if has_params then
-						[ExprBuilder.make_int gen.gcon old_i pos; null (gen.gclasses.nativearray t_dynamic) pos]
+						[make_int gen.gcon.basic old_i pos; null (gen.gclasses.nativearray t_dynamic) pos]
 					else
-						[ExprBuilder.make_int gen.gcon old_i pos]
+						[make_int gen.gcon.basic old_i pos]
 					in
 					cf.cf_meta <- [Meta.ReadOnly,[],pos];
 					cf.cf_expr <- Some {
@@ -287,7 +288,7 @@ struct
 					f
 				in
 				let cond_array = { (mk_field_access gen f "params" f.epos) with etype = gen.gclasses.nativearray t_dynamic } in
-				Codegen.index gen.gcon cond_array i e.etype e.epos
+				index gen.gcon.basic cond_array i e.etype e.epos
 			| _ ->
 				Type.map_expr run e
 		in

+ 14 - 14
src/generators/gencommon/enumToClass2.ml → src/codegen/gencommon/enumToClass2.ml

@@ -19,7 +19,7 @@
 open Common
 open Ast
 open Codegen
-open Codegen.ExprBuilder
+open Texpr.Builder
 open Type
 open Gencommon
 
@@ -37,7 +37,7 @@ let add_meta com en cl_enum =
 		let cf_meta = mk_field "__meta__" expr.etype expr.epos expr.epos in
 		cf_meta.cf_expr <- Some expr;
 		add_static cl_enum cf_meta;
-	) (Codegen.build_metadata com (TEnumDecl en));
+	) (Texpr.build_metadata com.basic (TEnumDecl en));
 
 type enclasses = {
 	base : tclass;
@@ -68,7 +68,7 @@ module EnumToClass2Modf = struct
 
 		(* add constructs field (for reflection) *)
 		if has_feature gen.gcon "Type.getEnumConstructs" then begin
-			let e_constructs = mk_array_decl basic.tstring (List.map (fun s -> make_string gen.gcon s pos) en.e_names) pos in
+			let e_constructs = mk_array_decl basic.tstring (List.map (fun s -> make_string gen.gcon.basic s pos) en.e_names) pos in
 			let cf_constructs = mk_field "__hx_constructs" e_constructs.etype pos pos in
 			cf_constructs.cf_kind <- Var { v_read = AccNormal; v_write = AccNever };
 			cf_constructs.cf_meta <- (Meta.ReadOnly,[],pos) :: (Meta.Protected,[],pos) :: cf_constructs.cf_meta;
@@ -105,7 +105,7 @@ module EnumToClass2Modf = struct
 			gen.gadd_to_module (TClassDecl cl_ctor) max_dep;
 
 			let esuper = mk (TConst TSuper) cl_enum_t pos in
-			let etag = make_string gen.gcon name pos in
+			let etag = make_string gen.gcon.basic name pos in
 			let efields = ref [] in
 			(match follow ef.ef_type with
 				| TFun(_, _) ->
@@ -146,7 +146,7 @@ module EnumToClass2Modf = struct
 						ctor_args := (ctor_arg_v, None) :: !ctor_args;
 
 						(* generate assignment for the constructor *)
-						let assign = Codegen.binop OpAssign efield (mk_local ctor_arg_v pos) t pos in
+						let assign = binop OpAssign efield (mk_local ctor_arg_v pos) t pos in
 						ctor_block := assign :: !ctor_block;
 
 						(* generate an enumEq check for the Equals method (TODO: extract this) *)
@@ -154,13 +154,13 @@ module EnumToClass2Modf = struct
 						let e_enumeq_check = mk (TCall (enumeq, [efield; eotherfield])) basic.tbool pos in
 						let e_param_check =
 							mk (TIf (mk (TUnop (Not, Prefix, e_enumeq_check)) basic.tbool pos,
-							         mk_return (make_bool gen.gcon false pos),
+							         mk_return (make_bool gen.gcon.basic false pos),
 							         None)
 							) basic.tvoid pos in
 						param_equal_checks := e_param_check :: !param_equal_checks;
 					) (List.rev params);
 
-					ctor_block := (mk (TCall(esuper,[make_int gen.gcon index pos])) basic.tvoid pos) :: !ctor_block;
+					ctor_block := (mk (TCall(esuper,[make_int gen.gcon.basic index pos])) basic.tvoid pos) :: !ctor_block;
 
 					let cf_ctor_t = TFun (params, basic.tvoid) in
 					let cf_ctor = mk_class_field "new" cf_ctor_t true pos (Method MethNormal) [] in
@@ -214,18 +214,18 @@ module EnumToClass2Modf = struct
 						let equals_exprs = ref (List.rev [
 							mk (TIf (
 								mk (TCall(refeq,[ethis;eother_local])) basic.tbool pos,
-								mk_return (make_bool gen.gcon true pos),
+								mk_return (make_bool gen.gcon.basic true pos),
 								None
 							)) basic.tvoid pos;
 							mk (TVar(other_en_v, Some ecast)) basic.tvoid pos;
 							mk (TIf(
 								mk (TBinop(OpEq,other_en_local,make_null cl_ctor_t pos)) basic.tbool pos,
-								mk_return (make_bool gen.gcon false pos),
+								mk_return (make_bool gen.gcon.basic false pos),
 								None
 							)) basic.tvoid pos;
 						]) in
 						equals_exprs := (List.rev !param_equal_checks) @ !equals_exprs;
-						equals_exprs := mk_return (make_bool gen.gcon true pos) :: !equals_exprs;
+						equals_exprs := mk_return (make_bool gen.gcon.basic true pos) :: !equals_exprs;
 
 						let cf_Equals_t = TFun([("other",false,t_dynamic)],basic.tbool) in
 						let cf_Equals = mk_class_field "Equals" cf_Equals_t true pos (Method MethNormal) [] in
@@ -250,7 +250,7 @@ module EnumToClass2Modf = struct
 								tf_args = [];
 								tf_type = basic.tint;
 								tf_expr = mk_block (mk_return (
-									mk (TCall(eparamsGetHashCode, [make_int gen.gcon index pos;etoString_args])) basic.tint pos
+									mk (TCall(eparamsGetHashCode, [make_int gen.gcon.basic index pos;etoString_args])) basic.tint pos
 								));
 							};
 							etype = cf_GetHashCode_t;
@@ -266,7 +266,7 @@ module EnumToClass2Modf = struct
 						eexpr = TFunction {
 							tf_args = [];
 							tf_type = basic.tvoid;
-							tf_expr = mk (TBlock [mk (TCall(esuper,[make_int gen.gcon index pos])) basic.tvoid pos]) basic.tvoid pos;
+							tf_expr = mk (TBlock [mk (TCall(esuper,[make_int gen.gcon.basic index pos])) basic.tvoid pos]) basic.tvoid pos;
 						};
 						etype = cf_ctor_t;
 						epos = pos;
@@ -349,7 +349,7 @@ module EnumToClass2Exprf = struct
 			let mk_converted_enum_index_access f =
 				let cl = (get_converted_enum_classes f.etype).base in
 				let e_enum = { f with etype = TInst (cl, []) } in
-				Codegen.field e_enum "_hx_index" com.basic.tint e.epos
+				field e_enum "_hx_index" com.basic.tint e.epos
 			in
 			match e.eexpr with
 			| TEnumIndex f ->
@@ -378,7 +378,7 @@ module EnumToClass2Exprf = struct
 				(match ef.ef_type with
 				| TFun (params, _) ->
 					let fname, _, _ = List.nth params i in
-					Codegen.field ecast fname e.etype e.epos
+					field ecast fname e.etype e.epos
 				| _ -> assert false)
 			| _ ->
 				Type.map_expr run e

+ 1 - 1
src/generators/gencommon/expressionUnwrap.ml → src/codegen/gencommon/expressionUnwrap.ml

@@ -494,7 +494,7 @@ let try_call_unwrap_statement com handle_cast problematic_expression_unwrap (add
 				| _ when ExtType.is_void e.etype ->
 					{ e with eexpr = TBlock([e; { e with eexpr = TReturn None }]) }
 				| _ ->
-					Codegen.mk_return e
+					Texpr.Builder.mk_return e
 		) e )
 	in
 

+ 0 - 0
src/generators/gencommon/filterClosures.ml → src/codegen/gencommon/filterClosures.ml


+ 2 - 2
src/generators/gencommon/fixOverrides.ml → src/codegen/gencommon/fixOverrides.ml

@@ -138,7 +138,7 @@ let run ~explicit_fn_name ~get_vmtype gen =
 									eexpr = TFunction({
 										tf_args = List.map (fun v -> v,None) vars;
 										tf_type = r2;
-										tf_expr = if is_void then call else (mk_return (mk_cast r2 call));
+										tf_expr = if is_void then call else (Texpr.Builder.mk_return (mk_cast r2 call));
 									});
 									etype = real_ftype;
 									epos = p;
@@ -208,7 +208,7 @@ let run ~explicit_fn_name ~get_vmtype gen =
 								let old_args, old_ret = get_fun f.cf_type in
 								let args, ret = get_fun t in
 								let tf_args = List.rev new_args in
-								let f3_mk_return = if ExtType.is_void ret then (fun e -> e) else (fun e -> mk_return (mk_cast ret e)) in
+								let f3_mk_return = if ExtType.is_void ret then (fun e -> e) else (fun e -> Texpr.Builder.mk_return (mk_cast ret e)) in
 								f3.cf_expr <- Some {
 									eexpr = TFunction({
 										tf_args = tf_args;

+ 13 - 13
src/generators/gencommon.ml → src/codegen/gencommon/gencommon.ml

@@ -108,7 +108,7 @@ let follow_once t =
 		| Some t -> t
 		| _ -> t_dynamic) (* avoid infinite loop / should be the same in this context *)
 	| TLazy f ->
-		!f()
+		lazy_type f
 	| TType (t,tl) ->
 		apply_params t.t_params tl t.t_type
 	| TAbstract({a_path = [],"Null"},[t]) ->
@@ -120,7 +120,7 @@ let t_empty = TAnon({ a_fields = PMap.empty; a_status = ref Closed })
 
 let alloc_var n t = Type.alloc_var n t null_pos
 
-let mk_local = ExprBuilder.make_local
+let mk_local = Texpr.Builder.make_local
 
 (* the undefined is a special var that works like null, but can have special meaning *)
 let undefined =
@@ -136,7 +136,7 @@ let debug_expr = s_expr debug_type
 
 let debug_mode = ref false
 let trace s = if !debug_mode then print_endline s else ()
-let timer name = if !debug_mode then Common.timer name else fun () -> ()
+let timer name = if !debug_mode then Timer.timer name else fun () -> ()
 
 let is_string t =
 	match follow t with
@@ -164,7 +164,7 @@ let anon_class t =
 			| Statics cl -> TClassDecl cl
 			| AbstractStatics a -> TAbstractDecl a
 			| _ -> assert false)
-	| TLazy f -> t_to_md (!f())
+	| TLazy f -> t_to_md (lazy_type f)
 	| TMono r -> (match !r with | Some t -> t_to_md t | None -> assert false)
 	| _ -> assert false
 
@@ -186,7 +186,7 @@ let mk_castfast t e = { e with eexpr = TCast(e, Some (TClassDecl null_class)); e
 
 let mk_static_field_access_infer cl field pos params =
 	try
-		let e_type = ExprBuilder.make_static_this cl pos in
+		let e_type = Texpr.Builder.make_static_this cl pos in
 		let cf = PMap.find field cl.cl_statics in
 		let t = if params = [] then cf.cf_type else apply_params cf.cf_params params cf.cf_type in
 		mk (TField(e_type, FStatic(cl, cf))) t pos
@@ -302,7 +302,7 @@ class ['tp, 'ret] rule_dispatcher name =
 				if key < priority then begin
 					let q = Hashtbl.find tbl key in
 					Stack.iter (fun (n, rule) ->
-						let t = if !debug_mode then Common.timer [("rule dispatcher rule: " ^ n)] else fun () -> () in
+						let t = if !debug_mode then Timer.timer [("rule dispatcher rule: " ^ n)] else fun () -> () in
 						let r = rule(tp) in
 						t();
 						if is_some r then begin ret := r; raise Exit end
@@ -362,7 +362,7 @@ class ['tp] rule_map_dispatcher name = object(self)
 				let q = Hashtbl.find tbl key in
 				Stack.iter (fun (n, rule) ->
 					trace ("running rule " ^ n);
-					let t = if !debug_mode then Common.timer [("rule map dispatcher rule: " ^ n)] else fun () -> () in
+					let t = if !debug_mode then Timer.timer [("rule map dispatcher rule: " ^ n)] else fun () -> () in
 					cur := rule !cur;
 					t();
 				) q
@@ -655,7 +655,7 @@ let init_ctx gen =
 			| Some t -> follow_f t
 			| _ -> Some t)
 		| TLazy f ->
-			follow_f (!f())
+			follow_f (lazy_type f)
 		| TType (t,tl) ->
 			follow_f (apply_params t.t_params tl t.t_type)
 		| TAbstract({a_path = [],"Null"},[t]) ->
@@ -719,7 +719,7 @@ let run_filters gen =
 	let has_errors = ref false in
 	gen.gcon.error <- (fun msg pos -> has_errors := true; last_error msg pos);
 	(* first of all, we have to make sure that the filters won't trigger a major Gc collection *)
-	let t = Common.timer ["gencommon_filters"] in
+	let t = Timer.timer ["gencommon_filters"] in
 	(if Common.defined gen.gcon Define.GencommonDebug then debug_mode := true else debug_mode := false);
 	let run_filters (filter : texpr rule_map_dispatcher) =
 		let rec loop acc mds =
@@ -815,7 +815,7 @@ let write_file gen w source_dir path extension out_files =
 	let t = timer ["write";"file"] in
 	let s_path = source_dir	^ "/" ^ (snd path) ^ "." ^ (extension) in
 	(* create the folders if they don't exist *)
-	mkdir_from_path s_path;
+	Path.mkdir_from_path s_path;
 
 	let contents = SourceWriter.contents w in
 	let should_write = if not (Common.defined gen.gcon Define.ReplaceFiles) && Sys.file_exists s_path then begin
@@ -870,7 +870,7 @@ let dump_descriptor gen name path_s module_s =
 	PMap.iter (fun name _ ->
 		SourceWriter.write w name;
 		SourceWriter.newline w
-	) gen.gcon.defines;
+	) gen.gcon.defines.Define.values;
 	SourceWriter.write w "end defines";
 	SourceWriter.newline w;
 	(* dump all defines with their values; keeping the old defines for compatibility *)
@@ -881,7 +881,7 @@ let dump_descriptor gen name path_s module_s =
 		SourceWriter.write w "=";
 		SourceWriter.write w v;
 		SourceWriter.newline w
-	) gen.gcon.defines;
+	) gen.gcon.defines.Define.values;
 	SourceWriter.write w "end defines_data";
 	SourceWriter.newline w;
 	(* dump all generated types *)
@@ -1074,7 +1074,7 @@ let rec replace_mono t =
 	| TAnon _
 	| TDynamic _ -> ()
 	| TLazy f ->
-		replace_mono (!f())
+		replace_mono (lazy_type f)
 
 (* helper *)
 let mk_class_field name t public pos kind params =

+ 1 - 1
src/generators/gencommon/hardNullableSynf.ml → src/codegen/gencommon/hardNullableSynf.ml

@@ -53,7 +53,7 @@ let rec is_null_t gen t = match gen.greal_type t with
 
 		Some (take_off_null of_t)
 	| TMono r -> (match !r with | Some t -> is_null_t gen t | None -> None)
-	| TLazy f -> is_null_t gen (!f())
+	| TLazy f -> is_null_t gen (lazy_type f)
 	| TType (t, tl) ->
 		is_null_t gen (apply_params t.t_params tl t.t_type)
 	| _ -> None

+ 3 - 2
src/generators/gencommon/initFunction.ml → src/codegen/gencommon/initFunction.ml

@@ -19,6 +19,7 @@
 open Common
 open Type
 open Codegen
+open Texpr.Builder
 open Gencommon
 
 (*
@@ -88,14 +89,14 @@ let handle_class com cl =
 				| Some e ->
 					(match cf.cf_params with
 					| [] ->
-						let var = mk (TField (ExprBuilder.make_static_this cl cf.cf_pos, FStatic(cl,cf))) cf.cf_type cf.cf_pos in
+						let var = mk (TField (make_static_this cl cf.cf_pos, FStatic(cl,cf))) cf.cf_type cf.cf_pos in
 						let ret = binop Ast.OpAssign var e cf.cf_type cf.cf_pos in
 						cf.cf_expr <- None;
 						ret :: acc
 					| _ ->
 						let params = List.map (fun _ -> t_dynamic) cf.cf_params in
 						let fn = apply_params cf.cf_params params in
-						let var = mk (TField (ExprBuilder.make_static_this cl cf.cf_pos, FStatic(cl,cf))) (fn cf.cf_type) cf.cf_pos in
+						let var = mk (TField (make_static_this cl cf.cf_pos, FStatic(cl,cf))) (fn cf.cf_type) cf.cf_pos in
 						let rec change_expr e =
 							Type.map_expr_type change_expr fn (fun v -> v.v_type <- fn v.v_type; v) e
 						in

+ 0 - 0
src/generators/gencommon/intDivisionSynf.ml → src/codegen/gencommon/intDivisionSynf.ml


+ 0 - 0
src/generators/gencommon/interfaceProps.ml → src/codegen/gencommon/interfaceProps.ml


+ 0 - 0
src/generators/gencommon/interfaceVarsDeleteModf.ml → src/codegen/gencommon/interfaceVarsDeleteModf.ml


+ 1 - 1
src/generators/gencommon/normalize.ml → src/codegen/gencommon/normalize.ml

@@ -63,7 +63,7 @@ let rec filter_param t =
 	| TDynamic _ ->
 		t
 	| TLazy f ->
-		filter_param (!f())
+		filter_param (lazy_type f)
 
 let init_expr_filter allowed_metas =
 	let rec run e =

+ 0 - 0
src/generators/gencommon/objectDeclMap.ml → src/codegen/gencommon/objectDeclMap.ml


+ 2 - 2
src/generators/gencommon/overloadingConstructor.ml → src/codegen/gencommon/overloadingConstructor.ml

@@ -106,7 +106,7 @@ let replace_super_call com c tl with_params me p follow_type =
 	{
 		eexpr = TCall(
 			{
-				eexpr = TField(ExprBuilder.make_static_this sup p, FStatic(sup,cf));
+				eexpr = TField(Texpr.Builder.make_static_this sup p, FStatic(sup,cf));
 				etype = apply_params cf.cf_params stl cf.cf_type;
 				epos = p
 			},
@@ -205,7 +205,7 @@ let create_static_ctor com ~empty_ctor_expr cl ctor follow_type =
 				eexpr = TCall(
 					{
 						eexpr = TField(
-							ExprBuilder.make_static_this cl p,
+							Texpr.Builder.make_static_this cl p,
 							FStatic(cl, static_ctor));
 						etype = apply_params static_ctor.cf_params (List.map snd cl.cl_params) static_ctor.cf_type;
 						epos = p

+ 6 - 5
src/generators/gencommon/realTypeParams.ml → src/codegen/gencommon/realTypeParams.ml

@@ -21,6 +21,7 @@ open Common
 open Ast
 open Type
 open Codegen
+open Texpr.Builder
 open Gencommon
 
 (* ******************************************* *)
@@ -405,7 +406,7 @@ struct
 		Will also look for previous cast() definitions and override them, to reflect the current type and fields
 
 		FIXME: this function still doesn't support generics that extend generics, and are cast as one of its subclasses. This needs to be taken care, by
-		looking at previous superclasses and whenever a generic class is found, its cast argument must be overriden. the toughest part is to know how to type
+		looking at previous superclasses and whenever a generic class is found, its cast argument must be overridden. the toughest part is to know how to type
 		the current type correctly.
 	*)
 	let create_cast_cfield gen cl name =
@@ -468,12 +469,12 @@ struct
 						t_cf
 						pos
 				in
-				[ExprBuilder.make_string gen.gcon cf.cf_name pos], expr
+				[make_string gen.gcon.basic cf.cf_name pos], expr
 			) fields
 		in
 
 		let mk_typehandle =
-			(fun cl -> mk (TCall (mk (TIdent "__typeof__") t_dynamic pos, [ExprBuilder.make_static_this cl pos])) t_dynamic pos)
+			(fun cl -> mk (TCall (mk (TIdent "__typeof__") t_dynamic pos, [make_static_this cl pos])) t_dynamic pos)
 		in
 		let mk_eq cl1 cl2 =
 			binop OpEq (mk_typehandle cl1) (mk_typehandle cl2) basic.tbool pos
@@ -503,7 +504,7 @@ struct
 				(* var fields = Reflect.fields(this); *)
 				mk (TVar (fields_var, Some (gen.gtools.r_fields true this))) basic.tvoid pos;
 				(* var i = 0; *)
-				mk (TVar (i_var, Some (ExprBuilder.make_int gen.gcon 0 pos))) basic.tvoid pos;
+				mk (TVar (i_var, Some (make_int gen.gcon.basic 0 pos))) basic.tvoid pos;
 				(* while (i < fields.length) *)
 				mk (TWhile (
 					binop OpLt local_i (mk_field_access gen local_fields "length" pos) basic.tbool pos,
@@ -711,7 +712,7 @@ let default_implementation gen (dyn_tparam_cast:texpr->t->texpr) ifaces =
 							false)
 						| _ -> false
 					in
-					let unifies = unifies && not (PMap.mem "cs_safe_casts" gen.gcon.defines) in
+					let unifies = unifies && not (PMap.mem "cs_safe_casts" gen.gcon.defines.Define.values) in
 					(match follow t with
 						| TInst(cl, p1 :: pl) when is_hxgeneric (TClassDecl cl) && not unifies && not (Meta.has Meta.Enum cl.cl_meta) ->
 							let iface = Hashtbl.find ifaces cl.cl_path in

+ 18 - 17
src/generators/gencommon/reflectionCFs.ml → src/codegen/gencommon/reflectionCFs.ml

@@ -21,6 +21,7 @@ open Common
 open Ast
 open Type
 open Codegen
+open Texpr.Builder
 open Gencommon
 open ClosuresToClass
 
@@ -238,7 +239,7 @@ let switch_case ctx pos field_name =
 			let i = hash_field_i32 ctx pos field_name in
 			mk (TConst (TInt i)) ctx.rcf_gen.gcon.basic.tint pos
 		| false ->
-			ExprBuilder.make_string ctx.rcf_gen.gcon field_name pos
+			make_string ctx.rcf_gen.gcon.basic field_name pos
 
 let call_super ctx fn_args ret_t cf cl this_t pos =
 	{
@@ -264,7 +265,7 @@ let enumerate_dynamic_fields ctx cl when_found base_arr =
 		let convert_str e = if ctx.rcf_optimize then ctx.rcf_lookup_function e else e in
 		let tmpinc = { eexpr = TUnop(Ast.Increment, Ast.Postfix, mk_local vtmp pos); etype = basic.tint; epos = pos } in
 		[
-			{ eexpr = TBinop(OpAssign, mk_local vtmp pos, ExprBuilder.make_int ctx.rcf_gen.gcon 0 pos); etype = basic.tint; epos = pos };
+			{ eexpr = TBinop(OpAssign, mk_local vtmp pos, make_int ctx.rcf_gen.gcon.basic 0 pos); etype = basic.tint; epos = pos };
 			{
 				eexpr = TWhile (
 					{ eexpr = TBinop(Ast.OpLt, mk_local vtmp pos, len); etype = basic.tbool; epos = pos },
@@ -378,12 +379,12 @@ let abstract_dyn_lookup_implementation ctx this field_local hash_local may_value
 				let vconflict = alloc_var "conflict" conflict_ctx.t in
 				let local_conflict = mk_local vconflict pos in
 				[mk (TIf (
-					mk (TBinop (OpLt, hash_local, ExprBuilder.make_int gen.gcon 0 pos)) basic.tbool pos,
+					mk (TBinop (OpLt, hash_local, make_int gen.gcon.basic 0 pos)) basic.tbool pos,
 					mk (TBlock [
 						mk (TVar (vconflict, Some (conflict_ctx.get_conflict ehead hash_local field_local))) basic.tvoid pos;
 						mk (TIf (
 							mk (TBinop (OpNotEq, local_conflict, mk (TConst TNull) local_conflict.etype pos)) basic.tbool pos,
-							mk_return (Codegen.field local_conflict "value" t_dynamic pos),
+							mk_return (field local_conflict "value" t_dynamic pos),
 							None
 						)) basic.tvoid pos;
 					]) basic.tvoid pos,
@@ -453,7 +454,7 @@ let abstract_dyn_lookup_implementation ctx this field_local hash_local may_value
 					let conflict_ctx = Option.get ctx.rcf_hash_conflict_ctx in
 					let ehead = mk_this (mk_internal_name "hx" "conflicts") conflict_ctx.t in
 					[mk (TIf (
-						mk (TBinop (OpLt, hash_local, ExprBuilder.make_int gen.gcon 0 pos)) basic.tbool pos,
+						mk (TBinop (OpLt, hash_local, make_int gen.gcon.basic 0 pos)) basic.tbool pos,
 						conflict_ctx.set ehead hash_local field_local value_local,
 						Some (mk (TBlock block) basic.tvoid pos)
 					)) basic.tvoid pos]
@@ -538,7 +539,7 @@ let get_delete_field ctx cl is_dynamic =
 			let conflict_ctx = Option.get ctx.rcf_hash_conflict_ctx in
 			let ehead = mk_this (mk_internal_name "hx" "conflicts") conflict_ctx.t in
 			(mk (TIf (
-				binop OpLt local_switch_var (ExprBuilder.make_int gen.gcon 0 pos) basic.tbool pos,
+				binop OpLt local_switch_var (make_int gen.gcon.basic 0 pos) basic.tbool pos,
 				mk_return (conflict_ctx.delete ehead local_switch_var local_name),
 				None
 			)) basic.tvoid pos) :: common
@@ -693,14 +694,14 @@ let implement_dynamic_object_ctor ctx cl =
 		if ctx.rcf_optimize then begin
 			mk (TConst (TInt (hash_field_i32 ctx pos s))) basic.tint pos
 		end else begin
-			ExprBuilder.make_string gen.gcon s pos
+			make_string gen.gcon.basic s pos
 		end
 	in
 
 	let do_objdecl e objdecl =
 		let exprs_before = ref [] in
 		let rec change_exprs decl acc = match decl with
-			| (name,expr) :: tl ->
+			| ((name,_,_),expr) :: tl ->
 				if is_side_effects_free expr then
 					change_exprs tl ((name,expr) :: acc)
 				else begin
@@ -837,7 +838,7 @@ let implement_final_lookup ctx cl =
 
 	let mk_throw str pos =
 		let e = ctx.rcf_mk_exception str pos in
-		ExprBuilder.make_throw e pos
+		make_throw e pos
 	in
 
 	(*
@@ -1219,7 +1220,7 @@ let implement_getFields ctx cl =
 				| Var _
 				| Method MethDynamic when not (List.memq cf cl.cl_overrides) ->
 					has_value := true;
-					mk_push (ExprBuilder.make_string gen.gcon cf.cf_name pos)
+					mk_push (make_string gen.gcon.basic cf.cf_name pos)
 				| _ -> null basic.tvoid pos
 		)
 	in
@@ -1338,7 +1339,7 @@ let implement_invokeField ctx slow_invoke cl =
 			(cases,
 				mk_return (
 					mk_this_call cf (List.map (fun (name,_,t) ->
-						let ret = { eexpr = TArray(dyn_arg_local, ExprBuilder.make_int ctx.rcf_gen.gcon !i pos); etype = t_dynamic; epos = pos } in
+						let ret = { eexpr = TArray(dyn_arg_local, make_int ctx.rcf_gen.gcon.basic !i pos); etype = t_dynamic; epos = pos } in
 						incr i;
 						ret
 					) (fst (get_fun (cf.cf_type))))
@@ -1367,9 +1368,9 @@ let implement_invokeField ctx slow_invoke cl =
 				let tf_args, _ = field_type_args ctx pos in
 				let tf_args, args = fun_args tf_args, field_args_exprs in
 
-				let tf_args, args = tf_args @ ["throwErrors",false, basic.tbool],       args @ [ExprBuilder.make_bool gen.gcon true pos] in
-				let tf_args, args = tf_args @ ["isCheck", false, basic.tbool],          args @ [ExprBuilder.make_bool gen.gcon false pos] in
-				let tf_args, args = tf_args @ ["handleProperties", false, basic.tbool], args @ [ExprBuilder.make_bool gen.gcon false pos] in
+				let tf_args, args = tf_args @ ["throwErrors",false, basic.tbool],       args @ [make_bool gen.gcon.basic true pos] in
+				let tf_args, args = tf_args @ ["isCheck", false, basic.tbool],          args @ [make_bool gen.gcon.basic false pos] in
+				let tf_args, args = tf_args @ ["handleProperties", false, basic.tbool], args @ [make_bool gen.gcon.basic false pos] in
 
 				mk (TCall ({ (mk_field_access gen this fun_name pos) with etype = TFun(tf_args, t_dynamic) }, args)) t_dynamic pos
 			end in
@@ -1549,7 +1550,7 @@ let implement_closure_cl ctx cl =
 			tf_args = tf_args;
 			tf_type = basic.tvoid;
 			tf_expr = { eexpr = TBlock({
-				eexpr = TCall({ eexpr = TConst(TSuper); etype = TInst(cl,[]); epos = pos }, [ExprBuilder.make_int ctx.rcf_gen.gcon (-1) pos; ExprBuilder.make_int ctx.rcf_gen.gcon (-1) pos]);
+				eexpr = TCall({ eexpr = TConst(TSuper); etype = TInst(cl,[]); epos = pos }, [make_int ctx.rcf_gen.gcon.basic (-1) pos; make_int ctx.rcf_gen.gcon.basic (-1) pos]);
 				etype = basic.tvoid;
 				epos = pos
 			} :: ctor_body); etype = basic.tvoid; epos = pos }
@@ -1561,7 +1562,7 @@ let implement_closure_cl ctx cl =
 	cl.cl_constructor <- Some ctor_cf;
 
 	let closure_fun eclosure e field is_static =
-		let f = ExprBuilder.make_string gen.gcon field eclosure.epos in
+		let f = make_string gen.gcon.basic field eclosure.epos in
 		let args = if ctx.rcf_optimize then [ f; { eexpr = TConst(TInt (hash_field_i32 ctx eclosure.epos field)); etype = basic.tint; epos = eclosure.epos } ] else [ f ] in
 		let args = args @ [ mk_cast (TInst(ctx.rcf_object_iface, [])) e ] in
 
@@ -1576,7 +1577,7 @@ let get_closure_func ctx closure_cl =
 		mk_cast eclosure.etype { eclosure with
 			eexpr = TNew(closure_cl, [], [
 				e;
-				ExprBuilder.make_string gen.gcon field eclosure.epos
+				make_string gen.gcon.basic field eclosure.epos
 			] @ (
 				if ctx.rcf_optimize then [ { eexpr = TConst(TInt (hash_field_i32 ctx eclosure.epos field)); etype = basic.tint; epos = eclosure.epos } ] else []
 			));

+ 0 - 0
src/generators/gencommon/renameTypeParameters.ml → src/codegen/gencommon/renameTypeParameters.ml


+ 0 - 0
src/generators/gencommon/setHXGen.ml → src/codegen/gencommon/setHXGen.ml


+ 1 - 1
src/generators/gencommon/switchToIf.ml → src/codegen/gencommon/switchToIf.ml

@@ -137,7 +137,7 @@ let configure gen (should_convert:texpr->bool) =
 						let fields = Hashtbl.create (List.length real_enum.e_names) in
 						PMap.iter (fun _ ef -> Hashtbl.add fields ef.ef_index ef) real_enum.e_constrs;
 
-						let enum_expr = ExprBuilder.make_typeexpr (TEnumDecl real_enum) e.epos in
+						let enum_expr = Texpr.Builder.make_typeexpr (TEnumDecl real_enum) e.epos in
 						let cases = List.map (fun (patterns, body) ->
 							let patterns = List.map (fun e ->
 								match e.eexpr with

+ 0 - 0
src/generators/gencommon/tArrayTransform.ml → src/codegen/gencommon/tArrayTransform.ml


+ 0 - 0
src/generators/gencommon/unnecessaryCastsRemoval.ml → src/codegen/gencommon/unnecessaryCastsRemoval.ml


+ 1 - 1
src/generators/gencommon/unreachableCodeEliminationSynf.ml → src/codegen/gencommon/unreachableCodeEliminationSynf.ml

@@ -129,7 +129,7 @@ let init com java_mode =
 			| TFunction tf ->
 				let changed, kind = process_expr tf.tf_expr in
 				let changed = if not (ExtType.is_void tf.tf_type) && kind <> BreaksFunction then
-					Type.concat changed (Codegen.mk_return (null tf.tf_type expr.epos))
+					Type.concat changed (Texpr.Builder.mk_return (null tf.tf_type expr.epos))
 				else
 					changed
 				in

+ 10 - 8
src/generators/genxml.ml → src/codegen/genxml.ml

@@ -123,7 +123,7 @@ let rec gen_type ?(values=None) t =
 		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())
+	| TLazy f -> gen_type (lazy_type f)
 
 and gen_type_decl n t pl =
 	let i = t_infos t in
@@ -132,7 +132,7 @@ and gen_type_decl n t pl =
 and gen_field att f =
 	let add_get_set acc name att =
 		match acc with
-		| AccNormal | AccResolve | AccRequire _ -> att
+		| AccNormal | AccResolve | AccRequire _ | AccCtor -> att
 		| AccNo | AccNever -> (name, "null") :: att
 		| AccCall -> (name,"accessor") :: att
 		| AccInline -> (name,"inline") :: att
@@ -171,7 +171,9 @@ and gen_field att f =
 		with Not_found ->
 			cf.cf_name
 	in
-	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 att = if f.cf_public then ("public","1") :: att else att in
+	let att = if (Meta.has Meta.Final) f.cf_meta then ("final","1") :: att else att in
+	node (field_name f) 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
@@ -286,10 +288,10 @@ let rec write_xml ch tabs x =
 		IO.printf ch "<![CDATA[%s]]>" s
 
 let generate com file =
-	let t = Common.timer ["generate";"xml"] in
+	let t = Timer.timer ["generate";"xml"] in
 	let x = node "haxe" [] (List.map (gen_type_decl com true) (List.filter (fun t -> not (Meta.has Meta.NoDoc (t_infos t).mt_meta)) com.types)) in
 	t();
-	let t = Common.timer ["write";"xml"] in
+	let t = Timer.timer ["write";"xml"] in
 	let ch = IO.output_channel (open_out_bin file) in
 	IO.printf ch "<!-- This file can be parsed by haxe.rtti.XmlParser -->\n";
 	write_xml ch "" x;
@@ -356,7 +358,7 @@ let generate_type com t =
 			| None -> t
 			| Some t -> notnull t)
 		| TLazy f ->
-			notnull ((!f)())
+			notnull (lazy_type f)
 		| TAbstract ({ a_path = [],"Null" },[t]) ->
 			t
 		| _ ->
@@ -385,7 +387,7 @@ let generate_type com t =
 			let fields = PMap.fold (fun f acc -> (f.cf_name ^ " : " ^ stype f.cf_type) :: acc) a.a_fields [] in
 			"{" ^ String.concat ", " fields ^ "}"
 		| TLazy f ->
-			stype ((!f)())
+			stype (lazy_type f)
 		| TDynamic t2 ->
 			if t == t2 then "Dynamic" else "Dynamic<" ^ stype t2 ^ ">"
 		| TFun ([],ret) ->
@@ -399,7 +401,7 @@ let generate_type com t =
 			| None -> stype t
 			| Some t -> ftype t)
 		| TLazy f ->
-			ftype ((!f)())
+			ftype (lazy_type f)
 		| TFun _ ->
 			"(" ^ stype t ^ ")"
 		| _ ->

+ 6 - 6
src/typing/java.ml → src/codegen/java.ml

@@ -356,7 +356,7 @@ let convert_java_enum ctx p pe =
 							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
+		if PMap.mem "java_loader_debug" ctx.jcom.defines.Define.values 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);
 
 		{
@@ -398,7 +398,7 @@ let convert_java_enum ctx p pe =
 				[convert_java_enum ctx p jc]
 		| false ->
 			let flags = ref [HExtern] in
-			if PMap.mem "java_loader_debug" ctx.jcom.defines then begin
+			if PMap.mem "java_loader_debug" ctx.jcom.defines.Define.values 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;
@@ -728,14 +728,14 @@ let fix_overrides_jclass com cls =
 			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 overridden = 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
+							overridden := { f with jf_flags = jm.jf_flags } :: !overridden
 						end;
 						ret
 					) cls.cmethods then
@@ -743,7 +743,7 @@ let fix_overrides_jclass com cls =
 					else
 						jm
 				) cmethods in
-				!overriden @ cmethods
+				!overridden @ cmethods
 			end else
 				cmethods
 			in
@@ -1144,7 +1144,7 @@ let add_java_lib com file std =
 
 let before_generate con =
 	let java_ver = try
-			int_of_string (PMap.find "java_ver" con.defines)
+			int_of_string (PMap.find "java_ver" con.defines.Define.values)
 		with | Not_found ->
 			Common.define_value con Define.JavaVer "7";
 			7

+ 2 - 2
src/typing/overloads.ml → src/codegen/overloads.ml

@@ -14,7 +14,7 @@ let same_overload_args ?(get_vmtype) t1 t2 f1 f2 =
 			| Some t -> follow_skip_null t
 			| _ -> t)
 		| TLazy f ->
-			follow_skip_null (!f())
+			follow_skip_null (lazy_type f)
 		| TAbstract ({ a_path = [],"Null" } as a, [p]) ->
 			TAbstract(a,[follow p])
 		| TType (t,tl) ->
@@ -87,7 +87,7 @@ struct
 			| None -> t_dynamic)
 		| TAnon _ -> t_dynamic
 		| TDynamic _ -> t
-		| TLazy f -> simplify_t (!f())
+		| TLazy f -> simplify_t (lazy_type f)
 		| TFun _ -> t
 
 	(* rate type parameters *)

+ 3 - 3
src/typing/swfLoader.ml → src/codegen/swfLoader.ml

@@ -235,7 +235,7 @@ let build_class com c file =
 							| HVInt i | HVUInt i ->
 								Some (Int (Int32.to_string i))
 							| HVFloat f ->
-								Some (Float (float_repres f))
+								Some (Float (Numeric.float_repres f))
 							) in
 							match v with
 							| None -> None
@@ -358,7 +358,7 @@ let build_class com c file =
 	(path.tpackage, [(EClass class_data,pos)])
 
 let extract_data (_,tags) =
-	let t = Common.timer ["read";"swf"] in
+	let t = Timer.timer ["read";"swf"] in
 	let h = Hashtbl.create 0 in
 	let rec loop_field f =
 		match f.hlf_kind with
@@ -450,7 +450,7 @@ let remove_debug_infos as3 =
 	As3hlparse.flatten (List.map loop_static hl)
 
 let parse_swf com file =
-	let t = Common.timer ["read";"swf"] in
+	let t = Timer.timer ["read";"swf"] in
 	let is_swc = file_extension file = "swc" || file_extension file = "ane" in
 	let file = (try Common.find_file com file with Not_found -> failwith ((if is_swc then "SWC" else "SWF") ^ " Library not found : " ^ file)) in
 	let ch = if is_swc then begin

+ 4 - 3
src/display/displayOutput.ml → src/compiler/displayOutput.ml

@@ -1,5 +1,6 @@
 open Globals
 open Common
+open Timer
 open Common.DisplayMode
 open Type
 open Display
@@ -16,12 +17,12 @@ let htmlescape s =
 
 let get_timer_fields start_time =
 	let tot = ref 0. in
-	Hashtbl.iter (fun _ t -> tot := !tot +. t.total) Common.htimers;
+	Hashtbl.iter (fun _ t -> tot := !tot +. t.total) Timer.htimers;
 	let fields = [("@TOTAL", Printf.sprintf "%.3fs" (get_time() -. start_time))] in
 	if !tot > 0. then
 		Hashtbl.fold (fun _ t acc ->
 			((String.concat "." t.id),(Printf.sprintf "%.3fs (%.0f%%)" t.total (t.total *. 100. /. !tot))) :: acc
-		) Common.htimers fields
+		) Timer.htimers fields
 	else
 		fields
 
@@ -786,7 +787,7 @@ let process_global_display_mode com tctx = match com.display.dms_kind with
 		let symbols = match CompilationServer.get() with
 			| None -> symbols
 			| Some cs ->
-				let l = CompilationServer.get_context_files cs ((get_signature com) :: (match com.get_macros() with None -> [] | Some com -> [get_signature com])) in
+				let l = CompilationServer.get_context_files cs ((Define.get_signature com.defines) :: (match com.get_macros() with None -> [] | Some com -> [Define.get_signature com.defines])) in
 				List.fold_left (fun acc (file,data) ->
 					print_endline (Printf.sprintf "%s %b" file (is_display_file file));
 					if (filter <> None || is_display_file file) then

+ 40 - 67
src/compiler/main.ml

@@ -54,18 +54,8 @@ exception Abort
 let executable_path() =
 	Extc.executable_path()
 
-let format msg p =
-	if p = null_pos then
-		msg
-	else begin
-		let error_printer file line = sprintf "%s:%d:" file line in
-		let epos = Lexer.get_error_pos error_printer p in
-		let msg = String.concat ("\n" ^ epos ^ " : ") (ExtString.String.nsplit msg "\n") in
-		sprintf "%s : %s" epos msg
-	end
-
-let message ctx msg p =
-	ctx.messages <- format msg p :: ctx.messages
+let message ctx msg =
+	ctx.messages <- msg :: ctx.messages
 
 let deprecated = []
 
@@ -83,12 +73,12 @@ let limit_string s offset =
 
 let error ctx msg p =
 	let msg = try List.assoc msg deprecated with Not_found -> msg in
-	message ctx msg p;
+	message ctx (CMError(msg,p));
 	ctx.has_error <- true
 
 let reserved_flags = [
 	"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python";
-	"as3";"swc";"macro";"sys"
+	"as3";"swc";"macro";"sys";"static"
 	]
 
 let delete_file f = try Sys.remove f with _ -> ()
@@ -109,7 +99,7 @@ let expand_env ?(h=None) path  =
 
 let add_libs com libs =
 	let call_haxelib() =
-		let t = Common.timer ["haxelib"] in
+		let t = Timer.timer ["haxelib"] in
 		let cmd = "haxelib path " ^ String.concat " " libs in
 		let pin, pout, perr = Unix.open_process_full cmd (Unix.environment()) in
 		let lines = Std.input_list pin in
@@ -158,7 +148,7 @@ let run_command ctx cmd =
 	let h = Hashtbl.create 0 in
 	Hashtbl.add h "__file__" ctx.com.file;
 	Hashtbl.add h "__platform__" (platform_name ctx.com.platform);
-	let t = Common.timer ["command"] in
+	let t = Timer.timer ["command"] in
 	let cmd = expand_env ~h:(Some h) cmd in
 	let len = String.length cmd in
 	if len > 3 && String.sub cmd 0 3 = "cd " then begin
@@ -180,7 +170,7 @@ let run_command ctx cmd =
 	let result = (match Unix.close_process_full (pout,pin,perr) with Unix.WEXITED c | Unix.WSIGNALED c | Unix.WSTOPPED c -> c) in
 	let serr = binary_string (Buffer.contents berr) in
 	let sout = binary_string (Buffer.contents bout) in
-	if serr <> "" then ctx.messages <- (if serr.[String.length serr - 1] = '\n' then String.sub serr 0 (String.length serr - 1) else serr) :: ctx.messages;
+	if serr <> "" then ctx.messages <- CMError((if serr.[String.length serr - 1] = '\n' then String.sub serr 0 (String.length serr - 1) else serr),null_pos) :: ctx.messages;
 	if sout <> "" then ctx.com.print (sout ^ "\n");
 	t();
 	result
@@ -218,7 +208,7 @@ module Initialize = struct
 				add_std "neko";
 				"n"
 			| Js ->
-				if not (PMap.exists (fst (Define.infos Define.JqueryVer)) com.defines) then
+				if not (PMap.exists (fst (Define.infos Define.JqueryVer)) com.defines.Define.values) then
 					Common.define_value com Define.JqueryVer "11204";
 
 				let es_version =
@@ -242,14 +232,7 @@ module Initialize = struct
 				add_std "lua";
 				"lua"
 			| Php ->
-				if Common.is_php7 com then
-					begin
-						com.package_rules <- PMap.add "php" (Directory "php7") com.package_rules;
-						com.package_rules <- PMap.add "php7" Forbidden com.package_rules;
-						add_std "php7"
-					end
-				else
-					add_std "php";
+				add_std "php";
 				"php"
 			| Cpp ->
 				Common.define_value com Define.HxcppApiLevel "332";
@@ -276,6 +259,8 @@ module Initialize = struct
 				add_std "java"; "java"
 			| Python ->
 				add_std "python";
+				if not (Common.defined com Define.PythonVersion) then
+					Common.define_value com Define.PythonVersion "3.3";
 				"python"
 			| Hl ->
 				add_std "hl";
@@ -296,16 +281,16 @@ let generate tctx ext xml_out interp swf_header =
 		Codegen.Dump.dump_dependencies com;
 		if not tctx.Typecore.in_macro then match tctx.Typecore.g.Typecore.macros with
 			| None -> ()
-			| Some(_,ctx) -> print_endline "generate"; Codegen.Dump.dump_dependencies ~target_override:(Some "macro") ctx.Typecore.com
+			| Some(_,ctx) -> Codegen.Dump.dump_dependencies ~target_override:(Some "macro") ctx.Typecore.com
 	end;
 	begin match com.platform with
 		| Neko | Hl | Eval 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
+		| Cpp | Cs | Java | Php -> Path.mkdir_from_path (com.file ^ "/.")
+		| _ -> Path.mkdir_from_path com.file
 	end;
 	if interp then
-		Std.finally (Common.timer ["interp"]) MacroContext.interpret tctx
+		Std.finally (Timer.timer ["interp"]) MacroContext.interpret tctx
 	else if com.platform = Cross then
 		()
 	else begin
@@ -321,10 +306,7 @@ let generate tctx ext xml_out interp swf_header =
 		| Lua ->
 			Genlua.generate,"lua"
 		| Php ->
-			if Common.is_php7 com then
-				Genphp7.generate,"php"
-			else
-				Genphp.generate,"php"
+			Genphp7.generate,"php"
 		| Cpp ->
 			Gencpp.generate,"cpp"
 		| Cs ->
@@ -341,7 +323,7 @@ let generate tctx ext xml_out interp swf_header =
 			assert false
 		in
 		Common.log com ("Generating " ^ name ^ ": " ^ com.file);
-		let t = Common.timer ["generate";name] in
+		let t = Timer.timer ["generate";name] in
 		generate com;
 		t()
 	end
@@ -453,7 +435,7 @@ try
 	Common.define_value com Define.HaxeVer (Printf.sprintf "%.3f" (float_of_int Globals.version /. 1000.));
 	Common.raw_define com "haxe3";
 	Common.define_value com Define.Dce "std";
-	com.warning <- (fun msg p -> message ctx ("Warning : " ^ msg) p);
+	com.warning <- (fun msg p -> message ctx (CMWarning(msg,p)));
 	com.error <- error ctx;
 	if CompilationServer.runs() then com.run_command <- run_command ctx;
 	Parser.display_error := (fun e p -> com.error (Parser.error_msg e) p);
@@ -654,19 +636,6 @@ try
 			com.foptimize <- false;
 			Common.define com Define.NoOpt;
 		), ": disable code optimizations");
-		("--php-front",Arg.String (fun f ->
-			if com.php_front <> None then raise (Arg.Bad "Multiple --php-front");
-			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");
-		("--php-prefix", Arg.String (fun f ->
-			if com.php_prefix <> None then raise (Arg.Bad "Multiple --php-prefix");
-			com.php_prefix <- Some f;
-			Common.define com Define.PhpPrefix;
-		),"<name> : prefix all classes with given name");
 		("--remap", Arg.String (fun s ->
 			let pack, target = (try ExtString.String.split s ":" with _ -> raise (Arg.Bad "Invalid remap format, expected source:target")) in
 			com.package_rules <- PMap.add pack (Remap target) com.package_rules;
@@ -690,7 +659,7 @@ try
 					init_wait_socket com.verbose host port
 			in
 			wait_loop process_params com.verbose accept
-		),"<[host:]port> : wait on the given port for commands to run)");
+		),"[[host:]port]|stdio] : wait on the given port (or use standard i/o) for commands to run)");
 		("--connect",Arg.String (fun _ ->
 			assert false
 		),"<[host:]port> : connect on the given port and run commands there)");
@@ -698,7 +667,7 @@ try
 			assert false
 		),"<dir> : set current working directory");
 		("-version",Arg.Unit (fun() ->
-			message ctx s_version null_pos;
+			message ctx (CMInfo(s_version,null_pos));
 			did_something := true;
 		),": print version and exit");
 		("--help-defines", Arg.Unit (fun() ->
@@ -745,11 +714,15 @@ try
 	process ctx.com.args;
 	process_libs();
 	if com.display.dms_display then begin
-		com.warning <- if com.display.dms_error_policy = EPCollect then (fun s p -> add_diagnostics_message com s p DisplayTypes.DiagnosticsSeverity.Warning) else message ctx;
+		com.warning <-
+			if com.display.dms_error_policy = EPCollect then
+				(fun s p -> add_diagnostics_message com s p DisplayTypes.DiagnosticsSeverity.Warning)
+			else
+				(fun msg p -> message ctx (CMWarning(msg,p)));
 		com.error <- error ctx;
 	end;
 	Lexer.old_format := Common.defined com Define.OldErrorFormat;
-	if !Lexer.old_format && !Parser.resume_display <> null_pos then begin
+	if !Lexer.old_format && Parser.do_resume () then begin
 		let p = !Parser.resume_display in
 		(* convert byte position to utf8 position *)
 		try
@@ -779,8 +752,8 @@ try
 	end else begin
 		ctx.setup();
 		Common.log com ("Classpath : " ^ (String.concat ";" com.class_path));
-		Common.log com ("Defines : " ^ (String.concat ";" (PMap.foldi (fun k v acc -> (match v with "1" -> k | _ -> k ^ "=" ^ v) :: acc) com.defines [])));
-		let t = Common.timer ["typing"] in
+		Common.log com ("Defines : " ^ (String.concat ";" (PMap.foldi (fun k v acc -> (match v with "1" -> k | _ -> k ^ "=" ^ v) :: acc) com.defines.Define.values [])));
+		let t = Timer.timer ["typing"] in
 		Typecore.type_expr_ref := (fun ctx e with_type -> Typer.type_expr ctx e with_type);
 		let tctx = Typer.create com in
 		List.iter (MacroContext.call_init_macro tctx) (List.rev !config_macros);
@@ -792,7 +765,7 @@ try
 			if ctx.has_next || ctx.has_error then raise Abort;
 			failwith "No completion point was found";
 		end;
-		let t = Common.timer ["filters"] in
+		let t = Timer.timer ["filters"] in
 		let main, types, modules = Typer.generate tctx in
 		com.main <- main;
 		com.types <- types;
@@ -809,7 +782,7 @@ try
 			Genxml.generate_hx com
 		| Some file ->
 			Common.log com ("Generating xml : " ^ file);
-			Common.mkdir_from_path file;
+			Path.mkdir_from_path file;
 			Genxml.generate com file);
 		if not !no_output then generate tctx ext !xml_out !interp !swf_header;
 	end;
@@ -842,9 +815,9 @@ with
 		end
 	| Error.Error (m,p) ->
 		error ctx (Error.error_msg m) p
-	| Interp.Error (msg,p :: l) | Hlmacro.Error (msg,p :: l) ->
-		message ctx msg p;
-		List.iter (message ctx "Called from") l;
+	| Hlmacro.Error (msg,p :: l) ->
+		message ctx (CMError(msg,p));
+		List.iter (fun p -> message ctx (CMError("Called from",p))) l;
 		error ctx "Aborted" null_pos;
 	| Typeload.Generic_Exception(m,p) ->
 		error ctx m p
@@ -853,7 +826,7 @@ with
 	| Failure msg when not (is_debug_run()) ->
 		error ctx ("Error: " ^ msg) null_pos
 	| Arg.Help msg ->
-		message ctx msg null_pos
+		message ctx (CMInfo(msg,null_pos))
 	| Display.DisplayPackage pack ->
 		raise (DisplayOutput.Completion (String.concat "." pack))
 	| Display.DisplayFields fields ->
@@ -862,7 +835,7 @@ with
 		) fields in
 		let fields =
 			if !measure_times then begin
-				close_times();
+				Timer.close_times();
 				(List.map (fun (name,value) -> ("@TIME " ^ name, Display.FKTimer value, "")) (DisplayOutput.get_timer_fields !start_time)) @ fields
 			end else
 				fields
@@ -881,7 +854,7 @@ with
 	| Display.DisplayToplevel il ->
 		let il =
 			if !measure_times then begin
-				close_times();
+				Timer.close_times();
 				(List.map (fun (name,value) -> IdentifierType.ITTimer ("@TIME " ^ name ^ ": " ^ value)) (DisplayOutput.get_timer_fields !start_time)) @ il
 			end else
 				il
@@ -901,15 +874,15 @@ with
 		Option.may (fun fields -> raise (DisplayOutput.Completion (DisplayOutput.print_fields fields))) fields
 	| Display.ModuleSymbols s | Display.Diagnostics s | Display.Statistics s | Display.Metadata s ->
 		raise (DisplayOutput.Completion s)
-	| Interp.Sys_exit i | Hlinterp.Sys_exit i ->
+	| EvalExceptions.Sys_exit i | Hlinterp.Sys_exit i ->
 		ctx.flush();
-		if !measure_times then report_times prerr_endline;
+		if !measure_times then Timer.report_times prerr_endline;
 		exit i
 	| e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" || CompilationServer.runs() with _ -> true) && not (is_debug_run()) ->
 		error ctx (Printexc.to_string e) null_pos
 
 ;;
-let other = Common.timer ["other"] in
+let other = Timer.timer ["other"] in
 Sys.catch_break true;
 MacroContext.setup();
 let args = List.tl (Array.to_list Sys.argv) in
@@ -927,4 +900,4 @@ with DisplayOutput.Completion c ->
 	exit 1
 );
 other();
-if !measure_times then report_times prerr_endline
+if !measure_times then Timer.report_times prerr_endline

+ 29 - 113
src/compiler/server.ml

@@ -3,6 +3,7 @@ open Globals
 open Ast
 open Common
 open Common.DisplayMode
+open Timer
 open Type
 open DisplayOutput
 open Json
@@ -11,7 +12,7 @@ exception Dirty of module_def
 
 let measure_times = ref false
 let prompt = ref false
-let start_time = ref (get_time())
+let start_time = ref (Timer.get_time())
 
 let is_debug_run() =
 	try Sys.getenv "HAXEDEBUG" = "1" with _ -> false
@@ -20,7 +21,7 @@ type context = {
 	com : Common.context;
 	mutable flush : unit -> unit;
 	mutable setup : unit -> unit;
-	mutable messages : string list;
+	mutable messages : compiler_message list;
 	mutable has_next : bool;
 	mutable has_error : bool;
 }
@@ -39,104 +40,13 @@ type server_message =
 let s_version =
 	Printf.sprintf "%d.%d.%d%s" version_major version_minor version_revision (match Version.version_extra with None -> "" | Some v -> " " ^ v)
 
-type timer_node = {
-	name : string;
-	path : string;
-	parent : timer_node;
-	info : string;
-	mutable time : float;
-	mutable num_calls : int;
-	mutable children : timer_node list;
-}
-
-let report_times print =
-	let nodes = Hashtbl.create 0 in
-	let rec root = {
-		name = "";
-		path = "";
-		parent = root;
-		info = "";
-		time = 0.;
-		num_calls = 0;
-		children = [];
-	} in
-	Hashtbl.iter (fun _ timer ->
-		let rec loop parent sl = match sl with
-			| [] -> assert false
-			| s :: sl ->
-				let path = (match parent.path with "" -> "" | _ -> parent.path ^ ".") ^ s in
-				let node = try
-					let node = Hashtbl.find nodes path in
-					node.num_calls <- node.num_calls + timer.calls;
-					node.time <- node.time +. timer.total;
-					node
-				with Not_found ->
-					let name,info = try
-						let i = String.rindex s '.' in
-						String.sub s (i + 1) (String.length s - i - 1),String.sub s 0 i
-					with Not_found ->
-						s,""
-					in
-					let node = {
-						name = name;
-						path = path;
-						parent = parent;
-						info = info;
-						time = timer.total;
-						num_calls = timer.calls;
-						children = [];
-					} in
-					Hashtbl.add nodes path node;
-					node
-				in
-				begin match sl with
-					| [] -> ()
-					| _ ->
-						let child = loop node sl in
-						if not (List.memq child node.children) then
-							node.children <- child :: node.children;
-				end;
-				node
-		in
-		let node = loop root timer.id in
-		if not (List.memq node root.children) then
-			root.children <- node :: root.children
-	) Common.htimers;
-	let max_name = ref 0 in
-	let max_calls = ref 0 in
-	let rec loop depth node =
-		let l = (String.length node.name) + 2 * depth in
-		if l > !max_name then max_name := l;
-		List.iter (fun child ->
-			if depth = 0 then begin
-				node.num_calls <- node.num_calls + child.num_calls;
-				node.time <- node.time +. child.time;
-			end;
-			loop (depth + 1) child;
-		) node.children;
-		node.children <- List.sort (fun node1 node2 -> compare node2.time node1.time) node.children;
-		if node.num_calls > !max_calls then max_calls := node.num_calls;
-	in
-	loop 0 root;
-	let max_calls = String.length (string_of_int !max_calls) in
-	print (Printf.sprintf "%-*s | %7s |   %% |  p%% | %*s | info" !max_name "name" "time(s)" max_calls "#");
-	let sep = String.make (!max_name + max_calls + 27) '-' in
-	print sep;
-	let print_time name node =
-		if node.time > 0.0009 then
-			print (Printf.sprintf "%-*s | %7.3f | %3.0f | %3.0f | %*i | %s" !max_name name node.time (node.time *. 100. /. root.time) (node.time *. 100. /. node.parent.time) max_calls node.num_calls node.info)
-	in
-	let rec loop depth node =
-		let name = (String.make (depth * 2) ' ') ^ node.name in
-		print_time name node;
-		List.iter (loop (depth + 1)) node.children
-	in
-	List.iter (loop 0) root.children;
-	print sep;
-	print_time "total" root
-
 let default_flush ctx =
-	List.iter prerr_endline (List.rev ctx.messages);
+	List.iter
+		(fun msg -> match msg with
+			| CMInfo _ -> print_endline (compiler_message_string msg)
+			| CMWarning _ | CMError _ -> prerr_endline (compiler_message_string msg)
+		)
+		(List.rev ctx.messages);
 	if ctx.has_error && !prompt then begin
 		print_endline "Press enter to exit...";
 		ignore(read_line());
@@ -193,7 +103,7 @@ let rec wait_loop process_params verbose accept =
 	let test_server_messages = DynArray.create () in
 	let cs = CompilationServer.create () in
 	let sign_string com =
-		let sign = get_signature com in
+		let sign = Define.get_signature com.defines in
 		let	sign_id =
 			try
 				CompilationServer.get_sign cs sign;
@@ -245,7 +155,7 @@ let rec wait_loop process_params verbose accept =
 		| true, Some stdin when Common.defined com2 Define.DisplayStdin ->
 			Typeload.parse_file_from_string com2 file p stdin
 		| _ ->
-			let sign = get_signature com2 in
+			let sign = Define.get_signature com2.defines in
 			let ftime = file_time ffile in
 			let fkey = (ffile,sign) in
 			try
@@ -289,9 +199,9 @@ let rec wait_loop process_params verbose accept =
 		(Unix.stat (Path.remove_trailing_slash dir)).Unix.st_mtime
 	in
 	let get_changed_directories (ctx : Typecore.typer) =
-		let t = Common.timer ["server";"module cache";"changed dirs"] in
+		let t = Timer.timer ["server";"module cache";"changed dirs"] in
 		let com = ctx.Typecore.com in
-		let sign = get_signature com in
+		let sign = Define.get_signature com.defines in
 		let dirs = try
 			(* First, check if we already have determined changed directories for current compilation. *)
 			Hashtbl.find changed_directories sign
@@ -355,9 +265,9 @@ let rec wait_loop process_params verbose accept =
 	let compilation_mark = ref 0 in
 	let mark_loop = ref 0 in
 	Typeload.type_module_hook := (fun (ctx:Typecore.typer) mpath p ->
-		let t = Common.timer ["server";"module cache"] in
+		let t = Timer.timer ["server";"module cache"] in
 		let com2 = ctx.Typecore.com in
-		let sign = get_signature com2 in
+		let sign = Define.get_signature com2.defines in
 		let content_changed m file =
 			let ffile = Path.unique_full_path file in
 			let fkey = (ffile,sign) in
@@ -475,13 +385,13 @@ let rec wait_loop process_params verbose accept =
 					PMap.iter (Hashtbl.replace com2.resources) m.m_extra.m_binded_res;
 					if ctx.Typecore.in_macro || com2.display.dms_full_typing then
 						PMap.iter (fun _ m2 -> add_modules (tabs ^ "  ") m0 m2) m.m_extra.m_deps;
-					List.iter (MacroContext.call_init_macro ctx) m.m_extra.m_macro_calls
+					List.iter (MacroContext.call_init_macro ctx) m.m_extra.m_reuse_macro_calls
 				)
 			end
 		in
 		try
 			let m = CompilationServer.find_module cs (mpath,sign) in
-			let tcheck = Common.timer ["server";"module cache";"check"] in
+			let tcheck = Timer.timer ["server";"module cache";"check"] in
 			begin match check m with
 			| None -> ()
 			| Some m' ->
@@ -490,7 +400,7 @@ let rec wait_loop process_params verbose accept =
 				raise Not_found;
 			end;
 			tcheck();
-			let tadd = Common.timer ["server";"module cache";"add modules"] in
+			let tadd = Timer.timer ["server";"module cache";"add modules"] in
 			add_modules "" m m;
 			tadd();
 			t();
@@ -520,16 +430,22 @@ let rec wait_loop process_params verbose accept =
 			ctx.flush <- (fun() ->
 				incr compilation_step;
 				compilation_mark := !mark_loop;
-				List.iter (fun s -> write (s ^ "\n"); if verbose then print_endline ("> " ^ s)) (List.rev ctx.messages);
+				List.iter
+					(fun msg ->
+						let s = compiler_message_string msg in
+						write (s ^ "\n");
+						if verbose then print_endline ("> " ^ s)
+					)
+					(List.rev ctx.messages);
 				if ctx.has_error then begin
 					measure_times := false;
 					write "\x02\n"
 				end else cache_context ctx.com;
 			);
 			ctx.setup <- (fun() ->
-				let sign = get_signature ctx.com in
+				let sign = Define.get_signature ctx.com.defines in
 				if verbose then begin
-					let defines = PMap.foldi (fun k v acc -> (k ^ "=" ^ v) :: acc) ctx.com.defines [] in
+					let defines = PMap.foldi (fun k v acc -> (k ^ "=" ^ v) :: acc) ctx.com.defines.Define.values [] in
 					print_endline ("Defines " ^ (String.concat "," (List.sort compare defines)));
 					print_endline ("Using signature " ^ Digest.to_hex sign);
 					print_endline ("Display position: " ^ (Printer.s_pos !Parser.resume_display));
@@ -580,8 +496,8 @@ let rec wait_loop process_params verbose accept =
 				stats.s_classes_built := 0;
 				stats.s_methods_typed := 0;
 				stats.s_macros_called := 0;
-				Hashtbl.clear Common.htimers;
-				let _ = Common.timer ["other"] in
+				Hashtbl.clear Timer.htimers;
+				let _ = Timer.timer ["other"] in
 				incr compilation_step;
 				compilation_mark := !mark_loop;
 				start_time := get_time();

+ 67 - 426
src/context/common.ml

@@ -20,6 +20,7 @@
 open Ast
 open Type
 open Globals
+open Define
 
 type package_rule =
 	| Forbidden
@@ -28,16 +29,6 @@ type package_rule =
 
 type pos = Globals.pos
 
-type basic_types = {
-	mutable tvoid : t;
-	mutable tint : t;
-	mutable tfloat : t;
-	mutable tbool : t;
-	mutable tnull : t -> t;
-	mutable tstring : t;
-	mutable tarray : t -> t;
-}
-
 let const_type basic const default =
 	match const with
 	| TString _ -> basic.tstring
@@ -53,6 +44,25 @@ type stats = {
 	s_macros_called : int ref;
 }
 
+type compiler_message =
+	| CMInfo of string * pos
+	| CMWarning of string * pos
+	| CMError of string * pos
+
+let compiler_message_string msg =
+	let (str,p) = match msg with
+		| CMInfo(str,p) | CMError(str,p) -> (str,p)
+		| CMWarning(str,p) -> ("Warning : " ^ str, p)
+	in
+	if p = null_pos then
+		str
+	else begin
+		let error_printer file line = Printf.sprintf "%s:%d:" file line in
+		let epos = Lexer.get_error_pos error_printer p in
+		let str = String.concat ("\n" ^ epos ^ " : ") (ExtString.String.nsplit str "\n") in
+		Printf.sprintf "%s : %s" epos str
+	end
+
 (**
 	The capture policy tells which handling we make of captured locals
 	(the locals which are referenced in local functions)
@@ -264,13 +274,12 @@ type context = {
 	mutable std_path : string list;
 	mutable class_path : string list;
 	mutable main_class : Type.path option;
-	mutable defines : (string,string) PMap.t;
 	mutable package_rules : (string,package_rule) PMap.t;
 	mutable error : string -> pos -> unit;
 	mutable warning : string -> pos -> unit;
 	mutable load_extern_type : (path -> pos -> (string * Ast.package) option) list; (* allow finding types which are not in sources *)
 	callbacks : compiler_callback;
-	mutable defines_signature : string option;
+	defines : Define.define;
 	mutable print : string -> unit;
 	mutable get_macros : unit -> context option;
 	mutable run_command : string -> int;
@@ -288,9 +297,6 @@ type context = {
 	mutable resources : (string,string) Hashtbl.t;
 	mutable neko_libs : string list;
 	mutable include_files : (string * string) list;
-	mutable php_front : string option;
-	mutable php_lib : string option;
-	mutable php_prefix : string option;
 	mutable swf_libs : (string * (unit -> Swf.swf) * (unit -> ((string list * string),As3hl.hl_class) Hashtbl.t)) list;
 	mutable java_libs : (string * bool * (unit -> unit) * (unit -> (path list)) * (path -> ((JData.jclass * string * string) option))) list; (* (path,std,close,all_files,lookup) *)
 	mutable net_libs : (string * bool * (unit -> path list) * (path -> IlData.ilclass option)) list; (* (path,std,all_files,lookup) *)
@@ -307,25 +313,6 @@ exception Abort of string * pos
 
 let display_default = ref DisplayMode.DMNone
 
-let get_signature com =
-	match com.defines_signature with
-	| Some s -> s
-	| None ->
-		let defines = PMap.foldi (fun k v acc ->
-			(* don't make much difference between these special compilation flags *)
-			match String.concat "_" (ExtString.String.nsplit k "-") with
-			(* If we add something here that might be used in conditional compilation it should be added to
-			   Parser.parse_macro_ident as well (issue #5682). *)
-			| "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" | "display_stdin" -> acc
-			| _ -> (k ^ "=" ^ v) :: acc
-		) com.defines [] in
-		let str = String.concat "@" (List.sort compare defines) in
-		let s = Digest.string str in
-		com.defines_signature <- Some s;
-		s
-
-let is_php7 com = com.platform = Php && PMap.exists "php7" com.defines
-
 module CompilationServer = struct
 	type cache = {
 		c_haxelib : (string list, string list) Hashtbl.t;
@@ -448,237 +435,35 @@ module CompilationServer = struct
 		Hashtbl.remove cs.cache.c_directories key
 end
 
-module Define = struct
-
-	type strict_defined =
-		| AbsolutePath
-		| AdvancedTelemetry
-		| AnnotateSource
-		(* | Analyzer *)
-		| As3
-		| CheckXmlProxy
-		| CoreApi
-		| CoreApiSerialize
-		| Cppia
-		| NoCppiaAst
-		| Dce
-		| DceDebug
-		| Debug
-		| Display
-		| DisplayStdin
-		| DllExport
-		| DllImport
-		| DocGen
-		| Dump
-		| DumpDependencies
-		| DumpIgnoreVarIds
-		| DynamicInterfaceClosures
-		| EraseGenerics
-		| EvalDebugger
-		| EvalStack
-		| EvalTimes
-		| FastCast
-		| Fdb
-		| FileExtension
-		| FlashStrict
-		| FlashUseStage
-		| ForceLibCheck
-		| ForceNativeProperty
-		| FormatWarning
-		| GencommonDebug
-		| HaxeBoot
-		| HaxeVer
-		| HxcppApiLevel
-		| HxcppGcGenerational
-		| HxcppDebugger
-		| IncludePrefix
-		| Interp
-		| JavaVer
-		| JqueryVer
-		| JsClassic
-		| JsEs
-		| JsUnflatten
-		| JsSourceMap
-		| JsEnumsAsObjects
-		| SourceMap
-		| KeepOldOutput
-		| LoopUnrollMaxCost
-		| LuaVer
-		| LuaJit
-		| Macro
-		| MacroDebug
-		| MacroTimes
-		| NekoSource
-		| NekoV1
-		| NetworkSandbox
-		| NetVer
-		| NetTarget
-		| NoCompilation
-		| NoCOpt
-		| NoDeprecationWarnings
-		| NoFlashOverride
-		| NoDebug
-		| NoInline
-		| NoOpt
-		| NoRoot
-		| NoSwfCompress
-		| NoTraces
-		| Objc
-		| OldConstructorInline
-		| OldErrorFormat
-		| PhpPrefix
-		| RealPosition
-		| ReplaceFiles
-		| Scriptable
-		| ShallowExpose
-		| SourceHeader
-		| SourceMapContent
-		| Swc
-		| SwfCompressLevel
-		| SwfDebugPassword
-		| SwfDirectBlit
-		| SwfGpu
-		| SwfMetadata
-		| SwfPreloaderFrame
-		| SwfProtected
-		| SwfScriptTimeout
-		| SwfUseDoAbc
-		| Sys
-		| Unsafe
-		| UseNekoc
-		| UseRttiDoc
-		| Vcproj
-		| NoMacroCache
-		| Last (* must be last *)
-
-	type define_parameter =
-		| HasParam of string
-		| Platform of platform
-		| Platforms of platform list
-
-	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",[Platform Flash])
-		| AnnotateSource -> "annotate_source",("Add additional comments to generated source code",[Platform Cpp])
-		(* | 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",("Mark some generated core api classes with the Serializable attribute on C#",[Platform Cs])
-		| Cppia -> "cppia",("Generate cpp instruction assembly",[])
-		| NoCppiaAst -> "nocppiaast",("Use legacy cppia generation",[])
-		| Dce -> "dce",("<mode:std|full|no> Set the dead code elimination mode (default std)",[])
-		| DceDebug -> "dce_debug",("Show DCE log",[])
-		| Debug -> "debug",("Activated when compiling with -debug",[])
-		| Display -> "display",("Activated during completion",[])
-		| DisplayStdin -> "display_stdin",("Read the contents of a file specified in --display from standard input",[])
-		| DllExport -> "dll_export",("GenCPP experimental linking",[Platform Cpp])
-		| DllImport -> "dll_import",("Handle Haxe-generated .NET dll imports",[Platform Cs])
-		| DocGen -> "doc_gen",("Do not perform any removal/change in order to correctly generate documentation",[])
-		| Dump -> "dump",("<mode:pretty|record|legacy> Dump typed AST in dump subdirectory using specified mode or non-prettified default",[])
-		| DumpDependencies -> "dump_dependencies",("Dump the classes dependencies in a dump subdirectory",[])
-		| DumpIgnoreVarIds -> "dump_ignore_var_ids",("Remove variable IDs from non-pretty dumps (helps with diff)",[])
-		| DynamicInterfaceClosures -> "dynamic_interface_closures",("Use slow path for interface closures to save space",[Platform Cpp])
-		| EraseGenerics -> "erase_generics",("Erase generic classes on C#",[Platform Cs])
-		| EvalDebugger -> "eval_debugger",("Support debugger in macro/interp mode. Allows host:port value to open a socket. Implies eval_stack.",[])
-		| EvalStack -> "eval_stack",("Record stack information in macro/interp mode",[])
-		| EvalTimes -> "eval_times",("Record per-method execution times in macro/interp mode. Implies eval_stack.",[])
-		| FastCast -> "fast_cast",("Enables an experimental casts cleanup on C# and Java",[Platforms [Cs;Java]])
-		| Fdb -> "fdb",("Enable full flash debug infos for FDB interactive debugging",[Platform Flash])
-		| FileExtension -> "file_extension",("Output filename extension for cpp source code",[Platform Cpp])
-		| FlashStrict -> "flash_strict",("More strict typing for flash target",[Platform Flash])
-		| FlashUseStage -> "flash_use_stage",("Keep the SWF library initial stage",[Platform Flash])
-		(* 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)",[Platforms [Cs;Java]])
-		| ForceNativeProperty -> "force_native_property",("Tag all properties with :nativeProperty metadata for 3.1 compatibility",[Platform Cpp])
-		| FormatWarning -> "format_warning",("Print a warning for each formated string, for 2.x compatibility",[])
-		| GencommonDebug -> "gencommon_debug",("GenCommon internal",[Platforms [Cs;Java]])
-		| HaxeBoot -> "haxe_boot",("Given the name 'haxe' to the flash boot class instead of a generated name",[Platform Flash])
-		| HaxeVer -> "haxe_ver",("The current Haxe version value",[])
-		| HxcppApiLevel -> "hxcpp_api_level",("Provided to allow compatibility between hxcpp versions",[Platform Cpp])
-		| HxcppGcGenerational -> "HXCPP_GC_GENERATIONAL",("Experimental Garbage Collector",[Platform Cpp])
-		| HxcppDebugger -> "HXCPP_DEBUGGER",("Include additional information for HXCPP_DEBUGGER",[Platform Cpp])
-		| IncludePrefix -> "include_prefix",("prepend path to generated include files",[Platform Cpp])
-		| Interp -> "interp",("The code is compiled to be run with --interp",[])
-		| JavaVer -> "java_ver",("<version:5-7> Sets the Java version to be targeted",[Platform Java])
-		| JqueryVer -> "jquery_ver",("The jQuery version supported by js.jquery.*. The version is encoded as an interger. e.g. 1.11.3 is encoded as 11103",[Platform Js])
-		| JsClassic -> "js_classic",("Don't use a function wrapper and strict mode in JS output",[Platform Js])
-		| JsEs -> "js_es",("Generate JS compilant with given ES standard version (default 5)",[Platform Js; HasParam "version number"])
-		| JsEnumsAsObjects -> "js_enums_as_objects",("Generate enum representation as object instead of as array",[Platform Js])
-		| JsUnflatten -> "js_unflatten",("Generate nested objects for packages and types",[Platform Js])
-		| JsSourceMap -> "js_source_map",("Generate JavaScript source map even in non-debug mode",[Platform Js])
-		| SourceMap -> "source_map",("Generate source map for compiled files (Currently supported for php7 only)",[Platform Php])
-		| KeepOldOutput -> "keep_old_output",("Keep old source files in the output directory (for C#/Java)",[Platforms [Cs;Java]])
-		| LoopUnrollMaxCost -> "loop_unroll_max_cost",("Maximum cost (number of expressions * iterations) before loop unrolling is canceled (default 250)",[])
-		| LuaJit -> "lua_jit",("Enable the jit compiler for lua (version 5.2 only)",[Platform Lua])
-		| LuaVer -> "lua_ver",("The lua version to target",[Platform Lua])
-		| Macro -> "macro",("Defined when code is compiled in the macro context",[])
-		| MacroDebug -> "macro_debug",("Show warnings for potential macro problems (e.g. macro-in-macro calls)",[])
-		| MacroTimes -> "macro_times",("Display per-macro timing when used with --times",[])
-		| NetVer -> "net_ver",("<version:20-45> Sets the .NET version to be targeted",[Platform Cs])
-		| NetTarget -> "net_target",("<name> Sets the .NET target. Defaults to \"net\". xbox, micro (Micro Framework), compact (Compact Framework) are some valid values",[Platform Cs])
-		| NekoSource -> "neko_source",("Output neko source instead of bytecode",[Platform Neko])
-		| NekoV1 -> "neko_v1",("Keep Neko 1.x compatibility",[Platform Neko])
-		| NetworkSandbox -> "network-sandbox",("Use local network sandbox instead of local file access one",[Platform Flash])
-		| NoCompilation -> "no-compilation",("Disable final compilation",[Platforms [Cs;Java;Cpp;Hl]])
-		| 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",[])
-		| NoFlashOverride -> "no-flash-override",("Change overrides on some basic classes into HX suffixed methods, flash only",[Platform Flash])
-		| NoOpt -> "no_opt",("Disable optimizations",[])
-		| NoInline -> "no_inline",("Disable inlining",[])
-		| NoRoot -> "no_root",("Generate top-level types into haxe.root namespace",[Platform Cs])
-		| NoMacroCache -> "no_macro_cache",("Disable macro context caching",[])
-		| NoSwfCompress -> "no_swf_compress",("Disable SWF output compression",[Platform Flash])
-		| NoTraces -> "no_traces",("Disable all trace calls",[])
-		| Objc -> "objc",("Sets the hxcpp output to objective-c++ classes. Must be defined for interop",[Platform Cpp])
-		| OldConstructorInline -> "old-constructor-inline",("Use old constructor inlining logic (from haxe 3.4.2) instead of the reworked version.",[])
-		| OldErrorFormat -> "old-error-format",("Use Haxe 3.x zero-based column error messages instead of new one-based format.",[])
-		| PhpPrefix -> "php_prefix",("Compiled with --php-prefix",[Platform Php])
-		| RealPosition -> "real_position",("Disables Haxe source mapping when targetting C#, removes position comments in Java and Php7 output",[Platforms [Cs;Java;Php]])
-		| ReplaceFiles -> "replace_files",("GenCommon internal",[Platforms [Java;Cs]])
-		| Scriptable -> "scriptable",("GenCPP internal",[Platform Cpp])
-		| ShallowExpose -> "shallow-expose",("Expose types to surrounding scope of Haxe generated closure without writing to window object",[Platform Js])
-		| SourceHeader -> "source-header",("Print value as comment on top of generated files, use '' value to disable",[])
-		| SourceMapContent -> "source-map-content",("Include the hx sources as part of the JS source map",[Platform Js])
-		| Swc -> "swc",("Output a SWC instead of a SWF",[Platform Flash])
-		| SwfCompressLevel -> "swf_compress_level",("<level:1-9> Set the amount of compression for the SWF output",[Platform Flash])
-		| SwfDebugPassword -> "swf_debug_password",("Set a password for debugging",[Platform Flash])
-		| SwfDirectBlit -> "swf_direct_blit",("Use hardware acceleration to blit graphics",[Platform Flash])
-		| SwfGpu -> "swf_gpu",("Use GPU compositing features when drawing graphics",[Platform Flash])
-		| SwfMetadata -> "swf_metadata",("<file> Include contents of <file> as metadata in the swf",[Platform Flash])
-		| SwfPreloaderFrame -> "swf_preloader_frame",("Insert empty first frame in swf",[Platform Flash])
-		| SwfProtected -> "swf_protected",("Compile Haxe private as protected in the SWF instead of public",[Platform Flash])
-		| SwfScriptTimeout -> "swf_script_timeout",("Maximum ActionScript processing time before script stuck dialog box displays (in seconds)",[Platform Flash])
-		| SwfUseDoAbc -> "swf_use_doabc",("Use DoAbc swf-tag instead of DoAbcDefine",[Platform Flash])
-		| Sys -> "sys",("Defined for all system platforms",[])
-		| Unsafe -> "unsafe",("Allow unsafe code when targeting C#",[Platform Cs])
-		| UseNekoc -> "use_nekoc",("Use nekoc compiler instead of internal one",[Platform Neko])
-		| UseRttiDoc -> "use_rtti_doc",("Allows access to documentation during compilation",[])
-		| Vcproj -> "vcproj",("GenCPP internal",[Platform Cpp])
-		| Last -> assert false
-
-	let get_documentation_list() =
-		let m = ref 0 in
-		let rec loop i =
-			let d = Obj.magic i in
-			if d <> Last then begin
-				let t, (doc,flags) = infos d in
-				let pfs = ref [] in
-				List.iter (function
-				| HasParam s -> () (* TODO *)
-				| Platform p -> pfs := p :: !pfs;
-				| Platforms pl -> pfs := pl @ !pfs;
-				) flags;
-				let pfs = platform_list_help (List.rev !pfs) in
-				if String.length t > !m then m := String.length t;
-				((String.concat "-" (ExtString.String.nsplit t "_")),doc ^ pfs) :: (loop (i + 1))
-			end else
-				[]
-		in
-		let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in
-		all,!m
-end
+(* Defines *)
+
+module Define = Define
+
+let defined com s =
+	Define.defined com.defines s
+
+let raw_defined com v =
+	Define.raw_defined com.defines v
+
+let defined_value com v =
+	Define.defined_value com.defines v
+
+let defined_value_safe ?default com v =
+	match default with
+		| Some s -> Define.defined_value_safe ~default:s com.defines v
+		| None -> Define.defined_value_safe com.defines v
+
+let define com v =
+	Define.define com.defines v
+
+let raw_define com v =
+	Define.raw_define com.defines v
+
+let define_value com k v =
+	Define.define_value com.defines k v
+
+let raw_defined_value com k =
+	Define.raw_defined_value com.defines k
 
 let short_platform_name = function
 	| Cross -> "x"
@@ -715,7 +500,7 @@ let default_config =
 	}
 
 let get_config com =
-	let defined f = PMap.mem (fst (Define.infos f)) com.defines in
+	let defined f = PMap.mem (fst (Define.infos f)) com.defines.values in
 	match com.platform with
 	| Cross ->
 		default_config
@@ -756,17 +541,10 @@ let get_config com =
 			pf_reserved_type_paths = [([],"Object");([],"Error")];
 		}
 	| Php ->
-		if is_php7 com then
-			{
-				default_config with
-				pf_static = false;
-			}
-		else
-			{
-				default_config with
-				pf_static = false;
-				pf_pad_nulls = true;
-			}
+		{
+			default_config with
+			pf_static = false;
+		}
 	| Cpp ->
 		{
 			default_config with
@@ -853,7 +631,6 @@ let create version s_version args =
 		std_path = [];
 		class_path = [];
 		main_class = None;
-		defines = defines;
 		package_rules = PMap.empty;
 		file = "";
 		types = [];
@@ -862,8 +639,6 @@ let create version s_version args =
 		main = None;
 		flash_version = 10.;
 		resources = Hashtbl.create 0;
-		php_front = None;
-		php_lib = None;
 		swf_libs = [];
 		java_libs = [];
 		net_libs = [];
@@ -872,10 +647,12 @@ let create version s_version args =
 		c_args = [];
 		neko_libs = [];
 		include_files = [];
-		php_prefix = None;
 		js_gen = None;
 		load_extern_type = [];
-		defines_signature = None;
+		defines = {
+			defines_signature = None;
+			values = defines;
+		};
 		get_macros = (fun() -> None);
 		warning = (fun _ _ -> assert false);
 		error = (fun _ _ -> assert false);
@@ -911,6 +688,10 @@ let clone com =
 			unresolved_identifiers = [];
 			interface_field_implementations = [];
 		};
+		defines = {
+			values = com.defines.values;
+			defines_signature = com.defines.defines_signature;
+		}
 	}
 
 let file_time file = Extc.filetime file
@@ -947,42 +728,13 @@ let flash_version_tag = function
 	| v when v >= 12.0 && float_of_int (int_of_float v) = v -> int_of_float v + 11
 	| v -> failwith ("Invalid SWF version " ^ string_of_float v)
 
-let raw_defined ctx v =
-	PMap.mem v ctx.defines
-
-let defined ctx v =
-	raw_defined ctx (fst (Define.infos v))
-
-let raw_defined_value ctx k =
-	PMap.find k ctx.defines
-
-let defined_value ctx v =
-	raw_defined_value ctx (fst (Define.infos v))
-
-let defined_value_safe ctx v =
-	try defined_value ctx v
-	with Not_found -> ""
-
-let raw_define ctx v =
-	let k,v = try ExtString.String.split v "=" with _ -> v,"1" in
-	ctx.defines <- PMap.add k v ctx.defines;
-	let k = String.concat "_" (ExtString.String.nsplit k "-") in
-	ctx.defines <- PMap.add k v ctx.defines;
-	ctx.defines_signature <- None
-
-let define_value ctx k v =
-	raw_define ctx (fst (Define.infos k) ^ "=" ^ v)
-
-let define ctx v =
-	raw_define ctx (fst (Define.infos v))
-
 let init_platform com pf =
 	com.platform <- pf;
 	let name = platform_name pf in
 	let forbid acc p = if p = name || PMap.mem p acc then acc else PMap.add p Forbidden acc in
 	com.package_rules <- List.fold_left forbid com.package_rules (List.map platform_name platforms);
 	com.config <- get_config com;
-(*	if com.config.pf_static then define com "static"; *)
+	if com.config.pf_static then define com Define.Static;
 	if com.config.pf_sys then define com Define.Sys else com.package_rules <- PMap.add "sys" Forbidden com.package_rules;
 	raw_define com name
 
@@ -1078,121 +830,10 @@ let find_file ctx f =
 		| None -> raise Not_found
 		| Some f -> f)
 
-let rec mkdir_recursive base dir_list =
-	match dir_list with
-	| [] -> ()
-	| dir :: remaining ->
-		let path = match base with
-				   | "" ->  dir
-				   | "/" -> "/" ^ dir
-				   | _ -> base ^ "/" ^ dir
-		in
-		let path_len = String.length path in
-		let path =
-			if path_len > 0 && (path.[path_len - 1] = '/' || path.[path_len - 1] == '\\') then
-				String.sub path 0 (path_len - 1)
-			else
-				path
-		in
-		if not ( (path = "") || ( (path_len = 2) && ((String.sub path 1 1) = ":") ) ) then
-			if not (Sys.file_exists path) then
-				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 [] [])
 
-(* ------------------------- TIMERS ----------------------------- *)
-
-type timer_infos = {
-	id : string list;
-	mutable start : float list;
-	mutable total : float;
-	mutable calls : int;
-}
-
-let get_time = Extc.time
-let htimers = Hashtbl.create 0
-
-let new_timer id =
-	let key = String.concat "." id in
-	try
-		let t = Hashtbl.find htimers key in
-		t.start <- get_time() :: t.start;
-		t.calls <- t.calls + 1;
-		t
-	with Not_found ->
-		let t = { id = id; start = [get_time()]; total = 0.; calls = 1; } in
-		Hashtbl.add htimers key t;
-		t
-
-let curtime = ref []
-
-let close t =
-	let start = (match t.start with
-		| [] -> assert false
-		| s :: l -> t.start <- l; s
-	) in
-	let now = get_time() in
-	let dt = now -. start in
-	t.total <- t.total +. dt;
-	let rec loop() =
-		match !curtime with
-		| [] -> failwith ("Timer " ^ (String.concat "." t.id) ^ " closed while not active")
-		| tt :: l -> curtime := l; if t != tt then loop()
-	in
-	loop();
-	(* because of rounding errors while adding small times, we need to make sure that we don't have start > now *)
-	List.iter (fun ct -> ct.start <- List.map (fun t -> let s = t +. dt in if s > now then now else s) ct.start) !curtime
-
-let timer id =
-	let t = new_timer id in
-	curtime := t :: !curtime;
-	(function() -> close t)
-
-let rec close_times() =
-	match !curtime with
-	| [] -> ()
-	| t :: _ -> close t; close_times()
-
-;;
-
-(*  Taken from OCaml source typing/oprint.ml
-
-	This is a better version of string_of_float which prints without loss of precision
-	so that float_of_string (float_repres x) = x for all floats x
-*)
-let valid_float_lexeme s =
-	let l = String.length s in
-	let rec loop i =
-		if i >= l then s ^ "." else
-		match s.[i] with
-		| '0' .. '9' | '-' -> loop (i+1)
-		| _ -> s
-	in loop 0
-
-let float_repres f =
-	match classify_float f with
-	| FP_nan -> "nan"
-	| FP_infinite ->
-		if f < 0.0 then "neg_infinity" else "infinity"
-	| _ ->
-		let float_val =
-			let s1 = Printf.sprintf "%.12g" f in
-			if f = float_of_string s1 then s1 else
-			let s2 = Printf.sprintf "%.15g" f in
-			if f = float_of_string s2 then s2 else
-			Printf.sprintf "%.18g" f
-		in valid_float_lexeme float_val
-
 let hash f =
 	let h = ref 0 in
 	for i = 0 to String.length f - 1 do
@@ -1213,6 +854,6 @@ let dump_context com = s_record_fields "" [
 	"platform",platform_name com.platform;
 	"std_path",s_list ", " (fun s -> s) com.std_path;
 	"class_path",s_list ", " (fun s -> s) com.class_path;
-	"defines",s_pmap (fun s -> s) (fun s -> s) com.defines;
-	"defines_signature",s_opt (fun s -> Digest.to_hex s) com.defines_signature;
-]
+	"defines",s_pmap (fun s -> s) (fun s -> s) com.defines.values;
+	"defines_signature",s_opt (fun s -> Digest.to_hex s) com.defines.defines_signature;
+]

+ 0 - 182
src/display/display.ml → src/context/display.ml

@@ -751,185 +751,3 @@ module Statistics = struct
 		if false then deal_with_imports ctx.com.shared.shared_display_information.import_positions;
 		symbols,relations
 end
-
-let explore_class_paths ctx class_paths recusive f_pack f_module f_type =
-	let rec loop dir pack =
-		try
-			let entries = Sys.readdir dir in
-			Array.iter (fun file ->
-				match file with
-					| "." | ".." ->
-						()
-					| _ when Sys.is_directory (dir ^ file) && file.[0] >= 'a' && file.[0] <= 'z' ->
-						f_pack file;
-						if recusive then loop (dir ^ file ^ "/") (file :: pack)
-					| _ ->
-						let l = String.length file in
-						if l > 3 && String.sub file (l - 3) 3 = ".hx" then begin
-							try
-								let name = String.sub file 0 (l - 3) in
-								let path = (List.rev pack,name) in
-								let md = ctx.g.do_load_module ctx path null_pos in
-								f_module md;
-								List.iter (fun mt -> f_type mt) md.m_types
-							with _ ->
-								()
-						end
-			) entries;
-		with Sys_error _ ->
-			()
-	in
-	List.iter (fun dir -> loop dir []) class_paths
-
-module ToplevelCollector = struct
-	open IdentifierType
-
-	let run ctx only_types =
-		let acc = DynArray.create () in
-		let add x = DynArray.add acc x in
-
-		if not only_types then begin
-			(* locals *)
-			PMap.iter (fun _ v ->
-				if not (is_gen_local v) then
-					add (ITLocal v)
-			) ctx.locals;
-
-			(* member vars *)
-			if ctx.curfun <> FunStatic then begin
-				let rec loop c =
-					List.iter (fun cf ->
-						if not (Meta.has Meta.NoCompletion cf.cf_meta) then add (ITMember(ctx.curclass,cf))
-					) c.cl_ordered_fields;
-					match c.cl_super with
-						| None ->
-							()
-						| Some (csup,tl) ->
-							loop csup; (* TODO: type parameters *)
-				in
-				loop ctx.curclass;
-				(* TODO: local using? *)
-			end;
-
-			(* statics *)
-			List.iter (fun cf ->
-				if not (Meta.has Meta.NoCompletion cf.cf_meta) then add (ITStatic(ctx.curclass,cf))
-			) ctx.curclass.cl_ordered_statics;
-
-			(* enum constructors *)
-			let rec enum_ctors t =
-				match t with
-				| TAbstractDecl ({a_impl = Some c} as a) when Meta.has Meta.Enum a.a_meta ->
-					List.iter (fun cf ->
-						if (Meta.has Meta.Enum cf.cf_meta) && not (Meta.has Meta.NoCompletion cf.cf_meta) then add (ITEnumAbstract(a,cf));
-					) c.cl_ordered_statics
-				| TClassDecl _ | TAbstractDecl _ ->
-					()
-				| TTypeDecl t ->
-					begin match follow t.t_type with
-						| TEnum (e,_) -> enum_ctors (TEnumDecl e)
-						| _ -> ()
-					end
-				| TEnumDecl e ->
-					PMap.iter (fun _ ef ->
-						add (ITEnum(e,ef))
-					) e.e_constrs;
-			in
-			List.iter enum_ctors ctx.m.curmod.m_types;
-			List.iter enum_ctors (List.map fst ctx.m.module_types);
-
-			(* imported globals *)
-			PMap.iter (fun _ (mt,s,_) ->
-				try
-					let t = match resolve_typedef mt with
-						| TClassDecl c -> (PMap.find s c.cl_statics).cf_type
-						| TEnumDecl en -> (PMap.find s en.e_constrs).ef_type
-						| TAbstractDecl {a_impl = Some c} -> (PMap.find s c.cl_statics).cf_type
-						| _ -> raise Not_found
-					in
-					add (ITGlobal(mt,s,t))
-				with Not_found ->
-					()
-			) ctx.m.module_globals;
-
-			(* literals *)
-			add (ITLiteral "null");
-			add (ITLiteral "true");
-			add (ITLiteral "false");
-		end;
-
-		let module_types = ref [] in
-
-		let add_type mt =
-			match mt with
-			| TClassDecl {cl_kind = KAbstractImpl _} -> ()
-			| _ ->
-				let path = (t_infos mt).mt_path in
-				if not (List.exists (fun mt2 -> (t_infos mt2).mt_path = path) !module_types) then begin
-					(match mt with
-					| TClassDecl c | TAbstractDecl { a_impl = Some c } when Meta.has Meta.CoreApi c.cl_meta ->
-						!merge_core_doc_ref ctx c
-					| _ -> ());
-					module_types := mt :: !module_types
-				end
-		in
-
-		(* module types *)
-		List.iter add_type ctx.m.curmod.m_types;
-
-		(* module imports *)
-		List.iter add_type (List.map fst ctx.m.module_types);
-
-		(* module using *)
-		List.iter (fun (c,_) ->
-			add_type (TClassDecl c)
-		) ctx.m.module_using;
-
-		(* TODO: wildcard packages. How? *)
-
-		(* packages and toplevel types *)
-		let class_paths = ctx.com.class_path in
-		let class_paths = List.filter (fun s -> s <> "") class_paths in
-
-		let packages = ref [] in
-		let add_package pack =
-			try
-				begin match PMap.find pack ctx.com.package_rules with
-					| Forbidden ->
-						()
-					| _ ->
-						raise Not_found
-				end
-			with Not_found ->
-				if not (List.mem pack !packages) then packages := pack :: !packages
-		in
-
-		let maybe_add_type mt = if not (t_infos mt).mt_private then add_type mt in
-
-		explore_class_paths ctx class_paths false add_package (fun _ -> ()) maybe_add_type;
-
-		List.iter (fun pack ->
-			add (ITPackage pack)
-		) !packages;
-
-		List.iter (fun mt ->
-			add (ITType mt)
-		) !module_types;
-
-		(* type params *)
-		List.iter (fun (_,t) ->
-			add (ITType (module_type_of_type t))
-		) ctx.type_params;
-
-		DynArray.to_list acc
-
-	let handle_unresolved_identifier ctx i p only_types =
-		let l = run ctx only_types in
-		let cl = List.map (fun it ->
-			let s = IdentifierType.get_name it in
-			(s,it),StringError.levenshtein i s
-		) l in
-		let cl = List.sort (fun (_,c1) (_,c2) -> compare c1 c2) cl in
-		let cl = StringError.filter_similar (fun (s,_) r -> r > 0 && r <= (min (String.length s) (String.length i)) / 3) cl in
-		ctx.com.display_information.unresolved_identifiers <- (i,p,cl) :: ctx.com.display_information.unresolved_identifiers
-end

+ 182 - 0
src/context/displayToplevel.ml

@@ -0,0 +1,182 @@
+open Common
+open Type
+open Typecore
+open Common.IdentifierType
+
+let explore_class_paths ctx class_paths recusive f_pack f_module f_type =
+	let rec loop dir pack =
+		try
+			let entries = Sys.readdir dir in
+			Array.iter (fun file ->
+				match file with
+					| "." | ".." ->
+						()
+					| _ when Sys.is_directory (dir ^ file) && file.[0] >= 'a' && file.[0] <= 'z' ->
+						f_pack file;
+						if recusive then loop (dir ^ file ^ "/") (file :: pack)
+					| _ ->
+						let l = String.length file in
+						if l > 3 && String.sub file (l - 3) 3 = ".hx" then begin
+							try
+								let name = String.sub file 0 (l - 3) in
+								let path = (List.rev pack,name) in
+								let md = ctx.g.do_load_module ctx path Globals.null_pos in
+								f_module md;
+								List.iter (fun mt -> f_type mt) md.m_types
+							with _ ->
+								()
+						end
+			) entries;
+		with Sys_error _ ->
+			()
+	in
+	List.iter (fun dir -> loop dir []) class_paths
+
+let collect ctx only_types =
+	let acc = DynArray.create () in
+	let add x = DynArray.add acc x in
+
+	if not only_types then begin
+		(* locals *)
+		PMap.iter (fun _ v ->
+			if not (is_gen_local v) then
+				add (ITLocal v)
+		) ctx.locals;
+
+		(* member vars *)
+		if ctx.curfun <> FunStatic then begin
+			let rec loop c =
+				List.iter (fun cf ->
+					if not (Meta.has Meta.NoCompletion cf.cf_meta) then add (ITMember(ctx.curclass,cf))
+				) c.cl_ordered_fields;
+				match c.cl_super with
+					| None ->
+						()
+					| Some (csup,tl) ->
+						loop csup; (* TODO: type parameters *)
+			in
+			loop ctx.curclass;
+			(* TODO: local using? *)
+		end;
+
+		(* statics *)
+		List.iter (fun cf ->
+			if not (Meta.has Meta.NoCompletion cf.cf_meta) then add (ITStatic(ctx.curclass,cf))
+		) ctx.curclass.cl_ordered_statics;
+
+		(* enum constructors *)
+		let rec enum_ctors t =
+			match t with
+			| TAbstractDecl ({a_impl = Some c} as a) when Meta.has Meta.Enum a.a_meta ->
+				List.iter (fun cf ->
+					if (Meta.has Meta.Enum cf.cf_meta) && not (Meta.has Meta.NoCompletion cf.cf_meta) then add (ITEnumAbstract(a,cf));
+				) c.cl_ordered_statics
+			| TClassDecl _ | TAbstractDecl _ ->
+				()
+			| TTypeDecl t ->
+				begin match follow t.t_type with
+					| TEnum (e,_) -> enum_ctors (TEnumDecl e)
+					| _ -> ()
+				end
+			| TEnumDecl e ->
+				PMap.iter (fun _ ef ->
+					add (ITEnum(e,ef))
+				) e.e_constrs;
+		in
+		List.iter enum_ctors ctx.m.curmod.m_types;
+		List.iter enum_ctors (List.map fst ctx.m.module_types);
+
+		(* imported globals *)
+		PMap.iter (fun _ (mt,s,_) ->
+			try
+				let t = match resolve_typedef mt with
+					| TClassDecl c -> (PMap.find s c.cl_statics).cf_type
+					| TEnumDecl en -> (PMap.find s en.e_constrs).ef_type
+					| TAbstractDecl {a_impl = Some c} -> (PMap.find s c.cl_statics).cf_type
+					| _ -> raise Not_found
+				in
+				add (ITGlobal(mt,s,t))
+			with Not_found ->
+				()
+		) ctx.m.module_globals;
+
+		(* literals *)
+		add (ITLiteral "null");
+		add (ITLiteral "true");
+		add (ITLiteral "false");
+	end;
+
+	let module_types = ref [] in
+
+	let add_type mt =
+		match mt with
+		| TClassDecl {cl_kind = KAbstractImpl _} -> ()
+		| _ ->
+			let path = (t_infos mt).mt_path in
+			if not (List.exists (fun mt2 -> (t_infos mt2).mt_path = path) !module_types) then begin
+				(match mt with
+				| TClassDecl c | TAbstractDecl { a_impl = Some c } when Meta.has Meta.CoreApi c.cl_meta ->
+					!merge_core_doc_ref ctx c
+				| _ -> ());
+				module_types := mt :: !module_types
+			end
+	in
+
+	(* module types *)
+	List.iter add_type ctx.m.curmod.m_types;
+
+	(* module imports *)
+	List.iter add_type (List.map fst ctx.m.module_types);
+
+	(* module using *)
+	List.iter (fun (c,_) ->
+		add_type (TClassDecl c)
+	) ctx.m.module_using;
+
+	(* TODO: wildcard packages. How? *)
+
+	(* packages and toplevel types *)
+	let class_paths = ctx.com.class_path in
+	let class_paths = List.filter (fun s -> s <> "") class_paths in
+
+	let packages = ref [] in
+	let add_package pack =
+		try
+			begin match PMap.find pack ctx.com.package_rules with
+				| Forbidden ->
+					()
+				| _ ->
+					raise Not_found
+			end
+		with Not_found ->
+			if not (List.mem pack !packages) then packages := pack :: !packages
+	in
+
+	let maybe_add_type mt = if not (t_infos mt).mt_private then add_type mt in
+
+	explore_class_paths ctx class_paths false add_package (fun _ -> ()) maybe_add_type;
+
+	List.iter (fun pack ->
+		add (ITPackage pack)
+	) !packages;
+
+	List.iter (fun mt ->
+		add (ITType mt)
+	) !module_types;
+
+	(* type params *)
+	List.iter (fun (_,t) ->
+		add (ITType (module_type_of_type t))
+	) ctx.type_params;
+
+	DynArray.to_list acc
+
+let handle_unresolved_identifier ctx i p only_types =
+	let l = collect ctx only_types in
+	let cl = List.map (fun it ->
+		let s = IdentifierType.get_name it in
+		(s,it),StringError.levenshtein i s
+	) l in
+	let cl = List.sort (fun (_,c1) (_,c2) -> compare c1 c2) cl in
+	let cl = StringError.filter_similar (fun (s,_) r -> r > 0 && r <= (min (String.length s) (String.length i)) / 3) cl in
+	ctx.com.display_information.unresolved_identifiers <- (i,p,cl) :: ctx.com.display_information.unresolved_identifiers

+ 0 - 0
src/display/displayTypes.ml → src/context/displayTypes.ml


+ 0 - 0
src/compiler/sourcemaps.ml → src/context/sourcemaps.ml


+ 27 - 12
src/typing/typecore.ml → src/context/typecore.ml

@@ -207,6 +207,14 @@ let save_locals ctx =
 
 let add_local ctx n t p =
 	let v = alloc_var n t p in
+	if Define.raw_defined ctx.com.defines "warn-var-shadowing" then begin
+		try
+			let v' = PMap.find n ctx.locals in
+			ctx.com.warning "This variable shadows a previously declared variable" p;
+			ctx.com.warning "Previous variable was here" v'.v_pos
+		with Not_found ->
+			()
+	end;
 	ctx.locals <- PMap.add n v ctx.locals;
 	v
 
@@ -268,14 +276,18 @@ let make_pass ctx f = f
 let init_class_done ctx =
 	ctx.pass <- PTypeField
 
-let exc_protect ctx f (where:string) =
-	let rec r = ref (fun() ->
+let exc_protect ?(force=true) ctx f (where:string) =
+	let r = ref (lazy_available t_dynamic) in
+	r := lazy_wait (fun() ->
 		try
-			f r
+			let t = f r in
+			r := lazy_available t;
+			t
 		with
 			| Error (m,p) ->
 				raise (Fatal_error ((error_msg m),p))
-	) in
+	);
+	if force then delay ctx PForce (fun () -> ignore(lazy_type r));
 	r
 
 let fake_modules = Hashtbl.create 0
@@ -286,7 +298,7 @@ let create_fake_module ctx file =
 			m_id = alloc_mid();
 			m_path = (["$DEP"],file);
 			m_types = [];
-			m_extra = module_extra file (Common.get_signature ctx.com) (file_time file) MFake [];
+			m_extra = module_extra file (Define.get_signature ctx.com.defines) (file_time file) MFake [];
 		} in
 		Hashtbl.add fake_modules file mdep;
 		mdep
@@ -476,7 +488,7 @@ module AbstractCast = struct
 						if not (has_mono t) then t
 						else t_dynamic
 				) a.a_params pl in
-				if com.platform = Globals.Js && a.a_path = ([],"Map") then begin match tl with
+				if com.platform = Globals.Js && a.a_path = (["haxe";"ds"],"Map") then begin match tl with
 					| t1 :: _ ->
 						let rec loop stack t =
 							if List.exists (fun t2 -> fast_eq t t2) stack then
@@ -721,15 +733,18 @@ let rec flush_pass ctx p where =
 let make_where ctx where =
 	where ^ " (" ^ ctx_pos ctx ^ ")"
 
-let exc_protect ctx f (where:string) =
-	let f = make_pass ~inf:(make_where ctx where) ctx f in
-	let rec r = ref (fun() ->
+let exc_protect ?(force=true) ctx f (where:string) =
+	let r = ref (lazy_available t_dynamic) in
+	r := lazy_wait (make_pass ~inf:(make_where ctx where) ctx (fun() ->
 		try
-			f r
+			let t = f r in
+			r := lazy_available t;
+			t
 		with
 			| Error (m,p) ->
-				raise (Fatal_error (error_msg m,p))
-	) in
+				raise (Fatal_error ((error_msg m),p))
+	));
+	if force then delay ctx PForce (fun () -> ignore(lazy_type r));
 	r
 
 */*)

+ 1 - 1
src/typing/abstract.ml → src/core/abstract.ml

@@ -29,7 +29,7 @@ let rec get_underlying_type a pl =
 				| Some t -> loop t
 				| _ -> t)
 			| TLazy f ->
-				loop (!f())
+				loop (lazy_type f)
 			| TAbstract({a_path=([],"Null")} as a,[t1]) ->
 				TAbstract(a,[loop t1])
 			| TType (t,tl) ->

+ 32 - 6
src/syntax/ast.ml → src/core/ast.ml

@@ -62,6 +62,7 @@ type keyword =
 	| False
 	| Abstract
 	| Macro
+	| Final
 
 type binop =
 	| OpAdd
@@ -136,6 +137,10 @@ type while_flag =
 	| NormalWhile
 	| DoWhile
 
+type quote_status =
+	| NoQuotes
+	| DoubleQuotes
+
 type type_path = {
 	tpackage : string list;
 	tname : string;
@@ -156,6 +161,7 @@ and complex_type =
 	| CTParent of type_hint
 	| CTExtend of placed_type_path list * class_field list
 	| CTOptional of type_hint
+	| CTNamed of placed_name * type_hint
 
 and type_hint = complex_type * pos
 
@@ -174,7 +180,7 @@ and expr_def =
 	| EBinop of binop * expr * expr
 	| EField of expr * string
 	| EParenthesis of expr
-	| EObjectDecl of (placed_name * expr) list
+	| EObjectDecl of ((string * pos * quote_status) * expr) list
 	| EArrayDecl of expr list
 	| ECall of expr * expr list
 	| ENew of placed_type_path * expr list
@@ -221,6 +227,7 @@ and access =
 	| ADynamic
 	| AInline
 	| AMacro
+	| AFinal
 
 and class_field_kind =
 	| FVar of type_hint option * expr option
@@ -362,6 +369,7 @@ let s_access = function
 	| ADynamic -> "dynamic"
 	| AInline -> "inline"
 	| AMacro -> "macro"
+	| AFinal -> "final"
 
 let s_keyword = function
 	| Function -> "function"
@@ -406,6 +414,7 @@ let s_keyword = function
 	| False -> "false"
 	| Abstract -> "abstract"
 	| Macro -> "macro"
+	| Final -> "final"
 
 let rec s_binop = function
 	| OpAdd -> "+"
@@ -551,7 +560,9 @@ let map_expr loop (e,p) =
 			let tl = List.map tpath tl in
 			let fl = List.map cfield fl in
 			CTExtend (tl,fl)
-		| CTOptional t -> CTOptional (type_hint t)),p
+		| CTOptional t -> CTOptional (type_hint t)
+		| CTNamed (n,t) -> CTNamed (n,type_hint t)
+		),p
 	and tparamdecl t =
 		let constraints = List.map type_hint t.tp_constraints in
 		let params = List.map tparamdecl t.tp_params in
@@ -585,7 +596,7 @@ let map_expr loop (e,p) =
 		EBinop (op,e1,e2)
 	| EField (e,f) -> EField (loop e, f)
 	| EParenthesis e -> EParenthesis (loop e)
-	| EObjectDecl fl -> EObjectDecl (List.map (fun ((f,p),e) -> (f,p),loop e) fl)
+	| EObjectDecl fl -> EObjectDecl (List.map (fun (k,e) -> k,loop e) fl)
 	| EArrayDecl el -> EArrayDecl (List.map loop el)
 	| ECall (e,el) ->
 		let e = loop e in
@@ -683,6 +694,10 @@ let iter_expr loop (e,p) =
 		opt f.f_expr
 	| EVars vl -> List.iter (fun (_,_,eo) -> opt eo) vl
 
+let s_object_key_name name =  function
+	| DoubleQuotes -> "\"" ^ s_escape name ^ "\""
+	| NoQuotes -> name
+
 let s_expr e =
 	let rec s_expr_inner tabs (e,_) =
 		match e with
@@ -691,7 +706,7 @@ let s_expr e =
 		| EBinop (op,e1,e2) -> s_expr_inner tabs e1 ^ " " ^ s_binop op ^ " " ^ s_expr_inner tabs e2
 		| EField (e,f) -> s_expr_inner tabs e ^ "." ^ f
 		| EParenthesis e -> "(" ^ (s_expr_inner tabs e) ^ ")"
-		| EObjectDecl fl -> "{ " ^ (String.concat ", " (List.map (fun ((n,_),e) -> n ^ " : " ^ (s_expr_inner tabs e)) fl)) ^ " }"
+		| EObjectDecl fl -> "{ " ^ (String.concat ", " (List.map (fun ((n,_,qs),e) -> (s_object_key_name n qs) ^ " : " ^ (s_expr_inner tabs e)) fl)) ^ " }"
 		| EArrayDecl el -> "[" ^ s_expr_list tabs el ", " ^ "]"
 		| ECall (e,el) -> s_expr_inner tabs e ^ "(" ^ s_expr_list tabs el ", " ^ ")"
 		| ENew (t,el) -> "new " ^ s_complex_type_path tabs t ^ "(" ^ s_expr_list tabs el ", " ^ ")"
@@ -745,6 +760,7 @@ let s_expr e =
 		| CTAnonymous fl -> "{ " ^ String.concat "; " (List.map (s_class_field tabs) fl) ^ "}";
 		| CTParent(t,_) -> "(" ^ s_complex_type tabs t ^ ")"
 		| CTOptional(t,_) -> "?" ^ s_complex_type tabs t
+		| CTNamed((n,_),(t,_)) -> n ^ ":" ^ s_complex_type tabs t
 		| CTExtend (tl, fl) -> "{> " ^ String.concat " >, " (List.map (s_complex_type_path tabs) tl) ^ ", " ^ String.concat ", " (List.map (s_class_field tabs) fl) ^ " }"
 	and s_class_field tabs f =
 		match f.cff_doc with
@@ -798,7 +814,7 @@ let s_expr e =
 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
+			| (_,[EObjectDecl values,_],_) -> List.fold_left (fun acc ((s,_,_),e) -> PMap.add s e acc) PMap.empty values
 			| _ -> raise Not_found
 		end
 	with Not_found ->
@@ -858,8 +874,18 @@ module Expr = struct
 
 	let field_assoc name fl =
 		let rec loop fl = match fl with
-			| ((name',_),e) :: fl -> if name' = name then e else loop fl
+			| ((name',_,_),e) :: fl -> if name' = name then e else loop fl
 			| [] -> raise Not_found
 		in
 		loop fl
+
+	let field_mem_assoc name fl =
+		let rec loop fl = match fl with
+			| ((name',_,_),e) :: fl -> if name' = name then raise Exit else loop fl
+			| [] -> false
+		in
+		try
+			loop fl
+		with Exit ->
+			true
 end

+ 291 - 0
src/core/define.ml

@@ -0,0 +1,291 @@
+open Globals
+
+type define = {
+	mutable values : (string,string) PMap.t;
+	mutable defines_signature : string option;
+}
+
+type strict_defined =
+	| AbsolutePath
+	| AdvancedTelemetry
+	| AnnotateSource
+	(* | Analyzer *)
+	| As3
+	| CheckXmlProxy
+	| CoreApi
+	| CoreApiSerialize
+	| Cppia
+	| NoCppiaAst
+	| Dce
+	| DceDebug
+	| Debug
+	| Display
+	| DisplayStdin
+	| DllExport
+	| DllImport
+	| DocGen
+	| Dump
+	| DumpDependencies
+	| DumpIgnoreVarIds
+	| DynamicInterfaceClosures
+	| EraseGenerics
+	| EvalDebugger
+	| EvalStack
+	| EvalTimes
+	| FastCast
+	| Fdb
+	| FileExtension
+	| FlashStrict
+	| FlashUseStage
+	| ForceLibCheck
+	| ForceNativeProperty
+	| FormatWarning
+	| GencommonDebug
+	| Haxe3Compat
+	| HaxeBoot
+	| HaxeVer
+	| HxcppApiLevel
+	| HxcppGcGenerational
+	| HxcppDebugger
+	| IncludePrefix
+	| Interp
+	| JavaVer
+	| JqueryVer
+	| JsClassic
+	| JsEs
+	| JsUnflatten
+	| JsSourceMap
+	| JsEnumsAsObjects
+	| SourceMap
+	| KeepOldOutput
+	| LoopUnrollMaxCost
+	| LuaVer
+	| LuaJit
+	| Macro
+	| MacroDebug
+	| MacroTimes
+	| NekoSource
+	| NekoV1
+	| NetworkSandbox
+	| NetVer
+	| NetTarget
+	| NoCompilation
+	| NoCOpt
+	| NoDeprecationWarnings
+	| NoFlashOverride
+	| NoDebug
+	| NoInline
+	| NoOpt
+	| NoRoot
+	| NoSwfCompress
+	| NoTraces
+	| Objc
+	| OldConstructorInline
+	| OldErrorFormat
+	| PhpLib
+	| PhpFront
+	| PhpPrefix
+	| PythonVersion
+	| RealPosition
+	| ReplaceFiles
+	| Scriptable
+	| ShallowExpose
+	| SourceHeader
+	| SourceMapContent
+	| Static
+	| Swc
+	| SwfCompressLevel
+	| SwfDebugPassword
+	| SwfDirectBlit
+	| SwfGpu
+	| SwfMetadata
+	| SwfPreloaderFrame
+	| SwfProtected
+	| SwfScriptTimeout
+	| SwfUseDoAbc
+	| Sys
+	| Unsafe
+	| UseNekoc
+	| UseRttiDoc
+	| Vcproj
+	| NoMacroCache
+	| Last (* must be last *)
+
+type define_parameter =
+	| HasParam of string
+	| Platform of platform
+	| Platforms of platform list
+
+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",[Platform Flash])
+	| AnnotateSource -> "annotate_source",("Add additional comments to generated source code",[Platform Cpp])
+	(* | Analyzer -> "analyzer",("Use static analyzer for optimization (experimental)") *)
+	| As3 -> "as3",("Defined when outputting 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",("Mark some generated core api classes with the Serializable attribute on C#",[Platform Cs])
+	| Cppia -> "cppia",("Generate cpp instruction assembly",[])
+	| NoCppiaAst -> "nocppiaast",("Use legacy cppia generation",[])
+	| Dce -> "dce",("<mode:std|full|no> Set the dead code elimination mode (default std)",[])
+	| DceDebug -> "dce_debug",("Show DCE log",[])
+	| Debug -> "debug",("Activated when compiling with -debug",[])
+	| Display -> "display",("Activated during completion",[])
+	| DisplayStdin -> "display_stdin",("Read the contents of a file specified in --display from standard input",[])
+	| DllExport -> "dll_export",("GenCPP experimental linking",[Platform Cpp])
+	| DllImport -> "dll_import",("Handle Haxe-generated .NET dll imports",[Platform Cs])
+	| DocGen -> "doc_gen",("Do not perform any removal/change in order to correctly generate documentation",[])
+	| Dump -> "dump",("<mode:pretty|record|legacy> Dump typed AST in dump subdirectory using specified mode or non-prettified default",[])
+	| DumpDependencies -> "dump_dependencies",("Dump the classes dependencies in a dump subdirectory",[])
+	| DumpIgnoreVarIds -> "dump_ignore_var_ids",("Remove variable IDs from non-pretty dumps (helps with diff)",[])
+	| DynamicInterfaceClosures -> "dynamic_interface_closures",("Use slow path for interface closures to save space",[Platform Cpp])
+	| EraseGenerics -> "erase_generics",("Erase generic classes on C#",[Platform Cs])
+	| EvalDebugger -> "eval_debugger",("Support debugger in macro/interp mode. Allows host:port value to open a socket. Implies eval_stack.",[])
+	| EvalStack -> "eval_stack",("Record stack information in macro/interp mode",[])
+	| EvalTimes -> "eval_times",("Record per-method execution times in macro/interp mode. Implies eval_stack.",[])
+	| FastCast -> "fast_cast",("Enables an experimental casts cleanup on C# and Java",[Platforms [Cs;Java]])
+	| Fdb -> "fdb",("Enable full flash debug infos for FDB interactive debugging",[Platform Flash])
+	| FileExtension -> "file_extension",("Output filename extension for cpp source code",[Platform Cpp])
+	| FlashStrict -> "flash_strict",("More strict typing for flash target",[Platform Flash])
+	| FlashUseStage -> "flash_use_stage",("Keep the SWF library initial stage",[Platform Flash])
+	(* 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)",[Platforms [Cs;Java]])
+	| ForceNativeProperty -> "force_native_property",("Tag all properties with :nativeProperty metadata for 3.1 compatibility",[Platform Cpp])
+	| FormatWarning -> "format_warning",("Print a warning for each formatted string, for 2.x compatibility",[])
+	| GencommonDebug -> "gencommon_debug",("GenCommon internal",[Platforms [Cs;Java]])
+	| Haxe3Compat -> "haxe3compat", ("Gives warnings about transition from Haxe 3.x to Haxe 4.0",[])
+	| HaxeBoot -> "haxe_boot",("Given the name 'haxe' to the flash boot class instead of a generated name",[Platform Flash])
+	| HaxeVer -> "haxe_ver",("The current Haxe version value",[])
+	| HxcppApiLevel -> "hxcpp_api_level",("Provided to allow compatibility between hxcpp versions",[Platform Cpp])
+	| HxcppGcGenerational -> "HXCPP_GC_GENERATIONAL",("Experimental Garbage Collector",[Platform Cpp])
+	| HxcppDebugger -> "HXCPP_DEBUGGER",("Include additional information for HXCPP_DEBUGGER",[Platform Cpp])
+	| IncludePrefix -> "include_prefix",("prepend path to generated include files",[Platform Cpp])
+	| Interp -> "interp",("The code is compiled to be run with --interp",[])
+	| JavaVer -> "java_ver",("<version:5-7> Sets the Java version to be targeted",[Platform Java])
+	| JqueryVer -> "jquery_ver",("The jQuery version supported by js.jquery.*. The version is encoded as an integer. e.g. 1.11.3 is encoded as 11103",[Platform Js])
+	| JsClassic -> "js_classic",("Don't use a function wrapper and strict mode in JS output",[Platform Js])
+	| JsEs -> "js_es",("Generate JS compliant with given ES standard version (default 5)",[Platform Js; HasParam "version number"])
+	| JsEnumsAsObjects -> "js_enums_as_objects",("Generate enum representation as object instead of as array",[Platform Js])
+	| JsUnflatten -> "js_unflatten",("Generate nested objects for packages and types",[Platform Js])
+	| JsSourceMap -> "js_source_map",("Generate JavaScript source map even in non-debug mode",[Platform Js])
+	| SourceMap -> "source_map",("Generate source map for compiled files (Currently supported for php only)",[Platform Php])
+	| KeepOldOutput -> "keep_old_output",("Keep old source files in the output directory (for C#/Java)",[Platforms [Cs;Java]])
+	| LoopUnrollMaxCost -> "loop_unroll_max_cost",("Maximum cost (number of expressions * iterations) before loop unrolling is canceled (default 250)",[])
+	| LuaJit -> "lua_jit",("Enable the jit compiler for lua (version 5.2 only)",[Platform Lua])
+	| LuaVer -> "lua_ver",("The lua version to target",[Platform Lua])
+	| Macro -> "macro",("Defined when code is compiled in the macro context",[])
+	| MacroDebug -> "macro_debug",("Show warnings for potential macro problems (e.g. macro-in-macro calls)",[])
+	| MacroTimes -> "macro_times",("Display per-macro timing when used with --times",[])
+	| NetVer -> "net_ver",("<version:20-45> Sets the .NET version to be targeted",[Platform Cs])
+	| NetTarget -> "net_target",("<name> Sets the .NET target. Defaults to \"net\". xbox, micro (Micro Framework), compact (Compact Framework) are some valid values",[Platform Cs])
+	| NekoSource -> "neko_source",("Output neko source instead of bytecode",[Platform Neko])
+	| NekoV1 -> "neko_v1",("Keep Neko 1.x compatibility",[Platform Neko])
+	| NetworkSandbox -> "network-sandbox",("Use local network sandbox instead of local file access one",[Platform Flash])
+	| NoCompilation -> "no-compilation",("Disable final compilation",[Platforms [Cs;Java;Cpp;Hl]])
+	| 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",[])
+	| NoFlashOverride -> "no-flash-override",("Change overrides on some basic classes into HX suffixed methods, flash only",[Platform Flash])
+	| NoOpt -> "no_opt",("Disable optimizations",[])
+	| NoInline -> "no_inline",("Disable inlining",[])
+	| NoRoot -> "no_root",("Generate top-level types into haxe.root namespace",[Platform Cs])
+	| NoMacroCache -> "no_macro_cache",("Disable macro context caching",[])
+	| NoSwfCompress -> "no_swf_compress",("Disable SWF output compression",[Platform Flash])
+	| NoTraces -> "no_traces",("Disable all trace calls",[])
+	| Objc -> "objc",("Sets the hxcpp output to objective-c++ classes. Must be defined for interop",[Platform Cpp])
+	| OldConstructorInline -> "old-constructor-inline",("Use old constructor inlining logic (from haxe 3.4.2) instead of the reworked version.",[])
+	| OldErrorFormat -> "old-error-format",("Use Haxe 3.x zero-based column error messages instead of new one-based format.",[])
+	| PhpPrefix -> "php_prefix",("Root namespace for generated php classes. E.g. if compiled with`-D php-prefix=some.sub`, then all classes will be generated in `\\some\\sub` namespace.",[Platform Php])
+	| PhpLib -> "php_lib",("Select the name for the php lib folder.",[Platform Php])
+	| PhpFront -> "php_front",("Select the name for the php front file (by default: `index.php`).", [Platform Php])
+	| PythonVersion -> "python_version",("The python version to target (default 3.3)",[Platform Python])
+	| RealPosition -> "real_position",("Disables Haxe source mapping when targetting C#, removes position comments in Java and Php output",[Platforms [Cs;Java;Php]])
+	| ReplaceFiles -> "replace_files",("GenCommon internal",[Platforms [Java;Cs]])
+	| Scriptable -> "scriptable",("GenCPP internal",[Platform Cpp])
+	| ShallowExpose -> "shallow-expose",("Expose types to surrounding scope of Haxe generated closure without writing to window object",[Platform Js])
+	| SourceHeader -> "source-header",("Print value as comment on top of generated files, use '' value to disable",[])
+	| SourceMapContent -> "source-map-content",("Include the hx sources as part of the JS source map",[Platform Js])
+	| Static -> "static",("Defined if the current target is static",[])
+	| Swc -> "swc",("Output a SWC instead of a SWF",[Platform Flash])
+	| SwfCompressLevel -> "swf_compress_level",("<level:1-9> Set the amount of compression for the SWF output",[Platform Flash])
+	| SwfDebugPassword -> "swf_debug_password",("Set a password for debugging",[Platform Flash])
+	| SwfDirectBlit -> "swf_direct_blit",("Use hardware acceleration to blit graphics",[Platform Flash])
+	| SwfGpu -> "swf_gpu",("Use GPU compositing features when drawing graphics",[Platform Flash])
+	| SwfMetadata -> "swf_metadata",("<file> Include contents of <file> as metadata in the swf",[Platform Flash])
+	| SwfPreloaderFrame -> "swf_preloader_frame",("Insert empty first frame in swf",[Platform Flash])
+	| SwfProtected -> "swf_protected",("Compile Haxe private as protected in the SWF instead of public",[Platform Flash])
+	| SwfScriptTimeout -> "swf_script_timeout",("Maximum ActionScript processing time before script stuck dialog box displays (in seconds)",[Platform Flash])
+	| SwfUseDoAbc -> "swf_use_doabc",("Use DoAbc swf-tag instead of DoAbcDefine",[Platform Flash])
+	| Sys -> "sys",("Defined for all system platforms",[])
+	| Unsafe -> "unsafe",("Allow unsafe code when targeting C#",[Platform Cs])
+	| UseNekoc -> "use_nekoc",("Use nekoc compiler instead of internal one",[Platform Neko])
+	| UseRttiDoc -> "use_rtti_doc",("Allows access to documentation during compilation",[])
+	| Vcproj -> "vcproj",("GenCPP internal",[Platform Cpp])
+	| Last -> assert false
+
+let get_documentation_list() =
+	let m = ref 0 in
+	let rec loop i =
+		let d = Obj.magic i in
+		if d <> Last then begin
+			let t, (doc,flags) = infos d in
+			let pfs = ref [] in
+			List.iter (function
+			| HasParam s -> () (* TODO *)
+			| Platform p -> pfs := p :: !pfs;
+			| Platforms pl -> pfs := pl @ !pfs;
+			) flags;
+			let pfs = platform_list_help (List.rev !pfs) in
+			if String.length t > !m then m := String.length t;
+			((String.concat "-" (ExtString.String.nsplit t "_")),doc ^ pfs) :: (loop (i + 1))
+		end else
+			[]
+	in
+	let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in
+	all,!m
+
+let raw_defined ctx v =
+	PMap.mem v ctx.values
+
+let defined ctx v =
+	raw_defined ctx (fst (infos v))
+
+let raw_defined_value ctx k =
+	PMap.find k ctx.values
+
+let defined_value ctx v =
+	raw_defined_value ctx (fst (infos v))
+
+let defined_value_safe ?default ctx v =
+	try defined_value ctx v
+	with Not_found -> match default with Some s -> s | None -> ""
+
+let raw_define ctx v =
+	let k,v = try ExtString.String.split v "=" with _ -> v,"1" in
+	ctx.values <- PMap.add k v ctx.values;
+	let k = String.concat "_" (ExtString.String.nsplit k "-") in
+	ctx.values <- PMap.add k v ctx.values;
+	ctx.defines_signature <- None
+
+let define_value ctx k v =
+	raw_define ctx (fst (infos k) ^ "=" ^ v)
+
+let define ctx v =
+	raw_define ctx (fst (infos v))
+
+let get_signature def =
+	match def.defines_signature with
+	| Some s -> s
+	| None ->
+		let defines = PMap.foldi (fun k v acc ->
+			(* don't make much difference between these special compilation flags *)
+			match String.concat "_" (ExtString.String.nsplit k "-") with
+			(* If we add something here that might be used in conditional compilation it should be added to
+			   Parser.parse_macro_ident as well (issue #5682). *)
+			| "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" | "display_stdin" -> acc
+			| _ -> (k ^ "=" ^ v) :: acc
+		) def.values [] in
+		let str = String.concat "@" (List.sort compare defines) in
+		let s = Digest.string str in
+		def.defines_signature <- Some s;
+		s

+ 0 - 0
src/typing/error.ml → src/core/error.ml


+ 0 - 0
src/compiler/globals.ml → src/core/globals.ml


+ 0 - 0
src/compiler/json.ml → src/core/json.ml


+ 9 - 13
src/context/meta.ml → src/core/meta.ml

@@ -89,7 +89,7 @@ type strict_meta =
 	| LibType
 	| LoopLabel
 	| LuaRequire
-	| LuaDotMethod 
+	| LuaDotMethod
 	| Meta
 	| Macro
 	| MaybeUsed
@@ -119,7 +119,6 @@ type strict_meta =
 	| Op
 	| Optional
 	| Overload
-	| PhpConstants
 	| PhpGlobal
 	| PhpClassConst
 	| PhpMagic
@@ -131,7 +130,6 @@ type strict_meta =
 	| Public
 	| PublicFields
 	| Pure
-	| QuotedField
 	| ReadOnly
 	| RealPath
 	| Remove
@@ -317,15 +315,13 @@ let get_info = function
 	| Op -> ":op",("Declares an abstract field as being an operator overload",[HasParam "The operation";UsedOn TAbstractField])
 	| Optional -> ":optional",("Marks the field of a structure as optional",[UsedOn TClassField])
 	| Overload -> ":overload",("Allows the field to be called with different argument types",[HasParam "Function specification (no expression)";UsedOn TClassField])
-	| PhpConstants -> ":phpConstants",("Marks the static fields of a class as PHP constants, without $",[Platform Php;UsedOn TClass])
-	| PhpGlobal -> ":phpGlobal",("(php7) Puts the static fields of a class in the global PHP namespace",[Platform Php;UsedOn TClass])
-	| PhpClassConst -> ":phpClassConst",("(php7)  Generate static var of an extern class as a PHP class constant",[Platform Php;UsedOn TClass])
-	| PhpMagic -> ":phpMagic",("(php7) Treat annotated field as special PHP magic field",[Platform Php;UsedOn TClassField])
-	| PhpNoConstructor -> ":phpNoConstructor",("(php7) Special meta for extern classes which does not have native constructor in PHP, but need a constructor in Haxe extern",[Platform Php;UsedOn TClass])
+	| PhpGlobal -> ":phpGlobal",("Indicates that static fields of an extern class actually are located in the global PHP namespace",[Platform Php;UsedOn TClass])
+	| PhpClassConst -> ":phpClassConst",("Indicates that a static var of an extern class is a PHP class constant",[Platform Php;UsedOn TClassField])
+	| PhpMagic -> ":phpMagic",("Treat annotated field as special PHP magic field. This meta makes compiler avoid renaming such fields on generating PHP code.",[Platform Php;UsedOn TClassField])
+	| PhpNoConstructor -> ":phpNoConstructor",("Special meta for extern classes which do not have native constructor in PHP, but need a constructor in Haxe extern",[Platform Php;UsedOn TClass])
 	| Pos -> ":pos",("Sets the position of a reified expression",[HasParam "Position";UsedOn TExpr])
 	| Public -> ":public",("Marks a class field as being public",[UsedOn TClassField;UsedInternally])
 	| PublicFields -> ":publicFields",("Forces all class fields of inheriting classes to be public",[UsedOn TClass])
-	| QuotedField -> ":quotedField",("Used internally to mark structure fields which are quoted in syntax",[UsedInternally])
 	| PrivateAccess -> ":privateAccess",("Allow private access to anything for the annotated expression",[UsedOn TExpr])
 	| Protected -> ":protected",("Marks a class field as being protected",[UsedOn TClassField;Platforms [Cs;Java;Flash]])
 	| Property -> ":property",("Marks a property field to be compiled as a native C# property",[UsedOn TClassField;Platform Cs])
@@ -336,11 +332,11 @@ let get_info = function
 	| 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",[UsedInternally])
 	| Resolve -> ":resolve",("Abstract fields marked with this metadata can be used to resolve unknown fields",[UsedOn TClassField])
-	| Rtti -> ":rtti",("Adds runtime type informations",[UsedOn TClass])
+	| Rtti -> ":rtti",("Adds runtime type information",[UsedOn TClass])
 	| Runtime -> ":runtime",("?",[])
 	| RuntimeValue -> ":runtimeValue",("Marks an abstract as being a runtime value",[UsedOn TAbstract])
 	| Scalar -> ":scalar",("Used by hxcpp to mark a custom coreType abstract",[UsedOn TAbstract; Platform Cpp])
-	| SelfCall -> ":selfCall",("Translates method calls into calling object directly",[UsedOn TClassField; Platform Js])
+	| SelfCall -> ":selfCall",("Translates method calls into calling object directly",[UsedOn TClassField; Platforms [Js;Lua]])
 	| Setter -> ":setter",("Generates a native setter function on the given field",[HasParam "Class field name";UsedOn TClassField;Platform Flash])
 	| StackOnly -> ":stackOnly",("Instances of this type can only appear on the stack",[Platform Cpp])
 	| StoredTypedExpr -> ":storedTypedExpr",("Used internally to reference a typed expression returned from a macro",[UsedInternally])
@@ -351,9 +347,9 @@ let get_info = function
 	| 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])
-	| StructInit -> ":structInit",("Allows to initialize the class with a structure that matches constructor parameters",[UsedOn TClass])
+	| StructInit -> ":structInit",("Allows one to initialize the class with a structure that matches constructor parameters",[UsedOn TClass])
 	| SuppressWarnings -> ":suppressWarnings",("Adds a SuppressWarnings annotation for the generated Java class",[Platform Java; UsedOn TClass])
-	| TemplatedCall -> ":templatedCall",("Indicates that the first parameter of static call should be treated as a template arguement",[Platform Cpp; UsedOn TClassField])
+	| TemplatedCall -> ":templatedCall",("Indicates that the first parameter of static call should be treated as a template argument",[Platform Cpp; 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",[UsedInternally; UsedOn TExpr])
 	| To -> ":to",("Specifies that the field of the abstract is a cast operation to the type identified in the function",[UsedOn TAbstractField])

+ 74 - 0
src/core/numeric.ml

@@ -0,0 +1,74 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2017  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
+(*  Taken from OCaml source typing/oprint.ml
+
+	This is a better version of string_of_float which prints without loss of precision
+	so that float_of_string (float_repres x) = x for all floats x
+*)
+let valid_float_lexeme s =
+	let l = String.length s in
+	let rec loop i =
+		if i >= l then s ^ "." else
+		match s.[i] with
+		| '0' .. '9' | '-' -> loop (i+1)
+		| _ -> s
+	in loop 0
+
+let float_repres f =
+	match classify_float f with
+	| FP_nan -> "nan"
+	| FP_infinite ->
+		if f < 0.0 then "neg_infinity" else "infinity"
+	| _ ->
+		let float_val =
+			let s1 = Printf.sprintf "%.12g" f in
+			if f = float_of_string s1 then s1 else
+			let s2 = Printf.sprintf "%.15g" f in
+			if f = float_of_string s2 then s2 else
+			Printf.sprintf "%.18g" f
+		in valid_float_lexeme float_val
+
+let parse_float s =
+	let rec loop sp i =
+		if i = String.length s then (if sp = 0 then s else String.sub s sp (i - sp)) else
+		match String.unsafe_get s i with
+		| ' ' when sp = i -> loop (sp + 1) (i + 1)
+		| '0'..'9' | '-' | '+' | 'e' | 'E' | '.' -> loop sp (i + 1)
+		| _ -> String.sub s sp (i - sp)
+	in
+	float_of_string (loop 0 0)
+
+let parse_int s =
+	let rec loop_hex i =
+		if i = String.length s then s else
+		match String.unsafe_get s i with
+		| '0'..'9' | 'a'..'f' | 'A'..'F' -> loop_hex (i + 1)
+		| _ -> String.sub s 0 i
+	in
+	let rec loop sp i =
+		if i = String.length s then (if sp = 0 then s else String.sub s sp (i - sp)) else
+		match String.unsafe_get s i with
+		| '0'..'9' -> loop sp (i + 1)
+		| ' ' when sp = i -> loop (sp + 1) (i + 1)
+		| '-' when i = 0 -> loop sp (i + 1)
+		| ('x' | 'X') when i = 1 && String.get s 0 = '0' -> loop_hex (i + 1)
+		| _ -> String.sub s sp (i - sp)
+	in
+	Int32.of_string (loop 0 0)

+ 47 - 1
src/compiler/path.ml → src/core/path.ml

@@ -153,4 +153,50 @@ let find_directories target recursive paths =
 		with Sys_error _ ->
 			acc
 	in
-	List.fold_left (fun acc dir -> loop acc dir) [] paths
+	List.fold_left (fun acc dir -> loop acc dir) [] paths
+
+let make_valid_filename s =
+	let r = Str.regexp "[^A-Za-z0-9_\\-\\.,]" in
+	Str.global_substitute r (fun s -> "_") s
+
+let rec create_file bin ext acc = function
+	| [] -> assert false
+	| d :: [] ->
+		let d = make_valid_filename d in
+		let maxlen = 200 - String.length ext in
+		let d = if String.length d > maxlen then String.sub d 0 maxlen else d in
+		let ch = (if bin then open_out_bin else open_out) (String.concat "/" (List.rev (d :: acc)) ^ ext) in
+		ch
+	| d :: l ->
+		let dir = String.concat "/" (List.rev (d :: acc)) in
+		if not (Sys.file_exists (remove_trailing_slash dir)) then Unix.mkdir dir 0o755;
+		create_file bin ext (d :: acc) l
+
+let rec mkdir_recursive base dir_list =
+	match dir_list with
+	| [] -> ()
+	| dir :: remaining ->
+		let path = match base with
+				   | "" ->  dir
+				   | "/" -> "/" ^ dir
+				   | _ -> base ^ "/" ^ dir
+		in
+		let path_len = String.length path in
+		let path =
+			if path_len > 0 && (path.[path_len - 1] = '/' || path.[path_len - 1] == '\\') then
+				String.sub path 0 (path_len - 1)
+			else
+				path
+		in
+		if not ( (path = "") || ( (path_len = 2) && ((String.sub path 1 1) = ":") ) ) then
+			if not (Sys.file_exists path) then
+				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

+ 388 - 0
src/core/texpr.ml

@@ -0,0 +1,388 @@
+open Globals
+open Ast
+open Type
+open Error
+
+let equal_fa fa1 fa2 = match fa1,fa2 with
+	| FStatic(c1,cf1),FStatic(c2,cf2) -> c1 == c2 && cf1 == cf2
+	| FInstance(c1,tl1,cf1),FInstance(c2,tl2,cf2) -> c1 == c2 && safe_for_all2 type_iseq tl1 tl2 && cf1 == cf2
+	(* TODO: This is technically not correct but unfortunately the compiler makes a distinct tclass_field for each anon field access. *)
+	| FAnon cf1,FAnon cf2 -> cf1.cf_name = cf2.cf_name
+	| FDynamic s1,FDynamic s2 -> s1 = s2
+	| FClosure(None,cf1),FClosure(None,cf2) -> cf1 == cf2
+	| FClosure(Some(c1,tl1),cf1),FClosure(Some(c2,tl2),cf2) -> c1 == c2 && safe_for_all2 type_iseq tl1 tl2 && cf1 == cf2
+	| FEnum(en1,ef1),FEnum(en2,ef2) -> en1 == en2 && ef1 == ef2
+	| _ -> false
+
+let rec equal e1 e2 = match e1.eexpr,e2.eexpr with
+	| TConst ct1,TConst ct2 -> ct1 = ct2
+	| TLocal v1,TLocal v2 -> v1 == v2
+	| TArray(eb1,ei1),TArray(eb2,ei2) -> equal eb1 eb2 && equal ei1 ei2
+	| TBinop(op1,lhs1,rhs1),TBinop(op2,lhs2,rhs2) -> op1 = op2 && equal lhs1 lhs2 && equal rhs1 rhs2
+	| TField(e1,fa1),TField(e2,fa2) -> equal e1 e2 && equal_fa fa1 fa2
+	| TTypeExpr mt1,TTypeExpr mt2 -> mt1 == mt2
+	| TParenthesis e1,TParenthesis e2 -> equal e1 e2
+	| TObjectDecl fl1,TObjectDecl fl2 -> safe_for_all2 (fun (s1,e1) (s2,e2) -> s1 = s2 && equal e1 e2) fl1 fl2
+	| (TArrayDecl el1,TArrayDecl el2) | (TBlock el1,TBlock el2) -> safe_for_all2 equal el1 el2
+	| TCall(e1,el1),TCall(e2,el2) -> equal e1 e2 && safe_for_all2 equal el1 el2
+	| TNew(c1,tl1,el1),TNew(c2,tl2,el2) -> c1 == c2 && safe_for_all2 type_iseq tl1 tl2 && safe_for_all2 equal el1 el2
+	| TUnop(op1,flag1,e1),TUnop(op2,flag2,e2) -> op1 = op2 && flag1 = flag2 && equal e1 e2
+	| TFunction tf1,TFunction tf2 -> tf1 == tf2
+	| TVar(v1,None),TVar(v2,None) -> v1 == v2
+	| TVar(v1,Some e1),TVar(v2,Some e2) -> v1 == v2 && equal e1 e2
+	| TFor(v1,ec1,eb1),TFor(v2,ec2,eb2) -> v1 == v2 && equal ec1 ec2 && equal eb1 eb2
+	| TIf(e1,ethen1,None),TIf(e2,ethen2,None) -> equal e1 e2 && equal ethen1 ethen2
+	| TIf(e1,ethen1,Some eelse1),TIf(e2,ethen2,Some eelse2) -> equal e1 e2 && equal ethen1 ethen2 && equal eelse1 eelse2
+	| TWhile(e1,eb1,flag1),TWhile(e2,eb2,flag2) -> equal e1 e2 && equal eb2 eb2 && flag1 = flag2
+	| TSwitch(e1,cases1,eo1),TSwitch(e2,cases2,eo2) ->
+		equal e1 e2 &&
+		safe_for_all2 (fun (el1,e1) (el2,e2) -> safe_for_all2 equal el1 el2 && equal e1 e2) cases1 cases2 &&
+		(match eo1,eo2 with None,None -> true | Some e1,Some e2 -> equal e1 e2 | _ -> false)
+	| TTry(e1,catches1),TTry(e2,catches2) -> equal e1 e2 && safe_for_all2 (fun (v1,e1) (v2,e2) -> v1 == v2 && equal e1 e2) catches1 catches2
+	| TReturn None,TReturn None -> true
+	| TReturn(Some e1),TReturn(Some e2) -> equal e1 e2
+	| TThrow e1,TThrow e2 -> equal e1 e2
+	| TCast(e1,None),TCast(e2,None) -> equal e1 e2
+	| TCast(e1,Some mt1),TCast(e2,Some mt2) -> equal e1 e2 && mt1 == mt2
+	| TMeta((m1,el1,_),e1),TMeta((m2,el2,_),e2) -> m1 = m2 && safe_for_all2 (fun e1 e2 -> (* TODO: cheating? *) (Ast.s_expr e1) = (Ast.s_expr e2)) el1 el2 && equal e1 e2
+	| (TBreak,TBreak) | (TContinue,TContinue) -> true
+	| TEnumParameter(e1,ef1,i1),TEnumParameter(e2,ef2,i2) -> equal e1 e2 && ef1 == ef2 && i1 = i2
+	| _ -> false
+
+let duplicate_tvars e =
+	let vars = Hashtbl.create 0 in
+	let copy_var v =
+		let v2 = alloc_var v.v_name v.v_type v.v_pos in
+		v2.v_meta <- v.v_meta;
+		v2.v_extra <- v.v_extra;
+		Hashtbl.add vars v.v_id v2;
+		v2;
+	in
+	let rec build_expr e =
+		match e.eexpr with
+		| TVar (v,eo) ->
+			let v2 = copy_var v in
+			{e with eexpr = TVar(v2, Option.map build_expr eo)}
+		| TFor (v,e1,e2) ->
+			let v2 = copy_var v in
+			{e with eexpr = TFor(v2, build_expr e1, build_expr e2)}
+		| TTry (e1,cl) ->
+			let cl = List.map (fun (v,e) ->
+				let v2 = copy_var v in
+				v2, build_expr e
+			) cl in
+			{e with eexpr = TTry(build_expr e1, cl)}
+		| TFunction f ->
+			let args = List.map (fun (v,c) -> copy_var v, c) f.tf_args in
+			let f = {
+				tf_args = args;
+				tf_type = f.tf_type;
+				tf_expr = build_expr f.tf_expr;
+			} in
+			{e with eexpr = TFunction f}
+		| TLocal v ->
+			(try
+				let v2 = Hashtbl.find vars v.v_id in
+				{e with eexpr = TLocal v2}
+			with _ ->
+				e)
+		| _ ->
+			map_expr build_expr e
+	in
+	build_expr e
+
+let rec skip e = match e.eexpr with
+	| TParenthesis e1 | TMeta(_,e1) | TBlock [e1] | TCast(e1,None) -> skip e1
+	| _ -> e
+
+let foldmap_list f acc el =
+	let rec loop acc el acc2 = (match el with
+		| [] -> acc,(List.rev acc2)
+		| e1 :: el ->
+			let acc,e1 = f acc e1 in
+			loop acc el (e1 :: acc2))
+	in loop acc el []
+
+let foldmap_opt f acc eo = match eo with
+	| Some(e) -> let acc,e = f acc e in acc,Some(e)
+	| None    -> acc,eo
+
+let foldmap_pairs f acc pairs =
+	let acc,pairs = List.fold_left
+		(fun (acc,el) (v,e) -> let acc,e = f acc e in (acc,(v,e) :: el))
+		(acc,[])
+		pairs
+	in acc,(List.rev pairs)
+
+let foldmap f acc e =
+	begin match e.eexpr with
+	| TConst _
+	| TLocal _
+	| TBreak
+	| TContinue
+	| TTypeExpr _
+	| TIdent _ ->
+		acc,e
+	| TArray (e1,e2) ->
+		let acc,e1 = f acc e1 in
+		let acc,e2 = f acc e2 in
+		acc,{ e with eexpr = TArray (e1, e2) }
+	| TBinop (op,e1,e2) ->
+		let acc,e1 = f acc e1 in
+		let acc,e2 = f acc e2 in
+		acc,{ e with eexpr = TBinop (op,e1,e2) }
+	| TFor (v,e1,e2) ->
+		let acc,e1 = f acc e1 in
+		let acc,e2 = f acc e2 in
+		acc,{ e with eexpr = TFor (v,e1,e2) }
+	| TWhile (e1,e2,flag) ->
+		let acc,e1 = f acc e1 in
+		let acc,e2 = f acc e2 in
+		acc,{ e with eexpr = TWhile (e1,e2,flag) }
+	| TThrow e1 ->
+		let acc,e1 = f acc e1 in
+		acc,{ e with eexpr = TThrow (e1) }
+	| TEnumParameter (e1,ef,i) ->
+		let acc,e1 = f acc e1 in
+		acc,{ e with eexpr = TEnumParameter(e1,ef,i) }
+	| TEnumIndex e1 ->
+		let acc,e1 = f acc e1 in
+		acc,{ e with eexpr = TEnumIndex e1 }
+	| TField (e1,v) ->
+		let acc,e1 = f acc e1 in
+		acc,{ e with eexpr = TField (e1,v) }
+	| TParenthesis e1 ->
+		let acc,e1 = f acc e1 in
+		acc,{ e with eexpr = TParenthesis (e1) }
+	| TUnop (op,pre,e1) ->
+		let acc,e1 = f acc e1 in
+		acc,{ e with eexpr = TUnop (op,pre,e1) }
+	| TArrayDecl el ->
+		let acc,el = foldmap_list f acc el in
+		acc,{ e with eexpr = TArrayDecl el }
+	| TNew (t,pl,el) ->
+		let acc,el = foldmap_list f acc el in
+		acc,{ e with eexpr = TNew (t,pl,el) }
+	| TBlock el ->
+		let acc,el = foldmap_list f acc el in
+		acc,{ e with eexpr = TBlock (el) }
+	| TObjectDecl el ->
+		let acc,el = foldmap_pairs f acc el in
+		acc,{ e with eexpr = TObjectDecl el }
+	| TCall (e1,el) ->
+		let acc,e1 = f acc e1 in
+		let acc,el = foldmap_list f acc el in
+		acc,{ e with eexpr = TCall (e1,el) }
+	| TVar (v,eo) ->
+		let acc,eo = foldmap_opt f acc eo in
+		acc,{ e with eexpr = TVar (v, eo) }
+	| TFunction fu ->
+		let acc,e1 = f acc fu.tf_expr in
+		acc,{ e with eexpr = TFunction { fu with tf_expr = e1 } }
+	| TIf (ec,e1,eo) ->
+		let acc,ec = f acc ec in
+		let acc,e1 = f acc e1 in
+		let acc,eo = foldmap_opt f acc eo in
+		acc,{ e with eexpr = TIf (ec,e1,eo)}
+	| TSwitch (e1,cases,def) ->
+		let acc,e1 = f acc e1 in
+		let acc,cases = List.fold_left (fun (acc,cases) (el,e2) ->
+			let acc,el = foldmap_list f acc el in
+			let acc,e2 = f acc e2 in
+			acc,((el,e2) :: cases)
+		) (acc,[]) cases in
+		let acc,def = foldmap_opt f acc def in
+		acc,{ e with eexpr = TSwitch (e1, cases, def) }
+	| TTry (e1,catches) ->
+		let acc,e1 = f acc e1 in
+		let acc,catches = foldmap_pairs f acc catches in
+		acc,{ e with eexpr = TTry (e1, catches) }
+	| TReturn eo ->
+		let acc,eo = foldmap_opt f acc eo in
+		acc,{ e with eexpr = TReturn eo }
+	| TCast (e1,t) ->
+		let acc,e1 = f acc e1 in
+		acc,{ e with eexpr = TCast (e1,t) }
+	| TMeta (m,e1) ->
+		let acc,e1 = f acc e1 in
+		acc,{ e with eexpr = TMeta(m,e1)}
+	end
+
+(* Collection of functions that return expressions *)
+module Builder = struct
+	let make_static_this c p =
+		let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in
+		mk (TTypeExpr (TClassDecl c)) ta p
+
+	let make_typeexpr mt pos =
+		let t =
+			match mt with
+			| TClassDecl c -> TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) }
+			| TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }
+			| TAbstractDecl a -> TAnon { a_fields = PMap.empty; a_status = ref (AbstractStatics a) }
+			| _ -> assert false
+		in
+		mk (TTypeExpr mt) t pos
+
+	let make_static_field c cf p =
+		let e_this = make_static_this c p in
+		mk (TField(e_this,FStatic(c,cf))) cf.cf_type p
+
+	let make_throw e p =
+		mk (TThrow e) t_dynamic p
+
+	let make_int basic i p =
+		mk (TConst (TInt (Int32.of_int i))) basic.tint p
+
+	let make_float basic f p =
+		mk (TConst (TFloat f)) basic.tfloat p
+
+	let make_bool basic b p =
+		mk (TConst(TBool b)) basic.tbool p
+
+	let make_string basic s p =
+		mk (TConst (TString s)) basic.tstring p
+
+	let make_null t p =
+		mk (TConst TNull) t p
+
+	let make_local v p =
+		mk (TLocal v) v.v_type p
+
+	let make_const_texpr basic ct p = match ct with
+		| TString s -> mk (TConst (TString s)) basic.tstring p
+		| TInt i -> mk (TConst (TInt i)) basic.tint p
+		| TFloat f -> mk (TConst (TFloat f)) basic.tfloat p
+		| TBool b -> mk (TConst (TBool b)) basic.tbool p
+		| TNull -> mk (TConst TNull) (basic.tnull (mk_mono())) p
+		| _ -> error "Unsupported constant" p
+
+	let field e name t p =
+		mk (TField (e,try quick_field e.etype name with Not_found -> assert false)) t p
+
+	let fcall e name el ret p =
+		let ft = tfun (List.map (fun e -> e.etype) el) ret in
+		mk (TCall (field e name ft p,el)) ret p
+
+	let mk_parent e =
+		mk (TParenthesis e) e.etype e.epos
+
+	let mk_return e =
+		mk (TReturn (Some e)) t_dynamic e.epos
+
+	let binop op a b t p =
+		mk (TBinop (op,a,b)) t p
+
+	let index basic e index t p =
+		mk (TArray (e,mk (TConst (TInt (Int32.of_int index))) basic.tint p)) t p
+end
+
+let set_default basic a c p =
+	let t = a.v_type in
+	let ve = mk (TLocal a) t p in
+	let cond =  TBinop (OpEq,ve,mk (TConst TNull) t p) in
+	mk (TIf (Builder.mk_parent (mk cond basic.tbool p), mk (TBinop (OpAssign,ve,mk (TConst c) t p)) t p,None)) basic.tvoid p
+
+(*
+	Tells if the constructor might be called without any issue whatever its parameters
+*)
+let rec constructor_side_effects e =
+	match e.eexpr with
+	| TBinop (op,_,_) when op <> OpAssign ->
+		true
+	| TField (_,FEnum _) ->
+		false
+	| TUnop _ | TArray _ | TField _ | TEnumParameter _ | TEnumIndex _ | TCall _ | TNew _ | TFor _ | TWhile _ | TSwitch _ | TReturn _ | TThrow _ ->
+		true
+	| TBinop _ | TTry _ | TIf _ | TBlock _ | TVar _
+	| TFunction _ | TArrayDecl _ | TObjectDecl _
+	| TParenthesis _ | TTypeExpr _ | TLocal _ | TMeta _
+	| TConst _ | TContinue | TBreak | TCast _ | TIdent _ ->
+		try
+			Type.iter (fun e -> if constructor_side_effects e then raise Exit) e;
+			false;
+		with Exit ->
+			true
+
+let type_constant basic c p =
+	match c with
+	| Int s ->
+		if String.length s > 10 && String.sub s 0 2 = "0x" then error "Invalid hexadecimal integer" p;
+		(try mk (TConst (TInt (Int32.of_string s))) basic.tint p
+		with _ -> mk (TConst (TFloat s)) basic.tfloat p)
+	| Float f -> mk (TConst (TFloat f)) basic.tfloat p
+	| String s -> mk (TConst (TString s)) basic.tstring p
+	| Ident "true" -> mk (TConst (TBool true)) basic.tbool p
+	| Ident "false" -> mk (TConst (TBool false)) basic.tbool p
+	| Ident "null" -> mk (TConst TNull) (basic.tnull (mk_mono())) p
+	| Ident t -> error ("Invalid constant :  " ^ t) p
+	| Regexp _ -> error "Invalid constant" p
+
+let rec type_constant_value basic (e,p) =
+	match e with
+	| EConst c ->
+		type_constant basic c p
+	| EParenthesis e ->
+		type_constant_value basic e
+	| EObjectDecl el ->
+		mk (TObjectDecl (List.map (fun (k,e) -> k,type_constant_value basic e) el)) (TAnon { a_fields = PMap.empty; a_status = ref Closed }) p
+	| EArrayDecl el ->
+		mk (TArrayDecl (List.map (type_constant_value basic) el)) (basic.tarray t_dynamic) p
+	| _ ->
+		error "Constant value expected" p
+
+let for_remap basic v e1 e2 p =
+	let v' = alloc_var v.v_name e1.etype e1.epos in
+	let ev' = mk (TLocal v') e1.etype e1.epos in
+	let t1 = (Abstract.follow_with_abstracts e1.etype) in
+	let ehasnext = mk (TField(ev',quick_field t1 "hasNext")) (tfun [] basic.tbool) e1.epos in
+	let ehasnext = mk (TCall(ehasnext,[])) basic.tbool ehasnext.epos in
+	let enext = mk (TField(ev',quick_field t1 "next")) (tfun [] v.v_type) e1.epos in
+	let enext = mk (TCall(enext,[])) v.v_type e1.epos in
+	let eassign = mk (TVar(v,Some enext)) basic.tvoid p in
+	let ebody = Type.concat eassign e2 in
+	mk (TBlock [
+		mk (TVar (v',Some e1)) basic.tvoid e1.epos;
+		mk (TWhile((mk (TParenthesis ehasnext) ehasnext.etype ehasnext.epos),ebody,NormalWhile)) basic.tvoid e1.epos;
+	]) basic.tvoid p
+
+(* -------------------------------------------------------------------------- *)
+(* BUILD META DATA OBJECT *)
+
+let build_metadata api t =
+	let p, meta, fields, statics = (match t with
+		| TClassDecl c ->
+			let fields = List.map (fun f -> f.cf_name,f.cf_meta) (c.cl_ordered_fields @ (match c.cl_constructor with None -> [] | Some f -> [{ f with cf_name = "_" }])) in
+			let statics =  List.map (fun f -> f.cf_name,f.cf_meta) c.cl_ordered_statics in
+			(c.cl_pos, ["",c.cl_meta],fields,statics)
+		| TEnumDecl e ->
+			(e.e_pos, ["",e.e_meta],List.map (fun n -> n, (PMap.find n e.e_constrs).ef_meta) e.e_names, [])
+		| TTypeDecl t ->
+			(t.t_pos, ["",t.t_meta],(match follow t.t_type with TAnon a -> PMap.fold (fun f acc -> (f.cf_name,f.cf_meta) :: acc) a.a_fields [] | _ -> []),[])
+		| TAbstractDecl a ->
+			(a.a_pos, ["",a.a_meta],[],[])
+	) in
+	let filter l =
+		let l = List.map (fun (n,ml) -> n, ExtList.List.filter_map (fun (m,el,p) -> match m with Meta.Custom s when String.length s > 0 && s.[0] <> ':' -> Some (s,el,p) | _ -> None) ml) l in
+		List.filter (fun (_,ml) -> ml <> []) l
+	in
+	let meta, fields, statics = filter meta, filter fields, filter statics in
+	let make_meta_field ml =
+		let h = Hashtbl.create 0 in
+		mk (TObjectDecl (List.map (fun (f,el,p) ->
+			if Hashtbl.mem h f then error ("Duplicate metadata '" ^ f ^ "'") p;
+			Hashtbl.add h f ();
+			(f,null_pos,NoQuotes), mk (match el with [] -> TConst TNull | _ -> TArrayDecl (List.map (type_constant_value api) el)) (api.tarray t_dynamic) p
+		) ml)) t_dynamic p
+	in
+	let make_meta l =
+		mk (TObjectDecl (List.map (fun (f,ml) -> (f,null_pos,NoQuotes),make_meta_field ml) l)) t_dynamic p
+	in
+	if meta = [] && fields = [] && statics = [] then
+		None
+	else
+		let meta_obj = [] in
+		let meta_obj = (if fields = [] then meta_obj else (("fields",null_pos,NoQuotes),make_meta fields) :: meta_obj) in
+		let meta_obj = (if statics = [] then meta_obj else (("statics",null_pos,NoQuotes),make_meta statics) :: meta_obj) in
+		let meta_obj = (try (("obj",null_pos,NoQuotes), make_meta_field (List.assoc "" meta)) :: meta_obj with Not_found -> meta_obj) in
+		Some (mk (TObjectDecl meta_obj) t_dynamic p)

+ 167 - 0
src/core/timer.ml

@@ -0,0 +1,167 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2017  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
+type timer_infos = {
+	id : string list;
+	mutable start : float list;
+	mutable total : float;
+	mutable calls : int;
+}
+
+let get_time = Extc.time
+let htimers = Hashtbl.create 0
+
+let new_timer id =
+	let key = String.concat "." id in
+	try
+		let t = Hashtbl.find htimers key in
+		t.start <- get_time() :: t.start;
+		t.calls <- t.calls + 1;
+		t
+	with Not_found ->
+		let t = { id = id; start = [get_time()]; total = 0.; calls = 1; } in
+		Hashtbl.add htimers key t;
+		t
+
+let curtime = ref []
+
+let close t =
+	let start = (match t.start with
+		| [] -> assert false
+		| s :: l -> t.start <- l; s
+	) in
+	let now = get_time() in
+	let dt = now -. start in
+	t.total <- t.total +. dt;
+	let rec loop() =
+		match !curtime with
+		| [] -> failwith ("Timer " ^ (String.concat "." t.id) ^ " closed while not active")
+		| tt :: l -> curtime := l; if t != tt then loop()
+	in
+	loop();
+	(* because of rounding errors while adding small times, we need to make sure that we don't have start > now *)
+	List.iter (fun ct -> ct.start <- List.map (fun t -> let s = t +. dt in if s > now then now else s) ct.start) !curtime
+
+let timer id =
+	let t = new_timer id in
+	curtime := t :: !curtime;
+	(function() -> close t)
+
+let rec close_times() =
+	match !curtime with
+	| [] -> ()
+	| t :: _ -> close t; close_times()
+
+(* Printing *)
+
+type timer_node = {
+	name : string;
+	path : string;
+	parent : timer_node;
+	info : string;
+	mutable time : float;
+	mutable num_calls : int;
+	mutable children : timer_node list;
+}
+
+let report_times print =
+	let nodes = Hashtbl.create 0 in
+	let rec root = {
+		name = "";
+		path = "";
+		parent = root;
+		info = "";
+		time = 0.;
+		num_calls = 0;
+		children = [];
+	} in
+	Hashtbl.iter (fun _ timer ->
+		let rec loop parent sl = match sl with
+			| [] -> assert false
+			| s :: sl ->
+				let path = (match parent.path with "" -> "" | _ -> parent.path ^ ".") ^ s in
+				let node = try
+					let node = Hashtbl.find nodes path in
+					node.num_calls <- node.num_calls + timer.calls;
+					node.time <- node.time +. timer.total;
+					node
+				with Not_found ->
+					let name,info = try
+						let i = String.rindex s '.' in
+						String.sub s (i + 1) (String.length s - i - 1),String.sub s 0 i
+					with Not_found ->
+						s,""
+					in
+					let node = {
+						name = name;
+						path = path;
+						parent = parent;
+						info = info;
+						time = timer.total;
+						num_calls = timer.calls;
+						children = [];
+					} in
+					Hashtbl.add nodes path node;
+					node
+				in
+				begin match sl with
+					| [] -> ()
+					| _ ->
+						let child = loop node sl in
+						if not (List.memq child node.children) then
+							node.children <- child :: node.children;
+				end;
+				node
+		in
+		let node = loop root timer.id in
+		if not (List.memq node root.children) then
+			root.children <- node :: root.children
+	) htimers;
+	let max_name = ref 0 in
+	let max_calls = ref 0 in
+	let rec loop depth node =
+		let l = (String.length node.name) + 2 * depth in
+		List.iter (fun child ->
+			if depth = 0 then begin
+				node.num_calls <- node.num_calls + child.num_calls;
+				node.time <- node.time +. child.time;
+			end;
+			loop (depth + 1) child;
+		) node.children;
+		node.children <- List.sort (fun node1 node2 -> compare node2.time node1.time) node.children;
+		if node.num_calls > !max_calls then max_calls := node.num_calls;
+		if node.time > 0.0009 && l > !max_name then max_name := l;
+	in
+	loop 0 root;
+	let max_calls = String.length (string_of_int !max_calls) in
+	print (Printf.sprintf "%-*s | %7s |   %% |  p%% | %*s | info" !max_name "name" "time(s)" max_calls "#");
+	let sep = String.make (!max_name + max_calls + 27) '-' in
+	print sep;
+	let print_time name node =
+		if node.time > 0.0009 then
+			print (Printf.sprintf "%-*s | %7.3f | %3.0f | %3.0f | %*i | %s" !max_name name node.time (node.time *. 100. /. root.time) (node.time *. 100. /. node.parent.time) max_calls node.num_calls node.info)
+	in
+	let rec loop depth node =
+		let name = (String.make (depth * 2) ' ') ^ node.name in
+		print_time name node;
+		List.iter (loop (depth + 1)) node.children
+	in
+	List.iter (loop 0) root.children;
+	print sep;
+	print_time "total" root

+ 120 - 246
src/typing/type.ml → src/core/type.ml

@@ -33,11 +33,12 @@ and var_kind = {
 
 and var_access =
 	| AccNormal
-	| AccNo				(* can't be accessed outside of the class itself and its subclasses *)
-	| AccNever			(* can't be accessed, even in subclasses *)
-	| AccResolve		(* call resolve("field") when accessed *)
-	| AccCall			(* perform a method call when accessed *)
-	| AccInline			(* similar to Normal but inline when accessed *)
+	| AccNo             (* can't be accessed outside of the class itself and its subclasses *)
+	| AccNever          (* can't be accessed, even in subclasses *)
+	| AccCtor           (* can only be accessed from the constructor *)
+	| AccResolve        (* call resolve("field") when accessed *)
+	| AccCall           (* perform a method call when accessed *)
+	| AccInline         (* similar to Normal but inline when accessed *)
 	| AccRequire of string * string option (* set when @:require(cond) fails *)
 
 and method_kind =
@@ -52,6 +53,7 @@ type module_check_policy =
 	| NoCheckDependencies
 	| NoCheckShadowing
 
+
 type t =
 	| TMono of t option ref
 	| TEnum of tenum * tparams
@@ -60,9 +62,14 @@ type t =
 	| TFun of tsignature
 	| TAnon of tanon
 	| TDynamic of t
-	| TLazy of (unit -> t) ref
+	| TLazy of tlazy ref
 	| TAbstract of tabstract * tparams
 
+and tlazy =
+	| LAvailable of t
+	| LProcessing of (unit -> t)
+	| LWait of (unit -> t)
+
 and tsignature = (string * bool * t) list * t
 
 and tparams = t list
@@ -118,7 +125,7 @@ and texpr_expr =
 	| TField of texpr * tfield_access
 	| TTypeExpr of module_type
 	| TParenthesis of texpr
-	| TObjectDecl of (string * texpr) list
+	| TObjectDecl of ((string * pos * quote_status) * texpr) list
 	| TArrayDecl of texpr list
 	| TCall of texpr * texpr list
 	| TNew of tclass * tparams * texpr list
@@ -229,12 +236,12 @@ and tclass = {
 
 and tenum_field = {
 	ef_name : string;
-	ef_type : t;
+	mutable ef_type : t;
 	ef_pos : pos;
 	ef_name_pos : pos;
 	ef_doc : Ast.documentation;
 	ef_index : int;
-	ef_params : type_params;
+	mutable ef_params : type_params;
 	mutable ef_meta : metadata;
 }
 
@@ -314,7 +321,7 @@ and module_def_extra = {
 	mutable m_processed : int;
 	mutable m_kind : module_kind;
 	mutable m_binded_res : (string, string) PMap.t;
-	mutable m_macro_calls : string list;
+	mutable m_reuse_macro_calls : string list;
 	mutable m_if_feature : (string *(tclass * tclass_field * bool)) list;
 	mutable m_features : (string,bool) Hashtbl.t;
 }
@@ -331,6 +338,16 @@ and build_state =
 	| Building of tclass list
 	| BuildMacro of (unit -> unit) list ref
 
+type basic_types = {
+	mutable tvoid : t;
+	mutable tint : t;
+	mutable tfloat : t;
+	mutable tbool : t;
+	mutable tnull : t -> t;
+	mutable tstring : t;
+	mutable tarray : t -> t;
+}
+
 (* ======= General utility ======= *)
 
 let alloc_var =
@@ -409,7 +426,7 @@ let module_extra file sign time kind policy =
 		m_deps = PMap.empty;
 		m_kind = kind;
 		m_binded_res = PMap.empty;
-		m_macro_calls = [];
+		m_reuse_macro_calls = [];
 		m_if_feature = [];
 		m_features = Hashtbl.create 0;
 		m_check_policy = policy;
@@ -490,6 +507,15 @@ let rec is_parent csup c =
 let add_descendant c descendant =
 	c.cl_descendants <- descendant :: c.cl_descendants
 
+let lazy_type f =
+	match !f with
+	| LAvailable t -> t
+	| LProcessing f | LWait f -> f()
+
+let lazy_available t = LAvailable t
+let lazy_processing f = LProcessing f
+let lazy_wait f = LWait f
+
 let map loop t =
 	match t with
 	| TMono r ->
@@ -521,7 +547,7 @@ let map loop t =
 				}
 		end
 	| TLazy f ->
-		let ft = !f() in
+		let ft = lazy_type f in
 		let ft2 = loop ft in
 		if ft == ft2 then t else ft2
 	| TDynamic t2 ->
@@ -551,7 +577,7 @@ let apply_params cparams params t =
 	let rec loop l1 l2 =
 		match l1, l2 with
 		| [] , [] -> []
-		| (x,TLazy f) :: l1, _ -> loop ((x,(!f)()) :: l1) l2
+		| (x,TLazy f) :: l1, _ -> loop ((x,lazy_type f) :: l1) l2
 		| (_,t1) :: l1 , t2 :: l2 -> (t1,t2) :: loop l1 l2
 		| _ -> assert false
 	in
@@ -607,7 +633,7 @@ let apply_params cparams params t =
 					}
 			end
 		| TLazy f ->
-			let ft = !f() in
+			let ft = lazy_type f in
 			let ft2 = loop ft in
 			if ft == ft2 then
 				t
@@ -631,7 +657,7 @@ let rec follow t =
 		| Some t -> follow t
 		| _ -> t)
 	| TLazy f ->
-		follow (!f())
+		follow (lazy_type f)
 	| TType (t,tl) ->
 		follow (apply_params t.t_params tl t.t_type)
 	| TAbstract({a_path = [],"Null"},[t]) ->
@@ -644,7 +670,7 @@ let rec is_nullable = function
 	| TAbstract ({ a_path = ([],"Null") },[_]) ->
 		true
 	| TLazy f ->
-		is_nullable (!f())
+		is_nullable (lazy_type f)
 	| TType (t,tl) ->
 		is_nullable (apply_params t.t_params tl t.t_type)
 	| TFun _ ->
@@ -671,7 +697,7 @@ let rec is_null ?(no_lazy=false) = function
 	| TAbstract ({ a_path = ([],"Null") },[t]) ->
 		not (is_nullable (follow t))
 	| TLazy f ->
-		if no_lazy then raise Exit else is_null (!f())
+		if no_lazy then raise Exit else is_null (lazy_type f)
 	| TType (t,tl) ->
 		is_null (apply_params t.t_params tl t.t_type)
 	| _ ->
@@ -684,7 +710,7 @@ let rec is_explicit_null = function
 	| TAbstract ({ a_path = ([],"Null") },[t]) ->
 		true
 	| TLazy f ->
-		is_null (!f())
+		is_null (lazy_type f)
 	| TType (t,tl) ->
 		is_null (apply_params t.t_params tl t.t_type)
 	| _ ->
@@ -701,8 +727,8 @@ let rec has_mono t = match t with
 		has_mono r || List.exists (fun (_,_,t) -> has_mono t) args
 	| TAnon a ->
 		PMap.fold (fun cf b -> has_mono cf.cf_type || b) a.a_fields false
-	| TLazy r ->
-		has_mono (!r())
+	| TLazy f ->
+		has_mono (lazy_type f)
 
 let concat e1 e2 =
 	let e = (match e1.eexpr, e2.eexpr with
@@ -726,7 +752,7 @@ let rec module_type_of_type = function
 	| TEnum(en,_) -> TEnumDecl en
 	| TType(t,_) -> TTypeDecl t
 	| TAbstract(a,_) -> TAbstractDecl a
-	| TLazy f -> module_type_of_type (!f())
+	| TLazy f -> module_type_of_type (lazy_type f)
 	| TMono r ->
 		(match !r with
 		| Some t -> module_type_of_type t
@@ -925,12 +951,19 @@ let rec s_type ctx t =
 			(if b then "?" else "") ^ (if s = "" then "" else s ^ " : ") ^ s_fun ctx t true
 		) l) ^ " -> " ^ s_fun ctx t false
 	| TAnon a ->
-		let fl = PMap.fold (fun f acc -> ((if Meta.has Meta.Optional f.cf_meta then " ?" else " ") ^ f.cf_name ^ " : " ^ s_type ctx f.cf_type) :: acc) a.a_fields [] in
-		"{" ^ (if not (is_closed a) then "+" else "") ^  String.concat "," fl ^ " }"
+		begin
+			match !(a.a_status) with
+			| Statics c -> Printf.sprintf "{ Statics %s }" (s_type_path c.cl_path)
+			| EnumStatics e -> Printf.sprintf "{ EnumStatics %s }" (s_type_path e.e_path)
+			| AbstractStatics a -> Printf.sprintf "{ AbstractStatics %s }" (s_type_path a.a_path)
+			| _ ->
+				let fl = PMap.fold (fun f acc -> ((if Meta.has Meta.Optional f.cf_meta then " ?" else " ") ^ f.cf_name ^ " : " ^ s_type ctx f.cf_type) :: acc) a.a_fields [] in
+				"{" ^ (if not (is_closed a) then "+" else "") ^  String.concat "," fl ^ " }"
+		end
 	| TDynamic t2 ->
 		"Dynamic" ^ s_type_params ctx (if t == t2 then [] else [t2])
 	| TLazy f ->
-		s_type ctx (!f())
+		s_type ctx (lazy_type f)
 
 and s_fun ctx t void =
 	match t with
@@ -943,7 +976,7 @@ and s_fun ctx t void =
 		| None -> s_type ctx t
 		| Some t -> s_fun ctx t void)
 	| TLazy f ->
-		s_fun ctx (!f()) void
+		s_fun ctx (lazy_type f) void
 	| _ ->
 		s_type ctx t
 
@@ -959,6 +992,7 @@ let s_access is_read = function
 	| AccCall -> if is_read then "get" else "set"
 	| AccInline	-> "inline"
 	| AccRequire (n,_) -> "require " ^ n
+	| AccCtor -> "ctor"
 
 let s_kind = function
 	| Var { v_read = AccNormal; v_write = AccNormal } -> "var"
@@ -1044,7 +1078,7 @@ let rec s_expr s_type e =
 	| TParenthesis e ->
 		sprintf "Parenthesis %s" (loop e)
 	| TObjectDecl fl ->
-		sprintf "ObjectDecl {%s}" (slist (fun (f,e) -> sprintf "%s : %s" f (loop e)) fl)
+		sprintf "ObjectDecl {%s}" (slist (fun ((f,_,qs),e) -> sprintf "%s : %s" (s_object_key_name f qs) (loop e)) fl)
 	| TArrayDecl el ->
 		sprintf "ArrayDecl [%s]" (slist loop el)
 	| TCall (e,el) ->
@@ -1109,7 +1143,7 @@ let rec s_expr_pretty print_var_ids tabs top_level s_type e =
 	| TField (e1,s) -> sprintf "%s.%s" (loop e1) (field_name s)
 	| TTypeExpr mt -> (s_type_path (t_path mt))
 	| TParenthesis e1 -> sprintf "(%s)" (loop e1)
-	| TObjectDecl fl -> sprintf "{%s}" (clist (fun (f,e) -> sprintf "%s : %s" f (loop e)) fl)
+	| TObjectDecl fl -> sprintf "{%s}" (clist (fun ((f,_,qs),e) -> sprintf "%s : %s" (s_object_key_name f qs) (loop e)) fl)
 	| TArrayDecl el -> sprintf "[%s]" (clist loop el)
 	| TCall (e1,el) -> sprintf "%s(%s)" (loop e1) (clist loop el)
 	| TNew (c,pl,el) ->
@@ -1204,7 +1238,7 @@ let rec s_expr_ast print_var_ids tabs s_type e =
 		tag "Field" [loop e1; sfa]
 	| TTypeExpr mt -> module_type mt
 	| TParenthesis e1 -> tag "Parenthesis" [loop e1]
-	| TObjectDecl fl -> tag "ObjectDecl" (List.map (fun (s,e) -> sprintf "%s: %s" s (loop e)) fl)
+	| TObjectDecl fl -> tag "ObjectDecl" (List.map (fun ((s,_,qs),e) -> sprintf "%s: %s" (s_object_key_name s qs) (loop e)) fl)
 	| TArrayDecl el -> tag "ArrayDecl" (List.map loop el)
 	| TCall (e1,el) -> tag "Call" (loop e1 :: (List.map loop el))
 	| TNew (c,tl,el) -> tag "New" ((s_type (TInst(c,tl))) :: (List.map loop el))
@@ -1452,7 +1486,7 @@ module Printer = struct
 			"m_processed",string_of_int me.m_processed;
 			"m_kind",s_module_kind me.m_kind;
 			"m_binded_res",""; (* TODO *)
-			"m_macro_calls",String.concat ", " me.m_macro_calls;
+			"m_reuse_macro_calls",String.concat ", " me.m_reuse_macro_calls;
 			"m_if_feature",""; (* TODO *)
 			"m_features",""; (* TODO *)
 		]
@@ -1510,7 +1544,7 @@ let rec link e a b =
 			else
 				loop t2
 		| TLazy f ->
-			loop (!f())
+			loop (lazy_type f)
 		| TAnon a ->
 			try
 				PMap.iter (fun _ f -> if loop f.cf_type then raise Exit) a.a_fields;
@@ -1612,7 +1646,7 @@ let unify_access a1 a2 =
 	| _ -> false
 
 let direct_access = function
-	| AccNo | AccNever | AccNormal | AccInline | AccRequire _ -> true
+	| AccNo | AccNever | AccNormal | AccInline | AccRequire _ | AccCtor -> true
 	| AccResolve | AccCall -> false
 
 let unify_kind k1 k2 =
@@ -1687,8 +1721,8 @@ let rec type_eq param a b =
 	if a == b then
 		()
 	else match a , b with
-	| TLazy f , _ -> type_eq param (!f()) b
-	| _ , TLazy f -> type_eq param a (!f())
+	| TLazy f , _ -> type_eq param (lazy_type f) b
+	| _ , TLazy f -> type_eq param a (lazy_type f)
 	| TMono t , _ ->
 		(match !t with
 		| None -> if param = EqCoreType || not (link t a b) then error [cannot_unify a b]
@@ -1798,8 +1832,8 @@ let rec unify a b =
 	if a == b then
 		()
 	else match a, b with
-	| TLazy f , _ -> unify (!f()) b
-	| _ , TLazy f -> unify a (!f())
+	| TLazy f , _ -> unify (lazy_type f) b
+	| _ , TLazy f -> unify a (lazy_type f)
 	| TMono t , _ ->
 		(match !t with
 		| None -> if not (link t a b) then error [cannot_unify a b]
@@ -2493,7 +2527,7 @@ module TExprToExpr = struct
 		| (TDynamic t2) as t ->
 			tpath ([],"Dynamic") ([],"Dynamic") (if t == t_dynamic then [] else [convert_type' t2])
 		| TLazy f ->
-			convert_type ((!f)())
+			convert_type (lazy_type f)
 
 	and convert_type' t =
 		convert_type t,null_pos
@@ -2528,7 +2562,7 @@ module TExprToExpr = struct
 		| TField (e,f) -> EField (convert_expr e, field_name f)
 		| TTypeExpr t -> fst (mk_path (full_type_path t) e.epos)
 		| TParenthesis e -> EParenthesis (convert_expr e)
-		| TObjectDecl fl -> EObjectDecl (List.map (fun (f,e) -> (f,null_pos), convert_expr e) fl)
+		| TObjectDecl fl -> EObjectDecl (List.map (fun (k,e) -> k, convert_expr e) fl)
 		| TArrayDecl el -> EArrayDecl (List.map convert_expr el)
 		| TCall (e,el) -> ECall (convert_expr e,List.map convert_expr el)
 		| TNew (c,pl,el) -> ENew ((match (try convert_type (TInst (c,pl)) with Exit -> convert_type (TInst (c,[]))) with CTPath p -> p,null_pos | _ -> assert false),List.map convert_expr el)
@@ -2581,213 +2615,6 @@ module TExprToExpr = struct
 
 end
 
-module Texpr = struct
-	let equal_fa fa1 fa2 = match fa1,fa2 with
-		| FStatic(c1,cf1),FStatic(c2,cf2) -> c1 == c2 && cf1 == cf2
-		| FInstance(c1,tl1,cf1),FInstance(c2,tl2,cf2) -> c1 == c2 && safe_for_all2 type_iseq tl1 tl2 && cf1 == cf2
-		(* TODO: This is technically not correct but unfortunately the compiler makes a distinct tclass_field for each anon field access. *)
-		| FAnon cf1,FAnon cf2 -> cf1.cf_name = cf2.cf_name
-		| FDynamic s1,FDynamic s2 -> s1 = s2
-		| FClosure(None,cf1),FClosure(None,cf2) -> cf1 == cf2
-		| FClosure(Some(c1,tl1),cf1),FClosure(Some(c2,tl2),cf2) -> c1 == c2 && safe_for_all2 type_iseq tl1 tl2 && cf1 == cf2
-		| FEnum(en1,ef1),FEnum(en2,ef2) -> en1 == en2 && ef1 == ef2
-		| _ -> false
-
-	let rec equal e1 e2 = match e1.eexpr,e2.eexpr with
-		| TConst ct1,TConst ct2 -> ct1 = ct2
-		| TLocal v1,TLocal v2 -> v1 == v2
-		| TArray(eb1,ei1),TArray(eb2,ei2) -> equal eb1 eb2 && equal ei1 ei2
-		| TBinop(op1,lhs1,rhs1),TBinop(op2,lhs2,rhs2) -> op1 = op2 && equal lhs1 lhs2 && equal rhs1 rhs2
-		| TField(e1,fa1),TField(e2,fa2) -> equal e1 e2 && equal_fa fa1 fa2
-		| TTypeExpr mt1,TTypeExpr mt2 -> mt1 == mt2
-		| TParenthesis e1,TParenthesis e2 -> equal e1 e2
-		| TObjectDecl fl1,TObjectDecl fl2 -> safe_for_all2 (fun (s1,e1) (s2,e2) -> s1 = s2 && equal e1 e2) fl1 fl2
-		| (TArrayDecl el1,TArrayDecl el2) | (TBlock el1,TBlock el2) -> safe_for_all2 equal el1 el2
-		| TCall(e1,el1),TCall(e2,el2) -> equal e1 e2 && safe_for_all2 equal el1 el2
-		| TNew(c1,tl1,el1),TNew(c2,tl2,el2) -> c1 == c2 && safe_for_all2 type_iseq tl1 tl2 && safe_for_all2 equal el1 el2
-		| TUnop(op1,flag1,e1),TUnop(op2,flag2,e2) -> op1 = op2 && flag1 = flag2 && equal e1 e2
-		| TFunction tf1,TFunction tf2 -> tf1 == tf2
-		| TVar(v1,None),TVar(v2,None) -> v1 == v2
-		| TVar(v1,Some e1),TVar(v2,Some e2) -> v1 == v2 && equal e1 e2
-		| TFor(v1,ec1,eb1),TFor(v2,ec2,eb2) -> v1 == v2 && equal ec1 ec2 && equal eb1 eb2
-		| TIf(e1,ethen1,None),TIf(e2,ethen2,None) -> equal e1 e2 && equal ethen1 ethen2
-		| TIf(e1,ethen1,Some eelse1),TIf(e2,ethen2,Some eelse2) -> equal e1 e2 && equal ethen1 ethen2 && equal eelse1 eelse2
-		| TWhile(e1,eb1,flag1),TWhile(e2,eb2,flag2) -> equal e1 e2 && equal eb2 eb2 && flag1 = flag2
-		| TSwitch(e1,cases1,eo1),TSwitch(e2,cases2,eo2) ->
-			equal e1 e2 &&
-			safe_for_all2 (fun (el1,e1) (el2,e2) -> safe_for_all2 equal el1 el2 && equal e1 e2) cases1 cases2 &&
-			(match eo1,eo2 with None,None -> true | Some e1,Some e2 -> equal e1 e2 | _ -> false)
-		| TTry(e1,catches1),TTry(e2,catches2) -> equal e1 e2 && safe_for_all2 (fun (v1,e1) (v2,e2) -> v1 == v2 && equal e1 e2) catches1 catches2
-		| TReturn None,TReturn None -> true
-		| TReturn(Some e1),TReturn(Some e2) -> equal e1 e2
-		| TThrow e1,TThrow e2 -> equal e1 e2
-		| TCast(e1,None),TCast(e2,None) -> equal e1 e2
-		| TCast(e1,Some mt1),TCast(e2,Some mt2) -> equal e1 e2 && mt1 == mt2
-		| TMeta((m1,el1,_),e1),TMeta((m2,el2,_),e2) -> m1 = m2 && safe_for_all2 (fun e1 e2 -> (* TODO: cheating? *) (Ast.s_expr e1) = (Ast.s_expr e2)) el1 el2 && equal e1 e2
-		| (TBreak,TBreak) | (TContinue,TContinue) -> true
-		| TEnumParameter(e1,ef1,i1),TEnumParameter(e2,ef2,i2) -> equal e1 e2 && ef1 == ef2 && i1 = i2
-		| _ -> false
-
-	let duplicate_tvars e =
-		let vars = Hashtbl.create 0 in
-		let copy_var v =
-			let v2 = alloc_var v.v_name v.v_type v.v_pos in
-			v2.v_meta <- v.v_meta;
-			v2.v_extra <- v.v_extra;
-			Hashtbl.add vars v.v_id v2;
-			v2;
-		in
-		let rec build_expr e =
-			match e.eexpr with
-			| TVar (v,eo) ->
-				let v2 = copy_var v in
-				{e with eexpr = TVar(v2, Option.map build_expr eo)}
-			| TFor (v,e1,e2) ->
-				let v2 = copy_var v in
-				{e with eexpr = TFor(v2, build_expr e1, build_expr e2)}
-			| TTry (e1,cl) ->
-				let cl = List.map (fun (v,e) ->
-					let v2 = copy_var v in
-					v2, build_expr e
-				) cl in
-				{e with eexpr = TTry(build_expr e1, cl)}
-			| TFunction f ->
-				let args = List.map (fun (v,c) -> copy_var v, c) f.tf_args in
-				let f = {
-					tf_args = args;
-					tf_type = f.tf_type;
-					tf_expr = build_expr f.tf_expr;
-				} in
-				{e with eexpr = TFunction f}
-			| TLocal v ->
-				(try
-					let v2 = Hashtbl.find vars v.v_id in
-					{e with eexpr = TLocal v2}
-				with _ ->
-					e)
-			| _ ->
-				map_expr build_expr e
-		in
-		build_expr e
-
-	let rec skip e = match e.eexpr with
-		| TParenthesis e1 | TMeta(_,e1) | TBlock [e1] | TCast(e1,None) -> skip e1
-		| _ -> e
-
-	let foldmap_list f acc el =
-		let rec loop acc el acc2 = (match el with
-			| [] -> acc,(List.rev acc2)
-			| e1 :: el ->
-				let acc,e1 = f acc e1 in
-				loop acc el (e1 :: acc2))
-		in loop acc el []
-
-	let foldmap_opt f acc eo = match eo with
-		| Some(e) -> let acc,e = f acc e in acc,Some(e)
-		| None    -> acc,eo
-
-	let foldmap_pairs f acc pairs =
-		let acc,pairs = List.fold_left
-			(fun (acc,el) (v,e) -> let acc,e = f acc e in (acc,(v,e) :: el))
-			(acc,[])
-			pairs
-		in acc,(List.rev pairs)
-
-	let foldmap f acc e =
-		begin match e.eexpr with
-		| TConst _
-		| TLocal _
-		| TBreak
-		| TContinue
-		| TTypeExpr _
-		| TIdent _ ->
-			acc,e
-		| TArray (e1,e2) ->
-			let acc,e1 = f acc e1 in
-			let acc,e2 = f acc e2 in
-			acc,{ e with eexpr = TArray (e1, e2) }
-		| TBinop (op,e1,e2) ->
-			let acc,e1 = f acc e1 in
-			let acc,e2 = f acc e2 in
-			acc,{ e with eexpr = TBinop (op,e1,e2) }
-		| TFor (v,e1,e2) ->
-			let acc,e1 = f acc e1 in
-			let acc,e2 = f acc e2 in
-			acc,{ e with eexpr = TFor (v,e1,e2) }
-		| TWhile (e1,e2,flag) ->
-			let acc,e1 = f acc e1 in
-			let acc,e2 = f acc e2 in
-			acc,{ e with eexpr = TWhile (e1,e2,flag) }
-		| TThrow e1 ->
-			let acc,e1 = f acc e1 in
-			acc,{ e with eexpr = TThrow (e1) }
-		| TEnumParameter (e1,ef,i) ->
-			let acc,e1 = f acc e1 in
-			acc,{ e with eexpr = TEnumParameter(e1,ef,i) }
-		| TEnumIndex e1 ->
-			let acc,e1 = f acc e1 in
-			acc,{ e with eexpr = TEnumIndex e1 }
-		| TField (e1,v) ->
-			let acc,e1 = f acc e1 in
-			acc,{ e with eexpr = TField (e1,v) }
-		| TParenthesis e1 ->
-			let acc,e1 = f acc e1 in
-			acc,{ e with eexpr = TParenthesis (e1) }
-		| TUnop (op,pre,e1) ->
-			let acc,e1 = f acc e1 in
-			acc,{ e with eexpr = TUnop (op,pre,e1) }
-		| TArrayDecl el ->
-			let acc,el = foldmap_list f acc el in
-			acc,{ e with eexpr = TArrayDecl el }
-		| TNew (t,pl,el) ->
-			let acc,el = foldmap_list f acc el in
-			acc,{ e with eexpr = TNew (t,pl,el) }
-		| TBlock el ->
-			let acc,el = foldmap_list f acc el in
-			acc,{ e with eexpr = TBlock (el) }
-		| TObjectDecl el ->
-			let acc,el = foldmap_pairs f acc el in
-			acc,{ e with eexpr = TObjectDecl el }
-		| TCall (e1,el) ->
-			let acc,e1 = f acc e1 in
-			let acc,el = foldmap_list f acc el in
-			acc,{ e with eexpr = TCall (e1,el) }
-		| TVar (v,eo) ->
-			let acc,eo = foldmap_opt f acc eo in
-			acc,{ e with eexpr = TVar (v, eo) }
-		| TFunction fu ->
-			let acc,e1 = f acc fu.tf_expr in
-			acc,{ e with eexpr = TFunction { fu with tf_expr = e1 } }
-		| TIf (ec,e1,eo) ->
-			let acc,ec = f acc ec in
-			let acc,e1 = f acc e1 in
-			let acc,eo = foldmap_opt f acc eo in
-			acc,{ e with eexpr = TIf (ec,e1,eo)}
-		| TSwitch (e1,cases,def) ->
-			let acc,e1 = f acc e1 in
-			let acc,cases = List.fold_left (fun (acc,cases) (el,e2) ->
-				let acc,el = foldmap_list f acc el in
-				let acc,e2 = f acc e2 in
-				acc,((el,e2) :: cases)
-			) (acc,[]) cases in
-			let acc,def = foldmap_opt f acc def in
-			acc,{ e with eexpr = TSwitch (e1, cases, def) }
-		| TTry (e1,catches) ->
-			let acc,e1 = f acc e1 in
-			let acc,catches = foldmap_pairs f acc catches in
-			acc,{ e with eexpr = TTry (e1, catches) }
-		| TReturn eo ->
-			let acc,eo = foldmap_opt f acc eo in
-			acc,{ e with eexpr = TReturn eo }
-		| TCast (e1,t) ->
-			let acc,e1 = f acc e1 in
-			acc,{ e with eexpr = TCast (e1,t) }
-		| TMeta (m,e1) ->
-			let acc,e1 = f acc e1 in
-			acc,{ e with eexpr = TMeta(m,e1)}
-		end
-end
-
 module ExtType = struct
 	let is_void = function
 		| TAbstract({a_path=[],"Void"},_) -> true
@@ -2831,11 +2658,16 @@ module StringError = struct
 		in
 		loop cl
 
-	let string_error_raise s sl msg =
-		if sl = [] then msg else
+	let get_similar s sl =
+		if sl = [] then [] else
 		let cl = List.map (fun s2 -> s2,levenshtein s s2) sl in
 		let cl = List.sort (fun (_,c1) (_,c2) -> compare c1 c2) cl in
 		let cl = filter_similar (fun s2 i -> i <= (min (String.length s) (String.length s2)) / 3) cl in
+		cl
+
+	let string_error_raise s sl msg =
+		if sl = [] then msg else
+		let cl = get_similar s sl in
 		match cl with
 			| [] -> raise Not_found
 			| [s] -> Printf.sprintf "%s (Suggestion: %s)" msg s
@@ -2845,3 +2677,45 @@ module StringError = struct
 		try string_error_raise s sl msg
 		with Not_found -> msg
 end
+
+let class_module_type c = {
+	t_path = [],"Class<" ^ (s_type_path c.cl_path) ^ ">" ;
+	t_module = c.cl_module;
+	t_doc = None;
+	t_pos = c.cl_pos;
+	t_name_pos = null_pos;
+	t_type = TAnon {
+		a_fields = c.cl_statics;
+		a_status = ref (Statics c);
+	};
+	t_private = true;
+	t_params = [];
+	t_meta = no_meta;
+}
+
+let enum_module_type m path p  = {
+	t_path = [], "Enum<" ^ (s_type_path path) ^ ">";
+	t_module = m;
+	t_doc = None;
+	t_pos = p;
+	t_name_pos = null_pos;
+	t_type = mk_mono();
+	t_private = true;
+	t_params = [];
+	t_meta = [];
+}
+
+let abstract_module_type a tl = {
+	t_path = [],Printf.sprintf "Abstract<%s%s>" (s_type_path a.a_path) (s_type_params (ref []) tl);
+	t_module = a.a_module;
+	t_doc = None;
+	t_pos = a.a_pos;
+	t_name_pos = null_pos;
+	t_type = TAnon {
+		a_fields = PMap.empty;
+		a_status = ref (AbstractStatics a);
+	};
+	t_private = true;
+	t_params = [];
+	t_meta = no_meta;
+}

+ 1 - 1
src/filters/capturedVars.ml

@@ -168,7 +168,7 @@ let captured_vars com e =
 				in
 				let e = loop e in
 				mk (TCall (
-					Codegen.mk_parent (mk (TFunction {
+					Texpr.Builder.mk_parent (mk (TFunction {
 						tf_args = List.map (fun (_,v) -> v, None) new_vars;
 						tf_type = e.etype;
 						tf_expr = mk_block (mk (TReturn (Some e)) e.etype e.epos);

+ 2 - 2
src/filters/defaultArguments.ml

@@ -19,7 +19,7 @@
 open Common
 open Type
 open Codegen
-open Codegen.ExprBuilder
+open Texpr.Builder
 
 (*
 	This Module Filter will go through all defined functions in all modules and change them
@@ -48,7 +48,7 @@ let add_opt com block pos (var,opt) =
 	| None | Some TNull ->
 		(var,opt)
 	| Some (TString str) ->
-		block := Codegen.set_default com var (TString str) pos :: !block;
+		block := Texpr.set_default com.basic var (TString str) pos :: !block;
 		(var, opt)
 	| Some const ->
 		let basic = com.basic in

+ 6 - 118
src/optimization/filters.ml → src/filters/filters.ml

@@ -23,6 +23,7 @@ open Type
 open Typecore
 open Error
 open Globals
+open FiltersCommon
 
 (** retrieve string from @:native metadata or raise Not_found *)
 let get_native_name meta =
@@ -81,33 +82,6 @@ let rec add_final_return e =
 			{ e with eexpr = TFunction f }
 		| _ -> e
 
-let rec wrap_js_exceptions com e =
-	let rec is_error t =
-		match follow t with
-		| TInst ({cl_path = (["js"],"Error")},_) -> true
-		| TInst ({cl_super = Some (csup,tl)}, _) -> is_error (TInst (csup,tl))
-		| _ -> false
-	in
-	let rec loop e =
-		match e.eexpr with
-		| TThrow eerr when not (is_error eerr.etype) ->
-			let terr = List.find (fun mt -> match mt with TClassDecl {cl_path = ["js";"_Boot"],"HaxeError"} -> true | _ -> false) com.types in
-			let cerr = match terr with TClassDecl c -> c | _ -> assert false in
-			(match eerr.etype with
-			| TDynamic _ ->
-				let eterr = Codegen.ExprBuilder.make_static_this cerr e.epos in
-				let ewrap = Codegen.fcall eterr "wrap" [eerr] t_dynamic e.epos in
-				{ e with eexpr = TThrow ewrap }
-			| _ ->
-				let ewrap = { eerr with eexpr = TNew (cerr,[],[eerr]); etype = TInst (cerr,[]) } in
-				{ e with eexpr = TThrow ewrap }
-			)
-		| _ ->
-			Type.map_expr loop e
-	in
-
-	loop e
-
 (* -------------------------------------------------------------------------- *)
 (* CHECK LOCAL VARS INIT *)
 
@@ -441,25 +415,6 @@ let save_class_state ctx t = match t with
 
 (* PASS 2 begin *)
 
-let rec is_removable_class c =
-	match c.cl_kind with
-	| KGeneric ->
-		(Meta.has Meta.Remove c.cl_meta ||
-		(match c.cl_super with
-			| Some (c,_) -> is_removable_class c
-			| _ -> false) ||
-		List.exists (fun (_,t) -> match follow t with
-			| TInst(c,_) ->
-				has_ctor_constraint c || Meta.has Meta.Const c.cl_meta
-			| _ ->
-				false
-		) c.cl_params)
-	| KTypeParameter _ ->
-		(* this shouldn't happen, have to investigate (see #4092) *)
-		true
-	| _ ->
-		false
-
 let remove_generic_base ctx t = match t with
 	| TClassDecl c when is_removable_class c ->
 		c.cl_extern <- true
@@ -485,43 +440,6 @@ let remove_extern_fields ctx t = match t with
 	| _ ->
 		()
 
-
-module VarLazifier = struct
-	let apply com e =
-		let rec loop var_inits e = match e.eexpr with
-			| TVar(v,Some e1) when (Meta.has (Meta.Custom ":extractorVariable") v.v_meta) ->
-				let var_inits,e1 = loop var_inits e1 in
-				let var_inits = PMap.add v.v_id e1 var_inits in
-				var_inits,{e with eexpr = TVar(v,None)}
-			| TLocal v ->
-				begin try
-					let e_init = PMap.find v.v_id var_inits in
-					let e = {e with eexpr = TBinop(OpAssign,e,e_init)} in
-					let e = {e with eexpr = TParenthesis e} in
-					let var_inits = PMap.remove v.v_id var_inits in
-					var_inits,e
-				with Not_found ->
-					var_inits,e
-				end
-			| TIf(e1,e2,eo) ->
-				let var_inits,e1 = loop var_inits e1 in
-				let _,e2 = loop var_inits e2 in
-				let eo = match eo with None -> None | Some e -> Some (snd (loop var_inits e)) in
-				var_inits,{e with eexpr = TIf(e1,e2,eo)}
-			| TSwitch(e1,cases,edef) ->
-				let var_inits,e1 = loop var_inits e1 in
-				let cases = List.map (fun (el,e) ->
-					let _,e = loop var_inits e in
-					el,e
-				) cases in
-				let edef = match edef with None -> None | Some e -> Some (snd (loop var_inits e)) in
-				var_inits,{e with eexpr = TSwitch(e1,cases,edef)}
-			| _ ->
-				Texpr.foldmap loop var_inits e
-		in
-		snd (loop PMap.empty e)
-end
-
 (* PASS 2 end *)
 
 (* PASS 3 begin *)
@@ -687,7 +605,7 @@ let add_field_inits reserved ctx t =
 (* Adds the __meta__ field if required *)
 let add_meta_field ctx t = match t with
 	| TClassDecl c ->
-		(match Codegen.build_metadata ctx.com t with
+		(match Texpr.build_metadata ctx.com.basic t with
 		| None -> ()
 		| Some e ->
 			add_feature ctx.com "has_metadata";
@@ -695,7 +613,6 @@ let add_meta_field ctx t = match t with
 			cf.cf_expr <- Some e;
 			let can_deal_with_interface_metadata () = match ctx.com.platform with
 				| Flash when Common.defined ctx.com Define.As3 -> false
-				| Php when not (Common.is_php7 ctx.com) -> false
 				| Cs | Java -> false
 				| _ -> true
 			in
@@ -814,37 +731,6 @@ let check_reserved_type_paths ctx t =
 
 (* 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 ->
-		ctx.curclass <- c;
-		let rec process_field f =
-			ctx.curfield <- f;
-			(match f.cf_expr with
-			| Some e when not (is_removable_field ctx f) ->
-				AbstractCast.cast_stack := f :: !AbstractCast.cast_stack;
-				f.cf_expr <- Some (run e);
-				AbstractCast.cast_stack := List.tl !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;
-		(match c.cl_constructor with
-		| None -> ()
-		| Some f -> process_field f);
-		(match c.cl_init with
-		| None -> ()
-		| Some e ->
-			c.cl_init <- Some (run e));
-	| TEnumDecl _ -> ()
-	| TTypeDecl _ -> ()
-	| TAbstractDecl _ -> ()
-
 let pp_counter = ref 1
 
 let is_cached t =
@@ -872,7 +758,7 @@ let iter_expressions fl mt =
 		()
 
 let filter_timer detailed s =
-	timer (if detailed then "filters" :: s else ["filters"])
+	Timer.timer (if detailed then "filters" :: s else ["filters"])
 
 let run com tctx main =
 	let detail_times = Common.raw_defined com "filter-times" in
@@ -907,6 +793,8 @@ let run com tctx main =
 			filters @ [
 				TryCatchWrapper.configure_java com
 			]
+		| Js ->
+			filters @ [JsExceptions.init tctx];
 		| _ -> filters
 	in
 	let t = filter_timer detail_times ["expr 1"] in
@@ -935,7 +823,6 @@ let run com tctx main =
 	let filters = [
 		Optimizer.sanitize com;
 		if com.config.pf_add_final_return then add_final_return else (fun e -> e);
-		if com.platform = Js then wrap_js_exceptions com else (fun e -> e);
 		rename_local_vars tctx reserved;
 		mark_switch_break_loops;
 	] in
@@ -987,6 +874,7 @@ let run com tctx main =
 	] in
 	let type_filters = match com.platform with
 		| Cs -> type_filters @ [ fun _ t -> InterfaceProps.run t ]
+		| Js -> JsExceptions.inject_callstack com type_filters
 		| _ -> type_filters
 	in
 	let t = filter_timer detail_times ["type 3"] in

+ 70 - 0
src/filters/filtersCommon.ml

@@ -0,0 +1,70 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2017  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*)
+open Type
+open Typecore
+
+let rec is_removable_class c =
+	match c.cl_kind with
+	| KGeneric ->
+		(Meta.has Meta.Remove c.cl_meta ||
+		(match c.cl_super with
+			| Some (c,_) -> is_removable_class c
+			| _ -> false) ||
+		List.exists (fun (_,t) -> match follow t with
+			| TInst(c,_) ->
+				has_ctor_constraint c || Meta.has Meta.Const c.cl_meta
+			| _ ->
+				false
+		) c.cl_params)
+	| KTypeParameter _ ->
+		(* this shouldn't happen, have to investigate (see #4092) *)
+		true
+	| _ ->
+		false
+
+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 ->
+		ctx.curclass <- c;
+		let rec process_field f =
+			ctx.curfield <- f;
+			(match f.cf_expr with
+			| Some e when not (is_removable_field ctx f) ->
+				AbstractCast.cast_stack := f :: !AbstractCast.cast_stack;
+				f.cf_expr <- Some (run e);
+				AbstractCast.cast_stack := List.tl !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;
+		(match c.cl_constructor with
+		| None -> ()
+		| Some f -> process_field f);
+		(match c.cl_init with
+		| None -> ()
+		| Some e ->
+			c.cl_init <- Some (run e));
+	| TEnumDecl _ -> ()
+	| TTypeDecl _ -> ()
+	| TAbstractDecl _ -> ()

+ 209 - 0
src/filters/jsExceptions.ml

@@ -0,0 +1,209 @@
+(*
+	The Haxe Compiler
+	Copyright (C) 2005-2017  Haxe Foundation
+
+	This program is free software; you can redistribute it and/or
+	modify it under the terms of the GNU General Public License
+	as published by the Free Software Foundation; either version 2
+	of the License, or (at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *)
+
+(*
+	This filter handles everything related to exceptions for the JavaScript target:
+
+	- wrapping non-js.Error types in HaxeError on throwing
+	- unwrapping HaxeError on catch
+	- transforming series of catches into a single catch with Std.is checks (optimized)
+	- re-throwing caught exception with js.Lib.rethrow
+	- storing caught exception in haxe.CallStack.lastException (if haxe.CallStack is used)
+
+	Basically it translates this:
+
+	 try throw "fail"
+	 catch (e:String) { trace(e); js.Lib.rethrow(); }
+	 catch (e:Bool) {}
+
+	into something like this (JS):
+
+	 try {
+		 throw new HaxeError("fail");
+	 } catch (e) {
+		 haxe.CallStack.lastException = e;
+		 var e1 = (e instanceof HaxeError) e.val : e;
+		 if (typeof e1 == "string") {
+			 trace(e1);
+			 throw e;
+		 } else if (typeof e1 == "boolean") {
+		 } else {
+			 throw e;
+		 }
+	 }
+*)
+
+open Common
+open Type
+open Typecore
+open Texpr.Builder
+
+let follow = Abstract.follow_with_abstracts
+
+let rec is_js_error c =
+	match c with
+	| { cl_path = ["js"],"Error" } -> true
+	| { cl_super = Some (csup,_) } -> is_js_error csup
+	| _ -> false
+
+let find_cl com path =
+	ExtList.List.find_map (function
+		| TClassDecl c when c.cl_path = path -> Some c
+		| _ -> None
+	) com.types
+
+let init ctx =
+	let cJsError = find_cl ctx.com (["js"],"Error") in
+	let cHaxeError = find_cl ctx.com (["js";"_Boot"],"HaxeError") in
+	let cStd = find_cl ctx.com ([],"Std") in
+	let cBoot = find_cl ctx.com (["js"],"Boot") in
+	let cSyntax = find_cl ctx.com (["js"],"Syntax") in
+
+	let dynamic_wrap e =
+		let eHaxeError = make_static_this cHaxeError e.epos in
+		fcall eHaxeError "wrap" [e] (TInst (cJsError, [])) e.epos
+	in
+
+	let static_wrap e =
+		{ e with eexpr = TNew (cHaxeError,[],[e]); etype = TInst (cHaxeError,[]) }
+	in
+
+	let rec loop vrethrow e =
+		match e.eexpr with
+		| TThrow eexc ->
+			let eexc = loop vrethrow eexc in
+			let eexc =
+				match follow eexc.etype with
+				| TDynamic _ | TMono _ ->
+					(match eexc.eexpr with
+					| TConst (TInt _ | TFloat _ | TString _ | TBool _ | TNull) -> static_wrap eexc
+					| _ -> dynamic_wrap eexc)
+				| TInst (c,_) when (is_js_error c) ->
+					eexc
+				| _ ->
+					static_wrap eexc
+			in
+			{ e with eexpr = TThrow eexc }
+
+		| TCall ({ eexpr = TField (_, FStatic ({ cl_path = ["js"],"Lib" }, { cf_name = "getOriginalException" })) }, _) ->
+			(match vrethrow with
+			| Some erethrowvar -> erethrowvar
+			| None -> abort "js.Lib.getOriginalException can only be called inside a catch block" e.epos)
+
+		| TCall ({ eexpr = TField (_, FStatic ({ cl_path = ["js"],"Lib" }, { cf_name = "rethrow" })) }, _) ->
+			(match vrethrow with
+			| Some erethrowvar -> { e with eexpr = TThrow erethrowvar }
+			| None -> abort "js.Lib.rethrow can only be called inside a catch block" e.epos)
+
+		| TTry (etry, catches) ->
+			let etry = loop vrethrow etry in
+
+			let catchall_name = match catches with [(v,_)] -> v.v_name | _ -> "e" in
+			let vcatchall = alloc_var catchall_name t_dynamic e.epos in
+			let ecatchall = make_local vcatchall e.epos in
+			let erethrow = mk (TThrow ecatchall) t_dynamic e.epos in
+
+			let eSyntax = make_static_this cSyntax e.epos in
+			let eHaxeError = make_static_this cHaxeError e.epos in
+			let eInstanceof = fcall eSyntax "instanceof" [ecatchall;eHaxeError] ctx.com.basic.tbool e.epos in
+			let eVal = field { ecatchall with etype = TInst (cHaxeError,[]) } "val" t_dynamic e.epos in
+			let eunwrap = mk (TIf (eInstanceof, eVal, Some (ecatchall))) t_dynamic e.epos in
+
+			let vunwrapped = alloc_var catchall_name t_dynamic e.epos in
+			vunwrapped.v_meta <- (Meta.CompilerGenerated,[],Globals.null_pos) :: vunwrapped.v_meta;
+			let eunwrapped = make_local vunwrapped e.epos in
+
+			let ecatch = List.fold_left (fun acc (v,ecatch) ->
+				let ecatch = loop (Some ecatchall) ecatch in
+
+				(* it's not really compiler-generated, but it kind of is, since it was used as catch identifier and we add a TVar for it *)
+				v.v_meta <- (Meta.CompilerGenerated,[],Globals.null_pos) :: v.v_meta;
+
+				match follow v.v_type with
+				| TDynamic _ ->
+					{ ecatch with
+						eexpr = TBlock [
+							mk (TVar (v, Some eunwrapped)) ctx.com.basic.tvoid ecatch.epos;
+							ecatch;
+						]
+					}
+				| t ->
+					let etype = make_typeexpr (module_type_of_type t) e.epos in
+					let args = [eunwrapped;etype] in
+					let echeck =
+						match Optimizer.api_inline ctx cStd "is" args e.epos with
+						| Some e -> e
+						| None ->
+							let eBoot = make_static_this cBoot e.epos in
+							fcall eBoot "__instanceof" [eunwrapped;etype] ctx.com.basic.tbool e.epos
+					in
+					let ecatch = { ecatch with
+						eexpr = TBlock [
+							mk (TVar (v, Some eunwrapped)) ctx.com.basic.tvoid ecatch.epos;
+							ecatch;
+						]
+					} in
+					mk (TIf (echeck, ecatch, Some acc)) e.etype e.epos
+			) erethrow (List.rev catches) in
+
+			let ecatch = { ecatch with
+				eexpr = TBlock [
+					mk (TVar (vunwrapped, Some eunwrap)) ctx.com.basic.tvoid e.epos;
+					ecatch;
+				]
+			} in
+			{ e with eexpr = TTry (etry, [(vcatchall,ecatch)]) }
+		| _ ->
+			Type.map_expr (loop vrethrow) e
+	in
+	loop None
+
+let inject_callstack com type_filters =
+	let cCallStack =
+		if Common.has_dce com then
+			if Common.has_feature com "haxe.CallStack.lastException" then
+				Some (find_cl com (["haxe"],"CallStack"))
+			else
+				None
+		else
+			try Some (find_cl com (["haxe"],"CallStack")) with Not_found -> None
+	in
+	match cCallStack with
+	| Some cCallStack ->
+		let rec loop e =
+			match e.eexpr with
+			| TTry (etry,[(v,ecatch)]) ->
+				let etry = loop etry in
+				let ecatch = loop ecatch in
+
+				let eCallStack = make_static_this cCallStack ecatch.epos in
+				let elastException = field eCallStack "lastException" t_dynamic ecatch.epos in
+				let elocal = make_local v ecatch.epos in
+				let eStoreException = mk (TBinop (Ast.OpAssign, elastException, elocal)) ecatch.etype ecatch.epos in
+				let ecatch = Type.concat eStoreException ecatch in
+				{ e with eexpr = TTry (etry,[(v,ecatch)]) }
+			| TTry _ ->
+				(* this should be handled by the filter above *)
+				assert false
+			| _ ->
+				Type.map_expr loop e
+		in
+		type_filters @ [ fun ctx t -> FiltersCommon.run_expression_filters ctx [loop] t ]
+	| None ->
+		type_filters

+ 4 - 4
src/filters/tryCatchWrapper.ml

@@ -21,7 +21,7 @@ open Common
 open Ast
 open Type
 open Codegen
-open Codegen.ExprBuilder
+open Texpr.Builder
 
 (* ******************************************* *)
 (* Try / Catch + throw native types handling *)
@@ -138,11 +138,11 @@ let configure_cs com =
 			let e_wrap = fcall e_hxexception "wrap" [expr] base_exception_t expr.epos in
 			make_throw e_wrap expr.epos
 	in
-	let unwrap_expr local_to_unwrap = Codegen.field (mk_cast local_to_unwrap hx_exception_t local_to_unwrap.epos) "obj" t_dynamic local_to_unwrap.epos in
+	let unwrap_expr local_to_unwrap = field (mk_cast local_to_unwrap hx_exception_t local_to_unwrap.epos) "obj" t_dynamic local_to_unwrap.epos in
 	let rethrow_expr rethrow = make_throw e_rethrow rethrow.epos in
 	let catch_map v e =
 		let e_exc = make_static_this exc_cl e.epos in
-		let e_field = Codegen.field e_exc "exception" base_exception_t e.epos in
+		let e_field = field e_exc "exception" base_exception_t e.epos in
 		let e_setstack = binop OpAssign e_field (make_local v e.epos) v.v_type e.epos in
 		Type.concat e_setstack e
 	in
@@ -171,7 +171,7 @@ let configure_java com =
 		let e_wrap = fcall e_hxexception "wrap" [expr] base_exception_t expr.epos in
 		make_throw e_wrap expr.epos
 	in
-	let unwrap_expr local_to_unwrap = Codegen.field (mk_cast local_to_unwrap hx_exception_t local_to_unwrap.epos) "obj" t_dynamic local_to_unwrap.epos in
+	let unwrap_expr local_to_unwrap = field (mk_cast local_to_unwrap hx_exception_t local_to_unwrap.epos) "obj" t_dynamic local_to_unwrap.epos in
 	let rethrow_expr exc = { exc with eexpr = TThrow exc } in
 	let catch_map v e =
 		let exc = make_static_this exc_cl e.epos in

+ 36 - 0
src/filters/varLazifier.ml

@@ -0,0 +1,36 @@
+open Ast
+open Type
+
+let apply com e =
+	let rec loop var_inits e = match e.eexpr with
+		| TVar(v,Some e1) when (Meta.has (Meta.Custom ":extractorVariable") v.v_meta) ->
+			let var_inits,e1 = loop var_inits e1 in
+			let var_inits = PMap.add v.v_id e1 var_inits in
+			var_inits,{e with eexpr = TVar(v,None)}
+		| TLocal v ->
+			begin try
+				let e_init = PMap.find v.v_id var_inits in
+				let e = {e with eexpr = TBinop(OpAssign,e,e_init)} in
+				let e = {e with eexpr = TParenthesis e} in
+				let var_inits = PMap.remove v.v_id var_inits in
+				var_inits,e
+			with Not_found ->
+				var_inits,e
+			end
+		| TIf(e1,e2,eo) ->
+			let var_inits,e1 = loop var_inits e1 in
+			let _,e2 = loop var_inits e2 in
+			let eo = match eo with None -> None | Some e -> Some (snd (loop var_inits e)) in
+			var_inits,{e with eexpr = TIf(e1,e2,eo)}
+		| TSwitch(e1,cases,edef) ->
+			let var_inits,e1 = loop var_inits e1 in
+			let cases = List.map (fun (el,e) ->
+				let _,e = loop var_inits e in
+				el,e
+			) cases in
+			let edef = match edef with None -> None | Some e -> Some (snd (loop var_inits e)) in
+			var_inits,{e with eexpr = TSwitch(e1,cases,edef)}
+		| _ ->
+			Texpr.foldmap loop var_inits e
+	in
+	snd (loop PMap.empty e)

+ 4 - 4
src/generators/genas3.ml

@@ -300,7 +300,7 @@ let rec type_str ctx t p =
 		| [], "UInt" -> "uint"
 		| _ -> type_str ctx (apply_params t.t_params args t.t_type) p)
 	| TLazy f ->
-		type_str ctx ((!f)()) p
+		type_str ctx (lazy_type f) p
 
 let rec iter_switch_break in_switch e =
 	match e.eexpr with
@@ -676,7 +676,7 @@ and gen_expr ctx e =
 		let bend = open_block ctx in
 		let cb = (if not ctx.constructor_block then
 			(fun () -> ())
-		else if not (Codegen.constructor_side_effects e) then begin
+		else if not (Texpr.constructor_side_effects e) then begin
 			ctx.constructor_block <- false;
 			(fun () -> ())
 		end else begin
@@ -754,7 +754,7 @@ 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) -> print ctx "%s : " (anon_field f); gen_value ctx e) fields;
 		spr ctx "}"
 	| TFor (v,it,e) ->
 		let handle_break = handle_break ctx e in
@@ -1204,7 +1204,7 @@ let generate_enum ctx e =
 			print ctx "public static var %s : %s = new %s(\"%s\",%d)" c.ef_name ename ename c.ef_name c.ef_index;
 	) e.e_constrs;
 	newline ctx;
-	(match Codegen.build_metadata ctx.inf.com (TEnumDecl e) with
+	(match Texpr.build_metadata ctx.inf.com.basic (TEnumDecl e) with
 	| None -> ()
 	| Some e ->
 		print ctx "public static var __meta__ : * = ";

+ 31 - 27
src/generators/gencpp.ml

@@ -176,7 +176,7 @@ let cached_source_writer common_ctx filename =
    new source_writer common_ctx (add_header) (add_buf) (close)
 ;;
 
-let make_class_directories = Common.mkdir_recursive;;
+let make_class_directories = Path.mkdir_recursive;;
 
 let make_base_directory dir =
    make_class_directories "" ( ( Str.split_delim (Str.regexp "[\\/]+") dir ) );;
@@ -634,7 +634,7 @@ let rec is_objc_type t =
    | TType(td,_) -> (Meta.has Meta.Objc td.t_meta)
    | TAbstract (a,_) -> (Meta.has Meta.Objc a.a_meta)
    | TMono r -> (match !r with | Some t -> is_objc_type t | _ -> false)
-   | TLazy f -> is_objc_type (!f())
+   | TLazy f -> is_objc_type (lazy_type f)
    | _ -> false
 ;;
 
@@ -806,7 +806,7 @@ and type_string_suff suffix haxe_type remap =
       | _ -> "Dynamic"  ^ suffix )
       *)
    | TDynamic haxe_type -> "Dynamic" ^ suffix
-   | TLazy func -> type_string_suff suffix ((!func)()) remap
+   | TLazy func -> type_string_suff suffix (lazy_type func) remap
    | TAbstract (abs,pl) when abs.a_impl <> None ->
       type_string_suff suffix (Abstract.get_underlying_type abs pl) remap
    | TAbstract (abs,pl) ->
@@ -1796,7 +1796,7 @@ let rec cpp_type_of ctx haxe_type =
    | TFun _ -> TCppObject
    | TAnon _ -> TCppObject
    | TDynamic _ -> TCppDynamic
-   | TLazy func -> cpp_type_of ctx ((!func)())
+   | TLazy func -> cpp_type_of ctx (lazy_type func)
    )
    and  cpp_type_from_path ctx path params default =
       match path,params with
@@ -2895,7 +2895,7 @@ let retype_expression ctx request_type function_args function_type expression_tr
             | OpDiv -> TCppScalar("Float")
             | OpBoolAnd | OpBoolOr -> TCppScalar("bool")
             | OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr -> TCppScalar("int")
-            | OpAssign -> cpp_type_of left.etype
+            | OpAssign -> (retype TCppUnchanged left).cpptype
             | _ -> TCppUnchanged
             in
             let e1 = retype binOpType left in
@@ -3006,14 +3006,14 @@ let retype_expression ctx request_type function_args function_type expression_tr
             CppBlock(cppExprs, List.rev !local_closures, !gc_stack ), TCppVoid
 
          | TObjectDecl (
-            ("fileName" , { eexpr = (TConst (TString file)) }) ::
-               ("lineNumber" , { eexpr = (TConst (TInt line)) }) ::
-                  ("className" , { eexpr = (TConst (TString class_name)) }) ::
-                     ("methodName", { eexpr = (TConst (TString meth)) }) :: [] ) ->
+            (("fileName",_,_) , { eexpr = (TConst (TString file)) }) ::
+               (("lineNumber",_,_) , { eexpr = (TConst (TInt line)) }) ::
+                  (("className",_,_) , { eexpr = (TConst (TString class_name)) }) ::
+                     (("methodName",_,_), { eexpr = (TConst (TString meth)) }) :: [] ) ->
               CppPosition(file,line,class_name,meth), TCppDynamic
 
          | TObjectDecl el ->
-            let retypedEls = List.map ( fun(v,e) -> v, retype TCppDynamic e) el in
+            let retypedEls = List.map ( fun((v,_,_),e) -> v, retype TCppDynamic e) el in
             (match return_type with
             | TCppVoid -> CppObjectDecl(retypedEls,false), TCppVoid
             | _ -> CppObjectDecl(retypedEls,false), TCppDynamic
@@ -4736,7 +4736,7 @@ let find_referenced_types_flags ctx obj field_name super_deps constructor_deps h
          | _ -> () );
          ) enum_def.e_constrs;
       if (not header_only) then begin
-         let meta = Codegen.build_metadata ctx.ctx_common (TEnumDecl enum_def) in
+         let meta = Texpr.build_metadata ctx.ctx_common.basic (TEnumDecl enum_def) in
          match meta with Some expr -> visit_params expr | _ -> ();
       end;
    in
@@ -5318,7 +5318,8 @@ let access_str a = match a with
    | AccResolve -> "AccResolve"
    | AccCall -> "AccCall"
    | AccInline -> "AccInline"
-   | AccRequire(_,_) -> "AccRequire" ;;
+   | AccRequire(_,_) -> "AccRequire"
+   | AccCtor -> "AccCtor";;
 
 
 let script_type t optional = if optional then begin
@@ -6050,7 +6051,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta
          )
       in
 
-      output_cpp "#if HXCPP_SCRIPTABLE\n";
+      output_cpp "#ifdef HXCPP_SCRIPTABLE\n";
 
       let stored_fields = List.filter is_data_member implemented_instance_fields in
       if ( (List.length stored_fields) > 0) then begin
@@ -7532,16 +7533,16 @@ class script_writer ctx filename asciiOut =
               this#checkCast return_type value false false;
          )
    | TObjectDecl (
-      ("fileName" , { eexpr = (TConst (TString file)) }) ::
-         ("lineNumber" , { eexpr = (TConst (TInt line)) }) ::
-            ("className" , { eexpr = (TConst (TString class_name)) }) ::
-               ("methodName", { eexpr = (TConst (TString meth)) }) :: [] ) ->
+      (("fileName",_,_) , { eexpr = (TConst (TString file)) }) ::
+         (("lineNumber",_,_) , { eexpr = (TConst (TInt line)) }) ::
+            (("className",_,_) , { eexpr = (TConst (TString class_name)) }) ::
+               (("methodName",_,_), { eexpr = (TConst (TString meth)) }) :: [] ) ->
             this#write ( (this#op IaPosInfo) ^ (this#stringText file) ^ (Printf.sprintf "%ld" line) ^ " " ^
                         (this#stringText class_name) ^ " " ^  (this#stringText meth))
 
    | TObjectDecl values ->this#write ( (this#op IaObjDef) ^ (string_of_int (List.length values)));
          this#write " ";
-         List.iter (fun (name,_) -> this#write (this#stringText name)  ) values;
+         List.iter (fun ((name,_,_),_) -> this#write (this#stringText name)  ) values;
          this#write "\n";
          List.iter (fun (_,e) -> this#gen_expression e ) values;
    | TTypeExpr type_expr ->
@@ -7992,7 +7993,7 @@ let generate_script_class common_ctx script class_def =
          script#writeOpLine IaInline;
       | Var v,_ ->
          let mode_code mode = match mode with
-         | AccNormal -> IaAccessNormal
+         | AccNormal | AccCtor -> IaAccessNormal
          | AccNo -> IaAccessNot
          | AccNever -> IaAccessNot
          | AccResolve -> IaAccessResolve
@@ -8075,7 +8076,7 @@ let generate_cppia ctx =
          if (is_internal) then
             (if (debug>=4) then print_endline (" internal enum " ^ (join_class_path enum_def.e_path ".") ))
          else begin
-            let meta = Codegen.build_metadata common_ctx object_def in
+            let meta = Texpr.build_metadata common_ctx.basic object_def in
             if (enum_def.e_extern) then
                (if (debug>=4) then print_endline ("external enum " ^  (join_class_path enum_def.e_path ".") ));
             generate_script_enum common_ctx script enum_def meta
@@ -8170,7 +8171,7 @@ let generate_source ctx =
          if (is_internal) then
             (if (debug>1) then print_endline (" internal enum " ^ name ))
          else begin
-            let meta = Codegen.build_metadata common_ctx object_def in
+            let meta = Texpr.build_metadata common_ctx.basic object_def in
             if (enum_def.e_extern) then
                (if (debug>1) then print_endline ("external enum " ^ name ));
             boot_enums := enum_def.e_path :: !boot_enums;
@@ -8188,7 +8189,9 @@ let generate_source ctx =
    (match common_ctx.main with
    | None -> generate_dummy_main common_ctx
    | Some e ->
-      let main_field = { cf_name = "__main__"; cf_type = t_dynamic; cf_expr = Some e; cf_expr_unoptimized = None; cf_pos = e.epos; cf_name_pos = null_pos; cf_public = true; cf_meta = []; cf_overloads = []; cf_doc = None; cf_kind = Var { v_read = AccNormal; v_write = AccNormal; }; cf_params = [] } in
+      let main_field = { (mk_field "__main__" t_dynamic e.epos null_pos) with
+         cf_expr = Some e;
+	  } in
       let class_def = { null_class with cl_path = ([],"@Main"); cl_ordered_statics = [main_field] } in
       main_deps := find_referenced_types ctx (TClassDecl class_def) super_deps constructor_deps false true false;
       generate_main ctx super_deps class_def
@@ -8254,10 +8257,10 @@ let generate_source ctx =
    let cmd_defines = ref "" in
    PMap.iter ( fun name value -> match name with
       | "true" | "sys" | "dce" | "cpp" | "debug" -> ()
-      | _ -> cmd_defines := !cmd_defines ^ " -D" ^ name ^ "=\"" ^ (escape_command value) ^ "\"" ) common_ctx.defines;
-   write_build_options common_ctx (common_ctx.file ^ "/Options.txt") common_ctx.defines;
+      | _ -> cmd_defines := !cmd_defines ^ " -D" ^ name ^ "=\"" ^ (escape_command value) ^ "\"" ) common_ctx.defines.Define.values;
+   write_build_options common_ctx (common_ctx.file ^ "/Options.txt") common_ctx.defines.Define.values;
    if ( not (Common.defined common_ctx Define.NoCompilation) ) then begin
-      let t = Common.timer ["generate";"cpp";"native compilation"] in
+      let t = Timer.timer ["generate";"cpp";"native compilation"] in
       let old_dir = Sys.getcwd() in
       Sys.chdir common_ctx.file;
       let cmd = ref "haxelib run hxcpp Build.xml haxe" in
@@ -8272,11 +8275,12 @@ let generate_source ctx =
    ;;
 
 let generate common_ctx =
+   let debug_level = if (Common.defined common_ctx Define.NoDebug) then 0 else 1 in
    if (Common.defined common_ctx Define.Cppia) then begin
-      let ctx = new_context common_ctx 1 (ref PMap.empty) (Hashtbl.create 0)  in
+      let ctx = new_context common_ctx debug_level (ref PMap.empty) (Hashtbl.create 0)  in
       generate_cppia ctx
    end else begin
-      let ctx = new_context common_ctx 1 (ref PMap.empty) (create_member_types common_ctx) in
+      let ctx = new_context common_ctx debug_level (ref PMap.empty) (create_member_types common_ctx) in
       generate_source ctx
    end
 ;;

+ 16 - 13
src/generators/gencs.ml

@@ -25,6 +25,7 @@ open Type
 open Gencommon
 open Gencommon.SourceWriter
 open Codegen
+open Texpr.Builder
 open Printf
 open Option
 open ExtString
@@ -45,7 +46,7 @@ let rec is_cs_basic_type t =
 			true
 		| TAbstract(a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
 			is_cs_basic_type (Abstract.get_underlying_type a pl)
-		| TEnum(e, _) when not (Meta.has Meta.Class e.e_meta) -> true
+		| TEnum(e, _) as t when not (is_hxgen_t t) -> true
 		| TInst(cl, _) when Meta.has Meta.Struct cl.cl_meta -> true
 		| _ -> false
 
@@ -101,7 +102,7 @@ let rec is_null t =
 			| Some t -> is_null t
 			| _ -> false)
 		| TLazy f ->
-			is_null (!f())
+			is_null (lazy_type f)
 		| _ -> false
 
 let rec get_ptr e = match e.eexpr with
@@ -381,7 +382,7 @@ struct
 					{ e with eexpr = TField(run ef, FDynamic "ToUpperInvariant") }
 
 				| TCall( { eexpr = TField(_, FStatic({ cl_path = [], "String" }, { cf_name = "fromCharCode" })) }, [cc] ) ->
-					{ e with eexpr = TNew(get_cl_from_t basic.tstring, [], [mk_cast tchar (run cc); ExprBuilder.make_int gen.gcon 1 cc.epos]) }
+					{ e with eexpr = TNew(get_cl_from_t basic.tstring, [], [mk_cast tchar (run cc); make_int gen.gcon.basic 1 cc.epos]) }
 				| TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("charAt" as field) })) }, args )
 				| TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("charCodeAt" as field) })) }, args )
 				| TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("indexOf" as field) })) }, args )
@@ -535,7 +536,7 @@ let add_cast_handler gen =
 				epos = e.epos
 			};
 			{
-				eexpr = TVar(i, Some( ExprBuilder.make_int gen.gcon (-1) e.epos ));
+				eexpr = TVar(i, Some( make_int gen.gcon.basic (-1) e.epos ));
 				etype = basic.tvoid;
 				epos = e.epos
 			};
@@ -1797,7 +1798,7 @@ let generate con =
 						| Some t -> run t
 						| _ -> () (* avoid infinite loop / should be the same in this context *))
 					| TLazy f ->
-						run (!f())
+						run (lazy_type f)
 					| _ -> ()
 			in
 			run t;
@@ -2124,7 +2125,7 @@ let generate con =
 										| TBlock _ ->
 											let unchecked = needs_unchecked e in
 											if unchecked then (begin_block w; write w "unchecked ");
-											let t = Common.timer ["expression to string"] in
+											let t = Timer.timer ["expression to string"] in
 											expr_s w e;
 											t();
 											line_reset_directive w;
@@ -2151,7 +2152,7 @@ let generate con =
 													| None -> ()
 													| Some sc ->
 														write w ": ";
-														let t = Common.timer ["expression to string"] in
+														let t = Timer.timer ["expression to string"] in
 														expr_s w sc;
 														write w " ";
 														t()
@@ -2316,7 +2317,7 @@ let generate con =
 					in
 					if prop v.v_read && prop v.v_write && (v.v_read = AccCall || v.v_write = AccCall) then begin
 						let this = if static then
-							ExprBuilder.make_static_this cl f.cf_pos
+							make_static_this cl f.cf_pos
 						else
 							{ eexpr = TConst TThis; etype = TInst(cl,List.map snd cl.cl_params); epos = f.cf_pos }
 						in
@@ -2689,6 +2690,8 @@ let generate con =
 				match e.eexpr, real_type e.etype with
 					| TConst TThis, _ when gen.gcurrent_path = (["haxe";"lang"], "Null") ->
 						e
+					| TConst (TInt _ | TFloat _ | TBool _), _ ->
+						e
 					| _, TInst({ cl_path = (["haxe";"lang"], "Null") }, [t]) ->
 						let e = { e with eexpr = TParenthesis(e) } in
 						{ (mk_field_access gen e "value" e.epos) with etype = t }
@@ -2737,7 +2740,7 @@ let generate con =
 
 		let cl_arg_exc = get_cl (get_type gen (["System"],"ArgumentException")) in
 		let cl_arg_exc_t = TInst (cl_arg_exc, []) in
-		let mk_arg_exception msg pos = mk (TNew (cl_arg_exc, [], [ExprBuilder.make_string gen.gcon msg pos])) cl_arg_exc_t pos in
+		let mk_arg_exception msg pos = mk (TNew (cl_arg_exc, [], [make_string gen.gcon.basic msg pos])) cl_arg_exc_t pos in
 		let closure_t = ClosuresToClass.DoubleAndDynamicClosureImpl.get_ctx gen (get_cl (get_type gen (["haxe";"lang"],"Function"))) 6 mk_arg_exception in
 		ClosuresToClass.configure gen closure_t;
 
@@ -2840,7 +2843,7 @@ let generate con =
 
 		let cl_field_exc = get_cl (get_type gen (["System"],"MemberAccessException")) in
 		let cl_field_exc_t = TInst (cl_field_exc, []) in
-		let mk_field_exception msg pos = mk (TNew (cl_field_exc, [], [ExprBuilder.make_string gen.gcon msg pos])) cl_field_exc_t pos in
+		let mk_field_exception msg pos = mk (TNew (cl_field_exc, [], [make_string gen.gcon.basic msg pos])) cl_field_exc_t pos in
 
 		let rcf_ctx =
 			ReflectionCFs.new_ctx
@@ -3073,7 +3076,7 @@ let generate con =
 									{ eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos }
 								end
 							in
-							let zero = ExprBuilder.make_int gen.gcon 0 e.epos in
+							let zero = make_int gen.gcon.basic 0 e.epos in
 							{ e with eexpr = TBinop(op, handler, zero) }
 		);
 
@@ -3120,7 +3123,7 @@ let generate con =
 			Hashtbl.iter (fun name v ->
 				let name = Codegen.escape_res_name name true in
 				let full_path = src ^ "/" ^ name in
-				mkdir_from_path full_path;
+				Path.mkdir_from_path full_path;
 
 				let f = open_out_bin full_path in
 				output_string f v;
@@ -3223,7 +3226,7 @@ let generate con =
 
 		RenameTypeParameters.run gen.gtypes_list;
 
-		mkdir_from_path gen.gcon.file;
+		Path.mkdir_from_path gen.gcon.file;
 
 		List.iter (fun md_def ->
 			let source_dir = gen.gcon.file ^ "/src/" ^ (String.concat "/" (fst (path_of_md_def md_def))) in

+ 55 - 66
src/generators/genhl.ml

@@ -46,7 +46,7 @@ type allocator = {
 	mutable a_hold : int list;
 }
 
-type lassign = (string index * int * int)
+type lassign = (string index * int)
 
 type method_context = {
 	mid : int;
@@ -108,8 +108,6 @@ type context = {
 	core_enum : tclass;
 	ref_abstract : tabstract;
 	cdebug_files : (string, string) lookup;
-	cdebug_locals : (string, string ) lookup;
-	cdebug_assigns : (lassign array) DynArray.t;
 }
 
 (* --- *)
@@ -246,7 +244,7 @@ let efield_name e f =
 let global_type ctx g =
 	DynArray.get ctx.cglobals.arr g
 
-let is_overriden ctx c f =
+let is_overridden ctx c f =
 	ctx.is_macro || Hashtbl.mem ctx.overrides (f.cf_name,c.cl_path)
 
 let alloc_float ctx f =
@@ -362,7 +360,7 @@ let rec to_type ?tref ctx t =
 		| ["haxe";"macro"], name -> Hashtbl.replace ctx.macro_typedefs name t; t
 		| _ -> t)
 	| TLazy f ->
-		to_type ?tref ctx (!f())
+		to_type ?tref ctx (lazy_type f)
 	| TFun (args, ret) ->
 		HFun (List.map (fun (_,o,t) ->
 			let pt = to_type ctx t in
@@ -592,7 +590,7 @@ and class_type ?(tref=None) ctx c pl statics =
 					let vid = (try -(fst (get_index f.cf_name p))-1 with Not_found -> assert false) in
 					DynArray.set virtuals vid g;
 					Some vid
-				else if is_overriden ctx c f then begin
+				else if is_overridden ctx c f then begin
 					let vid = DynArray.length virtuals in
 					DynArray.add virtuals g;
 					p.pindex <- PMap.add f.cf_name (-vid-1,HVoid) p.pindex;
@@ -827,10 +825,13 @@ let op ctx o =
 		DynArray.add ctx.m.mdebug ctx.m.mcurpos;
 		DynArray.add ctx.m.mops o
 
+let set_op ctx pos o =
+	DynArray.set ctx.m.mops pos o
+
 let jump ctx f =
 	let pos = current_pos ctx in
 	op ctx (OJAlways (-1)); (* loop *)
-	(fun() -> DynArray.set ctx.m.mops pos (f (current_pos ctx - pos - 1)))
+	(fun() -> set_op ctx pos (f (current_pos ctx - pos - 1)))
 
 let jump_back ctx =
 	let pos = current_pos ctx in
@@ -928,14 +929,14 @@ let real_name v =
 	in
 	loop v.v_meta
 
-let add_assign ctx v r =
+let add_assign ctx v =
 	let name = real_name v in
-	ctx.m.massign <- (lookup ctx.cdebug_locals name (fun() -> name), DynArray.length ctx.m.mops, r) :: ctx.m.massign
+	ctx.m.massign <- (alloc_string ctx name, current_pos ctx - 1) :: ctx.m.massign
 
 let add_capture ctx r =
 	Array.iter (fun v ->
 		let name = real_name v in
-		ctx.m.massign <- (lookup ctx.cdebug_locals name (fun() -> name), -1, r) :: ctx.m.massign
+		ctx.m.massign <- (alloc_string ctx name, -(r+2)) :: ctx.m.massign
 	) ctx.m.mcaptured.c_vars
 
 let before_return ctx =
@@ -1208,7 +1209,7 @@ and direct_method_call ctx c f ethis =
 		false
 	else if (match c.cl_kind with KTypeParameter _ ->  true | _ -> false) then
 		false
-	else if is_overriden ctx c f && ethis.eexpr <> TConst(TSuper) then
+	else if is_overridden ctx c f && ethis.eexpr <> TConst(TSuper) then
 		false
 	else
 		true
@@ -1333,10 +1334,20 @@ and jump_expr ctx e jcond =
 		jump_expr ctx e (not jcond)
 	| TBinop (OpEq,{ eexpr = TConst(TNull) },e) | TBinop (OpEq,e,{ eexpr = TConst(TNull) }) ->
 		let r = eval_expr ctx e in
-		jump ctx (fun i -> if jcond then OJNull (r,i) else OJNotNull (r,i))
+		if is_nullable(rtype ctx r) then
+			jump ctx (fun i -> if jcond then OJNull (r,i) else OJNotNull (r,i))
+		else if not jcond then
+			jump ctx (fun i -> OJAlways i)
+		else
+			(fun i -> ())
 	| TBinop (OpNotEq,{ eexpr = TConst(TNull) },e) | TBinop (OpNotEq,e,{ eexpr = TConst(TNull) }) ->
 		let r = eval_expr ctx e in
-		jump ctx (fun i -> if jcond then OJNotNull (r,i) else OJNull (r,i))
+		if is_nullable(rtype ctx r) then
+			jump ctx (fun i -> if jcond then OJNotNull (r,i) else OJNull (r,i))
+		else if jcond then
+			jump ctx (fun i -> OJAlways i)
+		else
+			(fun i -> ())
 	| TBinop (OpEq | OpNotEq | OpGt | OpGte | OpLt | OpLte as jop, e1, e2) ->
 		let t = common_type ctx e1 e2 (match jop with OpEq | OpNotEq -> true | _ -> false) e.epos in
 		let r1 = eval_to ctx e1 t in
@@ -1454,7 +1465,7 @@ and eval_expr ctx e =
 			| None ->
 				let r = alloc_var ctx v true in
 				op ctx (OMov (r,ri));
-				add_assign ctx v r;
+				add_assign ctx v;
 			| Some idx ->
 				op ctx (OSetEnumField (ctx.m.mcaptreg, idx, ri));
 		);
@@ -2052,11 +2063,11 @@ and eval_expr ctx e =
 		unsafe_cast_to ctx r (to_type ctx e.etype) e.epos
 	| TObjectDecl fl ->
 		(match to_type ctx e.etype with
-		| HVirtual vp as t when Array.length vp.vfields = List.length fl && not (List.exists (fun (s,e) -> s = "toString" && is_to_string e.etype) fl)  ->
+		| HVirtual vp as t when Array.length vp.vfields = List.length fl && not (List.exists (fun ((s,_,_),e) -> s = "toString" && is_to_string e.etype) fl)  ->
 			let r = alloc_tmp ctx t in
 			op ctx (ONew r);
 			hold ctx r;
-			List.iter (fun (s,ev) ->
+			List.iter (fun ((s,_,_),ev) ->
 				let fidx = (try PMap.find s vp.vindex with Not_found -> assert false) in
 				let _, _, ft = vp.vfields.(fidx) in
 				let v = eval_to ctx ev ft in
@@ -2069,7 +2080,7 @@ and eval_expr ctx e =
 			op ctx (ONew r);
 			hold ctx r;
 			let a = (match follow e.etype with TAnon a -> Some a | t -> if t == t_dynamic then None else assert false) in
-			List.iter (fun (s,ev) ->
+			List.iter (fun ((s,_,_),ev) ->
 				let ft = (try (match a with None -> raise Not_found | Some a -> PMap.find s a.a_fields).cf_type with Not_found -> ev.etype) in
 				let v = eval_to ctx ev (to_type ctx ft) in
 				op ctx (ODynSet (r,alloc_string ctx s,v));
@@ -2235,7 +2246,7 @@ and eval_expr ctx e =
 			| ALocal (v,l) ->
 				let r = value() in
 				op ctx (OMov (l, r));
-				add_assign ctx v l;
+				add_assign ctx v;
 				r
 			| AArray (ra,(at,vt),ridx) ->
 				hold ctx ra;
@@ -2307,7 +2318,6 @@ and eval_expr ctx e =
 			| ALocal (v,l) ->
 				let r = eval_to ctx { e with eexpr = TBinop (bop,e1,e2) } (to_type ctx e1.etype) in
 				op ctx (OMov (l, r));
-				add_assign ctx v l;
 				r
 			| acc ->
 				gen_assign_op ctx acc e1 (fun r ->
@@ -2369,13 +2379,11 @@ and eval_expr ctx e =
 		(match get_access ctx v, fix with
 		| ALocal (v,r), Prefix ->
 			unop r;
-			add_assign ctx v r;
 			r
 		| ALocal (v,r), Postfix ->
 			let r2 = alloc_tmp ctx (rtype ctx r) in
 			op ctx (OMov (r2,r));
 			unop r;
-			add_assign ctx v r;
 			r2
 		| acc, _ ->
 			let ret = ref 0 in
@@ -2534,7 +2542,7 @@ and eval_expr ctx e =
 	| TMeta (_,e) ->
 		eval_expr ctx e
 	| TFor (v,it,loop) ->
-		eval_expr ctx (Codegen.for_remap ctx.com v it loop e.epos)
+		eval_expr ctx (Texpr.for_remap ctx.com.basic v it loop e.epos)
 	| TSwitch (en,cases,def) ->
 		let rt = to_type ctx e.etype in
 		let r = alloc_tmp ctx rt in
@@ -2576,7 +2584,7 @@ and eval_expr ctx e =
 				if rt <> HVoid then op ctx (OMov (r,re));
 				jends := jump ctx (fun i -> OJAlways i) :: !jends
 			) cases;
-			DynArray.set ctx.m.mops (switch_pos - 1) (OSwitch (ridx,indexes,current_pos ctx - switch_pos));
+			set_op ctx (switch_pos - 1) (OSwitch (ridx,indexes,current_pos ctx - switch_pos));
 			List.iter (fun j -> j()) (!jends);
 		with Exit ->
 			let jends = ref [] in
@@ -2649,13 +2657,13 @@ and eval_expr ctx e =
 		before_break_continue ctx;
 		let pos = current_pos ctx in
 		op ctx (OJAlways (-1)); (* loop *)
-		ctx.m.mcontinues <- (fun target -> DynArray.set ctx.m.mops pos (OJAlways (target - (pos + 1)))) :: ctx.m.mcontinues;
+		ctx.m.mcontinues <- (fun target -> set_op ctx pos (OJAlways (target - (pos + 1)))) :: ctx.m.mcontinues;
 		alloc_tmp ctx HVoid
 	| TBreak ->
 		before_break_continue ctx;
 		let pos = current_pos ctx in
 		op ctx (OJAlways (-1)); (* loop *)
-		ctx.m.mbreaks <- (fun target -> DynArray.set ctx.m.mops pos (OJAlways (target - (pos + 1)))) :: ctx.m.mbreaks;
+		ctx.m.mbreaks <- (fun target -> set_op ctx pos (OJAlways (target - (pos + 1)))) :: ctx.m.mbreaks;
 		alloc_tmp ctx HVoid
 	| TTry (etry,catches) ->
 		let pos = current_pos ctx in
@@ -2669,7 +2677,7 @@ and eval_expr ctx e =
 		ctx.m.mtrys <- ctx.m.mtrys - 1;
 		op ctx (OEndTrap true);
 		let j = jump ctx (fun n -> OJAlways n) in
-		DynArray.set ctx.m.mops pos (OTrap (rtrap, current_pos ctx - (pos + 1)));
+		set_op ctx pos (OTrap (rtrap, current_pos ctx - (pos + 1)));
 		let rec loop l =
 			match l with
 			| [] ->
@@ -2718,7 +2726,7 @@ and eval_expr ctx e =
 			op ctx (OSafeCast (r,re));
 		r
 	| TIdent s ->
-		assert false
+		abort ("Unbound identifier " ^ s) e.epos
 
 and gen_assign_op ctx acc e1 f =
 	let f r =
@@ -2902,10 +2910,10 @@ and gen_method_wrapper ctx rt t p =
 			regs = DynArray.to_array ctx.m.mregs.arr;
 			code = DynArray.to_array ctx.m.mops;
 			debug = make_debug ctx ctx.m.mdebug;
+			assigns = Array.of_list (List.rev ctx.m.massign);
 		} in
 		ctx.m <- old;
 		DynArray.add ctx.cfunctions f;
-		DynArray.add ctx.cdebug_assigns [||];
 		fid
 
 and make_fun ?gen_content ctx name fidx f cthis cparent =
@@ -2943,7 +2951,7 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 	let args = List.map (fun (v,o) ->
 		let t = to_type ctx v.v_type in
 		let r = alloc_var ctx (if o = None then v else { v with v_type = if not (is_nullable t) then TAbstract(ctx.ref_abstract,[v.v_type]) else v.v_type }) true in
-		add_assign ctx v r;
+		add_assign ctx v; (* record var name *)
 		rtype ctx r
 	) f.tf_args in
 
@@ -2988,11 +2996,11 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 				| _ -> assert false)
 			| _ ->
 				assert false);
-			if capt = None then add_assign ctx v t;
+			if capt = None then add_assign ctx v;
 			let jend = jump ctx (fun n -> OJAlways n) in
 			j();
 			op ctx (OUnref (t,r));
-			if capt = None then add_assign ctx v t;
+			if capt = None then add_assign ctx v;
 			jend();
 			Hashtbl.replace ctx.m.mvars v.v_id t;
 			free ctx r;
@@ -3024,7 +3032,6 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 			| TString s ->
 				op ctx (OMov (r, make_string ctx s f.tf_expr.epos))
 			);
-			if capt = None then add_assign ctx v r;
 			j();
 		);
 		(match capt with
@@ -3066,13 +3073,12 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 		regs = DynArray.to_array ctx.m.mregs.arr;
 		code = DynArray.to_array ctx.m.mops;
 		debug = make_debug ctx ctx.m.mdebug;
+		assigns = Array.of_list (List.rev ctx.m.massign);
 	} in
-	let assigns = Array.of_list (List.rev ctx.m.massign) in
 	ctx.m <- old;
 	Hashtbl.add ctx.defined_funs fidx ();
 	let f = if ctx.optimize then Hlopt.optimize ctx.dump_out f else f in
 	DynArray.add ctx.cfunctions f;
-	DynArray.add ctx.cdebug_assigns assigns;
 	capt
 
 let generate_static ctx c f =
@@ -3260,7 +3266,7 @@ let generate_static_init ctx types main =
 					op ctx (OSetGlobal (g, rt));
 				end;
 
-				(match Codegen.build_metadata ctx.com (TClassDecl c) with
+				(match Texpr.build_metadata ctx.com.basic (TClassDecl c) with
 				| None -> ()
 				| Some e ->
 					let r = eval_to ctx e HDyn in
@@ -3306,7 +3312,7 @@ let generate_static_init ctx types main =
 						op ctx (OSetGlobal (g,r));
 				) e.e_names;
 
-				(match Codegen.build_metadata ctx.com (TEnumDecl e) with
+				(match Texpr.build_metadata ctx.com.basic (TEnumDecl e) with
 				| None -> ()
 				| Some e -> op ctx (OSetField (r,index "__meta__",eval_to ctx e HDyn)));
 
@@ -3647,7 +3653,14 @@ let write_code ch code debug =
 		write_index (Array.length f.code);
 		Array.iter write_type f.regs;
 		Array.iter write_op f.code;
-		if debug then write_debug_infos f.debug;
+		if debug then begin
+			write_debug_infos f.debug;
+			write_index (Array.length f.assigns);
+			Array.iter (fun (i,p) ->
+				write_index i;
+				write_index (p + 1);
+			) f.assigns;
+		end;
 	) code.functions
 
 (* --------------------------------------------------------------------------------------------------------------------- *)
@@ -3709,8 +3722,6 @@ let create_context com is_macro dump =
 		method_wrappers = PMap.empty;
 		cdebug_files = new_lookup();
 		macro_typedefs = Hashtbl.create 0;
-		cdebug_locals = new_lookup();
-		cdebug_assigns = DynArray.create();
 	} in
 	ignore(alloc_string ctx "");
 	ignore(class_type ctx ctx.base_class [] false);
@@ -3757,7 +3768,7 @@ let add_types ctx types =
 let build_code ctx types main =
 	let ep = generate_static_init ctx types main in
 	{
-		version = 2;
+		version = 3;
 		entrypoint = ep;
 		strings = DynArray.to_array ctx.cstrings.arr;
 		ints = DynArray.to_array ctx.cints.arr;
@@ -3800,7 +3811,7 @@ let generate com =
 		check ctx;
 		Hlinterp.check code false;
 	end;
-	let t = Common.timer ["write";"hl"] in
+	let t = Timer.timer ["write";"hl"] in
 
 	let escape_command s =
 		let b = Buffer.create 0 in
@@ -3810,38 +3821,16 @@ let generate com =
 
 	if file_extension com.file = "c" then begin
 		Hl2c.write_c com com.file code;
-		let t = Common.timer ["nativecompile";"hl"] in
+		let t = Timer.timer ["nativecompile";"hl"] in
 		if not (Common.defined com Define.NoCompilation) && com.run_command ("haxelib run hashlink build " ^ escape_command com.file) <> 0 then failwith "Build failed";
 		t();
 	end else begin
 		let ch = IO.output_string() in
-		write_code ch code true;
+		write_code ch code (not (Common.raw_defined com "hl-no-debug"));
 		let str = IO.close_out ch in
 		let ch = open_out_bin com.file in
 		output_string ch str;
 		close_out ch;
-(*
-		let ch = IO.output_string() in
-		let byte = IO.write_byte ch in
-		let write_index = write_index_gen byte in
-		write_index (DynArray.length ctx.cdebug_locals.arr);
-		DynArray.iter (fun s ->
-			write_index (String.length s);
-			IO.write_string ch s;
-		) ctx.cdebug_locals.arr;
-		write_index (DynArray.length ctx.cdebug_assigns);
-		DynArray.iter (fun a ->
-			write_index (Array.length a);
-			Array.iter (fun (i,p,r) ->
-				write_index i;
-				write_index p;
-				write_index r;
-			) a;
-		) ctx.cdebug_assigns;
-		let str = IO.close_out ch in
-		let dbg = open_out_bin (com.file ^ "d") in
-		output_string dbg str;
-		close_out dbg; *)
 	end;
 	t();
 	if Common.raw_defined com "run" then begin
@@ -3849,7 +3838,7 @@ let generate com =
 	end;
 	if Common.defined com Define.Interp then
 		try
-			let t = Common.timer ["generate";"hl";"interp"] in
+			let t = Timer.timer ["generate";"hl";"interp"] in
 			let ctx = Hlinterp.create true in
 			Hlinterp.add_code ctx code;
 			t();

+ 7 - 7
src/generators/genjava.ml

@@ -1868,7 +1868,7 @@ let generate con =
 					| Some t -> run t
 					| _ -> () (* avoid infinite loop / should be the same in this context *))
 				| TLazy f ->
-					run (!f())
+					run (lazy_type f)
 				| _ -> ()
 		in
 		run t;
@@ -2288,7 +2288,7 @@ let generate con =
 
 	let cl_arg_exc = get_cl (get_type gen (["java";"lang"],"IllegalArgumentException")) in
 	let cl_arg_exc_t = TInst (cl_arg_exc, []) in
-	let mk_arg_exception msg pos = mk (TNew (cl_arg_exc, [], [ExprBuilder.make_string gen.gcon msg pos])) cl_arg_exc_t pos in
+	let mk_arg_exception msg pos = mk (TNew (cl_arg_exc, [], [Texpr.Builder.make_string gen.gcon.basic msg pos])) cl_arg_exc_t pos in
 	let closure_t = ClosuresToClass.DoubleAndDynamicClosureImpl.get_ctx gen (get_cl (get_type gen (["haxe";"lang"],"Function"))) 6 mk_arg_exception in
 	ClosuresToClass.configure gen closure_t;
 
@@ -2379,7 +2379,7 @@ let generate con =
 
 	let cl_field_exc = get_cl (get_type gen (["java";"lang"],"RuntimeException")) in
 	let cl_field_exc_t = TInst (cl_field_exc, []) in
-	let mk_field_exception msg pos = mk (TNew (cl_field_exc, [], [ExprBuilder.make_string gen.gcon msg pos])) cl_field_exc_t pos in
+	let mk_field_exception msg pos = mk (TNew (cl_field_exc, [], [Texpr.Builder.make_string gen.gcon.basic msg pos])) cl_field_exc_t pos in
 
 	let rcf_ctx =
 		ReflectionCFs.new_ctx
@@ -2557,7 +2557,7 @@ let generate con =
 									{ eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos }
 								end
 							in
-							let zero = ExprBuilder.make_int gen.gcon 0 e.epos in
+							let zero = Texpr.Builder.make_int gen.gcon.basic 0 e.epos in
 							{ e with eexpr = TBinop(op, handler, zero) }
 			);
 
@@ -2600,7 +2600,7 @@ let generate con =
 	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")), []);
 
-	mkdir_from_path (gen.gcon.file ^ "/src");
+	Path.mkdir_from_path (gen.gcon.file ^ "/src");
 
 	let out_files = ref [] in
 
@@ -2610,7 +2610,7 @@ let generate con =
 		res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = 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;
+		Path.mkdir_from_path full_path;
 
 		let f = open_out_bin full_path in
 		output_string f v;
@@ -2629,7 +2629,7 @@ let generate con =
 	RenameTypeParameters.run gen.gtypes_list;
 
 	let parts = Str.split_delim (Str.regexp "[\\/]+") gen.gcon.file in
-	mkdir_recursive "" parts;
+	Path.mkdir_recursive "" parts;
 
 	let source_dir = gen.gcon.file ^ "/src" in
 	List.iter (fun md ->

+ 197 - 217
src/generators/genjs.ml

@@ -27,13 +27,17 @@ type sourcemap = {
 	sources_hash : (string, int) Hashtbl.t;
 	mappings : Rbuffer.t;
 
-	mutable source_last_line : int;
-	mutable source_last_col : int;
-	mutable source_last_file : int;
+	mutable source_last_pos : sourcemap_pos;
 	mutable print_comma : bool;
 	mutable output_last_col : int;
 	mutable output_current_col : int;
-	mutable current_expr : texpr option;
+	mutable current_expr : sourcemap_pos option;
+}
+
+and sourcemap_pos = {
+	file : int;
+	line : int;
+	col : int;
 }
 
 type ctx = {
@@ -45,7 +49,6 @@ type ctx = {
 	js_modern : bool;
 	js_flatten : bool;
 	es_version : int;
-	store_exception_stack : bool;
 	mutable current : tclass;
 	mutable statics : (tclass * string * texpr) list;
 	mutable inits : texpr list;
@@ -139,10 +142,55 @@ let add_feature ctx = Common.add_feature ctx.com
 
 let unsupported p = abort "This expression cannot be compiled to Javascript" p
 
+let encode_mapping smap pos =
+	if smap.print_comma then
+		Rbuffer.add_char smap.mappings ','
+	else
+		smap.print_comma <- true;
+
+	let base64_vlq number =
+		let encode_digit digit =
+			let chars = [|
+				'A';'B';'C';'D';'E';'F';'G';'H';'I';'J';'K';'L';'M';'N';'O';'P';
+				'Q';'R';'S';'T';'U';'V';'W';'X';'Y';'Z';'a';'b';'c';'d';'e';'f';
+				'g';'h';'i';'j';'k';'l';'m';'n';'o';'p';'q';'r';'s';'t';'u';'v';
+				'w';'x';'y';'z';'0';'1';'2';'3';'4';'5';'6';'7';'8';'9';'+';'/'
+			|] in
+			Array.unsafe_get chars digit
+		in
+		let to_vlq number =
+			if number < 0 then
+				((-number) lsl 1) + 1
+			else
+				number lsl 1
+		in
+		let rec loop vlq =
+			let shift = 5 in
+			let base = 1 lsl shift in
+			let mask = base - 1 in
+			let continuation_bit = base in
+			let digit = vlq land mask in
+			let next = vlq asr shift in
+			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
+		loop (to_vlq number)
+	in
+
+	base64_vlq (smap.output_current_col - smap.output_last_col);
+	base64_vlq (pos.file - smap.source_last_pos.file);
+	base64_vlq (pos.line - smap.source_last_pos.line);
+	base64_vlq (pos.col - smap.source_last_pos.col);
+
+	smap.source_last_pos <- pos;
+	smap.output_last_col <- smap.output_current_col
+
+let noop () = ()
+
+let add_mapping smap pos =
+	if pos.pmin < 0 then noop else
 
-let add_mapping smap force e =
-	if e.epos.pmin < 0 then () else
-	let pos = e.epos in
 	let file = try
 		Hashtbl.find smap.sources_hash pos.pfile
 	with Not_found ->
@@ -151,55 +199,23 @@ let add_mapping smap force e =
 		DynArray.add smap.sources pos.pfile;
 		length
 	in
-	let line, col = Lexer.find_pos pos in
-	let line = line - 1 in
-	if force || smap.source_last_file != file || smap.source_last_line != line || smap.source_last_col != col then begin
-		smap.current_expr <- Some e;
-		if smap.print_comma then
-			Rbuffer.add_char smap.mappings ','
-		else
-			smap.print_comma <- true;
-
-		let base64_vlq number =
-			let encode_digit digit =
-				let chars = [|
-					'A';'B';'C';'D';'E';'F';'G';'H';'I';'J';'K';'L';'M';'N';'O';'P';
-					'Q';'R';'S';'T';'U';'V';'W';'X';'Y';'Z';'a';'b';'c';'d';'e';'f';
-					'g';'h';'i';'j';'k';'l';'m';'n';'o';'p';'q';'r';'s';'t';'u';'v';
-					'w';'x';'y';'z';'0';'1';'2';'3';'4';'5';'6';'7';'8';'9';'+';'/'
-				|] in
-				Array.unsafe_get chars digit
-			in
-			let to_vlq number =
-				if number < 0 then
-					((-number) lsl 1) + 1
-				else
-					number lsl 1
-			in
-			let rec loop vlq =
-				let shift = 5 in
-				let base = 1 lsl shift in
-				let mask = base - 1 in
-				let continuation_bit = base in
-				let digit = vlq land mask in
-				let next = vlq asr shift in
-				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
-			loop (to_vlq number)
-		in
 
-		base64_vlq (smap.output_current_col - smap.output_last_col);
-		base64_vlq (file - smap.source_last_file);
-		base64_vlq (line - smap.source_last_line);
-		base64_vlq (col - smap.source_last_col);
+	let pos =
+		let line, col = Lexer.find_pos pos in
+		let line = line - 1 in
+		{ file = file; line = line; col = col }
+	in
+
+	if smap.source_last_pos <> pos then begin
+		let old_current_expr = smap.current_expr in
+		smap.current_expr <- Some pos;
+		encode_mapping smap pos;
+		(fun () -> smap.current_expr <- old_current_expr)
+	end else
+		noop
 
-		smap.source_last_file <- file;
-		smap.source_last_line <- line;
-		smap.source_last_col <- col;
-		smap.output_last_col <- smap.output_current_col
-	end
+let add_mapping ctx e =
+	Option.map_default (fun smap -> add_mapping smap e.epos) noop ctx.smap
 
 let handle_newlines ctx str =
 	Option.may (fun smap ->
@@ -210,7 +226,7 @@ let handle_newlines ctx str =
 				smap.output_last_col <- 0;
 				smap.output_current_col <- 0;
 				smap.print_comma <- false;
-				Option.may (fun e -> add_mapping smap true e) smap.current_expr;
+				Option.may (encode_mapping smap) smap.current_expr;
 				loop next
 			end with Not_found ->
 				smap.output_current_col <- smap.output_current_col + (String.length str - from);
@@ -288,7 +304,7 @@ let fun_block ctx f p =
 	let e = List.fold_left (fun e (a,c) ->
 		match c with
 		| None | Some TNull -> e
-		| Some c -> Type.concat (Codegen.set_default ctx.com a c p) e
+		| Some c -> Type.concat (Texpr.set_default ctx.com.basic a c p) e
 	) f.tf_expr f.tf_args in
 	e
 
@@ -336,6 +352,9 @@ let gen_constant ctx p = function
 	| TThis -> spr ctx (this ctx)
 	| TSuper -> assert false
 
+let print_deprecation_message com msg p =
+	com.warning msg p
+
 let rec gen_call ctx e el in_value =
 	match e.eexpr , el with
 	| TConst TSuper , params ->
@@ -362,46 +381,26 @@ let rec gen_call ctx e el in_value =
 		spr ctx "(";
 		concat ctx "," (gen_value ctx) el;
 		spr ctx ")";
-	| TIdent "__new__", { eexpr = TConst (TString cl) } :: params ->
-		print ctx "new %s(" cl;
-		concat ctx "," (gen_value ctx) params;
-		spr ctx ")";
-	| TIdent "__new__", e :: params ->
-		spr ctx "new ";
-		gen_value ctx e;
-		spr ctx "(";
-		concat ctx "," (gen_value ctx) params;
-		spr ctx ")";
-	| TIdent "__js__", [{ eexpr = TConst (TString "this") }] ->
-		spr ctx (this ctx)
-	| TIdent "__js__", [{ eexpr = TConst (TString code) }] ->
-		spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n"))
-	| TIdent "__js__", { eexpr = TConst (TString code); epos = p } :: tl ->
-		Codegen.interpolate_code ctx.com code tl (spr ctx) (gen_expr ctx) p
-	| TIdent "__instanceof__",  [o;t] ->
-		spr ctx "(";
-		gen_value ctx o;
-		print ctx " instanceof ";
-		gen_value ctx t;
-		spr ctx ")";
-	| TIdent "__typeof__",  [o] ->
-		spr ctx "typeof(";
-		gen_value ctx o;
-		spr ctx ")";
-	| TIdent "__strict_eq__" , [x;y] ->
-		(* add extra parenthesis here because of operator precedence *)
-		spr ctx "((";
-		gen_value ctx x;
-		spr ctx ") === ";
-		gen_value ctx y;
-		spr ctx ")";
-	| TIdent "__strict_neq__" , [x;y] ->
-		(* add extra parenthesis here because of operator precedence *)
-		spr ctx "((";
-		gen_value ctx x;
-		spr ctx ") !== ";
-		gen_value ctx y;
-		spr ctx ")";
+	| TField (_, FStatic ({ cl_path = ["js"],"Syntax" }, { cf_name = meth })), args ->
+		gen_syntax ctx meth args e.epos
+	| TIdent "__new__", args ->
+		print_deprecation_message ctx.com "__new__ is deprecated, use js.Syntax.new_ instead" e.epos;
+		gen_syntax ctx "new_" args e.epos
+	| TIdent "__js__", args ->
+		(* TODO: add deprecation warning when we figure out what to do with purity here *)
+		gen_syntax ctx "code" args e.epos
+	| TIdent "__instanceof__",  args ->
+		print_deprecation_message ctx.com "__instanceof__ is deprecated, use js.Syntax.instanceof instead" e.epos;
+		gen_syntax ctx "instanceof" args e.epos
+	| TIdent "__typeof__",  args ->
+		print_deprecation_message ctx.com "__typeof__ is deprecated, use js.Syntax.typeof instead" e.epos;
+		gen_syntax ctx "typeof" args e.epos
+	| TIdent "__strict_eq__" , args ->
+		print_deprecation_message ctx.com "__strict_eq__ is deprecated, use js.Syntax.strictEq instead" e.epos;
+		gen_syntax ctx "strictEq" args e.epos
+	| TIdent "__strict_neq__" , args ->
+		print_deprecation_message ctx.com "__strict_neq__ is deprecated, use js.Syntax.strictNeq instead" e.epos;
+		gen_syntax ctx "strictNeq" args e.epos
 	| TIdent "__define_feature__", [_;e] ->
 		gen_expr ctx e
 	| TIdent "__feature__", { eexpr = TConst (TString f) } :: eif :: eelse ->
@@ -410,8 +409,6 @@ let rec gen_call ctx e el in_value =
 		else match eelse with
 			| [] -> ()
 			| e :: _ -> gen_value ctx e)
-	| TIdent "__rethrow__", [] ->
-		spr ctx "throw $hx_rethrow";
 	| TIdent "__resources__", [] ->
 		spr ctx "[";
 		concat ctx "," (fun (name,data) ->
@@ -436,14 +433,19 @@ let rec gen_call ctx e el in_value =
 			spr ctx "console.log(";
 			(match infos.eexpr with
 			| TObjectDecl (
-				("fileName" , { eexpr = (TConst (TString file)) }) ::
-				("lineNumber" , { eexpr = (TConst (TInt line)) }) :: _) ->
+				(("fileName",_,_) , { eexpr = (TConst (TString file)) }) ::
+				(("lineNumber",_,_) , { eexpr = (TConst (TInt line)) }) :: _) ->
 					print ctx "\"%s:%i:\"," file (Int32.to_int line)
 			| _ ->
 				());
 			gen_value ctx e;
 			spr ctx ")";
 		end
+	| TField (x,f), [] when field_name f = "iterator" && is_dynamic_iterator ctx e ->
+		add_feature ctx "use.$getIterator";
+		print ctx "$getIterator(";
+		gen_value ctx x;
+		print ctx ")";
 	| _ ->
 		gen_value ctx e;
 		spr ctx "(";
@@ -464,7 +466,7 @@ and add_objectdecl_parens e =
 	loop e
 
 and gen_expr ctx e =
-	Option.may (fun smap -> add_mapping smap false e) ctx.smap;
+	let clear_mapping = add_mapping ctx e in
 	(match e.eexpr with
 	| TConst c -> gen_constant ctx e.epos c
 	| TLocal v -> spr ctx (ident v.v_name)
@@ -490,6 +492,17 @@ and gen_expr ctx e =
 		print ctx "$iterator(";
 		gen_value ctx x;
 		print ctx ")";
+	(* Don't generate `$iterator(value)` for exprs like `value.iterator--` *)
+	| TUnop (op,flag,({eexpr = TField (x,f)} as fe)) when field_name f = "iterator" && is_dynamic_iterator ctx fe ->
+		(match flag with
+			| Prefix ->
+				spr ctx (Ast.s_unop op);
+				gen_value ctx x;
+				spr ctx ".iterator"
+			| Postfix ->
+				gen_value ctx x;
+				spr ctx ".iterator";
+				spr ctx (Ast.s_unop op))
 	| TField (x,FClosure (Some ({cl_path=[],"Array"},_), {cf_name="push"})) ->
 		(* see https://github.com/HaxeFoundation/haxe/issues/1997 *)
 		add_feature ctx "use.$arrayPush";
@@ -654,9 +667,9 @@ and gen_expr ctx e =
 		ctx.in_loop <- old_in_loop
 	| TObjectDecl fields ->
 		spr ctx "{ ";
-		concat ctx ", " (fun (f,e) -> (match e.eexpr with
-			| TMeta((Meta.QuotedField,_,_),e) -> print ctx "\"%s\" : " (Ast.s_escape f);
-			| _ -> print ctx "%s : " (anon_field f));
+		concat ctx ", " (fun ((f,_,qs),e) -> (match qs with
+			| DoubleQuotes -> print ctx "\"%s\" : " (Ast.s_escape f);
+			| NoQuotes -> print ctx "%s : " (anon_field f));
 			gen_value ctx e
 		) fields;
 		spr ctx "}";
@@ -685,110 +698,14 @@ and gen_expr ctx e =
 		newline ctx;
 		spr ctx "}";
 		ctx.in_loop <- old_in_loop
-	| TTry (e,catchs) ->
+	| TTry (etry,[(v,ecatch)]) ->
 		spr ctx "try ";
-		gen_expr ctx e;
-		let vname = (match catchs with [(v,_)] -> check_var_declaration v; v.v_name | _ ->
-			let id = ctx.id_counter in
-			ctx.id_counter <- ctx.id_counter + 1;
-			"$e" ^ string_of_int id
-		) in
-		print ctx " catch( %s ) {" vname;
-		let bend = open_block ctx in
-		let last = ref false in
-		let else_block = ref false in
-
-		if ctx.store_exception_stack then begin
-			newline ctx;
-			print ctx "%s.lastException = %s" (ctx.type_accessor (TClassDecl { null_class with cl_path = ["haxe"],"CallStack" })) vname
-		end;
-
-		if (has_feature ctx "js.Lib.rethrow") then begin
-			let has_rethrow (_,e) =
-				let rec loop e = match e.eexpr with
-				| TCall({eexpr = TIdent "__rethrow__"}, []) -> raise Exit
-				| _ -> Type.iter loop e
-				in
-				try (loop e; false) with Exit -> true
-			in
-			if List.exists has_rethrow catchs then begin
-				newline ctx;
-				print ctx "var $hx_rethrow = %s" vname;
-			end
-		end;
-
-		if (has_feature ctx "js.Boot.HaxeError") then begin
-			let catch_var_used =
-				try
-					List.iter (fun (v,e) ->
-						match follow v.v_type with
-						| TDynamic _ -> (* Dynamic catch - unrap if the catch value is used *)
-							let rec loop e = match e.eexpr with
-							| TLocal v2 when v2 == v -> raise Exit
-							| _ -> Type.iter loop e
-							in
-							loop e
-						| _ -> (* not a Dynamic catch - we need to unwrap the error for type-checking *)
-							raise Exit
-					) catchs;
-					false
-				with Exit ->
-					true
-			in
-			if catch_var_used then begin
-				newline ctx;
-				print ctx "if (%s instanceof %s) %s = %s.val" vname (ctx.type_accessor (TClassDecl { null_class with cl_path = ["js";"_Boot"],"HaxeError" })) vname vname;
-			end;
-		end;
-
-		List.iter (fun (v,e) ->
-			if !last then () else
-			let t = (match follow v.v_type with
-			| TEnum (e,_) -> Some (TEnumDecl e)
-			| TInst (c,_) -> Some (TClassDecl c)
-			| TAbstract (a,_) -> Some (TAbstractDecl a)
-			| TFun _
-			| TLazy _
-			| TType _
-			| TAnon _ ->
-				assert false
-			| TMono _
-			| TDynamic _ ->
-				None
-			) in
-			match t with
-			| None ->
-				last := true;
-				if !else_block then print ctx "{";
-				if vname <> v.v_name then begin
-					newline ctx;
-					print ctx "var %s = %s" v.v_name vname;
-				end;
-				gen_block_element ctx e;
-				if !else_block then begin
-					newline ctx;
-					print ctx "}";
-				end
-			| Some t ->
-				if not !else_block then newline ctx;
-				print ctx "if( %s.__instanceof(%s," (ctx.type_accessor (TClassDecl { null_class with cl_path = ["js"],"Boot" })) vname;
-				gen_value ctx (mk (TTypeExpr t) (mk_mono()) e.epos);
-				spr ctx ") ) {";
-				let bend = open_block ctx in
-				if vname <> v.v_name then begin
-					newline ctx;
-					print ctx "var %s = %s" v.v_name vname;
-				end;
-				gen_block_element ctx e;
-				bend();
-				newline ctx;
-				spr ctx "} else ";
-				else_block := true
-		) catchs;
-		if not !last then print ctx "throw(%s)" vname;
-		bend();
-		newline ctx;
-		spr ctx "}";
+		gen_expr ctx etry;
+		check_var_declaration v;
+		print ctx " catch( %s ) " v.v_name;
+		gen_expr ctx ecatch
+	| TTry _ ->
+		abort "Unhandled try/catch, please report" e.epos
 	| TSwitch (e,cases,def) ->
 		spr ctx "switch";
 		gen_value ctx e;
@@ -834,8 +751,7 @@ and gen_expr ctx e =
 	| TIdent s ->
 		spr ctx s
 	);
-	Option.may (fun smap -> smap.current_expr <- None) ctx.smap
-
+	clear_mapping ()
 
 and gen_block_element ?(after=false) ctx e =
 	match e.eexpr with
@@ -858,7 +774,7 @@ and gen_block_element ?(after=false) ctx e =
 		if after then newline ctx
 
 and gen_value ctx e =
-	Option.may (fun smap -> add_mapping smap false e) ctx.smap;
+	let clear_mapping = add_mapping ctx e in
 	let assign e =
 		mk (TBinop (Ast.OpAssign,
 			mk (TLocal (match ctx.in_value with None -> assert false | Some v -> v)) t_dynamic e.epos,
@@ -972,8 +888,71 @@ and gen_value ctx e =
 			List.map (fun (v,e) -> v, block (assign e)) catchs
 		)) e.etype e.epos);
 		v());
-	Option.may (fun smap -> smap.current_expr <- None) ctx.smap
+	clear_mapping ()
 
+and gen_syntax ctx meth args pos =
+	match meth, args with
+	| "new_", cl :: params ->
+		spr ctx "new ";
+		begin
+			match cl.eexpr with
+			| TConst (TString cl) ->
+				spr ctx cl
+			| _ ->
+				gen_value ctx cl
+		end;
+		spr ctx "(";
+		concat ctx "," (gen_value ctx) params;
+		spr ctx ")"
+	| "instanceof", [o;t] ->
+		spr ctx "(";
+		gen_value ctx o;
+		print ctx " instanceof ";
+		gen_value ctx t;
+		spr ctx ")"
+	| "typeof", [o] ->
+		spr ctx "typeof(";
+		gen_value ctx o;
+		spr ctx ")"
+	| "strictEq" , [x;y] ->
+		(* add extra parenthesis here because of operator precedence *)
+		spr ctx "((";
+		gen_value ctx x;
+		spr ctx ") === ";
+		gen_value ctx y;
+		spr ctx ")";
+	| "strictNeq" , [x;y] ->
+		(* add extra parenthesis here because of operator precedence *)
+		spr ctx "((";
+		gen_value ctx x;
+		spr ctx ") !== ";
+		gen_value ctx y;
+		spr ctx ")";
+	| "delete" , [o;f] ->
+		spr ctx "delete(";
+		gen_value ctx o;
+		spr ctx "[";
+		gen_value ctx f;
+		spr ctx "]";
+		spr ctx ")";
+	| "code", code :: args ->
+		let code, code_pos =
+			match code.eexpr with
+			| TConst (TString s) -> s, code.epos
+			| _ -> abort "The `code` argument for js.Syntax must be a string constant" code.epos
+		in
+		begin
+			match args with
+			| [] ->
+				if code = "this" then
+					spr ctx (this ctx)
+				else
+					spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n"))
+			| _ ->
+				Codegen.interpolate_code ctx.com code args (spr ctx) (gen_expr ctx) code_pos
+		end
+	| _ ->
+		abort (Printf.sprintf "Unknown js.Syntax method `%s` with %d arguments" meth (List.length args)) pos
 
 let generate_package_create ctx (p,_) =
 	let rec loop acc = function
@@ -1224,7 +1203,7 @@ let generate_enum ctx e =
 		print ctx "%s.__empty_constructs__ = [%s]" p (String.concat "," (List.map (fun s -> Printf.sprintf "%s.%s" p s) ctors_without_args));
 		newline ctx
 	end;
-	begin match Codegen.build_metadata ctx.com (TEnumDecl e) with
+	begin match Texpr.build_metadata ctx.com.basic (TEnumDecl e) with
 	| None -> ()
 	| Some e ->
 		print ctx "%s.__meta__ = " p;
@@ -1290,9 +1269,7 @@ let alloc_ctx com =
 	let smap =
 		if com.debug || Common.defined com Define.JsSourceMap then
 			Some {
-				source_last_line = 0;
-				source_last_col = 0;
-				source_last_file = 0;
+				source_last_pos = { file = 0; line = 0; col = 0};
 				print_comma = false;
 				output_last_col = 0;
 				output_current_col = 0;
@@ -1313,7 +1290,6 @@ let alloc_ctx com =
 		js_modern = not (Common.defined com Define.JsClassic);
 		js_flatten = not (Common.defined com Define.JsUnflatten);
 		es_version = (try int_of_string (Common.defined_value com Define.JsEs) with _ -> 0);
-		store_exception_stack = if Common.has_dce com then (Common.has_feature com "haxe.CallStack.exceptionStack") else List.exists (function TClassDecl { cl_path=["haxe"],"CallStack" } -> true | _ -> false) com.types;
 		statics = [];
 		inits = [];
 		current = null_class;
@@ -1516,6 +1492,10 @@ let generate com =
 		print ctx "function $iterator(o) { if( o instanceof Array ) return function() { return HxOverrides.iter(o); }; return typeof(o.iterator) == 'function' ? $bind(o,o.iterator) : o.iterator; }";
 		newline ctx;
 	end;
+	if has_feature ctx "use.$getIterator" then begin
+		print ctx "function $getIterator(o) { if( o instanceof Array ) return HxOverrides.iter(o); else return o.iterator(); }";
+		newline ctx;
+	end;
 	if has_feature ctx "use.$bind" then begin
 		print ctx "var $_, $fid = 0";
 		newline ctx;

+ 102 - 90
src/generators/genlua.ml

@@ -24,6 +24,7 @@ open Ast
 open Type
 open Common
 open ExtList
+open Error
 
 type pos = Globals.pos
 
@@ -74,7 +75,7 @@ let get_exposed ctx path meta = try
         (match args with
          | [ EConst (String s), _ ] -> [s]
          | [] -> [path]
-         | _ -> abort "Invalid @:expose parameters" pos)
+         | _ -> error "Invalid @:expose parameters" pos)
     with Not_found -> []
 
 let dot_path = Globals.s_type_path
@@ -158,7 +159,7 @@ let println ctx =
             newline ctx
         end)
 
-let unsupported p = abort "This expression cannot be compiled to Lua" p
+let unsupported p = error "This expression cannot be compiled to Lua" p
 
 let basename path =
     try
@@ -189,7 +190,7 @@ let fun_block ctx f p =
     let e = List.fold_left (fun e (a,c) ->
         match c with
         | None | Some TNull -> e
-        | Some c -> Type.concat (Codegen.set_default ctx.com a c p) e
+        | Some c -> Type.concat (Texpr.set_default ctx.com.basic a c p) e
     ) f.tf_expr f.tf_args in
     e
 
@@ -243,7 +244,7 @@ let index_of f l =
 (* create a __lua__ call *)
 let mk_lua_code com code args t pos =
     let lua_local = mk (TIdent "__lua__") t_dynamic pos in
-    let code_const = Codegen.ExprBuilder.make_string com code pos in
+    let code_const = Texpr.Builder.make_string com code pos in
     mk (TCall (lua_local, code_const :: args)) t pos
 
 (* create a multi-return boxing call for given expr *)
@@ -257,7 +258,7 @@ let mk_mr_box ctx e =
     add_feature ctx "use._hx_box_mr";
     add_feature ctx "use._hx_table";
     let code = Printf.sprintf "_hx_box_mr(_hx_table.pack({0}), {%s})" s_fields in
-    mk_lua_code ctx.com code [e] e.etype e.epos
+    mk_lua_code ctx.com.basic code [e] e.etype e.epos
 
 (* create a multi-return select call for given expr and field name *)
 let mk_mr_select com e ecall name =
@@ -337,44 +338,66 @@ let gen_constant ctx p = function
     | TThis -> spr ctx (this ctx)
     | TSuper -> assert false
 
-let rec gen_call ctx e el =
+
+let rec is_function_type t = match follow(t) with
+        | TFun _ -> true
+        | _ -> false
+
+and gen_argument ctx e = begin
+    match e.eexpr with
+    | TField (x,(FInstance (_,_,f) | FAnon(f)))  when (is_function_type e.etype) ->
+            add_feature ctx "use._hx_bind";
+            print ctx "_hx_bind(";
+            gen_value ctx x;
+            print ctx ",";
+            gen_value ctx x;
+            print ctx "%s)" (if Meta.has Meta.SelfCall f.cf_meta then "" else (field f.cf_name))
+    | _ ->
+        gen_value ctx e;
+end
+
+and gen_paren_arguments ctx el = begin
+    spr ctx "(";
+    concat ctx ", " (gen_argument ctx) el;
+    spr ctx ")";
+end
+
+and gen_call ctx e el =
     ctx.iife_assign <- true;
     (match e.eexpr , el with
      | TConst TSuper , params ->
          (match ctx.current.cl_super with
-          | None -> abort "Missing api.setCurrentClass" e.epos
+          | None -> error "Missing api.setCurrentClass" e.epos
           | Some (c,_) ->
               print ctx "%s.super(%s" (ctx.type_accessor (TClassDecl c)) (this ctx);
-              List.iter (fun p -> print ctx ","; gen_value ctx p) params;
+              List.iter (fun p -> print ctx ","; gen_argument ctx p) params;
               spr ctx ")";
          );
      | TField ({ eexpr = TConst TSuper },f) , params ->
          (match ctx.current.cl_super with
-          | None -> abort "Missing api.setCurrentClass" e.epos
+          | None -> error "Missing api.setCurrentClass" e.epos
           | Some (c,_) ->
               let name = field_name f in
               print ctx "%s.prototype%s(%s" (ctx.type_accessor (TClassDecl c)) (field name) (this ctx);
-              List.iter (fun p -> print ctx ","; gen_value ctx p) params;
+              List.iter (fun p -> print ctx ","; gen_argument ctx p) params;
               spr ctx ")";
          );
      | TCall (x,_) , el when (match x.eexpr with TIdent "__lua__" -> false | _ -> true) ->
          gen_paren ctx [e];
-         gen_paren ctx el;
+         gen_paren_arguments ctx el;
      | TIdent "__new__", { eexpr = TConst (TString cl) } :: params ->
-         print ctx "%s.new(" cl;
-         concat ctx "," (gen_value ctx) params;
-         spr ctx ")";
+         print ctx "%s.new" cl;
+         gen_paren_arguments ctx params;
      | TIdent "__new__", e :: params ->
          gen_value ctx e;
-         spr ctx ".new(";
-         concat ctx "," (gen_value ctx) params;
-         spr ctx ")";
+         spr ctx ".new";
+         gen_paren_arguments ctx params;
      | TIdent "__callself__", { eexpr = TConst (TString head) } :: { eexpr = TConst (TString tail) } :: el ->
          print ctx "%s:%s" head tail;
-         gen_paren ctx el;
+         gen_paren_arguments ctx el;
      | TIdent "__call__", { eexpr = TConst (TString code) } :: el ->
          spr ctx code;
-         gen_paren ctx el;
+         gen_paren_arguments ctx el;
      | TIdent "__lua_length__", [e]->
          spr ctx "#"; gen_value ctx e;
      | TIdent "__lua_table__", el ->
@@ -388,14 +411,14 @@ let rec gen_call ctx e el =
                   if List.length(arr) > 0 then incr count;
               | { eexpr = TObjectDecl fields } ->
                   if (!count > 0 && List.length(fields) > 0) then spr ctx ",";
-                  concat ctx ", " (fun (f,e) ->
+                  concat ctx ", " (fun ((f,_,_),e) ->
                       print ctx "%s = " (anon_field f);
                       gen_value ctx e
                   ) fields;
                   if List.length(fields) > 0 then incr count;
               | { eexpr = TConst(TNull)} -> ()
               | _ ->
-                  abort "__lua_table__ only accepts array or anonymous object arguments" e.epos;
+                  error "__lua_table__ only accepts array or anonymous object arguments" e.epos;
              )) el;
          spr ctx "})";
      | TIdent "__lua__", [{ eexpr = TConst (TString code) }] ->
@@ -457,7 +480,7 @@ let rec gen_call ctx e el =
          gen_value ctx e;
          print ctx ",'%s'" (field_name ef);
          spr ctx ")(";
-         concat ctx "," (gen_value ctx) (e::el);
+         concat ctx "," (gen_argument ctx) (e::el);
          spr ctx ")";
      | TField (e, ((FInstance _ | FAnon _ | FDynamic _) as ef)), el ->
          let s = (field_name ef) in
@@ -467,7 +490,7 @@ let rec gen_call ctx e el =
              gen_value ctx e;
              print ctx ",\"%s\"" (field_name ef);
              if List.length(el) > 0 then spr ctx ",";
-             concat ctx "," (gen_value ctx) el;
+             concat ctx "," (gen_argument ctx) el;
              spr ctx ")";
          end else begin
              gen_value ctx e;
@@ -475,11 +498,11 @@ let rec gen_call ctx e el =
                  print ctx ".%s" (field_name ef)
              else
                  print ctx ":%s" (field_name ef);
-             gen_paren ctx el;
+             gen_paren_arguments ctx el;
          end;
      | _ ->
          gen_value ctx e;
-         gen_paren ctx el);
+         gen_paren_arguments ctx el);
     ctx.iife_assign <- false;
 
 and has_continue e =
@@ -562,6 +585,23 @@ and is_possible_string_field e field_name=
             false
 
 
+and ttype_multireturn t = match t with
+    | TInst (c,_) ->
+            Meta.has Meta.MultiReturn c.cl_meta
+    | TType (c,_) ->
+            Meta.has Meta.MultiReturn c.t_meta
+    | _ ->
+            false
+and check_multireturn_param ctx t pos =
+   match t with
+         TAbstract(_,p) | TInst(_,p) ->
+            if List.exists ttype_multireturn p then
+                error "MultiReturns must not be type parameters" pos
+            else
+                ()
+        | _ ->
+                ();
+
 and gen_expr ?(local=true) ctx e = begin
     match e.eexpr with
       TConst c ->
@@ -623,7 +663,7 @@ and gen_expr ?(local=true) ctx e = begin
         spr ctx "(function(x) return x.";
         print ctx "%s" (field_name ef);
         spr ctx " end )({";
-        concat ctx ", " (fun (f,e) -> print ctx "%s = " (anon_field f); gen_value ctx e) fields;
+        concat ctx ", " (fun ((f,_,_),e) -> print ctx "%s = " (anon_field f); gen_value ctx e) fields;
         spr ctx "})";
     | TField ({eexpr = TLocal v}, f) when Meta.has Meta.MultiReturn v.v_meta ->
         (* field of a multireturn local var is actually just a local var *)
@@ -860,9 +900,9 @@ and gen_expr ?(local=true) ctx e = begin
         ctx.separator <- true
     | TObjectDecl fields ->
         spr ctx "_hx_o({__fields__={";
-        concat ctx "," (fun (f,e) -> print ctx "%s=" (anon_field f); spr ctx "true") fields;
+        concat ctx "," (fun ((f,_,_),e) -> print ctx "%s=" (anon_field f); spr ctx "true") fields;
         spr ctx "},";
-        concat ctx "," (fun (f,e) -> print ctx "%s=" (anon_field f); gen_anon_value ctx e) fields;
+        concat ctx "," (fun ((f,_,_),e) -> print ctx "%s=" (anon_field f); gen_anon_value ctx e) fields;
         spr ctx "})";
         ctx.separator <- true
     | TFor (v,it,e2) ->
@@ -1070,7 +1110,7 @@ and gen_anon_value ctx e =
         ctx.in_value <- fst old;
         ctx.in_loop <- snd old;
         ctx.separator <- true
-    | _ when (is_function_type ctx e.etype) && not (is_const_null e) ->
+    | _ when (is_function_type e.etype) && not (is_const_null e) ->
         spr ctx "function(_,...) return ";
         gen_value ctx e;
         spr ctx "(...) end";
@@ -1214,11 +1254,6 @@ and gen_value ctx e =
                                         )) e.etype e.epos);
         v()
 
-and is_function_type ctx t =
-    match follow(t) with
-    | TFun _ -> true
-    | _ -> false;
-
 and gen_tbinop ctx op e1 e2 =
     (match op, e1.eexpr, e2.eexpr with
      | Ast.OpAssign, TField(e3, FInstance _), TFunction f ->
@@ -1263,7 +1298,7 @@ and gen_tbinop ctx op e1 e2 =
               spr ctx "_hx_funcToField(";
               gen_value ctx e2;
               spr ctx ")";
-          | TField(_, FInstance _ ), TLocal t  when (is_function_type ctx t.v_type)   ->
+          | TField(_, FInstance _ ), TLocal t  when (is_function_type t.v_type)   ->
               gen_value ctx e1;
               print ctx " %s " (Ast.s_binop op);
               add_feature ctx "use._hx_funcToField";
@@ -1393,7 +1428,7 @@ and gen_return ctx e eo =
          spr ctx "do return end"
      | Some e ->
          (match e.eexpr with
-          | TField (e2, ((FClosure (_, tcf) | FAnon tcf |FInstance (_,_,tcf)))) when is_function_type ctx tcf.cf_type ->
+          | TField (e2, ((FClosure (_, tcf) | FAnon tcf |FInstance (_,_,tcf)))) when (is_function_type tcf.cf_type) ->
               (* See issue #6259 *)
               add_feature ctx "use._hx_bind";
               spr ctx "do return ";
@@ -1436,40 +1471,20 @@ let check_multireturn ctx c =
     match c with
     | _ when Meta.has Meta.MultiReturn c.cl_meta ->
         if not c.cl_extern then
-            abort "MultiReturns must be externs" c.cl_pos
+            error "MultiReturns must be externs" c.cl_pos
         else if List.length c.cl_ordered_statics > 0 then
-            abort "MultiReturns must not contain static fields" c.cl_pos
+            error "MultiReturns must not contain static fields" c.cl_pos
         else if (List.exists (fun cf -> match cf.cf_kind with Method _ -> true | _-> false) c.cl_ordered_fields) then
-            abort "MultiReturns must not contain methods" c.cl_pos;
+            error "MultiReturns must not contain methods" c.cl_pos;
     | {cl_super = Some(csup,_)} when Meta.has Meta.MultiReturn csup.cl_meta ->
-        abort "Cannot extend a MultiReturn" c.cl_pos
+        error "Cannot extend a MultiReturn" c.cl_pos
     | _ -> ()
 
 
-let generate_package_create ctx (p,_) =
-    let rec loop acc = function
-        | [] -> ()
-        | p :: l when Hashtbl.mem ctx.packages (p :: acc) -> loop (p :: acc) l
-        | p :: l ->
-            Hashtbl.add ctx.packages (p :: acc) ();
-            (match acc with
-             | [] -> print ctx "local %s = {}" p
-             | _ ->
-                 let p = String.concat "." (List.rev acc) ^ (field p) in
-                 print ctx "%s = {}" p
-            );
-            ctx.separator <- true;
-            newline ctx;
-            loop (p :: acc) l
-    in
-    match p with
-    | [] -> print ctx "local "
-    | _ -> loop [] p
-
 let check_field_name c f =
     match f.cf_name with
     | "prototype" | "__proto__" | "constructor" ->
-        abort ("The field name '" ^ f.cf_name ^ "'  is not allowed in Lua") (match f.cf_expr with None -> c.cl_pos | Some e -> e.epos);
+        error ("The field name '" ^ f.cf_name ^ "'  is not allowed in Lua") (match f.cf_expr with None -> c.cl_pos | Some e -> e.epos);
     | _ -> ()
 
 (* convert a.b.c to ["a"]["b"]["c"] *)
@@ -1500,11 +1515,11 @@ let gen_class_static_field ctx c f =
 
 let gen_class_field ctx c f =
     let p = s_path ctx c.cl_path in
-    print ctx "%s.prototype." p;
     check_field_name c f;
+    print ctx "%s.prototype%s" p (field f.cf_name);
     match f.cf_expr with
     | None ->
-        println ctx "%s = nil;" f.cf_name;
+        println ctx "= nil;"
     | Some e ->
         ctx.id_counter <- 0;
         (match e.eexpr with
@@ -1512,7 +1527,7 @@ let gen_class_field ctx c f =
              let old = ctx.in_value, ctx.in_loop in
              ctx.in_value <- None;
              ctx.in_loop <- false;
-             print ctx "%s = function" f.cf_name;
+             print ctx " = function";
              print ctx "(%s) " (String.concat "," ("self" :: List.map ident (List.map arg_name f2.tf_args)));
              let fblock = fun_block ctx f2 e.epos in
              (match fblock.eexpr with
@@ -1557,7 +1572,7 @@ let generate_class ctx c =
     ctx.current <- c;
     ctx.id_counter <- 0;
     (match c.cl_path with
-     | [],"Function" -> abort "This class redefines a native one" c.cl_pos
+     | [],"Function" -> error "This class redefines a native one" c.cl_pos
      | _ -> ());
     let p = s_path ctx c.cl_path in
     let hxClasses = has_feature ctx "Type.resolveClass" in
@@ -1732,7 +1747,7 @@ let generate_static ctx (c,f,e) =
 let generate_enumMeta_fields ctx = function
     | TEnumDecl e -> begin
             let p = s_path ctx e.e_path in
-            match Codegen.build_metadata ctx.com (TEnumDecl e) with
+            match Texpr.build_metadata ctx.com.basic (TEnumDecl e) with
             | None -> ()
             | Some e ->
                 print ctx "%s.__meta__ = " p;
@@ -1745,15 +1760,13 @@ let generate_require ctx path meta =
     let _, args, mp = Meta.get Meta.LuaRequire meta in
     let p = (s_path ctx path) in
 
-    (* generate_package_create ctx path; *)
-
     (match args with
      | [(EConst(String(module_name)),_)] ->
          print ctx "%s = _G.require(\"%s\")" p module_name
      | [(EConst(String(module_name)),_) ; (EConst(String(object_path)),_)] ->
          print ctx "%s = _G.require(\"%s\").%s" p module_name object_path
      | _ ->
-         abort "Unsupported @:luaRequire format" mp);
+         error "Unsupported @:luaRequire format" mp);
 
     newline ctx
 
@@ -1768,13 +1781,9 @@ let generate_type ctx = function
         if p = "Std" && c.cl_ordered_statics = [] then
             ()
         else if (not c.cl_extern) && Meta.has Meta.LuaDotMethod c.cl_meta then
-            abort "LuaDotMethod is valid for externs only" c.cl_pos
+            error "LuaDotMethod is valid for externs only" c.cl_pos
         else if not c.cl_extern then
-            generate_class ctx c
-        else if Meta.has Meta.InitPackage c.cl_meta then
-            (match c.cl_path with
-             | ([],_) -> ()
-             | _ -> generate_package_create ctx c.cl_path);
+            generate_class ctx c;
         check_multireturn ctx c;
     | TEnumDecl e ->
         if not e.e_extern then generate_enum ctx e
@@ -1785,8 +1794,9 @@ let generate_type_forward ctx = function
     | TClassDecl c ->
         if not c.cl_extern then
             begin
-                generate_package_create ctx c.cl_path;
                 let p = s_path ctx c.cl_path in
+                let l,c = c.cl_path in
+                if List.length(l) == 0 then spr ctx "local ";
                 println ctx "%s = _hx_e()" p
             end
         else if Meta.has Meta.LuaRequire c.cl_meta && is_directly_used ctx.com c.cl_meta then
@@ -1795,8 +1805,9 @@ let generate_type_forward ctx = function
         if Meta.has Meta.LuaRequire e.e_meta && is_directly_used ctx.com e.e_meta then
             generate_require ctx e.e_path e.e_meta;
     | TEnumDecl e ->
-        generate_package_create ctx e.e_path;
         let p = s_path ctx e.e_path in
+        let l,c = e.e_path in
+        if List.length(l) == 0 then spr ctx "local ";
         println ctx "%s = _hx_e()" p;
     | TTypeDecl _ | TAbstractDecl _ -> ()
 
@@ -1821,7 +1832,7 @@ let alloc_ctx com =
         found_expose = false;
         lua_jit = Common.defined com Define.LuaJit;
         lua_ver = try
-                float_of_string (PMap.find "lua_ver" com.defines)
+                float_of_string (PMap.find "lua_ver" com.defines.Define.values)
             with | Not_found -> 5.2;
     } in
     ctx.type_accessor <- (fun t ->
@@ -1838,19 +1849,20 @@ let alloc_ctx com =
 let transform_multireturn ctx = function
     | TClassDecl c ->
         let transform_field f =
+            check_multireturn_param ctx f.cf_type f.cf_pos;
             match f.cf_expr with
             | Some e ->
+                let is_multireturn t =
+                    match follow t with
+                    | TInst (c, _) when Meta.has Meta.MultiReturn c.cl_meta -> true
+                    | _ -> false
+                in
                 let rec loop e =
-                    let is_multireturn t =
-                        match follow t with
-                        | TInst (c, _) when Meta.has Meta.MultiReturn c.cl_meta -> true
-                        | _ -> false
-                    in
                     match e.eexpr with
-     (*
-						if we found a var declaration initialized by a multi-return call, mark it with @:multiReturn meta,
-						so it will later be generated as multiple locals unpacking the value
-					*)
+                    (*
+                        if we found a var declaration initialized by a multi-return call, mark it with @:multiReturn meta,
+                        so it will later be generated as multiple locals unpacking the value
+                    *)
                     | TVar (v, Some ({ eexpr = TCall _ } as ecall)) when is_multireturn v.v_type ->
                         v.v_meta <- (Meta.MultiReturn,[],v.v_pos) :: v.v_meta;
                         let ecall = Type.map_expr loop ecall in
@@ -1859,7 +1871,7 @@ let transform_multireturn ctx = function
                     (* if we found a field access for the multi-return call, generate select call *)
                     | TField ({ eexpr = TCall _ } as ecall, f) when is_multireturn ecall.etype ->
                         let ecall = Type.map_expr loop ecall in
-                        mk_mr_select ctx.com e ecall (field_name f)
+                        mk_mr_select ctx.com.basic e ecall (field_name f)
 
                     (* if we found a multi-return call used as a value, box it *)
                     | TCall _ when is_multireturn e.etype ->
@@ -1881,7 +1893,7 @@ let transform_multireturn ctx = function
                         e
                     | TReturn Some(e2) ->
                         if is_multireturn e2.etype then
-                            failwith "You cannot return a multireturn type from a haxe function"
+                            error "You cannot return a multireturn type from a haxe function" e2.epos
                         else
                             Type.map_expr loop e;
      (*
@@ -2035,7 +2047,7 @@ let generate com =
     List.iter (generate_static ctx) (List.rev ctx.statics);
     (* Localize init variables inside a do-block *)
     (* Note: __init__ logic can modify static variables. *)
-    (* Generate statics *)
+    (* Generate static inits *)
     List.iter (gen_block_element ctx) (List.rev ctx.inits);
     b();
     newline ctx;

+ 4 - 4
src/generators/genneko.ml

@@ -260,7 +260,7 @@ and gen_expr ctx e =
 		gen_expr ctx e
 	| TObjectDecl fl ->
 		let hasToString = ref false in
-		let fl = List.map (fun (f,e) -> if f = "toString" then hasToString := (match follow e.etype with TFun ([],_) -> true | _ -> false); f , gen_expr ctx e) fl in
+		let fl = List.map (fun ((f,_,_),e) -> if f = "toString" then hasToString := (match follow e.etype with TFun ([],_) -> true | _ -> false); f , gen_expr ctx e) fl in
 		(EObject (if !hasToString then ("__string",ident p "@default__string") :: fl else fl),p)
 	| TArrayDecl el ->
 		call p (field p (ident p "Array") "new1") [array p (List.map (gen_expr ctx) el); int p (List.length el)]
@@ -296,7 +296,7 @@ and gen_expr ctx e =
 			in
 			match c with
 			| None | Some TNull -> acc
-			| Some c ->	gen_expr ctx (Codegen.set_default ctx.com a c e.epos) :: acc
+			| Some c ->	gen_expr ctx (Texpr.set_default ctx.com.basic a c e.epos) :: acc
 		) [] f.tf_args in
 		let e = gen_expr ctx f.tf_expr in
 		let e = (match inits with [] -> e | _ -> EBlock (List.rev (e :: inits)),p) in
@@ -630,7 +630,7 @@ let gen_name ctx acc t =
 		let setname = (EBinop ("=",field p path "__ename__",arr),p) in
 		let arr = call p (field p (ident p "Array") "new1") [array p (List.map (fun n -> gen_constant ctx e.e_pos (TString n)) e.e_names); int p (List.length e.e_names)] in
 		let setconstrs = (EBinop ("=", field p path "__constructs__", arr),p) in
-		let meta = (match Codegen.build_metadata ctx.com (TEnumDecl e) with
+		let meta = (match Texpr.build_metadata ctx.com.basic (TEnumDecl e) with
 			| None -> []
 			| Some e -> [EBinop ("=",field p path "__meta__", gen_expr ctx e),p]
 		) in
@@ -794,7 +794,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;
+			Path.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;

+ 0 - 2437
src/generators/genphp.ml

@@ -1,2437 +0,0 @@
-(*
-	The Haxe Compiler
-	Copyright (C) 2005-2017  Haxe Foundation
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *)
-
-open Ast
-open Type
-open Common
-open Codegen
-
-type method_name = {
-	mutable mpath : path;
-	mutable mname : string;
-}
-
-type inline_method = {
-	iname       : string;
-	iindex      : int;
-	iexpr       : texpr;
-	ihasthis    : bool;
-	iin_block   : bool;
-	iarguments  : string list;
-	ilocals     : (string,string) PMap.t;
-	iinv_locals : (string,string) PMap.t;
-}
-
-type context = {
-	com : Common.context;
-	ch : out_channel;
-	buf : Buffer.t;
-	path : path;
-	stack : Codegen.stack_context;
-	mutable nested_loops : int;
-	mutable inline_index : int;
-	mutable curclass : tclass;
-	mutable curmethod : string;
-	mutable tabs : string;
-	mutable in_value : string option;
-	mutable in_loop : bool;
-	mutable in_block : bool;
-	mutable in_instance_method : bool;
-	mutable imports : (string,string list list) Hashtbl.t;
-	mutable extern_required_paths : (string list * string) list;
-	mutable extern_classes_with_init : path list;
-	mutable locals : (string,string) PMap.t;
-	mutable inv_locals : (string,string) PMap.t;
-	mutable local_types : t list;
-	mutable inits : texpr list;
-	mutable constructor_block : bool;
-	mutable all_dynamic_methods: method_name list;
-	mutable dynamic_methods: tclass_field list;
-	mutable is_call : bool;
-	mutable cwd : string;
-	mutable inline_methods : inline_method list;
-	mutable lib_path : string;
-}
-
-let follow = Abstract.follow_with_abstracts
-
-(**
-	Check if specified expression is of `Float` type
-*)
-let is_float expr = match follow expr.etype with TAbstract ({ a_path = ([], "Float") }, _) -> true | _ -> false
-
-(**
-	If `expr` is a TCast or TMeta, then returns underlying expression (recursively bypassing nested casts).
-	Otherwise returns `expr` as is.
-*)
-let rec reveal_expr expr =
-	match expr.eexpr with
-		| TCast (e, _) -> reveal_expr e
-		| TMeta (_, e) -> reveal_expr e
-		| _ -> expr
-
-let join_class_path path separator =
-	let result = match fst path, snd path with
-	| [], s -> s
-	| el, s -> String.concat separator el ^ separator ^ s in
-	if (String.contains result '+') then begin
-		let idx = String.index result '+' in
-		(String.sub result 0 idx) ^ (String.sub result (idx+1) ((String.length result) - idx -1 ) )
-	end else
-		result;;
-
-(*  Get a string to represent a type.
-	 The "suffix" will be nothing or "_obj", depending if we want the name of the
-	 pointer class or the pointee (_obj class *)
-let rec class_string klass suffix params =
-	(match klass.cl_path with
-	(* Array class *)
-	|  ([],"Array") -> (snd klass.cl_path) ^ suffix ^ "<" ^ (String.concat ","
-					 (List.map type_string  params) ) ^ " >"
-	| _ when (match klass.cl_kind with KTypeParameter _ -> true | _ -> false) -> "Dynamic"
-	|  ([],"#Int") -> "/* # */int"
-	|  (["haxe";"io"],"Unsigned_char__") -> "unsigned char"
-	|  ([],"Class") -> "Class"
-	|  ([],"Null") -> (match params with
-			| [t] ->
-				(match follow t with
-				| TInst ({ cl_path = [],"Int" },_)
-				| TInst ({ cl_path = [],"Float" },_)
-				| TEnum ({ e_path = [],"Bool" },_) -> "Dynamic"
-				| _ -> "/*NULL*/" ^ (type_string t) )
-			| _ -> assert false);
-	(* Normal class *)
-	| _ -> (join_class_path klass.cl_path "::") ^ suffix
-	)
-and type_string_suff suffix haxe_type =
-	(match haxe_type with
-	| TMono r -> (match !r with None -> "Dynamic" | Some t -> type_string_suff suffix t)
-	| TAbstract ({ a_path = [],"Int" },[]) -> "int"
-	| TAbstract ({ a_path = [],"Float" },[]) -> "double"
-	| TAbstract ({ a_path = [],"Bool" },[]) -> "bool"
-	| TAbstract ({ a_path = [],"Void" },[]) -> "Void"
-	| TAbstract ({ a_path = [],"Null"},[t]) ->
-		(match follow t with
-		| TInst ({ cl_path = [],"Int" },_)
-		| TInst ({ cl_path = [],"Float" },_)
-		| TEnum ({ e_path = [],"Bool" },_) -> "Dynamic"
-		| _ -> type_string_suff suffix t)
-	| 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
-	| TType (type_def,params) ->
-		(match type_def.t_path with
-		| [] , "Array" ->
-			(match params with
-			| [t] -> "Array<" ^ (type_string (follow t) ) ^ " >"
-			| _ -> assert false)
-		| _ ->  type_string_suff suffix (apply_params type_def.t_params params type_def.t_type)
-		)
-	| TFun (args,haxe_type) -> "Dynamic"
-	| TAnon anon -> "Dynamic"
-	| TDynamic haxe_type -> "Dynamic"
-	| TLazy func -> type_string_suff suffix ((!func)())
-	)
-and type_string haxe_type =
-	type_string_suff "" haxe_type;;
-
-let debug_expression expression type_too =
-	"/* " ^ Type.s_expr_kind expression ^ (if (type_too) then " = " ^ (type_string (follow expression.etype)) else "") ^ " */";;
-
-let rec register_extern_required_path ctx path =
-	if (List.exists(fun p -> p = path) ctx.extern_classes_with_init) && not (List.exists(fun p -> p = path) ctx.extern_required_paths) then
-		ctx.extern_required_paths <- path :: ctx.extern_required_paths
-
-let s_expr_expr = Type.s_expr_kind
-
-let s_expr_name e =
-	s_type (print_context()) (follow e.etype)
-
-let s_type_name t =
-	s_type (print_context()) t
-
-
-
-and start_with s test =
-	let len = String.length test in
-	(String.length s > len && String.sub s 0 len = test)
-
-let rec is_uncertain_type t =
-	match follow t with
-	| TInst (c, _) -> c.cl_interface
-	| TMono _ -> true
-	| TAnon a ->
-	  (match !(a.a_status) with
-	  | Statics _
-	  | EnumStatics _ -> false
-	  | _ -> true)
-	| TDynamic _ -> true
-	| _ -> false
-
-let is_uncertain_expr e =
-	is_uncertain_type e.etype
-
-let rec is_anonym_type t =
-	match follow t with
-	| TAnon a ->
-	  (match !(a.a_status) with
-	  | Statics _
-	  | EnumStatics _ -> false
-	  | _ -> true)
-	| TDynamic _ -> true
-	| _ -> false
-
-let is_anonym_expr e = is_anonym_type e.etype
-
-let rec is_unknown_type t =
-	match follow t with
-	| TMono r ->
-		(match !r with
-		| None -> true
-		| Some t -> is_unknown_type t)
-	| _ -> false
-
-let is_unknown_expr e =	is_unknown_type e.etype
-
-let rec is_string_type t =
-	match follow t with
-	| TInst ({cl_path = ([], "String")}, _) -> true
-	| TAnon a ->
-	   (match !(a.a_status) with
-	   | Statics ({cl_path = ([], "String")}) -> true
-	   | _ -> false)
-	| TAbstract (a,pl) -> is_string_type (Abstract.get_underlying_type a pl)
-	| _ -> false
-
-let is_string_expr e = is_string_type e.etype
-
-let to_string ctx e =
-	let f = mk (TIdent "__call__") t_dynamic e.epos in
-	mk (TCall (f, [ ExprBuilder.make_string ctx.com "_hx_string_rec" e.epos; e; ExprBuilder.make_string ctx.com "" e.epos])) ctx.com.basic.tstring e.epos
-
-let as_string_expr ctx e =
-	match e.eexpr with
-	| TConst (TNull) ->
-		to_string ctx e
-	| _ when not (is_string_expr e) ->
-		to_string ctx e
-	| _ -> e
-(* for known String type that could have null value *)
-let to_string_null ctx e =
-	let f = mk (TIdent "__call__") t_dynamic e.epos in
-	mk (TCall (f, [ ExprBuilder.make_string ctx.com "_hx_string_or_null" e.epos; e])) ctx.com.basic.tstring e.epos
-
-
-let as_string_expr ctx e =	match e.eexpr with
-	| TConst (TNull) ->  to_string ctx e
-	| TConst (TString s) -> e
-	| TBinop (op,_,_) when (is_string_expr e)-> e
-	| TCall ({eexpr = TField({eexpr = TTypeExpr(TClassDecl {cl_path = ([],"Std")})},FStatic(c,f) )}, [_]) when (f.cf_name="string") -> e
-	| TCall ({eexpr = TLocal _}, [{eexpr = TConst (TString ("_hx_string_rec" | "_hx_str_or_null"))}]) -> e
-	| _ when not (is_string_expr e) -> to_string ctx e
-	| _ -> to_string_null ctx e
-
-let spr ctx s = Buffer.add_string ctx.buf s
-let print ctx = Printf.kprintf (fun s -> Buffer.add_string ctx.buf s)
-
-(*--php-prefix - added by skial bainn*)
-let prefix_class com name =
-	match com.php_prefix with
-	| Some prefix_class (* when not (String.length name <= 2 || String.sub name 0 2 = "__") *) ->
-		prefix_class ^ name
-	| _ ->
-		name
-
-let prefix_init_replace com code =
-	let r = Str.regexp "php_Boot" in
-	Str.global_replace r ("php_" ^ (prefix_class com "Boot")) code
-
-let s_path ctx path isextern p =
-	if isextern then begin
-		register_extern_required_path ctx path;
-		snd path
-	end else begin
-		(match path with
-		(*--php-prefix*)
-		| ([],"List")			-> (prefix_class ctx.com "HList")
-		(*--php-prefix*)
-		| ([],name)				-> (prefix_class ctx.com name)
-		| (pack,name) ->
-			(try
-				(match Hashtbl.find ctx.imports name with
-				| [p] when p = pack ->
-					()
-				| packs ->
-					if not (List.mem pack packs) then Hashtbl.replace ctx.imports name (pack :: packs))
-			with Not_found ->
-				Hashtbl.add ctx.imports name [pack]);
-			(*--php-prefix*)
-			String.concat "_" pack ^ "_" ^ (prefix_class ctx.com name))
-	end
-
-let s_path_haxe path =
-	match fst path, snd path with
-	| [], s -> s
-	| el, s -> String.concat "." el ^ "." ^ s
-
-let escape_bin s =
-	let b = Buffer.create 0 in
-	for i = 0 to String.length s - 1 do
-		match Char.code (String.unsafe_get s i) with
-		| c when c = Char.code('\\') || c = Char.code('"') || c = Char.code('$') ->
-			Buffer.add_string b "\\";
-			Buffer.add_char b (Char.chr c)
-		| c when c < 32 ->
-			Buffer.add_string b (Printf.sprintf "\\x%.2X" c)
-		| c ->
-			Buffer.add_char b (Char.chr c)
-	done;
-	Buffer.contents b
-
-(*
-haxe reserved words that match php ones: break, case, class, continue, default, do, else, extends, for, function, if, new, return, static, switch, var, while, interface, implements, public, private, try, catch, throw
- *)
-(* PHP only (for future use): cfunction, old_function *)
-let is_keyword n =
-	match String.lowercase n with
-	| "and" | "or" | "xor" | "__file__" | "exception" | "__line__" | "array"
-	| "as" | "const" | "declare" | "die" | "echo"| "elseif" | "empty"
-	| "enddeclare" | "endfor" | "endforeach" | "endif" | "endswitch"
-	| "endwhile" | "eval" | "exit" | "foreach"| "global" | "include"
-	| "include_once" | "isset" | "list" | "namespace" | "print" | "require" | "require_once"
-	| "unset" | "use" | "__function__" | "__class__" | "__method__" | "final"
-	| "php_user_filter" | "protected" | "abstract" | "__set" | "__get" | "__call"
-	| "clone" | "instanceof" | "break" | "case" | "class" | "continue" | "default"
-	| "do" | "else" | "extends" | "for" | "function" | "if" | "new" | "return"
-	| "static" | "switch" | "var" | "while" | "interface" | "implements" | "public"
-	| "private" | "try" | "catch" | "throw" | "goto" | "yield"
-		-> true
-	| _ -> false
-
-let s_ident n =
-	let suf = "h" in
-	if (is_keyword n) then (suf ^ n) else n
-
-let s_ident_field n =
-	if (is_keyword n) then ("{\"" ^ (escape_bin n) ^ "\"}") else n
-
-let s_ident_local n =
-	let suf = "h" in
-	match String.lowercase n with
-	| "globals" | "_server" | "_get" | "_post" | "_cookie" | "_files"
-	| "_env" | "_request" | "_session" -> suf ^ n
-	| _ -> n
-
-let create_directory com ldir =
- 	let atm_path = ref com.file in
- 	if not (Sys.file_exists com.file) then (Unix.mkdir com.file 0o755);
- 	(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 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
-
-let stack_init com use_add =
-	Codegen.stack_context_init com "GLOBALS['%s']" "GLOBALS['%e']" "__hx__spos" "tmp" use_add Globals.null_pos
-
-let init com cwd path def_type =
-	let rec create acc = function
-		| [] -> ()
-		| d :: l ->
-			let pdir = String.concat "/" (List.rev (d :: acc)) in
-			if not (Sys.file_exists pdir) then Unix.mkdir pdir 0o755;
-			create (d :: acc) l
-	in
-	let dir = if cwd <> "" then com.file :: (cwd :: fst path) else com.file :: fst path; in
-	create [] dir;
-	let filename path =
-		prefix_class com (match path with
-		| [], "List" -> "HList";
-		| _, s -> s) in
-	(*--php-prefix*)
-	let ch = open_out (String.concat "/" dir ^ "/" ^ (filename path) ^ (if def_type = 0 then ".class" else if def_type = 1 then ".enum"  else if def_type = 2 then ".interface" else ".extern") ^ ".php") in
-	let imports = Hashtbl.create 0 in
-	Hashtbl.add imports (snd path) [fst path];
-	let ctx = {
-		com = com;
-		stack = stack_init com false;
-		tabs = "";
-		ch = ch;
-		path = path;
-		buf = Buffer.create (1 lsl 14);
-		in_value = None;
-		in_loop = false;
-		in_instance_method = false;
-		imports = imports;
-		extern_required_paths = [];
-		extern_classes_with_init = [];
-		curclass = null_class;
-		curmethod = "";
-		locals = PMap.empty;
-		inv_locals = PMap.empty;
-		local_types = [];
-		inits = [];
-		constructor_block = false;
-		dynamic_methods = [];
-		all_dynamic_methods = [];
-		is_call = false;
-		cwd = cwd;
-		inline_methods = [];
-		nested_loops = 0;
-		inline_index = 0;
-		in_block = false;
-		lib_path = match com.php_lib with None -> "lib" | Some s -> s;
-	} in
-	Codegen.map_source_header com (fun s -> print ctx "// %s\n" s);
-	ctx
-
-let unsupported msg p = abort ("This expression cannot be generated to PHP: " ^ msg) p
-
-let newline ctx =
-	match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with
-	| '{' | ':' | ' '
-	| '}' when Buffer.nth ctx.buf (Buffer.length ctx.buf - 2) != '"' ->
-		print ctx "\n%s" ctx.tabs
-	| _ ->
-		print ctx ";\n%s" ctx.tabs
-
-let rec concat ctx s f = function
-	| [] -> ()
-	| [x] -> f x
-	| x :: l ->
-		f x;
-		spr ctx s;
-		concat ctx s f l
-
-let open_block ctx =
-	let oldt = ctx.tabs in
-	ctx.tabs <- "\t" ^ ctx.tabs;
-	(fun() -> ctx.tabs <- oldt)
-
-let parent e =
-	match e.eexpr with
-	| TParenthesis _ -> e
-	| _ -> mk (TParenthesis e) e.etype e.epos
-
-let inc_extern_path ctx path =
-	let rec slashes n =
-		if n = 0 then "" else ("../" ^ slashes (n-1))
-	in
-	let pre = if ctx.cwd = "" then ctx.lib_path ^ "/" else "" in
-	match path with
-		| ([],name) ->
-		pre ^ (slashes (List.length (fst ctx.path))) ^ (prefix_class ctx.com name) ^ ".extern.php"
-		| (pack,name) ->
-		pre ^ (slashes (List.length (fst ctx.path))) ^ String.concat "/" pack ^ "/" ^ (prefix_class ctx.com name) ^ ".extern.php"
-
-let close ctx =
-	output_string ctx.ch "<?php\n";
-	List.iter (fun path ->
-		if path <> ctx.path then output_string ctx.ch ("require_once dirname(__FILE__).'/" ^ (inc_extern_path ctx path) ^ "';\n");
-	) (List.rev ctx.extern_required_paths);
-	output_string ctx.ch "\n";
-	output_string ctx.ch (Buffer.contents ctx.buf);
-	close_out ctx.ch
-
-let save_locals ctx =
-	let old = ctx.locals in
-	let old_inv = ctx.inv_locals in
-	(fun() -> ctx.locals <- old; ctx.inv_locals <- old_inv)
-
-let define_local ctx l =
-	let rec loop n =
-	let name = (if n = 1 then s_ident_local l else s_ident_local (l ^ string_of_int n)) in
-	if PMap.mem name ctx.inv_locals then
-		loop (n+1)
-	else begin
-		ctx.locals <- PMap.add l name ctx.locals;
-		ctx.inv_locals <- PMap.add name l ctx.inv_locals;
-		name
-	end
-	in
-	loop 1
-
-let this ctx =
-	if ctx.in_value <> None then "$__hx__this" else "$this"
-
-let gen_constant ctx p = function
-	| TInt i -> print ctx "%ld" i
-	| TFloat s -> spr ctx s
-	| TString s ->
-		print ctx "\"%s\"" (escape_bin s)
-	| TBool b -> spr ctx (if b then "true" else "false")
-	| TNull -> spr ctx "null"
-	| TThis -> spr ctx (this ctx)
-	| TSuper -> spr ctx "ERROR /* unexpected call to super in gen_constant */"
-
-let arg_is_opt c =
-	match c with
-	| Some _ -> true
-	| None -> false
-
-let s_funarg ctx arg t p o =
-	let byref = if (String.length arg > 7 && String.sub arg 0 7 = "byref__") then "&" else "" in
-	print ctx "%s$%s" byref (s_ident_local arg);
-	if o then spr ctx " = null"
-(*
-	match c with
-	| _, Some _ -> spr ctx " = null"
-	| _, None -> ()
-*)
-let is_in_dynamic_methods ctx e s =
-	List.exists (fun dm ->
-		(* TODO: I agree, this is a mess ... but after hours of trials and errors I gave up; maybe in a calmer day *)
-		((String.concat "." ((fst dm.mpath) @ ["#" ^ (snd dm.mpath)])) ^ "." ^ dm.mname) = (s_type_name e.etype ^ "." ^ s)
-	) ctx.all_dynamic_methods
-
-let is_dynamic_method f =
-	(match f.cf_kind with
-		| Var _ -> true
-		| Method MethDynamic -> true
-		| _ -> false)
-
-let fun_block ctx f p =
-	let e = (match f.tf_expr with { eexpr = TBlock [{ eexpr = TBlock _ } as e] } -> e | e -> e) in
-	let e = List.fold_left (fun e (v,c) ->
-		match c with
-		| None | Some TNull -> e
-		| Some c -> Type.concat (Codegen.set_default ctx.com v c p) e
-	) e f.tf_args in
-	if ctx.com.debug then begin
-		Codegen.stack_block ctx.stack ctx.curclass ctx.curmethod e
-	end else
-		mk_block e
-
-let rec gen_array_args ctx lst =
-	match lst with
-	| [] -> ()
-	| h :: t ->
-		spr ctx "[";
-		gen_value ctx h;
-		spr ctx "]";
-		gen_array_args ctx t
-
-and gen_call ctx e el =
-	let rec genargs lst =
-		(match lst with
-		| [] -> ()
-		| h :: [] ->
-			spr ctx " = ";
-			gen_value ctx h;
-		| h :: t ->
-			spr ctx "[";
-			gen_value ctx h;
-			spr ctx "]";
-			genargs t)
-	in
-	match (reveal_expr e).eexpr , el with
-	| TConst TSuper , params ->
-		(match ctx.curclass.cl_super with
-		| None -> assert false
-		| Some (c,_) ->
-			spr ctx "parent::__construct(";
-			concat ctx "," (gen_value ctx) params;
-			spr ctx ")";
-		);
-	| TField ({ eexpr = TConst TSuper },f) , params ->
-		(match ctx.curclass.cl_super with
-		| None -> assert false
-		| Some (c,_) ->
-			print ctx "parent::%s(" (s_ident (field_name f));
-			concat ctx "," (gen_value ctx) params;
-			spr ctx ")";
-		);
-	| TField ({ eexpr = TTypeExpr _ }, FStatic (_, {cf_type = TDynamic _; cf_kind = Var _})) , params ->
-		spr ctx "call_user_func(";
-		ctx.is_call <- true;
-		gen_value ctx e;
-		ctx.is_call <- false;
-		spr ctx ", ";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")";
-	| TIdent "__set__", { eexpr = TConst (TString code) } :: el ->
-		print ctx "$%s" code;
-		genargs el;
-	| TIdent "__set__", e :: el ->
-		gen_value ctx e;
-		genargs el;
-	| TIdent "__setfield__", e :: (f :: el) ->
-		gen_value ctx e;
-		spr ctx "->{";
-		gen_value ctx f;
-		spr ctx "}";
-		genargs el;
-	| TIdent "__field__", e :: ({ eexpr = TConst (TString code) } :: el) ->
-		gen_value ctx e;
-		spr ctx "->";
-		spr ctx code;
-		gen_array_args ctx el;
-	| TIdent "__field__", e :: (f :: el) ->
-		gen_value ctx e;
-		spr ctx "->";
-		gen_value ctx f;
-		gen_array_args ctx el;
-	| TIdent "__prefix__", [] ->
-		(match ctx.com.php_prefix with
-		| Some prefix ->
-			print ctx "\"%s\"" prefix
-		| None ->
-			spr ctx "null")
-	| TIdent "__var__", { eexpr = TConst (TString code) } :: el ->
-		print ctx "$%s" code;
-		gen_array_args ctx el;
-	| TIdent "__var__", e :: el ->
-		gen_value ctx e;
-		gen_array_args ctx el;
-	| TIdent "__call__", { eexpr = TConst (TString code) } :: el ->
-		spr ctx code;
-		spr ctx "(";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")";
-	| TIdent "__php__", [{ eexpr = TConst (TString code) }] ->
-		(*--php-prefix*)
-		spr ctx (prefix_init_replace ctx.com code)
-	| TIdent "__php__", { eexpr = TConst (TString code); epos = p } :: tl ->
-		Codegen.interpolate_code ctx.com code tl (spr ctx) (gen_expr ctx) p
-	| TIdent "__instanceof__",  [e1;{ eexpr = TConst (TString t) }] ->
-		gen_value ctx e1;
-		print ctx " instanceof %s" t;
-	| TIdent "__physeq__",  [e1;e2] ->
-		spr ctx "(";
-		gen_value ctx e1;
-		spr ctx " === ";
-		gen_value ctx e2;
-		spr ctx ")"
-	| TLocal _, []
-	| TFunction _, []
-	| TCall _, []
-	| TParenthesis _, []
-	| TMeta _, []
-	| TBlock _, [] ->
-		ctx.is_call <- true;
-		spr ctx "call_user_func(";
-		gen_value ctx e;
-		ctx.is_call <- false;
-		spr ctx ")";
-	| TLocal _, el
-	| TFunction _, el
-	| TCall _, el
-	| TParenthesis _, el
-	| TMeta _, el
-	| TBlock _, el ->
-		ctx.is_call <- true;
-		spr ctx "call_user_func_array(";
-		gen_value ctx e;
-		ctx.is_call <- false;
-		spr ctx ", array(";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx "))"
-(*
-	| TCall (x,_), el when (match x.eexpr with | TLocal _ -> false | _ -> true) ->
-		ctx.is_call <- true;
-		spr ctx "call_user_func_array(";
-		gen_value ctx e;
-		ctx.is_call <- false;
-		spr ctx ", array(";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx "))"
-*)
-	| _ ->
-		ctx.is_call <- true;
-		gen_value ctx e;
-		ctx.is_call <- false;
-		spr ctx "(";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")";
-
-and could_be_string_var s =
-	s = "length"
-
-and gen_uncertain_string_var ctx s e =
-	match s with
-	| "length" ->
-		spr ctx "_hx_len(";
-		gen_value ctx e;
-		spr ctx ")"
-	| _ ->
-		gen_field_access ctx true e s;
-
-and gen_string_var ctx s e =
-	match s with
-	| "length" ->
-		spr ctx "strlen(";
-		gen_value ctx e;
-		spr ctx ")"
-	| _ ->
-		unsupported "gen_string_var " e.epos;
-
-and gen_string_static_call ctx s e el =
-	match s with
-	| "fromCharCode" ->
-		spr ctx "chr(";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")";
-	| _ -> unsupported "gen_string_static_call " e.epos;
-
-and could_be_string_call s =
-	s = "substr" || s = "substring" || s = "charAt" || s = "charCodeAt" || s = "indexOf" ||
-	s = "lastIndexOf" || s = "split" || s = "toLowerCase" || s = "toString" || s = "toUpperCase"
-
-and gen_string_call ctx s e el =
-	match s with
-	| "substr" ->
-		spr ctx "_hx_substr(";
-		gen_value ctx e;
-		spr ctx ", ";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")"
-	| "substring" ->
-		spr ctx "_hx_substring(";
-		gen_value ctx e;
-		spr ctx ", ";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")"
-	| "charAt" ->
-		spr ctx "_hx_char_at(";
-		gen_value ctx e;
-		spr ctx ", ";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")"
-	| "cca" ->
-		spr ctx "ord(substr(";
-		gen_value ctx e;
-		spr ctx ",";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ",1))"
-	| "charCodeAt" ->
-		spr ctx "_hx_char_code_at(";
-		gen_value ctx e;
-		spr ctx ", ";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")"
-	| "indexOf" ->
-		spr ctx "_hx_index_of(";
-		gen_value ctx e;
-		spr ctx ", ";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")"
-	| "lastIndexOf" ->
-		spr ctx "_hx_last_index_of(";
-		gen_value ctx e;
-		spr ctx ", ";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")"
-	| "split" ->
-		spr ctx "_hx_explode(";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ", ";
-		gen_value ctx e;
-		spr ctx ")"
-	| "toLowerCase" ->
-		spr ctx "strtolower(";
-		gen_value ctx e;
-		spr ctx ")"
-	| "toUpperCase" ->
-		spr ctx "strtoupper(";
-		gen_value ctx e;
-		spr ctx ")"
-	| "toString" ->
-		gen_value ctx e;
-	| _ ->
-		unsupported "gen_string_call" e.epos;
-
-and gen_uncertain_string_call ctx s e el =
-	spr ctx "_hx_string_call(";
-	gen_value ctx e;
-	print ctx ", \"%s\", array(" s;
-	concat ctx ", " (gen_value ctx) el;
-	spr ctx "))"
-
-and gen_field_op ctx e =
-	match e.eexpr with
-	| TField (f,s) ->
-		(match follow e.etype with
-		| TFun _ ->
-			gen_field_access ctx true f (field_name s)
-		| _ ->
-			gen_value_op ctx e)
-	| _ ->
-		gen_value_op ctx e
-
-and gen_value_op ctx e =
-	match e.eexpr with
-	| TBinop (op,_,_) when op = Ast.OpAnd || op = Ast.OpOr || op = Ast.OpXor ->
-		gen_value ctx e;
-	| _ ->
-		gen_value ctx e
-
-and is_static t =
-	match follow t with
-	| TAnon a -> (match !(a.a_status) with
-		| Statics c -> true
-		| _ -> false)
-	| _ -> false
-
-and get_constant_prefix meta =
-	let (_, args, pos) = Meta.get Meta.PhpConstants meta in
-	(match args with
-		| [EConst(String prefix), _] -> prefix
-		| [] -> ""
-		| _ -> abort "Invalid @:phpConstant parameters" pos)
-
-and gen_member_access ctx isvar e s =
-	match follow e.etype with
-	| TAnon a ->
-		(match !(a.a_status) with
-		| EnumStatics _ ->
-			let (isvar, access_operator) =
-				match e.eexpr with
-					| TField _ -> (false, "->")
-					| _ -> (isvar, "::")
-			in
-			print ctx "%s%s" (access_operator ^ (if isvar then "$" else "")) (s_ident s)
-		| Statics sta ->
-			let (sep, no_dollar) = if Meta.has Meta.PhpGlobal sta.cl_meta then
-					("", false)
-				else
-					match e.eexpr with
-						| TField _ -> ("->", true)
-						| _ -> ("::", false)
-			in
-			let isconst = Meta.has Meta.PhpConstants sta.cl_meta in
-			let cprefix = if isconst then get_constant_prefix sta.cl_meta else "" in
-			print ctx "%s%s%s" sep (if isvar && not isconst && not no_dollar then "$" else cprefix)
-			(if sta.cl_extern && sep = "" then s else s_ident s)
-		| _ -> print ctx "->%s" (if isvar then s_ident_field s else s_ident s))
-	| _ -> print ctx "->%s" (if isvar then s_ident_field s else s_ident s)
-
-and gen_field_access ctx isvar e s =
-	match (reveal_expr e).eexpr with
-	| TTypeExpr t ->
-		let isglobal = match t with
-		| TClassDecl(c) -> Meta.has Meta.PhpGlobal c.cl_meta && c.cl_extern
-		| _ -> false in
-		spr ctx (if isglobal then "" else (s_path ctx (t_path t) false e.epos));
-		gen_member_access ctx isvar e s
-	| TLocal _ ->
-		gen_expr ctx e;
-		print ctx "->%s" (if isvar then s_ident_field s else s_ident s)
-	| TArray (e1,e2) ->
-		spr ctx "_hx_array_get(";
-		gen_value ctx e1;
-		spr ctx ", ";
-		gen_value ctx e2;
-		spr ctx ")";
-		gen_member_access ctx isvar e s
-	| TBlock _
-	| TParenthesis _
-	| TMeta _
-	| TObjectDecl _
-	| TArrayDecl _
-	| TNew _ ->
-		spr ctx "_hx_deref(";
-		ctx.is_call <- false;
-		gen_value ctx e;
-		spr ctx ")";
-		gen_member_access ctx isvar e s
-	| TCast (ec, _) when (match ec.eexpr with | TNew _ | TArrayDecl _ | TConst TNull -> true | _ -> false) ->
-		spr ctx "_hx_deref(";
-		ctx.is_call <- false;
-		gen_value ctx e;
-		spr ctx ")";
-		gen_member_access ctx isvar e s
-	| TConst TNull ->
-		spr ctx "_hx_deref(null)";
-		gen_member_access ctx isvar e s
-	| _ ->
-		gen_expr ctx e;
-		gen_member_access ctx isvar e s
-
-and gen_dynamic_function ctx isstatic name f params p =
-	let old = ctx.in_value in
-	let old_l = ctx.locals in
-	let old_li = ctx.inv_locals in
-	let old_t = ctx.local_types in
-	ctx.in_value <- None;
-	ctx.local_types <- List.map snd params @ ctx.local_types;
-	let byref = if (String.length name > 9 && String.sub name 0 9 = "__byref__") then "&" else "" in
-	print ctx "function %s%s(" byref name;
-	concat ctx ", " (fun (v,c) ->
-		let arg = define_local ctx v.v_name in
-		s_funarg ctx arg v.v_type p (arg_is_opt c);
-	) f.tf_args;
-	spr ctx ") {";
-
-	if (List.length f.tf_args) > 0 then begin
-		if isstatic then
-			print ctx " return call_user_func_array(self::$%s, array("  name
-		else
-			print ctx " return call_user_func_array($this->%s, array("  name;
-		concat ctx ", " (fun (v,_) ->
-			spr ctx ("$" ^ v.v_name)
-		) f.tf_args;
-		print ctx ")); }";
-	end else if isstatic then
-		print ctx " return call_user_func(self::$%s); }"  name
-	else
-		print ctx " return call_user_func($this->%s); }"  name;
-
-	newline ctx;
-	if isstatic then
-		print ctx "public static $%s = null" name
-	else
-		print ctx "public $%s = null" name;
-	ctx.in_value <- old;
-	ctx.locals <- old_l;
-	ctx.inv_locals <- old_li;
-	ctx.local_types <- old_t
-
-and gen_function ctx name f params p =
-	let old = ctx.in_value in
-	let old_l = ctx.locals in
-	let old_li = ctx.inv_locals in
-	let old_t = ctx.local_types in
-	ctx.in_value <- None;
-	ctx.local_types <- List.map snd params @ ctx.local_types;
-	let byref = if (String.length name > 9 && String.sub name 0 9 = "__byref__") then "&" else "" in
-	print ctx "function %s%s(" byref name;
-	concat ctx ", " (fun (v,o) ->
-		let arg = define_local ctx v.v_name in
-		s_funarg ctx arg v.v_type p (arg_is_opt o);
-	) f.tf_args;
-	print ctx ") ";
-	gen_expr ctx (fun_block ctx f p);
-	ctx.in_value <- old;
-	ctx.locals <- old_l;
-	ctx.inv_locals <- old_li;
-	ctx.local_types <- old_t
-
-
-and gen_inline_function ctx f hasthis p =
-	ctx.nested_loops <- ctx.nested_loops - 1;
-	let old = ctx.in_value in
-	let old_l = ctx.locals in
-	let old_li = ctx.inv_locals in
-	let old_t = ctx.local_types in
-	ctx.in_value <- Some "closure";
-
-	let args a = List.map (fun (v,_) -> v.v_name) a in
-
-	let used_locals = ref PMap.empty in
-
-	let rec loop e = match e.eexpr with
-		| TLocal v when not (start_with v.v_name "__hx__") && PMap.mem v.v_name old_l ->
-			used_locals := PMap.add v.v_name v.v_name !used_locals
-		| _ ->
-			Type.iter loop e
-	in
-	loop f.tf_expr;
-
-	spr ctx "array(new _hx_lambda(array(";
-
-	let c = ref 0 in
-
-	let print_arg a =
-		if !c > 0 then spr ctx ", ";
-		incr c;
-		print ctx "&$%s" a;
-	in
-	if hasthis then print_arg "this";
-	PMap.iter (fun _ a -> print_arg a) !used_locals;
-
-	spr ctx "), \"";
-
-	spr ctx (inline_function ctx (args f.tf_args) hasthis !used_locals (fun_block ctx f p));
-	print ctx "\"), 'execute')";
-
-	ctx.in_value <- old;
-	ctx.locals <- old_l;
-	ctx.inv_locals <- old_li;
-	ctx.local_types <- old_t;
-	ctx.nested_loops <- ctx.nested_loops + 1;
-
-and unset_locals ctx old_l =
-	let lst = ref [] in
-	PMap.iter (fun n _ ->
-		if not (PMap.exists n old_l) then
-			lst := ["$" ^  n] @ !lst;
-	) ctx.inv_locals;
-	if (List.length !lst) > 0 then begin
-		newline ctx;
-		spr ctx "unset(";
-		concat ctx "," (fun (s) -> spr ctx s; ) !lst;
-		spr ctx ")"
-	end
-
-and gen_while_expr ctx e =
-	let old_loop = ctx.in_loop in
-	ctx.in_loop <- true;
-	let old_nested_loops = ctx.nested_loops in
-	ctx.nested_loops <- 1;
-	let old_l = ctx.inv_locals in
-	let b = save_locals ctx in
-	(match e.eexpr with
-	| TBlock (el) ->
-		List.iter (fun e -> newline ctx; gen_expr ctx e) el;
-	| _ ->
-		newline ctx;
-		gen_expr ctx e);
-	unset_locals ctx old_l;
-	b();
-	ctx.nested_loops <- old_nested_loops;
-	ctx.in_loop <- old_loop
-
-and gen_tfield ctx e e1 s =
-	let name = (field_name s) in
-	match follow e.etype with
-	| TFun (args, _) ->
-		(if ctx.is_call then begin
-			gen_field_access ctx false e1 name
-	  	end else if is_in_dynamic_methods ctx e1 name then begin
-	  		gen_field_access ctx true e1 name;
-	  	end else begin
-			let ob ex =
-				(match ex with
-				| TTypeExpr t ->
-					print ctx "\"";
-					spr ctx (s_path ctx (t_path t) false e1.epos);
-					print ctx "\""
-				| _ ->
-					gen_expr ctx e1) in
-
-			spr ctx "(property_exists(";
-			ob e1.eexpr;
-			print ctx ", \"%s\") ? " (s_ident name);
-			gen_field_access ctx true e1 name;
-			spr ctx ": array(";
-			ob e1.eexpr;
-			print ctx ", \"%s\"))" (s_ident name);
-
-		end)
-	| TMono _ ->
-		if ctx.is_call then
-			gen_field_access ctx false e1 name
-		else
-			gen_uncertain_string_var ctx name e1
-	| TDynamic _ when not ctx.is_call && (match s with FDynamic _ -> true | _ -> false) ->
-		spr ctx "_hx_field(";
-		gen_value ctx e1;
-		print ctx ", \"%s\")" name
-	| _ ->
-		if is_string_expr e1 then
-			gen_string_var ctx name e1
-		else if is_uncertain_expr e1 then
-			gen_uncertain_string_var ctx name e1
-		else
-			gen_field_access ctx true e1 name
-
-and gen_expr ctx e =
-	let in_block = ctx.in_block in
-	ctx.in_block <- false;
-	let restore_in_block ctx inb =
-		if inb then ctx.in_block <- true
-	in
-	match e.eexpr with
-	| TConst c ->
-		gen_constant ctx e.epos c
-	| TLocal v ->
-		spr ctx ("$" ^ (try PMap.find v.v_name ctx.locals with Not_found -> (s_ident_local v.v_name)))
-	| TArray (e1,e2) ->
-		(match e1.eexpr with
-		| TCall _
-		| TBlock _
-		| TParenthesis _
-		| TMeta _
-		| TArrayDecl _ ->
-			spr ctx "_hx_array_get(";
-			gen_value ctx e1;
-			spr ctx ", ";
-			gen_value ctx e2;
-			spr ctx ")";
-		| TCast (ec, _) when (match ec.eexpr with | TArrayDecl _  | TBlock _ -> true | _ -> false) ->
-			spr ctx "_hx_array_get(";
-			gen_value ctx e1;
-			spr ctx ", ";
-			gen_value ctx e2;
-			spr ctx ")";
-		| _ ->
-			gen_value ctx e1;
-			spr ctx "[";
-			gen_value ctx e2;
-			spr ctx "]");
-	| TBinop (op,e1,e2) ->
-		(* these operators are non-assoc in php, let let's make sure to separate them with parenthesises *)
-		let non_assoc = function
-			| (Ast.OpEq | Ast.OpNotEq | Ast.OpGt | Ast.OpGte | Ast.OpLt | Ast.OpLte) -> true
-			| _ -> false
-		in
-		(match e1.eexpr with
-		| TBinop (op2,_,_) when non_assoc op && non_assoc op2 ->
-			gen_expr ctx { e with eexpr = TBinop (op,mk (TParenthesis e1) e1.etype e1.epos,e2) }
-		| _ ->
-		let leftside e =
-			(match e.eexpr with
-			| TArray(te1, te2) ->
-				gen_value ctx te1;
-				spr ctx "->a[";
-				gen_value ctx te2;
-				spr ctx "]";
-			| _ ->
-				gen_field_op ctx e1;) in
-		let leftsidec e =
-			(match e.eexpr with
-			| TArray(te1, te2) ->
-				gen_value ctx te1;
-				spr ctx "->a[";
-				gen_value ctx te2;
-				spr ctx "]";
-			| TField (e1,s) ->
-				gen_field_access ctx true e1 (field_name s)
-			| _ ->
-				gen_field_op ctx e1;) in
-		let leftsidef e =
-			(match e.eexpr with
-			| TField (e1,s) ->
-				gen_field_access ctx true e1 (field_name s)
-			| _ ->
-				gen_field_op ctx e1;
-				) in
-		(match op with
-		| Ast.OpMod ->
-			spr ctx "_hx_mod(";
-			gen_value_op ctx e1;
-			spr ctx ", ";
-			gen_value_op ctx e2;
-			spr ctx ")";
-		| Ast.OpAssign ->
-			(match e1.eexpr with
-			| TArray(te1, te2) when (match te1.eexpr with | TCall _ | TParenthesis _ -> true | _ -> false) ->
-				spr ctx "_hx_array_assign(";
-				gen_value ctx te1;
-				spr ctx ", ";
-				gen_value ctx te2;
-				spr ctx ", ";
-				gen_value_op ctx e2;
-				spr ctx ")";
-			| _ ->
-				leftsidef e1;
-				spr ctx " = ";
-				gen_value_op ctx e2;
-			)
-		| Ast.OpAssignOp(Ast.OpAdd) when (is_uncertain_expr e1 && is_uncertain_expr e2) ->
-			(match e1.eexpr with
-			| TArray(te1, te2) ->
-				let t1 = define_local ctx "__hx__t1" in
-				let t2 = define_local ctx "__hx__t2" in
-
-				print ctx "_hx_array_assign($%s = " t1;
-				gen_value ctx te1;
-				print ctx ", $%s = " t2;
-				gen_value ctx te2;
-				print ctx ", $%s->a[$%s] + " t1 t2;
-				gen_value_op ctx e2;
-				spr ctx ")";
-			| _ ->
-				leftside e1;
-				spr ctx " = ";
-				spr ctx "_hx_add(";
-				gen_value_op ctx e1;
-				spr ctx ", ";
-				gen_value_op ctx e2;
-				spr ctx ")";
-			)
-		| Ast.OpAssignOp(Ast.OpAdd) when (is_string_expr e1 || is_string_expr e2) ->
-			leftside e1;
-			spr ctx " .= ";
-			gen_value_op ctx (as_string_expr ctx e2);
-		| Ast.OpAssignOp(Ast.OpShl) ->
-			leftside e1;
-			spr ctx " <<= ";
-			gen_value_op ctx e2;
-		| Ast.OpAssignOp(Ast.OpUShr) ->
-			leftside e1;
-			spr ctx " = ";
-			spr ctx "_hx_shift_right(";
-			gen_value_op ctx e1;
-			spr ctx ", ";
-			gen_value_op ctx e2;
-			spr ctx ")";
-		| Ast.OpAssignOp(Ast.OpMod) ->
-			leftside e1;
-			spr ctx " = ";
-			spr ctx "_hx_mod(";
-			gen_value_op ctx e1;
-			spr ctx ", ";
-			gen_value_op ctx e2;
-			spr ctx ")";
-		| Ast.OpAssignOp(_) ->
-			leftsidec e1;
-			print ctx " %s " (Ast.s_binop op);
-			gen_value_op ctx e2;
-		| Ast.OpAdd when (is_uncertain_expr e1 && is_uncertain_expr e2) ->
-			spr ctx "_hx_add(";
-			gen_value_op ctx e1;
-			spr ctx ", ";
-			gen_value_op ctx e2;
-			spr ctx ")";
-		| Ast.OpAdd when (is_string_expr e1 || is_string_expr e2) ->
-			gen_value_op ctx (as_string_expr ctx e1);
-			spr ctx " . ";
-			gen_value_op ctx (as_string_expr ctx e2);
-		| Ast.OpShl ->
-			gen_value_op ctx e1;
-			spr ctx " << ";
-			gen_value_op ctx e2;
-		| Ast.OpUShr ->
-			spr ctx "_hx_shift_right(";
-			gen_value_op ctx e1;
-			spr ctx ", ";
-			gen_value_op ctx e2;
-			spr ctx ")";
-		| Ast.OpNotEq
-		| Ast.OpEq ->
-			let s_op = if op = Ast.OpNotEq then " != " else " == " in
-			let s_phop = if op = Ast.OpNotEq then " !== " else " === " in
-			let se1 = s_expr_name e1 in
-			let se2 = s_expr_name e2 in
-			if
-				   e1.eexpr = TConst (TNull)
-				|| e2.eexpr = TConst (TNull)
-			then begin
-				(match e1.eexpr with
-				| TField (f, s) when is_anonym_expr e1 || is_unknown_expr e1 ->
-					spr ctx "_hx_field(";
-					gen_value ctx f;
-					print ctx ", \"%s\")" (field_name s);
-				| _ ->
-					gen_field_op ctx e1;
-				);
-				spr ctx s_phop;
-
-				(match e2.eexpr with
-				| TField (f, s) when is_anonym_expr e2 || is_unknown_expr e2 ->
-					spr ctx "_hx_field(";
-					gen_value ctx f;
-					print ctx ", \"%s\")" (field_name s);
-				| _ ->
-					gen_field_op ctx e2);
-			end else if
-				   ((se1 = "Int" || se1 = "Null<Int>") && (se2 = "Int" || se2 = "Null<Int>"))
-				|| ((se1 = "Float" || se1 = "Null<Float>") && (se2 = "Float" || se2 = "Null<Float>"))
-				&& not (is_float e1 && is_float e2)
-			then begin
-				gen_field_op ctx e1;
-				spr ctx s_phop;
-				gen_field_op ctx e2;
-			end else if
-				   ((se1 = "Int" || se1 = "Float" || se1 = "Null<Int>" || se1 = "Null<Float>")
-				&& (se1 = "Int" || se1 = "Float" || se1 = "Null<Int>" || se1 = "Null<Float>"))
-				|| (is_unknown_expr e1 && is_unknown_expr e2)
-				|| is_anonym_expr e1
-				|| is_anonym_expr e2
-			then begin
-				if op = Ast.OpNotEq then spr ctx "!";
-				spr ctx "_hx_equal(";
-				gen_field_op ctx e1;
-				spr ctx ", ";
-				gen_field_op ctx e2;
-				spr ctx ")";
-			end else if
-				(
-					   se1 == se2
-					|| (match e1.eexpr with | TConst _ | TLocal _ | TArray _  | TNew _ -> true | _ -> false)
-					|| (match e2.eexpr with | TConst _ | TLocal _ | TArray _  | TNew _ -> true | _ -> false)
-					|| is_string_expr e1
-					|| is_string_expr e2
-					|| is_anonym_expr e1
-					|| is_anonym_expr e2
-					|| is_unknown_expr e1
-					|| is_unknown_expr e2
-				)
-				&& (type_string (follow e1.etype)) <> "Dynamic"
-				&& (type_string (follow e2.etype)) <> "Dynamic"
-			then begin
-				gen_field_op ctx e1;
-				spr ctx s_phop;
-				gen_field_op ctx e2;
-			end else begin
-				let tmp = define_local ctx "_t" in
-				print ctx "(is_object($%s = " tmp;
-				gen_field_op ctx e1;
-				print ctx ") && ($%s instanceof Enum) ? $%s%s" tmp tmp s_op;
-				gen_field_op ctx e2;
-				print ctx " : ";
-				if op = Ast.OpNotEq then spr ctx "!";
-				print ctx "_hx_equal($%s, " tmp;
-				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;
-	| TEnumIndex e1 ->
-		spr ctx "_hx_deref(";
-		gen_value ctx e1;
-		spr ctx ")";
-		print ctx "->index";
-	| TField (e1,s) ->
-		gen_tfield ctx e e1 s
-	| TTypeExpr t ->
-		print ctx "_hx_qtype(\"%s\")" (s_path_haxe (t_path t))
-	| TParenthesis e ->
-		(match e.eexpr with
-		| TParenthesis _
-		| TReturn _ ->
-			gen_value ctx e;
-		| _ ->
-			spr ctx "(";
-			gen_value ctx e;
-			spr ctx ")"
-		);
-	| TMeta (_,e) ->
-		gen_expr ctx e
-	| TReturn eo ->
-		(match eo with
-		| None ->
-			spr ctx "return"
-		| Some e when (match follow e.etype with TEnum({ e_path = [],"Void" },[]) | TAbstract ({ a_path = [],"Void" },[]) -> true | _ -> false) ->
-			gen_value ctx e;
-			newline ctx;
-			spr ctx "return"
-		| Some e ->
-			(match e.eexpr with
-			| TThrow _ -> ()
-			| _ -> spr ctx "return ");
-			gen_value ctx e;
-			);
-	| TBreak ->
-		if ctx.in_loop then spr ctx "break" else print ctx "break %d" ctx.nested_loops
-	| TContinue ->
-		if ctx.in_loop then spr ctx "continue" else print ctx "continue %d" ctx.nested_loops
-	| TBlock [] when List.length ctx.dynamic_methods = 0 ->
-		spr ctx "{}"
-	| TBlock el ->
-		let old_l = ctx.inv_locals in
-		let b = save_locals ctx in
-		print ctx "{";
-		let bend = open_block ctx in
-		let cb = (
-			if not ctx.constructor_block then
-				(fun () -> ())
-			else begin
-				ctx.constructor_block <- false;
-				if List.length ctx.dynamic_methods > 0 then newline ctx else spr ctx " ";
-				List.iter (fun (f) ->
-					let name = f.cf_name in
-					match f.cf_expr with
-					| Some { eexpr = TFunction fd } ->
-						print ctx "if(!isset($this->%s)) $this->%s = " name name;
-						gen_inline_function ctx fd true e.epos;
-						newline ctx;
-					| _ -> ()
-				) ctx.dynamic_methods;
-				if Codegen.constructor_side_effects e then begin
-					print ctx "if(!%s::$skip_constructor) {" (s_path ctx (["php"],"Boot") false e.epos);
-					(fun() -> print ctx "}")
-				end else
-					(fun() -> ());
-			end) in
-		let remaining = ref (List.length el) in
-		let build e =
-			newline ctx;
-			if (in_block && !remaining = 1) then begin
-				(match e.eexpr with
-				| TIf _
-				| TSwitch _
-				| TThrow _
-				| TWhile _
-				| TFor _
-				| TTry _
-				| TBreak
-				| TBlock _ ->
-					restore_in_block ctx in_block;
-					gen_expr ctx e;
-					unset_locals ctx old_l;
-				| TReturn (Some e1) ->
-					(match e1.eexpr with
-					| TIf _
-					| TSwitch _
-					| TThrow _
-					| TWhile _
-					| TFor _
-					| TTry _
-					| TBlock _ -> ()
-					| _ ->
-						spr ctx "return "
-					);
-					gen_expr ctx e1;
-				| _ ->
-					spr ctx "return ";
-					gen_value ctx e;
-				)
-			end else begin
-				gen_expr ctx e;
-			end;
-			decr remaining;
-		in
-		List.iter build el;
-
-		if ctx.in_loop then begin
-			unset_locals ctx old_l;
-		end;
-		bend();
-		newline ctx;
-
-		cb();
-		print ctx "}";
-		b();
-	| TFunction f ->
-		let old = ctx.in_value, ctx.in_loop in
-		let old_meth = ctx.curmethod in
-		ctx.in_value <- None;
-		ctx.in_loop <- false;
-		ctx.curmethod <- ctx.curmethod ^ "@" ^ string_of_int (Lexer.get_error_line e.epos);
-		gen_inline_function ctx f false e.epos;
-		ctx.curmethod <- old_meth;
-		ctx.in_value <- fst old;
-		ctx.in_loop <- snd old;
-	| TCall (ec,el) ->
-		(match ec.eexpr with
-		| TArray _ ->
-			spr ctx "call_user_func_array(";
-			gen_value ctx ec;
-			spr ctx ", array(";
-			concat ctx ", " (gen_value ctx) el;
-			spr ctx "))";
-		| TField (ef,s) when is_static ef.etype && is_string_expr ef ->
-			gen_string_static_call ctx (field_name s) ef el
-		| TField (ef,s) when is_string_expr ef ->
-			gen_string_call ctx (field_name s) ef el
-		| TField (ef,s) when is_anonym_expr ef && could_be_string_call (field_name s) ->
-			gen_uncertain_string_call ctx (field_name s) ef el
-		| _ ->
-			gen_call ctx ec el);
-	| TArrayDecl el ->
-		spr ctx "(new _hx_array(array(";
-		concat ctx ", " (gen_value ctx) el;
-		spr ctx ")))";
-	| TThrow e ->
-		spr ctx "throw new HException(";
-		gen_value ctx e;
-		spr ctx ")";
-	| TVar (v,eo) ->
-		spr ctx "$";
-		let restore = save_locals ctx in
-		let n = define_local ctx v.v_name in
-		let restore2 = save_locals ctx in
-		restore();
-		(match eo with
-		| None ->
-			print ctx "%s = null" (s_ident_local n)
-		| Some e ->
-			print ctx "%s = " (s_ident_local n);
-			gen_value ctx e);
-		restore2()
-	| TNew (c,_,el) ->
-		(match c.cl_path, el with
-		| ([], "String"), _ ->
-			concat ctx "" (gen_value ctx) el
-		| ([], "Array"), el ->
-			spr ctx "new _hx_array(array(";
-			concat ctx ", " (gen_value ctx) el;
-			spr ctx "))"
-		| (_, _), _ ->
-			print ctx "new %s(" (s_path ctx c.cl_path c.cl_extern e.epos);
-			let count = ref (-1) in
-			concat ctx ", " (fun e ->
-				incr count;
-				match c.cl_constructor with
-				| Some f ->
-					gen_value ctx e;
-				| _ -> ();
-			) el;
-			spr ctx ")")
-	| TIf (cond,e,eelse) ->
-		spr ctx "if";
-		gen_value ctx (parent cond);
-		spr ctx " ";
-		restore_in_block ctx in_block;
-		gen_expr ctx (mk_block e);
-		(match eelse with
-		| None -> ()
-		| Some e when e.eexpr = TConst(TNull) -> ()
-		| Some e ->
-			spr ctx " else ";
-			restore_in_block ctx in_block;
-			gen_expr ctx (mk_block e));
-	| TUnop (op,Ast.Prefix,e) ->
-		(match e.eexpr with
-		| TArray(te1, te2) ->
-			(match op with
-			| Increment ->
-				spr ctx "_hx_array_increment(";
-				gen_value ctx te1;
-				spr ctx ",";
-				gen_value ctx te2;
-				spr ctx ")";
-			| Decrement ->
-				spr ctx "_hx_array_decrement(";
-				gen_value ctx te1;
-				spr ctx ",";
-				gen_value ctx te2;
-				spr ctx ")";
-			| _ ->
-				spr ctx (Ast.s_unop op);
-				gen_value ctx te1;
-				spr ctx "[";
-				gen_value ctx te2;
-				spr ctx "]";
-			);
-		| TField (e1,s) ->
-			spr ctx (Ast.s_unop op);
-			gen_tfield ctx e e1 s
-		| _ ->
-			spr ctx (Ast.s_unop op);
-			gen_value ctx e)
-	| TUnop (op,Ast.Postfix,e) ->
-		(match e.eexpr with
-		| TArray(te1, te2) ->
-			gen_value ctx te1;
-			spr ctx "->a[";
-			gen_value ctx te2;
-			spr ctx "]";
-		| TField (e1,s) ->
-			gen_field_access ctx true e1 (field_name s)
-		| _ ->
-			gen_value ctx e);
-		spr ctx (Ast.s_unop op)
-	| TWhile (cond,e,Ast.NormalWhile) ->
-		let old = save_locals ctx in
-		spr ctx "while";
-		gen_value ctx (parent cond);
-		spr ctx " {";
-		let bend = open_block ctx in
-		gen_while_expr ctx e;
-		bend();
-		newline ctx;
-		spr ctx "}";
-		old()
-	| TWhile (cond,e,Ast.DoWhile) ->
-		let old = save_locals ctx in
-		spr ctx "do {";
-		let bend = open_block ctx in
-		gen_while_expr ctx e;
-		bend();
-		newline ctx;
-		spr ctx "} while";
-		gen_value ctx (parent cond);
-		old()
-	| TObjectDecl fields ->
-		spr ctx "_hx_anonymous(array(";
-		concat ctx ", " (fun (f,e) -> print ctx "\"%s\" => " (escape_bin f); gen_value ctx e) fields;
-		spr ctx "))"
-	| TFor (v,it,e) ->
-		let b = save_locals ctx in
-		let tmp = define_local ctx "__hx__it" in
-		let v = define_local ctx v.v_name in
-		(match it.eexpr with
-		| TCall (e,_) ->
-			(match e.eexpr with
-			| TField (e,f) ->
-				spr ctx "if(null == ";
-				gen_value ctx e;
-				spr ctx ") throw new HException('null iterable')";
-				newline ctx;
-			| _ ->
-				());
-		| _ -> ()
-		);
-		print ctx "$%s = " tmp;
-		gen_value ctx it;
-		newline ctx;
-		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();
-		newline ctx;
-		spr ctx "}";
-		b();
-	| TTry (e,catchs) ->
-		spr ctx "try ";
-		restore_in_block ctx in_block;
-		gen_expr ctx (mk_block e);
-		let old = save_locals ctx in
-		let ex = define_local ctx "__hx__e" in
-		print ctx "catch(Exception $%s) {" ex;
-		let bend = open_block ctx in
-		let first = ref true in
-		let catchall = ref false in
-		let evar = define_local ctx "_ex_" in
-		newline ctx;
-		print ctx "$%s = ($%s instanceof HException) && $%s->getCode() == null ? $%s->e : $%s" evar ex ex ex ex;
-		old();
-		List.iter (fun (v,e) ->
-			let ev = define_local ctx v.v_name in
-			newline ctx;
-
-			let b = save_locals ctx in
-			if not !first then spr ctx "else ";
-			(match follow v.v_type with
-			| TEnum (te,_) -> (match te.e_path with
-				| [], "Bool"   -> print ctx "if(is_bool($%s = $%s))" ev evar
-				| _ -> print ctx "if(($%s = $%s) instanceof %s)" ev evar (s_path ctx te.e_path te.e_extern e.epos));
-				restore_in_block ctx in_block;
-				gen_expr ctx (mk_block e);
-			| TInst (tc,_) -> (match tc.cl_path with
-				| [], "Int"	-> print ctx "if(is_int($%s = $%s))"		ev evar
-				| [], "Float"  -> print ctx "if(is_numeric($%s = $%s))"	ev evar
-				| [], "String" -> print ctx "if(is_string($%s = $%s))"	ev evar
-				| [], "Array"  -> print ctx "if(($%s = $%s) instanceof _hx_array)"	ev evar
-				| _ -> print ctx "if(($%s = $%s) instanceof %s)"    ev evar (s_path ctx tc.cl_path tc.cl_extern e.epos));
-				restore_in_block ctx in_block;
-				gen_expr ctx (mk_block e);
-			| TAbstract (ta,_) -> (match ta.a_path with
-				| [], "Int"	-> print ctx "if(is_int($%s = $%s))"		ev evar
-				| [], "Float"  -> print ctx "if(is_numeric($%s = $%s))"	ev evar
-				| [], "Bool"   -> print ctx "if(is_bool($%s = $%s))" ev evar
-				| _ -> print ctx "if(($%s = $%s) instanceof %s)"    ev evar (s_path ctx ta.a_path false e.epos));
-				restore_in_block ctx in_block;
-				gen_expr ctx (mk_block e);
-			| TFun _
-			| TLazy _
-			| TType _
-			| TAnon _ ->
-				assert false
-			| TMono _
-			| TDynamic _ ->
-				catchall := true;
-				if not !first then spr ctx "{ ";
-				print ctx "$%s = $%s" ev evar;
-				newline ctx;
-				restore_in_block ctx in_block;
-				gen_expr ctx (mk_block e);
-				if not !first then spr ctx "}"
-			);
-			b();
-			first := false;
-		) catchs;
-		if not !catchall then
-			print ctx " else throw $%s;" ex;
-		bend();
-		newline ctx;
-		spr ctx "}"
-	| TSwitch (e,cases,def) ->
-		let old_loop = ctx.in_loop in
-		ctx.in_loop <- false;
-		ctx.nested_loops <- ctx.nested_loops + 1;
-		let old = save_locals ctx in
-		spr ctx "switch";
-		gen_value ctx (parent e);
-		spr ctx " {";
-		newline ctx;
-		List.iter (fun (el,e2) ->
-			List.iter (fun e ->
-				spr ctx "case ";
-				gen_value ctx e;
-				spr ctx ":";
-			) el;
-			restore_in_block ctx in_block;
-			gen_expr ctx (mk_block e2);
-			print ctx "break";
-			newline ctx;
-		) cases;
-		(match def with
-		| None -> ()
-		| Some e ->
-			spr ctx "default:";
-			restore_in_block ctx in_block;
-			gen_expr ctx (mk_block e);
-			print ctx "break";
-			newline ctx;
-		);
-		spr ctx "}";
-		ctx.nested_loops <- ctx.nested_loops - 1;
-		ctx.in_loop <- old_loop;
-		old()
-	| TCast (e,None) ->
-		gen_expr ctx e
-	| TCast (e1,Some t) ->
-		let mk_texpr = function
-			| TClassDecl c -> TAnon { a_fields = PMap.empty; a_status = ref (Statics c) }
-			| TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }
-			| TAbstractDecl a -> TAnon { a_fields = PMap.empty; a_status = ref (AbstractStatics a) }
-			| TTypeDecl _ -> assert false
-		in
-		spr ctx "_hx_cast(";
-		gen_expr ctx e1;
-		spr ctx ", ";
-		gen_expr ctx (mk (TTypeExpr t) (mk_texpr t) e1.epos);
-		spr ctx ")"
-	| TIdent s ->
-		spr ctx s
-
-and argument_list_from_locals include_this in_var l =
-	let lst = ref [] in
-	if (include_this && in_var) then lst := "__hx__this" :: !lst
-	else if include_this then lst := "this" :: !lst;
-	PMap.iter (fun n _ ->
-		lst := !lst @ [n];
-	) l;
-	!lst
-
-and remove_internals args =
-	List.filter (fun a -> a = "__hx__this" || not (start_with a "__hx__")) args;
-
-and inline_block ctx e =
-		let index = ctx.inline_index in
-		ctx.inline_index <- ctx.inline_index + 1;
-		let block = {
-			iname = (s_path ctx ctx.curclass.cl_path ctx.curclass.cl_extern ctx.curclass.cl_pos) ^ "_" ^ string_of_int index;
-			iindex = index;
-			ihasthis = ctx.in_instance_method; (* param this *)
-			iarguments = [];
-			iexpr = e;
-			ilocals = ctx.locals;
-			iin_block = true;
-			iinv_locals = ctx.inv_locals;
-		} in
-
-		print ctx "%s(" block.iname;
-		let in_value = (match ctx.in_value with Some _ -> true | _ -> false) in
-		(match remove_internals (argument_list_from_locals ctx.in_instance_method in_value ctx.locals) with
-		| [] -> ()
-		| l -> print ctx "$%s" (String.concat ", $" l)
-		);
-		spr ctx ")";
-
-		ctx.inline_methods <- ctx.inline_methods @ [block]
-
-and inline_function ctx args hasthis used_args e =
-		let index = ctx.inline_index in
-		ctx.inline_index <- ctx.inline_index + 1;
-		let block = {
-			iname = (s_path ctx ctx.curclass.cl_path ctx.curclass.cl_extern ctx.curclass.cl_pos) ^ "_" ^ string_of_int index;
-			iindex = index;
-			ihasthis = hasthis; (* param this *)
-			iarguments = args;
-			iexpr = e;
-			ilocals = used_args;
-			iin_block = false;
-			iinv_locals = used_args;
-		} in
-
-		ctx.inline_methods <- ctx.inline_methods @ [block];
-		block.iname
-
-and canbe_ternary_param e =
-	match e.eexpr with
-	| TTypeExpr _
-	| TConst _
-	| TLocal _
-	| TField (_,FEnum _)
-	| TParenthesis _
-	| TMeta _
-	| TObjectDecl _
-	| TArrayDecl _
-	| TCall _
-	| TUnop _
-	| TNew _
-	| TCast (_, _)
-	| TBlock [_] ->
-		true
-	| TIf (_,e,eelse) ->
-		cangen_ternary e eelse
-	| _ ->
-		false
-
-and cangen_ternary e eelse =
-	match eelse with
-	| Some other ->
-		(canbe_ternary_param e) && (canbe_ternary_param other)
-	| _ ->
-		false
-
-and gen_value ctx e =
-	match e.eexpr with
-	| TTypeExpr _
-	| TConst _
-	| TLocal _
-	| TArray _
-	| TBinop _
-	| TEnumParameter _
-	| TEnumIndex _
-	| TField _
-	| TParenthesis _
-	| TObjectDecl _
-	| TArrayDecl _
-	| TCall _
-	| TUnop _
-	| TNew _
-	| TFunction _
-	| TIdent _ ->
-		gen_expr ctx e
-	| TMeta (_,e1) ->
-		gen_value ctx e1
-	| TBlock [] ->
-		()
-	| TCast (_, Some _) ->
-		gen_expr ctx e
-	| TCast (e, None)
-	| TBlock [e] ->
-		gen_value ctx e
-	| TIf (cond,e,eelse) when (cangen_ternary e eelse) ->
-		spr ctx "(";
-		gen_value ctx cond;
-		spr ctx " ? ";
-		gen_value ctx e;
-
-		(match eelse with
-		| Some e ->
-			spr ctx " : ";
-			gen_value ctx e
-		| _ ->());
-		spr ctx ")";
-
-(*
-	| TIf (cond,e,eelse) ->
-		spr ctx "if";
-		gen_value ctx (parent cond);
-		spr ctx " ";
-		restore_in_block ctx in_block;
-		gen_expr ctx (mk_block e);
-		(match eelse with
-		| None -> ()
-		| Some e when e.eexpr = TConst(TNull) -> ()
-		| Some e ->
-			spr ctx " else ";
-			restore_in_block ctx in_block;
-			gen_expr ctx (mk_block e));
-*)
-	| TBlock _
-	| TBreak
-	| TContinue
-	| TVar _
-	| TReturn _
-	| TWhile _
-	| TThrow _
-	| TSwitch _
-	| TFor _
-	| TIf _
-	| TTry _ ->
-		inline_block ctx e
-
-let rec is_instance_method_defined cls m =
-	if PMap.exists m cls.cl_fields then
-		true
-	else
-		match cls.cl_super with
-		| Some (scls, _) ->
-			is_instance_method_defined scls m
-		| None ->
-			false
-
-let is_method_defined ctx m static =
-	if static then
-		PMap.exists m ctx.curclass.cl_statics
-	else
-		is_instance_method_defined ctx.curclass m
-
-let generate_self_method ctx rights m static setter =
-	if setter then (
-		if static then
-			print ctx "%s function %s($v) { return call_user_func(self::$%s, $v); }" rights (s_ident m) (s_ident m)
-		else
-			print ctx "%s function %s($v) { return call_user_func($this->%s, $v); }" rights (s_ident m) (s_ident m)
-	) else (
-		if static then
-			print ctx "%s function %s() { return call_user_func(self::$%s); }" rights (s_ident m) (s_ident m)
-		else
-			print ctx "%s function %s() { return call_user_func($this->%s); }" rights (s_ident m) (s_ident m)
-	);
-	newline ctx
-
-let gen_assigned_value ctx eo =	match eo with
-	| Some ({eexpr = TConst _} as e) ->
-		print ctx " = ";
-		gen_value ctx e
-	| _ ->
-		()
-
-let generate_field ctx static f =
-	if is_physical_field f then
-		newline ctx;
-	ctx.locals <- PMap.empty;
-	ctx.inv_locals <- PMap.empty;
-	ctx.in_instance_method <- not static;
-	let rights = if static then "static" else "public" in
-	let p = ctx.curclass.cl_pos in
-	match f.cf_expr with
-	| Some { eexpr = TFunction fd } ->
-		if f.cf_name = "__construct" then
-			ctx.curmethod <- "new"
-		else
-			ctx.curmethod <- f.cf_name;
-		spr ctx (rights ^ " ");
-		if is_dynamic_method f then
-			gen_dynamic_function ctx static (s_ident f.cf_name) fd f.cf_params p
-		else
-			gen_function ctx (s_ident f.cf_name) fd f.cf_params p
-	| _ ->
-		if not (is_physical_field f) then
-			()
-		else if ctx.curclass.cl_interface then
-			match follow f.cf_type, f.cf_kind with
-			| TFun (args,r), Method _ ->
-				print ctx "function %s(" (s_ident f.cf_name);
-				concat ctx ", " (fun (arg,o,t) ->
-					s_funarg ctx arg t p o;
-				) args;
-				print ctx ")";
-			| _ -> spr ctx "//"; ()
-		else if
-			(match f.cf_kind with
-			| Var v ->
-				(match v.v_read, v.v_write with
-				| AccCall, AccCall ->
-					let m1 = "get_" ^ f.cf_name in
-					let m2 = "set_" ^ f.cf_name in
-					if not (is_method_defined ctx m1 static) then (
-						generate_self_method ctx rights m1 static false;
-						print ctx "%s $%s" rights (s_ident m1);
-						if not (is_method_defined ctx m2 static) then
-							newline ctx);
-					if not (is_method_defined ctx m2 static) then (
-						generate_self_method ctx rights m2 static true;
-						print ctx "%s $%s" rights (s_ident m2);
-						newline ctx);
-					false
-				| AccCall, _ ->
-					let m = "get_" ^ f.cf_name in
-					if not (is_method_defined ctx m static) then generate_self_method ctx rights m static false;
-					print ctx "%s $%s" rights (s_ident f.cf_name);
-					gen_assigned_value ctx f.cf_expr;
-					true
-				| _, AccCall ->
-					let m = "set_" ^ f.cf_name in
-					if not (is_method_defined ctx m static) then generate_self_method ctx rights m static true;
-					print ctx "%s $%s" rights (s_ident f.cf_name);
-					gen_assigned_value ctx f.cf_expr;
-					true
-				| _ ->
-					false)
-			| _ -> false) then
-				()
-		else begin
-			let name = if static then s_ident f.cf_name else f.cf_name in
-			if static then
-				(match f.cf_kind with
-				| Var _ ->
-					(match follow f.cf_type with
-					| TFun _
-					| TDynamic _ ->
-						print ctx "static function %s() { $args = func_get_args(); return call_user_func_array(self::$%s, $args); }" name name;
-						newline ctx;
-					| _ ->
-						()
-					)
-				| _ ->
-					()
-				);
-			print ctx "%s $%s" rights name;
-			gen_assigned_value ctx f.cf_expr
-		end
-
-let generate_static_field_assign ctx path f =
-	let p = ctx.curclass.cl_pos in
-	if not ctx.curclass.cl_interface then
-		(match f.cf_expr with
-		| None -> ()
-		| Some e ->
-			match e.eexpr with
-			| TConst _ -> ()
-			| TFunction fd ->
-				(match f.cf_kind with
-				| Var _ when
-						(match follow f.cf_type with
-						| TFun _
-						| TDynamic _ ->
-							true;
-						| _ ->
-							false) ->
-					newline ctx;
-					print ctx "%s::$%s = " (s_path ctx path false p) (s_ident f.cf_name);
-					gen_value ctx e
-				| Method MethDynamic ->
-					newline ctx;
-					print ctx "%s::$%s = " (s_path ctx path false p) (s_ident f.cf_name);
-					gen_value ctx e
-				| _ -> ())
-			| _ when not (is_physical_field f) ->
-				()
-			| _ ->
-				newline ctx;
-				print ctx "%s::$%s = " (s_path ctx path false p) (s_ident f.cf_name);
-				gen_value ctx e)
-
-let rec super_has_dynamic c =
-	match c.cl_super with
-	| None -> false
-	| Some (csup, _) -> (match csup.cl_dynamic with
-		| Some _ -> true
-		| _ -> super_has_dynamic csup)
-
-let generate_inline_method ctx c m =
-	(match ctx.inline_methods with
-	| [] -> ()
-	| h :: t -> ctx.inline_methods <- t
-	);
-	ctx.curclass <- c;
-
-	let old = save_locals ctx in
-	ctx.in_value <- Some m.iname;
-	ctx.in_block <- m.iin_block;
-	ctx.in_loop <- false;
-	ctx.locals <- m.ilocals;
-	ctx.inv_locals <- m.iinv_locals;
-
-	newline ctx;
-	print ctx "function %s(" m.iname;
-	(* arguments *)
-	let in_value = (match ctx.in_value with Some _ -> true | _ -> false) in
-	let arguments = remove_internals (argument_list_from_locals m.ihasthis in_value ctx.locals) in
-	let arguments = match arguments with
-	| [h] when h = "this" -> ["__hx__this"]
-	| h :: t when h = "this" -> "__hx__this" :: t
-	| _ -> arguments
-	in
-
-	let marguments = List.map (define_local ctx) m.iarguments in
-	let arguments =  (List.map (fun a -> "&$" ^ a) arguments) @ (List.map (fun a -> "$" ^ a) marguments) in
-
-	(match arguments with
-	| [] -> ()
-	| l  -> spr ctx (String.concat ", " arguments)
-	);
-	spr ctx ") {";
-	ctx.nested_loops <- ctx.nested_loops - 1;
-	let block = open_block ctx in
-	newline ctx;
-
-	gen_expr ctx m.iexpr;
-	block();
-	old();
-	ctx.nested_loops <- ctx.nested_loops + 1;
-	newline ctx;
-	spr ctx "}"
-
-let generate_class ctx c =
-	let requires_constructor = ref true in
-	ctx.curclass <- c;
-	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
-	| None -> ()
-	| Some (csup,_) ->
-		requires_constructor := false;
-		print ctx "extends %s " (s_path ctx csup.cl_path csup.cl_extern c.cl_pos));
-	(* Do not add interfaces which are implemented through other interfaces inheritance *)
-	let unique = List.filter
-		(fun (iface, _) ->
-			not (List.exists
-				(fun (probably_descendant, _) ->
-					if probably_descendant == iface then
-						false
-					else
-						is_parent iface probably_descendant
-				)
-				c.cl_implements
-			)
-		)
-		c.cl_implements
-	in
-	let implements = ExtList.List.unique ~cmp:(fun a b -> (fst a).cl_path = (fst b).cl_path) unique in
-	(match implements with
-	| [] -> ()
-	| l ->
-		spr ctx (if c.cl_interface then "extends " else "implements ");
-		concat ctx ", " (fun (i,_) ->
-		print ctx "%s" (s_path ctx i.cl_path i.cl_extern c.cl_pos)) l);
-	spr ctx "{";
-
-	let get_dynamic_methods = List.filter is_dynamic_method c.cl_ordered_fields in
-
-	if not ctx.curclass.cl_interface then ctx.dynamic_methods <- get_dynamic_methods;
-
-	let cl = open_block ctx in
-	(match c.cl_constructor with
-	| None ->
-		if !requires_constructor && not c.cl_interface then begin
-			newline ctx;
-			spr ctx "public function __construct(){}"
-		end;
-	| Some f ->
-		let f = { f with
-			cf_name = "__construct";
-			cf_public = true;
-		} in
-		ctx.constructor_block <- true;
-		generate_field ctx false f;
-		ctx.constructor_block <- false;
-	);
-
-	List.iter (generate_field ctx false) c.cl_ordered_fields;
-
-	(match c.cl_dynamic with
-		| Some _ when not c.cl_interface && not (super_has_dynamic c) ->
-			newline ctx;
-			spr ctx "public $__dynamics = array();\n\tpublic function __get($n) {\n\t\tif(isset($this->__dynamics[$n]))\n\t\t\treturn $this->__dynamics[$n];\n\t}\n\tpublic function __set($n, $v) {\n\t\t$this->__dynamics[$n] = $v;\n\t}\n\tpublic function __call($n, $a) {\n\t\tif(isset($this->__dynamics[$n]) && is_callable($this->__dynamics[$n]))\n\t\t\treturn call_user_func_array($this->__dynamics[$n], $a);\n\t\tif('toString' == $n)\n\t\t\treturn $this->__toString();\n\t\tthrow new HException(\"Unable to call <\".$n.\">\");\n\t}"
-		| Some _
-		| _ ->
-			if List.length ctx.dynamic_methods > 0 then begin
-				newline ctx;
-				spr ctx "public function __call($m, $a) {\n\t\tif(isset($this->$m) && is_callable($this->$m))\n\t\t\treturn call_user_func_array($this->$m, $a);\n\t\telse if(isset($this->__dynamics[$m]) && is_callable($this->__dynamics[$m]))\n\t\t\treturn call_user_func_array($this->__dynamics[$m], $a);\n\t\telse if('toString' == $m)\n\t\t\treturn $this->__toString();\n\t\telse\n\t\t\tthrow new HException('Unable to call <'.$m.'>');\n\t}";
-			end;
-	);
-
-	List.iter (generate_field ctx true) c.cl_ordered_statics;
-
-	let gen_props props =
-		String.concat "," (List.map (fun (p,v) -> "\"" ^ p ^ "\" => \"" ^ v ^ "\"") props)
-	in
-
-	let rec fields c =
-		let list = Codegen.get_properties (c.cl_ordered_statics @ c.cl_ordered_fields) in
-		match c.cl_super with
-		| Some (csup, _) ->
-			list @ fields csup
-		| None ->
-			list
-	in
-
-	if not c.cl_interface then (match fields c with
-		| [] ->
-			()
-		| props ->
-			newline ctx;
-			print ctx "static $__properties__ = array(%s)" (gen_props props);
-		);
-
-
-	cl();
-	newline ctx;
-
-	if PMap.exists "__toString" c.cl_fields then
-		()
-	else if PMap.exists "toString" c.cl_fields && (not c.cl_interface) && (not c.cl_extern) then begin
-		print ctx "\tfunction __toString() { return $this->toString(); }";
-		newline ctx
-	end else if (not c.cl_interface) && (not c.cl_extern) then begin
-		print ctx "\tfunction __toString() { return '%s'; }" (s_path_haxe c.cl_path) ;
-		newline ctx
-	end;
-
-	print ctx "}"
-
-
-let createmain com e =
-	let filename = match com.php_front with None -> "index.php" | Some n -> n in
-	let ctx = {
-		com = com;
-		stack = stack_init com false;
-		tabs = "";
-		ch = open_out (com.file ^ "/" ^ filename);
-		path = ([], "");
-		buf = Buffer.create (1 lsl 14);
-		in_value = None;
-		in_loop = false;
-		in_instance_method = false;
-		imports = Hashtbl.create 0;
-		extern_required_paths = [];
-		extern_classes_with_init = [];
-		curclass = null_class;
-		curmethod = "";
-		locals = PMap.empty;
-		inv_locals = PMap.empty;
-		local_types = [];
-		inits = [];
-		constructor_block = false;
-		dynamic_methods = [];
-		all_dynamic_methods = [];
-		is_call = false;
-		cwd = "";
-		inline_methods = [];
-		nested_loops = 0;
-		inline_index = 0;
-		in_block = false;
-		lib_path = match com.php_lib with None -> "lib" | Some s -> s;
-	} in
-
-	spr ctx "if(version_compare(PHP_VERSION, '5.1.0', '<')) {
-    exit('Your current PHP version is: ' . PHP_VERSION . '. Haxe/PHP generates code for version 5.1.0 or later');
-} else if(version_compare(PHP_VERSION, '5.4.0', '<')) {
-	trigger_error('Your current PHP version is: ' . PHP_VERSION . '. Code generated by Haxe/PHP might not work for versions < 5.4.0', E_USER_WARNING);
-}";
-	newline ctx;
-	newline ctx;
-	spr ctx ("require_once dirname(__FILE__).'/" ^ ctx.lib_path ^ "/php/" ^ (prefix_class com "Boot.class.php';\n\n"));
-	gen_expr ctx e;
-	newline ctx;
-	spr ctx "\n?>";
-	close ctx
-
-let generate_main ctx c =
-	(match c.cl_ordered_statics with
-	| [{ cf_expr = Some e }] ->
-		gen_value ctx e;
-	| _ -> assert false);
-		newline ctx
-
-let generate_enum ctx e =
-	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
-
-	print ctx "class %s extends Enum {" ename;
-	PMap.iter (fun _ c ->
-		newline ctx;
-		match c.ef_type with
-		| TFun (args,_) ->
-			print ctx "public static function %s($" (s_ident c.ef_name);
-			concat ctx ", $" (fun (a,o,t) ->
-				spr ctx a;
-				if o then spr ctx " = null";
-			) args;
-			spr ctx ") {";
-			print ctx " return new %s(\"%s\", %d, array($" ename (s_ident c.ef_name) c.ef_index;
-			concat ctx ", $" (fun (a,_,_) -> spr ctx a) args;
-			print ctx ")); }";
-		| _ ->
-			print ctx "public static $%s" (s_ident c.ef_name);
-	) e.e_constrs;
-	newline ctx;
-
-	spr ctx "public static $__constructors = array(";
-
-	let first = ref true in
-	PMap.iter (fun _ c ->
-		if not !first then spr ctx ", ";
-		print ctx "%d => '%s'" c.ef_index (s_ident c.ef_name);
-		first := false;
-	) e.e_constrs;
-
-	spr ctx ")";
-
-	newline ctx;
-
-	(match Codegen.build_metadata ctx.com (TEnumDecl e) with
-	| None -> ()
-	| Some _ ->
-		spr ctx "public static $__meta__";
-		newline ctx);
-
-	pack();
-
-	print ctx "}";
-
-	PMap.iter (fun _ c ->
-		match c.ef_type with
-		| TFun (args,_) ->
-			();
-		| _ ->
-			newline ctx;
-			print ctx "%s::$%s = new %s(\"%s\", %d)" ename (s_ident c.ef_name) ename c.ef_name c.ef_index;
-	) e.e_constrs;
-
-	newline ctx;
-
-	match Codegen.build_metadata ctx.com (TEnumDecl e) with
-	| None -> ()
-	| Some e ->
-		print ctx "%s::$__meta__ = " ename;
-		gen_expr ctx e;
-		newline ctx
-
-let generate com =
-	let all_dynamic_methods = ref [] in
-	let extern_classes_with_init = ref [] in
-	let php_lib_path = (match com.php_lib with None -> "lib" | Some n -> n) in
- 	create_directory com (Str.split (Str.regexp "/")  php_lib_path);
-	(* check for methods with the same name but different case *)
-	let check_class_fields c =
-		let lc_names = ref [] in
-		let special_cases = ["toString"] in
-		let loop c lst static =
-			let in_special_cases name =
-				(List.exists (fun n -> String.lowercase n = name) (special_cases @ List.map (fun f -> f.cf_name) c.cl_overrides))
-			in
-			List.iter(fun cf ->
-				let name = String.lowercase cf.cf_name in
-				let prefixed_name s = (if s then "s_" else "i_") ^ name in
-				match cf.cf_kind, cf.cf_expr with
-				| (Method _, Some e) when not (in_special_cases name) ->
-					(try
-						let lc = List.find (fun n ->
-							let n = snd n in
-							if static then
-								(n = (prefixed_name false))
-							else
-								((n = (prefixed_name false)) || (n = (prefixed_name true)))
-						) !lc_names in
-						unsupported ("method '" ^ (Globals.s_type_path c.cl_path) ^ "." ^ cf.cf_name ^ "' already exists here '" ^ (fst lc) ^ "' (different case?)") c.cl_pos
-					with Not_found ->
-						lc_names := ((Globals.s_type_path c.cl_path) ^ "." ^ cf.cf_name, prefixed_name static) :: !lc_names)
-				| _ ->
-					()
-			) lst
-		in
-		let rec _check_class_fields cl =
-			(match cl.cl_super with
-			| Some (s,_) -> _check_class_fields s
-			| _ -> ());
-			loop cl cl.cl_ordered_statics true;
-			loop cl cl.cl_ordered_fields false
-		in
-		_check_class_fields c
-	in
-	List.iter (fun t ->
-		(match t with
-		| TClassDecl c ->
-			check_class_fields c
-		| TEnumDecl e ->
-			let e_names = ref [] in
-			List.iter(fun en -> (
-				if List.exists (fun n -> n = String.lowercase en) !e_names then
-					unsupported ("'" ^ en ^ "' constructor exists with different case") e.e_pos
-				else
-					e_names := (String.lowercase en) :: !e_names
-			)) (e.e_names)
-		| _ -> ())
-	) com.types;
-	List.iter (fun t ->
-		(match t with
-		| TClassDecl c ->
-			let dynamic_methods_names lst =
-				List.map (fun fd -> {
-					mpath = c.cl_path;
-					mname = fd.cf_name;
-				}) (List.filter is_dynamic_method lst)
-			in
-			all_dynamic_methods := dynamic_methods_names c.cl_ordered_fields @ !all_dynamic_methods;
-
-			if c.cl_extern then
-				(match c.cl_init with
-				| Some _ ->
-					extern_classes_with_init := c.cl_path :: !extern_classes_with_init;
-				| _ ->
-					())
-			else
-				all_dynamic_methods := dynamic_methods_names c.cl_ordered_statics @ !all_dynamic_methods;
-		| _ -> ())
-	) com.types;
-	List.iter (Codegen.fix_abstract_inheritance com) com.types;
-	List.iter (fun t ->
-		(match t with
-		| TClassDecl c ->
-			if c.cl_extern then begin
-				(match c.cl_init with
-				| None -> ()
-				| Some e ->
-					let ctx = init com php_lib_path c.cl_path 3 in
-					gen_expr ctx e;
-					newline ctx;
-					close ctx;
-					);
-			end else
-				let ctx = init com php_lib_path c.cl_path (if c.cl_interface then 2 else 0) in
-				ctx.extern_classes_with_init <- !extern_classes_with_init;
-				ctx.all_dynamic_methods <- !all_dynamic_methods;
-
-				generate_class ctx c;
-
-				(match c.cl_init with
-				| None -> ()
-				| Some e ->
-					newline ctx;
-					gen_expr ctx e);
-				List.iter (generate_static_field_assign ctx c.cl_path) c.cl_ordered_statics;
-				if c.cl_path = (["php"], "Boot") && com.debug then begin
-					newline ctx;
-					print ctx "$%s = new _hx_array(array())" ctx.stack.Codegen.stack_var;
-					newline ctx;
-					print ctx "$%s = new _hx_array(array())" ctx.stack.Codegen.stack_exc_var;
-				end;
-
-				let rec loop l =
-					match l with
-					| [] -> ()
-					| h :: _ ->
-						generate_inline_method ctx c h;
-						loop ctx.inline_methods
-				in
-				loop ctx.inline_methods;
-				newline ctx;
-				close ctx
-		| TEnumDecl e ->
-			if e.e_extern then
-				()
-			else
-				let ctx = init com php_lib_path e.e_path 1 in
-			generate_enum ctx e;
-			close ctx
-		| TTypeDecl _ | TAbstractDecl _ ->
-			());
-	) com.types;
-	(match com.main with
-	| None -> ()
-	| Some e -> createmain com e);
-	Hashtbl.iter (fun name data ->
-		write_resource com.file name data
-	) com.resources;

+ 164 - 199
src/generators/genphp7.ml

@@ -1,5 +1,5 @@
 (**
-	Compatible with PHP 7+
+	Compatible with PHP 7.0+
 *)
 
 open Ast
@@ -184,9 +184,9 @@ let get_php_prefix ctx =
 		| Some prefix -> prefix
 		| None ->
 			let lst =
-				match ctx.php_prefix with
-					| None -> []
-					| Some str ->
+				match Common.defined_value_safe ctx Define.PhpPrefix with
+					| "" -> []
+					| str ->
 						if String.length str = 0 then
 							[]
 						else
@@ -238,20 +238,21 @@ let error_message pos message = (stringify_pos pos) ^ ": " ^ message
 (**
 	Terminates compiler process and prints user-friendly instructions about filing an issue in compiler repo.
 *)
-let fail hxpos mlpos =
+let fail ?msg hxpos mlpos =
+	let msg =
+		error_message
+			hxpos
+			(
+				(match msg with Some msg -> msg | _ -> "")
+				^ " Unexpected expression. Please submit an issue with expression example and following information:"
+			)
+	in
 	match mlpos with
 		| (file, line, _, _) ->
-			Printf.printf "%s\n" (error_message hxpos "Unexpected expression. Please submit an issue with expression example and following information:");
-			Printf.printf "%s:%d\n" file line;
+			Printf.eprintf "%s\n" msg;
+			Printf.eprintf "%s:%d\n" file line;
 			assert false
 
-(**
-	Print compilation error message and abort compilation process.
-*)
-let error_and_exit pos message =
-	Printf.printf "%s" (error_message pos message);
-	exit 1
-
 (**
 	Check if `target` is a `Dynamic` type
 *)
@@ -295,10 +296,15 @@ let is_string_type t = match follow t with TInst ({ cl_path = ([], "String") },
 *)
 let is_string expr = is_string_type expr.etype
 
+(**
+	Check if specified type represents a function
+*)
+let is_function_type t = match follow t with TFun _ -> true | _ -> false
+
 (**
 	Check if `expr` is an access to a method of special `php.PHP` class
 *)
-let is_lang_extern expr =
+let is_syntax_extern expr =
 	match expr.eexpr with
 		| TField ({ eexpr = TTypeExpr (TClassDecl { cl_path = path }) }, _) when path = syntax_type_path -> true
 		| _ -> false
@@ -361,7 +367,7 @@ let parenthesis expr = {eexpr = TParenthesis expr; etype = expr.etype; epos = ex
 	Check if `current` binary should be surrounded with parenthesis
 *)
 let need_parenthesis_for_binop current parent =
-	if current = parent then
+	if current = parent && current != OpNotEq && current != OpEq then
 		false
 	else
 		match (current, parent) with
@@ -393,7 +399,7 @@ let needs_dereferencing for_assignment expr =
 			(* some of `php.Syntax` methods *)
 			| TCall ({ eexpr = TField (_, FStatic ({ cl_path = syntax_type_path }, { cf_name = name })) }, _) ->
 				(match name with
-					| "binop" | "object" | "array" -> for_assignment
+					| "codeDeref" -> for_assignment
 					| _ -> false
 				)
 			| _ -> false
@@ -619,7 +625,7 @@ let inject_defaults (ctx:Common.context) (func:tfunc) =
 			| (_, None) :: rest -> inject rest body_exprs
 			| (_, Some TNull) :: rest -> inject rest body_exprs
 			| (var, Some const) :: rest ->
-				let expr = Codegen.set_default ctx var const func.tf_expr.epos in
+				let expr = Texpr.set_default ctx.basic var const func.tf_expr.epos in
 			 	expr :: (inject rest body_exprs)
 	in
 	let exprs =
@@ -718,10 +724,21 @@ let need_boot_equal expr1 expr2 =
 	if is_constant_null expr1 || is_constant_null expr2 then
 		false
 	else
-		(is_int expr1 && (is_float expr2 || is_unknown_type expr2.etype))
-		|| (is_float expr1 && (is_float expr2 || is_int expr2 || is_unknown_type expr2.etype))
-		|| (is_unknown_type expr1.etype && (is_int expr2 || is_float expr2))
-		|| (is_unknown_type expr1.etype && is_unknown_type expr2.etype)
+		let unknown1 = is_unknown_type expr1.etype
+		and unknown2 = is_unknown_type expr2.etype in
+		if unknown1 && unknown2 then
+			true
+		else if is_function_type expr1.etype || is_function_type expr2.etype then
+			true
+		else
+			let int1 = is_int expr1
+			and int2 = is_int expr2
+			and float1 = is_float expr1
+			and float2 = is_float expr2 in
+			(int1 && float2)
+			|| (float1 && (float2 || int2))
+			|| (unknown1 && (int2 || float2))
+			|| ((int1 || float1) && unknown2)
 
 (**
 	Adds `return` expression to block if it does not have one already
@@ -761,7 +778,7 @@ let unpack_single_expr_block expr =
 	Check if specified type has rtti meta
 *)
 let has_rtti_meta ctx mtype =
-	match Codegen.build_metadata ctx mtype with
+	match Texpr.build_metadata ctx.basic mtype with
 		| None -> false
 		| Some _ -> true
 
@@ -818,8 +835,13 @@ let is_object_declaration expr =
 	Check if `subject_arg` and `type_arg` can be generated as `$subject instanceof Type` expression.
 *)
 let instanceof_compatible (subject_arg:texpr) (type_arg:texpr) : bool =
+	let is_real_class path =
+		match path with
+			| ([], "String") | ([], "Class") | (["php";"_NativeArray"], "NativeArray_Impl_") -> false
+			| _ -> true
+	in
 	match (reveal_expr_with_parenthesis type_arg).eexpr with
-		| TTypeExpr (TClassDecl { cl_path = path }) when path <> ([], "String") && path <> ([], "Class") ->
+		| TTypeExpr (TClassDecl { cl_path = path }) when is_real_class path ->
 			let subject_arg = reveal_expr_with_parenthesis subject_arg in
 			(match subject_arg.eexpr with
 				| TLocal _ | TField _ | TCall _ | TArray _ | TConst TThis -> not (is_magic subject_arg)
@@ -1306,9 +1328,12 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 						let alias_source = ref (List.rev module_path) in
 						let get_alias_next_part () =
 							match !alias_source with
-								| [] ->  failwith ("Failed to find already used type: " ^ get_full_type_name type_path)
+								| [] ->  fail ~msg:("Failed to find already used type: " ^ get_full_type_name type_path) self#pos __POS__
 								| name :: rest ->
-									alias_source := rest;
+									alias_source := (match rest with
+										| [] -> [name]
+										| _ -> rest
+									);
 									String.capitalize name
 						and added = ref false
 						and alias = ref (get_type_name type_path) in
@@ -1350,13 +1375,13 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 				| TFun _ -> self#use ~prefix:false ([], "Closure")
 				| TAnon _ -> "object"
 				| TDynamic _ -> "mixed"
-				| TLazy _ -> failwith "TLazy not implemented"
+				| TLazy _ -> fail ~msg:"TLazy not implemented" self#pos __POS__
 				| TMono mono ->
 					(match !mono with
 						| None -> "mixed"
 						| Some t -> self#use_t t
 					)
-				| TType _ -> failwith "TType not implemented"
+				| TType _ -> fail ~msg:"TType not implemented" self#pos __POS__
 				| TAbstract (abstr, _) ->
 					match abstr.a_path with
 						| ([],"Int") -> "int"
@@ -1547,17 +1572,19 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 			Hashtbl.iter write use_table
 		(**
 			Writes array item declaration to output buffer and appends ",\n"
+			Adds indentation and ",\n" if `separate_line` is `true`.
 		*)
-		method write_array_item ?key value_expr =
+		method write_array_item ?separate_line ?key value_expr =
+			let separate_line = match separate_line with Some true -> true | _ -> false in
+			if separate_line then self#write_indentation;
 			(match key with
 				| None ->
-					self#write_indentation;
 					self#write_expr value_expr;
 				| Some key_str ->
-					self#write (indentation  ^ "\"" ^ (String.escaped key_str) ^ "\" => ");
+					self#write ("\"" ^ (String.escaped key_str) ^ "\" => ");
 					self#write_expr value_expr
 			);
-			self#write ",\n"
+			if separate_line then self#write ",\n"
 		(**
 			Writes expression to output buffer
 		*)
@@ -1584,11 +1611,14 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 					self#write ")"
 				| TObjectDecl fields -> self#write_expr_object_declaration fields
 				| TArrayDecl exprs -> self#write_expr_array_decl exprs
-				| TCall (target, [arg1; arg2]) when is_std_is target && instanceof_compatible arg1 arg2 -> self#write_expr_lang_instanceof [arg1; arg2]
-				| TCall (_, [arg]) when is_native_struct_array_cast expr && is_object_declaration arg -> self#write_assoc_array_decl arg
-				| TCall ({ eexpr = TIdent name}, args) when is_magic expr -> self#write_expr_magic name args
+				| TCall (target, [arg1; arg2]) when is_std_is target && instanceof_compatible arg1 arg2 -> self#write_expr_syntax_instanceof [arg1; arg2]
+				| TCall (_, [arg]) when is_native_struct_array_cast expr && is_object_declaration arg ->
+					(match (reveal_expr arg).eexpr with TObjectDecl fields -> self#write_assoc_array_decl fields | _ -> fail self#pos __POS__)
+				| TCall ({ eexpr = TIdent name}, args) when is_magic expr ->
+					ctx.warning ("untyped " ^ name ^ " is deprecated. Use php.Syntax instead.") self#pos;
+					self#write_expr_magic name args
 				| TCall ({ eexpr = TField (expr, access) }, args) when is_string expr -> self#write_expr_call_string expr access args
-				| TCall (expr, args) when is_lang_extern expr -> self#write_expr_call_lang_extern expr args
+				| TCall (expr, args) when is_syntax_extern expr -> self#write_expr_call_syntax_extern expr args
 				| TCall (target, args) when is_sure_var_field_access target -> self#write_expr_call (parenthesis target) args
 				| TCall (target, args) -> self#write_expr_call target args
 				| TNew (_, _, args) when is_string expr -> write_args self#write self#write_expr args
@@ -1672,35 +1702,28 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 				| _ ->
 					self#write ((self#use array_type_path) ^ "::wrap([\n");
 					self#indent_more;
-					List.iter (fun expr -> self#write_array_item expr) exprs;
+					List.iter (fun expr -> self#write_array_item ~separate_line:true expr) exprs;
 					self#indent_less;
 					self#write_indentation;
 					self#write "])"
 		(**
-			Write associative array declaration (used for NativeStructArray)
+			Write associative array declaration
 		*)
-		method write_assoc_array_decl object_decl =
-			match (reveal_expr object_decl).eexpr with
-				| TObjectDecl fields ->
-					if List.length fields = 0 then
-						self#write "[]"
-					else begin
-						self#write "[\n";
-						self#indent_more;
-						List.iter
-							(fun (name, field) ->
-								self#write_indentation;
-								self#write_const_string name;
-								self#write " => ";
-								self#write_expr field;
-								self#write ",\n"
-							)
-							fields;
-						self#indent_less;
-						self#write_indentation;
-						self#write "]";
-					end
-				| _ -> fail object_decl.epos __POS__
+		method write_assoc_array_decl fields =
+			match fields with
+				| [] -> self#write "[]"
+				| [((key, _, _), value)] ->
+					self#write "[";
+					self#write_array_item ~key:key value;
+					self#write "]"
+				| _ ->
+					self#write "[\n";
+					self#indent_more;
+					let write_field ((key,_,_), value) = self#write_array_item ~separate_line:true ~key:key value in
+					List.iter write_field fields;
+					self#indent_less;
+					self#write_indentation;
+					self#write "]"
 		(**
 			Writes TArray to output buffer
 		*)
@@ -1980,9 +2003,9 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 			@see http://old.haxe.org/doc/advanced/magic#php-magic
 		*)
 		method write_expr_magic name args =
-			let error = error_message self#pos ("Invalid arguments for " ^ name ^ " magic call") in
+			let error = ("Invalid arguments for " ^ name ^ " magic call") in
 			match args with
-				| [] -> failwith error
+				| [] -> fail ~msg:error self#pos __POS__
 				| { eexpr = TConst (TString code) } as expr :: args ->
 					(match name with
 						| "__php__" ->
@@ -1998,7 +2021,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 						| "__physeq__" ->
 							(match args with
 								| [expr2] -> self#write_expr_binop OpEq expr expr2
-								| _ -> failwith error
+								| _ -> fail ~msg:error self#pos __POS__
 							)
 						| "__var__" ->
 							(match args with
@@ -2008,20 +2031,20 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 									self#write ("$" ^ code ^ "[");
 									self#write_expr expr2;
 									self#write "]"
-								| _ -> failwith error
+								| _ -> fail ~msg:error self#pos __POS__
 							)
-						| _ -> failwith error
+						| _ -> fail ~msg:error self#pos __POS__
 					)
 				| [expr1; expr2] ->
 					(match name with
 						| "__physeq__" ->
 							(match args with
 								| [expr1; expr2] -> self#write_expr_binop OpEq expr1 expr2
-								| _ -> failwith error
+								| _ -> fail ~msg:error self#pos __POS__
 							)
-						| _ -> failwith error
+						| _ -> fail ~msg:error self#pos __POS__
 					)
-				| _ -> failwith error
+				| _ -> fail ~msg:error self#pos __POS__
 		(**
 			Writes TTypeExpr to output buffer
 		*)
@@ -2096,10 +2119,6 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 						write_method ((self#use boot_type_path) ^ "::addOrConcat")
 					else
 						write_binop " + "
-				| OpMult -> write_binop " * "
-				| OpDiv -> write_binop " / "
-				| OpSub -> write_binop " - "
-				| OpAssign -> write_binop " = "
 				| OpEq ->
 					if need_boot_equal expr1 expr2 then
 						write_method ((self#use boot_type_path) ^ "::equal")
@@ -2113,17 +2132,6 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 						end
 					else
 						write_binop " !== "
-				| OpGt -> compare " > "
-				| OpGte -> compare " >= "
-				| OpLt -> compare " < "
-				| OpLte -> compare " <= "
-				| OpAnd -> write_binop " & "
-				| OpOr -> write_binop " | "
-				| OpXor -> write_binop " ^ "
-				| OpBoolAnd -> write_binop " && "
-				| OpBoolOr -> write_binop " || "
-				| OpShl  -> write_binop " << "
-				| OpShr -> write_binop " >> "
 				| OpMod ->
 					if is_int expr1 && is_int expr2 then
 						write_binop " % "
@@ -2145,14 +2153,6 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 						end
 					else
 						write_binop " += "
-				| OpAssignOp OpMult -> write_binop " *= "
-				| OpAssignOp OpDiv -> write_binop " /= "
-				| OpAssignOp OpSub -> write_binop " -= "
-				| OpAssignOp OpAnd -> write_binop " &= "
-				| OpAssignOp OpOr -> write_binop " |= "
-				| OpAssignOp OpXor -> write_binop " ^= "
-				| OpAssignOp OpShl  -> write_binop " <<= "
-				| OpAssignOp OpShr -> write_binop " >>= "
 				| OpAssignOp OpMod ->
 					if is_int expr1 && is_int expr2 then
 						write_binop " %= "
@@ -2162,26 +2162,21 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 					self#write_expr expr1;
 					self#write " = ";
 					write_method ((self#use boot_type_path) ^ "::shiftRightUnsigned")
-				| _ -> fail self#pos __POS__
+				| OpGt | OpGte | OpLt | OpLte ->
+					compare (" " ^ (Ast.s_binop operation) ^ " ")
+				| _ ->
+					write_binop (" " ^ (Ast.s_binop operation) ^ " ")
 		(**
 			Writes TUnOp to output buffer
 		*)
 		method write_expr_unop operation flag expr =
-			let write_unop operation =
-				match operation with
-					| Increment -> self#write "++"
-					| Decrement -> self#write "--"
-					| Not -> self#write "!"
-					| Neg -> self#write "-"
-					| NegBits -> self#write "~"
-			in
 			match flag with
 				| Prefix ->
-					write_unop operation;
+					self#write (Ast.s_unop operation);
 					self#write_expr expr
 				| Postfix ->
 					self#write_expr expr;
-					write_unop operation
+					self#write (Ast.s_unop operation)
 		method private write_expr_for_field_access expr access_str field_str =
 			let access_str = ref access_str in
 			(match (reveal_expr expr).eexpr with
@@ -2357,13 +2352,9 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 			match fields with
 				| [] ->  self#write ("new " ^ (self#use hxanon_type_path) ^ "()")
 				| _ ->
-					self#write ("new " ^ (self#use hxanon_type_path)  ^ "([\n");
-					self#indent_more;
-					let write_field (key, value) = self#write_array_item ~key:key value in
-					List.iter write_field fields;
-					self#indent_less;
-					self#write_indentation;
-					self#write "])"
+					self#write ("new " ^ (self#use hxanon_type_path)  ^ "(");
+					self#write_assoc_array_decl fields;
+					self#write ")"
 		(**
 			Writes specified type to output buffer depending on type of expression.
 		*)
@@ -2382,43 +2373,40 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 		(**
 			Write language specific expression declared in `php.Syntax` extern
 		*)
-		method write_expr_call_lang_extern expr args =
+		method write_expr_call_syntax_extern expr args =
 			let name = match expr.eexpr with
 				| TField (_, FStatic (_, field)) -> field_name field
 				| _ -> fail self#pos __POS__
 			in
 			match name with
-				| "int" | "float"
-				| "string" | "bool"
-				| "object" | "array" -> self#write_expr_lang_cast name args
-				| "binop" -> self#write_expr_lang_binop args
-				| "instanceof" -> self#write_expr_lang_instanceof args
-				| "foreach" -> self#write_expr_lang_foreach args
-				| "construct" -> self#write_expr_lang_construct args
-				| "getField" -> self#write_expr_lang_get_field args
-				| "setField" -> self#write_expr_lang_set_field args
-				| "getStaticField" -> self#write_expr_lang_get_static_field args
-				| "setStaticField" -> self#write_expr_lang_set_static_field args
-				| "call" -> self#write_expr_lang_call args
-				| "staticCall" -> self#write_expr_lang_static_call args
-				| "arrayDecl" -> self#write_expr_lang_array_decl args
-				| "splat" -> self#write_expr_lang_splat args
-				| "suppress" -> self#write_expr_lang_suppress args
+				| "code" | "codeDeref" -> self#write_expr_syntax_code args
+				| "instanceof" -> self#write_expr_syntax_instanceof args
+				| "foreach" -> self#write_expr_syntax_foreach args
+				| "construct" -> self#write_expr_syntax_construct args
+				| "getField" -> self#write_expr_syntax_get_field args
+				| "setField" -> self#write_expr_syntax_set_field args
+				| "getStaticField" -> self#write_expr_syntax_get_static_field args
+				| "setStaticField" -> self#write_expr_syntax_set_static_field args
+				| "call" -> self#write_expr_syntax_call args
+				| "staticCall" -> self#write_expr_syntax_static_call args
+				| "arrayDecl" -> self#write_expr_syntax_array_decl args
+				| "assocDecl" -> self#write_expr_syntax_assoc_decl args
+				| "suppress" -> self#write_expr_syntax_suppress args
 				| "keepVar" -> ()
-				| _ -> fail self#pos __POS__
+				| _ -> ctx.error ("php.Syntax." ^ name ^ "() is not supported.") self#pos
 		(**
-			Writes splat operator (for `php.Syntax.splat()`)
+			Writes plain php code (for `php.Syntax.php()`)
 		*)
-		method write_expr_lang_splat args =
+		method write_expr_syntax_code args =
 			match args with
-				| [ args_expr ] ->
-					self#write "...";
-					self#write_expr args_expr
-				| _ -> fail self#pos __POS__
+				| [] -> fail self#pos __POS__
+				| { eexpr = TConst (TString php) } :: args ->
+					Codegen.interpolate_code ctx php args self#write self#write_expr self#pos
+				| _ -> ctx.error "First argument of php.Syntax.php() must be a constant string." self#pos
 		(**
 			Writes error suppression operator (for `php.Syntax.suppress()`)
 		*)
-		method write_expr_lang_suppress args =
+		method write_expr_syntax_suppress args =
 			match args with
 				| [ args_expr ] ->
 					self#write "@";
@@ -2427,14 +2415,22 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 		(**
 			Writes native array declaration (for `php.Syntax.arrayDecl()`)
 		*)
-		method write_expr_lang_array_decl args =
+		method write_expr_syntax_array_decl args =
 			self#write "[";
 			write_args self#write (fun e -> self#write_expr e) args;
 			self#write "]"
+		(**
+			Writes native array declaration (for `php.Syntax.arrayDecl()`)
+		*)
+		method write_expr_syntax_assoc_decl args =
+			match args with
+				| [] -> self#write_assoc_array_decl []
+				| { eexpr = TObjectDecl fields } :: [] -> self#write_assoc_array_decl fields
+				| _ -> ctx.error "php.Syntax.assocDecl() accepts object declaration only." self#pos
 		(**
 			Writes a call to instance method (for `php.Syntax.call()`)
 		*)
-		method write_expr_lang_call args =
+		method write_expr_syntax_call args =
 			match args with
 				| obj_expr :: method_expr :: args ->
 					self#write_expr obj_expr;
@@ -2447,7 +2443,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 		(**
 			Writes a call to a static method (for `php.Syntax.staticCall()`)
 		*)
-		method write_expr_lang_static_call args =
+		method write_expr_syntax_static_call args =
 			match args with
 				| type_expr :: method_expr :: args ->
 					self#write_type type_expr;
@@ -2460,7 +2456,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 		(**
 			Writes field access for reading (for `php.Syntax.getField()`)
 		*)
-		method write_expr_lang_get_field args =
+		method write_expr_syntax_get_field args =
 			match args with
 				| obj_expr :: field_expr :: [] ->
 					self#write_expr obj_expr;
@@ -2471,7 +2467,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 		(**
 			Writes field access for writing (for `php.Syntax.setField()`)
 		*)
-		method write_expr_lang_set_field args =
+		method write_expr_syntax_set_field args =
 			match args with
 				| obj_expr :: field_expr :: value_expr :: [] ->
 					self#write_expr obj_expr;
@@ -2484,7 +2480,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 		(**
 			Writes static field access for reading (for `php.Syntax.getStaticField()`)
 		*)
-		method write_expr_lang_get_static_field args =
+		method write_expr_syntax_get_static_field args =
 			match args with
 				| type_expr :: field_expr :: [] ->
 					self#write_type type_expr;
@@ -2495,7 +2491,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 		(**
 			Writes static field access for writing (for `php.Syntax.setField()`)
 		*)
-		method write_expr_lang_set_static_field args =
+		method write_expr_syntax_set_static_field args =
 			match args with
 				| type_expr :: field_expr :: value_expr :: [] ->
 					self#write_expr type_expr;
@@ -2508,7 +2504,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 		(**
 			Writes `new` expression with class name taken local variable (for `php.Syntax.construct()`)
 		*)
-		method write_expr_lang_construct args =
+		method write_expr_syntax_construct args =
 			let (class_expr, args) = match args with
 				| class_expr :: args -> (class_expr, args)
 				| _ -> fail self#pos __POS__
@@ -2518,42 +2514,10 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 			self#write "(";
 			write_args self#write (fun e -> self#write_expr e) args;
 			self#write ")"
-		(**
-			Writes native php type conversion to output buffer (e.g. `php.Syntax.int()`)
-		*)
-		method write_expr_lang_cast type_name args =
-			match args with
-				| expr :: [] ->
-					let add_parentheses = match self#parent_expr with Some e -> is_access e | None -> false
-					and expr = match expr.eexpr with
-						| TLocal e -> expr
-						| _ -> parenthesis expr
-					in
-					if add_parentheses then self#write "(";
-					self#write ("(" ^ type_name ^")");
-					self#write_expr expr;
-					if add_parentheses then self#write ")"
-				| _ -> fail self#pos __POS__
-		(**
-			Generates binary operation to output buffer (for `php.Syntax.binop()`)
-		*)
-		method write_expr_lang_binop args =
-			match args with
-				| val_expr1 :: operator_expr :: val_expr2 :: [] ->
-					let operator = match operator_expr.eexpr with
-						| TConst (TString operator) -> operator
-						| _ -> error_and_exit self#pos "Second argument for php.Syntax.binop() must be a constant string"
-					in
-					self#write "(";
-					self#write_expr val_expr1;
-					self#write (" " ^ operator ^ " ");
-					self#write_expr val_expr2;
-					self#write ")"
-				| _ -> fail self#pos __POS__
 		(**
 			Writes `instanceof` expression to output buffer (for `php.Syntax.instanceof()`)
 		*)
-		method write_expr_lang_instanceof args =
+		method write_expr_syntax_instanceof args =
 			match args with
 				| val_expr :: type_expr :: [] ->
 					self#write "(";
@@ -2571,7 +2535,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 		(**
 			Writes `foreach` expression to output buffer (for `php.Syntax.foreach()`)
 		*)
-		method write_expr_lang_foreach args =
+		method write_expr_syntax_foreach args =
 			match args with
 				| collection_expr :: { eexpr = TFunction fn } :: [] ->
 					let (key_name, value_name) = match fn.tf_args with
@@ -2589,7 +2553,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 					self#write (" as $" ^ key_name ^ " => $" ^ value_name ^ ") ");
 					self#write_as_block fn.tf_expr
 				| _ ->
-					error_and_exit self#pos "PHP.foreach() only accepts anonymous function declaration for second argument."
+					ctx.error "php.Syntax.foreach() only accepts anonymous function declaration for second argument." self#pos
 		(**
 			Writes TCall to output buffer
 		*)
@@ -2978,7 +2942,7 @@ class virtual type_builder ctx (wrapper:type_wrapper) =
 			Writes rtti meta to output buffer
 		*)
 		method write_rtti_meta =
-			match Codegen.build_metadata ctx wrapper#get_module_type with
+			match Texpr.build_metadata ctx.basic wrapper#get_module_type with
 				| None -> ()
 				| Some meta_expr ->
 					let boot_class = writer#use boot_type_path in
@@ -3102,17 +3066,27 @@ class enum_builder ctx (enm:tenum) =
 			write_args writer#write (writer#write_arg true) args;
 			writer#write ") {\n";
 			writer#indent_more;
-			writer#write_indentation;
-			writer#write "return ";
 			let index_str = string_of_int field.ef_index in
+			let write_construction args =
+				writer#write ("new " ^ self#get_name ^ "('" ^ name ^ "', " ^ index_str ^", [");
+				write_args writer#write (fun (name, _, _) -> writer#write ("$" ^ name)) args;
+				writer#write "])"
+			in
 			(match args with
-				| [] -> writer#write ((writer#use hxenum_type_path) ^ "::singleton(static::class, '" ^ name ^ "', " ^ index_str ^")")
+				| [] ->
+					(* writer#write ((writer#use hxenum_type_path) ^ "::singleton(static::class, '" ^ name ^ "', " ^ index_str ^")") *)
+					writer#write_line "static $inst = null;";
+					writer#write_indentation;
+					writer#write "if (!$inst) $inst = ";
+					write_construction [];
+					writer#write ";\n";
+					writer#write_line "return $inst;"
 				| args ->
-					writer#write ("new " ^ self#get_name ^ "('" ^ name ^ "', " ^ index_str ^", [");
-					write_args writer#write (fun (name, _, _) -> writer#write ("$" ^ name)) args;
-					writer#write "])"
+					writer#write_indentation;
+					writer#write "return ";
+					write_construction args;
+					writer#write ";\n";
 			);
-			writer#write ";\n";
 			writer#indent_less;
 			writer#write_line "}"
 		(**
@@ -3296,15 +3270,8 @@ class class_builder ctx (cls:tclass) =
 						None
 					else
 						Some {
-							cf_name = "new";
-							cf_type = TFun ([], get_void ctx);
-							cf_public = true;
-							cf_pos = cls.cl_pos;
-							cf_name_pos = cls.cl_pos;
-							cf_doc = None;
-							cf_meta = [];
+							(mk_field "new" (TFun ([], get_void ctx)) cls.cl_pos cls.cl_pos) with
 							cf_kind = Method MethNormal;
-							cf_params = [];
 							cf_expr = Some {
 								eexpr = TFunction {
 									tf_args = [];
@@ -3314,8 +3281,6 @@ class class_builder ctx (cls:tclass) =
 								epos = cls.cl_pos;
 								etype = get_void ctx;
 							};
-							cf_expr_unoptimized = None;
-							cf_overloads = [];
 						}
 		(**
 			Writes type body to output buffer.
@@ -3693,10 +3658,11 @@ class generator (ctx:context) =
 			match self#get_entry_point with
 				| None -> ()
 				| Some (uses, entry_point) ->
-					let filename = match ctx.php_front with None -> "index.php" | Some n -> n in
+					let filename = Common.defined_value_safe ~default:"index.php" ctx Define.PhpFront in
 					let channel = open_out (root_dir ^ "/" ^ filename) in
 					output_string channel "<?php\n";
 					output_string channel uses;
+					output_string channel "\n";
 					output_string channel ("set_include_path(__DIR__.'/" ^ (String.concat "/" self#get_lib_path) ^ "');\n");
 					output_string channel "spl_autoload_register(\n";
 					output_string channel "	function($class){\n";
@@ -3724,9 +3690,8 @@ class generator (ctx:context) =
 			Returns path from `index.php` to directory which will contain all generated classes
 		*)
 		method private get_lib_path : string list =
-			match ctx.php_lib with
-				| None -> ["lib"];
-				| Some path -> (Str.split (Str.regexp "/")  path)
+			let path = Common.defined_value_safe ~default:"lib" ctx Define.PhpLib in
+			(Str.split (Str.regexp "/")  path)
 		(**
 			Returns PHP code for entry point
 		*)

+ 18 - 11
src/generators/genpy.ml

@@ -21,7 +21,7 @@ open Globals
 open Ast
 open Type
 open Common
-open Codegen.ExprBuilder
+open Texpr.Builder
 
 module Utils = struct
 	let class_of_module_type mt = match mt with
@@ -430,7 +430,7 @@ module Transformer = struct
 			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
+				mk (TIf(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
@@ -1314,7 +1314,7 @@ module Printer = struct
 				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
+							if not (Expr.field_mem_assoc s fl) then fl2 := ((s,null_pos,NoQuotes),null cf.cf_type cf.cf_pos) :: !fl2
 						) an.a_fields
 					| _ ->
 						()
@@ -1426,6 +1426,8 @@ module Printer = struct
 				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)
+			| FAnon({cf_name = "length"}) | FDynamic ("length") ->
+				Printf.sprintf "HxOverrides.length(%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}) ->
@@ -1469,13 +1471,16 @@ module Printer = struct
 			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_custom_check t_str =
+					Printf.sprintf "if %s:\n%s    %s    %s" t_str indent assign (print_expr {pctx with pc_indent = "    " ^ pctx.pc_indent} e)
+				in
 				let print_type_check t_str =
-					Printf.sprintf "if isinstance(_hx_e1, %s):\n%s    %s    %s" t_str indent assign (print_expr {pctx with pc_indent = "    " ^ pctx.pc_indent} e)
+					print_custom_check ("isinstance(_hx_e1, " ^ t_str ^ ")")
 				in
 				let res = match t with
 				| "str" -> print_type_check "str"
 				| "Bool" -> print_type_check "bool"
-				| "Int" -> print_type_check "int"
+				| "Int" -> print_custom_check "(isinstance(_hx_e1, int) and not isinstance(_hx_e1, bool))" (* for historic reasons bool extends int *)
 				| "Float" -> print_type_check "float"
 				| t -> print_type_check t
 				in
@@ -1616,7 +1621,7 @@ module Printer = struct
 					"print(" ^ (print_expr pctx e) ^ ")"
 				else
 					"print(str(" ^ (print_expr pctx e) ^ "))"
-			| TField(e1,((FAnon {cf_name = (("join" | "push" | "map" | "filter") as s)}) | FDynamic (("join" | "push" | "map" | "filter") as s))), [x] ->
+			| TField(e1,((FAnon {cf_name = (("split" | "join" | "push" | "map" | "filter") as s)}) | FDynamic (("split" | "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)
@@ -1683,10 +1688,10 @@ module Printer = struct
 			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" (Ast.s_escape (handle_keywords s)) (print_expr pctx e)) fl) in
+		let args = String.concat sep (List.map (fun ((s,_,_),e) -> Printf.sprintf "'%s': %s" (Ast.s_escape (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
+		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
@@ -2153,7 +2158,7 @@ module Generator = struct
 		gen_class_init ctx c
 
 	let gen_enum_metadata ctx en p =
-		let meta = Codegen.build_metadata ctx.com (TEnumDecl en) in
+		let meta = Texpr.build_metadata ctx.com.basic (TEnumDecl en) in
 		match meta with
 			| None ->
 				()
@@ -2370,7 +2375,9 @@ module Generator = struct
 			spr ctx "class _hx_AnonObject:\n";
 			if with_body then begin
 				spr ctx "    def __init__(self, fields):\n";
-				spr ctx "        self.__dict__ = fields"
+				spr ctx "        self.__dict__ = fields\n";
+				spr ctx "    def __repr__(self):\n";
+				spr ctx "        return repr(self.__dict__)"
 			end else
 				spr ctx "    pass";
 			Hashtbl.add used_paths ([],"_hx_AnonObject") true;
@@ -2428,7 +2435,7 @@ module Generator = struct
 		gen_static_inits ctx;
 		gen_main ctx;
 
-		mkdir_from_path com.file;
+		Path.mkdir_from_path com.file;
 		let ch = open_out_bin com.file in
 		output_string ch (Buffer.contents ctx.buf);
 		close_out ch

+ 2 - 2
src/generators/genswf.ml

@@ -85,7 +85,7 @@ let build_dependencies t =
 		| TDynamic t2 ->
 			add_type_rec (t::l) t2;
 		| TLazy f ->
-			add_type_rec l ((!f)())
+			add_type_rec l (lazy_type f)
 		| TMono r ->
 			(match !r with
 			| None -> ()
@@ -638,7 +638,7 @@ let generate swf_header com =
 		{header with h_frame_count = header.h_frame_count + 1},loop tags
 	| _ -> swf in
 	(* write swf/swc *)
-	let t = Common.timer ["write";"swf"] in
+	let t = Timer.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);
 	(match swc with

+ 5 - 14
src/generators/genswf9.ml

@@ -188,7 +188,7 @@ let rec follow_basic t =
 		| Some t -> follow_basic t
 		| _ -> t)
 	| TLazy f ->
-		follow_basic (!f())
+		follow_basic (lazy_type f)
 	| TAbstract ({ a_path = [],"Null" },[tp]) ->
 		(match follow_basic tp with
 		| TMono _
@@ -1025,7 +1025,7 @@ let rec gen_expr_content ctx retval e =
 	| TParenthesis e | TMeta (_,e) ->
 		gen_expr ctx retval e
 	| TObjectDecl fl ->
-		List.iter (fun (name,e) ->
+		List.iter (fun ((name,_,_),e) ->
 			write ctx (HString (reserved name));
 			gen_expr ctx true e
 		) fl;
@@ -1788,7 +1788,7 @@ let generate_construct ctx fdata c =
 	(* if skip_constructor, then returns immediatly *)
 	if ctx.need_ctor_skip then (match c.cl_kind with
 	| KGenericInstance _ -> ()
-	| _ when not (Codegen.constructor_side_effects fdata.tf_expr) -> ()
+	| _ when not (Texpr.constructor_side_effects fdata.tf_expr) -> ()
 	| _ ->
 		let id = ident "skip_constructor" in
 		getvar ctx (VGlobal (type_path ctx (["flash"],"Boot")));
@@ -2133,18 +2133,9 @@ let generate_class ctx c =
 	let fields = if c.cl_path <> ctx.boot then fields else begin
 		{
 			hlf_name = make_name {
-				cf_name = "init";
+				(mk_field "init" (TFun ([],t_dynamic)) c.cl_pos null_pos) with
 				cf_public = ctx.swc && ctx.swf_protected;
-				cf_meta = [];
-				cf_doc = None;
-				cf_pos = c.cl_pos;
-				cf_name_pos = null_pos;
-				cf_type = TFun ([],t_dynamic);
-				cf_params = [];
-				cf_expr = None;
-				cf_expr_unoptimized = None;
 				cf_kind = Method MethNormal;
-				cf_overloads = [];
 			} false;
 			hlf_slot = 0;
 			hlf_kind = (HFMethod {
@@ -2336,7 +2327,7 @@ let rec generate_type ctx t =
 		if e.e_extern then
 			None
 		else
-			let meta = Codegen.build_metadata ctx.com t in
+			let meta = Texpr.build_metadata ctx.com.basic t in
 			let hlc = generate_enum ctx e meta in
 			let init = begin_fun ctx [] ctx.com.basic.tvoid [ethis] false e.e_pos in
 			generate_enum_init ctx e hlc meta;

Some files were not shown because too many files changed in this diff