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

Merge branch 'development'

Simon Krajewski 8 жил өмнө
parent
commit
6e3d9dcbfe
100 өөрчлөгдсөн 4750 нэмэгдсэн , 265 устгасан
  1. 5 1
      .gitignore
  2. 17 1
      .travis.yml
  3. 5 3
      Makefile
  4. 7 7
      README.md
  5. 5 1
      appveyor.yml
  6. 34 0
      extra/CHANGES.txt
  7. 7 2
      extra/ImportAll.hx
  8. 6 0
      extra/all.hxml
  9. 4 5
      extra/release-checklist.txt
  10. 4 0
      haxe.hxproj
  11. 14 5
      src/context/common.ml
  12. 5 1
      src/context/meta.ml
  13. 2 0
      src/display/displayOutput.ml
  14. 37 36
      src/generators/gencpp.ml
  15. 2 7
      src/generators/genhl.ml
  16. 3 3
      src/generators/genjs.ml
  17. 31 4
      src/generators/genphp.ml
  18. 3330 0
      src/generators/genphp7.ml
  19. 2 2
      src/generators/genpy.ml
  20. 27 1
      src/generators/hlinterp.ml
  21. 2 1
      src/macro/interp.ml
  22. 12 2
      src/main.ml
  23. 1 0
      src/optimization/analyzerConfig.ml
  24. 20 7
      src/optimization/analyzerTexpr.ml
  25. 28 20
      src/optimization/analyzerTexprTransformer.ml
  26. 1 1
      src/optimization/filters.ml
  27. 1 1
      src/optimization/optimizer.ml
  28. 14 11
      src/syntax/parser.ml
  29. 1 1
      src/typing/matcher.ml
  30. 1 0
      src/typing/typeload.ml
  31. 19 20
      src/typing/typer.ml
  32. 17 4
      std/DateTools.hx
  33. 1 7
      std/cpp/ConstPointer.hx
  34. 12 13
      std/cpp/NativeArray.hx
  35. 2 1
      std/cpp/Pointer.hx
  36. 1 1
      std/cpp/_std/haxe/ds/IntMap.hx
  37. 1 1
      std/cpp/_std/haxe/ds/StringMap.hx
  38. 2 1
      std/cpp/_std/sys/io/Process.hx
  39. 2 0
      std/cs/_std/sys/FileSystem.hx
  40. 3 1
      std/cs/_std/sys/io/Process.hx
  41. 7 0
      std/haxe/CallStack.hx
  42. 1 1
      std/haxe/Http.hx
  43. 1 1
      std/haxe/Int64.hx
  44. 4 2
      std/haxe/Log.hx
  45. 7 2
      std/haxe/Serializer.hx
  46. 1 1
      std/haxe/Timer.hx
  47. 1 0
      std/haxe/extern/AsVar.hx
  48. 2 0
      std/haxe/io/BytesData.hx
  49. 20 17
      std/haxe/io/Input.hx
  50. 3 5
      std/haxe/macro/CompilationServer.hx
  51. 1 1
      std/haxe/macro/Compiler.hx
  52. 5 3
      std/haxe/rtti/Meta.hx
  53. 8 8
      std/haxe/xml/Parser.hx
  54. 2 1
      std/hl/Api.hx
  55. 35 1
      std/hl/Bytes.hx
  56. 1 1
      std/hl/Type.hx
  57. 1 1
      std/hl/_std/String.hx
  58. 3 3
      std/hl/_std/Type.hx
  59. 8 4
      std/hl/_std/haxe/io/Bytes.hx
  60. 2 2
      std/hl/_std/sys/db/Sqlite.hx
  61. 4 0
      std/hl/_std/sys/io/File.hx
  62. 56 7
      std/hl/_std/sys/io/Process.hx
  63. 10 2
      std/hl/_std/sys/net/Socket.hx
  64. 130 0
      std/hl/_std/sys/ssl/Certificate.hx
  65. 27 0
      std/hl/_std/sys/ssl/Digest.hx
  66. 36 0
      std/hl/_std/sys/ssl/Key.hx
  67. 10 0
      std/hl/_std/sys/ssl/Lib.hx
  68. 251 0
      std/hl/_std/sys/ssl/Socket.hx
  69. 4 0
      std/hl/types/ArrayBase.hx
  70. 1 1
      std/hl/types/ArrayBytes.hx
  71. 5 1
      std/hl/types/ArrayObj.hx
  72. 9 1
      std/java/_std/sys/io/Process.hx
  73. 1 1
      std/js/html/AlignSetting.hx
  74. 56 1
      std/js/html/AnchorElement.hx
  75. 72 1
      std/js/html/Animation.hx
  76. 16 1
      std/js/html/AnimationEffectReadOnly.hx
  77. 8 1
      std/js/html/AnimationEffectTiming.hx
  78. 37 0
      std/js/html/AnimationEffectTimingProperties.hx
  79. 40 1
      std/js/html/AnimationEffectTimingReadOnly.hx
  80. 20 1
      std/js/html/AnimationEvent.hx
  81. 1 1
      std/js/html/AnimationEventInit.hx
  82. 1 1
      std/js/html/AnimationPlayState.hx
  83. 12 1
      std/js/html/AnimationTimeline.hx
  84. 1 1
      std/js/html/AppletElement.hx
  85. 1 1
      std/js/html/ApplicationCache.hx
  86. 40 1
      std/js/html/AreaElement.hx
  87. 1 1
      std/js/html/ArrayBuffer.hx
  88. 8 1
      std/js/html/ArrayBufferView.hx
  89. 8 1
      std/js/html/Attr.hx
  90. 1 1
      std/js/html/Audio.hx
  91. 1 1
      std/js/html/AudioChannel.hx
  92. 1 1
      std/js/html/AudioContextState.hx
  93. 8 1
      std/js/html/AudioElement.hx
  94. 1 1
      std/js/html/AudioStreamTrack.hx
  95. 1 1
      std/js/html/AudioTrack.hx
  96. 1 1
      std/js/html/AudioTrackList.hx
  97. 12 1
      std/js/html/BRElement.hx
  98. 1 1
      std/js/html/BarProp.hx
  99. 16 1
      std/js/html/BaseElement.hx
  100. 40 1
      std/js/html/BatteryManager.hx

+ 5 - 1
.gitignore

@@ -63,6 +63,7 @@
 /tests/unit/node_modules/
 /tests/unit/node_modules/
 
 
 /haxe.sublime*
 /haxe.sublime*
+.idea
 build.bat
 build.bat
 /.vscode
 /.vscode
 tests/unit/compile.php.hxml
 tests/unit/compile.php.hxml
@@ -73,6 +74,7 @@ tests/unit/unit.py
 tests/unit/unit.py.res1.txt
 tests/unit/unit.py.res1.txt
 tests/unit/unit.py.res2.bin
 tests/unit/unit.py.res2.bin
 tests/sys/bin/
 tests/sys/bin/
+/tests/sys/dump/
 tests/optimization/dump/
 tests/optimization/dump/
 tests/misc/projects/*/*.n
 tests/misc/projects/*/*.n
 tests/unit/bin/
 tests/unit/bin/
@@ -88,4 +90,6 @@ tests/misc/projects/Issue4070/cpp/
 /tests/misc/eventLoop/dump
 /tests/misc/eventLoop/dump
 /tests/misc/eventLoop/eventLoop.py
 /tests/misc/eventLoop/eventLoop.py
 /tests/misc/eventLoop/php
 /tests/misc/eventLoop/php
-*.vscode/
+*.vscode/
+
+/tests/sys/temp

+ 17 - 1
.travis.yml

@@ -29,7 +29,10 @@ addons: &addons
 
 
 install_linux: &install_linux
 install_linux: &install_linux
   # Install neko and haxe dependencies
   # Install neko and haxe dependencies
+  - sudo add-apt-repository ppa:haxe/ocaml -y
+  - sudo apt-get update
   - sudo apt-get install -y
   - sudo apt-get install -y
+      ocaml
       ocaml-native-compilers
       ocaml-native-compilers
       camlp4
       camlp4
       pkg-config
       pkg-config
@@ -49,10 +52,13 @@ install_linux: &install_linux
   - sudo make install
   - sudo make install
   - popd
   - popd
   # Setup database
   # Setup database
-  - travis_retry sudo apt-get install mysql-server -y
+  - travis_retry sudo apt-get install mysql-server-5.6 -y
   - mysql -u root -e "create user travis@localhost identified by '';"
   - mysql -u root -e "create user travis@localhost identified by '';"
   - mysql -u root -e "create database haxe_test;"
   - mysql -u root -e "create database haxe_test;"
   - mysql -u root -e "grant all on haxe_test.* to travis@localhost;"
   - mysql -u root -e "grant all on haxe_test.* to travis@localhost;"
+  # Setup JDK
+  - jdk_switcher use oraclejdk7
+  - java -version
   # Build haxe
   # Build haxe
   - make package_src -s
   - make package_src -s
   - make -s
   - make -s
@@ -128,6 +134,15 @@ matrix:
             g++-multilib
             g++-multilib
       install: *install_linux
       install: *install_linux
 
 
+    - os: linux
+      env:
+        - TEST=php7
+      before_install:
+        - phpenv global "7.0"
+        # - sudo apt-get install php7-cli php7-mysql php7-sqlite -y || (sudo add-apt-repository ppa:ondrej/php -y && sudo apt-get update -y && sudo apt-get install  php7.0-cli php7.0-mysql php7.0-sqlite -y)
+        - php -v || true
+      install: *install_linux
+
     #######
     #######
     # osx #
     # osx #
     #######
     #######
@@ -146,6 +161,7 @@ script:
   - eval `ssh-agent -s` # for deployment to haxe.org
   - eval `ssh-agent -s` # for deployment to haxe.org
   - pushd tests
   - pushd tests
   -   mkdir ~/haxelib && haxelib setup ~/haxelib
   -   mkdir ~/haxelib && haxelib setup ~/haxelib
+  -   haxelib install record-macros
   -   haxe -version
   -   haxe -version
   -   haxe RunCi.hxml
   -   haxe RunCi.hxml
   -   neko RunCi.n
   -   neko RunCi.n

+ 5 - 3
Makefile

@@ -58,7 +58,7 @@ MODULES=json version globals path context/meta syntax/ast display/displayTypes t
 	syntax/lexer context/common generators/genxml \
 	syntax/lexer context/common generators/genxml \
 	syntax/parser typing/abstract typing/typecore display/display optimization/optimizerTexpr \
 	syntax/parser typing/abstract typing/typecore display/display optimization/optimizerTexpr \
 	optimization/optimizer typing/overloads typing/typeload generators/codegen generators/gencommon generators/genas3 \
 	optimization/optimizer typing/overloads typing/typeload generators/codegen generators/gencommon generators/genas3 \
-	generators/gencpp generators/genjs generators/genneko generators/genphp generators/genswf9 \
+	generators/gencpp generators/genjs generators/genneko generators/genphp generators/genphp7 generators/genswf9 \
 	generators/genswf generators/genjava generators/gencs generators/genpy macro/macroApi macro/interp generators/hlcode generators/hlopt generators/hlinterp generators/hl2c \
 	generators/genswf generators/genjava generators/gencs generators/genpy macro/macroApi macro/interp generators/hlcode generators/hlopt generators/hlinterp generators/hl2c \
 	generators/genlua \
 	generators/genlua \
 	optimization/dce optimization/analyzerConfig optimization/analyzerTypes optimization/analyzerTexpr \
 	optimization/dce optimization/analyzerConfig optimization/analyzerTypes optimization/analyzerTexpr \
@@ -134,7 +134,7 @@ uninstall:
 	else \
 	else \
 		rm -rf $(INSTALL_LIB_DIR); \
 		rm -rf $(INSTALL_LIB_DIR); \
 	fi
 	fi
-	
+
 
 
 # Modules
 # Modules
 
 
@@ -180,6 +180,8 @@ src/generators/genswf.$(MODULE_EXT): src/globals.$(MODULE_EXT) src/typing/type.$
 
 
 src/generators/hlinterp.$(MODULE_EXT): src/context/common.$(MODULE_EXT) src/generators/hlcode.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/generators/hlopt.$(MODULE_EXT) src/macro/macroApi.$(MODULE_EXT)
 src/generators/hlinterp.$(MODULE_EXT): src/context/common.$(MODULE_EXT) src/generators/hlcode.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/generators/hlopt.$(MODULE_EXT) src/macro/macroApi.$(MODULE_EXT)
 
 
+src/generators/genphp7.$(MODULE_EXT): src/typing/abstract.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/context/meta.$(MODULE_EXT) src/path.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/context/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
+
 src/generators/hl2c.$(MODULE_EXT): src/generators/hlcode.$(MODULE_EXT)
 src/generators/hl2c.$(MODULE_EXT): src/generators/hlcode.$(MODULE_EXT)
 
 
 src/generators/hlopt.$(MODULE_EXT): src/generators/hlcode.$(MODULE_EXT)
 src/generators/hlopt.$(MODULE_EXT): src/generators/hlcode.$(MODULE_EXT)
@@ -249,7 +251,7 @@ src/typing/typer.$(MODULE_EXT): src/typing/abstract.$(MODULE_EXT) src/context/me
 
 
 # main
 # main
 
 
-src/main.$(MODULE_EXT): src/context/meta.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/typing/error.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/path.$(MODULE_EXT) src/optimization/filters.$(MODULE_EXT) src/typing/matcher.$(MODULE_EXT) src/typing/typer.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/generators/genxml.$(MODULE_EXT) src/generators/genswf.$(MODULE_EXT) src/generators/genphp.$(MODULE_EXT) src/generators/genneko.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT) src/generators/genlua.$(MODULE_EXT) src/generators/gencpp.$(MODULE_EXT) src/generators/genas3.$(MODULE_EXT) src/context/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/generators/genjava.$(MODULE_EXT) src/generators/gencs.$(MODULE_EXT) src/generators/genpy.$(MODULE_EXT) src/generators/genhl.$(MODULE_EXT) src/display/display.$(MODULE_EXT) src/server.$(MODULE_EXT) src/display/displayOutput.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
+src/main.$(MODULE_EXT): src/context/meta.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/typing/error.$(MODULE_EXT) src/globals.$(MODULE_EXT) src/path.$(MODULE_EXT) src/optimization/filters.$(MODULE_EXT) src/typing/matcher.$(MODULE_EXT) src/typing/typer.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/generators/genxml.$(MODULE_EXT) src/generators/genswf.$(MODULE_EXT) src/generators/genphp.$(MODULE_EXT) src/generators/genphp7.$(MODULE_EXT) src/generators/genneko.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT) src/generators/genlua.$(MODULE_EXT) src/generators/gencpp.$(MODULE_EXT) src/generators/genas3.$(MODULE_EXT) src/context/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/generators/genjava.$(MODULE_EXT) src/generators/gencs.$(MODULE_EXT) src/generators/genpy.$(MODULE_EXT) src/generators/genhl.$(MODULE_EXT) src/display/display.$(MODULE_EXT) src/server.$(MODULE_EXT) src/display/displayOutput.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
 
 
 src/globals.$(MODULE_EXT): src/version.$(MODULE_EXT)
 src/globals.$(MODULE_EXT): src/version.$(MODULE_EXT)
 
 

+ 7 - 7
README.md

@@ -40,15 +40,15 @@ For the complete Haxe licenses, please see https://haxe.org/foundation/open-sour
 
 
 ## Installing Haxe
 ## Installing Haxe
 
 
-The latest stable release is [Haxe 3.4.0-rc.1](https://haxe.org/download/version/3.4.0-rc.1/). Pre-built binaries are available for your platform:
+The latest stable release is [Haxe 3.4.0-rc.2](https://haxe.org/download/version/3.4.0-rc.2/). Pre-built binaries are available for your platform:
 
 
- * **[Windows installer](https://haxe.org/download/file/3.4.0-rc.1/haxe-3.4.0-rc.1-win.exe)**
- * **[Windows binaries](https://haxe.org/download/file/3.4.0-rc.1/haxe-3.4.0-rc.1-win.zip)**
- * **[OSX installer](https://haxe.org/download/file/3.4.0-rc.1/haxe-3.4.0-rc.1-osx-installer.pkg)**
- * **[OSX binaries](https://haxe.org/download/file/3.4.0-rc.1/haxe-3.4.0-rc.1-osx.tar.gz)**
+ * **[Windows installer](https://haxe.org/download/file/3.4.0-rc.2/haxe-3.4.0-rc.2-win.exe)**
+ * **[Windows binaries](https://haxe.org/download/file/3.4.0-rc.2/haxe-3.4.0-rc.2-win.zip)**
+ * **[OSX installer](https://haxe.org/download/file/3.4.0-rc.2/haxe-3.4.0-rc.2-osx-installer.pkg)**
+ * **[OSX binaries](https://haxe.org/download/file/3.4.0-rc.2/haxe-3.4.0-rc.2-osx.tar.gz)**
  * **[Linux Software Packages](https://haxe.org/download/linux)**
  * **[Linux Software Packages](https://haxe.org/download/linux)**
- * **[Linux 32-bit binaries](https://haxe.org/download/file/3.4.0-rc.1/haxe-3.4.0-rc.1-linux32.tar.gz)**
- * **[Linux 64-bit binaries](https://haxe.org/download/file/3.4.0-rc.1/haxe-3.4.0-rc.1-linux64.tar.gz)**
+ * **[Linux 32-bit binaries](https://haxe.org/download/file/3.4.0-rc.2/haxe-3.4.0-rc.2-linux32.tar.gz)**
+ * **[Linux 64-bit binaries](https://haxe.org/download/file/3.4.0-rc.2/haxe-3.4.0-rc.2-linux64.tar.gz)**
 
 
 Automated development builds are available from [build.haxe.org](http://build.haxe.org).
 Automated development builds are available from [build.haxe.org](http://build.haxe.org).
 
 

+ 5 - 1
appveyor.yml

@@ -10,7 +10,7 @@ environment:
         MYSQL_USER: root
         MYSQL_USER: root
         MYSQL_PASSWORD: Password12!
         MYSQL_PASSWORD: Password12!
     matrix:
     matrix:
-        - TEST: "neko,python,cs,java,macro"
+        - TEST: "neko,python,cs,java,macro,php7"
         - TEST: "cpp"
         - TEST: "cpp"
 
 
 services:
 services:
@@ -36,6 +36,10 @@ install:
     - '%CYG_ROOT%/bin/bash -lc "opam install camlp4 --yes"'
     - '%CYG_ROOT%/bin/bash -lc "opam install camlp4 --yes"'
     # Install neko
     # Install neko
     - choco install neko --prerelease --ignore-dependencies -s 'https://ci.appveyor.com/nuget/neko' -y
     - choco install neko --prerelease --ignore-dependencies -s 'https://ci.appveyor.com/nuget/neko' -y
+    - choco install php --ignore-dependencies
+    - echo extension=php_mysqli.dll >> C:\tools\php\php.ini
+    - echo extension=php_sqlite3.dll >> C:\tools\php\php.ini
+    - echo extension=php_openssl.dll >> C:\tools\php\php.ini
     - RefreshEnv
     - RefreshEnv
     # do not use chocolatey's shim, which is buggy when processing arguments
     # do not use chocolatey's shim, which is buggy when processing arguments
     # see https://github.com/chocolatey/shimgen/issues/27
     # see https://github.com/chocolatey/shimgen/issues/27

+ 34 - 0
extra/CHANGES.txt

@@ -1,3 +1,37 @@
+2016-12-24: 3.4.0-RC2
+
+	New features:
+
+	js : added API documentation to HTML externs (#5868)
+	php : added php7 target, enabled with -D php7
+
+	Bugfixes:
+
+	all : fixed top-down inference infinite recursion issue (#5848)
+	all : fixed regression in Compiler.include (#5847)
+	all : fixed Not_found exception related to try/catch (#5851)
+	all : fixed metadata completion showing up in trace arguments (#5775)
+	all : fixed problem with useless pattern detection (#5873)
+	all : fixed issue with toString handling in trace arguments (#5858)
+	all : fixed inline constructor scoping (#5855)
+	cpp : fixed issue with cpp.Pointer variables being eliminated (#5850)
+	js : added Notification API to HTML externs (#5852)
+	js : fixed several options structures in HTML externs (#5849)
+	php/cs : FileSystem.deleteFile() and FileSystem.deleteDirectory() now throw on non-existent path (#5742)
+	php/lua : fixed field access on `null` (#4988)
+	php : fixed static field access on a `Class<T>` stored to a field (#5383)
+	php : fixed invalid detection of `NativeArray` by `Std.is()` (#5565)
+	php : fixed `stdin()`, `stdout()`, `stderr()` of `Sys` to use predefined constants for corresponding channels (#5733)
+	php : fixed Std.parseInt() on hexstrings for PHP7+ (#5521)
+	php : fixed typed cast in assign operations (#5135)
+	php : fixed exception thrown by `Reflect.fields(o)` when `o` is `Class<T>` (#5608)
+	php : fixed json encoding of empty objects (#5015)
+	php : fixed checking floats for equality (#4260)
+	php : throw if invalid json string supplied to Json.parse() (#4592)
+	php : fixed ssl connections (#4581)
+	php : fixed writing bytes containing zero byte to MySQL & SQLite (#4489)
+	php : fixed call()() cases for PHP5 (#5569)
+
 2016-11-29: 3.4.0-RC1
 2016-11-29: 3.4.0-RC1
 
 
 	New features:
 	New features:

+ 7 - 2
extra/ImportAll.hx

@@ -29,8 +29,10 @@ class ImportAll {
 			haxe.macro.Compiler.define("doc_gen");
 			haxe.macro.Compiler.define("doc_gen");
 		}
 		}
 		switch( pack ) {
 		switch( pack ) {
+		case "php7":
+			if( !Context.defined("php7") ) return;
 		case "php":
 		case "php":
-			if( !Context.defined("php") ) return;
+			if( !Context.defined("php") || Context.defined("php7") ) return;
 		case "neko":
 		case "neko":
 			if( !Context.defined("neko") ) return;
 			if( !Context.defined("neko") ) return;
 		case "js":
 		case "js":
@@ -71,7 +73,7 @@ class ImportAll {
 				if( file == ".svn" || file == "_std" )
 				if( file == ".svn" || file == "_std" )
 					continue;
 					continue;
 				var full = (pack == "") ? file : pack + "." + file;
 				var full = (pack == "") ? file : pack + "." + file;
-				if( StringTools.endsWith(file, ".hx") && file.indexOf(".") < 0 ) {
+				if( StringTools.endsWith(file, ".hx") && file.substr(0, file.length - 3).indexOf(".") < 0 ) {
 					var cl = full.substr(0, full.length - 3);
 					var cl = full.substr(0, full.length - 3);
 					switch( cl ) {
 					switch( cl ) {
 					case "ImportAll", "neko.db.MacroManager": continue;
 					case "ImportAll", "neko.db.MacroManager": continue;
@@ -83,6 +85,9 @@ class ImportAll {
 					case "haxe.remoting.SyncSocketConnection": if( !(Context.defined("neko") || Context.defined("php") || Context.defined("cpp")) ) 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;
 					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);
+					}
 					Context.getModule(cl);
 					Context.getModule(cl);
 				} else if( sys.FileSystem.isDirectory(p + "/" + file) )
 				} else if( sys.FileSystem.isDirectory(p + "/" + file) )
 					run(full);
 					run(full);

+ 6 - 0
extra/all.hxml

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

+ 4 - 5
extra/release-checklist.txt

@@ -20,14 +20,13 @@
 
 
 # Making the release
 # Making the release
 
 
-- Copy relevant changelog part to CHANGES.md.
+- Copy relevant changelog part to downloads/$version/CHANGES.md.
 - Write announcement post.
 - Write announcement post.
-- Copy announcement post to RELEASE.md.
-- Update versions.json
-- Push the generated binaries and installers to haxe.org.
+- Copy announcement post to downloads/$version/RELEASE.md.
+- Update downloads/versions.json
+- Push the generated binaries and installers to haxe.org, requires git-lfs
 
 
 # Announcing the release
 # Announcing the release
 
 
 - Regenerate and upload API documentation (check --title and -D version values).
 - Regenerate and upload API documentation (check --title and -D version values).
-- Update http://haxe.org/file/CHANGES.txt
 - Post announcement post to haxelang.
 - Post announcement post to haxelang.

+ 4 - 0
haxe.hxproj

@@ -416,6 +416,10 @@
     <hidden path="src\macro\macroApi.cmt" />
     <hidden path="src\macro\macroApi.cmt" />
     <hidden path="src\macro\macroApi.cmx" />
     <hidden path="src\macro\macroApi.cmx" />
     <hidden path="src\macro\macroApi.o" />
     <hidden path="src\macro\macroApi.o" />
+    <hidden path="src\generators\genphp7.cmi" />
+    <hidden path="src\generators\genphp7.cmt" />
+    <hidden path="src\generators\genphp7.cmx" />
+    <hidden path="src\generators\genphp7.o" />
   </hiddenPaths>
   </hiddenPaths>
   <!-- Executed before build -->
   <!-- Executed before build -->
   <preBuildCommand>make -j4 FD_OUTPUT=1 -f Makefile.win kill haxe</preBuildCommand>
   <preBuildCommand>make -j4 FD_OUTPUT=1 -f Makefile.win kill haxe</preBuildCommand>

+ 14 - 5
src/context/common.ml

@@ -23,6 +23,7 @@ open Globals
 
 
 type package_rule =
 type package_rule =
 	| Forbidden
 	| Forbidden
+	| Directory of string
 	| Remap of string
 	| Remap of string
 
 
 type pos = Globals.pos
 type pos = Globals.pos
@@ -315,6 +316,8 @@ let get_signature com =
 		com.defines_signature <- Some s;
 		com.defines_signature <- Some s;
 		s
 		s
 
 
+let php7 com = com.platform = Php && PMap.exists "php7" com.defines
+
 module CompilationServer = struct
 module CompilationServer = struct
 	type cache = {
 	type cache = {
 		c_haxelib : (string list, string list) Hashtbl.t;
 		c_haxelib : (string list, string list) Hashtbl.t;
@@ -704,11 +707,17 @@ let get_config com =
 			pf_reserved_type_paths = [([],"Object");([],"Error")];
 			pf_reserved_type_paths = [([],"Object");([],"Error")];
 		}
 		}
 	| Php ->
 	| Php ->
-		{
-			default_config with
-			pf_static = false;
-			pf_pad_nulls = true;
-		}
+		if php7 com then
+			{
+				default_config with
+				pf_static = false;
+			}
+		else
+			{
+				default_config with
+				pf_static = false;
+				pf_pad_nulls = true;
+			}
 	| Cpp ->
 	| Cpp ->
 		{
 		{
 			default_config with
 			default_config with

+ 5 - 1
src/context/meta.ml

@@ -117,6 +117,8 @@ type strict_meta =
 	| Overload
 	| Overload
 	| PhpConstants
 	| PhpConstants
 	| PhpGlobal
 	| PhpGlobal
+	| PhpClassConst
+	| PhpMagic
 	| PrivateAccess
 	| PrivateAccess
 	| Property
 	| Property
 	| Protected
 	| Protected
@@ -307,7 +309,9 @@ let get_info = function
 	| Optional -> ":optional",("Marks the field of a structure as optional",[UsedOn TClassField])
 	| 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])
 	| 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])
 	| PhpConstants -> ":phpConstants",("Marks the static fields of a class as PHP constants, without $",[Platform Php;UsedOn TClass])
-	| PhpGlobal -> ":phpGlobal",("Puts the static fields of a class in the global PHP namespace",[Platform Php;UsedOn TClass])
+	| PhpGlobal -> ":phpGlobal",("(php7) Puts the static fields of a class in the global PHP namespace",[Platforms [Php;Php];UsedOn TClass])
+	| PhpClassConst -> ":phpClassConst",("(php7)  Generate static var of an extern class as a PHP class constant",[Platform Php;UsedOn TClass])
+	| PhpMagic -> ":phpMagic",("(php7) Treat annotated field as special PHP magic field",[Platform Php;UsedOn TClassField])
 	| Public -> ":public",("Marks a class field as being public",[UsedOn TClassField;UsedInternally])
 	| 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])
 	| 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])
 	| QuotedField -> ":quotedField",("Used internally to mark structure fields which are quoted in syntax",[UsedInternally])

+ 2 - 0
src/display/displayOutput.ml

@@ -247,6 +247,7 @@ module TypePathHandler = struct
 			| x :: l ->
 			| x :: l ->
 				(try
 				(try
 					match PMap.find x com.package_rules with
 					match PMap.find x com.package_rules with
+					| Directory d -> d :: l
 					| Remap s -> s :: l
 					| Remap s -> s :: l
 					| _ -> p
 					| _ -> p
 				with
 				with
@@ -267,6 +268,7 @@ module TypePathHandler = struct
 									match PMap.find f com.package_rules with
 									match PMap.find f com.package_rules with
 									| Forbidden -> ()
 									| Forbidden -> ()
 									| Remap f -> packages := f :: !packages
 									| Remap f -> packages := f :: !packages
+									| Directory _ -> raise Not_found
 								with Not_found ->
 								with Not_found ->
 									packages := f :: !packages
 									packages := f :: !packages
 						else
 						else

+ 37 - 36
src/generators/gencpp.ml

@@ -1325,36 +1325,31 @@ let strip_file ctx file = (match Common.defined ctx Common.Define.AbsolutePath w
 ;;
 ;;
 
 
 let hx_stack_push ctx output clazz func_name pos gc_stack =
 let hx_stack_push ctx output clazz func_name pos gc_stack =
-   let has_stackframe = ref false in
    if ctx.ctx_debug_level > 0 then begin
    if ctx.ctx_debug_level > 0 then begin
       let stripped_file = strip_file ctx.ctx_common pos.pfile in
       let stripped_file = strip_file ctx.ctx_common pos.pfile in
       let esc_file = (Ast.s_escape stripped_file) in
       let esc_file = (Ast.s_escape stripped_file) in
       ctx.ctx_file_info := PMap.add stripped_file pos.pfile !(ctx.ctx_file_info);
       ctx.ctx_file_info := PMap.add stripped_file pos.pfile !(ctx.ctx_file_info);
-      if (ctx.ctx_debug_level>0) then begin
-         let full_name = clazz ^ "." ^ func_name ^ (
-           if (clazz="*") then
-             (" (" ^ esc_file ^ ":" ^ (string_of_int (Lexer.get_error_line pos) ) ^ ")")
-           else "") in
-
-         let hash_class_func = gen_hash 0 (clazz^"."^func_name) in
-         let hash_file = gen_hash 0 stripped_file in
-
-         let lineName  = (string_of_int (Lexer.get_error_line pos) ) in
-         incr ctx.ctx_file_id;
-         let classId = hash64 (clazz ^ "." ^ stripped_file) in
-         let varName = "_hx_pos_" ^ classId ^ "_" ^ lineName ^ "_" ^func_name in
-         let decl = ( varName ^ ",\"" ^ clazz ^ "\",\"" ^ func_name ^ "\"," ^ hash_class_func ^ ",\"" ^
-                 full_name ^ "\",\"" ^ esc_file ^ "\"," ^ lineName ^  "," ^ hash_file ) in
-         if ctx.ctx_is_header then
-            ctx.ctx_writer#write_h_unique ("HX_DECLARE_STACK_FRAME" ^ "(" ^ varName ^ ")\n")
-         else
-            ctx.ctx_writer#write_h_unique ("HX_DEFINE_STACK_FRAME" ^ "(" ^ decl ^ ")\n");
-         output ( (if gc_stack then "HX_GC_STACKFRAME" else "HX_STACKFRAME") ^ "(&" ^ varName ^ ")\n");
-         has_stackframe := true;
-      end
-   end;
-   if gc_stack && not !has_stackframe then
-      output ("HX_JUST_GC_STACKFRAME\n");
+      let full_name = clazz ^ "." ^ func_name ^ (
+        if (clazz="*") then
+          (" (" ^ esc_file ^ ":" ^ (string_of_int (Lexer.get_error_line pos) ) ^ ")")
+        else "") in
+
+      let hash_class_func = gen_hash 0 (clazz^"."^func_name) in
+      let hash_file = gen_hash 0 stripped_file in
+
+      let lineName  = (string_of_int (Lexer.get_error_line pos) ) in
+      incr ctx.ctx_file_id;
+      let classId = hash64 (clazz ^ "." ^ stripped_file) in
+      let varName = "_hx_pos_" ^ classId ^ "_" ^ lineName ^ "_" ^func_name in
+      let decl = ( varName ^ ",\"" ^ clazz ^ "\",\"" ^ func_name ^ "\"," ^ hash_class_func ^ ",\"" ^
+              full_name ^ "\",\"" ^ esc_file ^ "\"," ^ lineName ^  "," ^ hash_file ) in
+      if ctx.ctx_is_header then
+         ctx.ctx_writer#write_h_unique ("HX_DECLARE_STACK_FRAME" ^ "(" ^ varName ^ ")\n")
+      else
+         ctx.ctx_writer#write_h_unique ("HX_DEFINE_STACK_FRAME" ^ "(" ^ decl ^ ")\n");
+      output ( (if gc_stack then "HX_GC_STACKFRAME" else "HX_STACKFRAME") ^ "(&" ^ varName ^ ")\n");
+   end else if gc_stack then
+      output ("HX_JUST_GC_STACKFRAME\n")
 ;;
 ;;
 
 
 
 
@@ -2972,7 +2967,8 @@ let retype_expression ctx request_type function_args expression_tree forInjectio
                baseCpp.cppexpr, baseCpp.cpptype (* nothing to do *)
                baseCpp.cppexpr, baseCpp.cpptype (* nothing to do *)
             else (match return_type with
             else (match return_type with
                | TCppObjC(k) -> CppCastObjC(baseCpp,k), return_type
                | TCppObjC(k) -> CppCastObjC(baseCpp,k), return_type
-               | TCppInst(k) -> CppCast(baseCpp,return_type), return_type
+               | TCppPointer(_,_)
+               | TCppInst(_) -> CppCast(baseCpp,return_type), return_type
                | TCppString -> CppCastScalar(baseCpp,"::String"), return_type
                | TCppString -> CppCastScalar(baseCpp,"::String"), return_type
                | TCppCode(t) when baseStr <> (tcpp_to_string t)  ->
                | TCppCode(t) when baseStr <> (tcpp_to_string t)  ->
                      CppCast(baseCpp, t),  t
                      CppCast(baseCpp, t),  t
@@ -3924,8 +3920,8 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args injection
 
 
       let prologue = function gc_stack ->
       let prologue = function gc_stack ->
           cpp_gen_default_values ctx closure.close_args "__o_";
           cpp_gen_default_values ctx closure.close_args "__o_";
+          hx_stack_push ctx output_i class_name func_name closure.close_expr.cpppos gc_stack;
           if (ctx.ctx_debug_level>0) then begin
           if (ctx.ctx_debug_level>0) then begin
-             hx_stack_push ctx output_i class_name func_name closure.close_expr.cpppos gc_stack;
              if (closure.close_this != None) then
              if (closure.close_this != None) then
                 output_i ("HX_STACK_THIS(__this.mPtr)\n");
                 output_i ("HX_STACK_THIS(__this.mPtr)\n");
              List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (cpp_var_name_of v) ^ ",\"" ^ (cpp_debug_name_of v) ^"\")\n") )
              List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (cpp_var_name_of v) ^ ",\"" ^ (cpp_debug_name_of v) ^"\")\n") )
@@ -3955,11 +3951,11 @@ let gen_cpp_function_body ctx clazz is_static func_name function_def head_code t
    let dot_name = join_class_path clazz.cl_path "." in
    let dot_name = join_class_path clazz.cl_path "." in
    if no_debug then ctx.ctx_debug_level <- 0;
    if no_debug then ctx.ctx_debug_level <- 0;
    let prologue = function gc_stack ->
    let prologue = function gc_stack ->
-      let spacer = "            \t" in
+      let spacer = if no_debug then "\t" else "            \t" in
       let output_i = fun s -> output (spacer ^ s) in
       let output_i = fun s -> output (spacer ^ s) in
       ctx_default_values ctx function_def.tf_args "__o_";
       ctx_default_values ctx function_def.tf_args "__o_";
+      hx_stack_push ctx output_i dot_name func_name function_def.tf_expr.epos gc_stack;
       if ctx.ctx_debug_level >0 then begin
       if ctx.ctx_debug_level >0 then begin
-         hx_stack_push ctx output_i dot_name func_name function_def.tf_expr.epos gc_stack;
          if (not is_static)
          if (not is_static)
             then output_i ("HX_STACK_THIS(" ^ (if ctx.ctx_real_this_ptr then "this" else "__this") ^")\n");
             then output_i ("HX_STACK_THIS(" ^ (if ctx.ctx_real_this_ptr then "this" else "__this") ^")\n");
          List.iter (fun (v,_) -> if not (cpp_no_debug_synbol ctx v) then
          List.iter (fun (v,_) -> if not (cpp_no_debug_synbol ctx v) then
@@ -3977,11 +3973,9 @@ let gen_cpp_function_body ctx clazz is_static func_name function_def head_code t
 let gen_cpp_init ctx dot_name func_name var_name expr =
 let gen_cpp_init ctx dot_name func_name var_name expr =
    let output = ctx.ctx_output in
    let output = ctx.ctx_output in
    let prologue = function gc_stack ->
    let prologue = function gc_stack ->
-      if ctx.ctx_debug_level >0 then begin
-      let spacer = "            \t" in
+      let spacer = if ctx.ctx_debug_level > 0 then "            \t" else "\t" in
       let output_i = fun s -> output (spacer ^ s) in
       let output_i = fun s -> output (spacer ^ s) in
          hx_stack_push ctx output_i dot_name func_name expr.epos gc_stack;
          hx_stack_push ctx output_i dot_name func_name expr.epos gc_stack;
-      end
    in
    in
    let injection = mk_injection prologue var_name "" in
    let injection = mk_injection prologue var_name "" in
    gen_cpp_ast_expression_tree ctx dot_name func_name [] injection (mk_block expr);
    gen_cpp_ast_expression_tree ctx dot_name func_name [] injection (mk_block expr);
@@ -5082,8 +5076,11 @@ let access_str a = match a with
    | AccRequire(_,_) -> "AccRequire" ;;
    | AccRequire(_,_) -> "AccRequire" ;;
 
 
 
 
-let script_type t optional = if optional then "Object" else
+let script_type t optional = if optional then begin
    match type_string t with
    match type_string t with
+   | "::String" -> "String"
+   | _ -> "Object"
+   end else match type_string t with
    | "bool" -> "Int"
    | "bool" -> "Int"
    | "int" -> "Int"
    | "int" -> "Int"
    | "Float" -> "Float"
    | "Float" -> "Float"
@@ -6534,6 +6531,7 @@ type cppia_op =
 	| IaToInterfaceArray
 	| IaToInterfaceArray
 	| IaFun
 	| IaFun
 	| IaCast
 	| IaCast
+	| IaTCast
 	| IaBlock
 	| IaBlock
 	| IaBreak
 	| IaBreak
 	| IaContinue
 	| IaContinue
@@ -6738,6 +6736,7 @@ let cppia_op_info = function
 	| IaBinOp OpAssignOp OpLt
 	| IaBinOp OpAssignOp OpLt
 	| IaBinOp OpAssignOp OpAssignOp _
 	| IaBinOp OpAssignOp OpAssignOp _
 	| IaBinOp OpAssignOp OpArrow -> assert false
 	| IaBinOp OpAssignOp OpArrow -> assert false
+	| IaTCast -> ("TCAST", 221)
 ;;
 ;;
 
 
 class script_writer ctx filename asciiOut =
 class script_writer ctx filename asciiOut =
@@ -7217,8 +7216,10 @@ class script_writer ctx filename asciiOut =
             this#write "\n";
             this#write "\n";
             this#gen_expression catch_expr;
             this#gen_expression catch_expr;
          ) catches;
          ) catches;
-   | TCast (cast,None) -> this#checkCast expression.etype cast true true;
-   | TCast (cast,Some _) -> this#checkCast expression.etype cast true true;
+   | TCast (cast,Some (TClassDecl t)) ->
+         this#write ((this#op IaTCast) ^ (this#typeText (TInst(t,[])) ) ^ "\n");
+         this#gen_expression cast;
+   | TCast (cast,_) -> this#checkCast expression.etype cast true true;
    | TParenthesis _ -> abort "Unexpected parens" expression.epos
    | TParenthesis _ -> abort "Unexpected parens" expression.epos
    | TMeta(_,_) -> abort "Unexpected meta" expression.epos
    | TMeta(_,_) -> abort "Unexpected meta" expression.epos
    );
    );

+ 2 - 7
src/generators/genhl.ml

@@ -2820,12 +2820,7 @@ and make_fun ?gen_content ctx name fidx f cthis cparent =
 				op ctx (OBool (tmp, b));
 				op ctx (OBool (tmp, b));
 				op ctx (OToDyn (r, tmp));
 				op ctx (OToDyn (r, tmp));
 			| TString s ->
 			| TString s ->
-				let str, len = to_utf8 s f.tf_expr.epos in
-				let rb = alloc_tmp ctx HBytes in
-				op ctx (ONew r);
-				op ctx (OString (rb,alloc_string ctx str));
-				op ctx (OSetField (r,0,rb));
-				op ctx (OSetField (r,1,reg_int ctx len));
+				op ctx (OMov (r, make_string ctx s f.tf_expr.epos))
 			);
 			);
 			j();
 			j();
 		);
 		);
@@ -3530,7 +3525,7 @@ let add_types ctx types =
 						match f.cf_kind with
 						match f.cf_kind with
 						| Method MethNormal when not (List.exists (fun (m,_,_) -> m = Meta.Custom ":hlNative") f.cf_meta) ->
 						| Method MethNormal when not (List.exists (fun (m,_,_) -> m = Meta.Custom ":hlNative") f.cf_meta) ->
 							(match f.cf_expr with
 							(match f.cf_expr with
-							| Some { eexpr = TFunction { tf_expr = { eexpr = TBlock ([] | [{ eexpr = TReturn (Some { eexpr = TConst _ })}]) } } } ->
+							| Some { eexpr = TFunction { tf_expr = { eexpr = TBlock ([] | [{ eexpr = TReturn (Some { eexpr = TConst _ })}]) } } } | None ->
 								let name = prefix ^ String.lowercase (Str.global_replace (Str.regexp "[A-Z]+") "_\\0" f.cf_name) in
 								let name = prefix ^ String.lowercase (Str.global_replace (Str.regexp "[A-Z]+") "_\\0" f.cf_name) in
 								f.cf_meta <- (Meta.Custom ":hlNative", [(EConst (String lib),p);(EConst (String name),p)], p) :: f.cf_meta;
 								f.cf_meta <- (Meta.Custom ":hlNative", [(EConst (String lib),p);(EConst (String name),p)], p) :: f.cf_meta;
 							| _ -> ())
 							| _ -> ())

+ 3 - 3
src/generators/genjs.ml

@@ -650,7 +650,7 @@ and gen_expr ctx e =
 	| TObjectDecl fields ->
 	| TObjectDecl fields ->
 		spr ctx "{ ";
 		spr ctx "{ ";
 		concat ctx ", " (fun (f,e) -> (match e.eexpr with
 		concat ctx ", " (fun (f,e) -> (match e.eexpr with
-			| TMeta((Meta.QuotedField,_,_),e) -> print ctx "'%s' : " (Ast.s_escape f);
+			| TMeta((Meta.QuotedField,_,_),e) -> print ctx "\"%s\" : " (Ast.s_escape f);
 			| _ -> print ctx "%s : " (anon_field f));
 			| _ -> print ctx "%s : " (anon_field f));
 			gen_value ctx e
 			gen_value ctx e
 		) fields;
 		) fields;
@@ -941,9 +941,9 @@ and gen_value ctx e =
 			| _ -> cond
 			| _ -> cond
 		) in
 		) in
 		gen_value ctx cond;
 		gen_value ctx cond;
-		spr ctx "?";
+		spr ctx " ? ";
 		gen_value ctx e;
 		gen_value ctx e;
-		spr ctx ":";
+		spr ctx " : ";
 		(match eo with
 		(match eo with
 		| None -> spr ctx "null"
 		| None -> spr ctx "null"
 		| Some e -> gen_value ctx e);
 		| Some e -> gen_value ctx e);

+ 31 - 4
src/generators/genphp.ml

@@ -71,6 +71,21 @@ type context = {
 
 
 let follow = Abstract.follow_with_abstracts
 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 join_class_path path separator =
 	let result = match fst path, snd path with
 	let result = match fst path, snd path with
 	| [], s -> s
 	| [], s -> s
@@ -536,7 +551,7 @@ and gen_call ctx e el =
 			spr ctx "]";
 			spr ctx "]";
 			genargs t)
 			genargs t)
 	in
 	in
-	match e.eexpr , el with
+	match (reveal_expr e).eexpr , el with
 	| TConst TSuper , params ->
 	| TConst TSuper , params ->
 		(match ctx.curclass.cl_super with
 		(match ctx.curclass.cl_super with
 		| None -> assert false
 		| None -> assert false
@@ -790,10 +805,16 @@ and gen_member_access ctx isvar e s =
 		| EnumStatics _ ->
 		| EnumStatics _ ->
 			print ctx "::%s%s" (if isvar then "$" else "") (s_ident s)
 			print ctx "::%s%s" (if isvar then "$" else "") (s_ident s)
 		| Statics sta ->
 		| Statics sta ->
-			let sep = if Meta.has Meta.PhpGlobal sta.cl_meta then "" else "::" in
+			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 isconst = Meta.has Meta.PhpConstants sta.cl_meta in
 			let cprefix = if isconst then get_constant_prefix sta.cl_meta else "" in
 			let cprefix = if isconst then get_constant_prefix sta.cl_meta else "" in
-			print ctx "%s%s%s" sep (if isvar && not isconst then "$" else cprefix)
+			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)
 			(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))
 	| _ -> 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)
@@ -833,6 +854,9 @@ and gen_field_access ctx isvar e s =
 		gen_value ctx e;
 		gen_value ctx e;
 		spr ctx ")";
 		spr ctx ")";
 		gen_member_access ctx isvar e s
 		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_expr ctx e;
 		gen_member_access ctx isvar e s
 		gen_member_access ctx isvar e s
@@ -1203,6 +1227,7 @@ and gen_expr ctx e =
 			end else if
 			end else if
 				   ((se1 = "Int" || se1 = "Null<Int>") && (se2 = "Int" || se2 = "Null<Int>"))
 				   ((se1 = "Int" || se1 = "Null<Int>") && (se2 = "Int" || se2 = "Null<Int>"))
 				|| ((se1 = "Float" || se1 = "Null<Float>") && (se2 = "Float" || se2 = "Null<Float>"))
 				|| ((se1 = "Float" || se1 = "Null<Float>") && (se2 = "Float" || se2 = "Null<Float>"))
+				&& not (is_float e1 && is_float e2)
 			then begin
 			then begin
 				gen_field_op ctx e1;
 				gen_field_op ctx e1;
 				spr ctx s_phop;
 				spr ctx s_phop;
@@ -1775,7 +1800,9 @@ and gen_value ctx e =
 		gen_value ctx e1
 		gen_value ctx e1
 	| TBlock [] ->
 	| TBlock [] ->
 		()
 		()
-	| TCast (e, _)
+	| TCast (_, Some _) ->
+		gen_expr ctx e
+	| TCast (e, None)
 	| TBlock [e] ->
 	| TBlock [e] ->
 		gen_value ctx e
 		gen_value ctx e
 	| TIf (cond,e,eelse) when (cangen_ternary e eelse) ->
 	| TIf (cond,e,eelse) when (cangen_ternary e eelse) ->

+ 3330 - 0
src/generators/genphp7.ml

@@ -0,0 +1,3330 @@
+(**
+	Compatible with PHP 7+
+*)
+
+open Ast
+open Type
+open Common
+open Meta
+open Globals
+
+let debug = ref false
+
+(**
+	Escape string for constant strings generation.
+	Copy-pasted from genphp.
+*)
+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
+
+(**
+	Write resources passed to compiler via `-resource` flag
+	Copy-pasted from genphp
+*)
+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
+
+(**
+	Get list of keys in Hashtbl
+*)
+let hashtbl_keys tbl = Hashtbl.fold (fun key _ lst -> key :: lst) tbl []
+
+(**
+	@return List of items in `list1` which `list2` does not contain
+*)
+let diff_lists list1 list2 = List.filter (fun x -> not (List.mem x list2)) list1
+
+(**
+	Type path for native PHP Exception class
+*)
+let native_exception_path = ([], "Throwable")
+(**
+	Type path for Haxe exceptions wrapper
+*)
+let hxexception_type_path = (["php"; "_Boot"], "HxException")
+(**
+	Type path of `php.Boot`
+*)
+let boot_type_path = (["php"], "Boot")
+(**
+	Type path of the base class for all enums: `php.Boot.HxEnum`
+*)
+let hxenum_type_path = (["php"; "_Boot"], "HxEnum")
+(**
+	Type path of the implementation class for `Class<Dynamic>`
+*)
+let hxclass_type_path = (["php"; "_Boot"], "HxClass")
+(**
+	Type path of the implementation class for `String`
+*)
+let hxstring_type_path = (["php"; "_Boot"], "HxString")
+(**
+	Type path of the special implementation class for `String`
+	which is used when Dynamic value is suspected to be a string
+*)
+let hxdynamicstr_type_path = (["php"; "_Boot"], "HxDynamicStr")
+(**
+	Type path of the implementation class for anonymous objects
+*)
+let hxanon_type_path = (["php"; "_Boot"], "HxAnon")
+(**
+	Type path of the implementation class for closures
+*)
+let hxclosure_type_path = (["php"; "_Boot"], "HxClosure")
+(**
+	Type path for special PHP extern class to support specific language expressions
+*)
+let syntax_type_path = (["php"], "Syntax")
+(**
+	Special abstract which enables passing function arguments and return value by reference
+*)
+let ref_type_path = (["php"], "Ref")
+(**
+	Type path of the implementation class for `Array<T>`
+*)
+let array_type_path = ([], "Array")
+(**
+	Type path of the implementation class for `Array<T>`
+*)
+let native_array_type_path = (["php"], "NativeArray")
+(**
+	Type path of the `Void`
+*)
+let void_type_path = ([], "Void")
+(**
+	Type path of the `Bool`
+*)
+let bool_type_path = ([], "Bool")
+
+(**
+	Stub to use when you need a `Ast.pos` instance, but don't have one
+*)
+let dummy_pos = { pfile = ""; pmin = 0; pmax = 0 }
+
+(**
+	Check if specified string is a reserved word in PHP
+*)
+let is_keyword str =
+	match String.lowercase str with
+		| "__halt_compiler" | "abstract" | "and" | "array" | "as" | "break" | "callable" | "case" | "catch" | "class"
+		| "clone" | "const" | "continue" | "declare" | "default" | "die" | "do" | "echo" | "else" | "elseif" | "empty"
+		| "enddeclare" | "endfor" | "endforeach" | "endif" | "endswitch" | "endwhile" | "eval" | "exit" | "extends"
+		| "final" | "finally" | "for" | "foreach" | "function" | "global" | "goto" | "if" | "implements" | "include"
+		| "include_once" | "instanceof" | "insteadof" | "interface" | "isset" | "list" | "namespace" | "new" | "or"
+		| "print" | "private" | "protected" | "public" | "require" | "require_once" | "return" | "static" | "switch"
+		| "throw" | "trait" | "try" | "unset" | "use" | "var" | "while" | "xor" | "yield" | "__class__" | "__dir__"
+		| "__file__" | "__function__" | "__line__" | "__method__" | "__trait__" | "__namespace__" | "int" | "float"
+		| "bool" | "string" | "true" | "false" | "null" | "parent" | "void" | "iterable"
+			-> true
+		| _ -> false
+
+(**
+	Check if specified type is Void
+*)
+let is_void_type t = match follow t with TAbstract ({ a_path = void_type_path }, _) -> true | _ -> false
+
+(**
+	Check if specified type is Bool
+*)
+let is_bool_type t = match follow t with TAbstract ({ a_path = bool_type_path }, _) -> true | _ -> false
+
+(**
+	Check if specified type is php.NativeArray
+*)
+let is_native_array_type t = match follow t with TAbstract ({ a_path = native_array_type_path }, _) -> true | _ -> false
+
+(**
+	If `name` is not a reserved word in PHP then `name` is returned as-is.
+	Otherwise this method returns another string, which can be used instead of `name`
+*)
+let get_real_name name = if is_keyword name then name ^ "_hx" else name
+
+(**
+	If `path` contains some reserved in PHP words, they will be replaced with allowed words.
+*)
+let get_real_path path = List.map get_real_name path
+
+(**
+	Resolve real type (bypass abstracts and typedefs)
+*)
+let rec follow = Abstract.follow_with_abstracts
+
+let prefix = ref None
+(**
+	Returns value of `--php-prefix` compiler flag
+*)
+let get_php_prefix ctx =
+	match !prefix with
+		| Some prefix -> prefix
+		| None ->
+			let lst =
+				match ctx.php_prefix with
+					| None -> []
+					| Some str ->
+						if String.length str = 0 then
+							[]
+						else
+							Str.split (Str.regexp "\\.") str
+			in
+			prefix := Some lst;
+			lst
+
+(**
+	Adds packages specified by `--php-prefix` to `type_path`.
+	E.g. if `--php-prefix some.sub` and `type_path` is `(["pack"], "MyClass")`, then this function
+	will return `(["some", "sub", "pack"], "MyClass")`
+*)
+let add_php_prefix ctx type_path =
+	match type_path with
+		| (pack, name) -> ((get_php_prefix ctx) @ pack, name)
+
+(**
+	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
+
+(**
+	@return Error message with position information
+*)
+let error_message pos message = (Lexer.get_error_pos (Printf.sprintf "%s:%d:") pos) ^ ": " ^ message
+
+(**
+	Terminates compiler process and prints user-friendly instructions about filing an issue in compiler repo.
+*)
+let fail hxpos mlpos =
+	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;
+			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
+*)
+let rec is_dynamic_type (target:Type.t) = match follow target with TDynamic _ -> true | _ -> false
+
+(**
+	Check if `target` is `php.Ref`
+*)
+let is_ref (target:Type.t) = match target with TAbstract ({ a_path = type_path }, _) -> type_path = ref_type_path | _ -> false
+
+(**
+	Check if `field` is a `dynamic function`
+*)
+let rec is_dynamic_method (field:tclass_field) =
+	match field.cf_kind with
+		| Method MethDynamic -> true
+		| _ -> false
+
+(**
+	Check if specified expression is of `Dynamic` type
+*)
+let is_dynamic expr = is_dynamic_type expr.etype
+
+(**
+	Check if specified expression is of `Int` type
+*)
+let is_int expr = match follow expr.etype with TAbstract ({ a_path = ([], "Int") }, _) -> true | _ -> false
+
+(**
+	Check if specified expression is of `Float` type
+*)
+let is_float expr = match follow expr.etype with TAbstract ({ a_path = ([], "Float") }, _) -> true | _ -> false
+
+(**
+	Check if specified type is String
+*)
+let is_string_type t = match follow t with TInst ({ cl_path = ([], "String") }, _) -> true | _ -> false
+
+(**
+	Check if specified expression is of String type
+*)
+let is_string expr = is_string_type expr.etype
+
+(**
+	Check if `expr` is an access to a method of special `php.PHP` class
+*)
+let is_lang_extern expr =
+	match expr.eexpr with
+		| TField ({ eexpr = TTypeExpr (TClassDecl { cl_path = path }) }, _) when path = syntax_type_path -> true
+		| _ -> false
+
+(**
+	Check if specified type is actually a generic parameter
+*)
+let is_generic_parameter (target:Type.t) =
+	match follow target with
+		| TInst ({ cl_kind = KTypeParameter _ }, _) -> true
+		| _ -> false
+
+(**
+	Check if `target` type cannot be clarified on compilation
+*)
+let is_unknown_type (target:Type.t) = is_dynamic_type target || is_generic_parameter target
+
+(**
+	@return `Type.t` instance for `Void`
+*)
+let void = ref None
+let get_void ctx : Type.t =
+	match !void with
+		| Some value -> value
+		| None ->
+			let find com_type =
+				match com_type with
+					| TAbstractDecl ({ a_path = ([], "Void") } as abstr) -> void := Some (TAbstract (abstr, []));
+					| _ -> ()
+			in
+			List.iter find ctx.types;
+			match !void with
+				| Some value -> value
+				| None -> fail dummy_pos (try assert false with Assert_failure mlpos -> mlpos)
+
+(**
+	@return `tclass` instance for `php.Boot`
+*)
+let boot = ref None
+let get_boot ctx : tclass =
+	match !boot with
+		| Some value -> value
+		| None ->
+			let find com_type =
+				match com_type with
+					| TClassDecl ({ cl_path = path } as cls) when path = boot_type_path -> boot := Some cls;
+					| _ -> ()
+			in
+			List.iter find ctx.types;
+			match !boot with
+				| Some value -> value
+				| None -> fail dummy_pos (try assert false with Assert_failure mlpos -> mlpos)
+
+(**
+	@return `expr` wrapped in parenthesis
+*)
+let parenthesis expr = {eexpr = TParenthesis expr; etype = expr.etype; epos = expr.epos}
+
+(**
+	Check if `current` binary should be surrounded with parenthesis
+*)
+let need_parenthesis_for_binop current parent =
+	if current = parent then
+		false
+	else
+		match (current, parent) with
+			| (_, OpAssign) -> false
+			| (_, OpAssignOp _) -> false
+			| (OpAdd, OpSub) -> false
+			| (OpSub, OpAdd) -> false
+			| (OpMult, OpDiv) -> false
+			| (OpDiv, OpMult) -> false
+			| (OpMult, OpAdd) -> false
+			| (OpMult, OpSub) -> false
+			| (OpDiv, OpAdd) -> false
+			| (OpDiv, OpSub) -> false
+			| _ -> true
+
+(**
+	Check if specified expression may require dereferencing if used as "temporary expression"
+*)
+let needs_dereferencing expr =
+	let rec is_create target_expr =
+		match target_expr.eexpr with
+			| TParenthesis e -> is_create e
+			| TCast (e, _) -> is_create e
+			| TNew _ -> true
+			| TArrayDecl _ -> true
+			| TObjectDecl _ -> true
+			| TConst TNull -> true
+			| _ -> false
+	in
+	match expr.eexpr with
+		| TField (target_expr, _) -> is_create target_expr
+		| TArray (target_expr, _) -> is_create target_expr
+		| _ -> false
+
+(**
+	@return (arguments_list, return_type)
+*)
+let get_function_signature (field:tclass_field) : (string * bool * Type.t) list * Type.t =
+	match follow field.cf_type with
+		| TFun (args, return_type) -> (args, return_type)
+		| _ -> fail field.cf_pos (try assert false with Assert_failure mlpos -> mlpos)
+
+(**
+	Check if `target` is 100% guaranteed to be a scalar type in PHP.
+	Inversion of `is_sure_scalar` does not guarantee `target` is not scalar.
+*)
+let is_sure_scalar (target:Type.t) =
+	match follow target with
+		| TInst ({ cl_path = ([], "String") }, _) -> true
+		| TAbstract (abstr, _) ->
+			(match abstr.a_path with
+				| ([],"Int") -> true
+				| ([],"Float") -> true
+				| ([],"Bool") -> true
+				| _ -> false
+			)
+		| _ -> false
+
+(**
+	Indicates if `expr` is guaranteed to be an access to a `var` field.
+*)
+let is_sure_var_field_access expr =
+	match (reveal_expr expr).eexpr with
+		| TField (_, FStatic (_, { cf_kind = Var _ })) -> true
+		| TField (_, FInstance (_, _, { cf_kind = Var _ })) -> true
+		(* | TField (_, FAnon { cf_kind = Var _ }) -> true *) (* Sometimes we get anon access to non-anonymous objects *)
+		| _ -> false
+
+(**
+	Check if specified unary operation modifies value in place
+*)
+let is_modifying_unop op =
+	match op with
+		| Increment
+		| Decrement -> true
+		| _ -> false
+
+(**
+	Indicates whether `expr` is a field access which should be generated as global namespace function
+*)
+let is_php_global expr =
+	match expr.eexpr with
+		| TField (_, FStatic ({ cl_extern = true; cl_meta = meta }, _)) -> Meta.has Meta.PhpGlobal meta
+		| _ -> false
+
+(**
+	Indicates whether `expr` is a field access which should be generated as class constant access
+*)
+let is_php_class_const expr =
+	match expr.eexpr with
+		| TField (_, FStatic ({ cl_extern = true }, { cf_meta = meta; cf_kind = Var _ })) ->
+			Meta.has Meta.PhpClassConst meta
+		| _ -> false
+
+(**
+	Check if specified enum constructor has arguments
+*)
+let is_enum_constructor_with_args (constructor:tenum_field) =
+	match follow constructor.ef_type with
+		| TFun _ -> true
+		| _ -> false
+
+(**
+	Check if `target` is 100% guaranteed to be or extend an extern class.
+	Inversion of `sure_extends_extern` does not guarantee `target` does not extend an extern class.
+*)
+let rec sure_extends_extern (target:Type.t) =
+	match follow target with
+		| TInst ({ cl_path = ([], "String") }, _) -> false
+		| TInst ({ cl_extern = true }, _) -> true
+		| TInst ({ cl_super = Some (tsuper, params) }, _) -> sure_extends_extern (TInst (tsuper,params))
+		| _ -> false
+
+(**
+	@return `opt` value or `default` if `opt` is None
+*)
+let get_option_value (opt:'a option) default =
+	match opt with
+		| None -> default
+		| Some value -> value
+
+(**
+	@param path Something like [ "/some/path/first_dir_to_create"; "nested_level1"; "nested_level2" ]
+	@return String representation of created path (E.g. "/some/path/first_dir_to_create/nested_level1/nested_level2")
+*)
+let create_dir_recursive (path:string list) =
+	let rec create dir nested_dirs =
+		if not (Sys.file_exists dir) then (Unix.mkdir dir 0o755);
+		match nested_dirs with
+			| [] -> ();
+			| next :: rest -> create (dir ^ "/" ^ next) rest
+	in
+	match path with
+		| [] -> "";
+		| root :: rest ->
+			create root rest;
+			(String.concat "/" path)
+
+(**
+	@return String representation of specified type path. E.g. returns "\example\Test" for (["example"], "Test")
+*)
+let get_full_type_name ?escape ?omit_first_slash (type_path:path) =
+	let name =
+		match type_path with
+			| (module_path, type_name) ->
+				let parts =
+					match omit_first_slash with
+						| Some true -> get_real_path module_path
+						| _ -> "" :: get_real_path module_path
+				in
+				(String.concat "\\" parts) ^ "\\" ^ type_name
+	in
+	match escape with
+		| Some true -> String.escaped name
+		| _ -> name
+
+(**
+	Check if `target` is or implements native PHP `Throwable` interface
+*)
+let rec is_native_exception (target:Type.t) =
+	match follow target with
+		| TInst ({ cl_path = path }, _) when path = native_exception_path -> true
+		| TInst ({ cl_super = parent ; cl_implements = interfaces ; cl_path = path }, _) ->
+			let (parent, params) =
+				match parent with
+					| Some (parent, params) -> (Some parent, params)
+					| None -> (None, [])
+			in
+			let found = ref false in
+			List.iter
+				(fun (cls, params) ->
+					if not !found then
+						found := is_native_exception (TInst (cls, params))
+				)
+				interfaces;
+			if !found then
+				true
+			else
+				(match parent with
+					| Some parent -> is_native_exception (TInst (parent, params))
+					| None -> false
+				)
+		| _ -> false
+
+(**
+	@return Short type name. E.g. returns "Test" for (["example"], "Test")
+*)
+let get_type_name (type_path:path) = match type_path with (_, type_name) -> type_name
+
+(**
+	@return E.g. returns ["example"] for (["example"], "Test")
+*)
+let get_module_path (type_path:path) = match type_path with (module_path, _) -> module_path
+
+(**
+	@return PHP visibility keyword.
+*)
+let get_visibility (meta:metadata) = if Meta.has Meta.Protected meta then "protected" else "public"
+
+(**
+	Writes arguments list to output buffer
+*)
+let rec write_args buffer arg_writer (args:'a) =
+	match args with
+		| [] -> ()
+		| [arg] -> arg_writer arg
+		| arg :: rest ->
+			arg_writer arg;
+			Buffer.add_string buffer ", ";
+			write_args buffer arg_writer rest
+
+(**
+	Check if specified field is a var with non-constant expression
+*)
+let is_var_with_nonconstant_expr (field:tclass_field) =
+	match field.cf_kind with
+		| Var _ ->
+			(match field.cf_expr with
+				| None -> false
+				| Some ({eexpr = TConst _ }) -> false
+				| Some _ -> true
+			)
+		| Method _ -> false
+
+(**
+	@return New TBlock expression which is composed of setting default values for optional arguments and function body.
+*)
+let inject_defaults (ctx:Common.context) (func:tfunc) =
+	let rec inject args body_exprs =
+		match args with
+			| [] -> body_exprs
+			| (_, 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
+			 	expr :: (inject rest body_exprs)
+	in
+	let exprs =
+		match func.tf_expr.eexpr with
+			| TBlock exprs -> inject func.tf_args exprs
+			| _ -> inject func.tf_args [ func.tf_expr ]
+	in
+	{
+		eexpr = TBlock exprs;
+		etype = follow func.tf_expr.etype;
+		epos  = func.tf_expr.epos;
+	}
+
+(**
+	Check if `expr` is a constant string
+*)
+let is_constant_string expr =
+	match expr.eexpr with
+		| TConst (TString _) -> true
+		| _ -> false
+
+(**
+	Check if `expr` is a constant null
+*)
+let is_constant_null expr =
+	match expr.eexpr with
+		| TConst TNull -> true
+		| _ -> false
+
+(**
+	Check if `expr` is a constant
+*)
+let is_constant expr =
+	match expr.eexpr with
+		| TConst _ -> true
+		| _ -> false
+
+(**
+	Check if `expr` is a concatenation
+*)
+let is_concatenation expr =
+	match expr.eexpr with
+		| TBinop (OpAdd, expr1, expr2) -> (is_string expr1) || (is_string expr2)
+		| _ -> false
+
+(**
+	Check if provided expression is a binary operation
+*)
+let is_binop expr = match expr.eexpr with TBinop _ -> true | _ -> false
+
+(**
+	Check if provided expression is an assignment binary operation
+*)
+let is_binop_assign expr =
+	match expr.eexpr with
+		| TBinop (operation, _, _) ->
+			(match operation with
+				| OpAssign | OpAssignOp _ -> true
+				| _ -> false
+			)
+		| _ -> false
+
+(**
+	Check if specified expression is field access or array access
+*)
+let is_access expr =
+	match expr.eexpr with
+		| TField _ | TArray _ -> true
+		| _ -> false
+
+(**
+	Indicates if `expr` is actually a call to Haxe->PHP magic function
+	@see http://old.haxe.org/doc/advanced/magic#php-magic
+*)
+let is_magic expr =
+	match expr.eexpr with
+	| TCall ({ eexpr = TLocal { v_name = name }}, _) ->
+		(match name with
+			| "__php__" -> true
+			| "__call__" -> true
+			| "__physeq__" -> true
+			| "__var__" -> true
+			| _ -> false
+		)
+	| _ -> false
+
+(**
+	Check if `expr1` and `expr2` can be reliably checked for equality only with `Boot.equal()`
+*)
+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)
+
+(**
+	Adds `return` expression to block if it does not have one already
+*)
+let ensure_return_in_block block_expr =
+	match block_expr.eexpr with
+		| TBlock [] -> fail block_expr.epos (try assert false with Assert_failure mlpos -> mlpos)
+		| TBlock exprs ->
+			let reversed = List.rev exprs in
+			let last_expr = List.hd reversed in
+			let return_expr = { last_expr with eexpr = TReturn (Some last_expr) } in
+			let reversed = return_expr::(List.tl reversed) in
+			{ block_expr with eexpr = TBlock (List.rev reversed) }
+		| _ -> fail block_expr.epos (try assert false with Assert_failure mlpos -> mlpos)
+
+(**
+	Check if specified type has rtti meta
+*)
+let has_rtti_meta ctx mtype =
+	match Codegen.build_metadata ctx mtype with
+		| None -> false
+		| Some _ -> true
+
+(**
+	Check if this var accesses and meta combination should generate a variable
+*)
+let is_real_var field =
+	if Meta.has IsVar field.cf_meta then
+		true
+	else
+		match field.cf_kind with
+			| Var { v_read = read; v_write = write } -> read = AccNormal || write = AccNormal
+			| _ -> false
+
+(**
+	Check if user-defined field has the same name as one of php magic methods, but with not compatible signature.
+*)
+let field_needs_rename field =
+	match field.cf_kind with
+		| Var _ -> false
+		| Method _ ->
+			match field.cf_name with
+				| "__construct" | "__destruct" | "__call" | "__callStatic" | "__get" | "__set" | "__isset"
+				| "__unset" | "__sleep" | "__wakeup" | "__toString" | "__invoke" | "__set_state" | "__clone"
+				| "__debugInfo" -> not (Meta.has Meta.PhpMagic field.cf_meta)
+				| _ -> false
+(**
+	Get valid `field` name.
+*)
+let field_name field =
+	if field_needs_rename field then
+		"__hx__renamed" ^ field.cf_name
+	else
+		field.cf_name
+
+(**
+	PHP DocBlock types
+*)
+type doc_type =
+	| DocVar of string * (string option) (* (type name, description) *)
+	| DocMethod of (string * bool * t) list * t * (string option) (* (arguments, return type, description) *)
+| DocClass of string option
+
+(**
+	Common interface for module_type instances
+*)
+class virtual type_wrapper (type_path:path) (meta:metadata) (needs_generation:bool) =
+	object (self)
+		(**
+			Indicates if this type should be rendered to corresponding php file
+		*)
+		method needs_generation = needs_generation
+		(**
+			Indicates if class initialization method should be executed upon class loaded
+		*)
+		method virtual needs_initialization : bool
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method virtual get_source_file : string
+		(**
+			Returns `Type.module_type` instance for this type
+		*)
+		method virtual get_module_type : module_type
+		(**
+			Returns expression of a user-defined static __init__ method
+			@see http://old.haxe.org/doc/advanced/magic#initialization-magic
+		*)
+		method get_magic_init : texpr option = None
+		(**
+			Namespace path. E.g. ["some"; "pack"] for "some.pack.MyType"
+		*)
+		method get_namespace = get_module_path type_path
+		(**
+			Short type name. E.g. `SomeType` for `pack.SomeType`
+		*)
+		method get_name = get_type_name type_path
+		(**
+			Full type path
+		*)
+		method get_type_path = type_path
+	end
+
+(**
+	TClassDecl
+*)
+class class_wrapper (cls) =
+	object (self)
+		inherit type_wrapper cls.cl_path cls.cl_meta (not cls.cl_extern)
+		(**
+			Indicates if class initialization method should be executed upon class loaded
+		*)
+		method needs_initialization =
+			(* Interfaces may need initialization only for RTTI meta data.
+				But that meta is written in `class_wrapper#write_rtti_meta` *)
+			if cls.cl_interface then
+				false
+			else
+				match cls.cl_init with
+					| Some _ -> true
+					| None ->
+						let needs = ref false in
+						PMap.iter
+							(fun _ field ->
+								(* Check static vars with non-constant expressions *)
+								if not !needs then needs := is_var_with_nonconstant_expr field;
+								(* Check static dynamic functions *)
+								if not !needs then needs := is_dynamic_method field
+							)
+							cls.cl_statics;
+						!needs
+		(**
+			Returns expression of a user-defined static __init__ method
+			@see http://old.haxe.org/doc/advanced/magic#initialization-magic
+		*)
+		method get_magic_init = cls.cl_init
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method get_source_file = cls.cl_pos.pfile
+		(**
+			Returns `Type.module_type` instance for this type
+		*)
+		method get_module_type = TClassDecl cls
+	end
+
+(**
+	TEnumDecl
+*)
+class enum_wrapper (enm) =
+	object (self)
+		inherit type_wrapper enm.e_path enm.e_meta (not enm.e_extern)
+		(**
+			Indicates if class initialization method should be executed upon class loaded
+		*)
+		method needs_initialization = false
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method get_source_file = enm.e_pos.pfile
+		(**
+			Returns `Type.module_type` instance for this type
+		*)
+		method get_module_type = TEnumDecl enm
+	end
+
+(**
+	TTypeDecl
+*)
+class typedef_wrapper (tdef) =
+	object (self)
+		inherit type_wrapper tdef.t_path tdef.t_meta false
+		(**
+			Indicates if class initialization method should be executed upon class loaded
+		*)
+		method needs_initialization = false
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method get_source_file = tdef.t_pos.pfile
+		(**
+			Returns `Type.module_type` instance for this type
+		*)
+		method get_module_type = TTypeDecl tdef
+	end
+
+(**
+	TAbstractDecl
+*)
+class abstract_wrapper (abstr) =
+	object (self)
+		inherit type_wrapper abstr.a_path abstr.a_meta false
+		(**
+			Indicates if class initialization method should be executed upon class loaded
+		*)
+		method needs_initialization = false
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method get_source_file = abstr.a_pos.pfile
+		(**
+			Returns `Type.module_type` instance for this type
+		*)
+		method get_module_type = TAbstractDecl abstr
+	end
+
+(**
+	type_wrapper for classes
+*)
+let classes = Hashtbl.create 1000
+let get_class_wrapper cls  : type_wrapper =
+	try
+		let wrapper = Hashtbl.find classes cls in
+		wrapper
+	with
+		| Not_found ->
+			let wrapper = new class_wrapper cls in
+			Hashtbl.add classes cls wrapper;
+			wrapper
+		| e -> raise e
+
+(**
+	type_wrapper for enums
+*)
+let enums = Hashtbl.create 200
+let get_enum_wrapper enm : type_wrapper=
+	try
+		let wrapper = Hashtbl.find enums enm in
+		wrapper
+	with
+		| Not_found ->
+			let wrapper = new enum_wrapper enm in
+			Hashtbl.add enums enm wrapper;
+			wrapper
+		| e -> raise e
+
+(**
+	type_wrapper for typedefs
+*)
+let typedefs = Hashtbl.create 200
+let get_typedef_wrapper typedef : type_wrapper =
+	try
+		let wrapper = Hashtbl.find typedefs typedef in
+		wrapper
+	with
+		| Not_found ->
+			let wrapper = new typedef_wrapper typedef in
+			Hashtbl.add typedefs typedef wrapper;
+			wrapper
+		| e -> raise e
+
+(**
+	type_wrapper for abstracts
+*)
+let abstracts = Hashtbl.create 200
+let get_abstract_wrapper abstr : type_wrapper =
+	try
+		let wrapper = Hashtbl.find abstracts abstr in
+		wrapper
+	with
+		| Not_found ->
+			let wrapper = new abstract_wrapper abstr in
+			Hashtbl.add abstracts abstr wrapper;
+			wrapper
+		| e -> raise e
+
+(**
+	Returns wrapper for module_type.
+	Caches wrappers so that each type will always return the same wrapper instance.
+*)
+let get_wrapper (mtype:module_type) : type_wrapper =
+	match mtype with
+		| TClassDecl cls -> get_class_wrapper cls
+		| TEnumDecl enm -> get_enum_wrapper enm
+		| TTypeDecl typedef -> get_typedef_wrapper typedef
+		| TAbstractDecl abstr -> get_abstract_wrapper abstr
+
+(**
+	Drop cached instances of type_wrapper
+*)
+let clear_wrappers () =
+	Hashtbl.clear classes;
+	Hashtbl.clear enums;
+	Hashtbl.clear typedefs;
+	Hashtbl.clear abstracts
+
+(**
+	Check if specified type name is used in specified namespace
+*)
+let namespaces_types_cache = Hashtbl.create 512
+let type_name_used_in_namespace ctx name namespace =
+	let types = Hashtbl.find_all namespaces_types_cache namespace in
+	match types with
+		| [] ->
+			List.iter
+				(fun ctx_type ->
+					let wrapper = get_wrapper ctx_type in
+					Hashtbl.add namespaces_types_cache wrapper#get_namespace wrapper#get_name
+				)
+				ctx.types;
+			let types = Hashtbl.find_all namespaces_types_cache namespace in
+			List.mem name types
+		| _ ->
+			List.mem name types
+
+(**
+	Class to simplify collecting lists of declared and used local vars.
+	Collected data is needed to generate closures correctly.
+*)
+class local_vars =
+	object (self)
+		(** Hashtbl to collect local var used in current scope *)
+		val mutable used_locals = [Hashtbl.create 100]
+		(** Hashtbl to collect local vars declared in current scope *)
+		val mutable declared_locals = [Hashtbl.create 100]
+		(**
+			Clear collected data
+		*)
+		method clear : unit =
+			used_locals <- [Hashtbl.create 100];
+			declared_locals <- [Hashtbl.create 100]
+		(**
+			This method should be called upone entering deeper scope.
+			E.g. right before processing a closure. Just before closure arguments handling.
+		*)
+		method dive : unit =
+			used_locals <- (Hashtbl.create 100) :: used_locals;
+			declared_locals <- (Hashtbl.create 100) :: declared_locals
+		(**
+			This method should be called right after leaving a scope.
+			@return List of vars names used in finished scope, but declared in higher scopes.
+					And list of vars names declared in finished scope.
+		*)
+		method pop : string list * string list =
+			match used_locals with
+				| [] -> assert false
+				| used :: rest_used ->
+					match declared_locals with
+						| [] -> assert false
+						| declared :: rest_declared ->
+							let higher_vars = diff_lists (hashtbl_keys used) (hashtbl_keys declared)
+							and declared_vars = hashtbl_keys declared in
+							used_locals <- rest_used;
+							declared_locals <- rest_declared;
+							List.iter self#used higher_vars;
+							(higher_vars, declared_vars)
+		(**
+			This method should be called right after leaving a scope.
+			@return List of vars names used in finished scope, but declared in higher scopes
+		*)
+		method pop_used : string list = match self#pop with (higher_vars, _) -> higher_vars
+		(**
+			This method should be called right after leaving a scope.
+			@return List of vars names declared in finished scope
+		*)
+		method pop_declared : string list = match self#pop with (_, declared_vars) -> declared_vars
+		(**
+			Specify local var name declared in current scope
+		*)
+		method declared (name:string) : unit =
+			match declared_locals with
+				| [] -> assert false
+				| current :: _ -> Hashtbl.replace current name name
+		(**
+			Specify local var name used in current scope
+		*)
+		method used (name:string) : unit =
+			match used_locals with
+				| [] -> assert false
+				| current :: _ -> Hashtbl.replace current name name
+	end
+
+(**
+	Base class for type builders
+*)
+class virtual type_builder ctx wrapper =
+	object (self)
+		(** This is required to make wrapper accessible by extending classes *)
+		val wrapper = wrapper
+		(** This is required to make conext accessible by extending classes *)
+		val ctx = ctx
+		(** List of types for "use" section *)
+		val use_table = Hashtbl.create 50
+		(** Output buffer *)
+		val mutable buffer = Buffer.create 1024
+		(** Cache for generated conent *)
+		val mutable contents = ""
+		(** Intendation used for each line written *)
+		val mutable indentation = ""
+		(** Expressions nesting. E.g. "if(callFn(ident))" will be represented as [ident, callFn, if] *)
+		val mutable expr_hierarchy : texpr list = []
+		(** Object to collect local vars declarations and usage as we iterate through methods' expressions *)
+		val vars = new local_vars
+		(**
+			Get PHP namespace path
+		*)
+		method get_namespace =
+			match get_php_prefix ctx with
+				| [] -> get_real_path wrapper#get_namespace
+				| prefix -> get_real_path (prefix @ wrapper#get_namespace)
+		(**
+			Get type name
+		*)
+		method get_name : string = get_real_name wrapper#get_name
+		(**
+			Get full type path
+		*)
+		method get_type_path : path =
+			match wrapper#get_type_path with
+				| (path, name) -> (get_real_path path, get_real_name name)
+		(**
+			Returns hx source file name where this type was declared
+		*)
+		method get_source_file : string = wrapper#get_source_file
+		(**
+			Writes type declaration line to output buffer.
+			E.g. "class SomeClass extends Another implements IFace"
+		*)
+		method virtual private write_declaration : unit
+		(**
+			Writes type body to output buffer.
+			E.g. for "class SomeClass { <BODY> }" writes <BODY> part.
+		*)
+		method virtual private write_body : unit
+		(**
+			Writes expressions for `__hx__init` method
+		*)
+		method virtual private write_hx_init_body : unit
+		(**
+			Writes additional initialization code, which should be called before `__hx__init()`
+		*)
+		method virtual private write_pre_hx_init : unit
+		(**
+			Writes initialization code for type instances
+		*)
+		method virtual private write_instance_initialization : unit
+		(**
+			Indicates if type should be declared as `final`
+		*)
+		method is_final = false
+		(**
+			Indicates if `field` should be declared as `final`
+		*)
+		method is_final_field (field:tclass_field) : bool = false
+		(**
+			Increase indentation by one level
+		*)
+		method indent_more =
+			indentation <- indentation ^ "\t";
+		(**
+			Decrease indentation by one level
+		*)
+		method indent_less =
+			indentation <- String.make ((String.length indentation) - 1) '\t';
+		(**
+			Set indentation level (starting from zero for no indentation)
+		*)
+		method indent level =
+			indentation <- String.make level '\t';
+		(**
+			Indicates if class has user-defined static __init__ method
+			@see http://old.haxe.org/doc/advanced/magic#initialization-magic
+		*)
+		method has_magic_init = match wrapper#get_magic_init with None -> false | Some _ -> true
+		(**
+			Returns generated file contents
+		*)
+		method get_contents =
+			if (String.length contents) = 0 then begin
+				self#write_declaration;
+				self#write_line " {"; (** opening bracket for a class *)
+				self#write_body;
+				if wrapper#needs_initialization then self#write_hx_init;
+				self#indent 0;
+				self#write_line "}"; (** closing bracket for a class *)
+				self#write_empty_lines;
+				let boot_class = self#use boot_type_path in
+				(* Boot initialization *)
+				if boot_type_path = self#get_type_path then
+					self#write_statement (boot_class ^ "::__hx__init()");
+				(*let php_class = get_full_type_name ~escape:true ~omit_first_slash:true (add_php_prefix ctx self#get_type_path)*)
+				let haxe_class = match wrapper#get_type_path with (path, name) -> String.concat "." (path @ [name]) in
+				self#write_statement (boot_class ^ "::registerClass(" ^ (self#get_name) ^ "::class, '" ^ haxe_class ^ "')");
+				self#write_rtti_meta;
+				self#write_pre_hx_init;
+				(* Current class initialization *)
+				if wrapper#needs_initialization && boot_type_path <> self#get_type_path then
+					self#write_statement (self#get_name ^ "::__hx__init()");
+				let body = Buffer.contents buffer in
+				Buffer.clear buffer;
+				self#write_header;
+				self#write "\n";
+				let header = Buffer.contents buffer in
+				contents <- header ^ body;
+			end;
+			contents
+		(**
+			Adds type to "use" section if not added yet.
+			If it's a top-level type then type name returned without adding to "use" section.
+			@return Unique alias for specified type.
+		*)
+		method use ?prefix (type_path:path) =
+			if type_path = wrapper#get_type_path then
+				self#get_name
+			else
+				let type_path = match type_path with (pack, name) -> (pack, get_real_name name) in
+				let type_path =
+					match prefix with
+						| Some false -> type_path
+						| _ -> add_php_prefix ctx type_path
+				in
+				let module_path = get_module_path type_path in
+				match type_path with
+					| ([], type_name) -> "\\" ^ type_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)
+								| name :: rest ->
+									alias_source := rest;
+									String.capitalize name
+						and added = ref false
+						and alias = ref (get_type_name type_path) in
+						if !alias = self#get_name then
+							alias := get_alias_next_part () ^ !alias;
+						while not !added do
+							try
+								if (get_module_path type_path) <> wrapper#get_namespace && type_name_used_in_namespace ctx !alias wrapper#get_namespace then
+									alias := get_alias_next_part () ^ !alias
+								else
+									let used_type = Hashtbl.find use_table !alias in
+									if used_type = type_path then
+										added := true
+									else
+										alias := get_alias_next_part () ^ !alias;
+							with
+								| Not_found ->
+									Hashtbl.add use_table !alias type_path;
+									added := true
+								| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+						done;
+						!alias
+		(**
+			Extracts type path from Type.t value and execute self#use on it
+			@return Unique alias for specified type.
+		*)
+		method use_t (t_inst:Type.t) =
+			match follow t_inst with
+				| TEnum (tenum, _) -> self#use tenum.e_path
+				| TInst (tcls, _) ->
+					(match tcls.cl_kind with
+						| KTypeParameter _ -> "mixed"
+						| _ ->
+							(match tcls.cl_path with
+								| ([], "String") -> "string"
+								| _ -> self#use ~prefix:(not tcls.cl_extern) tcls.cl_path
+							)
+					)
+				| TFun _ -> self#use ~prefix:false ([], "Closure")
+				| TAnon _ -> "object"
+				| TDynamic _ -> "mixed"
+				| TLazy _ -> failwith "TLazy not implemented"
+				| TMono mono ->
+					(match !mono with
+						| None -> "mixed"
+						| Some t -> self#use_t t
+					)
+				| TType _ -> failwith "TType not implemented"
+				| TAbstract (abstr, _) ->
+					match abstr.a_path with
+						| ([],"Int") -> "int"
+						| ([],"Float") -> "float"
+						| ([],"Bool") -> "bool"
+						| ([],"Void") -> "void"
+						| ([],"Enum") -> "Enum"
+						| ([], "Class") -> "Class"
+						| _ when Meta.has Meta.CoreType abstr.a_meta -> "mixed"
+						| _ -> self#use_t abstr.a_this
+		(**
+			Indicates whether current expression nesting level is a top level of a block
+		*)
+		method private parent_expr_is_block =
+			let rec expr_is_block expr parents =
+				match expr.eexpr with
+					| TBlock _ -> true
+					| TIf (_, if_expr, Some else_expr) ->
+						if (expr_is_block if_expr []) || (expr_is_block else_expr []) then
+							true
+						else
+							(match parents with
+								| parent :: rest -> expr_is_block parent rest
+								| [] -> false
+							)
+					| TIf (_, _, None) -> true
+					| TTry _ -> true
+					| TWhile _ -> true
+					| TSwitch _ -> true
+					| _ -> false
+			in
+			match expr_hierarchy with
+				| _ :: parent :: rest -> expr_is_block parent rest
+				| _ -> false
+		(**
+			Returns parent expression.
+		*)
+		method private parent_expr =
+			match expr_hierarchy with
+				| _ :: expr :: _ -> Some expr
+				| _ -> None
+		(**
+			Indicates if parent expression is a call (bypasses casts and metas)
+		*)
+		method private parent_expr_is_call =
+			let rec expr_is_call expr parents =
+				match expr.eexpr with
+					| TCast _
+					| TMeta _ ->
+						(match parents with
+							| parent :: rest -> expr_is_call parent rest
+							| [] -> false
+						)
+					| TCall _ -> true
+					| _ -> false
+			in
+			match expr_hierarchy with
+				| _ :: parent :: rest -> expr_is_call parent rest
+				| _ -> false
+		(**
+			Position of currently generated code in source hx files
+		*)
+		method private pos =
+			match expr_hierarchy with
+				| { epos = pos } :: _ -> pos
+				| _ -> dummy_pos
+		(**
+			Add a function call to "dereference" part of expression to avoid "Cannot use temporary expression in write context"
+			erro in expressions like:
+			```
+			new MyClass().fieldName = 'value';
+			```
+		*)
+		method private dereference expr =
+			let boot_cls = get_boot ctx in
+			let deref_field = PMap.find "deref" boot_cls.cl_statics in
+			match expr.eexpr with
+				| TField (target_expr, access) ->
+					{
+						expr with eexpr = TField (
+							{
+								target_expr with eexpr = TCall (
+									{
+										target_expr with eexpr = TField (
+											{
+												target_expr with eexpr = TTypeExpr (TClassDecl boot_cls)
+											},
+											FStatic (boot_cls, deref_field)
+										)
+									},
+									[ target_expr ]
+								)
+							},
+							access
+						)
+					}
+				| TArray (target_expr, access_expr) ->
+					{
+						expr with eexpr = TArray (
+							{
+								target_expr with eexpr = TCall (
+									{
+										target_expr with eexpr = TField (
+											{
+												target_expr with eexpr = TTypeExpr (TClassDecl boot_cls)
+											},
+											FStatic (boot_cls, deref_field)
+										)
+									},
+									[ target_expr ]
+								)
+							},
+							access_expr
+						)
+					}
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes specified string to output buffer
+		*)
+		method private write str =
+			Buffer.add_string buffer str
+		(**
+			Writes fixed amount of empty lines (E.g. between methods)
+		*)
+		method private write_empty_lines =
+			self#write "\n";
+			self#write "\n"
+		(**
+			Writes current indentation to output buffer
+		*)
+		method private write_indentation =
+			Buffer.add_string buffer indentation
+		(**
+			Writes specified line to output buffer and appends \n
+		*)
+		method private write_line line =
+			Buffer.add_string buffer (indentation ^ line ^ "\n")
+		(**
+			Writes specified statement to output buffer and appends ";\n"
+		*)
+		method private write_statement statement =
+			Buffer.add_string buffer (indentation ^ statement ^ ";\n")
+		(**
+			Build file header (<?php, namespace and file doc block)
+		*)
+		method private write_header =
+			self#indent 0;
+			self#write_line "<?php";
+			self#write_line "/**";
+			Codegen.map_source_header ctx (fun s -> self#write_line (" * " ^ s));
+			if ctx.debug then self#write_line (" * Haxe source file: " ^ self#get_source_file);
+			self#write_line " */";
+			self#write "\n";
+			let namespace = self#get_namespace in
+			if List.length namespace > 0 then
+				self#write_line ("namespace " ^ (String.concat "\\" namespace) ^ ";\n");
+			self#write_use
+		(**
+			Build "use" statements
+		*)
+		method private write_use =
+			self#indent 0;
+			let write alias type_path =
+				if (get_module_path type_path) <> wrapper#get_namespace then
+					if get_type_name type_path = alias then
+						self#write_statement ("use " ^ (get_full_type_name type_path))
+					else
+						let full_name = get_full_type_name type_path in
+						self#write_statement ("use " ^ full_name ^ " as " ^ alias)
+			in
+			Hashtbl.iter write use_table
+		(**
+			Writes array item declaration to output buffer and appends ",\n"
+		*)
+		method private write_array_item ?key value_expr =
+			(match key with
+				| None ->
+					self#write_indentation;
+					self#write_expr value_expr;
+				| Some key_str ->
+					self#write (indentation  ^ "\"" ^ (String.escaped key_str) ^ "\" => ");
+					self#write_expr value_expr
+			);
+			self#write ",\n"
+		(**
+			Generates PHP docblock to output buffer.
+		*)
+		method private write_doc doc_block =
+			match doc_block with
+				| DocVar (type_name, doc) ->
+					self#write_line "/**";
+					self#write_line (" * @var " ^ type_name);
+					(match doc with
+						| None -> ()
+						| Some txt -> self#write_doc_description txt
+					);
+					self#write_line " */"
+				| DocClass doc ->
+					(match doc with
+						| None -> ()
+						| Some txt ->
+							self#write_line "/**";
+							self#write_doc_description txt;
+							self#write_line " */"
+					)
+				| DocMethod (args, return, doc) ->
+					self#write_method_docblock args return doc
+		(**
+			Writes description section of docblocks
+		*)
+		method write_doc_description (doc:string) =
+			let lines = Str.split (Str.regexp "\n") (String.trim doc)
+			and write_line line =
+				let trimmed = String.trim line in
+				if String.length trimmed > 0 then (
+					if String.get trimmed 0 = '*' then
+						self#write_line (" " ^ trimmed)
+					else
+						self#write_line (" * " ^ trimmed)
+				)
+			in
+			List.iter write_line lines
+		(**
+			Generates docblock for a method and writes it to output buffer
+		*)
+		method write_method_docblock args return_type doc =
+			self#write_line "/**";
+			(match doc with
+				| None -> ()
+				| Some txt ->
+					self#write_doc_description txt;
+					self#write_line " * "
+			);
+			let write_arg arg =
+				match arg with
+					| (arg_name, is_optional, arg_type) ->
+						self#write_line (" * @param " ^ (self#use_t arg_type) ^ " $" ^ arg_name)
+			in
+			List.iter write_arg args;
+			if List.length args > 0 then self#write_line " * ";
+			self#write_line (" * @return " ^ (self#use_t return_type));
+			self#write_line " */"
+		(**
+			Writes rtti meta to output buffer
+		*)
+		method write_rtti_meta =
+			match Codegen.build_metadata ctx wrapper#get_module_type with
+				| None -> ()
+				| Some meta_expr ->
+					let boot_class = self#use boot_type_path in
+					self#write (boot_class ^ "::registerMeta(" ^ (self#get_name) ^ "::class, ");
+					self#write_expr meta_expr;
+					self#write ");\n"
+		(**
+			Writes expression to output buffer
+		*)
+		method private write_expr (expr:texpr) =
+			expr_hierarchy <- expr :: expr_hierarchy;
+			(match expr.eexpr with
+				| TConst const -> self#write_expr_const const
+				| TLocal var ->
+					vars#used var.v_name;
+					self#write ("$" ^ var.v_name)
+				| TArray (target, index) -> self#write_expr_array_access target index
+				| TBinop (operation, expr1, expr2) when needs_dereferencing expr1 ->
+					self#write_expr { expr with eexpr = TBinop (operation, self#dereference expr1, expr2) }
+				| TBinop (operation, expr1, expr2) -> self#write_expr_binop operation expr1 expr2
+				| TField (fexpr, access) when is_php_global expr -> self#write_expr_php_global expr
+				| TField (fexpr, access) when is_php_class_const expr -> self#write_expr_php_class_const expr
+				| TField (expr, access) -> self#write_expr_field expr access
+				| TTypeExpr mtype -> self#write_expr_type mtype
+				| TParenthesis expr ->
+					self#write "(";
+					self#write_expr expr;
+					self#write ")"
+				| TObjectDecl fields -> self#write_expr_object_declaration fields
+				| TArrayDecl exprs -> self#write_expr_array_decl exprs
+				| TCall ({ eexpr = TLocal { v_name = name }}, args) when is_magic expr -> self#write_expr_magic name args
+				| TCall ({ eexpr = TField (expr, access) }, args) when is_string expr -> self#write_expr_call_string expr access args
+				| TCall (expr, args) when is_lang_extern expr -> self#write_expr_call_lang_extern expr args
+				| 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 buffer self#write_expr args
+				| TNew (tcls, _, args) -> self#write_expr_new tcls args
+				| TUnop (operation, flag, target_expr) when needs_dereferencing target_expr ->
+					self#write_expr { expr with eexpr = TUnop (operation, flag, self#dereference target_expr) }
+				| TUnop (operation, flag, expr) -> self#write_expr_unop operation flag expr
+				| TFunction fn -> self#write_expr_function fn
+				| TVar (var, expr) -> self#write_expr_var var expr
+				| TBlock exprs -> self#write_expr_block expr
+				| TFor (var, iterator, body) -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+				| TIf (condition, if_expr, else_expr) -> self#write_expr_if condition if_expr else_expr
+				| TWhile (condition, expr, do_while) -> self#write_expr_while condition expr do_while
+				| TSwitch (switch, cases, default ) -> self#write_expr_switch switch cases default
+				| TTry (try_expr, catches) -> self#write_expr_try_catch try_expr catches
+				| TReturn expr -> self#write_expr_return expr
+				| TBreak -> self#write_expr_loop_flow "break"
+				| TContinue -> self#write_expr_loop_flow "continue"
+				| TThrow expr -> self#write_expr_throw expr
+				| TCast (expr, mtype) -> self#write_expr_cast expr mtype
+				| TMeta (_, expr) -> self#write_expr expr
+				| TEnumParameter (expr, constructor, index) -> self#write_expr_enum_parameter expr constructor index
+			);
+			expr_hierarchy <- List.tl expr_hierarchy
+		(**
+			Writes type initialization method.
+		*)
+		method private write_hx_init =
+			self#write_empty_lines;
+			self#indent 1;
+			self#write_line "/**";
+			self#write_line " * @internal";
+			self#write_line " * @access private";
+			self#write_line " */";
+			self#write_line "static public function __hx__init ()";
+			self#write_line "{";
+			self#indent_more;
+			self#write_statement "static $called = false";
+			self#write_statement "if ($called) return";
+			self#write_statement "$called = true";
+			self#write "\n";
+			vars#clear;
+			(match wrapper#get_magic_init with
+				| None -> ()
+				| Some expr -> self#write_fake_block expr
+			);
+			self#write "\n";
+			vars#clear;
+			self#write_hx_init_body;
+			self#indent 1;
+			self#write_line "}"
+		(**
+			Writes `continue N` or `break N` with required N depending on nearest parent loop and amount of `switch` between loop and
+			`continue/break`
+		*)
+		method private write_expr_loop_flow word =
+			let rec count_N parent_exprs count =
+				match parent_exprs with
+					| [] -> count
+					| { eexpr = TWhile _ } :: _ -> count
+					| { eexpr = TSwitch _ } :: rest -> count_N rest (count + 1)
+					| _ :: rest -> count_N rest count
+			in
+			let count = count_N expr_hierarchy 1 in
+			if count > 1 then
+				self#write (word ^ " " ^ (string_of_int count))
+			else
+				self#write word
+		(**
+			Writes TConst to output buffer
+		*)
+		method private write_expr_const const =
+			match const with
+				| TInt value -> self#write (Int32.to_string value)
+				| TFloat str -> self#write str
+				| TString str -> self#write ("\"" ^ (escape_bin str) ^ "\"")
+				| TBool value -> self#write (if value then "true" else "false")
+				| TNull -> self#write "null"
+				| TThis -> self#write "$this"
+				| TSuper -> self#write "parent"
+		(**
+			Writes TArrayDecl to output buffer
+		*)
+		method private write_expr_array_decl exprs =
+			match exprs with
+				| [] -> self#write ("new " ^ (self#use array_type_path) ^ "()")
+				| [expr] ->
+					self#write ((self#use array_type_path) ^ "::wrap([");
+					self#write_expr expr;
+					self#write "])"
+				| _ ->
+					self#write ((self#use array_type_path) ^ "::wrap([\n");
+					self#indent_more;
+					List.iter (fun expr -> self#write_array_item expr) exprs;
+					self#indent_less;
+					self#write_indentation;
+					self#write "])"
+		(**
+			Writes TArray to output buffer
+		*)
+		method private write_expr_array_access target index =
+			(*self#write_expr target;
+			self#write "[";
+			self#write_expr index;
+			self#write "]"*)
+			let write_index left_bracket right_bracket =
+				self#write left_bracket;
+				self#write_expr index;
+				self#write right_bracket
+			in
+			match follow target.etype with
+				| TInst ({ cl_path = path }, _) when path = array_type_path ->
+					(match self#parent_expr with
+						| Some { eexpr = TBinop (OpAssign, { eexpr = TArray (t, i) }, _) } when t == target ->
+							self#write_expr target;
+							write_index "[" "]"
+						| Some { eexpr = TBinop (OpAssignOp _, { eexpr = TArray (t, i) }, _) } when t == target ->
+							self#write_expr target;
+							write_index "[" "]"
+						| Some { eexpr = TUnop (op, _, { eexpr = TArray (t, i) }) } when t == target && is_modifying_unop op ->
+							self#write_expr target;
+							write_index "[" "]"
+						| Some { eexpr = TField ({ eexpr = TArray (t, i) }, _) } ->
+							self#write_expr target;
+							write_index "[" "]"
+						| _ ->
+							self#write "(";
+							self#write_expr target;
+							self#write "->arr";
+							write_index "[" "] ?? null)"
+					)
+				| _ ->
+					self#write_expr target;
+					write_index "[" "]"
+		(**
+			Writes TVar to output buffer
+		*)
+		method private write_expr_var var expr =
+			vars#declared var.v_name;
+			self#write ("$" ^ var.v_name ^ " = ");
+			match expr with
+				| None -> self#write "null"
+				| Some expr -> self#write_expr expr
+		(**
+			Writes TFunction to output buffer
+		*)
+		method private write_expr_function ?name func =
+			match name with
+				| None -> self#write_closure_declaration func self#write_function_arg
+				| Some "__construct" -> self#write_constructor_function_declaration func self#write_function_arg
+				| Some name -> self#write_method_function_declaration name func self#write_function_arg
+		(**
+			Writes constructor declaration (except visibility and `static` keywords) to output buffer
+		*)
+		method private write_constructor_function_declaration func write_arg =
+			self#write ("function __construct (");
+			write_args buffer write_arg func.tf_args;
+			self#write ") {\n";
+			self#indent_more;
+			self#write_instance_initialization;
+			let func = inject_defaults ctx func in
+			begin match func.eexpr with
+				| TBlock [] -> ()
+				| _ -> self#write_fake_block func;
+			end;
+			self#indent_less;
+			self#write_indentation;
+			self#write "}"
+		(**
+			Writes method declaration (except visibility and `static` keywords) to output buffer
+		*)
+		method private write_method_function_declaration name func write_arg =
+			let by_ref = if is_ref func.tf_type then "&" else "" in
+			self#write ("function " ^ by_ref ^ name ^ " (");
+			write_args buffer write_arg func.tf_args;
+			self#write ") ";
+			self#write_expr (inject_defaults ctx func)
+		(**
+			Writes closure declaration to output buffer
+		*)
+		method private write_closure_declaration func write_arg =
+			vars#dive;
+			self#write "function (";
+			write_args buffer write_arg func.tf_args;
+			self#write ")";
+			(* Generate closure body to separate buffer *)
+			let original_buffer = buffer in
+			buffer <- Buffer.create 256;
+			self#write_expr (inject_defaults ctx func);
+			let body = Buffer.contents buffer in
+			buffer <- original_buffer;
+			(* Use captured local vars *)
+			let used_vars = vars#pop_used in
+			self#write " ";
+			if List.length used_vars > 0 then begin
+				self#write " use (";
+				write_args buffer (fun name -> self#write ("&$" ^ name)) used_vars;
+				self#write ") "
+			end;
+			self#write body
+		(**
+			Writes TBlock to output buffer
+		*)
+		method private write_expr_block block_expr =
+			(* Check if parent expr could not contain blocks in PHP, and this block needs to be wrapped in a closure. *)
+			let needs_closure = match self#parent_expr with
+				| None -> false
+				| Some e ->
+					match e.eexpr with
+						| TIf (_, _, _) -> false
+						| TWhile (_, _, _) -> false
+						| TTry (_, _) -> false
+						| TFor (_, _, _) -> false
+						| TFunction _ -> false
+						| TBlock _ -> false
+						| TSwitch (_, _, _) -> false
+						| _ -> true
+			in
+			if needs_closure then
+				begin
+					self#write "(";
+					self#write_expr {
+						block_expr with eexpr = TFunction {
+							tf_args = [];
+							tf_type = block_expr.etype;
+							tf_expr = ensure_return_in_block block_expr;
+						}
+					};
+					self#write ")()"
+				end
+			else
+				begin
+					let inline_block = self#parent_expr_is_block in
+					self#write_as_block ~inline:inline_block block_expr
+				end
+		(**
+			Emulates TBlock for parent expression and writes `expr` as inlined block
+		*)
+		method private write_fake_block expr =
+			self#write_indentation;
+			let fake_block = { expr with eexpr = TBlock [expr] } in
+			expr_hierarchy <- fake_block :: expr_hierarchy;
+			self#write_as_block ~inline:true expr;
+			expr_hierarchy <- List.tl expr_hierarchy
+		(**
+			Writes "{ <expressions> }" to output buffer
+		*)
+		method private write_as_block ?inline ?unset_locals expr =
+			let unset_locals = match unset_locals with Some true -> true | _ -> false
+			and exprs = match expr.eexpr with TBlock exprs -> exprs | _ -> [expr] in
+			let write_body () =
+				let write_expr expr =
+					self#write_expr expr;
+					match expr.eexpr with
+						| TBlock _ | TIf _ | TTry _ | TSwitch _ | TWhile (_, _, NormalWhile) -> self#write "\n"
+						| _ -> self#write ";\n"
+				in
+				let write_expr_with_indent expr =
+					self#write_indentation;
+					write_expr expr
+				in
+				let write_exprs () =
+					match exprs with
+						| [] -> ()
+						| first :: rest ->
+							write_expr first; (* write first expression without indentation in case of block inlining *)
+							List.iter write_expr_with_indent rest
+				in
+				if unset_locals then
+					begin
+						let original_buffer = buffer in
+						buffer <- Buffer.create 256;
+						vars#dive;
+						write_exprs();
+						let body = Buffer.contents buffer in
+						buffer <- original_buffer;
+						let locals = vars#pop_declared in
+						if List.length locals > 0 then begin
+							self#write ("unset($" ^ (String.concat ", $" locals) ^ ");\n");
+							self#write_indentation
+						end;
+						self#write body
+					end
+				else
+					write_exprs()
+			in
+			match inline with
+				| Some true -> write_body ()
+				| _ ->
+					self#write "{\n";
+					self#indent_more;
+					(match exprs with
+						| [] -> ()
+						| _ ->
+							self#write_indentation; (* indentation for the first expression in block *)
+							write_body ()
+					);
+					self#indent_less;
+					self#write_indentation;
+					self#write "}"
+		(**
+			Writes TReturn to output buffer
+		*)
+		method private write_expr_return expr =
+			match expr with
+				| None -> self#write "return";
+				| Some expr ->
+					self#write "return ";
+					self#write_expr expr
+		(**
+			Writes TThrow to output buffer
+		*)
+		method private write_expr_throw expr =
+			self#write "throw ";
+			if is_native_exception expr.etype then
+				self#write_expr expr
+			else if sure_extends_extern expr.etype || is_dynamic_type expr.etype then
+				begin
+					self#write "(is_object($__hx__throw = ";
+					self#write_expr expr;
+					self#write (") && $__hx__throw instanceof \\Throwable ? $__hx__throw : new " ^ (self#use hxexception_type_path) ^ "($__hx__throw))")
+				end
+			else
+				begin
+					self#write ("new " ^ (self#use hxexception_type_path) ^ "(");
+					self#write_expr expr;
+					self#write ")"
+				end
+		(**
+			Writes try...catch to output buffer
+		*)
+		method private write_expr_try_catch try_expr catches =
+			let catching_dynamic = ref false in
+			let haxe_exception = self#use hxexception_type_path
+			and first_catch = ref true in
+			let write_catch (var, expr) =
+				let dynamic = ref false in
+				(match follow var.v_type with
+					| TInst ({ cl_path = ([], "String") }, _) -> self#write "if (is_string($__hx__real_e)) {\n"
+					| TAbstract ({ a_path = ([], "Float") }, _) -> self#write "if (is_float($__hx__real_e)) {\n"
+					| TAbstract ({ a_path = ([], "Int") }, _) -> self#write "if (is_int($__hx__real_e)) {\n"
+					| TAbstract ({ a_path = ([], "Bool") }, _) -> self#write "if (is_bool($__hx__real_e)) {\n"
+					| TDynamic _ ->
+						dynamic := true;
+						catching_dynamic := true;
+						if not !first_catch then self#write "{\n"
+					| vtype -> self#write ("if ($__hx__real_e instanceof " ^ (self#use_t vtype) ^ ") {\n")
+				);
+				if !dynamic && !first_catch then
+					begin
+						self#write ("$" ^ var.v_name ^ " = $__hx__real_e;\n");
+						self#write_indentation;
+						self#write_as_block ~inline:true expr;
+					end
+				else
+					begin
+						self#indent_more;
+						self#write_statement ("$" ^ var.v_name ^ " = $__hx__real_e");
+						self#write_indentation;
+						self#write_as_block ~inline:true expr;
+						self#indent_less;
+						self#write_indentation;
+						self#write "}";
+					end;
+				if not !dynamic then self#write " else ";
+				first_catch := false;
+			in
+			self#write "try ";
+			self#write_as_block try_expr;
+			self#write " catch (\\Throwable $__hx__caught_e) {\n";
+			self#indent_more;
+			if ctx.debug then
+				self#write_statement ((self#use (["haxe"], "CallStack")) ^ "::saveExceptionTrace($__hx__caught_e)");
+			self#write_statement ("$__hx__real_e = ($__hx__caught_e instanceof " ^ haxe_exception ^ " ? $__hx__caught_e->e : $__hx__caught_e)");
+			self#write_indentation;
+			List.iter write_catch catches;
+			if not !catching_dynamic then
+				self#write " throw $__hx__caught_e;\n"
+			else
+				(match catches with [_] -> () | _ -> self#write "\n");
+			self#indent_less;
+			self#write_indentation;
+			self#write "}"
+		(**
+			Writes TCast to output buffer
+		*)
+		method private write_expr_cast expr (mtype:module_type option) =
+			match mtype with
+				| None -> self#write_expr expr
+				| Some mtype ->
+					self#write ((self#use boot_type_path) ^ "::typedCast(");
+					self#write_expr_type mtype;
+					self#write ", ";
+					self#write_expr expr;
+					self#write ")"
+		(**
+			Write Haxe->PHP magic function call
+			@see http://old.haxe.org/doc/advanced/magic#php-magic
+		*)
+		method private write_expr_magic name args =
+			let error = error_message self#pos ("Invalid arguments for " ^ name ^ " magic call") in
+			match args with
+				| [] -> failwith error
+				| { eexpr = TConst (TString code) } as expr :: args ->
+					(match name with
+						| "__php__" ->
+							(match expr.eexpr with
+								| TConst (TString php) ->
+									Codegen.interpolate_code ctx php args self#write self#write_expr self#pos
+								| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+							)
+						| "__call__" ->
+							self#write (code ^ "(");
+							write_args buffer self#write_expr args;
+							self#write ")"
+						| "__physeq__" ->
+							(match args with
+								| [expr2] -> self#write_expr_binop OpEq expr expr2
+								| _ -> failwith error
+							)
+						| "__var__" ->
+							(match args with
+								| [expr2] ->
+									self#write ("$" ^ code ^ "[");
+									self#write_expr expr2;
+									self#write "]"
+								| _ -> failwith error
+							)
+						| _ -> failwith error
+					)
+				| [expr1; expr2] ->
+					(match name with
+						| "__physeq__" ->
+							(match args with
+								| [expr1; expr2] -> self#write_expr_binop OpEq expr1 expr2
+								| _ -> failwith error
+							)
+						| _ -> failwith error
+					)
+				| _ -> failwith error
+		(**
+			Writes TTypeExpr to output buffer
+		*)
+		method private write_expr_type (mtype:module_type) =
+			let ttype = type_of_module_type mtype in
+			match expr_hierarchy with
+				| _ :: { eexpr = TField _ } :: _ -> self#write (self#use_t ttype)
+				| _ ->
+					let class_name =
+						match self#use_t ttype with
+							| "int" -> "'Int'"
+							| "float" -> "'Float'"
+							| "bool" -> "'Bool'"
+							| "string" -> "'String'"
+							| "mixed" -> "'Dynamic'"
+							| "Enum" -> "'Enum'"
+							| "Class" -> "'Class'"
+							| name -> name ^ "::class"
+					in
+					self#write ((self#use boot_type_path) ^ "::getClass(" ^ class_name ^ ")")
+		(**
+			Writes binary operation to output buffer
+		*)
+		method private write_expr_binop operation expr1 expr2 =
+			let write_method method_name =
+				self#write (method_name ^ "(");
+				self#write_expr expr1;
+				self#write ", ";
+				self#write_expr expr2;
+				self#write ")"
+			in
+			let write_for_concat expr =
+				if ((is_constant expr) && not (is_constant_null expr)) || (is_concatenation expr) then
+					self#write_expr expr
+				else begin
+					self#write "(";
+					self#write_expr expr;
+					self#write "??'null')"
+				end
+			and write_binop ?writer ?right_writer str =
+				let write_left = match writer with None -> self#write_expr | Some writer -> writer in
+				let write_right = match right_writer with None -> write_left | Some writer -> writer
+				and need_parenthesis =
+					match expr_hierarchy with
+						| _ :: { eexpr = TBinop (parent, _, _) } :: _ -> need_parenthesis_for_binop operation parent
+						| _ -> false
+				in
+				if need_parenthesis then self#write "(";
+				write_left expr1;
+				self#write str;
+				write_right expr2;
+				if need_parenthesis then self#write ")"
+			and compare_strings op =
+				write_method "strcmp";
+				self#write (op ^ "0")
+			in
+			let compare op =
+				if is_string expr1 && is_string expr2 then
+						compare_strings op
+					else
+						write_binop op
+			in
+			match operation with
+				| OpAdd ->
+					if (is_string expr1) || (is_string expr2) then
+						write_binop ~writer:write_for_concat " . "
+					else if (is_unknown_type expr1.etype) && (is_unknown_type expr2.etype) then
+						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")
+					else
+						write_binop " === "
+				| OpNotEq ->
+					if need_boot_equal expr1 expr2 then
+						begin
+							self#write "!";
+							write_method ((self#use boot_type_path) ^ "::equal")
+						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 " % "
+					else
+						write_method "fmod"
+				| OpUShr -> write_method ((self#use boot_type_path) ^ "::shiftRightUnsigned")
+				| OpAssignOp OpAdd ->
+					if (is_string expr1) then
+						begin
+							self#write_expr expr1;
+							self#write " = ";
+							write_binop ~writer:write_for_concat " . "
+						end
+					else if (is_unknown_type expr1.etype) && (is_unknown_type expr2.etype) then
+						begin
+							self#write_expr expr1;
+							self#write " = ";
+							write_method ((self#use boot_type_path) ^ "::addOrConcat")
+						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 " %= "
+					else
+						write_method "fmod"
+				| OpAssignOp OpUShr ->
+					self#write_expr expr1;
+					self#write " = ";
+					write_method ((self#use boot_type_path) ^ "::shiftRightUnsigned")
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes TUnOp to output buffer
+		*)
+		method private 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_expr expr
+				| Postfix ->
+					self#write_expr expr;
+					write_unop operation
+		(**
+			Writes TField to output buffer
+		*)
+		method private write_expr_field expr access =
+			let write_access access_str field_str =
+				let access_str = ref access_str in
+				let expr_without_casts = reveal_expr expr in
+				(match expr_without_casts.eexpr with
+					| TNew _
+					| TArrayDecl _
+					| TObjectDecl _ -> self#write_expr (parenthesis expr)
+					| TConst TSuper ->
+						self#write "parent";
+						access_str := "::"
+					| _ -> self#write_expr expr
+				);
+				self#write (!access_str ^ field_str)
+			in
+			match (follow expr.etype, access) with
+				| (TInst ({ cl_path = ([], "String") }, _), FInstance (_, _, { cf_name = "length"; cf_kind = Var _ })) ->
+					self#write "strlen(";
+					self#write_expr expr;
+					self#write ")"
+				| (_, FInstance (_, _, field)) -> write_access "->" (field_name field)
+				| (_, FStatic (_, ({ cf_kind = Var _ } as field))) ->
+					(match (reveal_expr expr).eexpr with
+						| TTypeExpr _ -> write_access "::" ("$" ^ (field_name field))
+						| _ -> write_access "->" (field_name field)
+					)
+				| (_, FStatic (_, ({ cf_kind = Method MethDynamic } as field))) ->
+					(match expr_hierarchy with
+						| _ :: { eexpr = TCall ({ eexpr = TField (e, a) }, _) } :: _ when a == access ->
+							self#write "(";
+							write_access "::" ("$" ^ (field_name field));
+							self#write ")"
+						| _ ->
+							write_access "::" ("$" ^ (field_name field))
+					)
+				| (_, FStatic (_, ({ cf_kind = Method _ } as field))) -> self#write_expr_field_static expr field
+				| (_, FAnon field) ->
+					let written_as_probable_string = self#write_expr_field_if_string expr (field_name field) in
+					if not written_as_probable_string then write_access "->" (field_name field)
+				| (_, FDynamic field_name) ->
+					let written_as_probable_string = self#write_expr_field_if_string expr field_name in
+					if not written_as_probable_string then write_access "->" field_name
+				| (_, FClosure (tcls, field)) -> self#write_expr_field_closure tcls field expr
+				| (_, FEnum (_, field)) ->
+					if is_enum_constructor_with_args field then
+						if not self#parent_expr_is_call then
+							begin
+								self#write (self#use boot_type_path ^ "::closure(");
+								self#write_expr expr;
+								(match (reveal_expr expr).eexpr with
+									| TTypeExpr _ -> self#write "::class"
+									| _ -> self#write "->phpClassName"
+								);
+								self#write (", '" ^ field.ef_name ^ "')")
+							end
+						else
+							write_access "::" field.ef_name
+					else
+						begin
+							write_access "::" field.ef_name;
+							self#write "()"
+						end
+
+		(**
+			Writes field access on Dynamic expression to output buffer
+		*)
+		method private write_expr_field_if_string expr field_name =
+			(* Special case for String fields *)
+			match field_name with
+				| "length"
+				| "toUpperCase"
+				| "toLowerCase"
+				| "charAt"
+				| "indexOf"
+				| "lastIndexOf"
+				| "split"
+				| "toString"
+				| "substring"
+				| "substr"
+				| "charCodeAt" ->
+					self#write ((self#use hxdynamicstr_type_path) ^ "::wrap(");
+					self#write_expr expr;
+					self#write (")->" ^ field_name);
+					true
+				| _ ->
+					false
+		(**
+			Convert field access expressions for strings to native PHP string functions and write to output buffer
+		*)
+		method private write_expr_call_string expr access args =
+			match access with
+				| FInstance (_, _, ({ cf_kind = Method _ } as field)) ->
+					self#write ((self#use hxstring_type_path) ^ "::" ^ (field_name field) ^ "(");
+					write_args buffer self#write_expr (expr :: args);
+					self#write ")"
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes FStatic field access for methods to output buffer
+		*)
+		method private write_expr_field_static expr field =
+			let write_expr () =
+				match expr.eexpr with
+					| TTypeExpr (TClassDecl { cl_path = ([], "String") }) -> self#write (self#use hxstring_type_path)
+					| _ -> self#write_expr expr
+			and operator =
+				match (reveal_expr expr).eexpr with
+					| TTypeExpr _ -> "::"
+					| _ -> "->"
+			in
+			match expr_hierarchy with
+				| _ :: { eexpr = TCall ({ eexpr = TField (e, FStatic (_, f)) }, _) } :: _ when e == expr && f == field ->
+					write_expr ();
+					self#write (operator ^ (field_name field))
+				| _ ->
+					let (args, return_type) = get_function_signature field  in
+					self#write "function(";
+					write_args buffer (self#write_arg true) args;
+					self#write ") { return ";
+					write_expr ();
+					self#write (operator ^ (field_name field) ^ "(");
+					write_args buffer (self#write_arg false) args;
+					self#write "); }"
+		(**
+			Writes FClosure field access to output buffer
+		*)
+		method private write_expr_field_closure tcls field expr =
+			if is_dynamic_method field then
+				match expr.eexpr with
+					| TTypeExpr mtype ->
+						let class_name = self#use_t (type_of_module_type mtype) in
+						self#write (class_name ^ "::$" ^ (field_name field) ^ "'");
+					| _ ->
+						self#write_expr expr;
+						self#write ("->" ^ (field_name field))
+			else
+				let new_closure = "new " ^ (self#use hxclosure_type_path) in
+				match expr.eexpr with
+					| TTypeExpr mtype ->
+						let class_name = self#use_t (type_of_module_type mtype) in
+						self#write (new_closure ^ "(" ^ class_name ^ "::class, '" ^ (field_name field) ^ "')");
+					| _ ->
+						self#write (new_closure ^ "(");
+						(match follow expr.etype with
+							| TInst ({ cl_path = ([], "String") }, []) ->
+								self#write ((self#use hxdynamicstr_type_path) ^ "::wrap(");
+								self#write_expr expr;
+								self#write ")"
+							| _ ->
+								self#write_expr expr
+						);
+						self#write (", '" ^ (field_name field) ^ "')")
+		(**
+			Write anonymous object declaration to output buffer
+		*)
+		method private write_expr_object_declaration fields =
+			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 "])"
+		(**
+			Writes specified type to output buffer depending on type of expression.
+		*)
+		method private write_type type_expr =
+			match type_expr.eexpr with
+				| TTypeExpr (TClassDecl tcls) ->
+					self#write (self#use_t (TInst (tcls, [])))
+				| _ ->
+					if is_string type_expr then
+						self#write_expr type_expr
+					else begin
+						self#write "(";
+						self#write_expr type_expr;
+						self#write "->phpClassName)";
+					end
+		(**
+			Write language specific expression declared in `php.PHP` extern
+		*)
+		method private write_expr_call_lang_extern expr args =
+			let name = match expr.eexpr with
+				| TField (_, FStatic (_, field)) -> field_name field
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+			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
+				| "keepVar" -> ()
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes splat operator (for `php.Syntax.splat()`)
+		*)
+		method private write_expr_lang_splat args =
+			match args with
+				| [ args_expr ] ->
+					self#write "...";
+					self#write_expr args_expr
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes error suppression operator (for `php.Syntax.suppress()`)
+		*)
+		method private write_expr_lang_suppress args =
+			match args with
+				| [ args_expr ] ->
+					self#write "@";
+					self#write_expr args_expr
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes native array declaration (for `php.Syntax.arrayDecl()`)
+		*)
+		method private write_expr_lang_array_decl args =
+			self#write "[";
+			write_args buffer (fun e -> self#write_expr e) args;
+			self#write "]"
+		(**
+			Writes a call to instance method (for `php.Syntax.call()`)
+		*)
+		method private write_expr_lang_call args =
+			match args with
+				| obj_expr :: method_expr :: args ->
+					self#write_expr obj_expr;
+					self#write "->{";
+					self#write_expr method_expr;
+					self#write "}(";
+					write_args buffer (fun e -> self#write_expr e) args;
+					self#write ")"
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes a call to a static method (for `php.Syntax.staticCall()`)
+		*)
+		method private write_expr_lang_static_call args =
+			match args with
+				| type_expr :: method_expr :: args ->
+					self#write_type type_expr;
+					self#write "::{";
+					self#write_expr method_expr;
+					self#write "}(";
+					write_args buffer (fun e -> self#write_expr e) args;
+					self#write ")"
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes field access for reading (for `php.Syntax.getField()`)
+		*)
+		method private write_expr_lang_get_field args =
+			match args with
+				| obj_expr :: field_expr :: [] ->
+					self#write_expr obj_expr;
+					self#write "->{";
+					self#write_expr field_expr;
+					self#write "}"
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes field access for writing (for `php.Syntax.setField()`)
+		*)
+		method private write_expr_lang_set_field args =
+			match args with
+				| obj_expr :: field_expr :: value_expr :: [] ->
+					self#write_expr obj_expr;
+					self#write "->{";
+					self#write_expr field_expr;
+					self#write "}";
+					self#write " = ";
+					self#write_expr value_expr
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes static field access for reading (for `php.Syntax.getStaticField()`)
+		*)
+		method private write_expr_lang_get_static_field args =
+			match args with
+				| type_expr :: field_expr :: [] ->
+					self#write_type type_expr;
+					self#write "::${";
+					self#write_expr field_expr;
+					self#write "}"
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes static field access for writing (for `php.Syntax.setField()`)
+		*)
+		method private write_expr_lang_set_static_field args =
+			match args with
+				| type_expr :: field_expr :: value_expr :: [] ->
+					self#write_expr type_expr;
+					self#write "::${";
+					self#write_expr field_expr;
+					self#write "}";
+					self#write " = ";
+					self#write_expr value_expr
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes `new` expression with class name taken local variable (for `php.Syntax.construct()`)
+		*)
+		method private write_expr_lang_construct args =
+			let (class_expr, args) = match args with
+				| class_expr :: args -> (class_expr, args)
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+			in
+			self#write "new ";
+			self#write_expr class_expr;
+			self#write "(";
+			write_args buffer (fun e -> self#write_expr e) args;
+			self#write ")"
+		(**
+			Writes native php type conversion to output buffer (e.g. `php.Syntax.int()`)
+		*)
+		method private 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 (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Generates binary operation to output buffer (for `php.Syntax.binop()`)
+		*)
+		method private 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 (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes `instanceof` expression to output buffer (for `php.Syntax.instanceof()`)
+		*)
+		method private write_expr_lang_instanceof args =
+			match args with
+				| val_expr :: type_expr :: [] ->
+					self#write_expr val_expr;
+					self#write " instanceof ";
+					(match type_expr.eexpr with
+						| TTypeExpr (TClassDecl tcls) ->
+							self#write (self#use_t (TInst (tcls, [])))
+						| _ ->
+							self#write_expr type_expr;
+							if not (is_string type_expr) then self#write "->phpClassName"
+					)
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes `foreach` expression to output buffer (for `php.Syntax.foreach()`)
+		*)
+		method private write_expr_lang_foreach args =
+			match args with
+				| collection_expr :: { eexpr = TFunction fn } :: [] ->
+					let (key_name, value_name) = match fn.tf_args with
+						| ({ v_name = key_name }, _) :: ({ v_name = value_name }, _) :: [] -> (key_name, value_name)
+						| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+					and add_parentheses =
+						match collection_expr.eexpr with
+							| TLocal _ -> false
+							| _ -> true
+					in
+					self#write "foreach (";
+					if add_parentheses then self#write "(";
+					self#write_expr collection_expr;
+					if add_parentheses then self#write ")";
+					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."
+		(**
+			Writes TCall to output buffer
+		*)
+		method private write_expr_call target_expr args =
+			let target_expr = reveal_expr target_expr in
+			(match target_expr.eexpr with
+				| TConst TSuper -> self#write "parent::__construct"
+				| TField (expr, FClosure (_,_)) -> self#write_expr (parenthesis target_expr)
+				| _ -> self#write_expr target_expr
+			);
+			self#write "(";
+			write_args buffer self#write_expr args;
+			self#write ")";
+		(**
+			Writes a name of a function or a constant from global php namespace
+		*)
+		method private write_expr_php_global target_expr =
+			match target_expr.eexpr with
+				| TField (_, FStatic (_, field)) -> self#write (field_name field)
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes access to PHP class constant
+		*)
+		method private write_expr_php_class_const target_expr =
+			match target_expr.eexpr with
+				| TField (_, FStatic (ecls, field)) ->
+					self#write ((self#use_t (TInst (ecls, []))) ^ "::" ^ (field_name field))
+				| _ -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes TNew to output buffer
+		*)
+		method private write_expr_new inst_class args =
+			let needs_php_prefix = not inst_class.cl_extern in
+			self#write ("new " ^ (self#use ~prefix:needs_php_prefix inst_class.cl_path) ^ "(");
+			write_args buffer self#write_expr args;
+			self#write ")"
+		(**
+			Writes ternary operator expressions to output buffer
+		*)
+		method private write_expr_ternary condition if_expr (else_expr:texpr) pos =
+			let parent_is_if = match self#parent_expr with Some { eexpr = TIf _ } -> true | _ -> false in
+			if parent_is_if then self#write "(";
+			(match condition.eexpr with
+				| TParenthesis expr -> self#write_expr expr;
+				| _ -> self#write_expr else_expr
+			);
+			self#write " ? ";
+			self#write_expr if_expr;
+			self#write " : ";
+			self#write_expr else_expr;
+			if parent_is_if then self#write ")"
+		(**
+			Writes "if...else..." expression to output buffer
+		*)
+		method private write_expr_if condition if_expr (else_expr:texpr option) =
+			let is_ternary =
+				if self#parent_expr_is_block then
+					false
+				else
+					match (if_expr.eexpr, else_expr) with
+						| (TBlock _, _) | (_, Some { eexpr=TBlock _ }) -> false
+						| _ -> true
+			in
+			if is_ternary then
+				match else_expr with
+					| None -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+					| Some expr ->
+						self#write_expr_ternary condition if_expr expr self#pos
+			else begin
+				self#write "if ";
+				self#write_expr condition;
+				self#write " ";
+				self#write_as_block if_expr;
+				(match else_expr with
+					| None -> ()
+					| Some expr ->
+						self#write " else ";
+						match expr.eexpr with
+							| TIf _ -> self#write_expr expr
+							| _ -> self#write_as_block expr
+				)
+			end
+		(**
+			Writes TWhile ("while..." or "do...while") to output buffer
+		*)
+		method private write_expr_while condition expr do_while =
+			match do_while with
+				| NormalWhile ->
+					self#write "while ";
+					self#write_expr condition;
+					self#write " ";
+					self#write_as_block ~unset_locals:true expr
+				| DoWhile ->
+					self#write "do ";
+					self#write_as_block ~unset_locals:true expr;
+					self#write " while ";
+					self#write_expr condition
+		(**
+			Writes TSwitch to output buffer
+		*)
+		method private write_expr_switch switch cases default =
+			let write_case (conditions, expr) =
+				List.iter
+					(fun condition ->
+						self#write_indentation;
+						self#write "case ";
+						self#write_expr condition;
+						self#write ":\n";
+					)
+					conditions;
+				self#indent_more;
+				self#write_indentation;
+				self#write_as_block ~inline:true expr;
+				self#write_statement "break";
+				self#indent_less
+			in
+			self#write "switch ";
+			self#write_expr switch;
+			self#write " {\n";
+			self#indent_more;
+			List.iter write_case cases;
+			(match default with
+				| None -> ()
+				| Some expr ->
+					self#write_line "default:";
+					self#indent_more;
+					self#write_indentation;
+					self#write_as_block ~inline:true expr;
+					self#write_statement "break";
+					self#indent_less
+			);
+			self#indent_less;
+			self#write_indentation;
+			self#write "}"
+		(**
+			Write TEnumParameter expression to output buffer
+		*)
+		method private write_expr_enum_parameter expr constructor index =
+			(match expr.eexpr with
+				| TConst TNull -> self#write "(null)"
+				| _ -> self#write_expr expr
+			);
+			self#write ("->params[" ^ (string_of_int index) ^ "]")
+		(**
+			Writes argument for function declarations or calls
+		*)
+		method write_arg with_optionals (arg_name, optional, (arg_type:Type.t)) =
+			self#write ("$" ^ arg_name ^ (if with_optionals && optional then " = null" else ""))
+		(**
+			Writes argument with optional value for function declarations
+		*)
+		method write_function_arg arg =
+			match arg with
+				| ({ v_name = arg_name; v_type = arg_type }, default_value) ->
+					vars#declared arg_name;
+					if is_ref arg_type then self#write "&";
+					self#write ("$" ^ arg_name);
+					match default_value with
+						| None -> ()
+						| Some const ->
+							self#write " = ";
+							self#write_expr_const const
+	end
+
+(**
+	Builds enum contents
+*)
+class enum_builder ctx (enm:tenum) =
+	object (self)
+		inherit type_builder ctx (get_wrapper (TEnumDecl enm))
+		(**
+			Writes type declaration line to output buffer.
+			E.g. "class SomeClass extends Another implements IFace"
+		*)
+		method private write_declaration =
+			self#write_doc (DocClass enm.e_doc);
+			self#write ("class " ^ self#get_name ^ " extends " ^ (self#use hxenum_type_path))
+		(**
+			Writes type body to output buffer.
+			E.g. for "class SomeClass { <BODY> }" writes <BODY> part.
+		*)
+		method private write_body =
+			let write_empty_lines = ref false in
+			PMap.iter
+				(fun name field ->
+					if !write_empty_lines then
+						self#write_empty_lines
+					else
+						write_empty_lines := true;
+					self#write_constructor name field
+				)
+				enm.e_constrs;
+			self#write_reflection
+		(**
+			Writes constructor declaration to output buffer
+		*)
+		method private write_constructor name (field:tenum_field) =
+			let args =
+				match follow field.ef_type with
+					| TFun (args, _) -> args
+					| TEnum _ -> []
+					| _ -> fail field.ef_pos (try assert false with Assert_failure mlpos -> mlpos)
+			in
+			self#indent 1;
+			self#write_doc (DocMethod (args, TEnum (enm, []), field.ef_doc));
+			self#write_indentation;
+			self#write ("static public function " ^ name ^ " (");
+			write_args buffer (self#write_arg true) args;
+			self#write ") {\n";
+			self#indent_more;
+			self#write_indentation;
+			self#write "return ";
+			let index_str = string_of_int field.ef_index in
+			(match args with
+				| [] -> self#write ((self#use hxenum_type_path) ^ "::singleton(static::class, '" ^ name ^ "', " ^ index_str ^")")
+				| args ->
+					self#write ("new " ^ self#get_name ^ "('" ^ name ^ "', " ^ index_str ^", [");
+					write_args buffer (fun (name, _, _) -> self#write ("$" ^ name)) args;
+					self#write "])"
+			);
+			self#write ";\n";
+			self#indent_less;
+			self#write_line "}"
+		(**
+			Writes special methods for reflection
+		*)
+		method private write_reflection =
+			(* __hx__list *)
+			self#write_empty_lines;
+			self#indent 1;
+			self#write_line "/**";
+			self#write_line " * Returns array of (constructorIndex => constructorName)";
+			self#write_line " *";
+			self#write_line " * @return string[]";
+			self#write_line " */";
+			self#write_line "static public function __hx__list () {";
+			self#indent_more;
+			self#write_line "return [";
+			self#indent_more;
+			PMap.iter
+				(fun name field ->
+					self#write_line ((string_of_int field.ef_index) ^ " => '" ^ name ^ "',")
+				)
+				enm.e_constrs;
+			self#indent_less;
+			self#write_statement "]";
+			self#indent_less;
+			self#write_line "}";
+			(* __hx__paramsCount *)
+			self#write_empty_lines;
+			self#indent 1;
+			self#write_line "/**";
+			self#write_line " * Returns array of (constructorName => parametersCount)";
+			self#write_line " *";
+			self#write_line " * @return int[]";
+			self#write_line " */";
+			self#write_line "static public function __hx__paramsCount () {";
+			self#indent_more;
+			self#write_line "return [";
+			self#indent_more;
+			PMap.iter
+				(fun name field ->
+					let count = match follow field.ef_type with
+						| TFun (params, _) -> List.length params
+						| TEnum _ -> 0
+						| _ -> fail field.ef_pos (try assert false with Assert_failure mlpos -> mlpos)
+					in
+					self#write_line ("'" ^ name ^ "' => " ^ (string_of_int count) ^ ",")
+				)
+				enm.e_constrs;
+			self#indent_less;
+			self#write_statement "]";
+			self#indent_less;
+			self#write_line "}";
+		(**
+			Method `__hx__init` is not needed for enums
+		**)
+		method private write_hx_init_body = ()
+		(**
+			No need for additional initialization of enum instances
+		*)
+		method private write_instance_initialization = ()
+		(**
+			No need for additional type initialization for enums
+		*)
+		method private write_pre_hx_init = ()
+	end
+
+(**
+	Builds class contents
+*)
+class class_builder ctx (cls:tclass) =
+	object (self)
+		inherit type_builder ctx (get_wrapper (TClassDecl cls)) as super
+		(**
+			Indicates if type should be declared as `final`
+		*)
+		method is_final =
+			if not (Meta.has Meta.Final cls.cl_meta) then
+				false
+			else begin
+				let hacked = ref false in
+				List.iter
+					(fun com_type ->
+						if not !hacked then
+							match com_type with
+								| TClassDecl tcls ->
+									if self#extended_by tcls then hacked := Meta.has Meta.Hack tcls.cl_meta
+								| _ -> ()
+					)
+					ctx.types;
+				not !hacked
+			end
+		(**
+			Indicates if `field` should be declared as `final`
+		*)
+		method is_final_field (field:tclass_field) : bool =
+			Meta.has Meta.Final field.cf_meta
+		(**
+			Recursively check if current class is a parent class for a `child`
+		*)
+		method private extended_by child =
+			let result =
+				if child == cls then
+					false
+				else
+					let rec check current =
+						match current.cl_super with
+							| None -> false
+							| Some (scls, _) ->
+								if scls == cls then true else check scls
+					in
+					check child
+			in
+			result
+		(**
+			Writes type declaration line to output buffer.
+			E.g. "class SomeClass extends Another implements IFace"
+		*)
+		method private write_declaration =
+			if self#is_final then self#write "final ";
+			self#write_doc (DocClass cls.cl_doc);
+			self#write (if cls.cl_interface then "interface " else "class ");
+			self#write self#get_name;
+			(
+				match cls.cl_super with
+					| None -> ();
+					| Some (super_class, params) ->
+						let super_name = self#use_t (TInst (super_class, params)) in
+						self#write (" extends " ^ super_name)
+			);
+			if List.length cls.cl_implements > 0 then begin
+				self#write (if cls.cl_interface then " extends " else " implements ");
+				let use_interface iface =
+					match iface with
+						| (i, params) -> self#use_t (TInst (i, params))
+				in
+				let interfaces = List.map use_interface cls.cl_implements in
+				self#write (String.concat ", " interfaces);
+			end;
+		(**
+			Returns either user-defined constructor or creates empty constructor if instance initialization is required.
+		*)
+		method private get_constructor : tclass_field option =
+			match cls.cl_constructor with
+				| Some field -> Some field
+				| None ->
+					if not self#constructor_is_required then
+						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 = [];
+							cf_kind = Method MethNormal;
+							cf_params = [];
+							cf_expr = Some {
+								eexpr = TFunction {
+									tf_args = [];
+									tf_type = get_void ctx;
+									tf_expr = { eexpr = TBlock []; epos = cls.cl_pos; etype = get_void ctx; };
+								};
+								epos = cls.cl_pos;
+								etype = get_void ctx;
+							};
+							cf_expr_unoptimized = None;
+							cf_overloads = [];
+						}
+		(**
+			Writes type body to output buffer.
+			E.g. for "class SomeClass { <BODY> }" writes <BODY> part.
+		*)
+		method private write_body =
+			let at_least_one_field_written = ref false in
+			let write_if_constant _ field =
+				match field.cf_kind with
+					| Var { v_read = AccInline; v_write = AccNever } ->
+						at_least_one_field_written := true;
+						self#write_field true field
+					| _ -> ()
+			and write_if_method is_static _ field =
+				match field.cf_kind with
+					| Var _ -> ()
+					| Method MethDynamic when is_static -> ()
+					| Method _ ->
+						if !at_least_one_field_written then self#write_empty_lines;
+						at_least_one_field_written := true;
+						self#write_field is_static field
+			and write_if_var is_static _ field =
+				match field.cf_kind with
+					| Var { v_read = AccInline; v_write = AccNever } -> ()
+					| Method MethDynamic ->
+						at_least_one_field_written := true;
+						let kind = Var { v_read = AccNormal; v_write = AccNormal; } in
+						self#write_field is_static { field with cf_kind = kind }
+					| Var _ ->
+						at_least_one_field_written := true;
+						self#write_field is_static field
+					| Method _ -> ()
+			in
+			if boot_type_path = self#get_type_path then begin
+				self#write_php_prefix ();
+				at_least_one_field_written := true
+			end;
+		 	if not cls.cl_interface then begin
+		 		(* Inlined statc vars (constants) *)
+				PMap.iter (write_if_constant) cls.cl_statics;
+				if !at_least_one_field_written then self#write_empty_lines;
+				at_least_one_field_written := false;
+		 		(* Statc vars *)
+				PMap.iter (write_if_var true) cls.cl_statics;
+				if !at_least_one_field_written then self#write_empty_lines;
+				at_least_one_field_written := false;
+				(* instance vars *)
+				PMap.iter (write_if_var false) cls.cl_fields
+			end;
+			(* Statc methods *)
+			PMap.iter (write_if_method true) cls.cl_statics;
+			(* Constructor *)
+			(match self#get_constructor with
+				| Some field -> write_if_method false "new" field
+				| None -> ()
+			);
+			(* Instance methods *)
+			PMap.iter (write_if_method false) cls.cl_fields;
+			(* Generate `__toString()` if not defined by user, but has `toString()` *)
+			self#write_toString_if_required
+		method private write_toString_if_required =
+			if PMap.exists "toString" cls.cl_fields then
+				if (not cls.cl_interface) && (not (PMap.exists "__toString" cls.cl_statics)) && (not (PMap.exists "__toString" cls.cl_fields)) then
+					begin
+						self#write_empty_lines;
+						self#indent 1;
+						self#write_line "public function __toString() {";
+						self#indent_more;
+						self#write_line "return $this->toString();";
+						self#indent_less;
+						self#write_line "}"
+					end
+		(**
+			Check if this class requires constructor to be generated even if there is no user-defined one
+		*)
+		method private constructor_is_required =
+			if List.length self#get_namespace > 0 then
+				false
+			else begin
+				let required = ref false in
+				List.iter
+					(fun field ->
+						if not !required then
+							required := (String.lowercase field.cf_name = String.lowercase self#get_name)
+					)
+					(cls.cl_ordered_statics @ cls.cl_ordered_fields);
+				!required
+			end
+		(**
+			Writes `--php-prefix` value as class constant PHP_PREFIX
+		*)
+		method private write_php_prefix () =
+			let prefix = String.concat "\\" (get_php_prefix ctx) in
+			let indentation = String.length indentation in
+			self#indent 1;
+			self#write_statement ("const PHP_PREFIX = \"" ^ (String.escaped prefix) ^ "\"");
+			self#indent indentation
+		(**
+			Writes expressions for `__hx__init` method
+		*)
+		method private write_hx_init_body =
+			(* `static dynamic function` initialization *)
+			let write_dynamic_method_initialization field =
+				let field_access = "self::$" ^ (field_name field) in
+				self#write_indentation;
+				self#write (field_access ^ " = ");
+				(match field.cf_expr with
+					| Some expr -> self#write_expr expr
+					| None -> fail field.cf_pos (try assert false with Assert_failure mlpos -> mlpos)
+				);
+				self#write ";\n"
+			in
+			PMap.iter
+				(fun _ field ->
+					match field.cf_kind with
+						| Method MethDynamic -> write_dynamic_method_initialization field
+						| _ -> ()
+				)
+				cls.cl_statics;
+			(* `static var` initialization *)
+			let write_var_initialization _ field =
+				let write_assign expr =
+					self#write_indentation;
+					self#write ("self::$" ^ (field_name field) ^ " = ");
+					self#write_expr expr
+				in
+				(* Do not generate fields for RTTI meta, because this generator uses another way to store it *)
+				let is_auto_meta_var = field.cf_name = "__meta__" && (has_rtti_meta ctx wrapper#get_module_type) in
+				if (is_var_with_nonconstant_expr field) && (not is_auto_meta_var) then begin
+					(match field.cf_expr with
+						| None -> ()
+						(* There can be not-inlined blocks when compiling with `-debug` *)
+						| Some { eexpr = TBlock exprs } ->
+							let rec write_per_line exprs =
+								match exprs with
+									| [] -> ()
+									| [expr] -> write_assign expr
+									| expr :: rest ->
+										self#write_indentation;
+										self#write_expr expr;
+										self#write ";\n";
+										write_per_line rest
+							in
+							write_per_line exprs
+						| Some expr -> write_assign expr
+					);
+					self#write ";\n"
+				end
+			in
+			PMap.iter write_var_initialization cls.cl_statics
+		(**
+			Writes single field to output buffer.
+		*)
+		method private write_field is_static field =
+			match field.cf_kind with
+				| Var { v_read = AccInline; v_write = AccNever } -> self#write_const field
+				| Var _ when is_real_var field ->
+					(* Do not generate fields for RTTI meta, because this generator uses another way to store it *)
+					let is_auto_meta_var = is_static && field.cf_name = "__meta__" && (has_rtti_meta ctx wrapper#get_module_type) in
+					if not is_auto_meta_var then self#write_var field is_static;
+				| Var _ -> ()
+				| Method MethMacro -> ()
+				| Method MethDynamic when is_static -> ()
+				| Method MethDynamic -> self#write_dynamic_method field
+				| Method _ -> self#write_method field is_static
+		(**
+			Writes var-field to output buffer
+		*)
+		method private write_var field is_static =
+			self#indent 1;
+			self#write_doc (DocVar (self#use_t field.cf_type, field.cf_doc));
+			self#write_indentation;
+			if is_static then self#write "static ";
+			let visibility = get_visibility field.cf_meta in
+			self#write (visibility ^ " $" ^ (field_name field));
+			match field.cf_expr with
+				| None -> self#write ";\n"
+				| Some expr ->
+					match expr.eexpr with
+						| TConst _ ->
+							self#write " = ";
+							self#write_expr expr;
+							self#write ";\n"
+						| _ -> self#write ";\n"
+		(**
+			Writes "inline var" to output buffer as constant
+		*)
+		method private write_const field =
+			self#indent 1;
+			self#write_doc (DocVar (self#use_t field.cf_type, field.cf_doc));
+			self#write_indentation;
+			self#write ("const " ^ (field_name field) ^ " = ");
+			match field.cf_expr with
+				| None -> fail self#pos (try assert false with Assert_failure mlpos -> mlpos)
+				| Some expr ->
+					self#write_expr expr;
+					self#write ";\n"
+		(**
+			Writes method to output buffer
+		*)
+		method private write_method field is_static =
+			vars#clear;
+			self#indent 1;
+			let (args, return_type) = get_function_signature field in
+			List.iter (fun (arg_name, _, _) -> vars#declared arg_name) args;
+			self#write_doc (DocMethod (args, return_type, field.cf_doc));
+			self#write_indentation;
+			if self#is_final_field field then self#write "final ";
+			if is_static then self#write "static ";
+			self#write ((get_visibility field.cf_meta) ^ " ");
+			match field.cf_expr with
+				| None ->
+					self#write ("function " ^ (field_name field) ^ " (");
+					write_args buffer (self#write_arg true) args;
+					self#write ")";
+					self#write " ;\n"
+				| Some { eexpr = TFunction fn } ->
+					let name = if field.cf_name = "new" then "__construct" else (field_name field) in
+					self#write_expr_function ~name:name fn;
+					self#write "\n"
+				| _ -> fail field.cf_pos (try assert false with Assert_failure mlpos -> mlpos)
+		(**
+			Writes dynamic method to output buffer.
+			Only for non-static methods. Static methods are created as static vars in `__hx__init`.
+		*)
+		method private write_dynamic_method field =
+			vars#clear;
+			self#indent 1;
+			let (args, return_type) = get_function_signature field in
+			List.iter (fun (arg_name, _, _) -> vars#declared arg_name) args;
+			self#write_doc (DocMethod (args, return_type, field.cf_doc));
+			self#write_indentation;
+			self#write ((get_visibility field.cf_meta) ^ " function " ^ (field_name field));
+			(match field.cf_expr with
+				| None -> (* interface *)
+					self#write " (";
+					write_args buffer (self#write_arg true) args;
+					self#write ");\n";
+				| Some { eexpr = TFunction fn } -> (* normal class *)
+					self#write " (";
+					write_args buffer self#write_function_arg fn.tf_args;
+					self#write ")\n";
+					self#write_line "{";
+					self#indent_more;
+					self#write_indentation;
+					let field_access = "$this->" ^ (field_name field)
+					and default_value = "$this->__hx__default__" ^ (field_name field) in
+					self#write ("if (" ^ field_access ^ " !== " ^ default_value ^ ") return call_user_func_array(" ^ field_access ^ ", func_get_args());\n");
+					self#write_fake_block fn.tf_expr;
+					self#indent_less;
+					self#write_line "}";
+					(* Don't forget to create a field for default value *)
+					self#write_statement ("protected $__hx__default__" ^ (field_name field))
+				| _ -> fail field.cf_pos (try assert false with Assert_failure mlpos -> mlpos)
+			);
+		(**
+			Writes initialization code for instances of this class
+		*)
+		method private write_instance_initialization =
+			let init_dynamic_method field =
+				let field_name = field_name field in
+				let default_field = "$this->__hx__default__" ^ field_name in
+				self#write_line ("if (!" ^ default_field ^ ") {");
+				self#indent_more;
+				self#write_statement (default_field ^ " = new " ^ (self#use hxclosure_type_path) ^ "($this, '" ^ field_name ^ "')");
+				self#write_statement ("if ($this->" ^ field_name ^ " === null) $this->" ^ field_name ^ " = " ^ default_field);
+				self#indent_less;
+				self#write_line "}"
+			in
+			PMap.iter
+				(fun _ field ->
+					match field.cf_kind with
+						| Method MethDynamic -> init_dynamic_method field
+						| _ -> ()
+				)
+				cls.cl_fields
+		(**
+			Writes additional initialization code, which should be called before `__hx__init()`
+		*)
+		method private write_pre_hx_init =
+			let getters = ref []
+			and setters = ref [] in
+			let collect field =
+				match field.cf_kind with
+					| Var { v_read = read; v_write = write } ->
+						if read = AccCall then getters := field.cf_name :: !getters;
+						if write = AccCall then setters := field.cf_name :: !setters;
+					| _ -> ()
+			in
+			List.iter collect cls.cl_ordered_fields;
+			List.iter collect cls.cl_ordered_statics;
+			let rec write lst =
+				match lst with
+					| [] -> ()
+					| [item] -> self#write_line ("'" ^ item ^ "' => true");
+					| item :: rest ->
+						self#write_line ("'" ^ item ^ "' => true,");
+						write rest
+			and type_name = get_full_type_name ~escape:true ~omit_first_slash:true (add_php_prefix ctx wrapper#get_type_path) in
+			let write_register register_method lst =
+				self#write_line ((self#use boot_type_path) ^ "::" ^ register_method ^ "('" ^ type_name ^ "', [");
+				self#indent_more;
+				write lst;
+				self#indent_less;
+				self#write_statement "])"
+			in
+			if List.length !getters > 0 then write_register "registerGetters" !getters;
+			if List.length !setters > 0 then write_register "registerSetters" !setters;
+	end
+
+(**
+	Handles generation process
+*)
+class generator (com:context) =
+	object (self)
+		val mutable build_dir = ""
+		val root_dir = com.file
+		val mutable init_types = []
+		val mutable boot : (type_builder * string) option  = None
+		(**
+			Perform required actions before actual php files generation
+		*)
+		method initialize =
+			self#create_output_dirs;
+		(**
+			Generates php file for specified type
+		*)
+		method generate (builder:type_builder) =
+			let contents = builder#get_contents
+			and namespace = builder#get_namespace
+			and name = builder#get_name in
+			let filename = (create_dir_recursive (build_dir :: namespace)) ^ "/" ^ name ^ ".php" in
+			let channel = open_out filename in
+			output_string channel contents;
+			close_out channel;
+			if builder#get_type_path = boot_type_path then
+				boot <- Some (builder, filename)
+			else if builder#has_magic_init then
+				init_types <- (get_full_type_name (namespace, name)) :: init_types
+		(**
+			Perform actions which should be executed after all classes were processed
+		*)
+		method finalize : unit =
+			self#generate_magic_init;
+			self#generate_entry_point
+		(**
+			Generates calls to static __init__ methods in Boot.php
+		*)
+		method generate_magic_init : unit =
+			match init_types with
+				| [] -> ()
+				| _ ->
+					match boot with
+						| None -> fail dummy_pos (try assert false with Assert_failure mlpos -> mlpos)
+						| Some (_, filename) ->
+							let channel = open_out_gen [Open_creat; Open_text; Open_append] 0o644 filename in
+							List.iter
+								(fun class_name -> output_string channel (class_name ^ "::__hx__init();\n"))
+								init_types;
+							close_out channel
+		(**
+			Creates `index.php` which can be used as entry-point for standalone Haxe->PHP app
+		*)
+		method generate_entry_point =
+			match self#get_main_class with
+				| None -> ()
+				| Some main_class ->
+					let channel = open_out (root_dir ^ "/index.php") in
+					output_string channel "<?php\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";
+					output_string channel "		$file = stream_resolve_include_path(str_replace('\\\\', '/', $class) .'.php');\n";
+					output_string channel "		if ($file) {\n";
+					output_string channel "			include_once $file;\n";
+					output_string channel "		}\n";
+					output_string channel "	}\n";
+					output_string channel ");\n";
+					(match boot with
+						| None -> fail dummy_pos (try assert false with Assert_failure mlpos -> mlpos)
+						| Some (builder, filename) ->
+							let boot_class = get_full_type_name (add_php_prefix com builder#get_type_path) in
+							output_string channel (boot_class ^ "::__hx__init();\n")
+					);
+					output_string channel (main_class ^ "::main();\n");
+					close_out channel
+		(**
+			Create necessary directories  before processing types
+		*)
+		method private create_output_dirs =
+			let build_path = (root_dir :: self#get_lib_path) in
+			build_dir <- create_dir_recursive build_path
+		(**
+			Returns path from `index.php` to directory which will contain all generated classes
+		*)
+		method private get_lib_path : string list =
+			match com.php_lib with
+				| None -> ["lib"];
+				| Some path -> (Str.split (Str.regexp "/")  path)
+		(**
+			Returns FQN for main class if defined
+		*)
+		method private get_main_class : string option =
+			match com.main_class with
+				| None -> None
+				| Some type_path -> Some (get_full_type_name (add_php_prefix com type_path))
+	end
+
+(**
+	Entry point to Genphp7
+*)
+let generate (com:context) =
+	let gen = new generator com in
+	gen#initialize;
+	let generate com_type =
+		let wrapper = get_wrapper com_type in
+		if wrapper#needs_generation then
+			match com_type with
+				| TClassDecl cls -> gen#generate (new class_builder com cls);
+				| TEnumDecl enm -> gen#generate (new enum_builder com enm);
+				| TTypeDecl typedef -> ();
+				| TAbstractDecl abstr -> ()
+	in
+	List.iter generate com.types;
+	gen#finalize;
+	Hashtbl.iter
+		(fun name data ->
+			write_resource com.file name data
+		)
+		com.resources;
+	clear_wrappers ();

+ 2 - 2
src/generators/genpy.ml

@@ -2461,7 +2461,7 @@ module Generator = struct
 	let run com =
 	let run com =
 		Transformer.init com;
 		Transformer.init com;
 		let ctx = mk_context com in
 		let ctx = mk_context com in
-		Codegen.map_source_header com (fun s -> print ctx "# %s\n" s);
+		Codegen.map_source_header com (fun s -> print ctx "# %s\n# coding: utf-8\n" s);
 		if has_feature ctx "closure_Array" || has_feature ctx "closure_String" then
 		if has_feature ctx "closure_Array" || has_feature ctx "closure_String" then
 			spr ctx "from functools import partial as _hx_partial";
 			spr ctx "from functools import partial as _hx_partial";
 		gen_imports ctx;
 		gen_imports ctx;
@@ -2478,4 +2478,4 @@ module Generator = struct
 end
 end
 
 
 let generate com =
 let generate com =
-	Generator.run com
+	Generator.run com

+ 27 - 1
src/generators/hlinterp.ml

@@ -1496,6 +1496,31 @@ let load_native ctx lib name t =
 			(function
 			(function
 			| [] -> VBool true
 			| [] -> VBool true
 			| _ -> assert false)
 			| _ -> assert false)
+		| "sys_string" ->
+			let cached_sys_name = ref None in
+			(function
+			| [] ->
+				VBytes (caml_to_hl (match Sys.os_type with
+				| "Unix" ->
+					(match !cached_sys_name with
+					| Some n -> n
+					| None ->
+						let ic = Unix.open_process_in "uname" in
+						let uname = (match input_line ic with
+							| "Darwin" -> "Mac"
+							| n -> n
+						) in
+						close_in ic;
+						cached_sys_name := Some uname;
+						uname)
+				| "Win32" | "Cygwin" -> "Windows"
+				| s -> s))
+			| _ ->
+				assert false)
+		| "sys_is64" ->
+			(function
+			| [] -> VBool (Sys.word_size = 64)
+			| _ -> assert false)
 		| "hash" ->
 		| "hash" ->
 			(function
 			(function
 			| [VBytes str] -> VInt (hash ctx (hl_to_caml str))
 			| [VBytes str] -> VInt (hash ctx (hl_to_caml str))
@@ -1912,7 +1937,8 @@ let load_native ctx lib name t =
 						| '1'..'9' | '+' | '$' | '^' | '*' | '?' | '.' | '[' | ']' ->
 						| '1'..'9' | '+' | '$' | '^' | '*' | '?' | '.' | '[' | ']' ->
 							Buffer.add_char buf '\\';
 							Buffer.add_char buf '\\';
 							Buffer.add_char buf c;
 							Buffer.add_char buf c;
-						| _ -> failwith ("Unsupported escaped char '" ^ String.make 1 c ^ "'"));
+						| _ ->
+							Buffer.add_char buf c);
 						loop c false l
 						loop c false l
 					| c :: l ->
 					| c :: l ->
 						match c with
 						match c with

+ 2 - 1
src/macro/interp.ml

@@ -1963,7 +1963,8 @@ let reg_lib =
 						| '1'..'9' | '+' | '$' | '^' | '*' | '?' | '.' | '[' | ']' ->
 						| '1'..'9' | '+' | '$' | '^' | '*' | '?' | '.' | '[' | ']' ->
 							Buffer.add_char buf '\\';
 							Buffer.add_char buf '\\';
 							Buffer.add_char buf c;
 							Buffer.add_char buf c;
-						| _ -> failwith ("Unsupported escaped char '" ^ String.make 1 c ^ "'"));
+						| _ ->
+							Buffer.add_char buf c);
 						loop c false l
 						loop c false l
 					| c :: l ->
 					| c :: l ->
 						match c with
 						match c with

+ 12 - 2
src/main.ml

@@ -277,7 +277,14 @@ module Initialize = struct
 				add_std "lua";
 				add_std "lua";
 				"lua"
 				"lua"
 			| Php ->
 			| Php ->
-				add_std "php";
+				if Common.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";
 				"php"
 				"php"
 			| Cpp ->
 			| Cpp ->
 				Common.define_value com Define.HxcppApiLevel "331";
 				Common.define_value com Define.HxcppApiLevel "331";
@@ -346,7 +353,10 @@ let generate tctx ext xml_out interp swf_header =
 		| Lua ->
 		| Lua ->
 			Genlua.generate,"lua"
 			Genlua.generate,"lua"
 		| Php ->
 		| Php ->
-			Genphp.generate,"php"
+			if Common.php7 com then
+				Genphp7.generate,"php"
+			else
+				Genphp.generate,"php"
 		| Cpp ->
 		| Cpp ->
 			Gencpp.generate,"cpp"
 			Gencpp.generate,"cpp"
 		| Cs ->
 		| Cs ->

+ 1 - 0
src/optimization/analyzerConfig.ml

@@ -118,6 +118,7 @@ let update_config_from_meta com config meta =
 				| EConst (Ident s) when s = flag_user_var_fusion -> {config with user_var_fusion = true}
 				| EConst (Ident s) when s = flag_user_var_fusion -> {config with user_var_fusion = true}
 				| EConst (Ident s) when s = "no_" ^ flag_user_var_fusion -> {config with user_var_fusion = false}
 				| EConst (Ident s) when s = "no_" ^ flag_user_var_fusion -> {config with user_var_fusion = false}
 				| EConst (Ident s) when s = flag_fusion_debug -> {config with fusion_debug = true}
 				| EConst (Ident s) when s = flag_fusion_debug -> {config with fusion_debug = true}
+				| EConst (Ident s) when s = "as_var" -> config
 				| _ ->
 				| _ ->
 					let s = Ast.s_expr e in
 					let s = Ast.s_expr e in
 					com.warning (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);
 					com.warning (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);

+ 20 - 7
src/optimization/analyzerTexpr.ml

@@ -123,13 +123,13 @@ let rec can_be_used_as_value com e =
 		(* | TCall _ | TNew _ when (match com.platform with Cpp | Php -> true | _ -> false) -> raise Exit *)
 		(* | TCall _ | TNew _ when (match com.platform with Cpp | Php -> true | _ -> false) -> raise Exit *)
 		| TReturn _ | TThrow _ | TBreak | TContinue -> raise Exit
 		| TReturn _ | TThrow _ | TBreak | TContinue -> raise Exit
 		| TUnop((Increment | Decrement),_,_) when not (target_handles_unops com) -> raise Exit
 		| TUnop((Increment | Decrement),_,_) when not (target_handles_unops com) -> raise Exit
-		| TNew _ when com.platform = Php -> raise Exit
+		| TNew _ when com.platform = Php && not (Common.php7 com) -> raise Exit
 		| TFunction _ -> ()
 		| TFunction _ -> ()
 		| _ -> Type.iter loop e
 		| _ -> Type.iter loop e
 	in
 	in
 	try
 	try
 		begin match com.platform,e.eexpr with
 		begin match com.platform,e.eexpr with
-			| (Cs | Cpp | Java | Flash),TConst TNull -> raise Exit
+			| (Cs | Cpp | Java | Flash | Lua),TConst TNull -> raise Exit
 			| _ -> ()
 			| _ -> ()
 		end;
 		end;
 		loop e;
 		loop e;
@@ -155,9 +155,22 @@ let is_ref_type = function
 	| TAbstract({a_path=["hl";"types"],"Ref"},_) -> true
 	| TAbstract({a_path=["hl";"types"],"Ref"},_) -> true
 	| _ -> false
 	| _ -> false
 
 
-let is_asvar_type t = match follow t with
-	| TAbstract({a_path = (["haxe";"extern"],"AsVar")},_) -> true
-	| _ -> false
+let rec is_asvar_type t =
+	let check meta =
+		AnalyzerConfig.has_analyzer_option meta "as_var"
+	in
+	match t with
+	| TInst(c,_) -> check c.cl_meta
+	| TEnum(en,_) -> check en.e_meta
+	| TType(t,tl) -> check t.t_meta || (is_asvar_type (apply_params t.t_params tl t.t_type))
+	| TAbstract(a,_) -> check a.a_meta
+	| TLazy f -> is_asvar_type (!f())
+	| TMono r ->
+		(match !r with
+		| Some t -> is_asvar_type t
+		| _ -> false)
+	| _ ->
+		false
 
 
 let type_change_ok com t1 t2 =
 let type_change_ok com t1 t2 =
 	if t1 == t2 then
 	if t1 == t2 then
@@ -669,7 +682,7 @@ module Fusion = struct
 							let el = List.map replace el in
 							let el = List.map replace el in
 							let e2 = replace e2 in
 							let e2 = replace e2 in
 							e2,el
 							e2,el
-						| Php | Cpp  when not (Common.defined com Define.Cppia) ->
+						| Php | Cpp  when not (Common.defined com Define.Cppia) && not (Common.php7 com) ->
 							let is_php_safe e1 =
 							let is_php_safe e1 =
 								let rec loop e = match e.eexpr with
 								let rec loop e = match e.eexpr with
 									| TCall _ -> raise Exit
 									| TCall _ -> raise Exit
@@ -781,7 +794,7 @@ module Fusion = struct
 							let e3 = replace e3 in
 							let e3 = replace e3 in
 							if not !found && has_state_read ir then raise Exit;
 							if not !found && has_state_read ir then raise Exit;
 							{e with eexpr = TBinop(OpAssign,{ea with eexpr = TArray(e1,e2)},e3)}
 							{e with eexpr = TBinop(OpAssign,{ea with eexpr = TArray(e1,e2)},e3)}
-						| TBinop(op,e1,e2) when (match com.platform with Cpp | Php -> true | _ -> false) ->
+						| TBinop(op,e1,e2) when (match com.platform with Cpp | Php when not (Common.php7 com) -> true | _ -> false) ->
 							let e1 = replace e1 in
 							let e1 = replace e1 in
 							let temp_found = !found in
 							let temp_found = !found in
 							found := false;
 							found := false;

+ 28 - 20
src/optimization/analyzerTexprTransformer.ml

@@ -246,6 +246,7 @@ let rec func ctx bb tf t p =
 		let e = List.fold_left (fun e f -> f e) e (List.rev fl) in
 		let e = List.fold_left (fun e f -> f e) e (List.rev fl) in
 		bb,e
 		bb,e
 	and declare_var_and_assign bb v e p =
 	and declare_var_and_assign bb v e p =
+		(* TODO: this section shouldn't be here because it can be handled as part of the normal value processing *)
 		let rec loop bb e = match e.eexpr with
 		let rec loop bb e = match e.eexpr with
 			| TParenthesis e1 ->
 			| TParenthesis e1 ->
 				loop bb e1
 				loop bb e1
@@ -255,6 +256,7 @@ let rec func ctx bb tf t p =
 						bb,e
 						bb,e
 					| e1 :: el ->
 					| e1 :: el ->
 						let bb = block_element bb e1 in
 						let bb = block_element bb e1 in
+						if bb == g.g_unreachable then raise Exit;
 						loop2 bb el
 						loop2 bb el
 					| [] ->
 					| [] ->
 						assert false
 						assert false
@@ -264,27 +266,33 @@ let rec func ctx bb tf t p =
 			| _ ->
 			| _ ->
 				bb,e
 				bb,e
 		in
 		in
-		let bb,e = loop bb e in
-		no_void v.v_type p;
-		let ev = mk (TLocal v) v.v_type p in
-		let was_assigned = ref false in
-		let assign e =
-			if not !was_assigned then begin
-				was_assigned := true;
-				add_texpr bb (mk (TVar(v,None)) ctx.com.basic.tvoid ev.epos);
-			end;
-			mk (TBinop(OpAssign,ev,e)) ev.etype ev.epos
-		in
-		let close = push_name v.v_name in
-		let bb = try
-			block_element_plus bb (map_values assign e) (fun e -> mk (TVar(v,Some e)) ctx.com.basic.tvoid ev.epos)
-		with Exit ->
-			let bb,e = value bb e in
-			add_texpr bb (mk (TVar(v,Some e)) ctx.com.basic.tvoid ev.epos);
+		let generate bb e =
+			no_void v.v_type p;
+			let ev = mk (TLocal v) v.v_type p in
+			let was_assigned = ref false in
+			let assign e =
+				if not !was_assigned then begin
+					was_assigned := true;
+					add_texpr bb (mk (TVar(v,None)) ctx.com.basic.tvoid ev.epos);
+				end;
+				mk (TBinop(OpAssign,ev,e)) ev.etype ev.epos
+			in
+			let close = push_name v.v_name in
+			let bb = try
+				block_element_plus bb (map_values assign e) (fun e -> mk (TVar(v,Some e)) ctx.com.basic.tvoid ev.epos)
+			with Exit ->
+				let bb,e = value bb e in
+				add_texpr bb (mk (TVar(v,Some e)) ctx.com.basic.tvoid ev.epos);
+				bb
+			in
+			close();
 			bb
 			bb
 		in
 		in
-		close();
-		bb
+		try
+			let bb,e = loop bb e in
+			generate bb e
+		with Exit ->
+			g.g_unreachable
 	and block_element_plus bb (e,efinal) f =
 	and block_element_plus bb (e,efinal) f =
 		let bb = block_element bb e in
 		let bb = block_element bb e in
 		let bb = match efinal with
 		let bb = match efinal with
@@ -481,7 +489,7 @@ let rec func ctx bb tf t p =
 			let bb_try_next = block bb_try e1 in
 			let bb_try_next = block bb_try e1 in
 			close();
 			close();
 			(* We always want to keep catch-blocks, so let's add a pseudo CFG edge if it's unreachable. *)
 			(* We always want to keep catch-blocks, so let's add a pseudo CFG edge if it's unreachable. *)
-			if bb_exc.bb_incoming = [] then add_cfg_edge bb_try_next bb_exc CFGMaybeThrow;
+			if bb_exc.bb_incoming = [] then add_cfg_edge (if bb_try_next == g.g_unreachable then bb_try else bb_try_next) bb_exc CFGMaybeThrow;
 			let is_reachable = ref (not (bb_try_next == g.g_unreachable)) in
 			let is_reachable = ref (not (bb_try_next == g.g_unreachable)) in
 			let catches = List.map (fun (v,e) ->
 			let catches = List.map (fun (v,e) ->
 				let bb_catch = create_node (BKCatch v) e.etype e.epos in
 				let bb_catch = create_node (BKCatch v) e.etype e.epos in

+ 1 - 1
src/optimization/filters.ml

@@ -901,7 +901,7 @@ let add_meta_field ctx t = match t with
 			f.cf_expr <- Some e;
 			f.cf_expr <- Some e;
 			let can_deal_with_interface_metadata () = match ctx.com.platform with
 			let can_deal_with_interface_metadata () = match ctx.com.platform with
 				| Flash when Common.defined ctx.com Define.As3 -> false
 				| Flash when Common.defined ctx.com Define.As3 -> false
-				| Php -> false
+				| Php when not (Common.php7 ctx.com) -> false
 				| _ -> true
 				| _ -> true
 			in
 			in
 			if c.cl_interface && not (can_deal_with_interface_metadata()) then begin
 			if c.cl_interface && not (can_deal_with_interface_metadata()) then begin

+ 1 - 1
src/optimization/optimizer.ml

@@ -1286,7 +1286,7 @@ let inline_constructors ctx e =
 				if cf.cf_name <> "length" then
 				if cf.cf_name <> "length" then
 					begin match (IntMap.find v.v_id !vars).ii_kind with
 					begin match (IntMap.find v.v_id !vars).ii_kind with
 					| IKArray _ -> cancel v e.epos
 					| IKArray _ -> cancel v e.epos
-					| _ -> ()
+					| _ -> (try ignore(get_field_var v cf.cf_name) with Not_found -> ignore(add_field_var v cf.cf_name e.etype));
 					end
 					end
 			| _ -> cancel v e.epos
 			| _ -> cancel v e.epos
 			end
 			end

+ 14 - 11
src/syntax/parser.ml

@@ -1228,27 +1228,30 @@ and parse_var_assignment = parser
 		end
 		end
 	| [< >] -> None
 	| [< >] -> None
 
 
+and parse_var_assignment_resume vl name pn t s =
+	try
+		let eo = parse_var_assignment s in
+		((name,pn),t,eo)
+	with Display e ->
+		let v = ((name,pn),t,Some e) in
+		let e = (EVars(List.rev (v :: vl)),punion pn (pos e)) in
+		display e
+
 and parse_var_decls_next vl = parser
 and parse_var_decls_next vl = parser
 	| [< '(Comma,p1); name,t,pn = parse_var_decl_head; s >] ->
 	| [< '(Comma,p1); name,t,pn = parse_var_decl_head; s >] ->
-		begin try
-			let eo = parse_var_assignment s in
-			parse_var_decls_next (((name,pn),t,eo) :: vl) s
-		with Display e ->
-			let v = ((name,pn),t,Some e) in
-			let e = (EVars(List.rev (v :: vl)),punion p1 (pos e)) in
-			display e
-		end
+		let v_decl = parse_var_assignment_resume vl name pn t s in
+		parse_var_decls_next (v_decl :: vl) s
 	| [< >] ->
 	| [< >] ->
 		vl
 		vl
 
 
 and parse_var_decls p1 = parser
 and parse_var_decls p1 = parser
 	| [< name,t,pn = parse_var_decl_head; s >] ->
 	| [< name,t,pn = parse_var_decl_head; s >] ->
-		let eo = parse_var_assignment s in
-		List.rev (parse_var_decls_next [(name,pn),t,eo] s)
+		let v_decl = parse_var_assignment_resume [] name pn t s in
+		List.rev (parse_var_decls_next [v_decl] s)
 	| [< s >] -> error (Custom "Missing variable identifier") p1
 	| [< s >] -> error (Custom "Missing variable identifier") p1
 
 
 and parse_var_decl = parser
 and parse_var_decl = parser
-	| [< name,t,pn = parse_var_decl_head; eo = parse_var_assignment >] -> ((name,pn),t,eo)
+	| [< name,t,pn = parse_var_decl_head; v_decl = parse_var_assignment_resume [] name pn t >] -> v_decl
 
 
 and inline_function = parser
 and inline_function = parser
 	| [< '(Kwd Inline,_); '(Kwd Function,p1) >] -> true, p1
 	| [< '(Kwd Inline,_); '(Kwd Function,p1) >] -> true, p1

+ 1 - 1
src/typing/matcher.ml

@@ -672,7 +672,7 @@ module Useless = struct
 						let patterns1 = ExtList.List.make arity (PatAny,p) in
 						let patterns1 = ExtList.List.make arity (PatAny,p) in
 						loop ((patterns1 @ patterns2) :: pAcc) (q1 :: qAcc) (r1 :: rAcc) pM qM rM
 						loop ((patterns1 @ patterns2) :: pAcc) (q1 :: qAcc) (r1 :: rAcc) pM qM rM
 					| ((PatOr(pat1,pat2)),_) :: patterns2 ->
 					| ((PatOr(pat1,pat2)),_) :: patterns2 ->
-						specialize' is_tuple con (((pat1 :: patterns2) :: (pat2 :: patterns2) :: pAcc)) (q1 :: q1 :: qM @ qAcc) (r1 :: r1 :: rM @ rAcc)
+						loop pAcc qAcc rAcc (((pat1 :: patterns2) :: (pat2 :: patterns2) :: pM)) (q1 :: q1 :: qM) (r1 :: r1 :: rM)
 					| (PatBind(_,pat1),_) :: patterns2 ->
 					| (PatBind(_,pat1),_) :: patterns2 ->
 						loop2 (pat1 :: patterns2)
 						loop2 (pat1 :: patterns2)
 					| _ ->
 					| _ ->

+ 1 - 0
src/typing/typeload.ml

@@ -3517,6 +3517,7 @@ let resolve_module_file com m remap p =
 			let x = (try
 			let x = (try
 				match PMap.find x com.package_rules with
 				match PMap.find x com.package_rules with
 				| Forbidden -> forbid := true; x
 				| Forbidden -> forbid := true; x
+				| Directory d -> d
 				| Remap d -> remap := d :: l; d
 				| Remap d -> remap := d :: l; d
 				with Not_found -> x
 				with Not_found -> x
 			) in
 			) in

+ 19 - 20
src/typing/typer.ml

@@ -970,7 +970,7 @@ let error_require r p =
 		error "This field is not available with the current compilation flags" p
 		error "This field is not available with the current compilation flags" p
 	else
 	else
 	let r = if r = "sys" then
 	let r = if r = "sys" then
-		"a system platform (php,neko,cpp,etc.)"
+		"a system platform (php,php7,neko,cpp,etc.)"
 	else try
 	else try
 		if String.sub r 0 5 <> "flash" then raise Exit;
 		if String.sub r 0 5 <> "flash" then raise Exit;
 		let _, v = ExtString.String.replace (String.sub r 5 (String.length r - 5)) "_" "." in
 		let _, v = ExtString.String.replace (String.sub r 5 (String.length r - 5)) "_" "." in
@@ -1801,10 +1801,10 @@ let unify_int ctx e k =
 	with Typeload.Generic_Exception (msg,p) ->
 	with Typeload.Generic_Exception (msg,p) ->
 		error msg p)
 		error msg p)
 
 
-let call_to_string ctx e =
+let call_to_string ctx ?(resume=false) e =
 	(* Ignore visibility of the toString field. *)
 	(* Ignore visibility of the toString field. *)
 	ctx.meta <- (Meta.PrivateAccess,[],e.epos) :: ctx.meta;
 	ctx.meta <- (Meta.PrivateAccess,[],e.epos) :: ctx.meta;
-	let acc = type_field ctx e "toString" e.epos MCall in
+	let acc = type_field ~resume ctx e "toString" e.epos MCall in
 	ctx.meta <- List.tl ctx.meta;
 	ctx.meta <- List.tl ctx.meta;
 	!build_call_ref ctx acc [] (WithType ctx.t.tstring) e.epos
 	!build_call_ref ctx acc [] (WithType ctx.t.tstring) e.epos
 
 
@@ -4012,23 +4012,28 @@ and maybe_type_against_enum ctx f with_type p =
 	try
 	try
 		begin match with_type with
 		begin match with_type with
 		| WithType t ->
 		| WithType t ->
-			let rec loop t = match follow t with
+			let rec loop stack t = match follow t with
 				| TEnum (en,_) ->
 				| TEnum (en,_) ->
 					en.e_path,en.e_names,TEnumDecl en
 					en.e_path,en.e_names,TEnumDecl en
 				| TAbstract ({a_impl = Some c} as a,_) when has_meta Meta.Enum a.a_meta ->
 				| TAbstract ({a_impl = Some c} as a,_) when has_meta Meta.Enum a.a_meta ->
-					a.a_path,List.map (fun cf -> cf.cf_name) c.cl_ordered_fields,TAbstractDecl a
+					let fields = ExtList.List.filter_map (fun cf ->
+						if Meta.has Meta.Enum cf.cf_meta then Some cf.cf_name else None
+					) c.cl_ordered_statics in
+					a.a_path,fields,TAbstractDecl a
 				| TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
 				| TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
 					begin match get_abstract_froms a pl with
 					begin match get_abstract_froms a pl with
-						| [t] -> loop t
+						| [t2] ->
+							if (List.exists (fast_eq t) stack) then raise Exit;
+							loop (t :: stack) t2
 						| _ -> raise Exit
 						| _ -> raise Exit
 					end
 					end
 				(* We might type against an enum constructor. *)
 				(* We might type against an enum constructor. *)
 				| TFun(_,tr) ->
 				| TFun(_,tr) ->
-					loop tr
+					loop stack tr
 				| _ ->
 				| _ ->
 					raise Exit
 					raise Exit
 			in
 			in
-			let path,fields,mt = loop t in
+			let path,fields,mt = loop [] t in
 			let old = ctx.m.curmod.m_types in
 			let old = ctx.m.curmod.m_types in
 			let restore () = ctx.m.curmod.m_types <- old in
 			let restore () = ctx.m.curmod.m_types <- old in
 			ctx.m.curmod.m_types <- ctx.m.curmod.m_types @ [mt];
 			ctx.m.curmod.m_types <- ctx.m.curmod.m_types @ [mt];
@@ -4062,23 +4067,17 @@ and type_call ctx e el (with_type:with_type) p =
 		if Common.defined ctx.com Define.NoTraces then
 		if Common.defined ctx.com Define.NoTraces then
 			null ctx.t.tvoid p
 			null ctx.t.tvoid p
 		else
 		else
-		let mk_to_string_meta e = EMeta((Meta.ToString,[],pos e),e),pos e in
+		let mk_to_string_meta e = EMeta((Meta.ToString,[],null_pos),e),pos e in
 		let params = (match el with [] -> [] | _ -> [("customParams",null_pos),(EArrayDecl (List.map mk_to_string_meta el) , p)]) in
 		let params = (match el with [] -> [] | _ -> [("customParams",null_pos),(EArrayDecl (List.map mk_to_string_meta el) , p)]) in
 		let infos = mk_infos ctx p params in
 		let infos = mk_infos ctx p params in
 		if (platform ctx.com Js || platform ctx.com Python) && el = [] && has_dce ctx.com then
 		if (platform ctx.com Js || platform ctx.com Python) && el = [] && has_dce ctx.com then
 			let e = type_expr ctx e Value in
 			let e = type_expr ctx e Value in
 			let infos = type_expr ctx infos Value in
 			let infos = type_expr ctx infos Value in
-			let e = try
-				begin match follow e.etype with
-					| TInst({cl_path=[],"String"},_) -> raise Not_found
-					| TMono _ -> raise Not_found
-					| TDynamic _ -> raise Not_found
-					| _ -> ()
-				end;
-				let acc = type_field ~resume:true ctx e "toString" p MCall in
-				build_call ctx acc [] (WithType ctx.t.tstring) p
-			with Not_found ->
-				e
+			let e = match follow e.etype with
+				| TAbstract({a_impl = Some c},_) when PMap.mem "toString" c.cl_statics ->
+					call_to_string ctx e
+				| _ ->
+					e
 			in
 			in
 			let v_trace = alloc_unbound_var "`trace" t_dynamic p in
 			let v_trace = alloc_unbound_var "`trace" t_dynamic p in
 			mk (TCall (mk (TLocal v_trace) t_dynamic p,[e;infos])) ctx.t.tvoid p
 			mk (TCall (mk (TLocal v_trace) t_dynamic p,[e;infos])) ctx.t.tvoid p

+ 17 - 4
std/DateTools.hx

@@ -33,10 +33,23 @@ class DateTools {
 	#elseif (neko && !(macro || interp))
 	#elseif (neko && !(macro || interp))
 	static var date_format = neko.Lib.load("std","date_format",2);
 	static var date_format = neko.Lib.load("std","date_format",2);
 	#else
 	#else
+	static var DAY_SHORT_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+	static var DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
+	static var MONTH_SHORT_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+	static var MONTH_NAMES = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
+	
 	private static function __format_get( d : Date, e : String ) : String {
 	private static function __format_get( d : Date, e : String ) : String {
 		return switch( e ){
 		return switch( e ){
 			case "%":
 			case "%":
 				"%";
 				"%";
+			case "a":
+				DAY_SHORT_NAMES[d.getDay()];
+			case "A":
+				DAY_NAMES[d.getDay()];
+			case "b","h":
+				MONTH_SHORT_NAMES[d.getMonth()];
+			case "B":
+				MONTH_NAMES[d.getMonth()];
 			case "C":
 			case "C":
 				untyped StringTools.lpad(Std.string(Std.int(d.getFullYear()/100)),"0",2);
 				untyped StringTools.lpad(Std.string(Std.int(d.getFullYear()/100)),"0",2);
 			case "d":
 			case "d":
@@ -114,16 +127,16 @@ class DateTools {
 		supported.
 		supported.
 
 
 		```haxe
 		```haxe
-		var t = DateTools.format(Date.now(), "%Y-%m-%d_%H:%M:%S"); 
+		var t = DateTools.format(Date.now(), "%Y-%m-%d_%H:%M:%S");
 		// 2016-07-08_14:44:05
 		// 2016-07-08_14:44:05
 
 
-		var t = DateTools.format(Date.now(), "%r"); 
+		var t = DateTools.format(Date.now(), "%r");
 		// 02:44:05 PM
 		// 02:44:05 PM
 
 
-		var t = DateTools.format(Date.now(), "%T"); 
+		var t = DateTools.format(Date.now(), "%T");
 		// 14:44:05
 		// 14:44:05
 
 
-		var t = DateTools.format(Date.now(), "%F"); 
+		var t = DateTools.format(Date.now(), "%F");
 		// 2016-07-08
 		// 2016-07-08
 		```
 		```
 	**/
 	**/

+ 1 - 7
std/cpp/ConstPointer.hx

@@ -21,7 +21,7 @@
  */
  */
  package cpp;
  package cpp;
 
 
-@:coreType @:include("cpp/Pointer.h") @:native("cpp.Pointer")
+@:coreType @:include("cpp/Pointer.h") @:native("cpp.Pointer") @:analyzer(as_var)
 extern class ConstPointer<T>
 extern class ConstPointer<T>
 {
 {
    // ptr actually returns the pointer - not strictly a 'T' - for pointers to smart pointers
    // ptr actually returns the pointer - not strictly a 'T' - for pointers to smart pointers
@@ -56,12 +56,6 @@ extern class ConstPointer<T>
 
 
    public function reinterpret<Other>():Pointer<Other>;
    public function reinterpret<Other>():Pointer<Other>;
 
 
-   inline public function typeCast<Other>():Pointer<Other>
-   {
-      var tmp:haxe.extern.AsVar<Pointer<Other>> = reinterpret();
-      return tmp;
-   }
-
    public function rawCast<Other>():RawPointer<Other>;
    public function rawCast<Other>():RawPointer<Other>;
 
 
    public function at(inIndex:Int):Reference<T>;
    public function at(inIndex:Int):Reference<T>;

+ 12 - 13
std/cpp/NativeArray.hx

@@ -30,12 +30,14 @@ extern class NativeArray {
       NativeArray.setSize(result,length);
       NativeArray.setSize(result,length);
       return result;
       return result;
    }
    }
+
    #else
    #else
+
    @:native("_hx_create_array_length")
    @:native("_hx_create_array_length")
    public static function create<T>(length:Int):Array<T>;
    public static function create<T>(length:Int):Array<T>;
    #end
    #end
 
 
-	public static inline function blit<T>( ioDestArray:Array<T>,
+   public static inline function blit<T>( ioDestArray:Array<T>,
 		inDestElement:Int, inSourceArray:Array<T>,
 		inDestElement:Int, inSourceArray:Array<T>,
 		inSourceElement:Int, inElementCount:Int ): Void  {
 		inSourceElement:Int, inElementCount:Int ): Void  {
 	untyped ioDestArray.blit(inDestElement, inSourceArray, inSourceElement, inElementCount);
 	untyped ioDestArray.blit(inDestElement, inSourceArray, inSourceElement, inElementCount);
@@ -58,21 +60,18 @@ extern class NativeArray {
       return Pointer.arrayElem(inArray,inIndex);
       return Pointer.arrayElem(inArray,inIndex);
    }
    }
 
 
-	public static inline function setData<T>( inArray:Array<T>,inData:Pointer<T>,inElementCount:Int ) : Void {
-      untyped inArray.setData(inData.raw,inElementCount);
-      }
-	public static inline function setUnmanagedData<T>( inArray:Array<T>,inData:ConstPointer<T>,inElementCount:Int ) : Void {
-      untyped inArray.setUnmanagedData(inData.raw,inElementCount);
-   }
+   @:nativeStaticExtension
+	public static function setData<T>( inArray:Array<T>,inData:Pointer<T>,inElementCount:Int ) : Void { }
+
+   @:nativeStaticExtension
+	public static function setUnmanagedData<T>( inArray:Array<T>,inData:ConstPointer<T>,inElementCount:Int ) : Void { }
 
 
+   @:nativeStaticExtension
+	public static function zero<T>( ioDestArray:Array<T>, ?inFirst:Int, ?inElements:Int ) : Void { };
 
 
-	public static inline function zero<T>( ioDestArray:Array<T>, ?inFirst:Int, ?inElements:Int ) : Void {
-		untyped ioDestArray.zero(inFirst, inElements);
-	};
+   @:nativeStaticExtension
+	public static function memcmp<T>( inArrayA:Array<T>, inArrayB:Array<T>) : Int { }
 
 
-	public static inline function memcmp<T>( inArrayA:Array<T>, inArrayB:Array<T>) : Int {
-		return untyped inArrayA.memcmp(inArrayB);
-	}
 
 
    #if cppia
    #if cppia
 	public static inline function unsafeGet<T>( inDestArray:Array<T>, inIndex:Int) : T {
 	public static inline function unsafeGet<T>( inDestArray:Array<T>, inIndex:Int) : T {

+ 2 - 1
std/cpp/Pointer.hx

@@ -24,6 +24,7 @@
 import haxe.extern.AsVar;
 import haxe.extern.AsVar;
 
 
 @:coreType
 @:coreType
+@:analyzer(as_var)
 extern class Pointer<T> extends ConstPointer<T> implements ArrayAccess<T>
 extern class Pointer<T> extends ConstPointer<T> implements ArrayAccess<T>
 {
 {
    public var ref(get,set):Reference<T>;
    public var ref(get,set):Reference<T>;
@@ -71,7 +72,7 @@ extern class Pointer<T> extends ConstPointer<T> implements ArrayAccess<T>
 
 
    inline public function toUnmanagedVector(elementCount:Int) : haxe.ds.Vector<T>
    inline public function toUnmanagedVector(elementCount:Int) : haxe.ds.Vector<T>
       return cast toUnmanagedArray(elementCount);
       return cast toUnmanagedArray(elementCount);
- 
+
 
 
    override public function inc():Pointer<T>;
    override public function inc():Pointer<T>;
    override public function dec():Pointer<T>;
    override public function dec():Pointer<T>;

+ 1 - 1
std/cpp/_std/haxe/ds/IntMap.hx

@@ -43,7 +43,7 @@ package haxe.ds;
   inline void set(int key, const ::cpp::Pointer<V> &value) {__int_hash_set(h,key,(Dynamic)value ); }
   inline void set(int key, const ::cpp::Pointer<V> &value) {__int_hash_set(h,key,(Dynamic)value ); }
 
 
   template<typename VALUE>
   template<typename VALUE>
-  inline Void set(Dynamic &key, const VALUE &value) { set( (int)key, value ); return null(); }
+  inline void set(Dynamic &key, const VALUE &value) { set( (int)key, value ); }
 ")
 ")
 @:coreApi class IntMap<T> implements haxe.Constraints.IMap<Int,T> {
 @:coreApi class IntMap<T> implements haxe.Constraints.IMap<Int,T> {
 
 

+ 1 - 1
std/cpp/_std/haxe/ds/StringMap.hx

@@ -43,7 +43,7 @@ package haxe.ds;
   inline void set(String key, const ::cpp::Pointer<V> &value) {__string_hash_set(h,key,(Dynamic)value ); }
   inline void set(String key, const ::cpp::Pointer<V> &value) {__string_hash_set(h,key,(Dynamic)value ); }
 
 
   template<typename VALUE>
   template<typename VALUE>
-  inline Void set(Dynamic &key, const VALUE &value) { set( (String)key, value ); return null(); }
+  inline void set(Dynamic &key, const VALUE &value) { set( (String)key, value ); }
 ")
 ")
 @:coreApi class StringMap<T> implements haxe.Constraints.IMap<String,T> {
 @:coreApi class StringMap<T> implements haxe.Constraints.IMap<String,T> {
 	@:ifFeature("haxe.ds.StringMap.*")
 	@:ifFeature("haxe.ds.StringMap.*")

+ 2 - 1
std/cpp/_std/sys/io/Process.hx

@@ -104,7 +104,8 @@ class Process {
 		return NativeProcess.process_pid(p);
 		return NativeProcess.process_pid(p);
 	}
 	}
 
 
-	public function exitCode() : Int {
+	public function exitCode( block : Bool = true ) : Null<Int> {
+		if( block == false ) throw "Non blocking exitCode() not supported on this platform";
 		return NativeProcess.process_exit(p);
 		return NativeProcess.process_exit(p);
 	}
 	}
 
 

+ 2 - 0
std/cs/_std/sys/FileSystem.hx

@@ -103,11 +103,13 @@ class FileSystem {
 
 
 	public static function deleteFile( path : String ) : Void
 	public static function deleteFile( path : String ) : Void
 	{
 	{
+		if (!File.Exists(path)) throw "Path '" + path + "' doesn't exist";
 		File.Delete(path);
 		File.Delete(path);
 	}
 	}
 
 
 	public static function deleteDirectory( path : String ) : Void
 	public static function deleteDirectory( path : String ) : Void
 	{
 	{
+		if (!Directory.Exists(path)) throw "Path '" + path + "' doesn't exist";
 		Directory.Delete(path);
 		Directory.Delete(path);
 	}
 	}
 
 

+ 3 - 1
std/cs/_std/sys/io/Process.hx

@@ -109,8 +109,10 @@ class Process {
 		return native.Id;
 		return native.Id;
 	}
 	}
 
 
-	public function exitCode() : Int
+	public function exitCode( block : Bool = true ) : Null<Int>
 	{
 	{
+		if( block == false && !native.HasExited )
+			return null;
 		native.WaitForExit();
 		native.WaitForExit();
 		return native.ExitCode;
 		return native.ExitCode;
 	}
 	}

+ 7 - 0
std/haxe/CallStack.hx

@@ -138,6 +138,13 @@ class CallStack {
 				stack.push(FilePos(null, file, Std.parseInt(line)));
 				stack.push(FilePos(null, file, Std.parseInt(line)));
 			}
 			}
 			return stack;
 			return stack;
+		#elseif hl
+			try {
+				throw null;
+			} catch( e : Dynamic ) {
+				var st = _getExceptionStack();
+				return makeStack(st.length > 2 ? st.sub(2,st.length - 2) : st);
+			}
 		#else
 		#else
 			return []; // Unsupported
 			return []; // Unsupported
 		#end
 		#end

+ 1 - 1
std/haxe/Http.hx

@@ -436,7 +436,7 @@ class Http {
 				sock = new php.net.SslSocket();
 				sock = new php.net.SslSocket();
 				#elseif java
 				#elseif java
 				sock = new java.net.SslSocket();
 				sock = new java.net.SslSocket();
-				#elseif (!no_ssl && (hxssl || cpp || (neko && !(macro || interp))))
+				#elseif (!no_ssl && (hxssl || hl || cpp || (neko && !(macro || interp))))
 				sock = new sys.ssl.Socket();
 				sock = new sys.ssl.Socket();
 				#else
 				#else
 				throw "Https is only supported with -lib hxssl";
 				throw "Https is only supported with -lib hxssl";

+ 1 - 1
std/haxe/Int64.hx

@@ -454,7 +454,7 @@ private typedef __Int64 = ___Int64;
 
 
 private class ___Int64 {
 private class ___Int64 {
 	public var high : Int32;
 	public var high : Int32;
-	public var low : Int32; 
+	public var low : Int32;
 
 
 	public inline function new( high, low ) {
 	public inline function new( high, low ) {
 		this.high = high;
 		this.high = high;

+ 4 - 2
std/haxe/Log.hx

@@ -35,8 +35,8 @@ class Log {
 
 
 		This method can be rebound to a custom function:
 		This method can be rebound to a custom function:
 			var oldTrace = haxe.Log.trace; // store old function
 			var oldTrace = haxe.Log.trace; // store old function
-			haxe.Log.trace = function(v, ?infos) { 
-			  // handle trace 
+			haxe.Log.trace = function(v, ?infos) {
+			  // handle trace
 			}
 			}
 			...
 			...
 			haxe.Log.trace = oldTrace;
 			haxe.Log.trace = oldTrace;
@@ -62,6 +62,8 @@ class Log {
 			}
 			}
 		#elseif js
 		#elseif js
 			untyped js.Boot.__trace(v,infos);
 			untyped js.Boot.__trace(v,infos);
+		#elseif (php && php7)
+			php.Boot.trace(v, infos);
 		#elseif php
 		#elseif php
 			if (infos!=null && infos.customParams!=null) {
 			if (infos!=null && infos.customParams!=null) {
 				var extra:String = "";
 				var extra:String = "";

+ 7 - 2
std/haxe/Serializer.hx

@@ -377,7 +377,7 @@ class Serializer {
 				#end
 				#end
 			default:
 			default:
 				if( useCache ) cache.pop();
 				if( useCache ) cache.pop();
-				if( #if flash try v.hxSerialize != null catch( e : Dynamic ) false #elseif (cs || java || python) Reflect.hasField(v, "hxSerialize") #else v.hxSerialize != null #end  ) {
+				if( #if flash try v.hxSerialize != null catch( e : Dynamic ) false #elseif (cs || java || python) Reflect.hasField(v, "hxSerialize") #elseif (php && php7) php.Global.method_exists(v, 'hxSerialize') #else v.hxSerialize != null #end  ) {
 					buf.add("C");
 					buf.add("C");
 					serializeString(Type.getClassName(c));
 					serializeString(Type.getClassName(c));
 					if( useCache ) cache.push(v);
 					if( useCache ) cache.push(v);
@@ -476,8 +476,13 @@ class Serializer {
 				buf.add(0);
 				buf.add(0);
 			else {
 			else {
 				buf.add(l);
 				buf.add(l);
-				for( i in 0...l )
+				for( i in 0...l ) {
+					#if (php && php7)
+					serialize(v.params[i]);
+					#elseif php
 					serialize(untyped __field__(v, __php__("params"), i));
 					serialize(untyped __field__(v, __php__("params"), i));
+					#end
+				}
 			}
 			}
 			#elseif (java || cs || python || hl)
 			#elseif (java || cs || python || hl)
 			if( useEnumIndex ) {
 			if( useEnumIndex ) {

+ 1 - 1
std/haxe/Timer.hx

@@ -179,7 +179,7 @@ class Timer {
 			return Sys.cpuTime();
 			return Sys.cpuTime();
 		#elseif sys
 		#elseif sys
 			return Sys.time();
 			return Sys.time();
-		
+
 		#else
 		#else
 			return 0;
 			return 0;
 		#end
 		#end

+ 1 - 0
std/haxe/extern/AsVar.hx

@@ -27,4 +27,5 @@ package haxe.extern;
 	argument expressions are bound to a local variable.
 	argument expressions are bound to a local variable.
 **/
 **/
 @:forward
 @:forward
+@:analyzer(as_var)
 abstract AsVar<T>(T) from T to T {}
 abstract AsVar<T>(T) from T to T {}

+ 2 - 0
std/haxe/io/BytesData.hx

@@ -27,6 +27,8 @@ package haxe.io;
 	typedef BytesData =	flash.utils.ByteArray;
 	typedef BytesData =	flash.utils.ByteArray;
 #elseif php
 #elseif php
 	typedef BytesData = php.BytesData;
 	typedef BytesData = php.BytesData;
+#elseif php
+	typedef BytesData = php.NativeString;
 #elseif cpp
 #elseif cpp
 	typedef BytesData = Array< cpp.UInt8 >;
 	typedef BytesData = Array< cpp.UInt8 >;
 #elseif java
 #elseif java

+ 20 - 17
std/haxe/io/Input.hx

@@ -24,6 +24,9 @@ package haxe.io;
 /**
 /**
 	An Input is an abstract reader. See other classes in the `haxe.io` package
 	An Input is an abstract reader. See other classes in the `haxe.io` package
 	for several possible implementations.
 	for several possible implementations.
+
+	All functions which read data throw `Eof` when the end of the stream
+	is reached.
 **/
 **/
 class Input {
 class Input {
 
 
@@ -65,17 +68,17 @@ class Input {
 			throw Error.OutsideBounds;
 			throw Error.OutsideBounds;
 		try {
 		try {
 			while( k > 0 ) {
 			while( k > 0 ) {
-			    #if neko
-				    untyped __dollar__sset(b,pos,readByte());
-			    #elseif php
-				    b.set(pos, readByte());
-			    #elseif cpp
-				    b[pos] = untyped readByte();
-			    #else
-				    b[pos] = cast readByte();
-			    #end
-			    pos++;
-			    k--;
+				#if neko
+					untyped __dollar__sset(b,pos,readByte());
+				#elseif php
+					b.set(pos, readByte());
+				#elseif cpp
+					b[pos] = untyped readByte();
+				#else
+					b[pos] = cast readByte();
+				#end
+				pos++;
+				k--;
 			}
 			}
 		} catch (eof: haxe.io.Eof){}
 		} catch (eof: haxe.io.Eof){}
 		return len-k;
 		return len-k;
@@ -284,7 +287,7 @@ class Input {
 		// php will overflow integers.  Convert them back to signed 32-bit ints.
 		// php will overflow integers.  Convert them back to signed 32-bit ints.
 		var n = bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
 		var n = bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
 		if (n & 0x80000000 != 0)
 		if (n & 0x80000000 != 0)
-		    return ( n | 0x80000000);
+			return ( n | 0x80000000);
 		else return n;
 		else return n;
 #elseif lua
 #elseif lua
 		var n = bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
 		var n = bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
@@ -317,11 +320,11 @@ class Input {
 
 
 #if (flash || js || python)
 #if (flash || js || python)
 	function getDoubleSig(bytes:Array<Int>)
 	function getDoubleSig(bytes:Array<Int>)
-    {
-        return (((bytes[1]&0xF) << 16) | (bytes[2] << 8) | bytes[3] ) * 4294967296. +
-            (bytes[4] >> 7) * 2147483648 +
-            (((bytes[4]&0x7F) << 24) | (bytes[5] << 16) | (bytes[6] << 8) | bytes[7]);
-    }
+	{
+		return (((bytes[1]&0xF) << 16) | (bytes[2] << 8) | bytes[3] ) * 4294967296. +
+			(bytes[4] >> 7) * 2147483648 +
+			(((bytes[4]&0x7F) << 24) | (bytes[5] << 16) | (bytes[6] << 8) | bytes[7]);
+	}
 #end
 #end
 
 
 }
 }

+ 3 - 5
std/haxe/macro/CompilationServer.hx

@@ -50,7 +50,7 @@ abstract ModuleCheckPolicy(Int) {
 	`--macro server.field(args)`.
 	`--macro server.field(args)`.
 **/
 **/
 class CompilationServer {
 class CompilationServer {
-	#if neko
+	#if macro
 
 
 	/**
 	/**
 		Sets the `ModuleCheckPolicy` of all files whose dot-path matches an
 		Sets the `ModuleCheckPolicy` of all files whose dot-path matches an
@@ -71,16 +71,14 @@ class CompilationServer {
 		compilation server should be restarted to ensure it takes effect.
 		compilation server should be restarted to ensure it takes effect.
 	**/
 	**/
 	static public function setModuleCheckPolicy(pathFilters:Array<String>, policy:Array<ModuleCheckPolicy>, ?recursive = true, ?contextOptions:ContextOptions = NormalContext) {
 	static public function setModuleCheckPolicy(pathFilters:Array<String>, policy:Array<ModuleCheckPolicy>, ?recursive = true, ?contextOptions:ContextOptions = NormalContext) {
-		pathFilters = [for (pathFilter in pathFilters) untyped pathFilter.__s];
-		@:privateAccess Compiler.load("server_add_module_check_policy", 4)(untyped pathFilters.__neko(), policy.__neko(), recursive, contextOptions);
+		@:privateAccess Compiler.load("server_add_module_check_policy", 4)(pathFilters, policy, recursive, contextOptions);
 	}
 	}
 
 
 	/**
 	/**
 		Invalidates all files given in `filePaths`, removing them from the cache.
 		Invalidates all files given in `filePaths`, removing them from the cache.
 	**/
 	**/
 	static public function invalidateFiles(filePaths:Array<String>) {
 	static public function invalidateFiles(filePaths:Array<String>) {
-		filePaths = [for (filePath in filePaths) untyped filePath.__s];
-		@:privateAccess Compiler.load("server_invalidate_files", 1)(untyped filePaths.__neko());
+		@:privateAccess Compiler.load("server_invalidate_files", 1)(filePaths);
 	}
 	}
 	#end
 	#end
 }
 }

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

@@ -213,7 +213,7 @@ class Compiler {
 				continue;
 				continue;
 			found = true;
 			found = true;
 			for( file in sys.FileSystem.readDirectory(path) ) {
 			for( file in sys.FileSystem.readDirectory(path) ) {
-				if( StringTools.endsWith(file, ".hx") && file.indexOf(".") < 0 ) {
+				if( StringTools.endsWith(file, ".hx") && file.substr(0, file.length - 3).indexOf(".") < 0 ) {
 					var cl = prefix + file.substr(0, file.length - 3);
 					var cl = prefix + file.substr(0, file.length - 3);
 					if( skip(cl) )
 					if( skip(cl) )
 						continue;
 						continue;

+ 5 - 3
std/haxe/rtti/Meta.hx

@@ -46,11 +46,11 @@ class Meta {
 	private static function isInterface(t:Dynamic):Bool {
 	private static function isInterface(t:Dynamic):Bool {
 		#if java
 		#if java
 			return java.Lib.toNativeType(t).isInterface();
 			return java.Lib.toNativeType(t).isInterface();
-		#elseif cs
+	#elseif cs
 			return cs.Lib.toNativeType(t).IsInterface;
 			return cs.Lib.toNativeType(t).IsInterface;
 		#elseif (flash && as3)
 		#elseif (flash && as3)
 			return untyped flash.Lib.describeType(t).factory.extendsClass.length() == 0;
 			return untyped flash.Lib.describeType(t).factory.extendsClass.length() == 0;
-		#elseif php
+		#elseif (php && !php7)
 			return untyped __php__("{0} instanceof _hx_interface", t);
 			return untyped __php__("{0} instanceof _hx_interface", t);
 		#else
 		#else
 			throw "Something went wrong";
 			throw "Something went wrong";
@@ -59,7 +59,9 @@ class Meta {
 
 
 	private static function getMeta(t:Dynamic):MetaObject
 	private static function getMeta(t:Dynamic):MetaObject
 	{
 	{
-#if (java || cs || php || (flash && as3))
+#if (php && php7)
+		return php.Boot.getMeta(t.phpClassName);
+#elseif (java || cs || php || (flash && as3))
 		var ret = Reflect.field(t, "__meta__");
 		var ret = Reflect.field(t, "__meta__");
 		if (ret == null && Std.is(t,Class))
 		if (ret == null && Std.is(t,Class))
 		{
 		{

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

@@ -52,27 +52,27 @@ class XmlParserException
 	 * the XML parsing error message
 	 * the XML parsing error message
 	 */
 	 */
 	public var message:String;
 	public var message:String;
-	
+
 	/**
 	/**
 	 * the line number at which the XML parsing error occured
 	 * the line number at which the XML parsing error occured
 	 */
 	 */
 	public var lineNumber:Int;
 	public var lineNumber:Int;
-	
+
 	/**
 	/**
 	 * the character position in the reported line at which the parsing error occured
 	 * the character position in the reported line at which the parsing error occured
 	 */
 	 */
 	public var positionAtLine:Int;
 	public var positionAtLine:Int;
-	
+
 	/**
 	/**
 	 * the character position in the XML string at which the parsing error occured
 	 * the character position in the XML string at which the parsing error occured
 	 */
 	 */
 	public var position:Int;
 	public var position:Int;
-	
+
 	/**
 	/**
 	 * the invalid XML string
 	 * the invalid XML string
 	 */
 	 */
 	public var xml:String;
 	public var xml:String;
-	
+
 	public function new(message:String, xml:String, position:Int)
 	public function new(message:String, xml:String, position:Int)
 	{
 	{
 		this.xml = xml;
 		this.xml = xml;
@@ -80,7 +80,7 @@ class XmlParserException
 		this.position = position;
 		this.position = position;
 		lineNumber = 1;
 		lineNumber = 1;
 		positionAtLine = 0;
 		positionAtLine = 0;
-		
+
 		for( i in 0...position)
 		for( i in 0...position)
 		{
 		{
 			var c = xml.fastCodeAt(i);
 			var c = xml.fastCodeAt(i);
@@ -92,7 +92,7 @@ class XmlParserException
 			}
 			}
 		}
 		}
 	}
 	}
-	
+
 	public function toString():String
 	public function toString():String
 	{
 	{
 		return Type.getClassName(Type.getClass(this)) + ": " + message + " at line " + lineNumber + " char " + positionAtLine;
 		return Type.getClassName(Type.getClass(this)) + ": " + message + " at line " + lineNumber + " char " + positionAtLine;
@@ -113,7 +113,7 @@ class Parser
 
 
 	/**
 	/**
 	 * Parses the String into an XML Document. Set strict parsing to true in order to enable a strict check of XML attributes and entities.
 	 * Parses the String into an XML Document. Set strict parsing to true in order to enable a strict check of XML attributes and entities.
-	 * 
+	 *
 	 * @throws haxe.xml.XmlParserException
 	 * @throws haxe.xml.XmlParserException
 	 */
 	 */
 	static public function parse(str:String, strict = false)
 	static public function parse(str:String, strict = false)

+ 2 - 1
std/hl/Api.hx

@@ -36,5 +36,6 @@ extern class Api {
 	@:hlNative("std", "get_virtual_value") static function getVirtualValue( v : Dynamic ) : Dynamic;
 	@:hlNative("std", "get_virtual_value") static function getVirtualValue( v : Dynamic ) : Dynamic;
 	@:hlNative("std", "set_error_handler") static function setErrorHandler( v : Dynamic -> Void ) : Void;
 	@:hlNative("std", "set_error_handler") static function setErrorHandler( v : Dynamic -> Void ) : Void;
 	@:hlNative("std", "breakpoint") static function breakPoint() : Void;
 	@:hlNative("std", "breakpoint") static function breakPoint() : Void;
-	
+	@:hlNative("std", "sys_is64") static function is64() : Bool;
+
 }
 }

+ 35 - 1
std/hl/Bytes.hx

@@ -113,10 +113,44 @@ package hl;
 		Please note that you need to retain the original unoffset'ed Bytes so it does not get garbage collected, unless the pointer was not GC allocated.
 		Please note that you need to retain the original unoffset'ed Bytes so it does not get garbage collected, unless the pointer was not GC allocated.
 	**/
 	**/
 	@:hlNative("std","bytes_offset")
 	@:hlNative("std","bytes_offset")
-	public function offset( pos : Int ) : Bytes {
+	public function offset( delta : Int ) : Bytes {
 		return null;
 		return null;
 	}
 	}
 
 
+	/**
+		Returns an offset between the two pointers. This might overflow in 64 bits if the addresses of the two pointers differs by more than 4GB
+	**/
+	@:hlNative("std","bytes_subtract")
+	public function subtract( other : Bytes ) : Int {
+		return 0;
+	}
+
+	@:hlNative("std", "bytes_address")
+	static function get_address( b : Bytes, high : Ref<Int> ) : Int {
+		return 0;
+	}
+
+	@:hlNative("std", "bytes_from_address")
+	static function from_address( low : Int, high : Int ) : Bytes {
+		return null;
+	}
+
+	/**
+		Creates an pointer at a given memory address (highly unsafe)
+	**/
+	public static inline function fromAddress( h : haxe.Int64 ) : Bytes {
+		return from_address(h.low, h.high);
+	}
+
+	/**
+		Returns the address value of the bytes. On 32 bit system the upper 32 bits will always be 0
+	**/
+	public function address() : haxe.Int64 {
+		var high = 0;
+		var low = get_address(this, high);
+		return haxe.Int64.make(high,low);
+	}
+
 	public function sub( pos : Int, size : Int ) {
 	public function sub( pos : Int, size : Int ) {
 		var b = new Bytes(size);
 		var b = new Bytes(size);
 		b.blit(0, this, pos, size);
 		b.blit(0, this, pos, size);

+ 1 - 1
std/hl/Type.hx

@@ -97,7 +97,7 @@ abstract TypeKind(Int) {
 		return null;
 		return null;
 	}
 	}
 
 
-	@:hlNative("std", "alloc_enum") public function allocEnum( index : Int, args : NativeArray<Dynamic> ) : Dynamic {
+	@:hlNative("std", "alloc_enum") public function allocEnum( index : Int, args : NativeArray<Dynamic>, nargs : Int ) : Dynamic {
 		return null;
 		return null;
 	}
 	}
 
 

+ 1 - 1
std/hl/_std/String.hx

@@ -117,7 +117,7 @@ class String {
 			if( pos < 0 ) pos = 0;
 			if( pos < 0 ) pos = 0;
 		} else if( len < 0 )
 		} else if( len < 0 )
 			len = sl + len - pos;
 			len = sl + len - pos;
-		if( pos + len > sl )
+		if( ((pos + len) : UInt) > (sl:UInt) )
 			len = sl - pos;
 			len = sl - pos;
 		if( pos < 0 || len <= 0 ) return "";
 		if( pos < 0 || len <= 0 ) return "";
 
 

+ 3 - 3
std/hl/_std/Type.hx

@@ -121,16 +121,16 @@ class Type {
 			return v;
 			return v;
 		}
 		}
 		var a : hl.types.ArrayDyn = cast params;
 		var a : hl.types.ArrayDyn = cast params;
-		var aobj = Std.instance(@:privateAccess a.array, hl.types.ArrayObj);
 		var narr;
 		var narr;
-		if( aobj == null ) {
+		if( @:privateAccess !a.array.isArrayObj() ) {
 			narr = new hl.NativeArray<Dynamic>(a.length);
 			narr = new hl.NativeArray<Dynamic>(a.length);
 			for( i in 0...a.length )
 			for( i in 0...a.length )
 				narr[i] = @:privateAccess a.array.getDyn(i);
 				narr[i] = @:privateAccess a.array.getDyn(i);
 		} else {
 		} else {
+			var aobj : hl.types.ArrayObj<Dynamic> = cast @:privateAccess a.array;
 			narr = @:privateAccess aobj.array;
 			narr = @:privateAccess aobj.array;
 		}
 		}
-		var v = @:privateAccess e.__type__.allocEnum(index, narr);
+		var v = @:privateAccess e.__type__.allocEnum(index, narr, a.length);
 		if( v == null ) throw "Constructor " + e.__ename__ +"." + e.__constructs__[index] + " does not takes " + narr.length + " parameters";
 		if( v == null ) throw "Constructor " + e.__ename__ +"." + e.__constructs__[index] + " does not takes " + narr.length + " parameters";
 		return v;
 		return v;
 	}
 	}

+ 8 - 4
std/hl/_std/haxe/io/Bytes.hx

@@ -36,6 +36,10 @@ class Bytes {
 		return (pos:UInt) >= (length : UInt);
 		return (pos:UInt) >= (length : UInt);
 	}
 	}
 
 
+	inline function outRange(pos:Int,len:Int) : Bool {
+		return pos < 0 || len < 0 || ((pos+len):UInt) > (length : UInt);
+	}
+
 	public function get( pos : Int ) : Int {
 	public function get( pos : Int ) : Int {
 		return if( out(pos) ) 0 else b[pos];
 		return if( out(pos) ) 0 else b[pos];
 	}
 	}
@@ -46,17 +50,17 @@ class Bytes {
 	}
 	}
 
 
 	public function blit( pos : Int, src : Bytes, srcpos : Int, len : Int ) : Void {
 	public function blit( pos : Int, src : Bytes, srcpos : Int, len : Int ) : Void {
-		if( pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length ) throw Error.OutsideBounds;
+		if( outRange(pos, len) || src.outRange(srcpos,len) ) throw Error.OutsideBounds;
 		b.blit(pos, src.b, srcpos, len);
 		b.blit(pos, src.b, srcpos, len);
 	}
 	}
 
 
 	public function fill( pos : Int, len : Int, value : Int ) : Void {
 	public function fill( pos : Int, len : Int, value : Int ) : Void {
-		if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
+		if( outRange(pos,len) ) throw Error.OutsideBounds;
 		b.fill(pos, len, value);
 		b.fill(pos, len, value);
 	}
 	}
 
 
 	public function sub( pos : Int, len : Int ) : Bytes {
 	public function sub( pos : Int, len : Int ) : Bytes {
-		if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
+		if( outRange(pos,len) ) throw Error.OutsideBounds;
 		return new Bytes(b.sub(pos, len), len);
 		return new Bytes(b.sub(pos, len), len);
 	}
 	}
 
 
@@ -116,7 +120,7 @@ class Bytes {
 	}
 	}
 
 
 	public function getString( pos : Int, len : Int ) : String {
 	public function getString( pos : Int, len : Int ) : String {
-		if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds;
+		if( outRange(pos,len) ) throw Error.OutsideBounds;
 
 
 		var b = new hl.Bytes(len + 1);
 		var b = new hl.Bytes(len + 1);
 		b.blit(0, this.b, pos, len);
 		b.blit(0, this.b, pos, len);

+ 2 - 2
std/hl/_std/sys/db/Sqlite.hx

@@ -22,8 +22,8 @@
 package sys.db;
 package sys.db;
 import haxe.crypto.BaseCode;
 import haxe.crypto.BaseCode;
 
 
-private typedef SqliteConnectionHandle = hl.types.NativeAbstract<"sqlite_database">;
-private typedef SqliteResultHandle = hl.types.NativeAbstract<"sqlite_result">;
+private typedef SqliteConnectionHandle = hl.Abstract<"sqlite_database">;
+private typedef SqliteResultHandle = hl.Abstract<"sqlite_result">;
 
 
 @:hlNative("sqlite")
 @:hlNative("sqlite")
 private class SqliteLib
 private class SqliteLib

+ 4 - 0
std/hl/_std/sys/io/File.hx

@@ -21,7 +21,11 @@
  */
  */
 package sys.io;
 package sys.io;
 
 
+#if doc_gen
+enum FileHandle { }
+#else
 typedef FileHandle = hl.Abstract<"hl_fdesc">;
 typedef FileHandle = hl.Abstract<"hl_fdesc">;
+#end
 
 
 @:access(Sys)
 @:access(Sys)
 @:coreApi class File {
 @:coreApi class File {

+ 56 - 7
std/hl/_std/sys/io/Process.hx

@@ -21,7 +21,7 @@
  */
  */
 package sys.io;
 package sys.io;
 
 
-private typedef ProcessHandle = hl.types.NativeAbstract<"hl_process">;
+private typedef ProcessHandle = hl.Abstract<"hl_process">;
 
 
 private class Stdin extends haxe.io.Output {
 private class Stdin extends haxe.io.Output {
 
 
@@ -50,7 +50,7 @@ private class Stdin extends haxe.io.Output {
 	}
 	}
 
 
 	@:hlNative("std","process_stdin_write") static function _stdin_write( p : ProcessHandle, bytes : hl.Bytes, pos : Int, len : Int ) : Int { return 0; }
 	@:hlNative("std","process_stdin_write") static function _stdin_write( p : ProcessHandle, bytes : hl.Bytes, pos : Int, len : Int ) : Int { return 0; }
-	@:hlNative("std","process_stdin_close") static function _stdin_close( p : ProcessHandle ) : Void { }
+	@:hlNative("std", "process_stdin_close") static function _stdin_close( p : ProcessHandle ) : Bool { return false; }
 
 
 }
 }
 
 
@@ -89,9 +89,54 @@ private class Stdout extends haxe.io.Input {
 	var p : ProcessHandle;
 	var p : ProcessHandle;
 	public var stdout(default,null) : haxe.io.Input;
 	public var stdout(default,null) : haxe.io.Input;
 	public var stderr(default,null) : haxe.io.Input;
 	public var stderr(default,null) : haxe.io.Input;
-	public var stdin(default,null) : haxe.io.Output;
+	public var stdin(default, null) : haxe.io.Output;
+
+	static var isWin = Sys.systemName() == "Windows";
 
 
 	public function new( cmd : String, ?args : Array<String> ) : Void {
 	public function new( cmd : String, ?args : Array<String> ) : Void {
+		var runCmd = cmd;
+		if( isWin ) {
+			var b = new StringBuf();
+			if( args == null ) {
+				var exe = Sys.getEnv("COMSPEC");
+				if( exe == null ) exe = "cmd.exe";
+				b.add("\"");
+				b.add(exe);
+				b.add("\" /C \"");
+				b.add(cmd);
+				b.addChar('"'.code);
+			} else {
+				b.addChar('"'.code);
+				b.add(cmd);
+				b.addChar('"'.code);
+				for( a in args ) {
+					b.add(" \"");
+					var bsCount = 0;
+					for( i in 0...a.length ) {
+						switch( StringTools.fastCodeAt(a, i) ) {
+						case '"'.code:
+							for( i in 0...bsCount * 2 )
+								b.addChar('\\'.code);
+							bsCount = 0;
+							b.add("\\\"");
+						case '\\'.code:
+							bsCount++;
+						case c:
+							for( i in 0...bsCount )
+								b.addChar('\\'.code);
+							bsCount = 0;
+							b.addChar(c);
+						}
+					}
+					// Add remaining backslashes, if any.
+					for( i in 0...bsCount * 2 )
+						b.addChar('\\'.code);
+					b.addChar('"'.code);
+				}
+				args = null;
+			}
+			runCmd = b.toString();
+		}
 		@:privateAccess {
 		@:privateAccess {
 			var aargs = null;
 			var aargs = null;
 			if( args != null ) {
 			if( args != null ) {
@@ -99,7 +144,7 @@ private class Stdout extends haxe.io.Input {
 				for( i in 0...args.length )
 				for( i in 0...args.length )
 					aargs[i] = Sys.getPath(args[i]);
 					aargs[i] = Sys.getPath(args[i]);
 			}
 			}
-			p = _run(Sys.getPath(cmd), aargs);
+			p = _run(Sys.getPath(runCmd), aargs);
 		}
 		}
 		if( p == null )
 		if( p == null )
 			throw new Sys.SysError("Process creation failure : "+cmd);
 			throw new Sys.SysError("Process creation failure : "+cmd);
@@ -112,8 +157,12 @@ private class Stdout extends haxe.io.Input {
 		return _pid(p);
 		return _pid(p);
 	}
 	}
 
 
-	public function exitCode() : Int {
-		return _exit(p);
+	public function exitCode( block : Bool = true ) : Null<Int> {
+		var running = false;
+		var code = _exit(p, block == false ? new hl.Ref(running) : null);
+		if( block == false )
+			return running ? null : code;
+		return code;
 	}
 	}
 
 
 	public function close() : Void {
 	public function close() : Void {
@@ -125,7 +174,7 @@ private class Stdout extends haxe.io.Input {
 	}
 	}
 
 
 	@:hlNative("std","process_run")	static function _run( cmd : hl.Bytes, args : hl.NativeArray<hl.Bytes> ) : ProcessHandle { return null; }
 	@:hlNative("std","process_run")	static function _run( cmd : hl.Bytes, args : hl.NativeArray<hl.Bytes> ) : ProcessHandle { return null; }
-	@:hlNative("std", "process_exit") static function _exit( p : ProcessHandle ) : Int { return 0; }
+	@:hlNative("std", "process_exit") static function _exit( p : ProcessHandle, running : hl.Ref<Bool> ) : Int { return 0; }
 	@:hlNative("std", "process_pid") static function _pid( p : ProcessHandle ) : Int { return 0; }
 	@:hlNative("std", "process_pid") static function _pid( p : ProcessHandle ) : Int { return 0; }
 	@:hlNative("std","process_close") static function _close( p : ProcessHandle ) : Void { }
 	@:hlNative("std","process_close") static function _close( p : ProcessHandle ) : Void { }
 	@:hlNative("std","process_kill") static function _kill( p : ProcessHandle ) : Void { }
 	@:hlNative("std","process_kill") static function _kill( p : ProcessHandle ) : Void { }

+ 10 - 2
std/hl/_std/sys/net/Socket.hx

@@ -22,7 +22,11 @@
 package sys.net;
 package sys.net;
 import haxe.io.Error;
 import haxe.io.Error;
 
 
-private typedef SocketHandle = hl.Abstract<"hl_socket">;
+#if doc_gen
+@:noDoc enum SocketHandle { }
+#else
+@:noDoc typedef SocketHandle = hl.Abstract<"hl_socket">;
+#end
 
 
 private class SocketOutput extends haxe.io.Output {
 private class SocketOutput extends haxe.io.Output {
 
 
@@ -110,7 +114,11 @@ class Socket {
 	}
 	}
 
 
 	public function new() : Void {
 	public function new() : Void {
-		if( __s == null ) __s = socket_new(false);
+		init();
+	}
+	
+	function init() : Void {
+		__s = socket_new(false);
 		input = new SocketInput(this);
 		input = new SocketInput(this);
 		output = new SocketOutput(this);
 		output = new SocketOutput(this);
 	}
 	}

+ 130 - 0
std/hl/_std/sys/ssl/Certificate.hx

@@ -0,0 +1,130 @@
+package sys.ssl;
+import sys.ssl.Lib;
+
+@:noDoc
+typedef CertificatePtr = hl.Abstract<"hl_ssl_cert">;
+
+@:coreApi
+class Certificate {
+	
+	var __h : Null<Certificate>;
+	var __x : CertificatePtr;
+
+	@:allow(sys.ssl.Socket)
+	function new( x : CertificatePtr, ?h: Null<Certificate> ){
+		__x = x;
+		__h = h;
+	}
+
+	public static function loadFile( file : String ) : Certificate {
+		return new Certificate( cert_load_file( @:privateAccess file.toUtf8() ) );
+	}
+	
+	public static function loadPath( path : String ) : Certificate {
+		return new Certificate( cert_load_path( @:privateAccess path.toUtf8() ) );
+	}
+
+	public static function fromString( str : String ) : Certificate {
+		return new Certificate( cert_add_pem(null, @:privateAccess str.toUtf8() ) );
+	}
+	
+	public static function loadDefaults() : Certificate {
+		var x = cert_load_defaults();
+		if ( x != null )
+			return new Certificate( x );
+		
+		var defPaths = null;
+		switch( Sys.systemName() ){
+			case "Linux":
+				defPaths = [
+					"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
+					"/etc/pki/tls/certs/ca-bundle.crt",   // Fedora/RHEL
+					"/etc/ssl/ca-bundle.pem",             // OpenSUSE
+					"/etc/pki/tls/cacert.pem",            // OpenELEC
+					"/etc/ssl/certs",                     // SLES10/SLES11
+					"/system/etc/security/cacerts"        // Android
+				];
+			case "BSD":
+				defPaths = [
+					"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
+					"/etc/ssl/cert.pem",                      // OpenBSD
+					"/etc/openssl/certs/ca-certificates.crt", // NetBSD	
+				];
+			case "Android":
+				defPaths = ["/system/etc/security/cacerts"];
+			default:
+		}
+		if( defPaths != null ){
+			for( path in defPaths ){
+				if( sys.FileSystem.exists(path) ){
+					if( sys.FileSystem.isDirectory(path) )
+						return loadPath(path);
+					else
+						return loadFile(path);
+				}
+			}
+		}
+		return null;
+	}
+
+	public var commonName(get,null) : Null<String>;
+	public var altNames(get, null) : Array<String>;
+	public var notBefore(get,null) : Date;
+	public var notAfter(get,null) : Date;
+
+	function get_commonName() : Null<String> {
+		return subject("CN");
+	}
+
+	function get_altNames() : Array<String> {
+		var a = cert_get_altnames(__x);
+		return [for( e in a ) @:privateAccess String.fromUTF8(e)];
+	}
+	
+	public function subject( field : String ) : Null<String> {
+		var s = cert_get_subject(__x, @:privateAccess field.toUtf8() );
+		return s==null ? null : new String( cast s );
+	}
+	
+	public function issuer( field : String ) : Null<String> {
+		var s = cert_get_issuer(__x, @:privateAccess field.toUtf8());
+		return s==null ? null : new String( cast s );
+	}
+
+	function get_notBefore() : Date {
+		var a = cert_get_notbefore( __x );
+		return new Date( a[0], a[1] - 1, a[2], a[3], a[4], a[5] );
+	}
+
+	function get_notAfter() : Date {
+		var a = cert_get_notafter( __x );
+		return new Date( a[0], a[1] - 1, a[2], a[3], a[4], a[5] );
+	}
+	
+	public function next() : Null<Certificate> {
+		var n = cert_get_next(__x);
+		return n == null ? null : new Certificate( n, __h==null ? this : __h );
+	}
+
+	public function add( pem : String ) : Void {
+		cert_add_pem(__x, @:privateAccess pem.toUtf8());
+	}
+
+	public function addDER( der : haxe.io.Bytes ) : Void {
+		cert_add_der(__x, @:privateAccess der.b, @:privateAccess der.length);
+	}
+
+	@:hlNative("ssl","cert_load_defaults") static function cert_load_defaults() : CertificatePtr { return null; }
+	@:hlNative("ssl","cert_load_file") static function cert_load_file( file : hl.Bytes ) : CertificatePtr { return null; }
+	@:hlNative("ssl","cert_load_path") static function cert_load_path( path : hl.Bytes ) : CertificatePtr { return null; }
+	@:hlNative("ssl","cert_get_subject") static function cert_get_subject( cert : CertificatePtr, obj : hl.Bytes ) : hl.Bytes { return null; }
+	@:hlNative("ssl","cert_get_issuer") static function cert_get_issuer( cert : CertificatePtr, obj : hl.Bytes ) : hl.Bytes { return null; }
+	@:hlNative("ssl","cert_get_altnames") static function cert_get_altnames( cert : CertificatePtr ) : hl.NativeArray<hl.Bytes> { return null; }
+	@:hlNative("ssl","cert_get_notbefore") static function cert_get_notbefore( cert : CertificatePtr ) : hl.NativeArray<Int> { return null; }
+	@:hlNative("ssl","cert_get_notafter") static function cert_get_notafter( cert : CertificatePtr ) : hl.NativeArray<Int> { return null; }
+	@:hlNative("ssl","cert_get_next") static function cert_get_next( cert : CertificatePtr ) : Null<CertificatePtr> { return null; }
+	@:hlNative("ssl","cert_add_pem") static function cert_add_pem( cert : Null<CertificatePtr>, data : hl.Bytes ) : CertificatePtr { return null; }
+	@:hlNative("ssl","cert_add_der") static function cert_add_der( cert : Null<CertificatePtr>, data : hl.Bytes, len : Int ) : CertificatePtr { return null; }
+	
+
+}

+ 27 - 0
std/hl/_std/sys/ssl/Digest.hx

@@ -0,0 +1,27 @@
+package sys.ssl;
+import sys.ssl.Lib;
+
+@:coreApi
+class Digest {
+	
+	public static function make( data : haxe.io.Bytes, alg : DigestAlgorithm ) : haxe.io.Bytes {
+		var size = 0;
+		var b = @:privateAccess dgst_make( data.b, data.length, (alg:String).toUtf8(), size );
+		return @:privateAccess new haxe.io.Bytes(b,size);
+	}
+	
+	public static function sign( data : haxe.io.Bytes, privKey : Key, alg : DigestAlgorithm ) : haxe.io.Bytes {
+		var size = 0;
+		var b = @:privateAccess dgst_sign( data.b, data.length, privKey.__k, (alg:String).toUtf8(), size );
+		return @:privateAccess new haxe.io.Bytes(b,size);
+	}
+	
+	public static function verify( data : haxe.io.Bytes, signature : haxe.io.Bytes, pubKey : Key, alg : DigestAlgorithm ) : Bool{
+		return @:privateAccess dgst_verify( data.b, data.length, signature.b, signature.length, pubKey.__k, (alg:String).toUtf8() );
+	}
+
+	@:hlNative("ssl","dgst_make") static function dgst_make( data : hl.Bytes, len : Int, alg : hl.Bytes, size : hl.Ref<Int> ) : hl.Bytes { return null; }
+	@:hlNative("ssl","dgst_sign") static function dgst_sign( data : hl.Bytes, len : Int, key : sys.ssl.Key.KeyPtr, alg : hl.Bytes, size : hl.Ref<Int> ) : hl.Bytes { return null; }
+	@:hlNative("ssl","dgst_verify") static function dgst_verify( data : hl.Bytes, dlen : Int, sign : hl.Bytes, slen : Int, key : sys.ssl.Key.KeyPtr, alg : hl.Bytes ) : Bool { return false; }
+	
+}

+ 36 - 0
std/hl/_std/sys/ssl/Key.hx

@@ -0,0 +1,36 @@
+package sys.ssl;
+import sys.ssl.Lib;
+
+@:noDoc
+typedef KeyPtr = hl.Abstract<"hl_ssl_pkey">;
+
+@:coreApi
+class Key {
+	
+	private var __k : KeyPtr;
+
+	private function new( k : KeyPtr ){
+		__k = k;
+	}
+	
+	public static function loadFile( file : String, ?isPublic : Bool, ?pass : String ) : Key {
+		var data = sys.io.File.getBytes( file );
+		var start = data.getString(0,11);
+		if( start == "-----BEGIN " )
+			return readPEM( data.toString(), isPublic==true, pass );
+		else
+			return readDER( data, isPublic==true );
+	}
+	
+	public static function readPEM( data : String, isPublic : Bool, ?pass : String ) : Key {
+		return new Key( key_from_pem( @:privateAccess data.toUtf8(), isPublic, pass == null ? null : @:privateAccess pass.toUtf8() ) );
+	}
+
+	public static function readDER( data : haxe.io.Bytes, isPublic : Bool ) : Key {
+		return new Key( key_from_der( @:privateAccess data.b, @:privateAccess data.length, isPublic ) );
+	}
+
+	@:hlNative("ssl","key_from_pem") static function key_from_pem( data : hl.Bytes, pub : Bool, pass : Null<hl.Bytes> ) : KeyPtr { return null; }
+	@:hlNative("ssl","key_from_der") static function key_from_der( data : hl.Bytes, len : Int, pub : Bool ) : KeyPtr { return null; }
+
+}

+ 10 - 0
std/hl/_std/sys/ssl/Lib.hx

@@ -0,0 +1,10 @@
+package sys.ssl;
+
+@:noDoc @:keep
+class Lib {
+	static function __init__() : Void{
+		ssl_init();
+	}
+	
+	@:hlNative("ssl","ssl_init") static function ssl_init(){};
+}

+ 251 - 0
std/hl/_std/sys/ssl/Socket.hx

@@ -0,0 +1,251 @@
+package sys.ssl;
+import sys.ssl.Lib;
+import sys.ssl.Key.KeyPtr;
+import sys.ssl.Certificate.CertificatePtr;
+import sys.net.Socket.SocketHandle;
+
+private typedef ConfigPtr = hl.Abstract<"mbedtls_ssl_config">;
+private typedef ContextPtr = hl.Abstract<"mbedtls_ssl_context">;
+
+@:keep
+private class SNICbResult {
+	public var cert : CertificatePtr;
+	public var key : KeyPtr; 
+	public function new( cert : Certificate, key : Key ){
+		this.cert = @:privateAccess cert.__x;
+		this.key = @:privateAccess key.__k;
+	}
+}
+
+private class SocketInput extends haxe.io.Input {
+	@:allow(sys.ssl.Socket) private var __s : Socket;
+
+	public function new( s : Socket ) {
+		this.__s = s;
+	}
+
+	public override function readByte() {
+		__s.handshake();
+		var r = ssl_recv_char( @:privateAccess __s.ssl );
+		if( r == -1 )
+			throw haxe.io.Error.Blocked;
+		else if( r < 0 )
+			throw new haxe.io.Eof();
+		return r;
+	}
+
+	public override function readBytes( buf : haxe.io.Bytes, pos : Int, len : Int ) : Int {
+		__s.handshake();
+		var r = ssl_recv(  @:privateAccess __s.ssl, @:privateAccess buf.b, pos, len );
+		if( r == -1 )
+			throw haxe.io.Error.Blocked;
+		else if( r < 0 )
+			throw new haxe.io.Eof();
+		return r;
+	}
+
+	public override function close() {
+		super.close();
+		if( __s != null ) __s.close();
+	}
+	
+	@:hlNative("ssl","ssl_recv") static function ssl_recv( ssl : ContextPtr, bytes : hl.Bytes, pos : Int, len : Int ) : Int { return -1; }
+	@:hlNative("ssl","ssl_recv_char") static function ssl_recv_char( ssl : ContextPtr ) : Int { return -1; }
+}
+
+private class SocketOutput extends haxe.io.Output {
+	@:allow(sys.ssl.Socket) private var __s : Socket;
+
+	public function new( s : Socket ) {
+		this.__s = s;
+	}
+
+	public override function writeByte( c : Int ) {
+		__s.handshake();
+		var r = ssl_send_char( @:privateAccess __s.ssl, c);
+		if( r == -1 )
+			throw haxe.io.Error.Blocked;
+		else if( r < 0 )
+			throw new haxe.io.Eof();
+	}
+
+	public override function writeBytes( buf : haxe.io.Bytes, pos : Int, len : Int) : Int {
+		__s.handshake();
+		var r = ssl_send( @:privateAccess __s.ssl, @:privateAccess buf.b, pos, len);
+		if( r == -1 )
+			throw haxe.io.Error.Blocked;
+		else if( r < 0 )
+			throw new haxe.io.Eof();
+		return r;
+	}
+
+	public override function close() {
+		super.close();
+		if( __s != null ) __s.close();
+	}
+
+	@:hlNative("ssl","ssl_send") static function ssl_send( ssl : ContextPtr, bytes : hl.Bytes, pos : Int, len : Int ) : Int { return -1; }
+	@:hlNative("ssl","ssl_send_char") static function ssl_send_char( ssl : ContextPtr, c : Int ) : Int { return -1; }
+
+}
+
+@:coreApi @:access(sys.net.Socket)
+class Socket extends sys.net.Socket {
+	
+	public static var DEFAULT_VERIFY_CERT : Null<Bool> = true;
+
+	public static var DEFAULT_CA : Null<Certificate>;
+	
+	private var conf : ConfigPtr;
+	private var ssl : ContextPtr;
+	
+	public var verifyCert : Null<Bool>;
+	private var caCert : Null<Certificate>;
+	private var hostname : String;
+
+	private var ownCert : Null<Certificate>;
+	private var ownKey : Null<Key>;
+	private var altSNIContexts : Null<Array<{match: String->Bool, key: Key, cert: Certificate}>>;
+	private var sniCallback : hl.Bytes -> SNICbResult;
+	private var handshakeDone : Bool;
+
+	private override function init() : Void {
+		__s = sys.net.Socket.socket_new( false );
+		input = new SocketInput( this );
+		output = new SocketOutput( this );
+		if( DEFAULT_VERIFY_CERT && DEFAULT_CA == null ){
+			try {
+				DEFAULT_CA = Certificate.loadDefaults();
+			}catch( e : Dynamic ){}
+		}
+		verifyCert = DEFAULT_VERIFY_CERT;
+		caCert = DEFAULT_CA;
+	}
+
+	public override function connect(host : sys.net.Host, port : Int) : Void {
+		conf = buildConfig( false );
+		ssl = ssl_new( conf );
+		ssl_set_socket( ssl, __s );
+		handshakeDone = false;
+		if( hostname == null )
+			hostname = host.host;
+		if( hostname != null )
+			ssl_set_hostname( ssl, @:privateAccess hostname.toUtf8() );
+		if( !sys.net.Socket.socket_connect( __s, host.ip, port ) )
+			throw new Sys.SysError("Failed to connect on "+host.toString()+":"+port);
+		handshake();
+	}
+
+	public function handshake() : Void {
+		if( !handshakeDone ){
+			var r = ssl_handshake( ssl );
+			if( r == 0 )
+				handshakeDone = true;
+			else if( r == -1 )
+				throw haxe.io.Error.Blocked;
+			else
+				throw new haxe.io.Eof();
+		}
+	}
+
+	public function setCA( cert : Certificate ) : Void {
+		caCert = cert;
+	}
+
+	public function setHostname( name : String ) : Void {
+		hostname = name;
+	}
+
+	public function setCertificate( cert : Certificate, key : Key ) : Void {
+		ownCert = cert;
+		ownKey = key;
+	}
+
+	public override function close() : Void {
+		if( ssl != null ) ssl_close( ssl );
+		if( conf != null ) conf_close( conf );
+		if( altSNIContexts != null )
+			sniCallback = null;
+		sys.net.Socket.socket_close( __s );
+		var input : SocketInput = cast input;
+		var output : SocketOutput = cast output;
+		@:privateAccess input.__s = output.__s = null;
+		input.close();
+		output.close();
+	}
+
+	public function addSNICertificate( cbServernameMatch : String->Bool, cert : Certificate, key : Key ) : Void {
+		if( altSNIContexts == null )
+			altSNIContexts = [];
+		altSNIContexts.push( {match: cbServernameMatch, cert: cert, key: key} );
+	}
+
+	public override function bind( host : sys.net.Host, port : Int ) : Void {
+		conf = buildConfig( true );
+
+		sys.net.Socket.socket_bind( __s, host.ip, port );
+	}
+
+	public override function accept() : Socket {
+		var c = sys.net.Socket.socket_accept( __s );
+		var cssl = ssl_new( conf );
+		ssl_set_socket( cssl, c );
+
+		var s = Type.createEmptyInstance( sys.ssl.Socket );
+		s.__s = c;
+		s.ssl = cssl;
+		s.input = new SocketInput(s);
+		s.output = new SocketOutput(s);
+		s.handshakeDone = false;
+
+		return s;
+	}
+
+	public function peerCertificate() : sys.ssl.Certificate {
+		var x = ssl_get_peer_certificate( ssl );
+		return x==null ? null : new sys.ssl.Certificate( x );
+	}
+
+	private function buildConfig( server : Bool ) : ConfigPtr {
+		var conf = conf_new( server );
+
+		if( ownCert != null && ownKey != null )
+			conf_set_cert( conf, @:privateAccess ownCert.__x, @:privateAccess ownKey.__k );
+
+		if ( altSNIContexts != null ) {
+			sniCallback = function(servername:hl.Bytes) : SNICbResult {
+				var servername = @:privateAccess String.fromUTF8(servername);
+				for( c in altSNIContexts ){
+					if( c.match(servername) )
+						return new SNICbResult(c.cert, c.key);
+				}
+				if( ownKey != null && ownCert != null )
+					return new SNICbResult(ownCert, ownKey);
+				return null;
+			}
+			conf_set_servername_callback( conf, sniCallback );
+		}
+
+		if ( caCert != null ) 
+			conf_set_ca( conf, caCert == null ? null : @:privateAccess caCert.__x  );
+		conf_set_verify( conf, if( verifyCert ) 1 else if( verifyCert==null ) 2 else 0 );
+		
+		return conf;
+	}
+	
+	
+	@:hlNative("ssl","ssl_new") static function ssl_new( conf : ConfigPtr ) : ContextPtr { return null; }
+	@:hlNative("ssl","ssl_close") static function ssl_close( ssl : ContextPtr ) : Void {}
+	@:hlNative("ssl","ssl_handshake") static function ssl_handshake( ssl : ContextPtr ) : Int { return -1; }
+	@:hlNative("ssl","ssl_set_socket") static function ssl_set_socket( ssl : ContextPtr, socket : SocketHandle ) : Void { }
+	@:hlNative("ssl","ssl_set_hostname") static function ssl_set_hostname( ssl : ContextPtr, name : hl.Bytes ) : Void { }
+	@:hlNative("ssl","ssl_get_peer_certificate") static function ssl_get_peer_certificate( ssl : ContextPtr ) : CertificatePtr { return null; }
+	
+	@:hlNative("ssl","conf_new") static function conf_new( server : Bool ) : ConfigPtr { return null; }
+	@:hlNative("ssl","conf_close") static function conf_close( conf : ConfigPtr ) : Void { }
+	@:hlNative("ssl","conf_set_ca") static function conf_set_ca( conf : ConfigPtr, ca : CertificatePtr ) : Void { }
+	@:hlNative("ssl","conf_set_verify") static function conf_set_verify( conf : ConfigPtr, mode : Int ) : Void { }
+	@:hlNative("ssl","conf_set_cert") static function conf_set_cert( conf : ConfigPtr, cert : CertificatePtr, pkey : KeyPtr ) : Void { }
+	@:hlNative("ssl","conf_set_servername_callback") static function conf_set_servername_callback( conf : ConfigPtr, cb : hl.Bytes -> SNICbResult ) : Void { }
+	
+}

+ 4 - 0
std/hl/types/ArrayBase.hx

@@ -107,6 +107,10 @@ class ArrayBase extends ArrayAccess {
 		return null;
 		return null;
 	}
 	}
 
 
+	function isArrayObj() {
+		return false;
+	}
+
 	public static function allocI32( bytes : BytesAccess<Int>, length : Int ) @:privateAccess {
 	public static function allocI32( bytes : BytesAccess<Int>, length : Int ) @:privateAccess {
 		var a : ArrayBytes.ArrayI32 = untyped $new(ArrayBytes.ArrayI32);
 		var a : ArrayBytes.ArrayI32 = untyped $new(ArrayBytes.ArrayI32);
 		a.length = length;
 		a.length = length;

+ 1 - 1
std/hl/types/ArrayBytes.hx

@@ -281,7 +281,7 @@ class BytesIterator<T> {
 
 
 	// called by compiler when accessing the array outside of its bounds, might trigger resize
 	// called by compiler when accessing the array outside of its bounds, might trigger resize
 	function __expand( index : Int ) {
 	function __expand( index : Int ) {
-		if( index < 0 ) throw "Invalid array access";
+		if( index < 0 ) throw "Invalid array index "+index;
 		var newlen = index + 1;
 		var newlen = index + 1;
 		if( newlen > size ) {
 		if( newlen > size ) {
 			var next = (size * 3) >> 1;
 			var next = (size * 3) >> 1;

+ 5 - 1
std/hl/types/ArrayObj.hx

@@ -47,6 +47,10 @@ class ArrayObj<T> extends ArrayBase {
 		return b.toString();
 		return b.toString();
 	}
 	}
 
 
+	override function isArrayObj() {
+		return true;
+	}
+
 	public function pop() : Null<T> {
 	public function pop() : Null<T> {
 		if( length == 0 )
 		if( length == 0 )
 			return null;
 			return null;
@@ -239,7 +243,7 @@ class ArrayObj<T> extends ArrayBase {
 
 
 	// called by compiler when accessing the array outside of its bounds, might trigger resize
 	// called by compiler when accessing the array outside of its bounds, might trigger resize
 	function __expand( index : Int ) {
 	function __expand( index : Int ) {
-		if( index < 0 ) throw "Invalid array access";
+		if( index < 0 ) throw "Invalid array index " + index;
 		var newlen = index + 1;
 		var newlen = index + 1;
 		var size : Int = array.length;
 		var size : Int = array.length;
 		if( newlen > size ) {
 		if( newlen > size ) {

+ 9 - 1
std/java/_std/sys/io/Process.hx

@@ -92,8 +92,16 @@ class Process {
 		return -1;
 		return -1;
 	}
 	}
 
 
-	public function exitCode() : Int
+	public function exitCode( block : Bool = true ) : Null<Int>
 	{
 	{
+		if( block == false ) {
+			try {
+				return proc.exitValue();
+			} catch( e : Dynamic ) {
+				return null;
+			}
+		}
+		
 		cast(stdout, ProcessInput).bufferContents();
 		cast(stdout, ProcessInput).bufferContents();
 		cast(stderr, ProcessInput).bufferContents();
 		cast(stderr, ProcessInput).bufferContents();
 		try
 		try

+ 1 - 1
std/js/html/AlignSetting.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\VTTCue.webidl line 14:0. Do not edit!
+// This file is generated from mozilla\VTTCue.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 56 - 1
std/js/html/AnchorElement.hx

@@ -20,25 +20,80 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\HTMLAnchorElement.webidl line 18:0. Do not edit!
+// This file is generated from mozilla\HTMLAnchorElement.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `HTMLAnchorElement` interface represents hyperlink elements and provides special properties and methods (beyond those of the regular `HTMLElement` object interface they also have available to them by inheritance) for manipulating the layout and presentation of such elements.
+
+	Documentation [HTMLAnchorElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement>
+**/
 @:native("HTMLAnchorElement")
 @:native("HTMLAnchorElement")
 extern class AnchorElement extends Element
 extern class AnchorElement extends Element
 {
 {
+	
+	/**
+		Is a `DOMString` that reflects the `target` HTML attribute, indicating where to display the linked resource.
+	**/
 	var target : String;
 	var target : String;
+	
+	/**
+		Is a `DOMString` indicating that the linked resource is intended to be downloaded rather than displayed in the browser. The value represent the proposed name of the file. If the name is not a valid filename of the underlying OS, browser will adapt it. The value is a URL with a scheme like `http:`, `file:`, `data:` or even `blob:` (created with `URL.createObjectURL`).
+	**/
 	var download : String;
 	var download : String;
 	var ping : String;
 	var ping : String;
+	
+	/**
+		Is a `DOMString` that reflects the `rel` HTML attribute, specifying the relationship of the target object to the linked object.
+	**/
 	var rel : String;
 	var rel : String;
+	
+	/**
+		Returns a `DOMTokenList` that reflects the `rel` HTML attribute, as a list of tokens.
+	**/
 	var relList(default,null) : DOMTokenList;
 	var relList(default,null) : DOMTokenList;
+	
+	/**
+		Is a `DOMString` that reflects the `hreflang` HTML attribute, indicating the language of the linked resource.
+	**/
 	var hreflang : String;
 	var hreflang : String;
+	
+	/**
+		Is a `DOMString` that reflects the `type` HTML attribute, indicating the MIME type of the linked resource.
+	**/
 	var type : String;
 	var type : String;
+	
+	/**
+		Is a `DOMString` being a synonym for the `Node.textContent` property.
+	**/
 	var text : String;
 	var text : String;
+	
+	/**
+		Is a `DOMString` representing a comma-separated list of coordinates.
+	**/
 	var coords : String;
 	var coords : String;
+	
+	/**
+		Is a `DOMString` representing the character encoding of the linked resource.
+	**/
 	var charset : String;
 	var charset : String;
+	
+	/**
+		Is a `DOMString` representing the anchor name.
+	**/
 	var name : String;
 	var name : String;
+	
+	/**
+		Is a `DOMString` representing that the `rev` HTML attribute, specifying the relationship of the link object to the target object.
+	**/
 	var rev : String;
 	var rev : String;
+	
+	/**
+		Is a `DOMString` representing the shape of the active area.
+	**/
 	var shape : String;
 	var shape : String;
 	var href : String;
 	var href : String;
 	var origin(default,null) : String;
 	var origin(default,null) : String;

+ 72 - 1
std/js/html/Animation.hx

@@ -20,34 +20,105 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\Animation.webidl line 20:0. Do not edit!
+// This file is generated from mozilla\Animation.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `Animation` interface of the Web Animations API represents a single animation player and provides playback controls and a timeline for an animation node or source.
+
+	Documentation [Animation](https://developer.mozilla.org/en-US/docs/Web/API/Animation) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/Animation$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/Animation>
+**/
 @:native("Animation")
 @:native("Animation")
 extern class Animation extends EventTarget
 extern class Animation extends EventTarget
 {
 {
+	
+	/**
+		Gets and sets the `String` used to identify the animation.
+	**/
 	var id : String;
 	var id : String;
+	
+	/**
+		Gets and sets the `AnimationEffectReadOnly` associated with this animation. This will usually be a `KeyframeEffect` object.
+	**/
 	var effect(default,null) : AnimationEffectReadOnly;
 	var effect(default,null) : AnimationEffectReadOnly;
+	
+	/**
+		Gets or sets the `AnimationTimeline` associated with this animation.
+	**/
 	var timeline(default,null) : AnimationTimeline;
 	var timeline(default,null) : AnimationTimeline;
+	
+	/**
+		Gets or sets the scheduled time when an animation's playback should begin.
+	**/
 	var startTime : Float;
 	var startTime : Float;
+	
+	/**
+		The current time value of the animation in milliseconds, whether running or paused. If the animation lacks a `AnimationTimeline`, is inactive or hasn't been played yet, its value is `null`.
+	**/
 	var currentTime : Float;
 	var currentTime : Float;
+	
+	/**
+		Gets or sets the playback rate of the animation.
+	**/
 	var playbackRate : Float;
 	var playbackRate : Float;
+	
+	/**
+		Returns an enumerated value describing the playback state of an animation.
+	**/
 	var playState(default,null) : AnimationPlayState;
 	var playState(default,null) : AnimationPlayState;
+	
+	/**
+		Returns the current ready Promise for this animation.
+	**/
 	var ready(default,null) : Promise<Animation>;
 	var ready(default,null) : Promise<Animation>;
+	
+	/**
+		Returns the current finished Promise for this animation.
+	**/
 	var finished(default,null) : Promise<Animation>;
 	var finished(default,null) : Promise<Animation>;
+	
+	/**
+		Gets and sets the event handler for the `finish` event.
+	**/
 	var onfinish : haxe.Constraints.Function;
 	var onfinish : haxe.Constraints.Function;
+	
+	/**
+		Gets and sets the event handler for the `cancel` event.
+	**/
 	var oncancel : haxe.Constraints.Function;
 	var oncancel : haxe.Constraints.Function;
 	
 	
 	/** @throws DOMError */
 	/** @throws DOMError */
 	function new( ?effect : KeyframeEffectReadOnly, ?timeline : AnimationTimeline ) : Void;
 	function new( ?effect : KeyframeEffectReadOnly, ?timeline : AnimationTimeline ) : Void;
+	
+	/**
+		Clears all `KeyframeEffect` caused by this animation and aborts its playback.
+	**/
 	function cancel() : Void;
 	function cancel() : Void;
 	/** @throws DOMError */
 	/** @throws DOMError */
+	
+	/**
+		Seeks either end of an animation, depending on whether the animation is playing or reversing.
+	**/
 	function finish() : Void;
 	function finish() : Void;
 	/** @throws DOMError */
 	/** @throws DOMError */
+	
+	/**
+		Starts or resumes playing of an animation, or begins the animation again if it previously finished.
+	**/
 	function play() : Void;
 	function play() : Void;
 	/** @throws DOMError */
 	/** @throws DOMError */
+	
+	/**
+		Suspends playing of an animation.
+	**/
 	function pause() : Void;
 	function pause() : Void;
 	/** @throws DOMError */
 	/** @throws DOMError */
+	
+	/**
+		Reverses playback direction, stopping at the start of the animation. If the animation is finished or unplayed, it will play from end to beginning.
+	**/
 	function reverse() : Void;
 	function reverse() : Void;
 }
 }

+ 16 - 1
std/js/html/AnimationEffectReadOnly.hx

@@ -20,14 +20,29 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AnimationEffectReadOnly.webidl line 50:0. Do not edit!
+// This file is generated from mozilla\AnimationEffectReadOnly.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `AnimationEffectReadOnly` interface of the Web Animations API defines current and future animation effects like `KeyframeEffect`, which can be passed to `Animation` objects for playing, and `KeyframeEffectReadOnly` (which is used by CSS Animations and Transitions).
+
+	Documentation [AnimationEffectReadOnly](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffectReadOnly) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffectReadOnly$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffectReadOnly>
+**/
 @:native("AnimationEffectReadOnly")
 @:native("AnimationEffectReadOnly")
 extern class AnimationEffectReadOnly
 extern class AnimationEffectReadOnly
 {
 {
+	
+	/**
+		The `AnimationEffectTimingReadOnly` object associated with the animation containing all the animation's timing values.
+	**/
 	var timing(default,null) : AnimationEffectTimingReadOnly;
 	var timing(default,null) : AnimationEffectTimingReadOnly;
 	
 	
+	
+	/**
+		Returns the calculated timing properties for this Animation Effect.
+	**/
 	function getComputedTiming() : ComputedTimingProperties;
 	function getComputedTiming() : ComputedTimingProperties;
 }
 }

+ 8 - 1
std/js/html/AnimationEffectTiming.hx

@@ -20,10 +20,17 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AnimationEffectTiming.webidl line 16:0. Do not edit!
+// This file is generated from mozilla\AnimationEffectTiming.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `AnimationEffectTiming` interface of the Web Animations API is comprised of timing properties. It is returned by the `timing` attribute of a `KeyframeEffect`.
+
+	Documentation [AnimationEffectTiming](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffectTiming) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffectTiming$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffectTiming>
+**/
 @:native("AnimationEffectTiming")
 @:native("AnimationEffectTiming")
 extern class AnimationEffectTiming extends AnimationEffectTimingReadOnly
 extern class AnimationEffectTiming extends AnimationEffectTimingReadOnly
 {
 {

+ 37 - 0
std/js/html/AnimationEffectTimingProperties.hx

@@ -0,0 +1,37 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+// This file is generated from mozilla\AnimationEffectReadOnly.webidl. Do not edit!
+
+package js.html;
+
+typedef AnimationEffectTimingProperties =
+{
+	@:optional var delay : Float;
+	@:optional var direction : PlaybackDirection;
+	@:optional var duration : haxe.extern.EitherType<Float,String>;
+	@:optional var easing : String;
+	@:optional var endDelay : Float;
+	@:optional var fill : FillMode;
+	@:optional var iterationStart : Float;
+	@:optional var iterations : Float;
+}

+ 40 - 1
std/js/html/AnimationEffectTimingReadOnly.hx

@@ -20,20 +20,59 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AnimationEffectTimingReadOnly.webidl line 16:0. Do not edit!
+// This file is generated from mozilla\AnimationEffectTimingReadOnly.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `AnimationEffectTimingReadOnly` interface of the Web Animations API is comprised of timing properties.
+
+	Documentation [AnimationEffectTimingReadOnly](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffectTimingReadOnly) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffectTimingReadOnly$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffectTimingReadOnly>
+**/
 @:native("AnimationEffectTimingReadOnly")
 @:native("AnimationEffectTimingReadOnly")
 extern class AnimationEffectTimingReadOnly
 extern class AnimationEffectTimingReadOnly
 {
 {
+	
+	/**
+		The number of milliseconds to delay the start of the animation. Defaults to `0`.
+	**/
 	var delay(default,null) : Float;
 	var delay(default,null) : Float;
+	
+	/**
+		The number of milliseconds to delay after the end of an animation. This is primarily of use when sequencing animations based on the end time of another animation. Defaults to `0`.
+	**/
 	var endDelay(default,null) : Float;
 	var endDelay(default,null) : Float;
+	
+	/**
+		Dictates whether the animation's effects should be reflected by the element(s) state prior to playing (`backwards`), retained after the animation has completed playing (`forwards`), or `both`. Defaults to `none`.
+	**/
 	var fill(default,null) : FillMode;
 	var fill(default,null) : FillMode;
+	
+	/**
+		A number representing which repetition the animation begins at and its progress through it.
+	**/
 	var iterationStart(default,null) : Float;
 	var iterationStart(default,null) : Float;
+	
+	/**
+		The number of times the animation should repeat. Defaults to `1`, and can also take a value of infinity to make it repeat infinitely.
+	**/
 	var iterations(default,null) : Float;
 	var iterations(default,null) : Float;
+	
+	/**
+		The number of milliseconds each iteration of the animation takes to complete. Defaults to `0`.
+	**/
 	var duration(default,null) : haxe.extern.EitherType<Float,String>;
 	var duration(default,null) : haxe.extern.EitherType<Float,String>;
+	
+	/**
+		Whether the animation runs forwards (`normal`), backwards (`reverse`), switches direction after each iteration (`alternate`), or runs backwards and switches direction after each iteration (`alternate-reverse`). Defaults to `normal`.
+	**/
 	var direction(default,null) : PlaybackDirection;
 	var direction(default,null) : PlaybackDirection;
+	
+	/**
+		The rate of the animation's change over time. Accepts the pre-defined values `linear`, `ease`, `ease-in`, `ease-out`, and `ease-in-out`, or a custom cubic-bezier value like `cubic-bezier(0.42, 0, 0.58, 1)`. Defaults to `linear`.
+	**/
 	var easing(default,null) : String;
 	var easing(default,null) : String;
 	
 	
 }
 }

+ 20 - 1
std/js/html/AnimationEvent.hx

@@ -20,15 +20,34 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AnimationEvent.webidl line 17:0. Do not edit!
+// This file is generated from mozilla\AnimationEvent.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `AnimationEvent` interface represents events providing information related to animations.
+
+	Documentation [AnimationEvent](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent>
+**/
 @:native("AnimationEvent")
 @:native("AnimationEvent")
 extern class AnimationEvent extends Event
 extern class AnimationEvent extends Event
 {
 {
+	
+	/**
+		Is a `DOMString` containing the value of the `animation-name` CSS property associated with the transition.
+	**/
 	var animationName(default,null) : String;
 	var animationName(default,null) : String;
+	
+	/**
+		Is a `float` giving the amount of time the animation has been running, in seconds, when this event fired, excluding any time the animation was paused. For an `"animationstart"` event, `elapsedTime` is `0.0` unless there was a negative value for `animation-delay`, in which case the event will be fired with `elapsedTime` containing  `(-1 * `delay`)`.
+	**/
 	var elapsedTime(default,null) : Float;
 	var elapsedTime(default,null) : Float;
+	
+	/**
+		Is a `DOMString`, starting with `'::'`, containing the name of the pseudo-element the animation runs on. If the animation doesn't run on a pseudo-element but on the element, an empty string: `''``.`
+	**/
 	var pseudoElement(default,null) : String;
 	var pseudoElement(default,null) : String;
 	
 	
 	/** @throws DOMError */
 	/** @throws DOMError */

+ 1 - 1
std/js/html/AnimationEventInit.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AnimationEvent.webidl line 23:0. Do not edit!
+// This file is generated from mozilla\AnimationEvent.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 1 - 1
std/js/html/AnimationPlayState.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\Animation.webidl line 15:0. Do not edit!
+// This file is generated from mozilla\Animation.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 12 - 1
std/js/html/AnimationTimeline.hx

@@ -20,13 +20,24 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AnimationTimeline.webidl line 16:0. Do not edit!
+// This file is generated from mozilla\AnimationTimeline.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `AnimationTimeline` interface of the Web Animations API represents the timeline of an animation. This interface exists to define timeline features (inherited by `DocumentTimeline` and future timeline types) and is not itself directly used by developers. Anywhere you see `AnimationTimeline`, you should use `DocumentTimeline` or any other timeline type instead.
+
+	Documentation [AnimationTimeline](https://developer.mozilla.org/en-US/docs/Web/API/AnimationTimeline) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/AnimationTimeline$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/AnimationTimeline>
+**/
 @:native("AnimationTimeline")
 @:native("AnimationTimeline")
 extern class AnimationTimeline
 extern class AnimationTimeline
 {
 {
+	
+	/**
+		Returns the time value in milliseconds for this timeline or `null` if this timeline is inactive.
+	**/
 	var currentTime(default,null) : Float;
 	var currentTime(default,null) : Float;
 	
 	
 }
 }

+ 1 - 1
std/js/html/AppletElement.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\HTMLAppletElement.webidl line 19:0. Do not edit!
+// This file is generated from mozilla\HTMLAppletElement.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 1 - 1
std/js/html/ApplicationCache.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\OfflineResourceList.webidl line 6:0. Do not edit!
+// This file is generated from mozilla\OfflineResourceList.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 40 - 1
std/js/html/AreaElement.hx

@@ -20,21 +20,60 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\HTMLAreaElement.webidl line 19:0. Do not edit!
+// This file is generated from mozilla\HTMLAreaElement.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `HTMLAreaElement` interface provides special properties and methods (beyond those of the regular object `HTMLElement` interface it also has available to it by inheritance) for manipulating the layout and presentation of area elements.
+
+	Documentation [HTMLAreaElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAreaElement) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAreaElement$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/HTMLAreaElement>
+**/
 @:native("HTMLAreaElement")
 @:native("HTMLAreaElement")
 extern class AreaElement extends Element
 extern class AreaElement extends Element
 {
 {
+	
+	/**
+		Is a `DOMString` that reflects the `alt` HTML attribute, containing alternative text for the element.
+	**/
 	var alt : String;
 	var alt : String;
+	
+	/**
+		Is a `DOMString` that reflects the `coords` HTML attribute, containing coordinates to define the hot-spot region.
+	**/
 	var coords : String;
 	var coords : String;
+	
+	/**
+		Is a `DOMString` that reflects the `shape` HTML attribute, indicating the shape of the hot-spot, limited to known values.
+	**/
 	var shape : String;
 	var shape : String;
+	
+	/**
+		Is a `DOMString` that reflects the `target` HTML attribute, indicating the browsing context in which to open the linked resource.
+	**/
 	var target : String;
 	var target : String;
+	
+	/**
+		Is a `DOMString` indicating that the linked resource is intended to be downloaded rather than displayed in the browser. The value represent the proposed name of the file. If the name is not a valid filename of the underlying OS, browser will adapt it.
+	**/
 	var download : String;
 	var download : String;
 	var ping : String;
 	var ping : String;
+	
+	/**
+		Is a `DOMString` that reflects the `rel` HTML attribute, indicating relationships of the current document to the linked resource.
+	**/
 	var rel : String;
 	var rel : String;
+	
+	/**
+		Returns a `DOMTokenList` that reflects the `rel` HTML attribute, indicating relationships of the current document to the linked resource, as a list of tokens.
+	**/
 	var relList(default,null) : DOMTokenList;
 	var relList(default,null) : DOMTokenList;
+	
+	/**
+		Is a `Boolean` flag indicating if the area is inactive (`true`) or active (`false`).
+	**/
 	var noHref : Bool;
 	var noHref : Bool;
 	var href : String;
 	var href : String;
 	var origin(default,null) : String;
 	var origin(default,null) : String;

+ 1 - 1
std/js/html/ArrayBuffer.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from typedarray.webidl line 13:0. Do not edit!
+// This file is generated from typedarray.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 8 - 1
std/js/html/ArrayBufferView.hx

@@ -20,10 +20,17 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from typedarray.webidl line 24:0. Do not edit!
+// This file is generated from typedarray.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	`ArrayBufferView` is a helper type representing any of the following JavaScript `TypedArray` types:
+
+	Documentation [ArrayBufferView](https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView>
+**/
 @:native("ArrayBufferView")
 @:native("ArrayBufferView")
 extern class ArrayBufferView
 extern class ArrayBufferView
 {
 {

+ 8 - 1
std/js/html/Attr.hx

@@ -20,10 +20,17 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\Attr.webidl line 15:0. Do not edit!
+// This file is generated from mozilla\Attr.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	This type represents a DOM element's attribute as an object. In most DOM methods, you will probably directly retrieve the attribute as a string (e.g., `Element.getAttribute()`, but certain functions (e.g., `Element.getAttributeNode()`) or means of iterating give `Attr` types.
+
+	Documentation [Attr](https://developer.mozilla.org/en-US/docs/Web/API/Attr) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/Attr$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/Attr>
+**/
 @:native("Attr")
 @:native("Attr")
 extern class Attr extends Node
 extern class Attr extends Node
 {
 {

+ 1 - 1
std/js/html/Audio.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from namedConstructors.webidl line 2:0. Do not edit!
+// This file is generated from namedConstructors.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 1 - 1
std/js/html/AudioChannel.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AudioChannel.webidl line 77:0. Do not edit!
+// This file is generated from mozilla\AudioChannel.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 1 - 1
std/js/html/AudioContextState.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AudioContext.webidl line 18:0. Do not edit!
+// This file is generated from mozilla\AudioContext.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 8 - 1
std/js/html/AudioElement.hx

@@ -20,10 +20,17 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\HTMLAudioElement.webidl line 17:0. Do not edit!
+// This file is generated from mozilla\HTMLAudioElement.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `HTMLAudioElement` interface provides access to the properties of `audio` elements, as well as methods to manipulate them. It derives from the `HTMLMediaElement` interface.
+
+	Documentation [HTMLAudioElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement>
+**/
 @:native("HTMLAudioElement")
 @:native("HTMLAudioElement")
 extern class AudioElement extends MediaElement
 extern class AudioElement extends MediaElement
 {
 {

+ 1 - 1
std/js/html/AudioStreamTrack.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AudioStreamTrack.webidl line 17:0. Do not edit!
+// This file is generated from mozilla\AudioStreamTrack.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 1 - 1
std/js/html/AudioTrack.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AudioTrack.webidl line 13:0. Do not edit!
+// This file is generated from mozilla\AudioTrack.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 1 - 1
std/js/html/AudioTrackList.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\AudioTrackList.webidl line 13:0. Do not edit!
+// This file is generated from mozilla\AudioTrackList.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 12 - 1
std/js/html/BRElement.hx

@@ -20,13 +20,24 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\HTMLBRElement.webidl line 19:0. Do not edit!
+// This file is generated from mozilla\HTMLBRElement.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `HTMLBRElement` interface represents a HTML line break element (`br`). It inherits from `HTMLElement`.
+
+	Documentation [HTMLBRElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLBRElement) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/HTMLBRElement$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/HTMLBRElement>
+**/
 @:native("HTMLBRElement")
 @:native("HTMLBRElement")
 extern class BRElement extends Element
 extern class BRElement extends Element
 {
 {
+	
+	/**
+		Is a `DOMString` indicating the flow of text around floating objects.
+	**/
 	var clear : String;
 	var clear : String;
 	
 	
 }
 }

+ 1 - 1
std/js/html/BarProp.hx

@@ -20,7 +20,7 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\BarProp.webidl line 9:0. Do not edit!
+// This file is generated from mozilla\BarProp.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 

+ 16 - 1
std/js/html/BaseElement.hx

@@ -20,14 +20,29 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\HTMLBaseElement.webidl line 18:0. Do not edit!
+// This file is generated from mozilla\HTMLBaseElement.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `HTMLBaseElement` interface contains the base URI for a document. This object inherits all of the properties and methods as described in the `HTMLElement` interface.
+
+	Documentation [HTMLBaseElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLBaseElement) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/HTMLBaseElement$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/HTMLBaseElement>
+**/
 @:native("HTMLBaseElement")
 @:native("HTMLBaseElement")
 extern class BaseElement extends Element
 extern class BaseElement extends Element
 {
 {
+	
+	/**
+		Is a `DOMString` that reflects the `href` HTML attribute, containing a base URL for relative URLs in the document.
+	**/
 	var href : String;
 	var href : String;
+	
+	/**
+		Is a `DOMString` that reflects the `target` HTML attribute, containing a default target browsing context or frame for elements that do not have a target reference specified.
+	**/
 	var target : String;
 	var target : String;
 	
 	
 }
 }

+ 40 - 1
std/js/html/BatteryManager.hx

@@ -20,20 +20,59 @@
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
 
 
-// This file is generated from mozilla\BatteryManager.webidl line 15:0. Do not edit!
+// This file is generated from mozilla\BatteryManager.webidl. Do not edit!
 
 
 package js.html;
 package js.html;
 
 
+/**
+	The `BatteryManager` interface provides ways to get information about the system's battery charge level.
+
+	Documentation [BatteryManager](https://developer.mozilla.org/en-US/docs/Web/API/BatteryManager) by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/BatteryManager$history), licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
+
+	@see <https://developer.mozilla.org/en-US/docs/Web/API/BatteryManager>
+**/
 @:native("BatteryManager")
 @:native("BatteryManager")
 extern class BatteryManager extends EventTarget
 extern class BatteryManager extends EventTarget
 {
 {
+	
+	/**
+		A Boolean value indicating whether or not the battery is currently being charged.
+	**/
 	var charging(default,null) : Bool;
 	var charging(default,null) : Bool;
+	
+	/**
+		A number representing the remaining time in seconds until the battery is fully charged, or 0 if the battery is already fully charged.
+	**/
 	var chargingTime(default,null) : Float;
 	var chargingTime(default,null) : Float;
+	
+	/**
+		A number representing the remaining time in seconds until the battery is completely discharged and the system will suspend.
+	**/
 	var dischargingTime(default,null) : Float;
 	var dischargingTime(default,null) : Float;
+	
+	/**
+		A number representing the system's battery charge level scaled to a value between 0.0 and 1.0.
+	**/
 	var level(default,null) : Float;
 	var level(default,null) : Float;
+	
+	/**
+		A handler for the `chargingchange` event; This event is sent when the battery charging state is updated.
+	**/
 	var onchargingchange : haxe.Constraints.Function;
 	var onchargingchange : haxe.Constraints.Function;
+	
+	/**
+		A handler for the `chargingtimechange` event; This event is sent when the battery charging time is updated
+	**/
 	var onchargingtimechange : haxe.Constraints.Function;
 	var onchargingtimechange : haxe.Constraints.Function;
+	
+	/**
+		A handler for the `dischargingtimechange` event; This event is sent when the battery discharging time is updated.
+	**/
 	var ondischargingtimechange : haxe.Constraints.Function;
 	var ondischargingtimechange : haxe.Constraints.Function;
+	
+	/**
+		A handler for the `levelchange` event; This event is sent when the battery level is updated.
+	**/
 	var onlevelchange : haxe.Constraints.Function;
 	var onlevelchange : haxe.Constraints.Function;
 	
 	
 }
 }

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