Pārlūkot izejas kodu

Merge branch 'development' into feature/asys

Aleksandr Kuzmenko 5 gadi atpakaļ
vecāks
revīzija
8c0de2aaa2
100 mainītis faili ar 1817 papildinājumiem un 2250 dzēšanām
  1. 19 1
      Makefile
  2. 3 7
      Makefile.win
  3. 10 15
      README.md
  4. 18 5
      azure-pipelines.yml
  5. 63 0
      extra/CHANGES.txt
  6. 190 0
      extra/FileAssociation.nsh
  7. 132 0
      extra/WinSetup.hx
  8. 2 1
      extra/azure-pipelines/build-linux.yml
  9. 2 1
      extra/azure-pipelines/build-mac.yml
  10. 2 1
      extra/azure-pipelines/build-windows.yml
  11. 1 1
      extra/azure-pipelines/test-windows.yml
  12. 0 16
      extra/build-haxesetup.xml
  13. 1 1
      extra/haxelib_src
  14. 7 3
      extra/installer.nsi
  15. 1 0
      extra/release-checklist.txt
  16. 0 71
      extra/setup.cpp
  17. 0 21
      extra/setup.sln
  18. 0 120
      extra/setup.vcproj
  19. 1 0
      libs/ilib/dune
  20. 2 1
      libs/ttflib/dune
  21. 2 0
      plugins/.gitignore
  22. 1 0
      plugins/example/.gitignore
  23. 24 0
      plugins/example/README.md
  24. 7 0
      plugins/example/dune
  25. 12 0
      plugins/example/haxelib.json
  26. 32 0
      plugins/example/hx/Example.macro.hx
  27. 70 0
      plugins/example/ml/example.ml
  28. 16 6
      src-json/define.json
  29. 7 1
      src-json/meta.json
  30. 0 2
      src/codegen/codegen.ml
  31. 18 2
      src/codegen/gencommon/castDetect.ml
  32. 10 3
      src/codegen/gencommon/reflectionCFs.ml
  33. 9 11
      src/compiler/haxe.ml
  34. 1 29
      src/compiler/server.ml
  35. 0 10
      src/context/common.ml
  36. 0 11
      src/context/compilationServer.ml
  37. 21 2
      src/context/display/diagnostics.ml
  38. 0 2
      src/context/display/displayJson.ml
  39. 163 0
      src/context/display/displayTexpr.ml
  40. 7 7
      src/context/display/importHandling.ml
  41. 2 5
      src/context/typecore.ml
  42. 8 8
      src/core/abstract.ml
  43. 4 2
      src/core/globals.ml
  44. 14 11
      src/core/numeric.ml
  45. 1 0
      src/core/tFunctions.ml
  46. 1 0
      src/core/tPrinting.ml
  47. 1 0
      src/core/tType.ml
  48. 11 3
      src/dune
  49. 8 39
      src/filters/filters.ml
  50. 10 0
      src/filters/filtersCommon.ml
  51. 222 0
      src/filters/tre.ml
  52. 0 1322
      src/generators/genas3.ml
  53. 8 9
      src/generators/genjs.ml
  54. 12 10
      src/generators/genjvm.ml
  55. 5 2
      src/generators/genlua.ml
  56. 89 25
      src/generators/genphp7.ml
  57. 58 62
      src/generators/genpy.ml
  58. 3 0
      src/generators/jvm/jvmSignature.ml
  59. 12 6
      src/macro/eval/evalContext.ml
  60. 34 12
      src/macro/eval/evalDebugSocket.ml
  61. 5 11
      src/macro/eval/evalEmitter.ml
  62. 2 5
      src/macro/eval/evalJit.ml
  63. 2 2
      src/macro/eval/evalMain.ml
  64. 5 6
      src/macro/eval/evalPrinting.ml
  65. 2 2
      src/macro/eval/evalPrototype.ml
  66. 11 11
      src/macro/eval/evalStdLib.ml
  67. 4 0
      src/macro/eval/evalString.ml
  68. 35 10
      src/macro/eval/evalThread.ml
  69. 12 12
      src/macro/eval/evalValue.ml
  70. 3 3
      src/optimization/analyzer.ml
  71. 1 1
      src/optimization/analyzerConfig.ml
  72. 3 3
      src/optimization/analyzerTexprTransformer.ml
  73. 13 7
      src/optimization/dce.ml
  74. 15 6
      src/optimization/inline.ml
  75. 1 0
      src/syntax/grammar.mly
  76. 1 1
      src/syntax/parserEntry.ml
  77. 6 6
      src/typing/calls.ml
  78. 4 5
      src/typing/fields.ml
  79. 33 4
      src/typing/forLoop.ml
  80. 96 59
      src/typing/nullSafety.ml
  81. 2 2
      src/typing/typeload.ml
  82. 1 1
      src/typing/typeloadCheck.ml
  83. 42 5
      src/typing/typeloadFields.ml
  84. 57 53
      src/typing/typeloadModule.ml
  85. 42 0
      src/typing/typer.ml
  86. 3 1
      std/Array.hx
  87. 1 1
      std/DateTools.hx
  88. 1 1
      std/Math.hx
  89. 0 6
      std/Reflect.hx
  90. 0 4
      std/Type.hx
  91. 4 2
      std/cs/Boot.hx
  92. 2 20
      std/cs/_std/Array.hx
  93. 38 53
      std/cs/_std/Std.hx
  94. 1 1
      std/cs/_std/Type.hx
  95. 3 14
      std/flash/Boot.hx
  96. 1 2
      std/flash/NativeXml.hx
  97. 0 15
      std/flash/_std/Reflect.hx
  98. 7 16
      std/flash/_std/Type.hx
  99. 1 0
      std/flash/_std/haxe/Http.hx
  100. 0 32
      std/flash/_std/haxe/Resource.hx

+ 19 - 1
Makefile

@@ -29,6 +29,19 @@ EXTENSION=
 LFLAGS=
 LFLAGS=
 STATICLINK?=0
 STATICLINK?=0
 
 
+SYSTEM_NAME=Unknown
+ifeq ($(OS),Windows_NT)
+	SYSTEM_NAME=Windows
+else
+	UNAME_S := $(shell uname -s)
+	ifeq ($(UNAME_S),Linux)
+		SYSTEM_NAME=Linux
+	endif
+	ifeq ($(UNAME_S),Darwin)
+		SYSTEM_NAME=Mac
+	endif
+endif
+
 # Configuration
 # Configuration
 
 
 ADD_REVISION?=0
 ADD_REVISION?=0
@@ -61,6 +74,11 @@ haxe:
 	$(DUNE_COMMAND) build --workspace dune-workspace.dev src/haxe.exe
 	$(DUNE_COMMAND) build --workspace dune-workspace.dev src/haxe.exe
 	cp -f _build/default/src/haxe.exe ./${HAXE_OUTPUT}
 	cp -f _build/default/src/haxe.exe ./${HAXE_OUTPUT}
 
 
+plugin: haxe
+	$(DUNE_COMMAND) build --workspace dune-workspace.dev plugins/$(PLUGIN)/$(PLUGIN).cmxs
+	mkdir -p plugins/$(PLUGIN)/cmxs/$(SYSTEM_NAME)
+	cp -f _build/default/plugins/$(PLUGIN)/$(PLUGIN).cmxs plugins/$(PLUGIN)/cmxs/$(SYSTEM_NAME)/plugin.cmxs
+
 kill_exe_win:
 kill_exe_win:
 ifdef SYSTEMROOT
 ifdef SYSTEMROOT
 	-@taskkill /F /IM haxe.exe 2>/dev/null
 	-@taskkill /F /IM haxe.exe 2>/dev/null
@@ -143,7 +161,7 @@ $(INSTALLER_TMP_DIR):
 	mkdir -p $(INSTALLER_TMP_DIR)
 	mkdir -p $(INSTALLER_TMP_DIR)
 
 
 $(INSTALLER_TMP_DIR)/neko-osx64.tar.gz: $(INSTALLER_TMP_DIR)
 $(INSTALLER_TMP_DIR)/neko-osx64.tar.gz: $(INSTALLER_TMP_DIR)
-	wget -nv http://nekovm.org/media/neko-2.1.0-osx64.tar.gz -O installer/neko-osx64.tar.gz
+	wget -nv https://github.com/HaxeFoundation/neko/releases/download/v2-3-0/neko-2.3.0-osx64.tar.gz -O installer/neko-osx64.tar.gz
 
 
 # Installer
 # Installer
 
 

+ 3 - 7
Makefile.win

@@ -72,7 +72,7 @@ package_choco:
 	rm -rf out/choco
 	rm -rf out/choco
 
 
 $(INSTALLER_TMP_DIR)/neko-win.zip: $(INSTALLER_TMP_DIR)
 $(INSTALLER_TMP_DIR)/neko-win.zip: $(INSTALLER_TMP_DIR)
-	wget -nv https://nekovm.org/media/neko-2.2.0-win$(NEKO_ARCH_STR).zip -O installer/neko-win.zip
+	wget -nv https://github.com/HaxeFoundation/neko/releases/download/v2-3-0/neko-2.3.0-win$(NEKO_ARCH_STR).zip -O installer/neko-win.zip
 
 
 package_installer_win: $(INSTALLER_TMP_DIR)/neko-win.zip package_win
 package_installer_win: $(INSTALLER_TMP_DIR)/neko-win.zip package_win
 	$(eval OUTFILE := $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_installer.zip)
 	$(eval OUTFILE := $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_installer.zip)
@@ -85,12 +85,8 @@ package_installer_win: $(INSTALLER_TMP_DIR)/neko-win.zip package_win
 	# haxe
 	# haxe
 	7z x -y $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_bin.zip -o$(INSTALLER_TMP_DIR)/resources
 	7z x -y $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_bin.zip -o$(INSTALLER_TMP_DIR)/resources
 	mv $(INSTALLER_TMP_DIR)/resources/haxe* $(INSTALLER_TMP_DIR)/resources/haxe
 	mv $(INSTALLER_TMP_DIR)/resources/haxe* $(INSTALLER_TMP_DIR)/resources/haxe
-	# haxesetup.exe
-	cd extra && \
-	$(CURDIR)/$(HAXELIB_OUTPUT) newrepo && \
-	$(CURDIR)/$(HAXELIB_OUTPUT) install hxcpp --quiet && \
-	$(CURDIR)/$(HAXELIB_OUTPUT) run hxcpp build-haxesetup.xml
-	cp extra/haxesetup.exe $(INSTALLER_TMP_DIR)/resources/haxe
+	# WinSetup.hx
+	cp extra/WinSetup.hx $(INSTALLER_TMP_DIR)/resources/haxe
 	# extra
 	# extra
 	cp extra/*.nsi $(INSTALLER_TMP_DIR)
 	cp extra/*.nsi $(INSTALLER_TMP_DIR)
 	cp extra/*.nsh $(INSTALLER_TMP_DIR)
 	cp extra/*.nsh $(INSTALLER_TMP_DIR)

+ 10 - 15
README.md

@@ -23,13 +23,13 @@ Haxe allows you to compile for the following targets:
  * C++
  * C++
  * C#
  * C#
  * Java
  * Java
+ * JVM
  * Lua
  * Lua
- * PHP
+ * PHP 7
  * Python 3
  * Python 3
  * [HashLink](https://hashlink.haxe.org/)
  * [HashLink](https://hashlink.haxe.org/)
  * [NekoVM](https://nekovm.org/)
  * [NekoVM](https://nekovm.org/)
  * Flash (SWF Bytecode)
  * Flash (SWF Bytecode)
- * ActionScript 3
  * And its own [interpreter](https://haxe.org/blog/eval/)
  * And its own [interpreter](https://haxe.org/blog/eval/)
 
 
 You can try Haxe directly from your browser at [try.haxe.org](https://try.haxe.org)!
 You can try Haxe directly from your browser at [try.haxe.org](https://try.haxe.org)!
@@ -88,19 +88,14 @@ You can get help and talk with fellow Haxers from around the world via:
 
 
 ## Version compatibility
 ## Version compatibility
 
 
-Haxe            | Neko  | SWF |  Python   | HL    | PHP   | Lua  |
-----            | ----  | ----   | ----   |  ---- | ----  | ---- |
-2.*             | 1.*   | 8-10   | -      | -     | -     | -    |
-3.0.0           | 2.0.0 |        | -      | -     | 5.1+  | -    |
-3.2.0           |       | 12-14  | 3.2+   | -     |       | -    |
-3.3.0           | 2.1.0 | 21     |        | -     |       | 5.1, 5.2, 5.3, LuaJIT 2.0, 2.1 |
-3.4.0           |       |        |        | 1.1   | 5.4+ and 7.0+ (with `-D php7`)   |      |
-4.0.0-preview.1 |       |        |        | 1.2   | 7.0+  |      |
-4.0.0-preview.3 |       |        |        | 1.3   |       |      |
-4.0.0-preview.4 |       |        |        | 1.6   |       |      |
-4.0.0-preview.5 |       |        |        | 1.8   |       |      |
-4.0.0-rc.1      |       |        |        | 1.9   |       |      |
-4.0.0-rc.3      |       |        |        | 1.10  |       |      |
+Haxe            | Neko  | SWF   | Python | HL   | PHP  | Lua |
+--------------- | ----- | ----- | ------ | ---- | ---- | --- |
+2.*             | 1.*   | 8-10  | -      | -    | -    | -   |
+3.0.0           | 2.0.0 |       | -      | -    | 5.1+ | -   |
+3.2.0           |       | 12-14 | 3.2+   | -    |      | -   |
+3.3.0           | 2.1.0 | 21    |        | -    |      | 5.1, 5.2, 5.3, LuaJIT 2.0, 2.1 |
+3.4.0           |       |       |        | 1.1  | 5.4+ and 7.0+ (with `-D php7`) |     |
+4.0.0           | 2.3.0 |       |        | 1.11 | 7.0+ |     |
 
 
 ## Contributing
 ## Contributing
 
 

+ 18 - 5
azure-pipelines.yml

@@ -5,6 +5,14 @@ variables:
   - name: AZURE_PIPELINES_BRANCH
   - name: AZURE_PIPELINES_BRANCH
     value: $(Build.SourceBranchName)
     value: $(Build.SourceBranchName)
 
 
+trigger:
+  branches:
+    include:
+      - '*'
+  tags:
+    include:
+      - '*'
+
 stages:
 stages:
   - stage: StageTest
   - stage: StageTest
     jobs:
     jobs:
@@ -55,7 +63,7 @@ stages:
             php:
             php:
               TEST: php
               TEST: php
             flash:
             flash:
-              TEST: flash9,as3
+              TEST: flash9
               APT_PACKAGES: libglib2.0 libfreetype6 xvfb
               APT_PACKAGES: libglib2.0 libfreetype6 xvfb
               DISPLAY: ':99.0'
               DISPLAY: ':99.0'
               AUDIODEV: 'null'
               AUDIODEV: 'null'
@@ -63,6 +71,7 @@ stages:
               TEST: python
               TEST: python
             lua:
             lua:
               TEST: lua
               TEST: lua
+              APT_PACKAGES: ncurses-dev
         steps:
         steps:
           - checkout: self
           - checkout: self
             fetchDepth: 20
             fetchDepth: 20
@@ -96,11 +105,15 @@ stages:
             condition: and(succeeded(), variables['APT_PACKAGES'])
             condition: and(succeeded(), variables['APT_PACKAGES'])
             displayName: Install apt packages
             displayName: Install apt packages
           - script: haxe RunCi.hxml
           - script: haxe RunCi.hxml
+            condition: and(succeeded(), not(and(variables['SAUCE'], variables['SAUCE_ACCESS_KEY'])))
             workingDirectory: $(Build.SourcesDirectory)/tests
             workingDirectory: $(Build.SourcesDirectory)/tests
-            env:
-              ${{ if variables['SAUCE_ACCESS_KEY'] }}:
-                SAUCE_ACCESS_KEY: $(SAUCE_ACCESS_KEY)
             displayName: Test
             displayName: Test
+          - script: haxe RunCi.hxml
+            condition: and(succeeded(), variables['SAUCE'], variables['SAUCE_ACCESS_KEY'])
+            workingDirectory: $(Build.SourcesDirectory)/tests
+            env:
+              SAUCE_ACCESS_KEY: $(SAUCE_ACCESS_KEY)
+            displayName: Test (with SauceLabs)
 
 
       - job: TestMac
       - job: TestMac
         dependsOn: BuildMac
         dependsOn: BuildMac
@@ -127,7 +140,7 @@ stages:
             php:
             php:
               TEST: php
               TEST: php
             flash:
             flash:
-              TEST: flash9,as3
+              TEST: flash9
             python:
             python:
               TEST: python
               TEST: python
             lua:
             lua:

+ 63 - 0
extra/CHANGES.txt

@@ -1,3 +1,66 @@
+2019-11-29: 4.0.3
+
+	General improvements:
+
+	hl : profiler API
+
+	Bugfixes:
+
+	all : fixed EnumValue handling in constant propagation with analyzer enabled (#8959)
+	all : fixed compiler crash upon Void items in array declarations (#8972)
+	hl : fixed `sys.thread.Lock` implementation for Hashlink 1.11+ (#8699)
+	js/eval/java/jvm/cs/python/lua : fixed `Std.parseInt()` for hexadecimals with leading whitespaces (#8978)
+	java/cs : fixed `Reflect.callMethod(o, method, args)` for `args` not containing optional arguments (#8975)
+	cs : fixed Json.stringify for @:struct-annotated classes (#8979)
+	cs : fixed bitwise shifts for `cs.types.Int64` (#8978)
+	python : fixed invalid generation of some inlined code blocks (#8971)
+	std : fixed an exception from `haxe.zip.Huffman` on reading a zip (#8875)
+	windows : workaround windows installer being detected as a malware by some anti-virus software (#8951)
+	windows : fix PATH env var modification when running windows installer without admin privileges (#8870)
+	all : fixed null-safety checker for field access on a call to inlined function
+
+2019-11-11: 4.0.2
+
+	General improvements and optimizations:
+
+	php : improved performance of `haxe.io.Bytes.get()` (#8938)
+	php : improved performance of serialization/unserialization of `haxe.io.Bytes` (#8943)
+	php : improved performance of enum-related methods in `Type` class of standard library
+
+	Bugfixes:
+
+	haxelib : Fixed too strict requirements to haxelib.json data for private libs
+	all : fixed `@:using` static extensions on `Null<SomeType>` (#8928)
+	php : fixed static methods with the same name in parent and child classes (#8944)
+
+2019-11-04: 4.0.1
+
+	Bugfixes:
+
+	haxelib : fixed git dependencies in haxelib.json
+	neko : updated windows & osx installer to install Neko 2.3.0 (#8906)
+	jvm : fixed compilation failure caused by a specific usage of `Array<Dynamic>` (#8872)
+	all : fixed compiler crash on loops with `continue` in all branches of the body (#8912)
+	all : fixed erasing typedef in AST on field access to forwarded abstract fields (#8919)
+
+
+2019-10-26: 4.0.0
+
+	General improvements:
+
+	js : updated externs for `Float32Array` and `Float64Array` (#8864)
+	php : added array access to `php.NativeStructArray` (#8893)
+
+	Bugfixes:
+
+	cs : fixed "This expression may be invalid" false warning (#8589)
+	php : fixed iterator fields on maps being removed (#8851)
+	php : fixed `-2147483648` as init value for static vars (#5289)
+	python : fixed modulo by a negative number (#8845)
+	java : fixed backslash escaping on `EReg.replace` (#3430)
+	lua : fixed `EReg.map` for unicode (#8861)
+	hl : fixed sqlite connection on OSX/Linux (#8878)
+
 2019-09-12: 4.0.0-rc.5
 2019-09-12: 4.0.0-rc.5
 
 
 	General improvements and optimizations:
 	General improvements and optimizations:

+ 190 - 0
extra/FileAssociation.nsh

@@ -0,0 +1,190 @@
+/*
+_____________________________________________________________________________
+
+                       File Association
+_____________________________________________________________________________
+
+ Based on code taken from http://nsis.sourceforge.net/File_Association
+
+ Usage in script:
+ 1. !include "FileAssociation.nsh"
+ 2. [Section|Function]
+      ${FileAssociationFunction} "Param1" "Param2" "..." $var
+    [SectionEnd|FunctionEnd]
+
+ FileAssociationFunction=[RegisterExtension|UnRegisterExtension]
+
+_____________________________________________________________________________
+
+ ${RegisterExtension} "[executable]" "[extension]" "[description]"
+
+"[executable]"     ; executable which opens the file format
+                   ;
+"[extension]"      ; extension, which represents the file format to open
+                   ;
+"[description]"    ; description for the extension. This will be display in Windows Explorer.
+                   ;
+
+
+ ${UnRegisterExtension} "[extension]" "[description]"
+
+"[extension]"      ; extension, which represents the file format to open
+                   ;
+"[description]"    ; description for the extension. This will be display in Windows Explorer.
+                   ;
+
+_____________________________________________________________________________
+
+                         Macros
+_____________________________________________________________________________
+
+ Change log window verbosity (default: 3=no script)
+
+ Example:
+ !include "FileAssociation.nsh"
+ !insertmacro RegisterExtension
+ ${FileAssociation_VERBOSE} 4   # all verbosity
+ !insertmacro UnRegisterExtension
+ ${FileAssociation_VERBOSE} 3   # no script
+*/
+
+
+!ifndef FileAssociation_INCLUDED
+!define FileAssociation_INCLUDED
+
+!include Util.nsh
+
+!verbose push
+!verbose 3
+!ifndef _FileAssociation_VERBOSE
+  !define _FileAssociation_VERBOSE 3
+!endif
+!verbose ${_FileAssociation_VERBOSE}
+!define FileAssociation_VERBOSE `!insertmacro FileAssociation_VERBOSE`
+!verbose pop
+
+!macro FileAssociation_VERBOSE _VERBOSE
+  !verbose push
+  !verbose 3
+  !undef _FileAssociation_VERBOSE
+  !define _FileAssociation_VERBOSE ${_VERBOSE}
+  !verbose pop
+!macroend
+
+
+
+!macro RegisterExtensionCall _EXECUTABLE _EXTENSION _DESCRIPTION
+  !verbose push
+  !verbose ${_FileAssociation_VERBOSE}
+  Push `${_DESCRIPTION}`
+  Push `${_EXTENSION}`
+  Push `${_EXECUTABLE}`
+  ${CallArtificialFunction} RegisterExtension_
+  !verbose pop
+!macroend
+
+!macro UnRegisterExtensionCall _EXTENSION _DESCRIPTION
+  !verbose push
+  !verbose ${_FileAssociation_VERBOSE}
+  Push `${_EXTENSION}`
+  Push `${_DESCRIPTION}`
+  ${CallArtificialFunction} UnRegisterExtension_
+  !verbose pop
+!macroend
+
+
+
+!define RegisterExtension `!insertmacro RegisterExtensionCall`
+!define un.RegisterExtension `!insertmacro RegisterExtensionCall`
+
+!macro RegisterExtension
+!macroend
+
+!macro un.RegisterExtension
+!macroend
+
+!macro RegisterExtension_
+  !verbose push
+  !verbose ${_FileAssociation_VERBOSE}
+
+  Exch $R2 ;exe
+  Exch
+  Exch $R1 ;ext
+  Exch
+  Exch 2
+  Exch $R0 ;desc
+  Exch 2
+  Push $0
+  Push $1
+
+  ReadRegStr $1 HKCR $R1 ""  ; read current file association
+  StrCmp "$1" "" NoBackup  ; is it empty
+  StrCmp "$1" "$R0" NoBackup  ; is it our own
+    WriteRegStr HKCR $R1 "backup_val" "$1"  ; backup current value
+NoBackup:
+  WriteRegStr HKCR $R1 "" "$R0"  ; set our file association
+
+  ReadRegStr $0 HKCR $R0 ""
+  StrCmp $0 "" 0 Skip
+    WriteRegStr HKCR "$R0" "" "$R0"
+    WriteRegStr HKCR "$R0\shell" "" "open"
+    WriteRegStr HKCR "$R0\DefaultIcon" "" "$R2,0"
+Skip:
+  WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"'
+  WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0"
+  WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"'
+
+  Pop $1
+  Pop $0
+  Pop $R2
+  Pop $R1
+  Pop $R0
+
+  !verbose pop
+!macroend
+
+
+
+!define UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
+!define un.UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
+
+!macro UnRegisterExtension
+!macroend
+
+!macro un.UnRegisterExtension
+!macroend
+
+!macro UnRegisterExtension_
+  !verbose push
+  !verbose ${_FileAssociation_VERBOSE}
+
+  Exch $R1 ;desc
+  Exch
+  Exch $R0 ;ext
+  Exch
+  Push $0
+  Push $1
+
+  ReadRegStr $1 HKCR $R0 ""
+  StrCmp $1 $R1 0 NoOwn ; only do this if we own it
+  ReadRegStr $1 HKCR $R0 "backup_val"
+  StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key
+  DeleteRegKey HKCR $R0
+  Goto NoOwn
+
+Restore:
+  WriteRegStr HKCR $R0 "" $1
+  DeleteRegValue HKCR $R0 "backup_val"
+  DeleteRegKey HKCR $R1 ;Delete key with association name settings
+
+NoOwn:
+
+  Pop $1
+  Pop $0
+  Pop $R1
+  Pop $R0
+
+  !verbose pop
+!macroend
+
+!endif # !FileAssociation_INCLUDED

+ 132 - 0
extra/WinSetup.hx

@@ -0,0 +1,132 @@
+import sys.io.Process;
+
+using haxe.io.Path;
+using StringTools;
+using sys.FileSystem;
+using WinSetup;
+
+enum abstract RegDataType<T>(String) to String {
+	var REG_EXPAND_SZ:RegDataType<String>;
+	var REG_SZ:RegDataType<String>;
+}
+
+class AccessDenied {
+	public var message:String;
+	public function new(msg:String) message = msg;
+	public function toString() return message;
+}
+
+class WinSetup {
+	static inline var HAXEPATH = 'HAXEPATH';
+	static inline var NEKO_INSTPATH = 'NEKO_INSTPATH';
+
+	static inline var REG_HKLM_ENVIRONMENT = 'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment';
+	static inline var REG_HKCU_ENVIRONMENT = 'HKEY_CURRENT_USER\\Environment';
+
+	static function main() {
+		try {
+			try {
+				run(REG_HKLM_ENVIRONMENT);
+			} catch(e:AccessDenied) {
+				run(REG_HKCU_ENVIRONMENT);
+			}
+		} catch(e:Dynamic) {
+			Sys.stderr().writeString(Std.string(e) + '\n');
+			#if debug
+				Sys.stderr().writeString(haxe.CallStack.toString(haxe.CallStack.exceptionStack()) + '\n');
+			#end
+			Sys.stderr().flush();
+			#if debug
+			Sys.println('Press any key to exit...');
+			Sys.getChar(false);
+			#end
+			Sys.exit(1);
+		}
+	}
+
+	static function envVar(name:String):String {
+		return '%$name%';
+	}
+
+	static function run(regDir:String) {
+		var haxePath = Sys.getCwd().removeTrailingSlashes();
+		var addHaxe = '$haxePath\\haxe.exe'.exists();
+		if(addHaxe) {
+			setRegValue(regDir, HAXEPATH, REG_SZ, haxePath);
+		}
+
+		var nekoPath = Path.join([Path.directory(haxePath), 'neko']).replace('/', '\\');
+		var addNeko = '$nekoPath\\neko.exe'.exists();
+		if(addNeko) {
+			setRegValue(regDir, NEKO_INSTPATH, REG_SZ, nekoPath);
+		}
+
+		if(!addHaxe && !addNeko) {
+			return;
+		}
+
+		var paths = readPath(regDir).split(';');
+		addHaxe = paths.indexOf(HAXEPATH.envVar()) < 0 && addHaxe;
+		if(addHaxe) {
+			paths.push(HAXEPATH.envVar());
+		}
+		addNeko = paths.indexOf(NEKO_INSTPATH.envVar()) < 0 && addNeko;
+		if(addNeko) {
+			paths.push(NEKO_INSTPATH.envVar());
+		}
+		if(addHaxe || addNeko) {
+			setRegValue(regDir, 'path', REG_EXPAND_SZ, paths.join(';'));
+		}
+	}
+
+	static function readPath(regDir:String):String {
+		var p = new Process('reg', ['query', regDir, '/v', 'path']);
+		if(p.exitCode() != 0) {
+			var error = p.stderr.readAll().toString();
+			p.close();
+			throw 'Cannot query reg.exe for PATH:\n$error';
+		}
+		/**
+		 * Sample response:
+		 *
+		 *	HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
+		 *	    path    REG_EXPAND_SZ    %SystemRoot%\system32;%SystemRoot%;%SystemRoo<...>
+		 */
+		var response = p.stdout.readAll().toString();
+		p.close();
+		var lines = response.split('\n');
+		for(line in lines) {
+			line = line.trim();
+			if(line.substr(0, 'path'.length).toLowerCase() == 'path') {
+				var column = 0;
+				var wasSpace = false;
+				for(pos in 0...line.length) {
+					var isSpace = line.isSpace(pos);
+					if(wasSpace && !isSpace) {
+						column++;
+						if(column == 2) {
+							return line.substr(pos);
+						}
+					}
+					wasSpace = isSpace;
+				}
+			}
+		}
+		throw 'Cannot parse a query to reg.exe for PATH value:\n$response';
+	}
+
+	static function setRegValue<T>(regDir:String, name:String, dataType:RegDataType<T>, value:T) {
+		var p = new Process('reg', ['add', regDir, '/v', name, '/t', dataType, '/d', '$value', '/f']);
+		if(p.exitCode() != 0) {
+			var error = p.stderr.readAll().toString();
+			p.close();
+			var msg = 'Cannot set a value for $name via reg.exe:\n$error';
+			if(~/access(.*)denied/i.match(error)) {
+				throw new AccessDenied(msg);
+			} else {
+				throw msg;
+			}
+		}
+		p.close();
+	}
+}

+ 2 - 1
extra/azure-pipelines/build-linux.yml

@@ -8,7 +8,8 @@ jobs:
       vmImage: ${{ parameters.vmImage }}
       vmImage: ${{ parameters.vmImage }}
     variables:
     variables:
       OPAMYES: 1
       OPAMYES: 1
-      ADD_REVISION: 1
+      ${{ if not(startsWith(variables['Build.SourceBranch'], 'refs/tags/')) }}:
+        ADD_REVISION: 1
     steps:
     steps:
       - checkout: self
       - checkout: self
         submodules: recursive
         submodules: recursive

+ 2 - 1
extra/azure-pipelines/build-mac.yml

@@ -8,7 +8,8 @@ jobs:
       vmImage: ${{ parameters.vmImage }}
       vmImage: ${{ parameters.vmImage }}
     variables:
     variables:
       OPAMYES: 1
       OPAMYES: 1
-      ADD_REVISION: 1
+      ${{ if not(startsWith(variables['Build.SourceBranch'], 'refs/tags/')) }}:
+        ADD_REVISION: 1
     steps:
     steps:
       - checkout: self
       - checkout: self
         submodules: recursive
         submodules: recursive

+ 2 - 1
extra/azure-pipelines/build-windows.yml

@@ -9,7 +9,8 @@ jobs:
       vmImage: ${{ parameters.vmImage }}
       vmImage: ${{ parameters.vmImage }}
     variables:
     variables:
       OPAMYES: 1
       OPAMYES: 1
-      ADD_REVISION: 1
+      ${{ if not(startsWith(variables['Build.SourceBranch'], 'refs/tags/')) }}:
+        ADD_REVISION: 1
       CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin/
       CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin/
       ${{ if eq(parameters.arch, '64') }}:
       ${{ if eq(parameters.arch, '64') }}:
         ARCH: 64
         ARCH: 64

+ 1 - 1
extra/azure-pipelines/test-windows.yml

@@ -37,7 +37,7 @@ jobs:
           TEST: php
           TEST: php
         # TODO. flash has never been enabled on our AppVeyor builds.
         # TODO. flash has never been enabled on our AppVeyor builds.
         # flash:
         # flash:
-        #   TEST: flash9,as3
+        #   TEST: flash9
         python:
         python:
           TEST: python
           TEST: python
         # TODO. Lua has never been enabled on our AppVeyor builds.
         # TODO. Lua has never been enabled on our AppVeyor builds.

+ 0 - 16
extra/build-haxesetup.xml

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

+ 1 - 1
extra/haxelib_src

@@ -1 +1 @@
-Subproject commit 0ea7cd696bdc4a2d63c4ea0e1466c3a40dd97de5
+Subproject commit 4b27f91d8a4ff279d9903091680fee2c93a0d574

+ 7 - 3
extra/installer.nsi

@@ -11,6 +11,7 @@
 !include "WordFunc.nsh"
 !include "WordFunc.nsh"
 !include "winmessages.nsh"
 !include "winmessages.nsh"
 !include "EnvVarUpdate.nsh"
 !include "EnvVarUpdate.nsh"
+!include "FileAssociation.nsh"
 
 
 ;--------------------------------
 ;--------------------------------
 
 
@@ -20,12 +21,12 @@
 !define VERLONG "%%VERLONG%%"
 !define VERLONG "%%VERLONG%%"
 
 
 ; Define Neko info
 ; Define Neko info
-!define NEKO_VERSION "2.2.0"
+!define NEKO_VERSION "2.3.0"
 
 
 ; Installer details
 ; Installer details
 VIAddVersionKey "CompanyName" "Haxe Foundation"
 VIAddVersionKey "CompanyName" "Haxe Foundation"
 VIAddVersionKey "ProductName" "Haxe Installer"
 VIAddVersionKey "ProductName" "Haxe Installer"
-VIAddVersionKey "LegalCopyright" "Haxe Foundation 2005-2018"
+VIAddVersionKey "LegalCopyright" "Haxe Foundation 2005-2019"
 VIAddVersionKey "FileDescription" "Haxe Installer"
 VIAddVersionKey "FileDescription" "Haxe Installer"
 VIAddVersionKey "ProductVersion" "${VERSION}.0"
 VIAddVersionKey "ProductVersion" "${VERSION}.0"
 VIAddVersionKey "FileVersion" "${VERSION}.0"
 VIAddVersionKey "FileVersion" "${VERSION}.0"
@@ -127,7 +128,9 @@ Section "Haxe ${VERSION}" Main
 
 
 	File /r /x .svn /x *.db /x Exceptions.log /x .local /x .multi /x *.pdb /x *.vshost.exe /x *.vshost.exe.config /x *.vshost.exe.manifest "resources\haxe\*.*"
 	File /r /x .svn /x *.db /x Exceptions.log /x .local /x .multi /x *.pdb /x *.vshost.exe /x *.vshost.exe.config /x *.vshost.exe.manifest "resources\haxe\*.*"
 
 
-	ExecWait "$INSTDIR\haxe\haxesetup.exe -silent"
+	${registerExtension} "$INSTDIR\haxe\haxe.exe --prompt" ".hxml" "Haxe compiler arguments list"
+	ExecWait '"$INSTDIR\haxe\haxe.exe" --cwd "$INSTDIR\haxe" -x WinSetup.hx'
+	SendMessage ${HWND_BROADCAST} ${WM_SETTINGCHANGE} 0 "STR:Environment" /TIMEOUT=5000
 
 
 	WriteUninstaller "$INSTDIR\Uninstall.exe"
 	WriteUninstaller "$INSTDIR\Uninstall.exe"
 
 
@@ -163,6 +166,7 @@ SectionEnd
 Section "un.Haxe" UninstMain
 Section "un.Haxe" UninstMain
 
 
 	RMDir /r "$INSTDIR\haxe"
 	RMDir /r "$INSTDIR\haxe"
+	${unregisterExtension} ".hxml" "Haxe compiler arguments list"
 	${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "%HAXEPATH%"
 	${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "%HAXEPATH%"
 	DeleteRegValue ${env_hklm} HAXEPATH
 	DeleteRegValue ${env_hklm} HAXEPATH
 	SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
 	SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000

+ 1 - 0
extra/release-checklist.txt

@@ -3,6 +3,7 @@
 - Check that haxelib is working
 - Check that haxelib is working
 - Make sure to update the haxelib submodule
 - Make sure to update the haxelib submodule
 - Check that the run-time haxelibs are ready for release: hxcpp, hxjava, hxcs
 - Check that the run-time haxelibs are ready for release: hxcpp, hxjava, hxcs
+- Check that the osx & windows installers has the latest neko release in "Makefile" and "Makefile.win" files
 
 
 # Making the release
 # Making the release
 
 

+ 0 - 71
extra/setup.cpp

@@ -1,71 +0,0 @@
-/*
-	Haxe Setup
-	Copyright (C) 2005-2016  Haxe Foundation
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-// this is a small program that do basic Haxe setup on Windows
-#include <windows.h>
-
-static void Set( HKEY k, const char *name, DWORD t, const char *data ) {
-	RegSetValueEx(k,name,0,t,(const BYTE*)data,(DWORD)strlen(data)+1);
-}
-
-int WINAPI WinMain( HINSTANCE inst, HINSTANCE prev, LPSTR lpCmdLine, int nCmdShow ) {
-	char path[MAX_PATH];
-	*path = '"';
-	GetModuleFileName(NULL,path+1,MAX_PATH);
-
-	// register .hxml extension
-	char *s = strrchr(path,'\\') + 1;
-	strcpy(s,"haxe.exe\" -prompt \"%1\"");
-	HKEY k;
-	RegCreateKey(HKEY_CLASSES_ROOT,".hxml\\shell\\Compile\\command",&k);
-	RegSetValueEx(k,NULL,0,REG_SZ,(const BYTE*)path,(DWORD)(strlen(path)+1));
-	*s = 0;
-
-	// add %HAXEPATH% to PATH and set HAXEPATH to current path
-	DWORD ktype;
-	DWORD ksize = 16000;
-	char *kdata = new char[16000];
-	memset(kdata,0,ksize);
-	RegOpenKey(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",&k);	
-	RegQueryValueEx(k,"PATH",NULL,&ktype,(LPBYTE)kdata,&ksize);
-	if( strstr(kdata,"%HAXEPATH%") == NULL ) {
-		char *s = kdata + strlen(kdata);
-		strcpy(s,";%HAXEPATH%");
-		Set(k,"PATH",REG_EXPAND_SZ,kdata);		
-	}
-	if( strstr(kdata,"%NEKO_INSTPATH%") == NULL ) {
-		char *s = kdata + strlen(kdata);
-		strcpy(s,";%NEKO_INSTPATH%");
-		Set(k,"PATH",REG_EXPAND_SZ,kdata);
-	}
-	Set(k,"HAXEPATH",REG_SZ,path + 1);	
-	s[-1] = 0;
-	strcpy(strrchr(path,'\\'),"\\neko");
-	Set(k,"NEKO_INSTPATH",REG_SZ,path+1);
-	RegCloseKey(k);
-
-	// inform running apps of env changes (W2K/NT systems only ?)
-	DWORD unused;
-	SendMessageTimeout(HWND_BROADCAST,WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, &unused );
-
-	// delete kdata;
-	// // register 
-	// if( strcmp(lpCmdLine,"-silent") != 0 )
-	// 	MessageBox(NULL,"Setup completed, you can start using Haxe now","haxesetup",MB_OK | MB_ICONINFORMATION);
-	return 0;
-}

+ 0 - 21
extra/setup.sln

@@ -1,21 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "setup", "setup.vcproj", "{6E869222-35FF-4BC0-B5AA-E63BCB8803A6}"
-	ProjectSection(ProjectDependencies) = postProject
-	EndProjectSection
-EndProject
-Global
-	GlobalSection(SolutionConfiguration) = preSolution
-		Debug = Debug
-		Release = Release
-	EndGlobalSection
-	GlobalSection(ProjectConfiguration) = postSolution
-		{6E869222-35FF-4BC0-B5AA-E63BCB8803A6}.Debug.ActiveCfg = Debug|Win32
-		{6E869222-35FF-4BC0-B5AA-E63BCB8803A6}.Debug.Build.0 = Debug|Win32
-		{6E869222-35FF-4BC0-B5AA-E63BCB8803A6}.Release.ActiveCfg = Release|Win32
-		{6E869222-35FF-4BC0-B5AA-E63BCB8803A6}.Release.Build.0 = Release|Win32
-	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-	EndGlobalSection
-	GlobalSection(ExtensibilityAddIns) = postSolution
-	EndGlobalSection
-EndGlobal

+ 0 - 120
extra/setup.vcproj

@@ -1,120 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="7.10"
-	Name="setup"
-	ProjectGUID="{6E869222-35FF-4BC0-B5AA-E63BCB8803A6}"
-	Keyword="Win32Proj">
-	<Platforms>
-		<Platform
-			Name="Win32"/>
-	</Platforms>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="1"
-			CharacterSet="2">
-			<Tool
-				Name="VCCLCompilerTool"
-				Optimization="0"
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
-				MinimalRebuild="TRUE"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="5"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="TRUE"
-				DebugInformationFormat="4"/>
-			<Tool
-				Name="VCCustomBuildTool"/>
-			<Tool
-				Name="VCLinkerTool"
-				OutputFile="$(OutDir)/haxesetup.exe"
-				LinkIncremental="2"
-				GenerateDebugInformation="TRUE"
-				ProgramDatabaseFile="$(OutDir)/setup.pdb"
-				SubSystem="2"
-				TargetMachine="1"/>
-			<Tool
-				Name="VCMIDLTool"/>
-			<Tool
-				Name="VCPostBuildEventTool"/>
-			<Tool
-				Name="VCPreBuildEventTool"/>
-			<Tool
-				Name="VCPreLinkEventTool"/>
-			<Tool
-				Name="VCResourceCompilerTool"/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"/>
-			<Tool
-				Name="VCWebDeploymentTool"/>
-			<Tool
-				Name="VCManagedWrapperGeneratorTool"/>
-			<Tool
-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="Release"
-			IntermediateDirectory="Release"
-			ConfigurationType="1"
-			CharacterSet="2">
-			<Tool
-				Name="VCCLCompilerTool"
-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
-				RuntimeLibrary="2"
-				BufferSecurityCheck="FALSE"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				Detect64BitPortabilityProblems="TRUE"
-				DebugInformationFormat="3"/>
-			<Tool
-				Name="VCCustomBuildTool"/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalDependencies="msvcrt60.lib"
-				OutputFile="$(OutDir)/haxesetup.exe"
-				LinkIncremental="1"
-				IgnoreDefaultLibraryNames="MSVCRT"
-				GenerateDebugInformation="TRUE"
-				SubSystem="2"
-				OptimizeReferences="2"
-				EnableCOMDATFolding="2"
-				TargetMachine="1"/>
-			<Tool
-				Name="VCMIDLTool"/>
-			<Tool
-				Name="VCPostBuildEventTool"/>
-			<Tool
-				Name="VCPreBuildEventTool"/>
-			<Tool
-				Name="VCPreLinkEventTool"/>
-			<Tool
-				Name="VCResourceCompilerTool"/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"/>
-			<Tool
-				Name="VCWebDeploymentTool"/>
-			<Tool
-				Name="VCManagedWrapperGeneratorTool"/>
-			<Tool
-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<File
-			RelativePath=".\setup.cpp">
-		</File>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>

+ 1 - 0
libs/ilib/dune

@@ -3,6 +3,7 @@
 (library
 (library
 	(name ilib)
 	(name ilib)
 	(modules_without_implementation ilData ilMeta)
 	(modules_without_implementation ilData ilMeta)
+	(modules (:standard \ dump))
 	(libraries extlib)
 	(libraries extlib)
 	(wrapped false)
 	(wrapped false)
 )
 )

+ 2 - 1
libs/ttflib/dune

@@ -2,6 +2,7 @@
 
 
 (library
 (library
 	(name ttflib)
 	(name ttflib)
-	(libraries extlib extlib_leftovers swflib)
+	(libraries extlib extlib_leftovers swflib unix)
+	(modules (:standard \ main))
 	(wrapped false)
 	(wrapped false)
 )
 )

+ 2 - 0
plugins/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 1 - 0
plugins/example/.gitignore

@@ -0,0 +1 @@
+.merlin

+ 24 - 0
plugins/example/README.md

@@ -0,0 +1,24 @@
+# How to build a plugin
+
+```
+$ make plugin PLUGIN=example
+```
+This command builds plugin for current OS only.
+
+# How to use your plugins in a Haxe project
+
+Setup your plugin as a haxe library:
+```
+$ haxelib dev example path/to/haxe/plugins/example
+```
+And then access it inside of a macro:
+```haxe
+macro static public function testPlugin() {
+	Example.plugin.hello();
+	return macro {}
+}
+```
+
+# How to start a new plugin
+
+Just make a copy of an "example" plugin directory and replace all occurrences of "example" word with your own plugin name.

+ 7 - 0
plugins/example/dune

@@ -0,0 +1,7 @@
+(data_only_dirs cmxs hx)
+(include_subdirs unqualified)
+
+(library
+	(name example)
+	(libraries haxe)
+)

+ 12 - 0
plugins/example/haxelib.json

@@ -0,0 +1,12 @@
+{
+	"name" : "example",
+	"url" : "http://haxe.org",
+	"license" : "MIT",
+	"description" : "Example Plugin",
+	"version" : "0.1.0",
+	"releasenote" : "Initial release",
+	"classPath": "hx",
+	"contributors" : ["example"],
+	"tags": ["plugin"],
+	"dependencies" : {}
+}

+ 32 - 0
plugins/example/hx/Example.macro.hx

@@ -0,0 +1,32 @@
+import haxe.PosInfos;
+
+using haxe.io.Path;
+
+typedef ExamplePluginApi = {
+	function hello():Void;
+	function stringifyPosition(p:haxe.macro.Expr.Position):String;
+	function hijackStaticTest():Void;
+}
+
+class Example {
+	/** Access plugin API */
+	static public var plugin(get,never):ExamplePluginApi;
+
+	static var _plugin:ExamplePluginApi;
+	static function get_plugin():ExamplePluginApi {
+		if(_plugin == null) {
+			try {
+				_plugin = eval.vm.Context.loadPlugin(getPluginPath());
+			} catch(e:Dynamic) {
+				throw 'Failed to load plugin: $e';
+			}
+		}
+		return _plugin;
+	}
+
+	static function getPluginPath():String {
+		var currentFile = (function(?p:PosInfos) return p.fileName)();
+		var srcDir = currentFile.directory().directory();
+		return Path.join([srcDir, 'cmxs', Sys.systemName(), 'plugin.cmxs']);
+	}
+}

+ 70 - 0
plugins/example/ml/example.ml

@@ -0,0 +1,70 @@
+open EvalValue
+open Type
+
+class plugin =
+	object (self)
+		(**
+			Prints greeting to stdout.
+			Takes no arguments, returns Void.
+		*)
+		method hello () : value =
+			print_endline "Hello from plugin";
+			(*
+				Plugin architecture requires to return something even for methods typed Void on Haxe side.
+				Return `null`
+			*)
+			vnull
+		(**
+			Takes `haxe.macro.Position` and returns a string of that position in the same format used for
+			compiler errors
+		*)
+		method stringify_position (pos:value) : value =
+			let pos = EvalDecode.decode_pos pos in
+			let str = Lexer.get_error_pos (Printf.sprintf "%s:%d:") pos in
+			EvalEncode.encode_string str
+		(**
+			Change all static methods named "test" to throw "Hello from plugin".
+			This is an example how to modify typed syntax tree.
+		*)
+		method hijack_static_test () : value =
+			let compiler = (EvalContext.get_ctx()).curapi in
+			(**
+				Add a callback like `haxe.macro.Context.onAfterTyping`
+			*)
+			compiler.after_typing (fun haxe_types ->
+				List.iter
+					(fun hx_type ->
+						match hx_type with
+							| TClassDecl cls ->
+								List.iter
+									(fun field ->
+										match field.cf_name, field.cf_expr with
+											| "test", Some e ->
+												let hello = {
+													eexpr = TConst (TString "Hello from plugin");
+													etype = (compiler.get_com()).basic.tstring;
+													epos = Globals.null_pos;
+												} in
+												field.cf_expr <- Some { e with eexpr = TThrow hello }
+											| _ -> ()
+									)
+									cls.cl_ordered_statics
+							| _ -> ()
+					)
+					haxe_types
+			);
+			vnull
+	end
+;;
+
+let api = new plugin in
+
+(**
+	Register our plugin API.
+	This code is executed upon `eval.vm.Context.loadPlugin` call.
+*)
+EvalStdLib.StdContext.register [
+	("hello", EvalEncode.vfun0 api#hello);
+	("stringifyPosition", EvalEncode.vfun1 api#stringify_position);
+	("hijackStaticTest", EvalEncode.vfun0 api#hijack_static_test);
+]

+ 16 - 6
src-json/define.json

@@ -10,23 +10,22 @@
 		"doc": "Allow the SWF to be measured with Monocle tool.",
 		"doc": "Allow the SWF to be measured with Monocle tool.",
 		"platforms": ["flash"]
 		"platforms": ["flash"]
 	},
 	},
+	{
+		"name": "AnalyzerOptimize",
+		"define": "analyzer_optimize",
+		"doc": "Perform advanced optimizations."
+	},
 	{
 	{
 		"name": "AnnotateSource",
 		"name": "AnnotateSource",
 		"define": "annotate_source",
 		"define": "annotate_source",
 		"doc": "Add additional comments to generated source code.",
 		"doc": "Add additional comments to generated source code.",
 		"platforms": ["cpp"]
 		"platforms": ["cpp"]
 	},
 	},
-	{
-		"name": "As3",
-		"define": "as3",
-		"doc": "Defined when outputting flash9 as3 source code."
-	},
 	{
 	{
 		"name": "Asys",
 		"name": "Asys",
 		"define": "asys",
 		"define": "asys",
 		"doc": "Defined for all platforms that support the libuv-based asys package."
 		"doc": "Defined for all platforms that support the libuv-based asys package."
 	},
 	},
-	{
 		"name": "CheckXmlProxy",
 		"name": "CheckXmlProxy",
 		"define": "check_xml_proxy",
 		"define": "check_xml_proxy",
 		"doc": "Check the used fields of the XML proxy."
 		"doc": "Check the used fields of the XML proxy."
@@ -168,6 +167,11 @@
 		"doc": "Record per-method execution times in macro/interp mode. Implies eval_stack.",
 		"doc": "Record per-method execution times in macro/interp mode. Implies eval_stack.",
 		"platforms": ["eval"]
 		"platforms": ["eval"]
 	},
 	},
+	{
+		"name": "FilterTimes",
+		"define": "filter_times",
+		"doc": "Record per-filter execution times upon --times."
+	},
 	{
 	{
 		"name": "FastCast",
 		"name": "FastCast",
 		"define": "fast_cast",
 		"define": "fast_cast",
@@ -555,6 +559,12 @@
 		"define": "static",
 		"define": "static",
 		"doc": "Defined if the current target is static."
 		"doc": "Defined if the current target is static."
 	},
 	},
+	{
+		"name": "StdEncodingUtf8",
+		"define": "std-encoding-utf8",
+		"doc": "Force utf8 encoding for stdin, stdout and stderr",
+		"platforms": ["java", "cs", "python"]
+	},
 	{
 	{
 		"name": "Swc",
 		"name": "Swc",
 		"define": "swc",
 		"define": "swc",

+ 7 - 1
src-json/meta.json

@@ -803,7 +803,7 @@
 		"name": "NullSafety",
 		"name": "NullSafety",
 		"metadata": ":nullSafety",
 		"metadata": ":nullSafety",
 		"doc": "Enables null safety for classes or fields. Disables null safety for classes, fields or expressions if provided with `Off` as an argument.",
 		"doc": "Enables null safety for classes or fields. Disables null safety for classes, fields or expressions if provided with `Off` as an argument.",
-		"params": ["Off | Loose | Strict"],
+		"params": ["Off | Loose | Strict | StrictThreaded"],
 		"targets": ["TClass", "TClassField", "TExpr"],
 		"targets": ["TClass", "TClassField", "TExpr"],
 		"links": ["https://haxe.org/manual/cr-null-safety.html"]
 		"links": ["https://haxe.org/manual/cr-null-safety.html"]
 	},
 	},
@@ -1101,6 +1101,12 @@
 		"platforms": ["java"],
 		"platforms": ["java"],
 		"targets": ["TClass"]
 		"targets": ["TClass"]
 	},
 	},
+	{
+		"name": "TailRecursion",
+		"metadata": ":tailRecursion",
+		"doc": "Internally used for tail recursion elimination.",
+		"internal": true
+	},
 	{
 	{
 		"name": "TemplatedCall",
 		"name": "TemplatedCall",
 		"metadata": ":templatedCall",
 		"metadata": ":templatedCall",

+ 0 - 2
src/codegen/codegen.ml

@@ -189,8 +189,6 @@ let fix_override com c f fd =
 						{ e with eexpr = TBlock (el_v @ el) }
 						{ e with eexpr = TBlock (el_v @ el) }
 				);
 				);
 			} in
 			} in
-			(* as3 does not allow wider visibility, so the base method has to be made public *)
-			if Common.defined com Define.As3 && has_class_field_flag f CfPublic then add_class_field_flag f2 CfPublic;
 			let targs = List.map (fun(v,c) -> (v.v_name, Option.is_some c, v.v_type)) nargs in
 			let targs = List.map (fun(v,c) -> (v.v_name, Option.is_some c, v.v_type)) nargs in
 			let fde = (match f.cf_expr with None -> assert false | Some e -> e) in
 			let fde = (match f.cf_expr with None -> assert false | Some e -> e) in
 			f.cf_expr <- Some { fde with eexpr = TFunction fd2 };
 			f.cf_expr <- Some { fde with eexpr = TFunction fd2 };

+ 18 - 2
src/codegen/gencommon/castDetect.ml

@@ -71,6 +71,14 @@ struct
 		let current_ret_type = ref None in
 		let current_ret_type = ref None in
 		let handle e tto tfrom = gen.ghandle_cast (gen.greal_type tto) (gen.greal_type tfrom) e in
 		let handle e tto tfrom = gen.ghandle_cast (gen.greal_type tto) (gen.greal_type tfrom) e in
 		let in_value = ref false in
 		let in_value = ref false in
+		let binop_right_expr_type op actual_type =
+			match op with
+			| OpShr | OpShl | OpUShr | OpAssignOp (OpShr | OpShl | OpUShr) ->
+				(match follow actual_type with
+				| TAbstract ({ a_path = (["cs"], "Int64") }, _) -> gen.gcon.basic.tint
+				| _ -> actual_type)
+			| _ -> actual_type
+		in
 
 
 		let rec run e =
 		let rec run e =
 			let was_in_value = !in_value in
 			let was_in_value = !in_value in
@@ -103,16 +111,19 @@ struct
 				(match field_access_esp gen (gen.greal_type tf.etype) (f) with
 				(match field_access_esp gen (gen.greal_type tf.etype) (f) with
 					| FClassField(cl,params,_,_,is_static,actual_t,_) ->
 					| FClassField(cl,params,_,_,is_static,actual_t,_) ->
 						let actual_t = if is_static then actual_t else apply_params cl.cl_params params actual_t in
 						let actual_t = if is_static then actual_t else apply_params cl.cl_params params actual_t in
+						let actual_t = binop_right_expr_type op actual_t in
 						let e1 = extract_expr (run e1) in
 						let e1 = extract_expr (run e1) in
 						{ e with eexpr = TBinop(op, e1, handle (run e2) actual_t e2.etype); etype = e1.etype }
 						{ e with eexpr = TBinop(op, e1, handle (run e2) actual_t e2.etype); etype = e1.etype }
 					| _ ->
 					| _ ->
 						let e1 = extract_expr (run e1) in
 						let e1 = extract_expr (run e1) in
-						{ e with eexpr = TBinop(op, e1, handle (run e2) e1.etype e2.etype); etype = e1.etype }
+						let actual_t = binop_right_expr_type op e2.etype in
+						{ e with eexpr = TBinop(op, e1, handle (run e2) e1.etype actual_t); etype = e1.etype }
 				)
 				)
 			| TBinop ( (Ast.OpAssign as op),e1,e2)
 			| TBinop ( (Ast.OpAssign as op),e1,e2)
 			| TBinop ( (Ast.OpAssignOp _ as op),e1,e2) ->
 			| TBinop ( (Ast.OpAssignOp _ as op),e1,e2) ->
 				let e1 = extract_expr (run e1) in
 				let e1 = extract_expr (run e1) in
-				{ e with eexpr = TBinop(op, e1, handle (run e2) e1.etype e2.etype); etype = e1.etype }
+				let actual_t = binop_right_expr_type op e2.etype in
+				{ e with eexpr = TBinop(op, e1, handle (run e2) e1.etype actual_t); etype = e1.etype }
 			| _ -> Type.map_expr run e
 			| _ -> Type.map_expr run e
 		in
 		in
 		run
 		run
@@ -1046,6 +1057,11 @@ let configure gen ?(overloads_cast_to_base = false) maybe_empty_t calls_paramete
 			| TCast( { eexpr = TCall( { eexpr = TIdent "__delegate__" } as local, [del] ) } as e2, _) ->
 			| TCast( { eexpr = TCall( { eexpr = TIdent "__delegate__" } as local, [del] ) } as e2, _) ->
 				{ e with eexpr = TCast({ e2 with eexpr = TCall(local, [Type.map_expr run del]) }, None) }
 				{ e with eexpr = TCast({ e2 with eexpr = TCall(local, [Type.map_expr run del]) }, None) }
 
 
+			| TBinop (OpAssignOp (Ast.OpShl | Ast.OpShr | Ast.OpUShr as op), e1, e2 ) ->
+				let e1 = run ~just_type:true e1 in
+				let e2 = handle (run e2) (gen.gcon.basic.tint) e2.etype in
+				let rett = binop_type op e e1 e2 in
+				{ e with eexpr = TBinop(OpAssignOp op, e1, e2); etype = rett.etype }
 			| TBinop ( (Ast.OpAssign | Ast.OpAssignOp _ as op), e1, e2 ) ->
 			| TBinop ( (Ast.OpAssign | Ast.OpAssignOp _ as op), e1, e2 ) ->
 				let e1 = run ~just_type:true e1 in
 				let e1 = run ~just_type:true e1 in
 				let e2 = handle (run e2) e1.etype e2.etype in
 				let e2 = handle (run e2) e1.etype e2.etype in

+ 10 - 3
src/codegen/gencommon/reflectionCFs.ml

@@ -1169,6 +1169,8 @@ let implement_invokeField ctx slow_invoke cl =
 			has_method := true;
 			has_method := true;
 			let i = ref 0 in
 			let i = ref 0 in
 			let dyn_arg_local = mk_local dynamic_arg pos in
 			let dyn_arg_local = mk_local dynamic_arg pos in
+			let length_name = match ctx.rcf_gen.gcon.platform with Cs -> "Length" | _ -> "length" in
+			let dyn_arg_length = field dyn_arg_local length_name ctx.rcf_gen.gcon.basic.tint pos in
 			let cases = List.map (switch_case ctx pos) names in
 			let cases = List.map (switch_case ctx pos) names in
 
 
 			let mk_this_call cf params =
 			let mk_this_call cf params =
@@ -1177,10 +1179,15 @@ let implement_invokeField ctx slow_invoke cl =
 			in
 			in
 			(cases,
 			(cases,
 				mk_return (
 				mk_return (
-					mk_this_call cf (List.map (fun (name,_,t) ->
-						let ret = { eexpr = TArray(dyn_arg_local, make_int ctx.rcf_gen.gcon.basic !i pos); etype = t_dynamic; epos = pos } in
+					mk_this_call cf (List.map (fun (name,optional,t) ->
+						let idx = make_int ctx.rcf_gen.gcon.basic !i pos in
+						let ret = { eexpr = TArray(dyn_arg_local, idx); etype = t_dynamic; epos = pos } in
 						incr i;
 						incr i;
-						ret
+						if optional then
+							let condition = binop OpGt dyn_arg_length idx ctx.rcf_gen.gcon.basic.tbool pos in
+							mk (TIf (condition, ret, Some (make_null ret.etype pos))) ret.etype pos
+						else
+							ret
 					) (fst (get_fun (cf.cf_type))))
 					) (fst (get_fun (cf.cf_type))))
 				)
 				)
 			)
 			)

+ 9 - 11
src/compiler/haxe.ml

@@ -82,7 +82,7 @@ let error ctx msg p =
 
 
 let reserved_flags = [
 let reserved_flags = [
 	"true";"false";"null";"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python";
 	"true";"false";"null";"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python";
-	"as3";"swc";"macro";"sys";"static";"utf16";"haxe";"haxe_ver"
+	"swc";"macro";"sys";"static";"utf16";"haxe";"haxe_ver"
 	]
 	]
 
 
 let reserved_flag_namespaces = ["target"]
 let reserved_flag_namespaces = ["target"]
@@ -104,9 +104,10 @@ let expand_env ?(h=None) path  =
 	) path
 	) path
 
 
 let add_libs com libs =
 let add_libs com libs =
+	let global_repo = List.exists (fun a -> a = "--haxelib-global") com.args in
 	let call_haxelib() =
 	let call_haxelib() =
 		let t = Timer.timer ["haxelib"] in
 		let t = Timer.timer ["haxelib"] in
-		let cmd = "haxelib path " ^ String.concat " " libs in
+		let cmd = "haxelib" ^ (if global_repo then " --global" else "") ^ " path " ^ String.concat " " libs in
 		let pin, pout, perr = Unix.open_process_full cmd (Unix.environment()) in
 		let pin, pout, perr = Unix.open_process_full cmd (Unix.environment()) in
 		let lines = Std.input_list pin in
 		let lines = Std.input_list pin in
 		let err = Std.input_list perr in
 		let err = Std.input_list perr in
@@ -307,8 +308,6 @@ let generate tctx ext interp swf_header =
 		()
 		()
 	else begin
 	else begin
 		let generate,name = match com.platform with
 		let generate,name = match com.platform with
-		| Flash when Common.defined com Define.As3 ->
-			Genas3.generate,"AS3"
 		| Flash ->
 		| Flash ->
 			Genswf.generate swf_header,"swf"
 			Genswf.generate swf_header,"swf"
 		| Neko ->
 		| Neko ->
@@ -502,6 +501,7 @@ let do_type tctx config_macros classes =
 	CommonCache.lock_signature com "after_init_macros";
 	CommonCache.lock_signature com "after_init_macros";
 	List.iter (fun f -> f ()) (List.rev com.callbacks#get_after_init_macros);
 	List.iter (fun f -> f ()) (List.rev com.callbacks#get_after_init_macros);
 	run_or_diagnose com (fun () ->
 	run_or_diagnose com (fun () ->
+		if com.display.dms_kind <> DMNone then Option.may (DisplayTexpr.check_display_file tctx) (CompilationServer.get ());
 		List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath null_pos)) (List.rev classes);
 		List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath null_pos)) (List.rev classes);
 		Finalization.finalize tctx;
 		Finalization.finalize tctx;
 	) ();
 	) ();
@@ -645,7 +645,8 @@ let rec process_params create pl =
 		| "--cwd" :: dir :: l | "-C" :: dir :: l ->
 		| "--cwd" :: dir :: l | "-C" :: dir :: l ->
 			(* we need to change it immediately since it will affect hxml loading *)
 			(* we need to change it immediately since it will affect hxml loading *)
 			(try Unix.chdir dir with _ -> raise (Arg.Bad ("Invalid directory: " ^ dir)));
 			(try Unix.chdir dir with _ -> raise (Arg.Bad ("Invalid directory: " ^ dir)));
-			loop acc l
+			(* Push the --cwd arg so the arg processor know we did something. *)
+			loop (dir :: "--cwd" :: acc) l
 		| "--connect" :: hp :: l ->
 		| "--connect" :: hp :: l ->
 			(match CompilationServer.get() with
 			(match CompilationServer.get() with
 			| None ->
 			| None ->
@@ -716,11 +717,6 @@ try
 		("Target",["--js"],["-js"],Arg.String (Initialize.set_platform com Js),"<file>","compile code to JavaScript file");
 		("Target",["--js"],["-js"],Arg.String (Initialize.set_platform com Js),"<file>","compile code to JavaScript file");
 		("Target",["--lua"],["-lua"],Arg.String (Initialize.set_platform com Lua),"<file>","compile code to Lua file");
 		("Target",["--lua"],["-lua"],Arg.String (Initialize.set_platform com Lua),"<file>","compile code to Lua file");
 		("Target",["--swf"],["-swf"],Arg.String (Initialize.set_platform com Flash),"<file>","compile code to Flash SWF file");
 		("Target",["--swf"],["-swf"],Arg.String (Initialize.set_platform com Flash),"<file>","compile code to Flash SWF file");
-		("Target",["--as3"],["-as3"],Arg.String (fun dir ->
-			Initialize.set_platform com Flash dir;
-			Common.define com Define.As3;
-			Common.define com Define.NoInline;
-		),"<directory>","generate AS3 code into target directory");
 		("Target",["--neko"],["-neko"],Arg.String (Initialize.set_platform com Neko),"<file>","compile code to Neko Binary");
 		("Target",["--neko"],["-neko"],Arg.String (Initialize.set_platform com Neko),"<file>","compile code to Neko Binary");
 		("Target",["--php"],["-php"],Arg.String (fun dir ->
 		("Target",["--php"],["-php"],Arg.String (fun dir ->
 			classes := (["php"],"Boot") :: !classes;
 			classes := (["php"],"Boot") :: !classes;
@@ -937,8 +933,10 @@ try
 			assert false
 			assert false
 		),"<[host:]port>","connect on the given port and run commands there");
 		),"<[host:]port>","connect on the given port and run commands there");
 		("Compilation",["-C";"--cwd"],[], Arg.String (fun dir ->
 		("Compilation",["-C";"--cwd"],[], Arg.String (fun dir ->
-			assert false
+			(* This is handled by process_params, but passed through so we know we did something. *)
+			did_something := true;
 		),"<dir>","set current working directory");
 		),"<dir>","set current working directory");
+		("Compilation",["--haxelib-global"],[], Arg.Unit (fun () -> ()),"","pass --global argument to haxelib");
 	] in
 	] in
 	let args_callback cl =
 	let args_callback cl =
 		begin try
 		begin try

+ 1 - 29
src/compiler/server.ml

@@ -183,8 +183,6 @@ module ServerCompilationContext = struct
 		mutable compilation_mark : int;
 		mutable compilation_mark : int;
 		(* A list of delays which are run after compilation *)
 		(* A list of delays which are run after compilation *)
 		mutable delays : (unit -> unit) list;
 		mutable delays : (unit -> unit) list;
-		(* A list of modules which were (perhaps temporarily) removed from the cache *)
-		mutable removed_modules : (context_cache * path * module_def) list;
 		(* True if it's an actual compilation, false if it's a display operation *)
 		(* True if it's an actual compilation, false if it's a display operation *)
 		mutable was_compilation : bool;
 		mutable was_compilation : bool;
 	}
 	}
@@ -198,7 +196,6 @@ module ServerCompilationContext = struct
 		compilation_mark = 0;
 		compilation_mark = 0;
 		mark_loop = 0;
 		mark_loop = 0;
 		delays = [];
 		delays = [];
-		removed_modules = [];
 		was_compilation = false;
 		was_compilation = false;
 	}
 	}
 
 
@@ -210,9 +207,6 @@ module ServerCompilationContext = struct
 		sctx.delays <- [];
 		sctx.delays <- [];
 		List.iter (fun f -> f()) fl
 		List.iter (fun f -> f()) fl
 
 
-	let is_removed_module sctx m =
-		List.exists (fun (_,_,m') -> m == m') sctx.removed_modules
-
 	let reset sctx =
 	let reset sctx =
 		Hashtbl.clear sctx.changed_directories;
 		Hashtbl.clear sctx.changed_directories;
 		sctx.was_compilation <- false
 		sctx.was_compilation <- false
@@ -417,8 +411,6 @@ let add_modules sctx ctx m p =
 			| MCode, MMacro | MMacro, MCode ->
 			| MCode, MMacro | MMacro, MCode ->
 				(* this was just a dependency to check : do not add to the context *)
 				(* this was just a dependency to check : do not add to the context *)
 				PMap.iter (Hashtbl.replace com.resources) m.m_extra.m_binded_res;
 				PMap.iter (Hashtbl.replace com.resources) m.m_extra.m_binded_res;
-			| _ when is_removed_module sctx m ->
-				()
 			| _ ->
 			| _ ->
 				ServerMessage.reusing com tabs m;
 				ServerMessage.reusing com tabs m;
 				m.m_extra.m_added <- sctx.compilation_step;
 				m.m_extra.m_added <- sctx.compilation_step;
@@ -476,22 +468,11 @@ let type_module sctx (ctx:Typecore.typer) mpath p =
 (* Sets up the per-compilation context. *)
 (* Sets up the per-compilation context. *)
 let create sctx write params =
 let create sctx write params =
 	let cs = sctx.cs in
 	let cs = sctx.cs in
-	let recache_removed_modules () =
-		List.iter (fun (cc,k,m) ->
-			try
-				ignore(cc#find_module k);
-			with Not_found ->
-				cc#cache_module k m
-		) sctx.removed_modules;
-		sctx.removed_modules <- []
-	in
 	let maybe_cache_context com =
 	let maybe_cache_context com =
 		if com.display.dms_full_typing then begin
 		if com.display.dms_full_typing then begin
 			CommonCache.cache_context sctx.cs com;
 			CommonCache.cache_context sctx.cs com;
 			ServerMessage.cached_modules com "" (List.length com.modules);
 			ServerMessage.cached_modules com "" (List.length com.modules);
-			sctx.removed_modules <- [];
-		end else
-			recache_removed_modules ()
+		end
 	in
 	in
 	let ctx = create_context params in
 	let ctx = create_context params in
 	ctx.flush <- (fun() ->
 	ctx.flush <- (fun() ->
@@ -517,15 +498,6 @@ let create sctx write params =
 		ServerMessage.defines ctx.com "";
 		ServerMessage.defines ctx.com "";
 		ServerMessage.signature ctx.com "" sign;
 		ServerMessage.signature ctx.com "" sign;
 		ServerMessage.display_position ctx.com "" (DisplayPosition.display_position#get);
 		ServerMessage.display_position ctx.com "" (DisplayPosition.display_position#get);
-		(* Special case for diagnostics: It's not treated as a display mode, but we still want to invalidate the
-			current file in order to run diagnostics on it again. *)
-		if ctx.com.display.dms_display || (match ctx.com.display.dms_kind with DMDiagnostics _ -> true | _ -> false) then begin
-			let file = (DisplayPosition.display_position#get).pfile in
-			(* force parsing again : if the completion point have been changed *)
-			cs#remove_files file;
-			sctx.removed_modules <- cs#filter_modules file;
-			add_delay sctx recache_removed_modules;
-		end;
 		try
 		try
 			if (Hashtbl.find sctx.class_paths sign) <> ctx.com.class_path then begin
 			if (Hashtbl.find sctx.class_paths sign) <> ctx.com.class_path then begin
 				ServerMessage.class_paths_changed ctx.com "";
 				ServerMessage.class_paths_changed ctx.com "";

+ 0 - 10
src/context/common.ml

@@ -155,7 +155,6 @@ class compiler_callbacks = object(self)
 end
 end
 
 
 type shared_display_information = {
 type shared_display_information = {
-	mutable import_positions : (pos,bool ref * placed_name list) PMap.t;
 	mutable diagnostics_messages : (string * pos * DisplayTypes.DiagnosticsKind.t * DisplayTypes.DiagnosticsSeverity.t) list;
 	mutable diagnostics_messages : (string * pos * DisplayTypes.DiagnosticsKind.t * DisplayTypes.DiagnosticsSeverity.t) list;
 	mutable dead_blocks : (string,(pos * expr) list) Hashtbl.t;
 	mutable dead_blocks : (string,(pos * expr) list) Hashtbl.t;
 }
 }
@@ -358,14 +357,6 @@ let get_config com =
 			pf_supports_threads = true;
 			pf_supports_threads = true;
 			pf_supports_unicode = false;
 			pf_supports_unicode = false;
 		}
 		}
-	| Flash when defined Define.As3 ->
-		{
-			default_config with
-			pf_sys = false;
-			pf_capture_policy = CPLoopVars;
-			pf_add_final_return = true;
-			pf_can_skip_non_nullable_argument = false;
-		}
 	| Flash ->
 	| Flash ->
 		{
 		{
 			default_config with
 			default_config with
@@ -446,7 +437,6 @@ let create version s_version args =
 		args = args;
 		args = args;
 		shared = {
 		shared = {
 			shared_display_information = {
 			shared_display_information = {
-				import_positions = PMap.empty;
 				diagnostics_messages = [];
 				diagnostics_messages = [];
 				dead_blocks = Hashtbl.create 0;
 				dead_blocks = Hashtbl.create 0;
 			}
 			}

+ 0 - 11
src/context/compilationServer.ml

@@ -164,17 +164,6 @@ class cache = object(self)
 			) cc#get_modules
 			) cc#get_modules
 		) contexts
 		) contexts
 
 
-	method filter_modules file =
-		let removed = DynArray.create () in
-		(* TODO: Using filter_map_inplace would be better, but we can't move to OCaml 4.03 yet *)
-		Hashtbl.iter (fun _ cc ->
-			Hashtbl.iter (fun k m ->
-				if m.m_extra.m_file = file then DynArray.add removed (cc,k,m);
-			) cc#get_modules
-		) contexts;
-		DynArray.iter (fun (cc,k,_) -> Hashtbl.remove cc#get_modules k) removed;
-		DynArray.to_list removed
-
 	(* haxelibs *)
 	(* haxelibs *)
 
 
 	method find_haxelib key =
 	method find_haxelib key =

+ 21 - 2
src/context/display/diagnostics.ml

@@ -9,6 +9,7 @@ open DisplayTypes.DisplayMode
 type diagnostics_context = {
 type diagnostics_context = {
 	com : Common.context;
 	com : Common.context;
 	mutable removable_code : (string * pos * pos) list;
 	mutable removable_code : (string * pos * pos) list;
+	mutable import_positions : (pos,bool ref) PMap.t;
 }
 }
 
 
 open DisplayTypes
 open DisplayTypes
@@ -104,6 +105,7 @@ let prepare com global =
 	let dctx = {
 	let dctx = {
 		removable_code = [];
 		removable_code = [];
 		com = com;
 		com = com;
+		import_positions = PMap.empty;
 	} in
 	} in
 	List.iter (function
 	List.iter (function
 		| TClassDecl c when global || DisplayPosition.display_position#is_in_file c.cl_pos.pfile ->
 		| TClassDecl c when global || DisplayPosition.display_position#is_in_file c.cl_pos.pfile ->
@@ -113,6 +115,23 @@ let prepare com global =
 		| _ ->
 		| _ ->
 			()
 			()
 	) com.types;
 	) com.types;
+	let process_modules com =
+		List.iter (fun m ->
+			PMap.iter (fun p b ->
+				if not (PMap.mem p dctx.import_positions) then
+					dctx.import_positions <- PMap.add p b dctx.import_positions
+				else if !b then begin
+					let b' = PMap.find p dctx.import_positions in
+					b' := true
+				end
+			) m.m_extra.m_display.m_import_positions
+		) com.modules
+	in
+	process_modules com;
+	begin match com.get_macros() with
+	| None -> ()
+	| Some com -> process_modules com
+	end;
 	dctx
 	dctx
 
 
 let is_diagnostics_run p = match (!Parser.display_mode) with
 let is_diagnostics_run p = match (!Parser.display_mode) with
@@ -181,9 +200,9 @@ module Printer = struct
 			) suggestions in
 			) suggestions in
 			add DKUnresolvedIdentifier p DiagnosticsSeverity.Error (JArray suggestions);
 			add DKUnresolvedIdentifier p DiagnosticsSeverity.Error (JArray suggestions);
 		) com.display_information.unresolved_identifiers;
 		) com.display_information.unresolved_identifiers;
-		PMap.iter (fun p (r,_) ->
+		PMap.iter (fun p r ->
 			if not !r then add DKUnusedImport p DiagnosticsSeverity.Warning (JArray [])
 			if not !r then add DKUnusedImport p DiagnosticsSeverity.Warning (JArray [])
-		) com.shared.shared_display_information.import_positions;
+		) dctx.import_positions;
 		List.iter (fun (s,p,kind,sev) ->
 		List.iter (fun (s,p,kind,sev) ->
 			add kind p sev (JString s)
 			add kind p sev (JString s)
 		) (List.rev com.shared.shared_display_information.diagnostics_messages);
 		) (List.rev com.shared.shared_display_information.diagnostics_messages);

+ 0 - 2
src/context/display/displayJson.ml

@@ -63,8 +63,6 @@ class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationServer.t)
 		TypeloadParse.current_stdin := jsonrpc#get_opt_param (fun () ->
 		TypeloadParse.current_stdin := jsonrpc#get_opt_param (fun () ->
 			let s = jsonrpc#get_string_param "contents" in
 			let s = jsonrpc#get_string_param "contents" in
 			Common.define com Define.DisplayStdin; (* TODO: awkward *)
 			Common.define com Define.DisplayStdin; (* TODO: awkward *)
-			(* Remove our current display file from the cache so the server doesn't pick it up *)
-			cs#remove_files file;
 			Some s
 			Some s
 		) None;
 		) None;
 		Parser.was_auto_triggered := was_auto_triggered;
 		Parser.was_auto_triggered := was_auto_triggered;

+ 163 - 0
src/context/display/displayTexpr.ml

@@ -0,0 +1,163 @@
+open Globals
+open Common
+open Ast
+open Type
+open Typecore
+open DisplayPosition
+open CompletionItem
+open CompilationServer
+open ClassFieldOrigin
+
+let find_field_by_position sc p =
+	List.find (fun cff ->
+		if pos cff.cff_name = p then true else false
+	) sc.d_data
+
+let find_enum_field_by_position sc p =
+	List.find (fun eff ->
+		if pos eff.ec_name = p then true else false
+	) sc.d_data
+
+let find_class_by_position cfile p =
+	let rec loop dl = match dl with
+		| (EClass c,_) :: dl when pos c.d_name = p -> c
+		| _ :: dl -> loop dl
+		| [] -> raise Not_found
+	in
+	loop cfile.c_decls
+
+let find_enum_by_position cfile p =
+	let rec loop dl = match dl with
+		| (EEnum en,_) :: dl when pos en.d_name = p -> en
+		| _ :: dl -> loop dl
+		| [] -> raise Not_found
+	in
+	loop cfile.c_decls
+
+let find_typedef_by_position cfile p =
+	let rec loop dl = match dl with
+		| (ETypedef td,_) :: dl when pos td.d_name = p -> td
+		| _ :: dl -> loop dl
+		| [] -> raise Not_found
+	in
+	loop cfile.c_decls
+
+let find_abstract_by_position cfile p =
+	let rec loop dl = match dl with
+		| (EAbstract a,_) :: dl when pos a.d_name = p -> a
+		| _ :: dl -> loop dl
+		| [] -> raise Not_found
+	in
+	loop cfile.c_decls
+
+let check_display_field ctx sc c cf =
+	let cff = find_field_by_position sc cf.cf_name_pos in
+	let ctx,cctx = TypeloadFields.create_class_context ctx c (fun () -> ()) cf.cf_pos in
+	let ctx,fctx = TypeloadFields.create_field_context (ctx,cctx) c cff in
+	let cf = TypeloadFields.init_field (ctx,cctx,fctx) cff in
+	ignore(follow cf.cf_type)
+
+let check_display_class ctx cc cfile c =
+	let check_field sc cf =
+		if display_position#enclosed_in cf.cf_pos then
+			check_display_field ctx sc c cf;
+		DisplayEmitter.check_display_metadata ctx cf.cf_meta
+	in
+	match c.cl_kind with
+	| KAbstractImpl a ->
+		let sa = find_abstract_by_position cfile c.cl_name_pos in
+		let check_field = check_field sa in
+		List.iter check_field c.cl_ordered_statics;
+	| _ ->
+		let sc = find_class_by_position cfile c.cl_name_pos in
+		ignore(Typeload.type_type_params ctx c.cl_path (fun() -> c.cl_params) null_pos sc.d_params);
+		List.iter (function
+			| (HExtends(ct,p) | HImplements(ct,p)) when display_position#enclosed_in p ->
+				ignore(Typeload.load_instance ~allow_display:true ctx (ct,p) false)
+			| _ ->
+				()
+		) sc.d_flags;
+		let check_field = check_field sc in
+		List.iter check_field c.cl_ordered_statics;
+		List.iter check_field c.cl_ordered_fields;
+		Option.may check_field c.cl_constructor
+
+let check_display_enum ctx cc cfile en =
+	let se = find_enum_by_position cfile en.e_name_pos in
+	ignore(Typeload.type_type_params ctx en.e_path (fun() -> en.e_params) null_pos se.d_params);
+	PMap.iter (fun _ ef ->
+		if display_position#enclosed_in ef.ef_pos then begin
+			let sef = find_enum_field_by_position se ef.ef_name_pos in
+			ignore(TypeloadModule.load_enum_field ctx en (TEnum (en,List.map snd en.e_params)) (ref false) (ref 0) sef)
+		end
+	) en.e_constrs
+
+let check_display_typedef ctx cc cfile td =
+	let st = find_typedef_by_position cfile td.t_name_pos in
+	ignore(Typeload.type_type_params ctx td.t_path (fun() -> td.t_params) null_pos st.d_params);
+	ignore(Typeload.load_complex_type ctx true st.d_data)
+
+let check_display_abstract ctx cc cfile a =
+	let sa = find_abstract_by_position cfile a.a_name_pos in
+	ignore(Typeload.type_type_params ctx a.a_path (fun() -> a.a_params) null_pos sa.d_params);
+	List.iter (function
+		| (AbOver(ct,p) | AbFrom(ct,p) | AbTo(ct,p)) when display_position#enclosed_in p ->
+			ignore(Typeload.load_complex_type ctx true (ct,p))
+		| _ ->
+			()
+	) sa.d_flags
+
+let check_display_module ctx cc cfile m =
+	let imports = List.filter (function
+		| (EImport _ | EUsing _),_ -> true
+		| _ -> false
+	) cfile.c_decls in
+	let imports = TypeloadModule.handle_import_hx ctx m imports null_pos in
+	let ctx = TypeloadModule.type_types_into_module ctx m imports null_pos in
+	List.iter (fun md ->
+		let infos = t_infos md in
+		if display_position#enclosed_in infos.mt_name_pos then
+			DisplayEmitter.display_module_type ctx md infos.mt_name_pos;
+		begin if display_position#enclosed_in infos.mt_pos then match md with
+		| TClassDecl c ->
+			check_display_class ctx cc cfile c
+		| TEnumDecl en ->
+			check_display_enum ctx cc cfile en
+		| TTypeDecl td ->
+			check_display_typedef ctx cc cfile td
+		| TAbstractDecl a ->
+			check_display_abstract ctx cc cfile a
+		end;
+		DisplayEmitter.check_display_metadata ctx infos.mt_meta
+	) m.m_types
+
+let check_display_file ctx cs =
+	match ctx.com.cache with
+	| Some cc ->
+		begin try
+			(* TODO: diagnostics currently relies on information collected during typing. *)
+			begin match ctx.com.display.dms_kind with
+				| DMDiagnostics _ -> raise Not_found
+				| _ -> ()
+			end;
+			let p = DisplayPosition.display_position#get in
+			let cfile = cc#find_file (Path.unique_full_path p.pfile) in
+			let path = (cfile.c_package,get_module_name_of_cfile p.pfile cfile) in
+			(* We have to go through type_module_hook because one of the module's dependencies could be
+			   invalid (issue #8991). *)
+			begin match !TypeloadModule.type_module_hook ctx path null_pos with
+			| None -> raise Not_found
+			| Some m -> check_display_module ctx cc cfile m
+			end
+		with Not_found ->
+			(* Special case for diagnostics: It's not treated as a display mode, but we still want to invalidate the
+				current file in order to run diagnostics on it again. *)
+			if ctx.com.display.dms_display || (match ctx.com.display.dms_kind with DMDiagnostics _ -> true | _ -> false) then begin
+				let file = (DisplayPosition.display_position#get).pfile in
+				(* force parsing again : if the completion point have been changed *)
+				cs#remove_files file;
+				cs#taint_modules file;
+			end;
+		end
+	| None ->
+		()

+ 7 - 7
src/context/display/importHandling.ml

@@ -43,17 +43,17 @@ let convert_import_to_something_usable pt path =
 	in
 	in
 	loop [] None None path
 	loop [] None None path
 
 
-let add_import_position com p path =
-	let infos = com.shared.shared_display_information in
-	if not (PMap.mem p infos.import_positions) then
-		infos.import_positions <- PMap.add p (ref false,path) infos.import_positions
+let add_import_position ctx p path =
+	let infos = ctx.m.curmod.m_extra.m_display in
+	if not (PMap.mem p infos.m_import_positions) then
+		infos.m_import_positions <- PMap.add p (ref false) infos.m_import_positions
 
 
-let mark_import_position com p =
+let mark_import_position ctx p =
 	try
 	try
-		let r = fst (PMap.find p com.shared.shared_display_information.import_positions) in
+		let r = PMap.find p ctx.m.curmod.m_extra.m_display.m_import_positions in
 		r := true
 		r := true
 	with Not_found ->
 	with Not_found ->
 		()
 		()
 
 
 let maybe_mark_import_position ctx p =
 let maybe_mark_import_position ctx p =
-	if Diagnostics.is_diagnostics_run p then mark_import_position ctx.com p
+	if Diagnostics.is_diagnostics_run p then mark_import_position ctx p

+ 2 - 5
src/context/typecore.ml

@@ -464,16 +464,13 @@ let rec can_access ctx ?(in_overload=false) c cf stat =
 			| None -> false)
 			| None -> false)
 		with Not_found -> false
 		with Not_found -> false
 	in
 	in
-	let b = loop c
+	loop c
 	(* access is also allowed of we access a type parameter which is constrained to our (base) class *)
 	(* access is also allowed of we access a type parameter which is constrained to our (base) class *)
 	|| (match c.cl_kind with
 	|| (match c.cl_kind with
 		| KTypeParameter tl ->
 		| KTypeParameter tl ->
 			List.exists (fun t -> match follow t with TInst(c,_) -> loop c | _ -> false) tl
 			List.exists (fun t -> match follow t with TInst(c,_) -> loop c | _ -> false) tl
 		| _ -> false)
 		| _ -> false)
-	|| (Meta.has Meta.PrivateAccess ctx.meta) in
-	(* TODO: find out what this does and move it to genas3 *)
-	if b && Common.defined ctx.com Common.Define.As3 && not (Meta.has Meta.Public cf.cf_meta) then cf.cf_meta <- (Meta.Public,[],cf.cf_pos) :: cf.cf_meta;
-	b
+	|| (Meta.has Meta.PrivateAccess ctx.meta)
 
 
 (** removes the first argument of the class field's function type and all its overloads *)
 (** removes the first argument of the class field's function type and all its overloads *)
 let prepare_using_field cf = match follow cf.cf_type with
 let prepare_using_field cf = match follow cf.cf_type with

+ 8 - 8
src/core/abstract.ml

@@ -71,17 +71,17 @@ let rec get_underlying_type ?(return_first=false) a pl =
 					let s = String.concat " -> " (List.map (fun t -> s_type pctx t) (List.rev (t :: underlying_type_stack.rec_stack))) in
 					let s = String.concat " -> " (List.map (fun t -> s_type pctx t) (List.rev (t :: underlying_type_stack.rec_stack))) in
 					error ("Abstract chain detected: " ^ s) a.a_pos
 					error ("Abstract chain detected: " ^ s) a.a_pos
 				end;
 				end;
-				(*
-					Even if only the first underlying type was requested
-					keep traversing to detect mutually recursive abstracts
-				*)
-				let result = get_underlying_type a tl in
-				if return_first then t
-				else result
+				get_underlying_type a tl
 			| _ ->
 			| _ ->
 				t
 				t
 		in
 		in
-		rec_stack_loop underlying_type_stack (TAbstract(a,pl)) loop t
+		(*
+			Even if only the first underlying type was requested
+			keep traversing to detect mutually recursive abstracts
+		*)
+		let result = rec_stack_loop underlying_type_stack (TAbstract(a,pl)) loop t in
+		if return_first then t
+		else result
 	in
 	in
 	try
 	try
 		if not (Meta.has Meta.MultiType a.a_meta) then raise Not_found;
 		if not (Meta.has Meta.MultiType a.a_meta) then raise Not_found;

+ 4 - 2
src/core/globals.ml

@@ -24,11 +24,11 @@ type platform =
 	| Hl
 	| Hl
 	| Eval
 	| Eval
 
 
-let version = 4000
+let version = 4100
 let version_major = version / 1000
 let version_major = version / 1000
 let version_minor = (version mod 1000) / 100
 let version_minor = (version mod 1000) / 100
 let version_revision = (version mod 100)
 let version_revision = (version mod 100)
-let version_pre = Some "rc.5"
+let version_pre = Some "rc.1"
 
 
 let macro_platform = ref Neko
 let macro_platform = ref Neko
 
 
@@ -71,6 +71,8 @@ let platform_list_help = function
 
 
 let null_pos = { pfile = "?"; pmin = -1; pmax = -1 }
 let null_pos = { pfile = "?"; pmin = -1; pmax = -1 }
 
 
+let mk_zero_range_pos p = { p with pmax = p.pmin }
+
 let s_type_path (p,s) = match p with [] -> s | _ -> String.concat "." p ^ "." ^ s
 let s_type_path (p,s) = match p with [] -> s | _ -> String.concat "." p ^ "." ^ s
 
 
 let starts_with s c =
 let starts_with s c =

+ 14 - 11
src/core/numeric.ml

@@ -56,19 +56,22 @@ let parse_float s =
 	float_of_string (loop 0 0)
 	float_of_string (loop 0 0)
 
 
 let parse_int s =
 let parse_int s =
-	let rec loop_hex i =
-		if i = String.length s then s else
-		match String.unsafe_get s i with
-		| '0'..'9' | 'a'..'f' | 'A'..'F' -> loop_hex (i + 1)
-		| _ -> String.sub s 0 i
+	let rec loop_hex sp i =
+		if i = String.length s then
+			String.sub s sp (i - sp)
+		else
+			match String.unsafe_get s i with
+			| '0'..'9' | 'a'..'f' | 'A'..'F' -> loop_hex sp (i + 1)
+			| _ -> String.sub s sp (i - sp)
 	in
 	in
-	let rec loop sp i =
+	let rec loop sp i digits_count =
 		if i = String.length s then (if sp = 0 then s else String.sub s sp (i - sp)) else
 		if i = String.length s then (if sp = 0 then s else String.sub s sp (i - sp)) else
 		match String.unsafe_get s i with
 		match String.unsafe_get s i with
-		| '0'..'9' -> loop sp (i + 1)
-		| ' ' when sp = i -> loop (sp + 1) (i + 1)
-		| '-' when i = 0 -> loop sp (i + 1)
-		| ('x' | 'X') when i = 1 && String.get s 0 = '0' -> loop_hex (i + 1)
+		| '0'..'9' -> loop sp (i + 1) (digits_count + 1)
+		| ' ' | '+' when sp = i -> loop (sp + 1) (i + 1) digits_count
+		| c when sp = i && Char.code c > 8 && Char.code c < 14 -> loop (sp + 1) (i + 1) digits_count
+		| '-' when i = sp -> loop sp (i + 1) digits_count
+		| ('x' | 'X') when digits_count = 1 && String.get s (i - 1) = '0' -> loop_hex sp (i + 1)
 		| _ -> String.sub s sp (i - sp)
 		| _ -> String.sub s sp (i - sp)
 	in
 	in
-	Int32.of_string (loop 0 0)
+	Int32.of_string (loop 0 0 0)

+ 1 - 0
src/core/tFunctions.ml

@@ -116,6 +116,7 @@ let module_extra file sign time kind policy =
 		m_display = {
 		m_display = {
 			m_inline_calls = [];
 			m_inline_calls = [];
 			m_type_hints = [];
 			m_type_hints = [];
+			m_import_positions = PMap.empty;
 		};
 		};
 		m_dirty = None;
 		m_dirty = None;
 		m_added = 0;
 		m_added = 0;

+ 1 - 0
src/core/tPrinting.ml

@@ -583,6 +583,7 @@ module Printer = struct
 			"v_capture",string_of_bool v.v_capture;
 			"v_capture",string_of_bool v.v_capture;
 			"v_extra",s_opt s_tvar_extra v.v_extra;
 			"v_extra",s_opt s_tvar_extra v.v_extra;
 			"v_meta",s_metadata v.v_meta;
 			"v_meta",s_metadata v.v_meta;
+			"v_pos",s_pos v.v_pos;
 		]
 		]
 
 
 	let s_module_kind = function
 	let s_module_kind = function

+ 1 - 0
src/core/tType.ml

@@ -318,6 +318,7 @@ and module_def = {
 and module_def_display = {
 and module_def_display = {
 	mutable m_inline_calls : (pos * pos) list; (* calls whatever is at pos1 from pos2 *)
 	mutable m_inline_calls : (pos * pos) list; (* calls whatever is at pos1 from pos2 *)
 	mutable m_type_hints : (pos * pos) list;
 	mutable m_type_hints : (pos * pos) list;
+	mutable m_import_positions : (pos,bool ref) PMap.t;
 }
 }
 
 
 and module_def_extra = {
 and module_def_extra = {

+ 11 - 3
src/dune

@@ -6,18 +6,26 @@
 	)
 	)
 )
 )
 
 
-(executable
+(library
 	(name haxe)
 	(name haxe)
-	(public_name haxe)
-	(package haxe)
 	(libraries
 	(libraries
 		extc extproc extlib_leftovers ilib javalib neko objsize pcre swflib ttflib ziplib
 		extc extproc extlib_leftovers ilib javalib neko objsize pcre swflib ttflib ziplib
 		json
 		json
 		unix str threads dynlink
 		unix str threads dynlink
 		xml-light extlib ptmap sha
 		xml-light extlib ptmap sha
 	)
 	)
+	(modules (:standard \ haxe))
 	(preprocess (per_module
 	(preprocess (per_module
 		((pps sedlex.ppx) json lexer)
 		((pps sedlex.ppx) json lexer)
 	))
 	))
+	(wrapped false)
+)
+
+(executable
+	(name haxe)
+	(public_name haxe)
+	(package haxe)
+	(libraries haxe)
+	(modules haxe)
 	(link_flags (:include ../lib.sexp))
 	(link_flags (:include ../lib.sexp))
 )
 )

+ 8 - 39
src/filters/filters.ml

@@ -545,7 +545,6 @@ let add_rtti ctx t =
 
 
 (* Adds member field initializations as assignments to the constructor *)
 (* Adds member field initializations as assignments to the constructor *)
 let add_field_inits reserved ctx t =
 let add_field_inits reserved ctx t =
-	let is_as3 = Common.defined ctx.com Define.As3 && not ctx.in_macro in
 	let apply c =
 	let apply c =
 		let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_params)) c.cl_pos in
 		let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_params)) c.cl_pos in
 		(* TODO: we have to find a variable name which is not used in any of the functions *)
 		(* TODO: we have to find a variable name which is not used in any of the functions *)
@@ -553,28 +552,7 @@ let add_field_inits reserved ctx t =
 		let need_this = ref false in
 		let need_this = ref false in
 		let inits,fields = List.fold_left (fun (inits,fields) cf ->
 		let inits,fields = List.fold_left (fun (inits,fields) cf ->
 			match cf.cf_kind,cf.cf_expr with
 			match cf.cf_kind,cf.cf_expr with
-			| Var _, Some _ ->
-				if is_as3 then (inits, cf :: fields) else (cf :: inits, cf :: fields)
-			| Method MethDynamic, Some e when is_as3 ->
-				(* TODO : this would have a better place in genSWF9 I think - NC *)
-				(* we move the initialization of dynamic functions to the constructor and also solve the
-				   'this' problem along the way *)
-				let rec use_this v e = match e.eexpr with
-					| TConst TThis ->
-						need_this := true;
-						mk (TLocal v) v.v_type e.epos
-					| _ -> Type.map_expr (use_this v) e
-				in
-				let e = Type.map_expr (use_this v) e in
-				let cf2 = {cf with cf_expr = Some e} in
-				(* if the method is an override, we have to remove the class field to not get invalid overrides *)
-				let fields = if List.memq cf c.cl_overrides then begin
-					c.cl_fields <- PMap.remove cf.cf_name c.cl_fields;
-					fields
-				end else
-					cf2 :: fields
-				in
-				(cf2 :: inits, fields)
+			| Var _, Some _ -> (cf :: inits, cf :: fields)
 			| _ -> (inits, cf :: fields)
 			| _ -> (inits, cf :: fields)
 		) ([],[]) c.cl_ordered_fields in
 		) ([],[]) c.cl_ordered_fields in
 		c.cl_ordered_fields <- (List.rev fields);
 		c.cl_ordered_fields <- (List.rev fields);
@@ -587,12 +565,7 @@ let add_field_inits reserved ctx t =
 				| Some e ->
 				| Some e ->
 					let lhs = mk (TField({ ethis with epos = cf.cf_pos },FInstance (c,List.map snd c.cl_params,cf))) cf.cf_type cf.cf_pos in
 					let lhs = mk (TField({ ethis with epos = cf.cf_pos },FInstance (c,List.map snd c.cl_params,cf))) cf.cf_type cf.cf_pos in
 					cf.cf_expr <- None;
 					cf.cf_expr <- None;
-					let eassign = mk (TBinop(OpAssign,lhs,e)) cf.cf_type e.epos in
-					if is_as3 then begin
-						let echeck = mk (TBinop(OpEq,lhs,(mk (TConst TNull) lhs.etype e.epos))) ctx.com.basic.tbool e.epos in
-						mk (TIf(echeck,eassign,None)) eassign.etype e.epos
-					end else
-						eassign;
+					mk (TBinop(OpAssign,lhs,e)) cf.cf_type e.epos
 			) inits in
 			) inits in
 			let el = if !need_this then (mk (TVar((v, Some ethis))) ethis.etype ethis.epos) :: el else el in
 			let el = if !need_this then (mk (TVar((v, Some ethis))) ethis.etype ethis.epos) :: el else el in
 			let cf = match c.cl_constructor with
 			let cf = match c.cl_constructor with
@@ -643,7 +616,6 @@ let add_meta_field ctx t = match t with
 			let cf = mk_field "__meta__" e.etype e.epos null_pos in
 			let cf = mk_field "__meta__" e.etype e.epos null_pos in
 			cf.cf_expr <- Some e;
 			cf.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
 				| Cs | Java -> false
 				| Cs | Java -> false
 				| _ -> true
 				| _ -> true
 			in
 			in
@@ -699,7 +671,7 @@ let check_cs_events com t = match t with
 
 
 					(* add @:keep to event methods if the event is kept *)
 					(* add @:keep to event methods if the event is kept *)
 					if Meta.has Meta.Keep f.cf_meta && not (Meta.has Meta.Keep m.cf_meta) then
 					if Meta.has Meta.Keep f.cf_meta && not (Meta.has Meta.Keep m.cf_meta) then
-						m.cf_meta <- (Meta.Keep,[],f.cf_pos) :: m.cf_meta;
+						m.cf_meta <- (Dce.mk_keep_meta f.cf_pos) :: m.cf_meta;
 				in
 				in
 				process_event_method ("add_" ^ f.cf_name);
 				process_event_method ("add_" ^ f.cf_name);
 				process_event_method ("remove_" ^ f.cf_name)
 				process_event_method ("remove_" ^ f.cf_name)
@@ -809,7 +781,7 @@ module ForRemap = struct
 end
 end
 
 
 let run com tctx main =
 let run com tctx main =
-	let detail_times = Common.raw_defined com "filter-times" in
+	let detail_times = Common.defined com DefineList.FilterTimes in
 	let new_types = List.filter (fun t ->
 	let new_types = List.filter (fun t ->
 		let cached = is_cached t in
 		let cached = is_cached t in
 		begin match t with
 		begin match t with
@@ -837,7 +809,7 @@ let run com tctx main =
 	NullSafety.run com new_types;
 	NullSafety.run com new_types;
 	(* PASS 1: general expression filters *)
 	(* PASS 1: general expression filters *)
 	let filters = [
 	let filters = [
-		(* ForRemap.apply tctx; *)
+		ForRemap.apply tctx;
 		VarLazifier.apply com;
 		VarLazifier.apply com;
 		AbstractCast.handle_abstract_casts tctx;
 		AbstractCast.handle_abstract_casts tctx;
 	] in
 	] in
@@ -848,8 +820,9 @@ let run com tctx main =
 		fix_return_dynamic_from_void_function tctx true;
 		fix_return_dynamic_from_void_function tctx true;
 		check_local_vars_init;
 		check_local_vars_init;
 		check_abstract_as_value;
 		check_abstract_as_value;
-		if Common.defined com Define.OldConstructorInline then Optimizer.inline_constructors tctx else InlineConstructors.inline_constructors tctx;
+		if defined com Define.AnalyzerOptimize then Tre.run tctx else (fun e -> e);
 		Optimizer.reduce_expression tctx;
 		Optimizer.reduce_expression tctx;
+		if Common.defined com Define.OldConstructorInline then Optimizer.inline_constructors tctx else InlineConstructors.inline_constructors tctx;
 		CapturedVars.captured_vars com;
 		CapturedVars.captured_vars com;
 	] in
 	] in
 	let filters =
 	let filters =
@@ -929,11 +902,7 @@ let run com tctx main =
 	com.stage <- CDceStart;
 	com.stage <- CDceStart;
 	let t = filter_timer detail_times ["dce"] in
 	let t = filter_timer detail_times ["dce"] in
 	(* DCE *)
 	(* DCE *)
-	let dce_mode = if Common.defined com Define.As3 then
-		"no"
-	else
-		(try Common.defined_value com Define.Dce with _ -> "no")
-	in
+	let dce_mode = try Common.defined_value com Define.Dce with _ -> "no" in
 	let dce_mode = match dce_mode with
 	let dce_mode = match dce_mode with
 		| "full" -> if Common.defined com Define.Interp then Dce.DceNo else DceFull
 		| "full" -> if Common.defined com Define.Interp then Dce.DceNo else DceFull
 		| "std" -> DceStd
 		| "std" -> DceStd

+ 10 - 0
src/filters/filtersCommon.ml

@@ -38,6 +38,16 @@ let rec is_removable_class c =
 	| _ ->
 	| _ ->
 		false
 		false
 
 
+(**
+	Check if `field` is overridden in subclasses
+*)
+let is_overridden cls field =
+	let rec loop_inheritance c =
+		(PMap.mem field.cf_name c.cl_fields)
+		|| List.exists (fun d -> loop_inheritance d) c.cl_descendants;
+	in
+	List.exists (fun d -> loop_inheritance d) cls.cl_descendants
+
 let run_expression_filters ctx filters t =
 let run_expression_filters ctx filters t =
 	let run e =
 	let run e =
 		List.fold_left (fun e f -> f e) e filters
 		List.fold_left (fun e f -> f e) e filters

+ 222 - 0
src/filters/tre.ml

@@ -0,0 +1,222 @@
+open Type
+open Typecore
+open Globals
+
+let rec collect_new_args_values ctx args declarations values n =
+	match args with
+	| [] -> declarations, values
+	| arg :: rest ->
+		let v = alloc_var VGenerated ("`tmp" ^ (string_of_int n)) arg.etype arg.epos in
+		let decl = { eexpr = TVar (v, Some arg); etype = ctx.t.tvoid; epos = v.v_pos }
+		and value = { arg with eexpr = TLocal v } in
+		collect_new_args_values ctx rest (decl :: declarations) (value :: values) (n + 1)
+
+let rec assign_args vars exprs =
+	match vars, exprs with
+	| [], [] -> []
+	| (v, _) :: rest_vars, e :: rest_exprs
+	| (v, Some e) :: rest_vars, rest_exprs ->
+		let arg = { e with eexpr = TLocal v } in
+		{ e with eexpr = TBinop (OpAssign, arg, e) } :: assign_args rest_vars rest_exprs
+	| _ -> assert false
+
+let replacement_for_TReturn ctx fn args p =
+	let temps_rev, args_rev = collect_new_args_values ctx args [] [] 0
+	and continue = mk TContinue ctx.t.tvoid Globals.null_pos in
+	{
+		etype = ctx.t.tvoid;
+		epos = p;
+		eexpr = TMeta ((Meta.TailRecursion, [], null_pos), {
+			eexpr = TBlock ((List.rev temps_rev) @ (assign_args fn.tf_args (List.rev args_rev)) @ [continue]);
+			etype = ctx.t.tvoid;
+			epos = p;
+		});
+	}
+
+let collect_captured_args args e =
+	let result = ref [] in
+	let rec loop in_closure e =
+		match e.eexpr with
+		| TLocal ({ v_kind = VUser TVOArgument } as v) when in_closure && not (List.memq v !result) && List.memq v args ->
+			result := v :: !result
+		| TFunction { tf_expr = e } ->
+			loop true e
+		| _ ->
+			iter (loop in_closure) e
+	in
+	loop false e;
+	!result
+
+let rec redeclare_vars ctx vars declarations replace_list =
+	match vars with
+	| [] -> declarations, replace_list
+	| v :: rest ->
+		let new_v = alloc_var VGenerated ("`" ^ v.v_name) v.v_type v.v_pos in
+		let decl =
+			{
+				eexpr = TVar (new_v, Some { eexpr = TLocal v; etype = v.v_type; epos = v.v_pos; });
+				etype = ctx.t.tvoid;
+				epos = v.v_pos;
+			}
+		in
+		redeclare_vars ctx rest (decl :: declarations) ((v, new_v) :: replace_list)
+
+let rec replace_vars replace_list in_tail_recursion e =
+	match e.eexpr with
+	| TBinop (OpAssign, ({ eexpr = TLocal { v_kind = VUser TVOArgument } } as arg), value) when in_tail_recursion ->
+		let value = replace_vars replace_list in_tail_recursion value in
+		{ e with eexpr = TBinop (OpAssign, arg, value) }
+	| TLocal v ->
+		(try
+			let v = List.assq v replace_list in
+			{ e with eexpr = TLocal v }
+		with Not_found ->
+			e
+		)
+	| TMeta ((Meta.TailRecursion, _, _), _) -> map_expr (replace_vars replace_list true) e
+	| _ -> map_expr (replace_vars replace_list in_tail_recursion) e
+
+let wrap_loop ctx args body =
+	let wrap e =
+		let cond = mk (TConst (TBool true)) ctx.t.tbool Globals.null_pos in
+		{ e with eexpr = TWhile (cond, e, Ast.NormalWhile) }
+	in
+	match collect_captured_args args body with
+	| [] -> wrap body
+	| captured_args ->
+		let declarations, replace_list = redeclare_vars ctx captured_args [] [] in
+		wrap { body with eexpr = TBlock (declarations @ [replace_vars replace_list false body]) }
+
+let fn_args_vars fn = List.map (fun (v,_) -> v) fn.tf_args
+
+let is_recursive_named_local_call fn_var callee args =
+	match callee.eexpr with
+	(* named local function*)
+	| TLocal v ->
+		v == fn_var
+	| _ -> false
+
+let is_recursive_method_call cls field callee args =
+	match callee.eexpr, args with
+	(* member abstract function*)
+	| TField (_, FStatic (_, cf)), { eexpr = TLocal v } :: _ when has_meta Meta.Impl cf.cf_meta ->
+		cf == field && has_meta Meta.This v.v_meta
+	(* static method *)
+	| TField (_, FStatic (_, cf)), _
+	(* instance method *)
+	| TField ({ eexpr = TConst TThis }, FInstance (_, _, cf)), _ ->
+		cf == field && not (FiltersCommon.is_overridden cls field)
+	| _ -> false
+
+let rec transform_function ctx is_recursive_call fn =
+	let add_loop = ref false in
+	let rec transform_expr cancel_tre function_end e =
+		match e.eexpr with
+		(* cancel tre inside of loops bodies *)
+		| TWhile _ | TFor _ ->
+			map_expr (transform_expr true false) e
+		(* cancel tre inside of try blocks *)
+		| TTry (e_try, catches) ->
+			let e_try = transform_expr true function_end e_try in
+			let catches = List.map (fun (v, e) -> v, transform_expr cancel_tre function_end e) catches in
+			{ e with eexpr = TTry (e_try, catches) }
+		(* named local function *)
+		| TBinop (OpAssign, ({ eexpr = TLocal ({ v_kind = VUser TVOLocalFunction } as v) } as e_var), ({ eexpr = TFunction fn } as e_fn)) ->
+			let fn = transform_function ctx (is_recursive_named_local_call v) fn in
+			{ e with eexpr = TBinop (OpAssign, e_var, { e_fn with eexpr = TFunction fn }) }
+		(* anonymous function *)
+		| TFunction _ ->
+			e
+		(* return a recursive call to current function *)
+		| TReturn (Some { eexpr = TCall (callee, args) }) when not cancel_tre && is_recursive_call callee args ->
+			add_loop := true;
+			replacement_for_TReturn ctx fn args e.epos
+		| TReturn (Some e_return) ->
+			{ e with eexpr = TReturn (Some (transform_expr cancel_tre function_end e_return)) }
+		| TBlock exprs ->
+			let rec loop exprs =
+				match exprs with
+				| [] -> []
+				| [{ eexpr = TCall (callee, args) } as e] when not cancel_tre && function_end && is_recursive_call callee args ->
+					add_loop := true;
+					[replacement_for_TReturn ctx fn args e.epos]
+				| { eexpr = TCall (callee, args) } :: [{ eexpr = TReturn None }] when not cancel_tre && is_recursive_call callee args ->
+					add_loop := true;
+					[replacement_for_TReturn ctx fn args e.epos]
+				| e :: rest ->
+					let function_end = function_end && rest = [] in
+					transform_expr cancel_tre function_end e :: loop rest
+			in
+			{ e with eexpr = TBlock (loop exprs) }
+		| _ ->
+			map_expr (transform_expr cancel_tre function_end) e
+	in
+	let body = transform_expr false true fn.tf_expr in
+	let body =
+		if !add_loop then
+			let body =
+				if ExtType.is_void (follow fn.tf_type) then
+					mk (TBlock [body; mk (TReturn None) ctx.t.tvoid null_pos]) ctx.t.tvoid null_pos
+				else
+					body
+			in
+			wrap_loop ctx (fn_args_vars fn) body
+		else
+			body
+	in
+	{ fn with tf_expr = body }
+
+let rec has_tail_recursion is_recursive_call cancel_tre function_end e =
+	match e.eexpr with
+	(* cancel tre inside of loops bodies *)
+	| TFor _ | TWhile _ ->
+		check_expr (has_tail_recursion is_recursive_call true false) e
+	(* cancel tre inside of try blocks *)
+	| TTry (e, catches) ->
+		has_tail_recursion is_recursive_call true function_end e
+		|| List.exists (fun (_, e) -> has_tail_recursion is_recursive_call cancel_tre function_end e) catches
+	(* named local function *)
+	| TBinop (OpAssign, { eexpr = TLocal ({ v_kind = VUser TVOLocalFunction } as v) }, { eexpr = TFunction fn }) ->
+		has_tail_recursion (is_recursive_named_local_call v) false true fn.tf_expr
+	(* anonymous function *)
+	| TFunction _ ->
+		false
+	| TReturn (Some { eexpr = TCall (callee, args)}) ->
+		not cancel_tre && is_recursive_call callee args
+	| TBlock exprs ->
+		let rec loop exprs =
+			match exprs with
+			| [] -> false
+			| [{ eexpr = TCall (callee, args) }] when not cancel_tre && function_end ->
+				is_recursive_call callee args
+			| { eexpr = TCall (callee, args) } :: [{ eexpr = TReturn None }] when not cancel_tre ->
+				is_recursive_call callee args
+			| e :: rest ->
+				let function_end = function_end && rest = [] in
+				has_tail_recursion is_recursive_call cancel_tre function_end e
+				|| loop rest
+		in
+		loop exprs
+	| _ ->
+		check_expr (has_tail_recursion is_recursive_call cancel_tre function_end) e
+
+let run ctx e =
+	match e.eexpr with
+	| TFunction fn ->
+		let is_tre_eligible =
+			match ctx.curfield.cf_kind with
+			| Method MethDynamic -> false
+			| Method MethInline -> true
+			| Method _ when ctx.curfun = FunStatic -> true
+			| _ -> has_class_field_flag ctx.curfield CfFinal
+			in
+		let is_recursive_call callee args =
+			is_tre_eligible && is_recursive_method_call ctx.curclass ctx.curfield callee args
+		in
+		if has_tail_recursion is_recursive_call false true fn.tf_expr then
+			(* print_endline ("TRE: " ^ ctx.curfield.cf_pos.pfile ^ ": " ^ ctx.curfield.cf_name); *)
+			let fn = transform_function ctx is_recursive_call fn in
+			{ e with eexpr = TFunction fn }
+		else
+			e
+	| _ -> e

+ 0 - 1322
src/generators/genas3.ml

@@ -1,1322 +0,0 @@
-(*
-	The Haxe Compiler
-	Copyright (C) 2005-2019  Haxe Foundation
-
-	This program is free software; you can redistribute it and/or
-	modify it under the terms of the GNU General Public License
-	as published by the Free Software Foundation; either version 2
-	of the License, or (at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *)
-
-open Type
-open Common
-open FlashProps
-
-type context_infos = {
-	com : Common.context;
-}
-
-type context = {
-	inf : context_infos;
-	ch : out_channel;
-	buf : Buffer.t;
-	path : Globals.path;
-	mutable get_sets : (string * bool,string) Hashtbl.t;
-	mutable curclass : tclass;
-	mutable tabs : string;
-	mutable in_value : tvar option;
-	mutable in_static : bool;
-	mutable handle_break : bool;
-	mutable imports : (string,string list list) Hashtbl.t;
-	mutable gen_uid : int;
-	mutable local_types : t list;
-	mutable constructor_block : bool;
-	mutable block_inits : (unit -> unit) option;
-}
-
-let follow = Abstract.follow_with_abstracts
-
-let is_var_field f =
-	match f with
-	| FStatic (_,f) | FInstance (_,_,f) ->
-		(match f.cf_kind with Var _ | Method MethDynamic -> true | _ -> false)
-	| _ ->
-		false
-
-let is_special_compare e1 e2 =
-	match e1.eexpr, e2.eexpr with
-	| TConst TNull, _  | _ , TConst TNull -> None
-	| _ ->
-	match follow e1.etype, follow e2.etype with
-	| TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) , _ | _ , TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) -> Some c
-	| _ -> None
-
-let is_fixed_override cf t =
-	let is_type_parameter c = match c.cl_kind with
-		| KTypeParameter _ -> true
-		| _ -> false
-	in
-	match follow cf.cf_type,follow t with
-	| TFun(_,r1),TFun(_,r2) ->
-		begin match follow r1,follow r2 with
-		| TInst(c1,_),TInst(c2,_) when c1 != c2 && not (is_type_parameter c1) && not (is_type_parameter c2) -> true
-		| _ -> false
-		end
-	| _ ->
-		false
-
-let protect name =
-	match name with
-	| "Error" | "Namespace" | "Object" -> "_" ^ name
-	| _ -> name
-
-let s_path ctx stat path p =
-	match path with
-	| ([],name) ->
-		(match name with
-		| "Int" -> "int"
-		| "Float" -> "Number"
-		| "Dynamic" -> "Object"
-		| "Bool" -> "Boolean"
-		| "Enum" -> "Class"
-		| "EnumValue" -> "enum"
-		| _ -> name)
-	| (["flash"],"FlashXml__") ->
-		"Xml"
-	| (["flash";"errors"],"Error") ->
-		"Error"
-	| (["flash"],"Vector") ->
-		"Vector"
-	| (["flash";"xml"],"XML") ->
-		"XML"
-	| (["flash";"xml"],"XMLList") ->
-		"XMLList"
-	| ["flash";"utils"],"QName" ->
-		"QName"
-	| ["flash";"utils"],"Namespace" ->
-		"Namespace"
-	| (["haxe"],"Int32") when not stat ->
-		"int"
-	| (pack,name) ->
-		let name = protect name in
-		let packs = (try Hashtbl.find ctx.imports name with Not_found -> []) in
-		if not (List.mem pack packs) then Hashtbl.replace ctx.imports name (pack :: packs);
-		Globals.s_type_path (pack,name)
-
-let reserved =
-	let h = Hashtbl.create 0 in
-	List.iter (fun l -> Hashtbl.add h l ())
-	(* these ones are defined in order to prevent recursion in some Std functions *)
-	["is";"as";"int";"uint";"const";"getTimer";"typeof";"parseInt";"parseFloat";
-	(* AS3 keywords which are not Haxe ones *)
-	"finally";"with";"final";"internal";"native";"namespace";"include";"delete";
-	(* some globals give some errors with Flex SDK as well *)
-	"print";"trace";
-	(* we don't include get+set since they are not 'real' keywords, but they can't be used as method names *)
-	"function";"class";"var";"if";"else";"while";"do";"for";"break";"continue";"return";"extends";"implements";
-	"import";"switch";"case";"default";"static";"public";"private";"try";"catch";"new";"this";"throw";"interface";
-	"override";"package";"null";"true";"false";"void"
-	];
-	h
-
-	(* "each", "label" : removed (actually allowed in locals and fields accesses) *)
-
-let s_ident n =
-	if Hashtbl.mem reserved n then "_" ^ n else n
-
-let valid_as3_ident s =
-	try
-		for i = 0 to String.length s - 1 do
-			match String.unsafe_get s i with
-			| 'a'..'z' | 'A'..'Z' | '$' | '_' -> ()
-			| '0'..'9' when i > 0 -> ()
-			| _ -> raise Exit
-		done;
-		true
-	with Exit ->
-		false
-
-let anon_field s =
-	let s = s_ident s in
-	if not (valid_as3_ident s) then "\"" ^ (StringHelper.s_escape s) ^ "\"" else s
-
-let rec create_dir acc = function
-	| [] -> ()
-	| d :: l ->
-		let dir = String.concat "/" (List.rev (d :: acc)) in
-		if not (Sys.file_exists dir) then Unix.mkdir dir 0o755;
-		create_dir (d :: acc) l
-
-let init infos path =
-	let dir = infos.com.file :: fst path in
-	create_dir [] dir;
-	let ch = open_out (String.concat "/" dir ^ "/" ^ snd path ^ ".as") in
-	let imports = Hashtbl.create 0 in
-	Hashtbl.add imports (snd path) [fst path];
-	{
-		inf = infos;
-		tabs = "";
-		ch = ch;
-		path = path;
-		buf = Buffer.create (1 lsl 14);
-		in_value = None;
-		in_static = false;
-		handle_break = false;
-		imports = imports;
-		curclass = null_class;
-		gen_uid = 0;
-		local_types = [];
-		get_sets = Hashtbl.create 0;
-		constructor_block = false;
-		block_inits = None;
-	}
-
-let close ctx =
-	begin match ctx.inf.com.main_class with
-		| Some tp when tp = ctx.curclass.cl_path ->
-			output_string ctx.ch "// Compile __main__.as instead\n";
-		| _ ->
-			()
-	end;
-	output_string ctx.ch (Printf.sprintf "package %s {\n" (String.concat "." (fst ctx.path)));
-	Hashtbl.iter (fun name paths ->
-		List.iter (fun pack ->
-			let path = pack, name in
-			if path <> ctx.path then output_string ctx.ch ("\timport " ^ Globals.s_type_path path ^ ";\n");
-		) paths
-	) ctx.imports;
-	output_string ctx.ch (Buffer.contents ctx.buf);
-	close_out ctx.ch
-
-let gen_local ctx l =
-	ctx.gen_uid <- ctx.gen_uid + 1;
-	if ctx.gen_uid = 1 then l else l ^ string_of_int ctx.gen_uid
-
-let spr ctx s = Buffer.add_string ctx.buf s
-let print ctx = Printf.kprintf (fun s -> Buffer.add_string ctx.buf s)
-
-let unsupported p = abort "This expression cannot be generated to AS3" p
-
-let newline ctx =
-	let rec loop p =
-		match Buffer.nth ctx.buf p with
-		| '}' | '{' | ':' | ';' -> print ctx "\n%s" ctx.tabs
-		| '\n' | '\t' -> loop (p - 1)
-		| _ -> print ctx ";\n%s" ctx.tabs
-	in
-	loop (Buffer.length ctx.buf - 1)
-
-let block_newline ctx = match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with
-	| '}' -> print ctx ";\n%s" ctx.tabs
-	| _ -> newline ctx
-
-let rec concat ctx s f = function
-	| [] -> ()
-	| [x] -> f x
-	| x :: l ->
-		f x;
-		spr ctx s;
-		concat ctx s f l
-
-let open_block ctx =
-	let oldt = ctx.tabs in
-	ctx.tabs <- "\t" ^ ctx.tabs;
-	(fun() -> ctx.tabs <- oldt)
-
-let parent e =
-	match e.eexpr with
-	| TParenthesis _ -> e
-	| _ -> mk (TParenthesis e) e.etype e.epos
-
-let default_value tstr =
-	match tstr with
-	| "int" | "uint" -> "0"
-	| "Number" -> "NaN"
-	| "Boolean" -> "false"
-	| _ -> "null"
-
-let rec type_str ctx t p =
-	match t with
-	| TEnum _ | TInst _ when List.memq t ctx.local_types ->
-		"*"
-	| TAbstract ({a_path = [],"Null"},[t]) ->
-		(match follow t with
-		| TAbstract ({ a_path = [],"UInt" },_)
-		| TAbstract ({ a_path = [],"Int" },_)
-		| TAbstract ({ a_path = [],"Float" },_)
-		| TAbstract ({ a_path = [],"Bool" },_) -> "*"
-		| _ -> type_str ctx t p)
-	| TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
-		type_str ctx (Abstract.get_underlying_type a pl) p
-	| TAbstract (a,_) ->
-		(match a.a_path with
-		| [], "Void" -> "void"
-		| [], "UInt" -> "uint"
-		| [], "Int" -> "int"
-		| [], "Float" -> "Number"
-		| [], "Bool" -> "Boolean"
-		| ["flash"], "AnyType" -> "*"
-		| _ -> s_path ctx true a.a_path p)
-	| TEnum (e,_) ->
-		if e.e_extern then "Object" else s_path ctx true e.e_path p
-	| TInst ({ cl_path = ["flash"],"Vector" },[pt]) ->
-		(match pt with
-		| TInst({cl_kind = KTypeParameter _},_) -> "*"
-		| _ -> "Vector.<" ^ type_str ctx pt p ^ ">")
-	| TInst (c,_) ->
-		(match c.cl_kind with
-		| KNormal | KGeneric | KGenericInstance _ | KAbstractImpl _ -> s_path ctx false c.cl_path p
-		| KTypeParameter _ | KExpr _ | KMacroType | KGenericBuild _ -> "*")
-	| TFun _ ->
-		"Function"
-	| TMono r ->
-		(match r.tm_type with None -> "*" | Some t -> type_str ctx t p)
-	| TAnon _ | TDynamic _ ->
-		"*"
-	| TType (t,args) ->
-		(match t.t_path with
-		| [], "UInt" -> "uint"
-		| _ -> type_str ctx (apply_params t.t_params args t.t_type) p)
-	| TLazy f ->
-		type_str ctx (lazy_type f) p
-
-let rec iter_switch_break in_switch e =
-	match e.eexpr with
-	| TFunction _ | TWhile _ | TFor _ -> ()
-	| TSwitch _ when not in_switch -> iter_switch_break true e
-	| TBreak when in_switch -> raise Exit
-	| _ -> iter (iter_switch_break in_switch) e
-
-let handle_break ctx e =
-	let old_handle = ctx.handle_break in
-	try
-		iter_switch_break false e;
-		ctx.handle_break <- false;
-		(fun() -> ctx.handle_break <- old_handle)
-	with
-		Exit ->
-			spr ctx "try {";
-			let b = open_block ctx in
-			newline ctx;
-			ctx.handle_break <- true;
-			(fun() ->
-				b();
-				ctx.handle_break <- old_handle;
-				newline ctx;
-				spr ctx "} catch( e : * ) { if( e != \"__break__\" ) throw e; }";
-			)
-
-let this ctx = if ctx.in_value <> None then "$this" else "this"
-
-let generate_resources infos =
-	if Hashtbl.length infos.com.resources <> 0 then begin
-		let dir = (infos.com.file :: ["__res"]) in
-		create_dir [] dir;
-		let add_resource name data =
-			let name = Bytes.unsafe_to_string (Base64.str_encode name) in
-			let ch = open_out_bin (String.concat "/" (dir @ [name])) in
-			output_string ch data;
-			close_out ch
-		in
-		Hashtbl.iter (fun name data -> add_resource name data) infos.com.resources;
-		let ctx = init infos ([],"__resources__") in
-		spr ctx "\timport flash.utils.Dictionary;\n";
-		spr ctx "\tpublic class __resources__ {\n";
-		spr ctx "\t\tpublic static var list:Dictionary;\n";
-		let inits = ref [] in
-		let k = ref 0 in
-		Hashtbl.iter (fun name _ ->
-			let varname = ("v" ^ (string_of_int !k)) in
-			k := !k + 1;
-			print ctx "\t\t[Embed(source = \"__res/%s\", mimeType = \"application/octet-stream\")]\n" (Bytes.unsafe_to_string (Base64.str_encode name));
-			print ctx "\t\tpublic static var %s:Class;\n" varname;
-			inits := ("list[\"" ^ StringHelper.s_escape name ^ "\"] = " ^ varname ^ ";") :: !inits;
-		) infos.com.resources;
-		spr ctx "\t\tstatic public function __init__():void {\n";
-		spr ctx "\t\t\tlist = new Dictionary();\n";
-		List.iter (fun init ->
-			print ctx "\t\t\t%s\n" init
-		) !inits;
-		spr ctx "\t\t}\n";
-		spr ctx "\t}\n";
-		spr ctx "}";
-		close ctx;
-	end
-
-let gen_constant ctx p = function
-	| TInt i -> print ctx "%ld" i
-	| TFloat s -> spr ctx s
-	| TString s -> print ctx "\"%s\"" (StringHelper.s_escape s)
-	| TBool b -> spr ctx (if b then "true" else "false")
-	| TNull -> spr ctx "null"
-	| TThis -> spr ctx (this ctx)
-	| TSuper -> spr ctx "super"
-
-let rec gen_function_header ctx name f params p =
-	let old = ctx.in_value in
-	let old_t = ctx.local_types in
-	let old_bi = ctx.block_inits in
-	ctx.in_value <- None;
-	ctx.local_types <- List.map snd params @ ctx.local_types;
-	let init () =
- 		List.iter (fun (v,o) -> match o with
-			| Some c when is_nullable v.v_type && c.eexpr <> TConst TNull ->
-				newline ctx;
-				print ctx "if(%s==null) %s=" v.v_name v.v_name;
-				gen_expr ctx c;
-			| _ -> ()
-		) f.tf_args;
-		ctx.block_inits <- None;
-	in
-	ctx.block_inits <- Some init;
-	print ctx "function%s(" (match name with None -> "" | Some (n,meta) ->
-		let rec loop = function
-			| [] -> n
-			| (Meta.Getter,[Ast.EConst (Ast.Ident i),_],_) :: _ -> "get " ^ i
-			| (Meta.Setter,[Ast.EConst (Ast.Ident i),_],_) :: _ -> "set " ^ i
-			| _ :: l -> loop l
-		in
-		" " ^ loop meta
-	);
-	concat ctx "," (fun (v,c) ->
-		match v.v_name with
-			| "__arguments__" ->
-				print ctx "...__arguments__"
-			| _ ->
-				let tstr = type_str ctx v.v_type p in
-				print ctx "%s : %s" (s_ident v.v_name) tstr;
-				match c with
-				| None ->
-					if ctx.constructor_block then print ctx " = %s" (default_value tstr);
-				| Some ({eexpr = TConst _ } as e) ->
-					spr ctx " = ";
-					gen_expr ctx e
-				| _ ->
-					spr ctx " = null"
-	) f.tf_args;
-	print ctx ") : %s " (type_str ctx f.tf_type p);
-	(fun () ->
-		ctx.in_value <- old;
-		ctx.local_types <- old_t;
-		ctx.block_inits <- old_bi;
-	)
-
-and gen_call ctx e el r =
-	match e.eexpr , el with
-	| TCall (x,_) , el ->
-		spr ctx "(";
-		gen_value ctx e;
-		spr ctx ")";
-		spr ctx "(";
-		concat ctx "," (gen_value ctx) el;
-		spr ctx ")";
-	| TIdent "__is__" , [e1;e2] ->
-		gen_value ctx e1;
-		spr ctx " is ";
-		gen_value ctx e2;
-	| TIdent "__in__" , [e1;e2] ->
-		spr ctx "(";
-		gen_value ctx e1;
-		spr ctx " in ";
-		gen_value ctx e2;
-		spr ctx ")"
-	| TIdent "__as__", [e1;e2] ->
-		gen_value ctx e1;
-		spr ctx " as ";
-		gen_value ctx e2;
-	| TIdent "__int__", [e] ->
-		spr ctx "int(";
-		gen_value ctx e;
-		spr ctx ")";
-	| TIdent "__float__", [e] ->
-		spr ctx "Number(";
-		gen_value ctx e;
-		spr ctx ")";
-	| TIdent "__typeof__", [e] ->
-		spr ctx "typeof ";
-		gen_value ctx e;
-	| TIdent "__keys__", [e] ->
-		let ret = (match ctx.in_value with None -> assert false | Some r -> r) in
-		print ctx "%s = new Array()" ret.v_name;
-		newline ctx;
-		let tmp = gen_local ctx "$k" in
-		print ctx "for(var %s : String in " tmp;
-		gen_value ctx e;
-		print ctx ") %s.push(%s)" ret.v_name tmp;
-	| TIdent "__hkeys__", [e] ->
-		let ret = (match ctx.in_value with None -> assert false | Some r -> r) in
-		print ctx "%s = new Array()" ret.v_name;
-		newline ctx;
-		let tmp = gen_local ctx "$k" in
-		print ctx "for(var %s : String in " tmp;
-		gen_value ctx e;
-		print ctx ") %s.push(%s.substr(1))" ret.v_name tmp;
-	| TIdent "__foreach__", [e] ->
-		let ret = (match ctx.in_value with None -> assert false | Some r -> r) in
-		print ctx "%s = new Array()" ret.v_name;
-		newline ctx;
-		let tmp = gen_local ctx "$k" in
-		print ctx "for each(var %s : * in " tmp;
-		gen_value ctx e;
-		print ctx ") %s.push(%s)" ret.v_name tmp;
-	| TIdent "__new__", e :: args ->
-		spr ctx "new ";
-		gen_value ctx e;
-		spr ctx "(";
-		concat ctx "," (gen_value ctx) args;
-		spr ctx ")";
-	| TIdent "__delete__", [e;f] ->
-		spr ctx "delete(";
-		gen_value ctx e;
-		spr ctx "[";
-		gen_value ctx f;
-		spr ctx "]";
-		spr ctx ")";
-	| TIdent "__unprotect__", [e] ->
-		gen_value ctx e
-	| TIdent "__vector__", [] ->
-		let t = match r with TAbstract ({a_path = [],"Class"}, [vt]) -> vt | _ -> assert false in
-		spr ctx (type_str ctx t e.epos);
-	| TIdent "__vector__", [e] ->
-		spr ctx (type_str ctx r e.epos);
-		spr ctx "(";
-		gen_value ctx e;
-		spr ctx ")"
-	| TField (_, FStatic( { cl_path = (["flash"],"Lib") }, { cf_name = "as" })), [e1;e2] ->
-		gen_value ctx e1;
-		spr ctx " as ";
-		gen_value ctx e2
-	| TField (_, FStatic ({ cl_path = (["flash"],"Vector") }, cf)), args ->
-		(match cf.cf_name, args with
-		| "ofArray", [e] | "convert", [e] ->
-			(match follow r with
-			| TInst ({ cl_path = (["flash"],"Vector") },[t]) ->
-				print ctx "Vector.<%s>(" (type_str ctx t e.epos);
-				gen_value ctx e;
-				print ctx ")";
-			| _ -> assert false)
-		| _ -> assert false)
-	| TField(e1, (FAnon {cf_name = s} | FDynamic s)),[ef] when s = "map" || s = "filter" ->
-		spr ctx (s_path ctx true (["flash";],"Boot") e.epos);
-		gen_field_access ctx t_dynamic (s ^ "Dynamic");
-		spr ctx "(";
-		concat ctx "," (gen_value ctx) [e1;ef];
-		spr ctx ")"
-	| TField (ee,f), args when is_var_field f ->
-		spr ctx "(";
-		gen_value ctx e;
-		spr ctx ")";
-		spr ctx "(";
-		concat ctx "," (gen_value ctx) el;
-		spr ctx ")"
-	| TField (e1,FInstance(_,_,cf)),el when is_fixed_override cf e.etype ->
-		let s = type_str ctx r e.epos in
-		spr ctx "((";
-		gen_value ctx e;
-		spr ctx "(";
-		concat ctx "," (gen_value ctx) el;
-		spr ctx ")";
-		print ctx ") as %s)" s
-	| TField (e1, f), el ->
-		begin
-		let default () = gen_call_default ctx e el in
-		let mk_prop_acccess prop_cl prop_tl prop_cf = mk (TField (e1, FInstance (prop_cl, prop_tl, prop_cf))) prop_cf.cf_type e.epos in
-		let mk_static_acccess cl prop_cf = mk (TField (e1, FStatic (cl, prop_cf))) prop_cf.cf_type e.epos in
-		let gen_assign lhs rhs = gen_expr ctx (mk (TBinop (OpAssign, lhs, rhs)) rhs.etype e.epos) in
-		match f, el with
-		| FInstance (cl, tl, cf), [] ->
-			(match is_extern_instance_accessor ~isget:true cl tl cf with
-			| Some (prop_cl, prop_tl, prop_cf) ->
-				let efield = mk_prop_acccess prop_cl prop_tl prop_cf in
-				gen_expr ctx efield
-			| None ->
-				default ())
-
-		| FInstance (cl, tl, cf), [evalue] ->
-			(match is_extern_instance_accessor ~isget:false cl tl cf with
-			| Some (prop_cl, prop_tl, prop_cf) ->
-				let efield = mk_prop_acccess prop_cl prop_tl prop_cf in
-				gen_assign efield evalue
-			| None ->
-				default ())
-
-		| FStatic (cl, cf), [] ->
-			(match is_extern_static_accessor ~isget:true cl cf with
-			| Some prop_cf ->
-				let efield = mk_static_acccess cl prop_cf in
-				gen_expr ctx efield
-			| None ->
-				default ())
-
-		| FStatic (cl, cf), [evalue] ->
-			(match is_extern_static_accessor ~isget:false cl cf with
-			| Some prop_cf ->
-				let efield = mk_static_acccess cl prop_cf in
-				gen_assign efield evalue
-			| None ->
-				default ())
-		| _ ->
-			default ()
-		end
-	| _ ->
-		gen_call_default ctx e el
-
-and gen_call_default ctx e el =
-	gen_value ctx e;
-	spr ctx "(";
-	concat ctx "," (gen_value ctx) el;
-	spr ctx ")"
-
-and gen_value_op ctx e =
-	match e.eexpr with
-	| TBinop (op,_,_) when op = Ast.OpAnd || op = Ast.OpOr || op = Ast.OpXor ->
-		spr ctx "(";
-		gen_value ctx e;
-		spr ctx ")";
-	| _ ->
-		gen_value ctx e
-
-and gen_field_access ctx t s =
-	let field c =
-		match fst c.cl_path, snd c.cl_path, s with
-		| [], "Math", "NaN"
-		| [], "Math", "NEGATIVE_INFINITY"
-		| [], "Math", "POSITIVE_INFINITY"
-		| [], "Math", "isFinite"
-		| [], "Math", "isNaN"
-		| [], "Date", "now"
-		| [], "Date", "fromTime"
-		| [], "Date", "fromString"
-		->
-			print ctx "[\"%s\"]" s
-		| [], "String", "charCodeAt" ->
-			spr ctx "[\"charCodeAtHX\"]"
-		| [], "Array", "map" ->
-			spr ctx "[\"mapHX\"]"
-		| [], "Array", "filter" ->
-			spr ctx "[\"filterHX\"]"
-		| [], "Date", "toString" ->
-			print ctx "[\"toStringHX\"]"
-		| [], "String", "cca" ->
-			print ctx ".charCodeAt"
-		| ["flash";"xml"], "XML", "namespace" ->
-			print ctx ".namespace"
-		| _ ->
-			print ctx ".%s" (s_ident s)
-	in
-	match follow t with
-	| TInst (c,_) -> field c
-	| TAnon a ->
-		(match !(a.a_status) with
-		| Statics c -> field c
-		| _ -> print ctx ".%s" (s_ident s))
-	| _ ->
-		print ctx ".%s" (s_ident s)
-
-and gen_expr ctx e =
-	match e.eexpr with
-	| TConst c ->
-		gen_constant ctx e.epos c
-	| TLocal v ->
-		spr ctx (s_ident v.v_name)
-	| TArray ({ eexpr = TIdent "__global__" },{ eexpr = TConst (TString s) }) ->
-		let path = Ast.parse_path s in
-		spr ctx (s_path ctx false path e.epos)
-	| TArray (e1,e2) ->
-		gen_value ctx e1;
-		spr ctx "[";
-		gen_value ctx e2;
-		spr ctx "]";
-	| TBinop (Ast.OpEq,e1,e2) when (match is_special_compare e1 e2 with Some c -> true | None -> false) ->
-		let c = match is_special_compare e1 e2 with Some c -> c | None -> assert false in
-		gen_expr ctx (mk (TCall (mk (TField (mk (TTypeExpr (TClassDecl c)) t_dynamic e.epos,FDynamic "compare")) t_dynamic e.epos,[e1;e2])) ctx.inf.com.basic.tbool e.epos);
-	(* what is this used for? *)
-(* 	| TBinop (op,{ eexpr = TField (e1,s) },e2) ->
-		gen_value_op ctx e1;
-		gen_field_access ctx e1.etype s;
-		print ctx " %s " (Ast.s_binop op);
-		gen_value_op ctx e2; *)
-	(* assignments to variable or dynamic methods fields on interfaces are generated as class["field"] = value *)
-	| TBinop (op,{eexpr = TField (ei, FInstance({cl_interface = true},_,{cf_kind = (Method MethDynamic | Var _); cf_name = s}))},e2) ->
-		gen_value ctx ei;
-		print ctx "[\"%s\"]" s;
-		print ctx " %s " (Ast.s_binop op);
-		gen_value_op ctx e2;
-	| TBinop (op,e1,e2) ->
-		gen_value_op ctx e1;
-		print ctx " %s " (Ast.s_binop op);
-		gen_value_op ctx e2;
-	(* variable fields and dynamic methods on interfaces are generated as (class["field"] as class) *)
-	| TField (ei, FInstance({cl_interface = true},_,{cf_kind = (Method MethDynamic | Var _); cf_name = s})) ->
-		spr ctx "(";
-		gen_value ctx ei;
-		print ctx "[\"%s\"]" s;
-		print ctx " as %s)" (type_str ctx e.etype e.epos);
-	| TField({eexpr = TArrayDecl _} as e1,s) ->
-		spr ctx "(";
-		gen_expr ctx e1;
-		spr ctx ")";
-		gen_field_access ctx e1.etype (field_name s)
-	| TEnumIndex e ->
-		gen_value ctx e;
-		print ctx ".index";
-	| TEnumParameter (e,_,i) ->
-		gen_value ctx e;
-		print ctx ".params[%i]" i;
-	| TField (e,s) ->
-		gen_value ctx e;
-		gen_field_access ctx e.etype (field_name s)
-	| TTypeExpr t ->
-		spr ctx (s_path ctx true (t_path t) e.epos)
-	| TParenthesis e ->
-		spr ctx "(";
-		gen_value ctx e;
-		spr ctx ")";
-	| TMeta (_,e) ->
-		gen_expr ctx e
-	| TReturn eo ->
-		if ctx.in_value <> None then unsupported e.epos;
-		(match eo with
-		| None ->
-			spr ctx "return"
-		| Some e when (match follow e.etype with TEnum({ e_path = [],"Void" },[]) | TAbstract ({ a_path = [],"Void" },[]) -> true | _ -> false) ->
-			print ctx "{";
-			let bend = open_block ctx in
-			newline ctx;
-			gen_value ctx e;
-			newline ctx;
-			spr ctx "return";
-			bend();
-			newline ctx;
-			print ctx "}";
-		| Some e ->
-			spr ctx "return ";
-			gen_value ctx e);
-	| TBreak ->
-		if ctx.in_value <> None then unsupported e.epos;
-		if ctx.handle_break then spr ctx "throw \"__break__\"" else spr ctx "break"
-	| TContinue ->
-		if ctx.in_value <> None then unsupported e.epos;
-		spr ctx "continue"
-	| TBlock el ->
-		print ctx "{";
-		let bend = open_block ctx in
-		let cb = (if not ctx.constructor_block then
-			(fun () -> ())
-		else if not (Texpr.constructor_side_effects e) then begin
-			ctx.constructor_block <- false;
-			(fun () -> ())
-		end else begin
-			ctx.constructor_block <- false;
-			print ctx " if( !%s.skip_constructor ) {" (s_path ctx true (["flash"],"Boot") e.epos);
-			(fun() -> print ctx "}")
-		end) in
-		(match ctx.block_inits with None -> () | Some i -> i());
-		List.iter (fun e -> gen_block_element ctx e) el;
-		bend();
-		newline ctx;
-		cb();
-		print ctx "}";
-	| TFunction f ->
-		let h = gen_function_header ctx None f [] e.epos in
-		let old = ctx.in_static in
-		ctx.in_static <- true;
-		gen_expr ctx f.tf_expr;
-		ctx.in_static <- old;
-		h();
-	| TCall (v,el) ->
-		gen_call ctx v el e.etype
-	| TArrayDecl el ->
-		spr ctx "[";
-		concat ctx "," (gen_value ctx) el;
-		spr ctx "]"
-	| TThrow e ->
-		spr ctx "throw ";
-		gen_value ctx e;
-	| TVar (v,eo) ->
-		spr ctx "var ";
-		print ctx "%s : %s" (s_ident v.v_name) (type_str ctx v.v_type e.epos);
-		begin match eo with
-		| None -> ()
-		| Some e ->
-			spr ctx " = ";
-			gen_value ctx e
-		end
-	| TNew (c,params,el) ->
-		(match c.cl_path, params with
-		| (["flash"],"Vector"), [pt] -> print ctx "new Vector.<%s>(" (type_str ctx pt e.epos)
-		| _ -> print ctx "new %s(" (s_path ctx true c.cl_path e.epos));
-		concat ctx "," (gen_value ctx) el;
-		spr ctx ")"
-	| TIf (cond,e,eelse) ->
-		spr ctx "if";
-		gen_value ctx (parent cond);
-		spr ctx " ";
-		gen_expr ctx e;
-		(match eelse with
-		| None -> ()
-		| Some e ->
-			newline ctx;
-			spr ctx "else ";
-			gen_expr ctx e);
-	| TUnop (op,Ast.Prefix,e) ->
-		spr ctx (Ast.s_unop op);
-		gen_value ctx e
-	| TUnop (op,Ast.Postfix,e) ->
-		gen_value ctx e;
-		spr ctx (Ast.s_unop op)
-	| TWhile (cond,e,Ast.NormalWhile) ->
-		let handle_break = handle_break ctx e in
-		spr ctx "while";
-		gen_value ctx (parent cond);
-		spr ctx " ";
-		gen_expr ctx e;
-		handle_break();
-	| TWhile (cond,e,Ast.DoWhile) ->
-		let handle_break = handle_break ctx e in
-		spr ctx "do ";
-		gen_expr ctx e;
-		spr ctx " while";
-		gen_value ctx (parent cond);
-		handle_break();
-	| TObjectDecl fields ->
-		spr ctx "{ ";
-		concat ctx ", " (fun ((f,_,_),e) -> print ctx "%s : " (anon_field f); gen_value ctx e) fields;
-		spr ctx "}"
-	| TFor (v,it,e) ->
-		let handle_break = handle_break ctx e in
-		let tmp = gen_local ctx "$it" in
-		print ctx "{ var %s : * = " tmp;
-		gen_value ctx it;
-		newline ctx;
-		print ctx "while( %s.hasNext() ) { var %s : %s = %s.next()" tmp (s_ident v.v_name) (type_str ctx v.v_type e.epos) tmp;
-		newline ctx;
-		gen_expr ctx e;
-		newline ctx;
-		spr ctx "}}";
-		handle_break();
-	| TTry (e,catchs) ->
-		spr ctx "try ";
-		gen_expr ctx e;
-		List.iter (fun (v,e) ->
-			newline ctx;
-			print ctx "catch( %s : %s )" (s_ident v.v_name) (type_str ctx v.v_type e.epos);
-			gen_expr ctx e;
-		) catchs;
-	| TSwitch (e,cases,def) ->
-		spr ctx "switch";
-		gen_value ctx (parent e);
-		spr ctx " {";
-		newline ctx;
-		List.iter (fun (el,e2) ->
-			List.iter (fun e ->
-				spr ctx "case ";
-				gen_value ctx e;
-				spr ctx ":";
-			) el;
-			gen_block ctx e2;
-			print ctx "break";
-			newline ctx;
-		) cases;
-		(match def with
-		| None -> ()
-		| Some e ->
-			spr ctx "default:";
-			gen_block ctx e;
-			print ctx "break";
-			newline ctx;
-		);
-		spr ctx "}"
-	| TCast (e1,None) ->
-		let s = type_str ctx e.etype e.epos in
-		if s = "*" then
-			gen_expr ctx e1
-		else begin
-			spr ctx "((";
-			gen_value ctx e1;
-			print ctx ") as %s)" s
-		end
-	| TCast (e1,Some t) ->
-		gen_expr ctx (Codegen.default_cast ctx.inf.com e1 t e.etype e.epos)
-	| TIdent s ->
-		spr ctx s
-
-and gen_block_element ctx e = match e.eexpr with
-	| TObjectDecl fl ->
-		List.iter (fun (_,e) -> gen_block_element ctx e) fl
-	| _ ->
-		block_newline ctx;
-		gen_expr ctx e
-
-and gen_block ctx e =
-	newline ctx;
-	match e.eexpr with
-	| TBlock [] -> ()
-	| _ ->
-		gen_expr ctx e;
-		newline ctx
-
-and gen_value ctx e =
-	let assign e =
-		mk (TBinop (Ast.OpAssign,
-			mk (TLocal (match ctx.in_value with None -> assert false | Some r -> r)) t_dynamic e.epos,
-			e
-		)) e.etype e.epos
-	in
-	let block e =
-		mk (TBlock [e]) e.etype e.epos
-	in
-	let value block =
-		let old = ctx.in_value in
-		let t = type_str ctx e.etype e.epos in
-		let r = alloc_var VGenerated (gen_local ctx "$r") e.etype e.epos in
-		ctx.in_value <- Some r;
-		if ctx.in_static then
-			print ctx "function() : %s " t
-		else
-			print ctx "(function($this:%s) : %s " (snd ctx.path) t;
-		let b = if block then begin
-			spr ctx "{";
-			let b = open_block ctx in
-			newline ctx;
-			print ctx "var %s : %s" r.v_name t;
-			newline ctx;
-			b
-		end else
-			(fun() -> ())
-		in
-		(fun() ->
-			if block then begin
-				newline ctx;
-				print ctx "return %s" r.v_name;
-				b();
-				newline ctx;
-				spr ctx "}";
-			end;
-			ctx.in_value <- old;
-			if ctx.in_static then
-				print ctx "()"
-			else
-				print ctx "(%s))" (this ctx)
-		)
-	in
-	match e.eexpr with
-	| TCall ({ eexpr = TIdent "__keys__" },_) | TCall ({ eexpr = TIdent "__hkeys__" },_) ->
-		let v = value true in
-		gen_expr ctx e;
-		v()
-	| TConst _
-	| TLocal _
-	| TArray _
-	| TBinop _
-	| TField _
-	| TEnumParameter _
-	| TEnumIndex _
-	| TTypeExpr _
-	| TParenthesis _
-	| TObjectDecl _
-	| TArrayDecl _
-	| TCall _
-	| TNew _
-	| TUnop _
-	| TFunction _
-	| TIdent _ ->
-		gen_expr ctx e
-	| TMeta (_,e1) ->
-		gen_value ctx e1
-	| TCast (e1,None) ->
-		let s = type_str ctx e.etype e1.epos in
-		begin match s with
-		| "*" ->
-			gen_value ctx e1
-		| "Function" | "Array" | "String" ->
-			spr ctx "((";
-			gen_value ctx e1;
-			print ctx ") as %s)" s;
-		| _ ->
-			print ctx "%s(" s;
-			gen_value ctx e1;
-			spr ctx ")";
-		end
-	| TCast (e1,Some t) ->
-		gen_value ctx (Codegen.default_cast ctx.inf.com e1 t e.etype e.epos)
-	| TReturn _
-	| TBreak
-	| TContinue ->
-		unsupported e.epos
-	| TVar _
-	| TFor _
-	| TWhile _
-	| TThrow _ ->
-		(* value is discarded anyway *)
-		let v = value true in
-		gen_expr ctx e;
-		v()
-	| TBlock [] ->
-		spr ctx "null"
-	| TBlock [e] ->
-		gen_value ctx e
-	| TBlock el ->
-		let v = value true in
-		let rec loop = function
-			| [] ->
-				spr ctx "return null";
-			| [e] ->
-				gen_expr ctx (assign e);
-			| e :: l ->
-				gen_expr ctx e;
-				newline ctx;
-				loop l
-		in
-		loop el;
-		v();
-	| TIf (cond,e,eo) ->
-		spr ctx "(";
-		gen_value ctx cond;
-		spr ctx "?";
-		gen_value ctx e;
-		spr ctx ":";
-		(match eo with
-		| None -> spr ctx "null"
-		| Some e -> gen_value ctx e);
-		spr ctx ")"
-	| TSwitch (cond,cases,def) ->
-		let v = value true in
-		gen_expr ctx (mk (TSwitch (cond,
-			List.map (fun (e1,e2) -> (e1,assign e2)) cases,
-			match def with None -> None | Some e -> Some (assign e)
-		)) e.etype e.epos);
-		v()
-	| TTry (b,catchs) ->
-		let v = value true in
-		gen_expr ctx (mk (TTry (block (assign b),
-			List.map (fun (v,e) -> v, block (assign e)) catchs
-		)) e.etype e.epos);
-		v()
-
-let generate_field ctx static f =
-	newline ctx;
-	ctx.in_static <- static;
-	ctx.gen_uid <- 0;
-	List.iter (fun(m,pl,_) ->
-		match m,pl with
-		| Meta.Meta, [Ast.ECall ((Ast.EConst (Ast.Ident n),_),args),_] ->
-			let mk_arg (a,p) =
-				match a with
-				| Ast.EConst (Ast.String(s,_)) -> (None, s)
-				| Ast.EBinop (Ast.OpAssign,(Ast.EConst (Ast.Ident n),_),(Ast.EConst (Ast.String(s,_)),_)) -> (Some n, s)
-				| _ -> abort "Invalid meta definition" p
-			in
-			print ctx "[%s" n;
-			(match args with
-			| [] -> ()
-			| _ ->
-				print ctx "(";
-				concat ctx "," (fun a ->
-					match mk_arg a with
-					| None, s -> gen_constant ctx (snd a) (TString s)
-					| Some s, e -> print ctx "%s=" s; gen_constant ctx (snd a) (TString e)
-				) args;
-				print ctx ")");
-			print ctx "]";
-		| _ -> ()
-	) f.cf_meta;
-	let cfl_overridden = TClass.get_overridden_fields ctx.curclass f in
-	let overrides_public = List.exists (fun cf -> Meta.has Meta.Public cf.cf_meta) cfl_overridden in
-	let public = (has_class_field_flag f CfPublic) || Hashtbl.mem ctx.get_sets (f.cf_name,static) || (f.cf_name = "main" && static)
-		|| f.cf_name = "resolve" || Meta.has Meta.Public f.cf_meta
-		(* consider all abstract methods public to avoid issues with inlined private access *)
-	    || (match ctx.curclass.cl_kind with KAbstractImpl _ -> true | _ -> false)
-		|| overrides_public
-	in
-	let rights = (if static then "static " else "") ^ (if public then "public" else "protected") in
-	let p = ctx.curclass.cl_pos in
-	match f.cf_expr, f.cf_kind with
-	| Some { eexpr = TFunction fd }, Method (MethNormal | MethInline) ->
-		print ctx "%s%s " rights (if static || not (has_class_field_flag f CfFinal) then "" else " final ");
-		let rec loop c =
-			match c.cl_super with
-			| None -> ()
-			| Some (c,_) ->
-				if PMap.mem f.cf_name c.cl_fields then
-					spr ctx "override "
-				else
-					loop c
-		in
-		if not static then loop ctx.curclass;
-		let h = gen_function_header ctx (Some (s_ident f.cf_name, f.cf_meta)) fd f.cf_params p in
-		gen_expr ctx fd.tf_expr;
-		h();
-		newline ctx
-	| _ ->
-		let is_getset = (match f.cf_kind with Var { v_read = AccCall } | Var { v_write = AccCall } -> true | _ -> false) in
-		if ctx.curclass.cl_interface then
-			match follow f.cf_type with
-			| TFun (args,r) when (match f.cf_kind with Method MethDynamic | Var _ -> false | _ -> true) ->
-				let rec loop = function
-					| [] -> f.cf_name
-					| (Meta.Getter,[Ast.EConst (Ast.String(name,_)),_],_) :: _ -> "get " ^ name
-					| (Meta.Setter,[Ast.EConst (Ast.String(name,_)),_],_) :: _ -> "set " ^ name
-					| _ :: l -> loop l
-				in
-				print ctx "function %s(" (loop f.cf_meta);
-				concat ctx "," (fun (arg,o,t) ->
-					let tstr = type_str ctx t p in
-					print ctx "%s : %s" arg tstr;
-					if o then print ctx " = %s" (default_value tstr);
-				) args;
-				print ctx ") : %s " (type_str ctx r p);
-			| _ -> ()
-		else
-		let gen_init () = match f.cf_expr with
-			| None -> ()
-			| Some e ->
-				if not static || (match e.eexpr with | TConst _ | TFunction _ | TTypeExpr _ -> true | _ -> false) then begin
-					print ctx " = ";
-					gen_value ctx e
-				end else
-					Codegen.ExtClass.add_static_init ctx.curclass f e e.epos
-		in
-		if is_getset then begin
-			let t = type_str ctx f.cf_type p in
-			let id = s_ident f.cf_name in
-			let v = (match f.cf_kind with Var v -> v | _ -> assert false) in
- 			(match v.v_read with
-			| AccNormal | AccNo | AccNever ->
-				print ctx "%s function get %s() : %s { return $%s; }" rights id t id;
-				newline ctx
-			| AccCall ->
-				print ctx "%s function get %s() : %s { return %s(); }" rights id t ("get_" ^ f.cf_name);
-				newline ctx
-			| _ -> ());
-			(match v.v_write with
-			| AccNormal | AccNo | AccNever ->
-				print ctx "%s function set %s( __v : %s ) : void { $%s = __v; }" rights id t id;
-				newline ctx
-			| AccCall ->
-				print ctx "%s function set %s( __v : %s ) : void { %s(__v); }" rights id t ("set_" ^ f.cf_name);
-				newline ctx
-			| _ -> ());
-			print ctx "%sprotected var $%s : %s" (if static then "static " else "") (s_ident f.cf_name) (type_str ctx f.cf_type p);
-			gen_init()
-		end else begin
-			print ctx "%s var %s : %s" rights (s_ident f.cf_name) (type_str ctx f.cf_type p);
-			gen_init()
-		end
-
-let rec define_getset ctx stat c =
-	let def f name =
-		Hashtbl.add ctx.get_sets (name,stat) f.cf_name
-	in
-	let field f =
-		match f.cf_kind with
-		| Method _ -> ()
-		| Var v ->
-			(match v.v_read with AccCall -> def f ("get_" ^ f.cf_name) | _ -> ());
-			(match v.v_write with AccCall -> def f ("set_" ^ f.cf_name) | _ -> ())
-	in
-	List.iter field (if stat then c.cl_ordered_statics else c.cl_ordered_fields);
-	match c.cl_super with
-	| Some (c,_) when not stat -> define_getset ctx stat c
-	| _ -> ()
-
-let generate_class ctx c =
-	ctx.curclass <- c;
-	define_getset ctx true c;
-	define_getset ctx false c;
-	ctx.local_types <- List.map snd c.cl_params;
-	let pack = open_block ctx in
-	print ctx "\tpublic %s%s%s %s " (if c.cl_final then " final " else "") "" (if c.cl_interface then "interface" else "class") (snd c.cl_path);
-	(match c.cl_super with
-	| None -> ()
-	| Some (csup,_) -> print ctx "extends %s " (s_path ctx true csup.cl_path c.cl_pos));
-	(match c.cl_implements with
-	| [] -> ()
-	| l ->
-		spr ctx (if c.cl_interface then "extends " else "implements ");
-		concat ctx ", " (fun (i,_) -> print ctx "%s" (s_path ctx true i.cl_path c.cl_pos)) l);
-	spr ctx "{";
-	let cl = open_block ctx in
-	(match c.cl_constructor with
-	| None -> ()
-	| Some f ->
-		let f = { f with
-			cf_name = snd c.cl_path;
-			cf_flags = set_flag f.cf_flags (int_of_class_field_flag CfPublic);
-			cf_kind = Method MethNormal;
-		} in
-		ctx.constructor_block <- true;
-		generate_field ctx false f;
-	);
-	List.iter (generate_field ctx false) c.cl_ordered_fields;
-	List.iter (generate_field ctx true) c.cl_ordered_statics;
-	let has_init = match c.cl_init with
-		| None -> false
-		| Some e ->
-			newline ctx;
-			spr ctx "static static_init function init() : void";
-			gen_expr ctx (mk_block e);
-			true;
-	in
-	cl();
-	newline ctx;
-	print ctx "}";
-	pack();
-	newline ctx;
-	print ctx "}";
-	if has_init then begin
-		newline ctx;
-		spr ctx "namespace static_init";
-		newline ctx;
-		print ctx "%s.static_init::init()" (s_path ctx true ctx.curclass.cl_path Globals.null_pos);
-	end;
-	newline ctx;
-	if c.cl_interface && Meta.has (Meta.Custom ":hasMetadata") c.cl_meta then begin
-		(* we have to reference the metadata class in order for it to be compiled *)
-		let path = fst c.cl_path,snd c.cl_path ^ "_HxMeta" in
-		spr ctx (Globals.s_type_path path);
-		newline ctx
-	end
-
-let generate_main ctx inits =
-	ctx.curclass <- { null_class with cl_path = [],"__main__" };
-	let pack = open_block ctx in
-	print ctx "\timport flash.Lib";
-	newline ctx;
-	print ctx "public class __main__ extends %s {" (s_path ctx true (["flash"],"Boot") Globals.null_pos);
-	let cl = open_block ctx in
-	newline ctx;
-	spr ctx "public function __main__() {";
-	let fl = open_block ctx in
-	newline ctx;
-	spr ctx "super()";
-	newline ctx;
-	spr ctx "flash.Lib.current = this";
-	List.iter (fun e -> newline ctx; gen_expr ctx e) inits;
-	fl();
-	newline ctx;
-	print ctx "}";
-	cl();
-	newline ctx;
-	print ctx "}";
-	pack();
-	newline ctx;
-	print ctx "}";
-	newline ctx
-
-let generate_enum ctx e =
-	ctx.local_types <- List.map snd e.e_params;
-	let pack = open_block ctx in
-	let ename = snd e.e_path in
-	print ctx "\tpublic final class %s extends enum {" ename;
-	let cl = open_block ctx in
-	newline ctx;
-	print ctx "public static const __isenum : Boolean = true";
-	newline ctx;
-	print ctx "public function %s( t : String, index : int, p : Array = null ) : void { this.tag = t; this.index = index; this.params = p; }" ename;
-	PMap.iter (fun _ c ->
-		newline ctx;
-		match c.ef_type with
-		| TFun (args,_) ->
-			print ctx "public static function %s(" c.ef_name;
-			concat ctx ", " (fun (a,o,t) ->
-				print ctx "%s : %s" (s_ident a) (type_str ctx t c.ef_pos);
-				if o then spr ctx " = null";
-			) args;
-			print ctx ") : %s {" ename;
-			print ctx " return new %s(\"%s\",%d,[" ename c.ef_name c.ef_index;
-			concat ctx "," (fun (a,_,_) -> spr ctx (s_ident a)) args;
-			print ctx "]); }";
-		| _ ->
-			print ctx "public static var %s : %s = new %s(\"%s\",%d)" c.ef_name ename ename c.ef_name c.ef_index;
-	) e.e_constrs;
-	newline ctx;
-	(match Texpr.build_metadata ctx.inf.com.basic (TEnumDecl e) with
-	| None -> ()
-	| Some e ->
-		print ctx "public static var __meta__ : * = ";
-		gen_expr ctx e;
-		newline ctx);
-	print ctx "public static var __constructs__ : Array = [%s];" (String.concat "," (List.map (fun s -> "\"" ^ StringHelper.s_escape s ^ "\"") e.e_names));
-	cl();
-	newline ctx;
-	print ctx "}";
-	pack();
-	newline ctx;
-	print ctx "}";
-	newline ctx
-
-let generate_base_enum ctx =
-	let pack = open_block ctx in
-	spr ctx "\timport flash.Boot";
-	newline ctx;
-	spr ctx "public class enum {";
-	let cl = open_block ctx in
-	newline ctx;
-	spr ctx "public var tag : String";
-	newline ctx;
-	spr ctx "public var index : int";
-	newline ctx;
-	spr ctx "public var params : Array";
-	newline ctx;
-	spr ctx "public function toString() : String { return flash.Boot.enum_to_string(this); }";
-	cl();
-	newline ctx;
-	print ctx "}";
-	pack();
-	newline ctx;
-	print ctx "}";
-	newline ctx
-
-let generate com =
-	com.warning "-as3 target is deprecated. Use -swf instead. See https://github.com/HaxeFoundation/haxe/issues/8295" Globals.null_pos;
-	let infos = {
-		com = com;
-	} in
-	generate_resources infos;
-	let ctx = init infos ([],"enum") in
-	generate_base_enum ctx;
-	close ctx;
-	let inits = ref [] in
-	List.iter (fun t ->
-		match t with
-		| TClassDecl c ->
-			let c = (match c.cl_path with
-				| ["flash"],"FlashXml__" -> { c with cl_path = [],"Xml" }
-				| (pack,name) -> { c with cl_path = (pack,protect name) }
-			) in
-			if c.cl_extern then
-				(match c.cl_init with
-				| None -> ()
-				| Some e -> inits := e :: !inits)
-			else
-				let ctx = init infos c.cl_path in
-				generate_class ctx c;
-				close ctx
-		| TEnumDecl e ->
-			let pack,name = e.e_path in
-			let e = { e with e_path = (pack,protect name) } in
-			if e.e_extern then
-				()
-			else
-				let ctx = init infos e.e_path in
-				generate_enum ctx e;
-				close ctx
-		| TTypeDecl _ | TAbstractDecl _ ->
-			()
-	) com.types;
-	(match com.main with
-	| None -> ()
-	| Some e -> inits := e :: !inits);
-	let ctx = init infos ([],"__main__") in
-	generate_main ctx (List.rev !inits);
-	close ctx

+ 8 - 9
src/generators/genjs.ml

@@ -352,7 +352,7 @@ let is_dynamic_iterator ctx e =
 				loop (Abstract.get_underlying_type a tl)
 				loop (Abstract.get_underlying_type a tl)
 			| _ -> false
 			| _ -> false
 		in
 		in
-		has_feature ctx "HxOverrides.iter" && loop x.etype
+		has_feature ctx "haxe.iterators.ArrayIterator.*" && loop x.etype
 	in
 	in
 	match e.eexpr with
 	match e.eexpr with
 	| TField (x,f) when field_name f = "iterator" -> check x
 	| TField (x,f) when field_name f = "iterator" -> check x
@@ -962,11 +962,8 @@ and gen_syntax ctx meth args pos =
 		in
 		in
 		begin
 		begin
 			match args with
 			match args with
-			| [] ->
-				if code = "this" then
-					spr ctx (this ctx)
-				else
-					spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n"))
+			| [] when code = "this" ->
+				spr ctx (this ctx)
 			| _ ->
 			| _ ->
 				Codegen.interpolate_code ctx.com code args (spr ctx) (gen_value ctx) code_pos
 				Codegen.interpolate_code ctx.com code args (spr ctx) (gen_value ctx) code_pos
 		end
 		end
@@ -1750,11 +1747,13 @@ let generate com =
 	List.iter (fun (_,_,e) -> chk_features e) ctx.statics;
 	List.iter (fun (_,_,e) -> chk_features e) ctx.statics;
 	if has_feature ctx "use.$iterator" then begin
 	if has_feature ctx "use.$iterator" then begin
 		add_feature ctx "use.$bind";
 		add_feature ctx "use.$bind";
-		print ctx "function $iterator(o) { if( o instanceof Array ) return function() { return HxOverrides.iter(o); }; return typeof(o.iterator) == 'function' ? $bind(o,o.iterator) : o.iterator; }";
+		let array_iterator = s_path ctx (["haxe"; "iterators"], "ArrayIterator") in
+		print ctx "function $iterator(o) { if( o instanceof Array ) return function() { return new %s(o); }; return typeof(o.iterator) == 'function' ? $bind(o,o.iterator) : o.iterator; }" array_iterator;
 		newline ctx;
 		newline ctx;
 	end;
 	end;
 	if has_feature ctx "use.$getIterator" then begin
 	if has_feature ctx "use.$getIterator" then begin
-		print ctx "function $getIterator(o) { if( o instanceof Array ) return HxOverrides.iter(o); else return o.iterator(); }";
+		let array_iterator = s_path ctx (["haxe"; "iterators"], "ArrayIterator") in
+		print ctx "function $getIterator(o) { if( o instanceof Array ) return new %s(o); else return o.iterator(); }" array_iterator;
 		newline ctx;
 		newline ctx;
 	end;
 	end;
 	if has_feature ctx "use.$bind" then begin
 	if has_feature ctx "use.$bind" then begin
@@ -1776,7 +1775,7 @@ let generate com =
 	end;
 	end;
 	if has_feature ctx "$global.$haxeUID" then begin
 	if has_feature ctx "$global.$haxeUID" then begin
 		add_feature ctx "js.Lib.global";
 		add_feature ctx "js.Lib.global";
-		print ctx "if(typeof $global.$haxeUID == \"undefined\") $global.$haxeUID = 0;\n";
+		print ctx "$global.$haxeUID |= 0;\n";
 	end;
 	end;
 	List.iter (gen_block_element ~after:true ctx) (List.rev ctx.inits);
 	List.iter (gen_block_element ~after:true ctx) (List.rev ctx.inits);
 	List.iter (generate_static ctx) (List.rev ctx.statics);
 	List.iter (generate_static ctx) (List.rev ctx.statics);

+ 12 - 10
src/generators/genjvm.ml

@@ -43,11 +43,13 @@ let rec pow a b = match b with
 
 
 let java_hash s =
 let java_hash s =
 	let h = ref Int32.zero in
 	let h = ref Int32.zero in
-	let l = String.length s in
+	let l = UTF8.length s in
 	let i31 = Int32.of_int 31 in
 	let i31 = Int32.of_int 31 in
-	String.iteri (fun i char ->
-		let char = Int32.of_int (int_of_char char) in
-		h := Int32.add !h (Int32.mul char (pow i31 (l - (i + 1))))
+	let i = ref 0 in
+	UTF8.iter (fun char ->
+		let char = Int32.of_int (UCharExt.uint_code char) in
+		h := Int32.add !h (Int32.mul char (pow i31 (l - (!i + 1))));
+		incr i;
 	) s;
 	) s;
 	!h
 	!h
 
 
@@ -201,6 +203,7 @@ let rec jsignature_of_type stack t =
 			| ["java"],"Char16" -> TChar
 			| ["java"],"Char16" -> TChar
 			| [],"Single" -> TFloat
 			| [],"Single" -> TFloat
 			| [],"Float" -> TDouble
 			| [],"Float" -> TDouble
+			| [],"Void" -> void_sig
 			| [],"Null" ->
 			| [],"Null" ->
 				begin match tl with
 				begin match tl with
 				| [t] -> get_boxed_type (jsignature_of_type t)
 				| [t] -> get_boxed_type (jsignature_of_type t)
@@ -575,11 +578,8 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 	method expect_reference_type = jm#expect_reference_type
 	method expect_reference_type = jm#expect_reference_type
 
 
 	method cast t =
 	method cast t =
-		if follow t != t_dynamic then begin
-			let vt = self#vtype t in
-			jm#cast vt
-		end else
-			self#expect_reference_type
+		let vt = self#vtype t in
+		jm#cast vt
 
 
 	method cast_expect ret t = match ret with
 	method cast_expect ret t = match ret with
 		| RValue (Some jsig) -> jm#cast jsig
 		| RValue (Some jsig) -> jm#cast jsig
@@ -2759,7 +2759,9 @@ let debug_path path = match path with
 
 
 let is_extern_abstract a = match a.a_impl with
 let is_extern_abstract a = match a.a_impl with
 	| Some {cl_extern = true} -> true
 	| Some {cl_extern = true} -> true
-	| _ -> false
+	| _ -> match a.a_path with
+		| ([],("Void" | "Float" | "Int" | "Single" | "Bool" | "Null")) -> true
+		| _ -> false
 
 
 let generate_module_type ctx mt =
 let generate_module_type ctx mt =
 	failsafe (t_infos mt).mt_pos (fun () ->
 	failsafe (t_infos mt).mt_pos (fun () ->

+ 5 - 2
src/generators/genlua.ml

@@ -2060,11 +2060,14 @@ let generate com =
     List.iter (transform_multireturn ctx) com.types;
     List.iter (transform_multireturn ctx) com.types;
     List.iter (generate_type ctx) com.types;
     List.iter (generate_type ctx) com.types;
 
 
-    if has_feature ctx "use._bitop" || has_feature ctx "lua.Boot.clamp" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_bit_clamp.lua");
+    (* If bit ops are manually imported include the haxe wrapper for them *)
+    if has_feature ctx "use._bitop" then begin
         print_file (Common.find_file com "lua/_lua/_hx_bit.lua");
         print_file (Common.find_file com "lua/_lua/_hx_bit.lua");
     end;
     end;
 
 
+    (* integer clamping is always required, and will use bit ops if available *)
+    print_file (Common.find_file com "lua/_lua/_hx_bit_clamp.lua");
+
     (* Array is required, always patch it *)
     (* Array is required, always patch it *)
     println ctx "_hx_array_mt.__index = Array.prototype";
     println ctx "_hx_array_mt.__index = Array.prototype";
     newline ctx;
     newline ctx;

+ 89 - 25
src/generators/genphp7.ml

@@ -911,20 +911,18 @@ class class_wrapper (cls) =
 				match cls.cl_init with
 				match cls.cl_init with
 					| Some _ -> true
 					| Some _ -> true
 					| None ->
 					| None ->
-						let needs = ref false in
-						PMap.iter
-							(fun _ field ->
+						List.exists
+							(fun field ->
 								(* Skip `inline var` fields *)
 								(* Skip `inline var` fields *)
-								if not (is_inline_var field) then begin
-									if not !needs then needs := is_var_with_nonconstant_expr 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
-								end
+								not (is_inline_var field)
+								&& match field.cf_kind, field.cf_expr with
+									| Var _, Some { eexpr = TConst (TInt value) } -> value = Int32.min_int
+									| Var _, Some { eexpr = TConst _ } -> false
+									| Var _, Some _ -> true
+									| Method MethDynamic, _ -> true
+									| _ -> false
 							)
 							)
-							cls.cl_statics;
-						!needs
+							cls.cl_ordered_statics
 		(**
 		(**
 			Returns expression of a user-defined static __init__ method
 			Returns expression of a user-defined static __init__ method
 			@see http://old.haxe.org/doc/advanced/magic#initialization-magic
 			@see http://old.haxe.org/doc/advanced/magic#initialization-magic
@@ -2888,6 +2886,12 @@ class virtual type_builder ctx (wrapper:type_wrapper) =
 			Returns hx source file name where this type was declared
 			Returns hx source file name where this type was declared
 		*)
 		*)
 		method get_source_file : string = wrapper#get_source_file
 		method get_source_file : string = wrapper#get_source_file
+		(**
+			Get amount of arguments of a parent method.
+			Returns (mandatory_args_count * total_args_count)
+			Returns `None` if no such parent method exists.
+		*)
+		method private get_parent_method_args_count name is_static : (int * int) option = None
 		(**
 		(**
 			Writes type declaration line to output buffer.
 			Writes type declaration line to output buffer.
 			E.g. "class SomeClass extends Another implements IFace"
 			E.g. "class SomeClass extends Another implements IFace"
@@ -3078,10 +3082,10 @@ class virtual type_builder ctx (wrapper:type_wrapper) =
 		(**
 		(**
 			Writes method to output buffer
 			Writes method to output buffer
 		*)
 		*)
-		method private write_method name func =
+		method private write_method name func is_static =
 			match name with
 			match name with
 				| "__construct" -> self#write_constructor_declaration func
 				| "__construct" -> self#write_constructor_declaration func
-				| _ -> self#write_method_declaration name func
+				| _ -> self#write_method_declaration name func is_static
 		(**
 		(**
 			Writes constructor declaration (except visibility and `static` keywords) to output buffer
 			Writes constructor declaration (except visibility and `static` keywords) to output buffer
 		*)
 		*)
@@ -3097,15 +3101,42 @@ class virtual type_builder ctx (wrapper:type_wrapper) =
 			writer#indent_less;
 			writer#indent_less;
 			writer#write_with_indentation "}"
 			writer#write_with_indentation "}"
 		(**
 		(**
-			Writes method declaration (except visibility and `static` keywords) to output buffer
+			Writes method declaration (except visibility keywords) to output buffer
 		*)
 		*)
-		method private write_method_declaration name func =
+		method private write_method_declaration name func is_static =
+			if is_static then writer#write "static ";
 			let by_ref = if is_ref func.tf_type then "&" else "" in
 			let by_ref = if is_ref func.tf_type then "&" else "" in
 			writer#write ("function " ^ by_ref ^ name ^ " (");
 			writer#write ("function " ^ by_ref ^ name ^ " (");
-			write_args writer#write writer#write_function_arg func.tf_args;
+			let args =
+				if is_static then
+					self#align_args_to_parent_static_method func.tf_args name
+				else
+					func.tf_args
+			in
+			write_args writer#write writer#write_function_arg args;
 			writer#write ") ";
 			writer#write ") ";
 			if not (self#write_body_if_special_method name) then
 			if not (self#write_body_if_special_method name) then
 				writer#write_expr (inject_defaults ctx func)
 				writer#write_expr (inject_defaults ctx func)
+		(**
+		*)
+		method private align_args_to_parent_static_method args method_name =
+			match self#get_parent_method_args_count method_name true with
+				| None -> args
+				| Some (mandatory, total) ->
+					let default_value() = Some (mk (TConst TNull) t_dynamic null_pos) in
+					let next value = max 0 (value - 1) in
+					let rec loop args mandatory total =
+						match args with
+							| [] when total = 0 -> []
+							| [] ->
+								let arg_var = alloc_var VGenerated ("_" ^ (string_of_int total)) t_dynamic null_pos in
+								(arg_var, default_value()) :: loop args (next mandatory) (next total)
+							| (arg_var, None) :: rest when mandatory = 0 ->
+								(arg_var, default_value()) :: loop rest 0 (next total)
+							| arg :: rest ->
+								arg :: loop rest (next mandatory) (next total)
+					in
+					loop args mandatory total
 		(**
 		(**
 			Writes a body for a special method if `field` represents one.
 			Writes a body for a special method if `field` represents one.
 			Returns `true` if `field` is such a method.
 			Returns `true` if `field` is such a method.
@@ -3318,6 +3349,31 @@ class class_builder ctx (cls:tclass) =
 					ctx.pgc_common.types;
 					ctx.pgc_common.types;
 				not !hacked
 				not !hacked
 			end
 			end
+		(**
+			Get amount of arguments of a parent method.
+			Returns `None` if no such parent method exists.
+		*)
+		method private get_parent_method_args_count name is_static : (int * int) option =
+			match cls.cl_super with
+				| None -> None
+				| Some (cls, _) ->
+					let fields = if is_static then cls.cl_statics else cls.cl_fields in
+					try
+						match (PMap.find name fields).cf_type with
+							| TFun (args,_) ->
+								let rec count args mandatory total =
+									match args with
+										| [] ->
+											(mandatory, total)
+										| (_, true, _) :: rest ->
+											let left_count = List.length args in
+											(mandatory, total + left_count)
+										| (_, false, _) :: rest ->
+											count rest (mandatory + 1) (total + 1)
+								in
+								Some (count args 0 0)
+							| _ -> None
+					with Not_found -> None
 		(**
 		(**
 			Indicates if `field` should be declared as `final`
 			Indicates if `field` should be declared as `final`
 		*)
 		*)
@@ -3531,13 +3587,13 @@ class class_builder ctx (cls:tclass) =
 				);
 				);
 				writer#write ";\n"
 				writer#write ";\n"
 			in
 			in
-			PMap.iter
-				(fun _ field ->
+			List.iter
+				(fun field ->
 					match field.cf_kind with
 					match field.cf_kind with
 						| Method MethDynamic -> write_dynamic_method_initialization field
 						| Method MethDynamic -> write_dynamic_method_initialization field
 						| _ -> ()
 						| _ -> ()
 				)
 				)
-				cls.cl_statics;
+				cls.cl_ordered_statics;
 			(* `static var` initialization *)
 			(* `static var` initialization *)
 			let write_var_initialization field =
 			let write_var_initialization field =
 				let write_assign expr =
 				let write_assign expr =
@@ -3548,8 +3604,8 @@ class class_builder ctx (cls:tclass) =
 					Do not generate fields for RTTI meta, because this generator uses another way to store it.
 					Do not generate fields for RTTI meta, because this generator uses another way to store it.
 					Also skip initialization for `inline var` fields as those are generated as PHP class constants.
 					Also skip initialization for `inline var` fields as those are generated as PHP class constants.
 				*)
 				*)
-				let is_auto_meta_var = field.cf_name = "__meta__" && (has_rtti_meta ctx.pgc_common wrapper#get_module_type) in
-				if (is_var_with_nonconstant_expr field) && (not is_auto_meta_var) && (not (is_inline_var field)) then begin
+				let is_auto_meta_var() = field.cf_name = "__meta__" && (has_rtti_meta ctx.pgc_common wrapper#get_module_type) in
+				if (is_var_with_nonconstant_expr field) && (not (is_auto_meta_var())) && (not (is_inline_var field)) then begin
 					(match field.cf_expr with
 					(match field.cf_expr with
 						| None -> ()
 						| None -> ()
 						(* There can be not-inlined blocks when compiling with `-debug` *)
 						(* There can be not-inlined blocks when compiling with `-debug` *)
@@ -3569,6 +3625,11 @@ class class_builder ctx (cls:tclass) =
 					);
 					);
 					writer#write ";\n"
 					writer#write ";\n"
 				end
 				end
+				else match field.cf_expr with
+					| Some ({ eexpr = TConst (TInt value) } as expr) when value = Int32.min_int ->
+						write_assign expr;
+						writer#write ";\n"
+					| _ -> ()
 			in
 			in
 			List.iter write_var_initialization cls.cl_ordered_statics
 			List.iter write_var_initialization cls.cl_ordered_statics
 		(**
 		(**
@@ -3597,7 +3658,10 @@ class class_builder ctx (cls:tclass) =
 			let visibility = get_visibility field.cf_meta in
 			let visibility = get_visibility field.cf_meta in
 			writer#write (visibility ^ " $" ^ (field_name field));
 			writer#write (visibility ^ " $" ^ (field_name field));
 			match field.cf_expr with
 			match field.cf_expr with
-				| None -> writer#write ";\n"
+				| None ->
+					writer#write ";\n"
+				| Some { eexpr = TConst (TInt value) } when value = Int32.min_int ->
+					writer#write ";\n"
 				| Some expr ->
 				| Some expr ->
 					match expr.eexpr with
 					match expr.eexpr with
 						| TConst _ ->
 						| TConst _ ->
@@ -3631,17 +3695,17 @@ class class_builder ctx (cls:tclass) =
 			self#write_doc (DocMethod (args, return_type, field.cf_doc));
 			self#write_doc (DocMethod (args, return_type, field.cf_doc));
 			writer#write_indentation;
 			writer#write_indentation;
 			if self#is_final_field field then writer#write "final ";
 			if self#is_final_field field then writer#write "final ";
-			if is_static then writer#write "static ";
 			writer#write ((get_visibility field.cf_meta) ^ " ");
 			writer#write ((get_visibility field.cf_meta) ^ " ");
 			match field.cf_expr with
 			match field.cf_expr with
 				| None ->
 				| None ->
+					if is_static then writer#write "static ";
 					writer#write ("function " ^ (field_name field) ^ " (");
 					writer#write ("function " ^ (field_name field) ^ " (");
 					write_args writer#write (writer#write_arg true) args;
 					write_args writer#write (writer#write_arg true) args;
 					writer#write ")";
 					writer#write ")";
 					writer#write " ;\n"
 					writer#write " ;\n"
 				| Some { eexpr = TFunction fn } ->
 				| Some { eexpr = TFunction fn } ->
 					let name = if field.cf_name = "new" then "__construct" else (field_name field) in
 					let name = if field.cf_name = "new" then "__construct" else (field_name field) in
-					self#write_method name fn;
+					self#write_method name fn is_static;
 					writer#write "\n"
 					writer#write "\n"
 				| _ -> fail field.cf_pos __POS__
 				| _ -> fail field.cf_pos __POS__
 		(**
 		(**

+ 58 - 62
src/generators/genpy.ml

@@ -157,13 +157,7 @@ module Transformer = struct
 					| _ ->
 					| _ ->
 						{ ae.a_expr with eexpr = TBlock (el @ [ae.a_expr])}
 						{ ae.a_expr with eexpr = TBlock (el @ [ae.a_expr])}
 
 
-	let lift_expr ?(is_value = false) ?(next_id = None) ?(blocks = []) e =
-		let next_id = match next_id with
-			| None ->
-				new_counter()
-			| Some f ->
-				f
-		in
+	let lift_expr ?(is_value = false) next_id ?(blocks = []) e =
 		{
 		{
 			a_expr = e;
 			a_expr = e;
 			a_blocks = blocks;
 			a_blocks = blocks;
@@ -172,7 +166,7 @@ module Transformer = struct
 		}
 		}
 
 
 	let lift_expr1 is_value next_id blocks e =
 	let lift_expr1 is_value next_id blocks e =
-		lift_expr ~is_value:is_value ~next_id:(Some next_id) ~blocks:blocks e
+		lift_expr ~is_value:is_value next_id ~blocks:blocks e
 
 
 	let alloc_var = Type.alloc_var VGenerated
 	let alloc_var = Type.alloc_var VGenerated
 
 
@@ -331,7 +325,7 @@ module Transformer = struct
 				let eb = mk (TBlock (List.rev assigns)) t_dynamic p in
 				let eb = mk (TBlock (List.rev assigns)) t_dynamic p in
 				Type.concat eb tf.tf_expr
 				Type.concat eb tf.tf_expr
 		in
 		in
-		let e1 = to_expr (transform_expr ~next_id:(Some ae.a_next_id) body) in
+		let e1 = to_expr (transform_expr ae.a_next_id body) in
 		let fn = mk (TFunction({
 		let fn = mk (TFunction({
 			tf_expr = e1;
 			tf_expr = e1;
 			tf_args = tf.tf_args;
 			tf_args = tf.tf_args;
@@ -345,7 +339,7 @@ module Transformer = struct
 			let def = mk (TVar(new_var,Some fn)) fn.etype p in
 			let def = mk (TVar(new_var,Some fn)) fn.etype p in
 			lift_expr1 false ae.a_next_id [def] new_local
 			lift_expr1 false ae.a_next_id [def] new_local
 		end else
 		end else
-			lift_expr fn
+			lift_expr ae.a_next_id fn
 
 
 	and transform_var_expr ae eo v =
 	and transform_var_expr ae eo v =
 		KeywordHandler.check_var_declaration v;
 		KeywordHandler.check_var_declaration v;
@@ -358,18 +352,18 @@ module Transformer = struct
 				b,Some(f.a_expr)
 				b,Some(f.a_expr)
 		in
 		in
 		let e = mk (TVar(v,new_expr)) ae.a_expr.etype ae.a_expr.epos in
 		let e = mk (TVar(v,new_expr)) ae.a_expr.etype ae.a_expr.epos in
-		lift_expr ~next_id:(Some ae.a_next_id) ~blocks:b e
+		lift_expr ae.a_next_id ~blocks:b e
 
 
-	and transform_expr ?(is_value = false) ?(next_id = None) ?(blocks = []) (e : texpr) : adjusted_expr =
-		transform1 (lift_expr ~is_value ~next_id ~blocks e)
+	and transform_expr ?(is_value = false) next_id ?(blocks = []) (e : texpr) : adjusted_expr =
+		transform1 (lift_expr ~is_value next_id ~blocks e)
 
 
 	and transform_expr1 is_value next_id blocks e =
 	and transform_expr1 is_value next_id blocks e =
-		transform_expr ~is_value ~next_id:(Some next_id) ~blocks e
+		transform_expr ~is_value next_id ~blocks e
 
 
 	and transform_exprs_to_block el tb is_value p next_id =
 	and transform_exprs_to_block el tb is_value p next_id =
 		match el with
 		match el with
 			| [e] ->
 			| [e] ->
-				transform_expr ~is_value ~next_id:(Some next_id) e
+				transform_expr ~is_value next_id e
 			| _ ->
 			| _ ->
 				let size = List.length el in
 				let size = List.length el in
 				let res = DynArray.create () in
 				let res = DynArray.create () in
@@ -382,13 +376,13 @@ module Transformer = struct
 						| _ -> false
 						| _ -> false
 					in
 					in
 					if not (is_removable_statement e) then
 					if not (is_removable_statement e) then
-						let ae = transform_expr ~is_value ~next_id:(Some next_id) e in
+						let ae = transform_expr ~is_value next_id e in
 						List.iter (DynArray.add res) ae.a_blocks;
 						List.iter (DynArray.add res) ae.a_blocks;
 						DynArray.add res ae.a_expr
 						DynArray.add res ae.a_expr
 					else
 					else
 						()
 						()
 				) el;
 				) el;
-				lift_expr (mk (TBlock (DynArray.to_list res)) tb p)
+				lift_expr next_id (mk (TBlock (DynArray.to_list res)) tb p)
 
 
 	and transform_switch ae is_value e1 cases edef =
 	and transform_switch ae is_value e1 cases edef =
 		let case_functions = ref [] in
 		let case_functions = ref [] in
@@ -485,7 +479,7 @@ module Transformer = struct
 			forward_transform e ae
 			forward_transform e ae
 
 
 	and transform_op_assign_op ae e1 op one is_value post =
 	and transform_op_assign_op ae e1 op one is_value post =
-		let e1_ = transform_expr e1 ~is_value:true ~next_id:(Some ae.a_next_id) in
+		let e1_ = transform_expr ae.a_next_id e1 ~is_value:true in
 		let handle_as_local temp_local =
 		let handle_as_local temp_local =
 			let ex = ae.a_expr in
 			let ex = ae.a_expr in
 			let res_var = alloc_var (ae.a_next_id()) ex.etype ex.epos in
 			let res_var = alloc_var (ae.a_next_id()) ex.etype ex.epos in
@@ -502,7 +496,7 @@ module Transformer = struct
 			let block = e1_.a_blocks @ blocks in
 			let block = e1_.a_blocks @ blocks in
 			if is_value then begin
 			if is_value then begin
 				let f = exprs_to_func block (ae.a_next_id()) ae in
 				let f = exprs_to_func block (ae.a_next_id()) ae in
-				lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks
+				lift_expr ae.a_next_id f.a_expr ~is_value:true ~blocks:f.a_blocks
 			end else begin
 			end else begin
 				let block = e1_.a_blocks @ [assign_expr] in
 				let block = e1_.a_blocks @ [assign_expr] in
 				transform_exprs_to_block block ex.etype false ex.epos ae.a_next_id
 				transform_exprs_to_block block ex.etype false ex.epos ae.a_next_id
@@ -535,7 +529,7 @@ module Transformer = struct
 				let block = e1_.a_blocks @ [temp_var_l;temp_var_r;temp_var;assign_expr;if post then temp_local else temp_var_expr] in
 				let block = e1_.a_blocks @ [temp_var_l;temp_var_r;temp_var;assign_expr;if post then temp_local else temp_var_expr] in
 				if is_value then begin
 				if is_value then begin
 					let f = exprs_to_func block (ae.a_next_id()) ae in
 					let f = exprs_to_func block (ae.a_next_id()) ae in
-					lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks
+					lift_expr ae.a_next_id f.a_expr ~is_value:true ~blocks:f.a_blocks
 				end else
 				end else
 					transform_exprs_to_block block ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
 					transform_exprs_to_block block ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
 			| TField(e1,fa) ->
 			| TField(e1,fa) ->
@@ -553,7 +547,7 @@ module Transformer = struct
 				let block = e1_.a_blocks @ [temp_var_l;temp_var;assign_expr;if post then temp_local else temp_var_expr] in
 				let block = e1_.a_blocks @ [temp_var_l;temp_var;assign_expr;if post then temp_local else temp_var_expr] in
 				if is_value then begin
 				if is_value then begin
 					let f = exprs_to_func block (ae.a_next_id()) ae in
 					let f = exprs_to_func block (ae.a_next_id()) ae in
-					lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks
+					lift_expr ae.a_next_id f.a_expr ~is_value:true ~blocks:f.a_blocks
 				end else
 				end else
 					transform_exprs_to_block block ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
 					transform_exprs_to_block block ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
 			| _ ->
 			| _ ->
@@ -613,13 +607,13 @@ module Transformer = struct
 			let assign = { ex with eexpr = TVar(fvar, Some(f))} in
 			let assign = { ex with eexpr = TVar(fvar, Some(f))} in
 			let call_expr = (mk (TLocal fvar) fexpr.etype ex.epos ) in
 			let call_expr = (mk (TLocal fvar) fexpr.etype ex.epos ) in
 			let substitute = mk (TCall(call_expr, [])) ex.etype ex.epos in
 			let substitute = mk (TCall(call_expr, [])) ex.etype ex.epos in
-			lift_expr ~blocks:[assign] substitute)
+			lift_expr base.a_next_id ~blocks:[assign] substitute)
 		in
 		in
 		match exprs with
 		match exprs with
 		| [{ eexpr = TFunction({ tf_args = []} as f) } as x] ->
 		| [{ eexpr = TFunction({ tf_args = []} as f) } as x] ->
 			let l = to_tlocal_expr name f.tf_type f.tf_expr.epos in
 			let l = to_tlocal_expr name f.tf_type f.tf_expr.epos in
 			let substitute = mk (TCall(l, [])) f.tf_type f.tf_expr.epos in
 			let substitute = mk (TCall(l, [])) f.tf_type f.tf_expr.epos in
-			lift_expr ~blocks:[x] substitute
+			lift_expr base.a_next_id ~blocks:[x] substitute
 		| _ -> def
 		| _ -> def
 
 
 	and transform_call is_value e params ae =
 	and transform_call is_value e params ae =
@@ -629,7 +623,7 @@ module Transformer = struct
 			let blocks = e.a_blocks @ (List.flatten (List.map (fun (p) -> p.a_blocks) params)) in
 			let blocks = e.a_blocks @ (List.flatten (List.map (fun (p) -> p.a_blocks) params)) in
 			let params = List.map (fun (p) -> p.a_expr) params in
 			let params = List.map (fun (p) -> p.a_expr) params in
 			let e = { ae.a_expr with eexpr = TCall(e.a_expr, params) } in
 			let e = { ae.a_expr with eexpr = TCall(e.a_expr, params) } in
-			lift_expr ~blocks:blocks e
+			lift_expr ae.a_next_id ~blocks:blocks e
 		in
 		in
 		match e, params with
 		match e, params with
 		(* the foreach block should not be handled as a value *)
 		(* the foreach block should not be handled as a value *)
@@ -648,9 +642,9 @@ module Transformer = struct
 		| (is_value,TBlock [x]) ->
 		| (is_value,TBlock [x]) ->
 			trans is_value [] x
 			trans is_value [] x
 		| (false,TBlock []) ->
 		| (false,TBlock []) ->
-			lift_expr a_expr
+			lift_expr ae.a_next_id a_expr
 		| (true,TBlock []) ->
 		| (true,TBlock []) ->
-			lift_expr (mk (TConst TNull) ae.a_expr.etype ae.a_expr.epos)
+			lift_expr ae.a_next_id (mk (TConst TNull) ae.a_expr.etype ae.a_expr.epos)
 		| (false,TBlock el) ->
 		| (false,TBlock el) ->
 			transform_exprs_to_block el ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
 			transform_exprs_to_block el ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
 		| (true,TBlock el) ->
 		| (true,TBlock el) ->
@@ -672,7 +666,7 @@ module Transformer = struct
 			let fn_assign = mk (TVar (t_var,Some f)) ae.a_expr.etype ae.a_expr.epos in
 			let fn_assign = mk (TVar (t_var,Some f)) ae.a_expr.etype ae.a_expr.epos in
 			let ev = mk (TLocal t_var) ae.a_expr.etype ae.a_expr.epos in
 			let ev = mk (TLocal t_var) ae.a_expr.etype ae.a_expr.epos in
 			let substitute = mk (TCall(ev,[])) ae.a_expr.etype ae.a_expr.epos in
 			let substitute = mk (TCall(ev,[])) ae.a_expr.etype ae.a_expr.epos in
-			lift_expr ~blocks:[fn_assign] substitute
+			lift_expr ae.a_next_id ~blocks:[fn_assign] substitute
 		| (is_value,TFunction(f)) ->
 		| (is_value,TFunction(f)) ->
 			transform_function f ae is_value
 			transform_function f ae is_value
 		| (_,TVar(v,None)) ->
 		| (_,TVar(v,None)) ->
@@ -714,7 +708,7 @@ module Transformer = struct
 
 
 			let blocks = a1.a_blocks @ [var_decl] in
 			let blocks = a1.a_blocks @ [var_decl] in
 
 
-			lift_expr ~blocks: blocks twhile
+			lift_expr ae.a_next_id ~blocks: blocks twhile
 		| (_,TReturn None) ->
 		| (_,TReturn None) ->
 			ae
 			ae
 		| (_,TReturn (Some ({eexpr = TFunction f} as ef))) ->
 		| (_,TReturn (Some ({eexpr = TFunction f} as ef))) ->
@@ -795,10 +789,10 @@ module Transformer = struct
 			| [] ->
 			| [] ->
 				let meta = Meta.Custom(":ternaryIf"), [], ae.a_expr.epos in
 				let meta = Meta.Custom(":ternaryIf"), [], ae.a_expr.epos in
 				let ternary = { ae.a_expr with eexpr = TMeta(meta, new_if) } in
 				let ternary = { ae.a_expr with eexpr = TMeta(meta, new_if) } in
-				lift_expr ~blocks:blocks ternary
+				lift_expr ae.a_next_id ~blocks:blocks ternary
 			| b ->
 			| b ->
 				let f = exprs_to_func (List.append blocks [new_if]) (ae.a_next_id ()) ae in
 				let f = exprs_to_func (List.append blocks [new_if]) (ae.a_next_id ()) ae in
-				lift_expr ~blocks:f.a_blocks f.a_expr)
+				lift_expr ae.a_next_id ~blocks:f.a_blocks f.a_expr)
 		| (false, TIf(econd, eif, eelse)) ->
 		| (false, TIf(econd, eif, eelse)) ->
 			let econd = trans true [] econd in
 			let econd = trans true [] econd in
 			let eif = to_expr (trans false [] eif) in
 			let eif = to_expr (trans false [] eif) in
@@ -842,20 +836,20 @@ module Transformer = struct
 		(* anon field access on optional params *)
 		(* anon field access on optional params *)
 		| (is_value, TField(e,FAnon cf)) when Meta.has Meta.Optional cf.cf_meta ->
 		| (is_value, TField(e,FAnon cf)) when Meta.has Meta.Optional cf.cf_meta ->
 			let e = dynamic_field_read e cf.cf_name ae.a_expr.etype in
 			let e = dynamic_field_read e cf.cf_name ae.a_expr.etype in
-			transform_expr ~is_value:is_value e
+			transform_expr ae.a_next_id ~is_value:is_value e
 		| (is_value, TBinop(OpAssign,{eexpr = TField(e1,FAnon cf)},e2)) when Meta.has Meta.Optional cf.cf_meta ->
 		| (is_value, TBinop(OpAssign,{eexpr = TField(e1,FAnon cf)},e2)) when Meta.has Meta.Optional cf.cf_meta ->
 			let e = dynamic_field_write e1 cf.cf_name e2 in
 			let e = dynamic_field_write e1 cf.cf_name e2 in
-			transform_expr ~is_value:is_value e
+			transform_expr ae.a_next_id ~is_value:is_value e
 		| (is_value, TBinop(OpAssignOp op,{eexpr = TField(e1,FAnon cf); etype = t},e2)) when Meta.has Meta.Optional cf.cf_meta ->
 		| (is_value, TBinop(OpAssignOp op,{eexpr = TField(e1,FAnon cf); etype = t},e2)) when Meta.has Meta.Optional cf.cf_meta ->
 			let e = dynamic_field_read_write ae.a_next_id e1 cf.cf_name op e2 t in
 			let e = dynamic_field_read_write ae.a_next_id e1 cf.cf_name op e2 t in
-			transform_expr ~is_value:is_value e
+			transform_expr ae.a_next_id ~is_value:is_value e
 
 
 		| (is_value, TUnop( (Increment | Decrement) as unop, unop_flag,{eexpr = TField(e1, FAnon cf); etype = t; epos = p})) when Meta.has Meta.Optional cf.cf_meta  ->
 		| (is_value, TUnop( (Increment | Decrement) as unop, unop_flag,{eexpr = TField(e1, FAnon cf); etype = t; epos = p})) when Meta.has Meta.Optional cf.cf_meta  ->
 			let e = dynamic_field_inc_dec ae.a_next_id e1 cf.cf_name unop unop_flag t p in
 			let e = dynamic_field_inc_dec ae.a_next_id e1 cf.cf_name unop unop_flag t p in
-			transform_expr ~is_value:is_value e
+			transform_expr ae.a_next_id ~is_value:is_value e
 		| (is_value, TUnop( (Increment | Decrement) as unop, unop_flag,{eexpr = TField(e1, FDynamic field_name); etype = t; epos = p})) ->
 		| (is_value, TUnop( (Increment | Decrement) as unop, unop_flag,{eexpr = TField(e1, FDynamic field_name); etype = t; epos = p})) ->
 			let e = dynamic_field_inc_dec ae.a_next_id e1 field_name unop unop_flag t p in
 			let e = dynamic_field_inc_dec ae.a_next_id e1 field_name unop unop_flag t p in
-			transform_expr ~is_value:is_value e
+			transform_expr ae.a_next_id ~is_value:is_value e
 		(*
 		(*
 			anon field access with non optional members like iterator, length, split must be handled too, we need to Reflect on them too when it's a runtime method
 			anon field access with non optional members like iterator, length, split must be handled too, we need to Reflect on them too when it's a runtime method
 		*)
 		*)
@@ -872,17 +866,17 @@ module Transformer = struct
 		| (_, TUnop(op, Prefix, e)) ->
 		| (_, TUnop(op, Prefix, e)) ->
 			let e1 = trans true [] e in
 			let e1 = trans true [] e in
 			let r = { a_expr with eexpr = TUnop(op, Prefix, e1.a_expr) } in
 			let r = { a_expr with eexpr = TUnop(op, Prefix, e1.a_expr) } in
-			lift_expr ~blocks:e1.a_blocks r
+			lift_expr ae.a_next_id ~blocks:e1.a_blocks r
 
 
 		| (is_value, TField(e,FDynamic s)) ->
 		| (is_value, TField(e,FDynamic s)) ->
 			let e = dynamic_field_read e s ae.a_expr.etype in
 			let e = dynamic_field_read e s ae.a_expr.etype in
-			transform_expr ~is_value:is_value e
+			transform_expr ae.a_next_id ~is_value:is_value e
 		| (is_value, TBinop(OpAssign,{eexpr = TField(e1,FDynamic s)},e2)) ->
 		| (is_value, TBinop(OpAssign,{eexpr = TField(e1,FDynamic s)},e2)) ->
 			let e = dynamic_field_write e1 s e2 in
 			let e = dynamic_field_write e1 s e2 in
-			transform_expr ~is_value:is_value e
+			transform_expr ae.a_next_id ~is_value:is_value e
 		| (is_value, TBinop(OpAssignOp op,{eexpr = TField(e1,FDynamic s); etype = t},e2)) ->
 		| (is_value, TBinop(OpAssignOp op,{eexpr = TField(e1,FDynamic s); etype = t},e2)) ->
 			let e = dynamic_field_read_write ae.a_next_id e1 s op e2 t in
 			let e = dynamic_field_read_write ae.a_next_id e1 s op e2 t in
-			transform_expr ~is_value:is_value e
+			transform_expr ae.a_next_id ~is_value:is_value e
 		| (is_value, TBinop(OpAssign, left, right))->
 		| (is_value, TBinop(OpAssign, left, right))->
 			(let left = trans true [] left in
 			(let left = trans true [] left in
 			let right = trans true [] right in
 			let right = trans true [] right in
@@ -925,7 +919,7 @@ module Transformer = struct
 			let e2 = trans true [] e2 in
 			let e2 = trans true [] e2 in
 			let r = { a_expr with eexpr = TArray(e1.a_expr, e2.a_expr)} in
 			let r = { a_expr with eexpr = TArray(e1.a_expr, e2.a_expr)} in
 			let blocks = List.append e1.a_blocks e2.a_blocks in
 			let blocks = List.append e1.a_blocks e2.a_blocks in
-			lift_expr ~blocks:blocks r
+			lift_expr ae.a_next_id ~blocks:blocks r
 		| (false, TTry(etry, catches)) ->
 		| (false, TTry(etry, catches)) ->
 			let etry = trans false [] etry in
 			let etry = trans false [] etry in
 			let catches = List.map (fun(v,e) -> KeywordHandler.check_var_declaration v; v, trans false [] e) catches in
 			let catches = List.map (fun(v,e) -> KeywordHandler.check_var_declaration v; v, trans false [] e) catches in
@@ -952,49 +946,49 @@ module Transformer = struct
 			let blocks = List.flatten (List.map (fun (_,ex) -> ex.a_blocks) fields) in
 			let blocks = List.flatten (List.map (fun (_,ex) -> ex.a_blocks) fields) in
 			let fields = List.map (fun (name,ex) -> name, ex.a_expr) fields in
 			let fields = List.map (fun (name,ex) -> name, ex.a_expr) fields in
 			let r = { a_expr with eexpr = (TObjectDecl(fields) )} in
 			let r = { a_expr with eexpr = (TObjectDecl(fields) )} in
-			lift_expr ~blocks r
+			lift_expr ae.a_next_id ~blocks r
 		| (_, TArrayDecl(values)) ->
 		| (_, TArrayDecl(values)) ->
 			let values = List.map (trans true []) values in
 			let values = List.map (trans true []) values in
 			let blocks = List.flatten (List.map (fun (v) -> v.a_blocks) values) in
 			let blocks = List.flatten (List.map (fun (v) -> v.a_blocks) values) in
 			let exprs = List.map (fun (v) -> v.a_expr) values in
 			let exprs = List.map (fun (v) -> v.a_expr) values in
 			let r = { a_expr with eexpr = TArrayDecl exprs } in
 			let r = { a_expr with eexpr = TArrayDecl exprs } in
-			lift_expr ~blocks:blocks r
+			lift_expr ae.a_next_id ~blocks:blocks r
 		| (is_value, TCast(e1,Some mt)) ->
 		| (is_value, TCast(e1,Some mt)) ->
 			let e = Codegen.default_cast ~vtmp:(ae.a_next_id()) (match !como with Some com -> com | None -> assert false) e1 mt ae.a_expr.etype ae.a_expr.epos in
 			let e = Codegen.default_cast ~vtmp:(ae.a_next_id()) (match !como with Some com -> com | None -> assert false) e1 mt ae.a_expr.etype ae.a_expr.epos in
-			transform_expr ~is_value:is_value e
+			transform_expr ae.a_next_id ~is_value:is_value e
 		| (is_value, TCast(e,None)) ->
 		| (is_value, TCast(e,None)) ->
 			let e = trans is_value [] e in
 			let e = trans is_value [] e in
 			let r = { a_expr with eexpr = TCast(e.a_expr, None)} in
 			let r = { a_expr with eexpr = TCast(e.a_expr, None)} in
-			lift_expr ~blocks:e.a_blocks r
+			lift_expr ae.a_next_id ~blocks:e.a_blocks r
 		| (_, TField(e,f)) ->
 		| (_, TField(e,f)) ->
 			let e = trans true [] e in
 			let e = trans true [] e in
 			let r = { a_expr with eexpr = TField(e.a_expr, f) } in
 			let r = { a_expr with eexpr = TField(e.a_expr, f) } in
-			lift_expr ~blocks:e.a_blocks r
+			lift_expr ae.a_next_id ~blocks:e.a_blocks r
 		| (is_value, TMeta(m, e)) ->
 		| (is_value, TMeta(m, e)) ->
 			let e = trans is_value [] e in
 			let e = trans is_value [] e in
 			let r = { a_expr with eexpr = TMeta(m, e.a_expr); etype = e.a_expr.etype } in
 			let r = { a_expr with eexpr = TMeta(m, e.a_expr); etype = e.a_expr.etype } in
-			lift_expr ~blocks:e.a_blocks r
-		| ( _, TLocal _ ) -> lift_expr a_expr
+			lift_expr ae.a_next_id ~blocks:e.a_blocks r
+		| ( _, TLocal _ ) -> lift_expr ae.a_next_id a_expr
 
 
-		| ( _, TConst _ ) -> lift_expr a_expr
-		| ( _, TTypeExpr _ ) -> lift_expr a_expr
+		| ( _, TConst _ ) -> lift_expr ae.a_next_id a_expr
+		| ( _, TTypeExpr _ ) -> lift_expr ae.a_next_id a_expr
 		| ( _, TUnop _ ) -> assert false
 		| ( _, TUnop _ ) -> assert false
 		| ( true, TWhile(econd, ebody, DoWhile) ) ->
 		| ( true, TWhile(econd, ebody, DoWhile) ) ->
 			let new_expr = trans false [] a_expr in
 			let new_expr = trans false [] a_expr in
 			let f = exprs_to_func (new_expr.a_blocks @ [new_expr.a_expr]) (ae.a_next_id()) ae in
 			let f = exprs_to_func (new_expr.a_blocks @ [new_expr.a_expr]) (ae.a_next_id()) ae in
-			lift_expr ~is_value:true ~blocks:f.a_blocks f.a_expr
+			lift_expr ae.a_next_id ~is_value:true ~blocks:f.a_blocks f.a_expr
 
 
 		| ( _, TBreak ) | ( _, TContinue ) | ( _, TIdent _) ->
 		| ( _, TBreak ) | ( _, TContinue ) | ( _, TIdent _) ->
-			lift_expr a_expr
+			lift_expr ae.a_next_id a_expr
 
 
 	and transform e =
 	and transform e =
-		to_expr (transform1 (lift_expr e))
+		to_expr (transform1 (lift_expr (new_counter()) e))
 
 
 	and forward_transform e base =
 	and forward_transform e base =
 		transform1 (lift_expr1 base.a_is_value base.a_next_id base.a_blocks e)
 		transform1 (lift_expr1 base.a_is_value base.a_next_id base.a_blocks e)
 
 
 	let transform_to_value e =
 	let transform_to_value e =
-		to_expr (transform1 (lift_expr e ~is_value:true))
+		to_expr (transform1 (lift_expr (new_counter()) e ~is_value:true))
 
 
 end
 end
 
 
@@ -1306,8 +1300,8 @@ module Printer = struct
 					Printf.sprintf "%s(%s,%s)" (third ops) (print_expr pctx e1) (print_expr pctx e2)
 					Printf.sprintf "%s(%s,%s)" (third ops) (print_expr pctx e1) (print_expr pctx e2)
 				| _,_ -> Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (snd ops) (print_expr pctx e2))
 				| _,_ -> Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (snd ops) (print_expr pctx e2))
 			| TBinop(OpMod,e1,e2) when (is_type1 "" "Int")(e1.etype) && (is_type1 "" "Int")(e2.etype) ->
 			| TBinop(OpMod,e1,e2) when (is_type1 "" "Int")(e1.etype) && (is_type1 "" "Int")(e2.etype) ->
-				(match e1.eexpr with
-				| TConst(TInt(x)) when (Int32.to_int x) >= 0 ->
+				(match e1.eexpr, e2.eexpr with
+				| TConst(TInt(x1)), TConst(TInt(x2)) when (Int32.to_int x1) >= 0 && (Int32.to_int x2) >= 0 ->
 					(* constant optimization *)
 					(* constant optimization *)
 					Printf.sprintf "%s %% %s" (print_expr pctx e1) (print_expr pctx e2)
 					Printf.sprintf "%s %% %s" (print_expr pctx e1) (print_expr pctx e2)
 				| _ ->
 				| _ ->
@@ -2505,13 +2499,15 @@ module Generator = struct
 		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\n";
 			spr ctx "from functools import partial as _hx_partial\n";
 		spr ctx "import sys\n";
 		spr ctx "import sys\n";
-		spr ctx "try:\n";
-		spr ctx "    if sys.stdout.encoding != 'utf-8':\n";
-		spr ctx "        sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='utf8', buffering=1)\n";
-		spr ctx "    if sys.stderr.encoding != 'utf-8':\n";
-		spr ctx "        sys.stderr = open(sys.stderr.fileno(), mode='w', encoding='utf8', buffering=1)\n";
-		spr ctx "except:\n";
-		spr ctx "    pass\n";
+		if defined com Define.StdEncodingUtf8 then begin
+			spr ctx "try:\n";
+			spr ctx "    if sys.stdout.encoding != 'utf-8':\n";
+			spr ctx "        sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='utf8', buffering=1)\n";
+			spr ctx "    if sys.stderr.encoding != 'utf-8':\n";
+			spr ctx "        sys.stderr = open(sys.stderr.fileno(), mode='w', encoding='utf8', buffering=1)\n";
+			spr ctx "except:\n";
+			spr ctx "    pass\n";
+		end;
 		gen_imports ctx;
 		gen_imports ctx;
 		gen_resources ctx;
 		gen_resources ctx;
 		gen_types ctx;
 		gen_types ctx;

+ 3 - 0
src/generators/jvm/jvmSignature.ml

@@ -227,6 +227,9 @@ module NativeSignatures = struct
 	let haxe_empty_constructor_path = (["haxe";"jvm"],"EmptyConstructor")
 	let haxe_empty_constructor_path = (["haxe";"jvm"],"EmptyConstructor")
 	let haxe_empty_constructor_sig = TObject(haxe_empty_constructor_path,[])
 	let haxe_empty_constructor_sig = TObject(haxe_empty_constructor_path,[])
 
 
+	let void_path = ["java";"lang"],"Void"
+	let void_sig = TObject(void_path,[])
+
 	(* numeric *)
 	(* numeric *)
 
 
 	let number_path = ["java";"lang"],"Number"
 	let number_path = ["java";"lang"],"Number"

+ 12 - 6
src/macro/eval/evalContext.ml

@@ -59,6 +59,10 @@ type env_info = {
 	kind : env_kind;
 	kind : env_kind;
 	(* The name of capture variables. Maps local slots to variable names. Only filled in debug mode. *)
 	(* The name of capture variables. Maps local slots to variable names. Only filled in debug mode. *)
 	capture_infos : (int,var_info) Hashtbl.t;
 	capture_infos : (int,var_info) Hashtbl.t;
+	(* The number of local variables. *)
+	num_locals : int;
+	(* The number of capture variables. *)
+	num_captures : int;
 }
 }
 
 
 (* Per-environment debug information. These values are only modified while debugging. *)
 (* Per-environment debug information. These values are only modified while debugging. *)
@@ -405,17 +409,19 @@ let no_debug = {
 	debug_pos = null_pos;
 	debug_pos = null_pos;
 }
 }
 
 
-let create_env_info static pfile kind capture_infos =
+let create_env_info static pfile kind capture_infos num_locals num_captures =
 	let info = {
 	let info = {
 		static = static;
 		static = static;
 		kind = kind;
 		kind = kind;
 		pfile = hash pfile;
 		pfile = hash pfile;
 		pfile_unique = hash (Path.unique_full_path pfile);
 		pfile_unique = hash (Path.unique_full_path pfile);
 		capture_infos = capture_infos;
 		capture_infos = capture_infos;
+		num_locals = num_locals;
+		num_captures = num_captures;
 	} in
 	} in
 	info
 	info
 
 
-let push_environment ctx info num_locals num_captures =
+let push_environment ctx info =
 	let eval = get_eval ctx in
 	let eval = get_eval ctx in
 	let timer = if ctx.detail_times then
 	let timer = if ctx.detail_times then
 		Timer.timer ["macro";"execution";kind_name eval info.kind]
 		Timer.timer ["macro";"execution";kind_name eval info.kind]
@@ -427,15 +433,15 @@ let push_environment ctx info num_locals num_captures =
 	else
 	else
 		no_debug
 		no_debug
 	in
 	in
-	let locals = if num_locals = 0 then
+	let locals = if info.num_locals = 0 then
 		empty_array
 		empty_array
 	else
 	else
-		Array.make num_locals vnull
+		Array.make info.num_locals vnull
 	in
 	in
-	let captures = if num_captures = 0 then
+	let captures = if info.num_captures = 0 then
 		empty_array
 		empty_array
 	else
 	else
-		Array.make num_captures vnull
+		Array.make info.num_captures vnull
 	in
 	in
 	let stack_depth = match eval.env with
 	let stack_depth = match eval.env with
 		| None -> 1;
 		| None -> 1;

+ 34 - 12
src/macro/eval/evalDebugSocket.ml

@@ -333,28 +333,34 @@ module ValueCompletion = struct
 		loop IntMap.empty proto
 		loop IntMap.empty proto
 
 
 	let prototype_static_fields proto =
 	let prototype_static_fields proto =
-		IntMap.fold (fun name _ acc -> IntMap.add name (name,"field",None) acc) proto.pnames IntMap.empty
-
+		IntMap.fold (fun name offset acc ->
+			let v = proto.pfields.(offset) in
+			let kind = match v with
+				| VFunction _ -> "method"
+				| _ -> "field"
+			in
+			IntMap.add name (name,kind,None) acc
+		) proto.pnames IntMap.empty
 
 
 	let to_json l =
 	let to_json l =
 		JArray (List.map (fun (n,k,column) ->
 		JArray (List.map (fun (n,k,column) ->
-			let fields = ["label",JString (rev_hash n);"kind",JString k] in
+			let fields = ["label",JString (rev_hash n);"type",JString k] in
 			let fields = match column with None -> fields | Some column -> ("start",JInt column) :: fields in
 			let fields = match column with None -> fields | Some column -> ("start",JInt column) :: fields in
 			JObject fields
 			JObject fields
 		) l)
 		) l)
 
 
 	let collect_idents ctx env =
 	let collect_idents ctx env =
 		let acc = Hashtbl.create 0 in
 		let acc = Hashtbl.create 0 in
-		let add key =
+		let add key kind =
 			if not (Hashtbl.mem acc key) then
 			if not (Hashtbl.mem acc key) then
-				Hashtbl.add acc key (key,"value",None)
+				Hashtbl.add acc key (key,kind,None)
 		in
 		in
 		(* 0. Extra locals *)
 		(* 0. Extra locals *)
-		IntMap.iter (fun key _ -> add key) env.env_extra_locals;
+		IntMap.iter (fun key _ -> add key "variable") env.env_extra_locals;
 		(* 1. Variables *)
 		(* 1. Variables *)
 		let rec loop scopes = match scopes with
 		let rec loop scopes = match scopes with
 			| scope :: scopes ->
 			| scope :: scopes ->
-				Hashtbl.iter (fun key _ -> add (hash key)) scope.local_ids;
+				Hashtbl.iter (fun key _ -> add (hash key) "variable") scope.local_ids;
 				loop scopes
 				loop scopes
 			| [] ->
 			| [] ->
 				()
 				()
@@ -362,7 +368,7 @@ module ValueCompletion = struct
 		loop env.env_debug.scopes;
 		loop env.env_debug.scopes;
 		(* 2. Captures *)
 		(* 2. Captures *)
 		Hashtbl.iter (fun slot vi ->
 		Hashtbl.iter (fun slot vi ->
-			add (hash vi.vi_name)
+			add (hash vi.vi_name) "variable"
 		) env.env_info.capture_infos;
 		) env.env_info.capture_infos;
 		(* 3. Instance *)
 		(* 3. Instance *)
 		if not env.env_info.static then begin
 		if not env.env_info.static then begin
@@ -370,7 +376,7 @@ module ValueCompletion = struct
 			begin match v with
 			begin match v with
 			| VInstance vi ->
 			| VInstance vi ->
 				let fields = prototype_instance_fields vi.iproto in
 				let fields = prototype_instance_fields vi.iproto in
-				IntMap.iter (fun key _ -> add key) fields
+				IntMap.iter (fun key (_,kind,_) -> add key kind) fields
 			| _ ->
 			| _ ->
 				()
 				()
 			end
 			end
@@ -380,7 +386,7 @@ module ValueCompletion = struct
 			| EKMethod(i1,_) ->
 			| EKMethod(i1,_) ->
 				let proto = get_static_prototype_raise ctx i1 in
 				let proto = get_static_prototype_raise ctx i1 in
 				let fields = prototype_static_fields proto in
 				let fields = prototype_static_fields proto in
-				IntMap.iter (fun key _ -> add key) fields
+				IntMap.iter (fun key (_,kind,_) -> add key kind) fields
 			| _ ->
 			| _ ->
 				raise Not_found
 				raise Not_found
 		end;
 		end;
@@ -388,7 +394,18 @@ module ValueCompletion = struct
 		begin match ctx.toplevel with
 		begin match ctx.toplevel with
 		| VObject o ->
 		| VObject o ->
 			let fields = object_fields o in
 			let fields = object_fields o in
-			List.iter (fun (n,_) -> add n) fields
+			List.iter (fun (n,v) ->
+				let kind = match v with
+					| VPrototype proto ->
+						begin match proto.pkind with
+						| PClass _ -> "class"
+						| PEnum _ -> "enum"
+						| _ -> "class" (* ? *)
+						end
+					| _ -> "module"
+				in
+				add n kind
+			) fields
 		| _ ->
 		| _ ->
 			()
 			()
 		end;
 		end;
@@ -487,8 +504,13 @@ module ValueCompletion = struct
 		with _ ->
 		with _ ->
 			save();
 			save();
 			raise Exit
 			raise Exit
-		end;
+		end
 
 
+	let get_completion ctx text column env =
+		if text = "" then
+			collect_idents ctx env
+		else
+			get_completion ctx text column env
 end
 end
 
 
 type handler_context = {
 type handler_context = {

+ 5 - 11
src/macro/eval/evalEmitter.ml

@@ -714,12 +714,6 @@ let emit_neg exec p env = match exec env with
 
 
 (* Function *)
 (* Function *)
 
 
-type env_creation = {
-	ec_info : env_info;
-	ec_num_locals : int;
-	ec_num_captures : int;
-}
-
 let execute_set_local i env v =
 let execute_set_local i env v =
 	env.env_locals.(i) <- v
 	env.env_locals.(i) <- v
 
 
@@ -743,21 +737,21 @@ let process_arguments fl vl env =
 [@@inline]
 [@@inline]
 
 
 let create_function_noret ctx eci exec fl vl =
 let create_function_noret ctx eci exec fl vl =
-	let env = push_environment ctx eci.ec_info eci.ec_num_locals eci.ec_num_captures in
+	let env = push_environment ctx eci in
 	process_arguments fl vl env;
 	process_arguments fl vl env;
 	let v = exec env in
 	let v = exec env in
 	pop_environment ctx env;
 	pop_environment ctx env;
 	v
 	v
 
 
 let create_function ctx eci exec fl vl =
 let create_function ctx eci exec fl vl =
-	let env = push_environment ctx eci.ec_info eci.ec_num_locals eci.ec_num_captures in
+	let env = push_environment ctx eci in
 	process_arguments fl vl env;
 	process_arguments fl vl env;
 	let v = try exec env with Return v -> v in
 	let v = try exec env with Return v -> v in
 	pop_environment ctx env;
 	pop_environment ctx env;
 	v
 	v
 
 
 let create_closure_noret ctx eci refs exec fl vl =
 let create_closure_noret ctx eci refs exec fl vl =
-	let env = push_environment ctx eci.ec_info eci.ec_num_locals eci.ec_num_captures in
+	let env = push_environment ctx eci in
 	Array.iter (fun (i,vr) -> env.env_captures.(i) <- vr) refs;
 	Array.iter (fun (i,vr) -> env.env_captures.(i) <- vr) refs;
 	process_arguments fl vl env;
 	process_arguments fl vl env;
 	let v = exec env in
 	let v = exec env in
@@ -765,7 +759,7 @@ let create_closure_noret ctx eci refs exec fl vl =
 	v
 	v
 
 
 let create_closure refs ctx eci exec fl vl =
 let create_closure refs ctx eci exec fl vl =
-	let env = push_environment ctx eci.ec_info eci.ec_num_locals eci.ec_num_captures in
+	let env = push_environment ctx eci in
 	Array.iter (fun (i,vr) -> env.env_captures.(i) <- vr) refs;
 	Array.iter (fun (i,vr) -> env.env_captures.(i) <- vr) refs;
 	process_arguments fl vl env;
 	process_arguments fl vl env;
 	let v = try exec env with Return v -> v in
 	let v = try exec env with Return v -> v in
@@ -774,7 +768,7 @@ let create_closure refs ctx eci exec fl vl =
 
 
 let emit_closure ctx mapping eci hasret exec fl env =
 let emit_closure ctx mapping eci hasret exec fl env =
 	let refs = Array.map (fun (i,slot) -> i,emit_capture_read slot env) mapping in
 	let refs = Array.map (fun (i,slot) -> i,emit_capture_read slot env) mapping in
-	let create = match hasret,eci.ec_num_captures with
+	let create = match hasret,eci.num_captures with
 		| true,0 -> create_function
 		| true,0 -> create_function
 		| false,0 -> create_function_noret
 		| false,0 -> create_function_noret
 		| _ -> create_closure refs
 		| _ -> create_closure refs

+ 2 - 5
src/macro/eval/evalJit.ml

@@ -684,11 +684,8 @@ and jit_tfunction jit static pos tf =
 	pop_scope jit;
 	pop_scope jit;
 	fl,exec
 	fl,exec
 
 
-and get_env_creation jit static file info = {
-	ec_info = create_env_info static file info jit.capture_infos;
-	ec_num_locals = jit.max_num_locals;
-	ec_num_captures = Hashtbl.length jit.captures;
-}
+and get_env_creation jit static file info =
+	create_env_info static file info jit.capture_infos jit.max_num_locals (Hashtbl.length jit.captures)
 
 
 (* Creates a [EvalValue.vfunc] of function [tf], which can be [static] or not. *)
 (* Creates a [EvalValue.vfunc] of function [tf], which can be [static] or not. *)
 let jit_tfunction ctx key_type key_field tf static pos =
 let jit_tfunction ctx key_type key_field tf static pos =

+ 2 - 2
src/macro/eval/evalMain.ml

@@ -156,8 +156,8 @@ let call_path ctx path f vl api =
 			let vtype = get_static_prototype_as_value ctx (path_hash path) api.pos in
 			let vtype = get_static_prototype_as_value ctx (path_hash path) api.pos in
 			let vfield = field vtype (hash f) in
 			let vfield = field vtype (hash f) in
 			let p = api.pos in
 			let p = api.pos in
-			let info = create_env_info true p.pfile EKEntrypoint (Hashtbl.create 0) in
-			let env = push_environment ctx info 0 0 in
+			let info = create_env_info true p.pfile EKEntrypoint (Hashtbl.create 0) 0 0 in
+			let env = push_environment ctx info in
 			env.env_leave_pmin <- p.pmin;
 			env.env_leave_pmin <- p.pmin;
 			env.env_leave_pmax <- p.pmax;
 			env.env_leave_pmax <- p.pmax;
 			let v = call_value_on vtype vfield vl in
 			let v = call_value_on vtype vfield vl in

+ 5 - 6
src/macro/eval/evalPrinting.ml

@@ -25,7 +25,6 @@ open EvalField
 open EvalHash
 open EvalHash
 open EvalString
 open EvalString
 
 
-let rempty = create_ascii ""
 let rbropen = create_ascii "{"
 let rbropen = create_ascii "{"
 let rbrclose = create_ascii "}"
 let rbrclose = create_ascii "}"
 let rbkopen = create_ascii "["
 let rbkopen = create_ascii "["
@@ -64,14 +63,14 @@ let rec s_object depth o =
 	create_with_length s (try UTF8.length s with _ -> String.length s)
 	create_with_length s (try UTF8.length s with _ -> String.length s)
 
 
 and s_array depth va =
 and s_array depth va =
-	join rempty [
+	join empty_string [
 		rbkopen;
 		rbkopen;
 		EvalArray.join va (s_value depth) rcomma;
 		EvalArray.join va (s_value depth) rcomma;
 		rbkclose;
 		rbkclose;
 	]
 	]
 
 
 and s_vector depth vv =
 and s_vector depth vv =
-	join rempty [
+	join empty_string [
 		rbkopen;
 		rbkopen;
 		EvalArray.join (EvalArray.create vv) (s_value depth) rcomma;
 		EvalArray.join (EvalArray.create vv) (s_value depth) rcomma;
 		rbkclose;
 		rbkclose;
@@ -90,7 +89,7 @@ and s_enum_value depth ve =
 	match ve.eargs with
 	match ve.eargs with
 	| [||] -> create_ascii name
 	| [||] -> create_ascii name
 	| vl ->
 	| vl ->
-		join rempty [
+		join empty_string [
 			create_ascii name;
 			create_ascii name;
 			rpopen;
 			rpopen;
 			join rcomma (Array.to_list (Array.map (s_value (depth + 1)) vl));
 			join rcomma (Array.to_list (Array.map (s_value (depth + 1)) vl));
@@ -98,8 +97,8 @@ and s_enum_value depth ve =
 		]
 		]
 
 
 and s_proto_kind proto = match proto.pkind with
 and s_proto_kind proto = match proto.pkind with
-	| PClass _ -> join rempty [create_ascii "Class<"; s_hash proto.ppath; rgt]
-	| PEnum _ -> join rempty [create_ascii "Enum<"; s_hash proto.ppath; rgt]
+	| PClass _ -> join empty_string [create_ascii "Class<"; s_hash proto.ppath; rgt]
+	| PEnum _ -> join empty_string [create_ascii "Enum<"; s_hash proto.ppath; rgt]
 	| PInstance | PObject -> assert false
 	| PInstance | PObject -> assert false
 
 
 and s_value depth v =
 and s_value depth v =

+ 2 - 2
src/macro/eval/evalPrototype.ml

@@ -33,8 +33,8 @@ let eval_expr ctx kind e =
 	catch_exceptions ctx (fun () ->
 	catch_exceptions ctx (fun () ->
 		let jit,f = jit_expr ctx e in
 		let jit,f = jit_expr ctx e in
 		let num_captures = Hashtbl.length jit.captures in
 		let num_captures = Hashtbl.length jit.captures in
-		let info = create_env_info true e.epos.pfile kind jit.capture_infos in
-		let env = push_environment ctx info jit.max_num_locals num_captures in
+		let info = create_env_info true e.epos.pfile kind jit.capture_infos jit.max_num_locals num_captures in
+		let env = push_environment ctx info in
 		Std.finally (fun _ -> pop_environment ctx env) f env
 		Std.finally (fun _ -> pop_environment ctx env) f env
 	) e.Type.epos
 	) e.Type.epos
 
 

+ 11 - 11
src/macro/eval/evalStdLib.ml

@@ -952,7 +952,7 @@ module StdEReg = struct
 	let split = vifun1 (fun vthis s ->
 	let split = vifun1 (fun vthis s ->
 		let this = this vthis in
 		let this = this vthis in
 		let s = decode_string s in
 		let s = decode_string s in
-		if String.length s = 0 then encode_array [encode_string ""]
+		if String.length s = 0 then encode_array [v_empty_string]
 		else begin
 		else begin
 			let max = if this.r_global then -1 else 2 in
 			let max = if this.r_global then -1 else 2 in
 			let l = Pcre.full_split ~iflags:0x2000 ~max ~rex:this.r s in
 			let l = Pcre.full_split ~iflags:0x2000 ~max ~rex:this.r s in
@@ -1540,9 +1540,9 @@ module StdIntMap = struct
 	let toString = vifun0 (fun vthis ->
 	let toString = vifun0 (fun vthis ->
 		let this = this vthis in
 		let this = this vthis in
 		let l = IntHashtbl.fold (fun key vvalue acc ->
 		let l = IntHashtbl.fold (fun key vvalue acc ->
-			(join rempty [create_ascii (string_of_int key); create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in
+			(join empty_string [create_ascii (string_of_int key); create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in
 		let s = join rcomma l in
 		let s = join rcomma l in
-		let s = join rempty [rbropen;s;rbrclose] in
+		let s = join empty_string [rbropen;s;rbrclose] in
 		vstring s
 		vstring s
 	)
 	)
 
 
@@ -1599,9 +1599,9 @@ module StdStringMap = struct
 	let toString = vifun0 (fun vthis ->
 	let toString = vifun0 (fun vthis ->
 		let this = this vthis in
 		let this = this vthis in
 		let l = StringHashtbl.fold (fun _ (key,vvalue) acc ->
 		let l = StringHashtbl.fold (fun _ (key,vvalue) acc ->
-			(join rempty [key; create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in
+			(join empty_string [key; create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in
 		let s = join rcomma l in
 		let s = join rcomma l in
-		let s = join rempty [rbropen;s;rbrclose] in
+		let s = join empty_string [rbropen;s;rbrclose] in
 		vstring s
 		vstring s
 	)
 	)
 
 
@@ -1657,9 +1657,9 @@ module StdObjectMap = struct
 	let toString = vifun0 (fun vthis ->
 	let toString = vifun0 (fun vthis ->
 		let this = this vthis in
 		let this = this vthis in
 		let l = ValueHashtbl.fold (fun key vvalue acc ->
 		let l = ValueHashtbl.fold (fun key vvalue acc ->
-			(join rempty [s_value 0 key; create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in
+			(join empty_string [s_value 0 key; create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in
 		let s = join rcomma l in
 		let s = join rcomma l in
-		let s = join rempty [rbropen;s;rbrclose] in
+		let s = join empty_string [rbropen;s;rbrclose] in
 		vstring s
 		vstring s
 	)
 	)
 
 
@@ -2190,7 +2190,7 @@ module StdString = struct
 	let charAt = vifun1 (fun vthis index ->
 	let charAt = vifun1 (fun vthis index ->
 		let this = this vthis in
 		let this = this vthis in
 		let i = decode_int index in
 		let i = decode_int index in
-		if i < 0 || i >= this.slength then encode_string ""
+		if i < 0 || i >= this.slength then v_empty_string
 		else vstring (from_char_code (char_at this i))
 		else vstring (from_char_code (char_at this i))
 	)
 	)
 
 
@@ -2288,7 +2288,7 @@ module StdString = struct
 		let cl_this = this.slength in
 		let cl_this = this.slength in
 		let c_pos = decode_int pos in
 		let c_pos = decode_int pos in
 		if c_pos >= cl_this then
 		if c_pos >= cl_this then
-			encode_string ""
+			v_empty_string
 		else begin
 		else begin
 			let c_pos = if c_pos < 0 then begin
 			let c_pos = if c_pos < 0 then begin
 				let c_pos = this.slength + c_pos in
 				let c_pos = this.slength + c_pos in
@@ -2320,7 +2320,7 @@ module StdString = struct
 		let c_first,c_last = if c_first > c_last then c_last,c_first else c_first,c_last in
 		let c_first,c_last = if c_first > c_last then c_last,c_first else c_first,c_last in
 		let c_last = if c_last > cl_this then cl_this else c_last in
 		let c_last = if c_last > cl_this then cl_this else c_last in
 		if c_first > cl_this || c_first = c_last then
 		if c_first > cl_this || c_first = c_last then
-			encode_string ""
+			v_empty_string
 		else begin
 		else begin
 			begin
 			begin
 				let b_offset1 = get_offset this c_first in
 				let b_offset1 = get_offset this c_first in
@@ -3236,7 +3236,7 @@ let init_empty_constructors builtins =
 	Hashtbl.add h key_eval_Vector (fun () -> encode_vector_instance (Array.make 0 vnull));
 	Hashtbl.add h key_eval_Vector (fun () -> encode_vector_instance (Array.make 0 vnull));
 	Hashtbl.add h key_Date (fun () -> encode_instance key_Date ~kind:(IDate 0.));
 	Hashtbl.add h key_Date (fun () -> encode_instance key_Date ~kind:(IDate 0.));
 	Hashtbl.add h key_EReg (fun () -> encode_instance key_EReg ~kind:(IRegex {r = Pcre.regexp ""; r_rex_string = create_ascii "~//"; r_global = false; r_string = ""; r_groups = [||]}));
 	Hashtbl.add h key_EReg (fun () -> encode_instance key_EReg ~kind:(IRegex {r = Pcre.regexp ""; r_rex_string = create_ascii "~//"; r_global = false; r_string = ""; r_groups = [||]}));
-	Hashtbl.add h key_String (fun () -> encode_string "");
+	Hashtbl.add h key_String (fun () -> v_empty_string);
 	Hashtbl.add h key_haxe_ds_StringMap (fun () -> encode_instance key_haxe_ds_StringMap ~kind:(IStringMap (StringHashtbl.create ())));
 	Hashtbl.add h key_haxe_ds_StringMap (fun () -> encode_instance key_haxe_ds_StringMap ~kind:(IStringMap (StringHashtbl.create ())));
 	Hashtbl.add h key_haxe_ds_IntMap (fun () -> encode_instance key_haxe_ds_IntMap ~kind:(IIntMap (IntHashtbl.create ())));
 	Hashtbl.add h key_haxe_ds_IntMap (fun () -> encode_instance key_haxe_ds_IntMap ~kind:(IIntMap (IntHashtbl.create ())));
 	Hashtbl.add h key_haxe_ds_ObjectMap (fun () -> encode_instance key_haxe_ds_ObjectMap ~kind:(IObjectMap (Obj.magic (ValueHashtbl.create 0))));
 	Hashtbl.add h key_haxe_ds_ObjectMap (fun () -> encode_instance key_haxe_ds_ObjectMap ~kind:(IObjectMap (Obj.magic (ValueHashtbl.create 0))));

+ 4 - 0
src/macro/eval/evalString.ml

@@ -34,6 +34,10 @@ let create_with_length s length = {
 	soffsets = [];
 	soffsets = [];
 }
 }
 
 
+let empty_string = create_ascii ""
+
+let v_empty_string = VString empty_string
+
 let create_unknown s =
 let create_unknown s =
 	vstring (create_with_length s (try UTF8.length s with _ -> String.length s))
 	vstring (create_with_length s (try UTF8.length s with _ -> String.length s))
 
 

+ 35 - 10
src/macro/eval/evalThread.ml

@@ -16,7 +16,7 @@ module Deque = struct
 		Mutex.unlock this.dmutex
 		Mutex.unlock this.dmutex
 
 
 	let pop this blocking =
 	let pop this blocking =
-		let rec loop () =
+		if not blocking then begin
 			Mutex.lock this.dmutex;
 			Mutex.lock this.dmutex;
 			match this.dvalues with
 			match this.dvalues with
 			| v :: vl ->
 			| v :: vl ->
@@ -24,16 +24,41 @@ module Deque = struct
 				Mutex.unlock this.dmutex;
 				Mutex.unlock this.dmutex;
 				Some v
 				Some v
 			| [] ->
 			| [] ->
-				if not blocking then begin
-					Mutex.unlock this.dmutex;
-					None
-				end else begin
-					Mutex.unlock this.dmutex;
+				Mutex.unlock this.dmutex;
+				None
+		end else begin
+			(* Optimistic first attempt with immediate lock. *)
+			Mutex.lock this.dmutex;
+			begin match this.dvalues with
+			| v :: vl ->
+				this.dvalues <- vl;
+				Mutex.unlock this.dmutex;
+				Some v
+			| [] ->
+				Mutex.unlock this.dmutex;
+				(* First attempt failed, let's be pessimistic now to avoid locks. *)
+				let rec loop () =
 					Thread.yield();
 					Thread.yield();
-					loop()
-				end
-		in
-		loop()
+					match this.dvalues with
+					| v :: vl ->
+						(* Only lock if there's a chance to have a value. This avoids high amounts of unneeded locking. *)
+						Mutex.lock this.dmutex;
+						(* We have to check again because the value could be gone by now. *)
+						begin match this.dvalues with
+						| v :: vl ->
+							this.dvalues <- vl;
+							Mutex.unlock this.dmutex;
+							Some v
+						| [] ->
+							Mutex.unlock this.dmutex;
+							loop()
+						end
+					| [] ->
+						loop()
+				in
+				loop()
+			end
+		end
 
 
 	let push this i =
 	let push this i =
 		Mutex.lock this.dmutex;
 		Mutex.lock this.dmutex;

+ 12 - 12
src/macro/eval/evalValue.ml

@@ -60,18 +60,18 @@ module StringHashtbl = struct
 end
 end
 
 
 module IntHashtbl = struct
 module IntHashtbl = struct
-	type 'value t = 'value IntMap.t ref
-
-	let add this key v = this := IntMap.add key v !this
-	let copy this = ref !this
-	let create () = ref IntMap.empty
-	let find this key = IntMap.find key !this
-	let fold f this acc = IntMap.fold f !this acc
-	let is_empty this = IntMap.is_empty !this
-	let iter f this = IntMap.iter f !this
-	let mem this key = IntMap.mem key !this
-	let remove this key = this := IntMap.remove key !this
-	let clear this = this := IntMap.empty
+	type 'value t = (int, 'value) Hashtbl.t
+
+	let add this key v = Hashtbl.replace this key v
+	let copy this = Hashtbl.copy this
+	let create () = Hashtbl.create 0
+	let find this key = Hashtbl.find this key
+	let fold f this acc = Hashtbl.fold f this acc
+	let is_empty this = Hashtbl.length this = 0
+	let iter f this = Hashtbl.iter f this
+	let mem this key = Hashtbl.mem this key
+	let remove this key = Hashtbl.remove this key
+	let clear this = Hashtbl.clear this
 end
 end
 
 
 type vregex = {
 type vregex = {

+ 3 - 3
src/optimization/analyzer.ml

@@ -365,11 +365,11 @@ module ConstPropagation = DataFlow(struct
 	let top = Top
 	let top = Top
 	let bottom = Bottom
 	let bottom = Bottom
 
 
-	let equals lat1 lat2 = match lat1,lat2 with
+	let rec equals lat1 lat2 = match lat1,lat2 with
 		| Top,Top | Bottom,Bottom -> true
 		| Top,Top | Bottom,Bottom -> true
 		| Const ct1,Const ct2 -> ct1 = ct2
 		| Const ct1,Const ct2 -> ct1 = ct2
 		| Null t1,Null t2 -> t1 == t2
 		| Null t1,Null t2 -> t1 == t2
-		| EnumValue(i1,_),EnumValue(i2,_) -> i1 = i2
+		| EnumValue(i1,tl1),EnumValue(i2,tl2) -> i1 = i2 && List.for_all2 equals tl1 tl2
 		| ModuleType(mt1,_),ModuleType (mt2,_) -> mt1 == mt2
 		| ModuleType(mt1,_),ModuleType (mt2,_) -> mt1 == mt2
 		| _ -> false
 		| _ -> false
 
 
@@ -517,7 +517,7 @@ end)
 (*
 (*
 	Propagates local variables to other local variables.
 	Propagates local variables to other local variables.
 
 
-	Respects scopes on targets where it matters (all except JS and As3).
+	Respects scopes on targets where it matters (all except JS).
 *)
 *)
 module CopyPropagation = DataFlow(struct
 module CopyPropagation = DataFlow(struct
 	open BasicBlock
 	open BasicBlock

+ 1 - 1
src/optimization/analyzerConfig.ml

@@ -64,7 +64,7 @@ let is_ignored meta =
 
 
 let get_base_config com =
 let get_base_config com =
 	{
 	{
-		optimize = Common.raw_defined com "analyzer-optimize";
+		optimize = Common.defined com Define.AnalyzerOptimize;
 		const_propagation = not (Common.raw_defined com "analyzer-no-const-propagation");
 		const_propagation = not (Common.raw_defined com "analyzer-no-const-propagation");
 		copy_propagation = not (Common.raw_defined com "analyzer-no-copy-propagation");
 		copy_propagation = not (Common.raw_defined com "analyzer-no-copy-propagation");
 		local_dce = not (Common.raw_defined com "analyzer-no-local-dce");
 		local_dce = not (Common.raw_defined com "analyzer-no-local-dce");

+ 3 - 3
src/optimization/analyzerTexprTransformer.ml

@@ -243,6 +243,7 @@ let rec func ctx bb tf t p =
 		let e = List.fold_left (fun e f -> f e) e fl in
 		let e = List.fold_left (fun e f -> f e) e fl in
 		bb,e
 		bb,e
 	and declare_var_and_assign bb v e p =
 	and declare_var_and_assign bb v e p =
+		no_void v.v_type p;
 		(* TODO: this section shouldn't be here because it can be handled as part of the normal value processing *)
 		(* 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 ->
@@ -264,7 +265,6 @@ let rec func ctx bb tf t p =
 				bb,e
 				bb,e
 		in
 		in
 		let generate bb e =
 		let generate bb e =
-			no_void v.v_type p;
 			let ev = mk (TLocal v) v.v_type p in
 			let ev = mk (TLocal v) v.v_type p in
 			let was_assigned = ref false in
 			let was_assigned = ref false in
 			let assign e =
 			let assign e =
@@ -475,7 +475,7 @@ let rec func ctx bb tf t p =
 			let bb_next = if bb_breaks = [] then begin
 			let bb_next = if bb_breaks = [] then begin
 				(* The loop appears to be infinite, let's assume that something within it throws.
 				(* The loop appears to be infinite, let's assume that something within it throws.
 				   Otherwise DCE's mark-pass won't see its body and removes everything. *)
 				   Otherwise DCE's mark-pass won't see its body and removes everything. *)
-				add_cfg_edge bb_loop_body_next bb_exit CFGMaybeThrow;
+				add_cfg_edge bb_loop_body bb_exit CFGMaybeThrow;
 				g.g_unreachable
 				g.g_unreachable
 			end else
 			end else
 				create_node BKNormal bb.bb_type bb.bb_pos
 				create_node BKNormal bb.bb_type bb.bb_pos
@@ -484,7 +484,7 @@ let rec func ctx bb tf t p =
 			set_syntax_edge bb_loop_pre (SEWhile(bb_loop_head,bb_loop_body,bb_next));
 			set_syntax_edge bb_loop_pre (SEWhile(bb_loop_head,bb_loop_body,bb_next));
 			close_node g bb_loop_pre;
 			close_node g bb_loop_pre;
 			add_texpr bb_loop_pre {e with eexpr = TWhile(e1,make_block_meta bb_loop_body,NormalWhile)};
 			add_texpr bb_loop_pre {e with eexpr = TWhile(e1,make_block_meta bb_loop_body,NormalWhile)};
-			add_cfg_edge bb_loop_body_next bb_loop_head CFGGoto;
+			if bb_loop_body_next != g.g_unreachable then add_cfg_edge bb_loop_body_next bb_loop_head CFGGoto;
 			add_cfg_edge bb_loop_head bb_loop_body CFGGoto;
 			add_cfg_edge bb_loop_head bb_loop_body CFGGoto;
 			close_node g bb_loop_body_next;
 			close_node g bb_loop_body_next;
 			close_node g bb_loop_head;
 			close_node g bb_loop_head;

+ 13 - 7
src/optimization/dce.ml

@@ -97,6 +97,12 @@ let keep_whole_enum dce en =
 	Meta.has_one_of keep_metas en.e_meta
 	Meta.has_one_of keep_metas en.e_meta
 	|| not (dce.full || is_std_file dce en.e_module.m_extra.m_file || has_meta Meta.Dce en.e_meta)
 	|| not (dce.full || is_std_file dce en.e_module.m_extra.m_file || has_meta Meta.Dce en.e_meta)
 
 
+let mk_used_meta pos =
+	Meta.Used,[],(mk_zero_range_pos pos)
+
+let mk_keep_meta pos =
+	Meta.Keep,[],(mk_zero_range_pos pos)
+
 (*
 (*
 	Check if a field is kept.
 	Check if a field is kept.
 	`keep_field` is checked to determine the DCE entry points, i.e. all fields that have `@:keep` or kept for other reasons.
 	`keep_field` is checked to determine the DCE entry points, i.e. all fields that have `@:keep` or kept for other reasons.
@@ -148,7 +154,7 @@ and check_and_add_feature dce s =
 and mark_field dce c cf stat =
 and mark_field dce c cf stat =
 	let add cf =
 	let add cf =
 		if not (Meta.has Meta.Used cf.cf_meta) then begin
 		if not (Meta.has Meta.Used cf.cf_meta) then begin
-			cf.cf_meta <- (Meta.Used,[],cf.cf_pos) :: cf.cf_meta;
+			cf.cf_meta <- (mk_used_meta cf.cf_pos) :: cf.cf_meta;
 			dce.added_fields <- (c,cf,stat) :: dce.added_fields;
 			dce.added_fields <- (c,cf,stat) :: dce.added_fields;
 			dce.marked_fields <- cf :: dce.marked_fields;
 			dce.marked_fields <- cf :: dce.marked_fields;
 			check_feature dce (Printf.sprintf "%s.%s" (s_type_path c.cl_path) cf.cf_name);
 			check_feature dce (Printf.sprintf "%s.%s" (s_type_path c.cl_path) cf.cf_name);
@@ -195,13 +201,13 @@ let rec update_marked_class_fields dce c =
 
 
 (* mark a class as kept. If the class has fields marked as @:?keep, make sure to keep them *)
 (* mark a class as kept. If the class has fields marked as @:?keep, make sure to keep them *)
 and mark_class dce c = if not (Meta.has Meta.Used c.cl_meta) then begin
 and mark_class dce c = if not (Meta.has Meta.Used c.cl_meta) then begin
-	c.cl_meta <- (Meta.Used,[],c.cl_pos) :: c.cl_meta;
+	c.cl_meta <- (mk_used_meta c.cl_pos) :: c.cl_meta;
 	check_feature dce (Printf.sprintf "%s.*" (s_type_path c.cl_path));
 	check_feature dce (Printf.sprintf "%s.*" (s_type_path c.cl_path));
 	update_marked_class_fields dce c;
 	update_marked_class_fields dce c;
 end
 end
 
 
 let rec mark_enum dce e = if not (Meta.has Meta.Used e.e_meta) then begin
 let rec mark_enum dce e = if not (Meta.has Meta.Used e.e_meta) then begin
-	e.e_meta <- (Meta.Used,[],e.e_pos) :: e.e_meta;
+	e.e_meta <- (mk_used_meta e.e_pos) :: e.e_meta;
 	check_and_add_feature dce "has_enum";
 	check_and_add_feature dce "has_enum";
 	check_feature dce (Printf.sprintf "%s.*" (s_type_path e.e_path));
 	check_feature dce (Printf.sprintf "%s.*" (s_type_path e.e_path));
 	PMap.iter (fun _ ef -> mark_t dce ef.ef_pos ef.ef_type) e.e_constrs;
 	PMap.iter (fun _ ef -> mark_t dce ef.ef_pos ef.ef_type) e.e_constrs;
@@ -209,7 +215,7 @@ end
 
 
 and mark_abstract dce a = if not (Meta.has Meta.Used a.a_meta) then begin
 and mark_abstract dce a = if not (Meta.has Meta.Used a.a_meta) then begin
 	check_feature dce (Printf.sprintf "%s.*" (s_type_path a.a_path));
 	check_feature dce (Printf.sprintf "%s.*" (s_type_path a.a_path));
-	a.a_meta <- (Meta.Used,[],a.a_pos) :: a.a_meta
+	a.a_meta <- (mk_used_meta a.a_pos) :: a.a_meta
 end
 end
 
 
 (* mark a type as kept *)
 (* mark a type as kept *)
@@ -219,7 +225,7 @@ and mark_t dce p t =
 		begin match follow t with
 		begin match follow t with
 		| TInst({cl_kind = KTypeParameter tl} as c,pl) ->
 		| TInst({cl_kind = KTypeParameter tl} as c,pl) ->
 			if not (Meta.has Meta.Used c.cl_meta) then begin
 			if not (Meta.has Meta.Used c.cl_meta) then begin
-				c.cl_meta <- (Meta.Used,[],c.cl_pos) :: c.cl_meta;
+				c.cl_meta <- (mk_used_meta c.cl_pos) :: c.cl_meta;
 				List.iter (mark_t dce p) tl;
 				List.iter (mark_t dce p) tl;
 			end;
 			end;
 			List.iter (mark_t dce p) pl
 			List.iter (mark_t dce p) pl
@@ -779,7 +785,7 @@ let sweep dce com =
 				end;
 				end;
 			in
 			in
 			(* add :keep so subsequent filter calls do not process class fields again *)
 			(* add :keep so subsequent filter calls do not process class fields again *)
-			c.cl_meta <- (Meta.Keep,[],c.cl_pos) :: c.cl_meta;
+			c.cl_meta <- (mk_keep_meta c.cl_pos) :: c.cl_meta;
  			c.cl_ordered_statics <- List.filter (fun cf ->
  			c.cl_ordered_statics <- List.filter (fun cf ->
 				let b = keep_field dce cf c true in
 				let b = keep_field dce cf c true in
 				if not b then begin
 				if not b then begin
@@ -843,7 +849,7 @@ let run com main mode =
 	} in
 	} in
 	begin match main with
 	begin match main with
 		| Some {eexpr = TCall({eexpr = TField(e,(FStatic(c,cf)))},_)} | Some {eexpr = TBlock ({ eexpr = TCall({eexpr = TField(e,(FStatic(c,cf)))},_)} :: _)} ->
 		| Some {eexpr = TCall({eexpr = TField(e,(FStatic(c,cf)))},_)} | Some {eexpr = TBlock ({ eexpr = TCall({eexpr = TField(e,(FStatic(c,cf)))},_)} :: _)} ->
-			cf.cf_meta <- (Meta.Keep,[],cf.cf_pos) :: cf.cf_meta
+			cf.cf_meta <- (mk_keep_meta cf.cf_pos) :: cf.cf_meta
 		| _ ->
 		| _ ->
 			()
 			()
 	end;
 	end;

+ 15 - 6
src/optimization/inline.ml

@@ -136,7 +136,12 @@ let api_inline ctx c field params p =
 			mk (TBinop (Ast.OpEq, tof, (mk (TConst (TString t)) tstring p))) tbool p
 			mk (TBinop (Ast.OpEq, tof, (mk (TConst (TString t)) tstring p))) tbool p
 		in
 		in
 
 
-		(match t.eexpr with
+		let rec skip_cast = function
+			| { eexpr = TCast (e, None) } -> skip_cast e
+			| e -> e
+		in
+
+		(match (skip_cast t).eexpr with
 		(* generate simple typeof checks for basic types *)
 		(* generate simple typeof checks for basic types *)
 		| TTypeExpr (TClassDecl ({ cl_path = [],"String" })) -> Some (typeof "string")
 		| TTypeExpr (TClassDecl ({ cl_path = [],"String" })) -> Some (typeof "string")
 		| TTypeExpr (TAbstractDecl ({ a_path = [],"Bool" })) -> Some (typeof "boolean")
 		| TTypeExpr (TAbstractDecl ({ a_path = [],"Bool" })) -> Some (typeof "boolean")
@@ -149,10 +154,14 @@ let api_inline ctx c field params p =
 		| TTypeExpr (TClassDecl ({ cl_path = [],"Array" })) ->
 		| TTypeExpr (TClassDecl ({ cl_path = [],"Array" })) ->
 			(* generate (o instanceof Array) && o.__enum__ == null check *)
 			(* generate (o instanceof Array) && o.__enum__ == null check *)
 			let iof = Texpr.Builder.fcall (eJsSyntax()) "instanceof" [o;t] tbool p in
 			let iof = Texpr.Builder.fcall (eJsSyntax()) "instanceof" [o;t] tbool p in
-			let enum = mk (TField (o, FDynamic "__enum__")) (mk_mono()) p in
-			let null = mk (TConst TNull) (mk_mono()) p in
-			let not_enum = mk (TBinop (Ast.OpEq, enum, null)) tbool p in
-			Some (mk (TBinop (Ast.OpBoolAnd, iof, not_enum)) tbool p)
+			if not (Common.defined ctx.com Define.JsEnumsAsArrays) then
+				Some iof
+			else begin
+				let enum = mk (TField (o, FDynamic "__enum__")) t_dynamic p in
+				let null = mk (TConst TNull) t_dynamic p in
+				let not_enum = mk (TBinop (Ast.OpEq, enum, null)) tbool p in
+				Some (mk (TBinop (Ast.OpBoolAnd, iof, not_enum)) tbool p)
+			end
 		| TTypeExpr (TClassDecl cls) ->
 		| TTypeExpr (TClassDecl cls) ->
 			if cls.cl_interface then
 			if cls.cl_interface then
 				Some (Texpr.Builder.fcall (eJsBoot()) "__implements" [o;t] tbool p)
 				Some (Texpr.Builder.fcall (eJsBoot()) "__implements" [o;t] tbool p)
@@ -576,7 +585,7 @@ class inline_state ctx ethis params cf f p = object(self)
 			| TVar (v, Some { eexpr = TConst _ }) ->
 			| TVar (v, Some { eexpr = TConst _ }) ->
 				(try
 				(try
 					let data = Hashtbl.find locals v.v_id in
 					let data = Hashtbl.find locals v.v_id in
-					if data.i_read = 0 && not data.i_write then mk (TBlock []) e.etype e.epos
+					if data.i_read = 0 && data.i_called = 0 && not data.i_write then mk (TBlock []) e.etype e.epos
 					else Type.map_expr drop_unused_vars e
 					else Type.map_expr drop_unused_vars e
 				with Not_found ->
 				with Not_found ->
 					Type.map_expr drop_unused_vars e
 					Type.map_expr drop_unused_vars e

+ 1 - 0
src/syntax/grammar.mly

@@ -926,6 +926,7 @@ and parse_constraint_param s =
 		let cto = (match s with parser
 		let cto = (match s with parser
 			| [< '(DblDot,_); s >] ->
 			| [< '(DblDot,_); s >] ->
 				(match s with parser
 				(match s with parser
+				| [< '(POpen,p1); t = parse_complex_type; '(PClose,p2) >] -> Some t
 				| [< t = parse_complex_type >] -> Some t
 				| [< t = parse_complex_type >] -> Some t
 				| [< >] -> serror())
 				| [< >] -> serror())
 			| [< >] -> None
 			| [< >] -> None

+ 1 - 1
src/syntax/parserEntry.ml

@@ -32,7 +32,7 @@ type small_type =
 	| TVersion of (version * version * version) * (version list option)
 	| TVersion of (version * version * version) * (version list option)
 
 
 let is_true = function
 let is_true = function
-	| TBool false | TNull | TFloat 0. | TString "" -> false
+	| TBool false | TNull | TFloat 0. -> false
 	| _ -> true
 	| _ -> true
 
 
 let s_small_type v =
 let s_small_type v =

+ 6 - 6
src/typing/calls.ml

@@ -118,6 +118,12 @@ let mk_array_set_call ctx (cf,tf,r,e1,e2o) c ebase p =
 			let ef = mk (TField(et,(FStatic(c,cf)))) tf p in
 			let ef = mk (TField(et,(FStatic(c,cf)))) tf p in
 			make_call ctx ef [ebase;e1;evalue] r p
 			make_call ctx ef [ebase;e1;evalue] r p
 
 
+let rec needs_temp_var e =
+	match e.eexpr with
+	| TLocal _ | TTypeExpr _ | TConst _ -> false
+	| TField (e, _) | TParenthesis e -> needs_temp_var e
+	| _ -> true
+
 let call_to_string ctx ?(resume=false) e =
 let call_to_string ctx ?(resume=false) e =
 	let gen_to_string e =
 	let gen_to_string e =
 		(* Ignore visibility of the toString field. *)
 		(* Ignore visibility of the toString field. *)
@@ -129,12 +135,6 @@ let call_to_string ctx ?(resume=false) e =
 	if ctx.com.config.pf_static && not (is_nullable e.etype) then
 	if ctx.com.config.pf_static && not (is_nullable e.etype) then
 		gen_to_string e
 		gen_to_string e
 	else begin (* generate `if(e == null) 'null' else e.toString()` *)
 	else begin (* generate `if(e == null) 'null' else e.toString()` *)
-		let rec needs_temp_var e =
-			match e.eexpr with
-			| TLocal _ | TTypeExpr _ | TConst _ -> false
-			| TField (e, _) | TParenthesis e -> needs_temp_var e
-			| _ -> true
-		in
 		let string_null = mk (TConst (TString "null")) ctx.t.tstring e.epos in
 		let string_null = mk (TConst (TString "null")) ctx.t.tstring e.epos in
 		if needs_temp_var e then
 		if needs_temp_var e then
 			let tmp = alloc_var VGenerated "tmp" e.etype e.epos in
 			let tmp = alloc_var VGenerated "tmp" e.etype e.epos in

+ 4 - 5
src/typing/fields.ml

@@ -250,15 +250,14 @@ let field_access ctx mode f fmode t e p =
 					| _ -> false
 					| _ -> false
 				)
 				)
 			in
 			in
-			if bypass_accessor then
-				let prefix = (match ctx.com.platform with Flash when Common.defined ctx.com Define.As3 -> "$" | _ -> "") in
+			if bypass_accessor then (
 				(match e.eexpr with TLocal _ when Common.defined ctx.com Define.Haxe3Compat -> ctx.com.warning "Field set has changed here in Haxe 4: call setter explicitly to keep Haxe 3.x behaviour" p | _ -> ());
 				(match e.eexpr with TLocal _ when Common.defined ctx.com Define.Haxe3Compat -> ctx.com.warning "Field set has changed here in Haxe 4: call setter explicitly to keep Haxe 3.x behaviour" p | _ -> ());
 				if not (is_physical_field f) then begin
 				if not (is_physical_field f) then begin
 					display_error ctx "This field cannot be accessed because it is not a real variable" p;
 					display_error ctx "This field cannot be accessed because it is not a real variable" p;
 					display_error ctx "Add @:isVar here to enable it" f.cf_pos;
 					display_error ctx "Add @:isVar here to enable it" f.cf_pos;
 				end;
 				end;
-				AKExpr (mk (TField (e,if prefix = "" then fmode else FDynamic (prefix ^ f.cf_name))) t p)
-			else if is_abstract_this_access() then begin
+				AKExpr (mk (TField (e,fmode)) t p)
+			) else if is_abstract_this_access() then begin
 				let this = get_this ctx p in
 				let this = get_this ctx p in
 				if mode = MSet then begin
 				if mode = MSet then begin
 					let c,a = match ctx.curclass with {cl_kind = KAbstractImpl a} as c -> c,a | _ -> assert false in
 					let c,a = match ctx.curclass with {cl_kind = KAbstractImpl a} as c -> c,a | _ -> assert false in
@@ -337,7 +336,7 @@ let rec using_field ctx mode e i p =
 		loop ctx.m.module_using
 		loop ctx.m.module_using
 	with Not_found -> try
 	with Not_found -> try
 		(* type using from `@:using(Path)` *)
 		(* type using from `@:using(Path)` *)
-		let mt = module_type_of_type e.etype in
+		let mt = module_type_of_type (follow e.etype) in
 		loop (t_infos mt).mt_using
 		loop (t_infos mt).mt_using
 	with Not_found | Exit -> try
 	with Not_found | Exit -> try
 		(* global using *)
 		(* global using *)

+ 33 - 4
src/typing/forLoop.ml

@@ -9,13 +9,42 @@ open Error
 open Texpr.Builder
 open Texpr.Builder
 
 
 let optimize_for_loop_iterator ctx v e1 e2 p =
 let optimize_for_loop_iterator ctx v e1 e2 p =
-	let c,tl = (match follow e1.etype with TInst (c,pl) -> c,pl | _ -> raise Exit) in
+	let c,tl =
+		let rec get_class_and_params e =
+			match follow e.etype with
+			| TInst (c,pl) -> c,pl
+			| _ ->
+				match e.eexpr with
+				| TCast (e,None) ->
+					get_class_and_params e
+				| TCall ({ eexpr = TField (_, FInstance (c,pl,cf)) }, _) ->
+					let t = apply_params c.cl_params pl cf.cf_type in
+					(match follow t with
+					| TFun (_, t) ->
+						(match follow t with
+						| TInst (c,pl) -> c,pl
+						| _ -> raise Exit
+						)
+					| _ -> raise Exit
+					)
+				| _ -> raise Exit
+		in
+		get_class_and_params e1
+	in
 	let _, _, fhasnext = (try raw_class_field (fun cf -> apply_params c.cl_params tl cf.cf_type) c tl "hasNext" with Not_found -> raise Exit) in
 	let _, _, fhasnext = (try raw_class_field (fun cf -> apply_params c.cl_params tl cf.cf_type) c tl "hasNext" with Not_found -> raise Exit) in
 	if fhasnext.cf_kind <> Method MethInline then raise Exit;
 	if fhasnext.cf_kind <> Method MethInline then raise Exit;
-	let tmp = gen_local ctx e1.etype e1.epos in
-	let eit = mk (TLocal tmp) e1.etype p in
+	let it_type = TInst(c,tl) in
+	let tmp = gen_local ctx it_type e1.epos in
+	let eit = mk (TLocal tmp) it_type p in
 	let ehasnext = make_call ctx (mk (TField (eit,FInstance (c, tl, fhasnext))) (TFun([],ctx.t.tbool)) p) [] ctx.t.tbool p in
 	let ehasnext = make_call ctx (mk (TField (eit,FInstance (c, tl, fhasnext))) (TFun([],ctx.t.tbool)) p) [] ctx.t.tbool p in
-	let enext = mk (TVar (v,Some (make_call ctx (mk (TField (eit,quick_field_dynamic eit.etype "next")) (TFun ([],v.v_type)) p) [] v.v_type p))) ctx.t.tvoid p in
+	let fa_next =
+		try
+			match raw_class_field (fun cf -> apply_params c.cl_params tl cf.cf_type) c tl "next" with
+			| _, _, fa -> FInstance (c, tl, fa)
+		with Not_found ->
+			quick_field_dynamic eit.etype "next"
+	in
+	let enext = mk (TVar (v,Some (make_call ctx (mk (TField (eit,fa_next)) (TFun ([],v.v_type)) p) [] v.v_type p))) ctx.t.tvoid p in
 	let eblock = (match e2.eexpr with
 	let eblock = (match e2.eexpr with
 		| TBlock el -> { e2 with eexpr = TBlock (enext :: el) }
 		| TBlock el -> { e2 with eexpr = TBlock (enext :: el) }
 		| _ -> mk (TBlock [enext;e2]) ctx.t.tvoid p
 		| _ -> mk (TBlock [enext;e2]) ctx.t.tvoid p

+ 96 - 59
src/typing/nullSafety.ml

@@ -34,6 +34,7 @@ type safety_mode =
 	| SMOff
 	| SMOff
 	| SMLoose
 	| SMLoose
 	| SMStrict
 	| SMStrict
+	| SMStrictThreaded
 
 
 (**
 (**
 	Terminates compiler process and prints user-friendly instructions about filing an issue in compiler repo.
 	Terminates compiler process and prints user-friendly instructions about filing an issue in compiler repo.
@@ -136,18 +137,18 @@ type safety_subject =
 	*)
 	*)
 	| SNotSuitable
 	| SNotSuitable
 
 
-let rec get_subject loose_safety expr =
+let rec get_subject mode expr =
 	match (reveal_expr expr).eexpr with
 	match (reveal_expr expr).eexpr with
 		| TLocal v ->
 		| TLocal v ->
 			SLocalVar v.v_id
 			SLocalVar v.v_id
-		| TField ({ eexpr = TTypeExpr _ }, FStatic (cls, field)) when loose_safety || (has_class_field_flag field CfFinal) ->
+		| TField ({ eexpr = TTypeExpr _ }, FStatic (cls, field)) when (mode <> SMStrictThreaded) || (has_class_field_flag field CfFinal) ->
 			SFieldOfClass (cls.cl_path, [field.cf_name])
 			SFieldOfClass (cls.cl_path, [field.cf_name])
-		| TField ({ eexpr = TConst TThis }, (FInstance (_, _, field) | FAnon field)) when loose_safety || (has_class_field_flag field CfFinal) ->
+		| TField ({ eexpr = TConst TThis }, (FInstance (_, _, field) | FAnon field)) when (mode <> SMStrictThreaded) || (has_class_field_flag field CfFinal) ->
 			SFieldOfThis [field.cf_name]
 			SFieldOfThis [field.cf_name]
-		| TField ({ eexpr = TLocal v }, (FInstance (_, _, field) | FAnon field)) when loose_safety || (has_class_field_flag field CfFinal) ->
+		| TField ({ eexpr = TLocal v }, (FInstance (_, _, field) | FAnon field)) when (mode <> SMStrictThreaded) || (has_class_field_flag field CfFinal) ->
 			SFieldOfLocalVar (v.v_id, [field.cf_name])
 			SFieldOfLocalVar (v.v_id, [field.cf_name])
-		| TField (e, (FInstance (_, _, field) | FAnon field)) when loose_safety ->
-			(match get_subject loose_safety e with
+		| TField (e, (FInstance (_, _, field) | FAnon field)) when (mode <> SMStrictThreaded) ->
+			(match get_subject mode e with
 				| SFieldOfClass (path, fields) -> SFieldOfClass (path, field.cf_name :: fields)
 				| SFieldOfClass (path, fields) -> SFieldOfClass (path, field.cf_name :: fields)
 				| SFieldOfThis fields -> SFieldOfThis (field.cf_name :: fields)
 				| SFieldOfThis fields -> SFieldOfThis (field.cf_name :: fields)
 				| SFieldOfLocalVar (var_id, fields) -> SFieldOfLocalVar (var_id, field.cf_name :: fields)
 				| SFieldOfLocalVar (var_id, fields) -> SFieldOfLocalVar (var_id, field.cf_name :: fields)
@@ -155,13 +156,17 @@ let rec get_subject loose_safety expr =
 			)
 			)
 		|_ -> SNotSuitable
 		|_ -> SNotSuitable
 
 
-let rec is_suitable loose_safety expr =
+(**
+	Check if provided expression is a subject to null safety.
+	E.g. a call cannot be such a subject, because we cannot track null-state of the call result.
+*)
+let rec is_suitable mode expr =
 	match (reveal_expr expr).eexpr with
 	match (reveal_expr expr).eexpr with
 		| TField ({ eexpr = TConst TThis }, FInstance _)
 		| TField ({ eexpr = TConst TThis }, FInstance _)
 		| TField ({ eexpr = TLocal _ }, (FInstance _ | FAnon _))
 		| TField ({ eexpr = TLocal _ }, (FInstance _ | FAnon _))
 		| TField ({ eexpr = TTypeExpr _ }, FStatic _)
 		| TField ({ eexpr = TTypeExpr _ }, FStatic _)
 		| TLocal _ -> true
 		| TLocal _ -> true
-		| TField (target, (FInstance _ | FStatic _ | FAnon _)) when loose_safety -> is_suitable loose_safety target
+		| TField (target, (FInstance _ | FStatic _ | FAnon _)) when mode <> SMStrictThreaded -> is_suitable mode target
 		|_ -> false
 		|_ -> false
 
 
 class unificator =
 class unificator =
@@ -341,7 +346,7 @@ let rec can_pass_type src dst =
 	Collect nullable local vars which are checked against `null`.
 	Collect nullable local vars which are checked against `null`.
 	Returns a tuple of (vars_checked_to_be_null * vars_checked_to_be_not_null) in case `condition` evaluates to `true`.
 	Returns a tuple of (vars_checked_to_be_null * vars_checked_to_be_not_null) in case `condition` evaluates to `true`.
 *)
 *)
-let rec process_condition loose_safety condition (is_nullable_expr:texpr->bool) callback =
+let rec process_condition mode condition (is_nullable_expr:texpr->bool) callback =
 	let nulls = ref []
 	let nulls = ref []
 	and not_nulls = ref [] in
 	and not_nulls = ref [] in
 	let add to_nulls expr =
 	let add to_nulls expr =
@@ -352,17 +357,17 @@ let rec process_condition loose_safety condition (is_nullable_expr:texpr->bool)
 	let rec traverse positive e =
 	let rec traverse positive e =
 		match e.eexpr with
 		match e.eexpr with
 			| TUnop (Not, Prefix, e) -> traverse (not positive) e
 			| TUnop (Not, Prefix, e) -> traverse (not positive) e
-			| TBinop (OpEq, { eexpr = TConst TNull }, checked_expr) when is_suitable loose_safety checked_expr ->
+			| TBinop (OpEq, { eexpr = TConst TNull }, checked_expr) when is_suitable mode checked_expr ->
 				add positive checked_expr
 				add positive checked_expr
-			| TBinop (OpEq, checked_expr, { eexpr = TConst TNull }) when is_suitable loose_safety checked_expr ->
+			| TBinop (OpEq, checked_expr, { eexpr = TConst TNull }) when is_suitable mode checked_expr ->
 				add positive checked_expr
 				add positive checked_expr
-			| TBinop (OpNotEq, { eexpr = TConst TNull }, checked_expr) when is_suitable loose_safety checked_expr ->
+			| TBinop (OpNotEq, { eexpr = TConst TNull }, checked_expr) when is_suitable mode checked_expr ->
 				add (not positive) checked_expr
 				add (not positive) checked_expr
-			| TBinop (OpNotEq, checked_expr, { eexpr = TConst TNull }) when is_suitable loose_safety checked_expr ->
+			| TBinop (OpNotEq, checked_expr, { eexpr = TConst TNull }) when is_suitable mode checked_expr ->
 				add (not positive) checked_expr
 				add (not positive) checked_expr
-			| TBinop (OpEq, e, checked_expr) when is_suitable loose_safety checked_expr && not (is_nullable_expr e) ->
+			| TBinop (OpEq, e, checked_expr) when is_suitable mode checked_expr && not (is_nullable_expr e) ->
 				if positive then not_nulls := checked_expr :: !not_nulls
 				if positive then not_nulls := checked_expr :: !not_nulls
-			| TBinop (OpEq, checked_expr, e) when is_suitable loose_safety checked_expr && not (is_nullable_expr e) ->
+			| TBinop (OpEq, checked_expr, e) when is_suitable mode checked_expr && not (is_nullable_expr e) ->
 				if positive then not_nulls := checked_expr :: !not_nulls
 				if positive then not_nulls := checked_expr :: !not_nulls
 			| TBinop (OpBoolAnd, left_expr, right_expr) when positive ->
 			| TBinop (OpBoolAnd, left_expr, right_expr) when positive ->
 				traverse positive left_expr;
 				traverse positive left_expr;
@@ -370,7 +375,7 @@ let rec process_condition loose_safety condition (is_nullable_expr:texpr->bool)
 			| TBinop (OpBoolAnd, left_expr, right_expr) when not positive ->
 			| TBinop (OpBoolAnd, left_expr, right_expr) when not positive ->
 				List.iter
 				List.iter
 					(fun e ->
 					(fun e ->
-						let _, not_nulls = process_condition loose_safety left_expr is_nullable_expr callback in
+						let _, not_nulls = process_condition mode left_expr is_nullable_expr callback in
 						List.iter (add true) not_nulls
 						List.iter (add true) not_nulls
 					)
 					)
 					[left_expr; right_expr]
 					[left_expr; right_expr]
@@ -380,7 +385,7 @@ let rec process_condition loose_safety condition (is_nullable_expr:texpr->bool)
 			| TBinop (OpBoolOr, left_expr, right_expr) when positive ->
 			| TBinop (OpBoolOr, left_expr, right_expr) when positive ->
 				List.iter
 				List.iter
 					(fun e ->
 					(fun e ->
-						let nulls, _ = process_condition loose_safety left_expr is_nullable_expr callback in
+						let nulls, _ = process_condition mode left_expr is_nullable_expr callback in
 						List.iter (add true) nulls
 						List.iter (add true) nulls
 					)
 					)
 					[left_expr; right_expr]
 					[left_expr; right_expr]
@@ -406,7 +411,7 @@ let rec contains_safe_meta metadata =
 	match metadata with
 	match metadata with
 		| [] -> false
 		| [] -> false
 		| (Meta.NullSafety, [], _) :: _
 		| (Meta.NullSafety, [], _) :: _
-		| (Meta.NullSafety, [(EConst (Ident ("Loose" | "Strict")), _)], _) :: _  -> true
+		| (Meta.NullSafety, [(EConst (Ident ("Loose" | "Strict" | "StrictThreaded")), _)], _) :: _  -> true
 		| _ :: rest -> contains_safe_meta rest
 		| _ :: rest -> contains_safe_meta rest
 
 
 let safety_enabled meta =
 let safety_enabled meta =
@@ -423,6 +428,8 @@ let safety_mode (metadata:Ast.metadata) =
 				traverse (Some SMLoose) rest
 				traverse (Some SMLoose) rest
 			| _, (Meta.NullSafety, [(EConst (Ident "Strict"), _)], _) :: rest ->
 			| _, (Meta.NullSafety, [(EConst (Ident "Strict"), _)], _) :: rest ->
 				traverse (Some SMStrict) rest
 				traverse (Some SMStrict) rest
+			| _, (Meta.NullSafety, [(EConst (Ident "StrictThreaded"), _)], _) :: rest ->
+				traverse (Some SMStrictThreaded) rest
 			| _, _ :: rest ->
 			| _, _ :: rest ->
 				traverse mode rest
 				traverse mode rest
 	in
 	in
@@ -435,7 +442,7 @@ let rec validate_safety_meta report (metadata:Ast.metadata) =
 		| [] -> ()
 		| [] -> ()
 		| (Meta.NullSafety, args, pos) :: rest ->
 		| (Meta.NullSafety, args, pos) :: rest ->
 			(match args with
 			(match args with
-				| ([] | [(EConst (Ident ("Off" | "Loose" | "Strict")), _)]) -> ()
+				| ([] | [(EConst (Ident ("Off" | "Loose" | "Strict" | "StrictThreaded")), _)]) -> ()
 				| _ -> add_error report "Invalid argument for @:nullSafety meta" pos
 				| _ -> add_error report "Invalid argument for @:nullSafety meta" pos
 			);
 			);
 			validate_safety_meta report rest
 			validate_safety_meta report rest
@@ -450,16 +457,6 @@ let should_be_initialized field =
 		| Var _ -> Meta.has Meta.IsVar field.cf_meta
 		| Var _ -> Meta.has Meta.IsVar field.cf_meta
 		| _ -> false
 		| _ -> false
 
 
-(**
-	Check if `field` is overridden in subclasses
-*)
-let is_overridden cls field =
-	let rec loop_inheritance c =
-		(PMap.mem field.cf_name c.cl_fields)
-		|| List.exists (fun d -> loop_inheritance d) c.cl_descendants;
-	in
-	List.exists (fun d -> loop_inheritance d) cls.cl_descendants
-
 (**
 (**
 	Check if all items of the `needle` list exist in the same order in the beginning of the `haystack` list.
 	Check if all items of the `needle` list exist in the same order in the beginning of the `haystack` list.
 *)
 *)
@@ -504,7 +501,7 @@ class immediate_execution =
 							(* known to be pure *)
 							(* known to be pure *)
 							| { cl_path = ([], "Array") }, _ -> true
 							| { cl_path = ([], "Array") }, _ -> true
 							(* try to analyze function code *)
 							(* try to analyze function code *)
-							| _, ({ cf_expr = (Some { eexpr = TFunction fn }) } as field) when (has_class_field_flag field CfFinal) || not (is_overridden cls field) ->
+							| _, ({ cf_expr = (Some { eexpr = TFunction fn }) } as field) when (has_class_field_flag field CfFinal) || not (FiltersCommon.is_overridden cls field) ->
 								if arg_num < 0 || arg_num >= List.length fn.tf_args then
 								if arg_num < 0 || arg_num >= List.length fn.tf_args then
 									false
 									false
 								else begin
 								else begin
@@ -638,31 +635,67 @@ class safety_scope (mode:safety_mode) (scope_type:scope_type) (safe_locals:(safe
 			match self#get_subject expr with
 			match self#get_subject expr with
 				| SNotSuitable -> ()
 				| SNotSuitable -> ()
 				| subj ->
 				| subj ->
-					let remove safe_subj safe_fields fields =
+					(*
+						If this is an assignment to a field, drop all safe field accesses first,
+						because it could alter an object of those field accesses.
+					*)
+					(match subj with
+						| SFieldOfClass _ | SFieldOfLocalVar _ | SFieldOfThis _ -> self#drop_safe_fields_in_strict_mode
+						| _ -> ()
+					);
+					let add_to_remove safe_subj safe_fields fields to_remove =
 						if list_starts_with_list (List.rev safe_fields) (List.rev fields) then
 						if list_starts_with_list (List.rev safe_fields) (List.rev fields) then
-							Hashtbl.remove safe_locals safe_subj
+							safe_subj :: to_remove
+						else
+							to_remove
 					in
 					in
-					Hashtbl.iter
-						(fun safe_subj safe_expr ->
-							match safe_subj, subj with
-								| SFieldOfLocalVar (safe_id, _), SLocalVar v_id when safe_id = v_id ->
-									Hashtbl.remove safe_locals safe_subj
-								| SFieldOfLocalVar (safe_id, safe_fields), SFieldOfLocalVar (v_id, fields) when safe_id = v_id ->
-									remove safe_subj safe_fields fields
-								| SFieldOfClass (safe_path, safe_fields), SFieldOfClass (path, fields) when safe_path = path ->
-									remove safe_subj safe_fields fields
-								| SFieldOfClass (safe_path, safe_fields), SFieldOfClass (path, fields) when safe_path = path ->
-									remove safe_subj safe_fields fields
-								| SFieldOfThis safe_fields, SFieldOfThis fields ->
-									remove safe_subj safe_fields fields
-								| _ -> ()
+					let remove_list =
+						Hashtbl.fold
+							(fun safe_subj safe_expr to_remove ->
+								match safe_subj, subj with
+									| SFieldOfLocalVar (safe_id, _), SLocalVar v_id when safe_id = v_id ->
+										safe_subj :: to_remove
+									| SFieldOfLocalVar (safe_id, safe_fields), SFieldOfLocalVar (v_id, fields) when safe_id = v_id ->
+										add_to_remove safe_subj safe_fields fields to_remove
+									| SFieldOfClass (safe_path, safe_fields), SFieldOfClass (path, fields) when safe_path = path ->
+										add_to_remove safe_subj safe_fields fields to_remove
+									| SFieldOfClass (safe_path, safe_fields), SFieldOfClass (path, fields) when safe_path = path ->
+										add_to_remove safe_subj safe_fields fields to_remove
+									| SFieldOfThis safe_fields, SFieldOfThis fields ->
+										add_to_remove safe_subj safe_fields fields to_remove
+									| _ -> to_remove
+							)
+							safe_locals []
+					in
+					List.iter (Hashtbl.remove safe_locals) remove_list
+		(**
+			Should be called upon a call.
+			In Strict mode making a call removes all field accesses from safety.
+		*)
+		method call_made =
+			self#drop_safe_fields_in_strict_mode
+		(**
+			Un-safe all field accesses if safety mode is one of strict modes
+		*)
+		method private drop_safe_fields_in_strict_mode =
+			match mode with
+			| SMOff | SMLoose -> ()
+			| SMStrict | SMStrictThreaded ->
+				let remove_list =
+					Hashtbl.fold
+						(fun subj expr to_remove ->
+							match subj with
+							| SFieldOfLocalVar _ | SFieldOfClass _ | SFieldOfThis _ -> subj :: to_remove
+							| _ -> to_remove
 						)
 						)
-						(Hashtbl.copy safe_locals)
+						safe_locals []
+				in
+				List.iter (Hashtbl.remove safe_locals) remove_list
 		(**
 		(**
 			Wrapper for `get_subject` function
 			Wrapper for `get_subject` function
 		*)
 		*)
 		method private get_subject =
 		method private get_subject =
-			get_subject (mode <> SMStrict)
+			get_subject mode
 	end
 	end
 
 
 (**
 (**
@@ -765,12 +798,12 @@ class local_safety (mode:safety_mode) =
 				| TWhile (condition, body, DoWhile) ->
 				| TWhile (condition, body, DoWhile) ->
 					let original_safe_locals = self#get_safe_locals_copy in
 					let original_safe_locals = self#get_safe_locals_copy in
 					condition_callback condition;
 					condition_callback condition;
-					let (_, not_nulls) = process_condition (mode <> SMStrict) condition is_nullable_expr (fun _ -> ()) in
+					let (_, not_nulls) = process_condition mode condition is_nullable_expr (fun _ -> ()) in
 					body_callback
 					body_callback
 						(fun () ->
 						(fun () ->
 							List.iter
 							List.iter
 								(fun not_null ->
 								(fun not_null ->
-									match get_subject (mode <> SMStrict) not_null with
+									match get_subject mode not_null with
 										| SNotSuitable -> ()
 										| SNotSuitable -> ()
 										| subj ->
 										| subj ->
 											if Hashtbl.mem original_safe_locals subj then
 											if Hashtbl.mem original_safe_locals subj then
@@ -781,7 +814,7 @@ class local_safety (mode:safety_mode) =
 						body
 						body
 				| TWhile (condition, body, NormalWhile) ->
 				| TWhile (condition, body, NormalWhile) ->
 					condition_callback condition;
 					condition_callback condition;
-					let (nulls, not_nulls) = process_condition (mode <> SMStrict) condition is_nullable_expr (fun _ -> ()) in
+					let (nulls, not_nulls) = process_condition mode condition is_nullable_expr (fun _ -> ()) in
 					(** execute `body` with known not-null variables *)
 					(** execute `body` with known not-null variables *)
 					List.iter self#get_current_scope#add_to_safety not_nulls;
 					List.iter self#get_current_scope#add_to_safety not_nulls;
 					body_callback
 					body_callback
@@ -833,7 +866,7 @@ class local_safety (mode:safety_mode) =
 				| TIf (condition, if_body, else_body) ->
 				| TIf (condition, if_body, else_body) ->
 					condition_callback condition;
 					condition_callback condition;
 					let (_, not_nulls) =
 					let (_, not_nulls) =
-						process_condition (mode <> SMStrict) condition is_nullable_expr (fun _ -> ())
+						process_condition mode condition is_nullable_expr (fun _ -> ())
 					in
 					in
 					(* Don't touch expressions, which already was safe before this `if` *)
 					(* Don't touch expressions, which already was safe before this `if` *)
 					let filter = List.filter (fun e -> not (self#is_safe e)) in
 					let filter = List.filter (fun e -> not (self#is_safe e)) in
@@ -842,7 +875,7 @@ class local_safety (mode:safety_mode) =
 						{ eexpr = TUnop (Not, Prefix, condition); etype = condition.etype; epos = condition.epos }
 						{ eexpr = TUnop (Not, Prefix, condition); etype = condition.etype; epos = condition.epos }
 					in
 					in
 					let (_, else_not_nulls) =
 					let (_, else_not_nulls) =
-						process_condition (mode <> SMStrict) not_condition is_nullable_expr (fun _ -> ())
+						process_condition mode not_condition is_nullable_expr (fun _ -> ())
 					in
 					in
 					let else_not_nulls = filter else_not_nulls in
 					let else_not_nulls = filter else_not_nulls in
 					(** execute `if_body` with known not-null variables *)
 					(** execute `if_body` with known not-null variables *)
@@ -873,7 +906,7 @@ class local_safety (mode:safety_mode) =
 		*)
 		*)
 		method process_and left_expr right_expr is_nullable_expr (callback:texpr->unit) =
 		method process_and left_expr right_expr is_nullable_expr (callback:texpr->unit) =
 			callback left_expr;
 			callback left_expr;
-			let (_, not_nulls) = process_condition (mode <> SMStrict) left_expr is_nullable_expr (fun e -> ()) in
+			let (_, not_nulls) = process_condition mode left_expr is_nullable_expr (fun e -> ()) in
 			List.iter self#get_current_scope#add_to_safety not_nulls;
 			List.iter self#get_current_scope#add_to_safety not_nulls;
 			callback right_expr;
 			callback right_expr;
 			List.iter self#get_current_scope#remove_from_safety not_nulls
 			List.iter self#get_current_scope#remove_from_safety not_nulls
@@ -881,7 +914,7 @@ class local_safety (mode:safety_mode) =
 			Handle boolean OR outside of `if` condition.
 			Handle boolean OR outside of `if` condition.
 		*)
 		*)
 		method process_or left_expr right_expr is_nullable_expr (callback:texpr->unit) =
 		method process_or left_expr right_expr is_nullable_expr (callback:texpr->unit) =
-			let (nulls, _) = process_condition (mode <> SMStrict) left_expr is_nullable_expr callback in
+			let (nulls, _) = process_condition mode left_expr is_nullable_expr callback in
 			List.iter self#get_current_scope#add_to_safety nulls;
 			List.iter self#get_current_scope#add_to_safety nulls;
 			callback right_expr;
 			callback right_expr;
 			List.iter self#get_current_scope#remove_from_safety nulls
 			List.iter self#get_current_scope#remove_from_safety nulls
@@ -889,7 +922,7 @@ class local_safety (mode:safety_mode) =
 			Remove subject from the safety list if a nullable value is assigned or if an object with safe field is reassigned.
 			Remove subject from the safety list if a nullable value is assigned or if an object with safe field is reassigned.
 		*)
 		*)
 		method handle_assignment is_nullable_expr left_expr (right_expr:texpr) =
 		method handle_assignment is_nullable_expr left_expr (right_expr:texpr) =
-			if is_suitable (mode <> SMStrict) left_expr then
+			if is_suitable mode left_expr then
 				self#get_current_scope#reassigned left_expr;
 				self#get_current_scope#reassigned left_expr;
 				if is_nullable_expr right_expr then
 				if is_nullable_expr right_expr then
 					match left_expr.eexpr with
 					match left_expr.eexpr with
@@ -911,6 +944,8 @@ class local_safety (mode:safety_mode) =
 						| _ -> ()
 						| _ -> ()
 				else if is_nullable_type left_expr.etype then
 				else if is_nullable_type left_expr.etype then
 					self#get_current_scope#add_to_safety left_expr
 					self#get_current_scope#add_to_safety left_expr
+		method call_made =
+			self#get_current_scope#call_made
 	end
 	end
 
 
 (**
 (**
@@ -1282,11 +1317,11 @@ class expr_checker mode immediate_execution report =
 			Make sure nobody tries to access a field on a nullable value
 			Make sure nobody tries to access a field on a nullable value
 		*)
 		*)
 		method private check_field target access p =
 		method private check_field target access p =
+			self#check_expr target;
 			if self#is_nullable_expr target then
 			if self#is_nullable_expr target then
 				self#error ("Cannot access \"" ^ accessed_field_name access ^ "\" of a nullable value.") [p; target.epos];
 				self#error ("Cannot access \"" ^ accessed_field_name access ^ "\" of a nullable value.") [p; target.epos];
-			self#check_expr target
 		(**
 		(**
-			Check constructor invocation: don't pass nulable values to not-nullable arguments
+			Check constructor invocation: don't pass nullable values to not-nullable arguments
 		*)
 		*)
 		method private check_new e_new =
 		method private check_new e_new =
 			match e_new.eexpr with
 			match e_new.eexpr with
@@ -1321,7 +1356,7 @@ class expr_checker mode immediate_execution report =
 				| _ ->
 				| _ ->
 					self#check_expr callee
 					self#check_expr callee
 			);
 			);
-			match follow callee.etype with
+			(match follow callee.etype with
 				| TFun (types, _) ->
 				| TFun (types, _) ->
 					if is_trace callee then
 					if is_trace callee then
 						let real_args =
 						let real_args =
@@ -1343,6 +1378,8 @@ class expr_checker mode immediate_execution report =
 						self#check_args callee args types
 						self#check_args callee args types
 				| _ ->
 				| _ ->
 					List.iter self#check_expr args
 					List.iter self#check_expr args
+			);
+			local_safety#call_made
 		(**
 		(**
 			Check if specified expressions can be passed to a call which expects `types`.
 			Check if specified expressions can be passed to a call which expects `types`.
 		*)
 		*)

+ 2 - 2
src/typing/typeload.ml

@@ -122,7 +122,7 @@ let load_type_def ctx p t =
 		with Not_found ->
 		with Not_found ->
 			(* Check the local imports *)
 			(* Check the local imports *)
 			let t,pi = List.find (fun (t2,pi) -> path_matches t2) ctx.m.module_types in
 			let t,pi = List.find (fun (t2,pi) -> path_matches t2) ctx.m.module_types in
-			ImportHandling.mark_import_position ctx.com pi;
+			ImportHandling.mark_import_position ctx pi;
 			t
 			t
 	with
 	with
 	| Not_found when no_pack ->
 	| Not_found when no_pack ->
@@ -134,7 +134,7 @@ let load_type_def ctx p t =
 				| (pack,ppack) :: l ->
 				| (pack,ppack) :: l ->
 					begin try
 					begin try
 						let mt = load_type ctx (pack,t.tname) tname p in
 						let mt = load_type ctx (pack,t.tname) tname p in
-						ImportHandling.mark_import_position ctx.com ppack;
+						ImportHandling.mark_import_position ctx ppack;
 						mt
 						mt
 					with Not_found ->
 					with Not_found ->
 						loop l
 						loop l

+ 1 - 1
src/typing/typeloadCheck.ml

@@ -436,7 +436,7 @@ module Inheritance = struct
 						List.find path_matches ctx.m.curmod.m_types
 						List.find path_matches ctx.m.curmod.m_types
 					with Not_found ->
 					with Not_found ->
 						let t,pi = List.find (fun (lt,_) -> path_matches lt) ctx.m.module_types in
 						let t,pi = List.find (fun (lt,_) -> path_matches lt) ctx.m.module_types in
-						ImportHandling.mark_import_position ctx.com pi;
+						ImportHandling.mark_import_position ctx pi;
 						t
 						t
 					in
 					in
 					{ t with tpackage = fst (t_path lt) },p
 					{ t with tpackage = fst (t_path lt) },p

+ 42 - 5
src/typing/typeloadFields.ml

@@ -159,6 +159,7 @@ let ensure_struct_init_constructor ctx c ast_fields p =
 		let params = List.map snd c.cl_params in
 		let params = List.map snd c.cl_params in
 		let ethis = mk (TConst TThis) (TInst(c,params)) p in
 		let ethis = mk (TConst TThis) (TInst(c,params)) p in
 		let args,el,tl = List.fold_left (fun (args,el,tl) cf -> match cf.cf_kind with
 		let args,el,tl = List.fold_left (fun (args,el,tl) cf -> match cf.cf_kind with
+			| Var { v_write = AccNever } -> args,el,tl
 			| Var _ ->
 			| Var _ ->
 				let has_default_expr = field_has_default_expr cf.cf_name in
 				let has_default_expr = field_has_default_expr cf.cf_name in
 				let opt = has_default_expr || (Meta.has Meta.Optional cf.cf_meta) in
 				let opt = has_default_expr || (Meta.has Meta.Optional cf.cf_meta) in
@@ -202,8 +203,6 @@ let transform_abstract_field com this_t a_t a f =
 	let p = f.cff_pos in
 	let p = f.cff_pos in
 	match f.cff_kind with
 	match f.cff_kind with
 	| FProp ((("get" | "never"),_),(("set" | "never"),_),_,_) when not stat ->
 	| FProp ((("get" | "never"),_),(("set" | "never"),_),_,_) when not stat ->
-		(* TODO: hack to avoid issues with abstract property generation on As3 *)
-		if Common.defined com Define.As3 then f.cff_access <- (AExtern,null_pos) :: f.cff_access;
 		{ f with cff_access = (AStatic,null_pos) :: f.cff_access; cff_meta = (Meta.Impl,[],null_pos) :: f.cff_meta }
 		{ f with cff_access = (AStatic,null_pos) :: f.cff_access; cff_meta = (Meta.Impl,[],null_pos) :: f.cff_meta }
 	| FProp _ when not stat ->
 	| FProp _ when not stat ->
 		error "Member property accessors must be get/set or never" p;
 		error "Member property accessors must be get/set or never" p;
@@ -325,6 +324,11 @@ type enum_abstract_mode =
 	| EAInt of int ref
 	| EAInt of int ref
 	| EAOther
 	| EAOther
 
 
+type enum_constructor_visibility =
+	| VUnknown
+	| VPublic of placed_access
+	| VPrivate of placed_access
+
 let build_enum_abstract ctx c a fields p =
 let build_enum_abstract ctx c a fields p =
 	let mode =
 	let mode =
 		if does_unify a.a_this ctx.t.tint then EAInt (ref 0)
 		if does_unify a.a_this ctx.t.tint then EAInt (ref 0)
@@ -334,7 +338,31 @@ let build_enum_abstract ctx c a fields p =
 	List.iter (fun field ->
 	List.iter (fun field ->
 		match field.cff_kind with
 		match field.cff_kind with
 		| FVar(ct,eo) when not (List.mem_assoc AStatic field.cff_access) ->
 		| FVar(ct,eo) when not (List.mem_assoc AStatic field.cff_access) ->
-			field.cff_access <- [AStatic,null_pos; if (List.mem_assoc APrivate field.cff_access) then (APrivate,null_pos) else (APublic,null_pos)];
+			let check_visibility_conflict visibility p1 =
+				match visibility with
+				| VUnknown ->
+					()
+				| VPublic(access,p2) | VPrivate(access,p2) ->
+					display_error ctx (Printf.sprintf "Conflicting access modifier %s" (Ast.s_access access)) p1;
+					display_error ctx "Conflicts with this" p2;
+			in
+			let rec loop visibility acc = match acc with
+				| (AExtern,p) :: acc ->
+					display_error ctx "extern modifier is not allowed on enum abstract fields" p;
+					loop visibility acc
+				| (APrivate,p) as access :: acc ->
+					check_visibility_conflict visibility p;
+					loop (VPrivate access) acc
+				| (APublic,p) as access :: acc ->
+					check_visibility_conflict visibility p;
+					loop (VPublic access) acc
+				| _ :: acc ->
+					loop visibility acc
+				| [] ->
+					visibility
+			in
+			let visibility = loop VUnknown field.cff_access in
+			field.cff_access <- [AStatic,null_pos; match visibility with VPublic acc | VPrivate acc -> acc | VUnknown -> (APublic,null_pos)];
 			field.cff_meta <- (Meta.Enum,[],null_pos) :: (Meta.Impl,[],null_pos) :: field.cff_meta;
 			field.cff_meta <- (Meta.Enum,[],null_pos) :: (Meta.Impl,[],null_pos) :: field.cff_meta;
 			let ct = match ct with
 			let ct = match ct with
 				| Some _ -> ct
 				| Some _ -> ct
@@ -872,6 +900,17 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p =
 					a.a_from_field <- (TLazy r,cf) :: a.a_from_field;
 					a.a_from_field <- (TLazy r,cf) :: a.a_from_field;
 				| (Meta.To,_,_) :: _ ->
 				| (Meta.To,_,_) :: _ ->
 					if fctx.is_macro then error (cf.cf_name ^ ": Macro cast functions are not supported") p;
 					if fctx.is_macro then error (cf.cf_name ^ ": Macro cast functions are not supported") p;
+					(match cf.cf_kind, cf.cf_type with
+					| Var _, _ ->
+						error "@:to meta should be used on methods" p
+					| Method _, TFun(args, _) when not fctx.is_abstract_member && List.length args <> 1 ->
+						if not (Meta.has Meta.MultiType a.a_meta) then (* TODO: get rid of this check once multitype is removed *)
+						error ("static @:to method should have one argument") p
+					| Method _, TFun(args, _) when fctx.is_abstract_member && List.length args <> 1 ->
+						if not (Meta.has Meta.MultiType a.a_meta) then (* TODO: get rid of this check once multitype is removed *)
+						error "@:to method should have no arguments" p
+					| _ -> ()
+					);
 					(* TODO: this doesn't seem quite right... *)
 					(* TODO: this doesn't seem quite right... *)
 					if not (Meta.has Meta.Impl cf.cf_meta) then cf.cf_meta <- (Meta.Impl,[],null_pos) :: cf.cf_meta;
 					if not (Meta.has Meta.Impl cf.cf_meta) then cf.cf_meta <- (Meta.Impl,[],null_pos) :: cf.cf_meta;
 					let resolve_m args =
 					let resolve_m args =
@@ -1216,8 +1255,6 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 						), p))
 						), p))
 			in
 			in
 			let t2, f2 = get_overload overloads in
 			let t2, f2 = get_overload overloads in
-			(* accessors must be public on As3 (issue #1872) *)
-			if Common.defined ctx.com Define.As3 then f2.cf_meta <- (Meta.Public,[],null_pos) :: f2.cf_meta;
 			(match f2.cf_kind with
 			(match f2.cf_kind with
 				| Method MethMacro ->
 				| Method MethMacro ->
 					display_error ctx (f2.cf_name ^ ": Macro methods cannot be used as property accessor") p;
 					display_error ctx (f2.cf_name ^ ": Macro methods cannot be used as property accessor") p;

+ 57 - 53
src/typing/typeloadModule.ml

@@ -344,6 +344,58 @@ let module_pass_1 ctx m tdecls loadp =
 	let decls = List.rev !decls in
 	let decls = List.rev !decls in
 	decls, List.rev tdecls
 	decls, List.rev tdecls
 
 
+let load_enum_field ctx e et is_flat index c =
+	let p = c.ec_pos in
+	let params = ref [] in
+	params := type_type_params ~enum_constructor:true ctx ([],fst c.ec_name) (fun() -> !params) c.ec_pos c.ec_params;
+	let params = !params in
+	let ctx = { ctx with type_params = params @ ctx.type_params } in
+	let rt = (match c.ec_type with
+		| None -> et
+		| Some (t,pt) ->
+			let t = load_complex_type ctx true (t,pt) in
+			(match follow t with
+			| TEnum (te,_) when te == e ->
+				()
+			| _ ->
+				error "Explicit enum type must be of the same enum type" pt);
+			t
+	) in
+	let t = (match c.ec_args with
+		| [] -> rt
+		| l ->
+			is_flat := false;
+			let pnames = ref PMap.empty in
+			TFun (List.map (fun (s,opt,(t,tp)) ->
+				(match t with CTPath({tpackage=[];tname="Void"}) -> error "Arguments of type Void are not allowed in enum constructors" tp | _ -> ());
+				if PMap.mem s (!pnames) then error ("Duplicate argument `" ^ s ^ "` in enum constructor " ^ fst c.ec_name) p;
+				pnames := PMap.add s () (!pnames);
+				s, opt, load_type_hint ~opt ctx p (Some (t,tp))
+			) l, rt)
+	) in
+	let f = {
+		ef_name = fst c.ec_name;
+		ef_type = t;
+		ef_pos = p;
+		ef_name_pos = snd c.ec_name;
+		ef_doc = c.ec_doc;
+		ef_index = !index;
+		ef_params = params;
+		ef_meta = c.ec_meta;
+	} in
+	let cf = {
+		(mk_field f.ef_name f.ef_type p f.ef_name_pos) with
+		cf_kind = (match follow f.ef_type with
+			| TFun _ -> Method MethNormal
+			| _ -> Var { v_read = AccNormal; v_write = AccNo }
+		);
+		cf_doc = f.ef_doc;
+		cf_params = f.ef_params;
+	} in
+	if ctx.is_display_file && DisplayPosition.display_position#enclosed_in f.ef_name_pos then
+		DisplayEmitter.display_enum_field ctx e f p;
+	f,cf
+
 (*
 (*
 	In this pass, we can access load and access other modules types, but we cannot follow them or access their structure
 	In this pass, we can access load and access other modules types, but we cannot follow them or access their structure
 	since they have not been setup. We also build a context_init list that will be evaluated the first time we evaluate
 	since they have not been setup. We also build a context_init list that will be evaluated the first time we evaluate
@@ -353,14 +405,14 @@ let init_module_type ctx context_init do_init (decl,p) =
 	let get_type name =
 	let get_type name =
 		try List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types with Not_found -> assert false
 		try List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types with Not_found -> assert false
 	in
 	in
-	let check_path_display path p = match ctx.com.display.dms_kind with
+	let check_path_display path p = match !Parser.display_mode with
 		(* We cannot use ctx.is_display_file because the import could come from an import.hx file. *)
 		(* We cannot use ctx.is_display_file because the import could come from an import.hx file. *)
 		| DMDiagnostics b when (b || DisplayPosition.display_position#is_in_file p.pfile) && Filename.basename p.pfile <> "import.hx" ->
 		| DMDiagnostics b when (b || DisplayPosition.display_position#is_in_file p.pfile) && Filename.basename p.pfile <> "import.hx" ->
-			ImportHandling.add_import_position ctx.com p path;
+			ImportHandling.add_import_position ctx p path;
 		| DMStatistics ->
 		| DMStatistics ->
-			ImportHandling.add_import_position ctx.com p path;
+			ImportHandling.add_import_position ctx p path;
 		| DMUsage _ ->
 		| DMUsage _ ->
-			ImportHandling.add_import_position ctx.com p path;
+			ImportHandling.add_import_position ctx p path;
 			if DisplayPosition.display_position#is_in_file p.pfile then DisplayPath.handle_path_display ctx path p
 			if DisplayPosition.display_position#is_in_file p.pfile then DisplayPath.handle_path_display ctx path p
 		| _ ->
 		| _ ->
 			if DisplayPosition.display_position#is_in_file p.pfile then DisplayPath.handle_path_display ctx path p
 			if DisplayPosition.display_position#is_in_file p.pfile then DisplayPath.handle_path_display ctx path p
@@ -617,56 +669,8 @@ let init_module_type ctx context_init do_init (decl,p) =
 		let is_flat = ref true in
 		let is_flat = ref true in
 		let fields = ref PMap.empty in
 		let fields = ref PMap.empty in
 		List.iter (fun c ->
 		List.iter (fun c ->
-			let p = c.ec_pos in
-			let params = ref [] in
-			params := type_type_params ~enum_constructor:true ctx ([],fst c.ec_name) (fun() -> !params) c.ec_pos c.ec_params;
-			let params = !params in
-			let ctx = { ctx with type_params = params @ ctx.type_params } in
-			let rt = (match c.ec_type with
-				| None -> et
-				| Some (t,pt) ->
-					let t = load_complex_type ctx true (t,pt) in
-					(match follow t with
-					| TEnum (te,_) when te == e ->
-						()
-					| _ ->
-						error "Explicit enum type must be of the same enum type" pt);
-					t
-			) in
-			let t = (match c.ec_args with
-				| [] -> rt
-				| l ->
-					is_flat := false;
-					let pnames = ref PMap.empty in
-					TFun (List.map (fun (s,opt,(t,tp)) ->
-						(match t with CTPath({tpackage=[];tname="Void"}) -> error "Arguments of type Void are not allowed in enum constructors" tp | _ -> ());
-						if PMap.mem s (!pnames) then error ("Duplicate argument `" ^ s ^ "` in enum constructor " ^ fst c.ec_name) p;
-						pnames := PMap.add s () (!pnames);
-						s, opt, load_type_hint ~opt ctx p (Some (t,tp))
-					) l, rt)
-			) in
 			if PMap.mem (fst c.ec_name) e.e_constrs then error ("Duplicate constructor " ^ fst c.ec_name) (pos c.ec_name);
 			if PMap.mem (fst c.ec_name) e.e_constrs then error ("Duplicate constructor " ^ fst c.ec_name) (pos c.ec_name);
-			let f = {
-				ef_name = fst c.ec_name;
-				ef_type = t;
-				ef_pos = p;
-				ef_name_pos = snd c.ec_name;
-				ef_doc = c.ec_doc;
-				ef_index = !index;
-				ef_params = params;
-				ef_meta = c.ec_meta;
-			} in
-			let cf = {
-				(mk_field f.ef_name f.ef_type p f.ef_name_pos) with
-				cf_kind = (match follow f.ef_type with
-					| TFun _ -> Method MethNormal
-					| _ -> Var { v_read = AccNormal; v_write = AccNo }
-				);
-				cf_doc = f.ef_doc;
-				cf_params = f.ef_params;
-			} in
- 			if ctx.is_display_file && DisplayPosition.display_position#enclosed_in f.ef_name_pos then
- 				DisplayEmitter.display_enum_field ctx e f p;
+			let f,cf = load_enum_field ctx e et is_flat index c in
 			e.e_constrs <- PMap.add f.ef_name f e.e_constrs;
 			e.e_constrs <- PMap.add f.ef_name f e.e_constrs;
 			fields := PMap.add cf.cf_name cf !fields;
 			fields := PMap.add cf.cf_name cf !fields;
 			incr index;
 			incr index;

+ 42 - 0
src/typing/typer.ml

@@ -1122,6 +1122,48 @@ and type_unop ctx op flag e p =
 				let e = mk_array_get_call ctx (AbstractCast.find_array_access ctx a tl ekey None p) c ebase p in
 				let e = mk_array_get_call ctx (AbstractCast.find_array_access ctx a tl ekey None p) c ebase p in
 				loop (AKExpr e)
 				loop (AKExpr e)
 			end
 			end
+		| AKUsing (emethod,cl,cf,etarget,force_inline) when (op = Decrement || op = Increment) && has_meta Meta.Impl cf.cf_meta ->
+			let l = save_locals ctx in
+			let init_tmp,etarget,eget =
+				match needs_temp_var etarget, fst e with
+				| true, EField (_, field_name) ->
+					let tmp = gen_local ctx etarget.etype p in
+					let tmp_ident = (EConst (Ident tmp.v_name), p) in
+					(
+						mk (TVar (tmp, Some etarget)) ctx.t.tvoid p,
+						mk (TLocal tmp) tmp.v_type p,
+						(EField (tmp_ident,field_name), p)
+					)
+				| _ -> (mk (TBlock []) ctx.t.tvoid p, etarget, e)
+			in
+			let op = (match op with Increment -> OpAdd | Decrement -> OpSub | _ -> assert false) in
+			let one = (EConst (Int "1"),p) in
+			(match follow cf.cf_type with
+			| TFun (_, t) ->
+				(match flag with
+				| Prefix ->
+					let get = type_binop ctx op eget one false WithType.value p in
+					unify ctx get.etype t p;
+					l();
+					let call_setter = make_call ctx emethod [etarget; get] t ~force_inline p in
+					mk (TBlock [init_tmp; call_setter]) t p
+				| Postfix ->
+					let get = type_expr ctx eget WithType.value in
+					let tmp_value = gen_local ctx t p in
+					let plusone = type_binop ctx op (EConst (Ident tmp_value.v_name),p) one false WithType.value p in
+					unify ctx get.etype t p;
+					l();
+					mk (TBlock [
+						init_tmp;
+						mk (TVar (tmp_value,Some get)) ctx.t.tvoid p;
+						make_call ctx emethod [etarget; plusone] t ~force_inline p;
+						mk (TLocal tmp_value) t p;
+					]) t p
+				)
+			| _ ->
+				l();
+				assert false
+			)
 		| AKInline _ | AKUsing _ | AKMacro _ ->
 		| AKInline _ | AKUsing _ | AKMacro _ ->
 			error "This kind of operation is not supported" p
 			error "This kind of operation is not supported" p
 		| AKFieldSet _ ->
 		| AKFieldSet _ ->

+ 3 - 1
std/Array.hx

@@ -265,7 +265,9 @@ extern class Array<T> {
 	/**
 	/**
 		Returns an iterator of the Array values.
 		Returns an iterator of the Array values.
 	**/
 	**/
-	function iterator():Iterator<T>;
+	@:runtime inline function iterator():haxe.iterators.ArrayIterator<T> {
+		return new haxe.iterators.ArrayIterator(this);
+	}
 
 
 	/**
 	/**
 		Creates a new Array by applying function `f` to all elements of `this`.
 		Creates a new Array by applying function `f` to all elements of `this`.

+ 1 - 1
std/DateTools.hx

@@ -194,7 +194,7 @@ class DateTools {
 	/**
 	/**
 		Converts a number of minutes to a timestamp.
 		Converts a number of minutes to a timestamp.
 	**/
 	**/
-	#if as3 extern #end public static inline function minutes(n:Float):Float {
+	public static inline function minutes(n:Float):Float {
 		return n * 60.0 * 1000.0;
 		return n * 60.0 * 1000.0;
 	}
 	}
 
 

+ 1 - 1
std/Math.hx

@@ -233,7 +233,7 @@ extern class Math {
 	**/
 	**/
 	static function random():Float;
 	static function random():Float;
 
 
-	#if ((flash && !as3) || cpp || eval)
+	#if (flash || cpp || eval)
 	/**
 	/**
 		Returns the largest integer value that is not greater than `v`, as a `Float`.
 		Returns the largest integer value that is not greater than `v`, as a `Float`.
 
 

+ 0 - 6
std/Reflect.hx

@@ -47,9 +47,6 @@ extern class Reflect {
 		to `Reflect.getProperty` for a function supporting property accessors.
 		to `Reflect.getProperty` for a function supporting property accessors.
 
 
 		If `field` is null, the result is unspecified.
 		If `field` is null, the result is unspecified.
-
-		(As3) If used on a property field, the getter will be invoked. It is
-		not possible to obtain the value directly.
 	**/
 	**/
 	public static function field(o:Dynamic, field:String):Dynamic;
 	public static function field(o:Dynamic, field:String):Dynamic;
 
 
@@ -60,9 +57,6 @@ extern class Reflect {
 		work for anonymous structures.
 		work for anonymous structures.
 
 
 		If `o` or `field` are null, the result is unspecified.
 		If `o` or `field` are null, the result is unspecified.
-
-		(As3) If used on a property field, the setter will be invoked. It is
-		not possible to set the value directly.
 	**/
 	**/
 	public static function setField(o:Dynamic, field:String, value:Dynamic):Void;
 	public static function setField(o:Dynamic, field:String, value:Dynamic):Void;
 
 

+ 0 - 4
std/Type.hx

@@ -189,8 +189,6 @@ extern class Type {
 		The order of the fields in the returned Array is unspecified.
 		The order of the fields in the returned Array is unspecified.
 
 
 		If `c` is null, the result is unspecified.
 		If `c` is null, the result is unspecified.
-
-		(As3) This method only returns instance fields that are public.
 	**/
 	**/
 	public static function getInstanceFields(c:Class<Dynamic>):Array<String>;
 	public static function getInstanceFields(c:Class<Dynamic>):Array<String>;
 
 
@@ -202,8 +200,6 @@ extern class Type {
 		The order of the fields in the returned Array is unspecified.
 		The order of the fields in the returned Array is unspecified.
 
 
 		If `c` is null, the result is unspecified.
 		If `c` is null, the result is unspecified.
-
-		(As3) This method only returns class fields that are public.
 	**/
 	**/
 	public static function getClassFields(c:Class<Dynamic>):Array<String>;
 	public static function getClassFields(c:Class<Dynamic>):Array<String>;
 
 

+ 4 - 2
std/cs/Boot.hx

@@ -41,8 +41,10 @@ import Reflect;
 @:dox(hide)
 @:dox(hide)
 class Boot {
 class Boot {
 	@:keep public static function init():Void {
 	@:keep public static function init():Void {
-		cs.system.Console.InputEncoding = new cs.system.text.UTF8Encoding();
-		cs.system.Console.OutputEncoding = new cs.system.text.UTF8Encoding();
+		#if std_encoding_utf8
+			cs.system.Console.InputEncoding = new cs.system.text.UTF8Encoding();
+			cs.system.Console.OutputEncoding = new cs.system.text.UTF8Encoding();
+		#end
 		cs.Lib.applyCultureChanges();
 		cs.Lib.applyCultureChanges();
 	}
 	}
 }
 }

+ 2 - 20
std/cs/_std/Array.hx

@@ -415,8 +415,8 @@ final class Array<T> implements ArrayAccess<T> {
 		return ofNative(newarr);
 		return ofNative(newarr);
 	}
 	}
 
 
-	public inline function iterator():Iterator<T> {
-		return new ArrayIterator<T>(this);
+	public inline function iterator():haxe.iterators.ArrayIterator<T> {
+		return new haxe.iterators.ArrayIterator(this);
 	}
 	}
 
 
 	public function resize(len:Int):Void {
 	public function resize(len:Int):Void {
@@ -460,21 +460,3 @@ final class Array<T> implements ArrayAccess<T> {
 		return __a[idx] = val;
 		return __a[idx] = val;
 	}
 	}
 }
 }
-
-private final class ArrayIterator<T> {
-	var arr:Array<T>;
-	var len:Int;
-	var i:Int;
-
-	public inline function new(a:Array<T>) {
-		arr = a;
-		len = a.length;
-		i = 0;
-	}
-
-	public inline function hasNext():Bool
-		return i < len;
-
-	public inline function next():T
-		return arr[i++];
-}

+ 38 - 53
std/cs/_std/Std.hx

@@ -79,65 +79,50 @@ import cs.internal.Exceptions;
 		if (x == null)
 		if (x == null)
 			return null;
 			return null;
 
 
-		var ret = 0;
 		var base = 10;
 		var base = 10;
-		var i = -1;
 		var len = x.length;
 		var len = x.length;
-
-		if (StringTools.startsWith(x, "0") && len > 2) {
-			var c:Int = cast untyped x[1];
-			if (c == 'x'.code || c == 'X'.code) {
-				i = 1;
-				base = 16;
-			}
-		}
-
-		var foundAny = i != -1;
-		var isNeg = false;
-		while (++i < len) {
-			var c = cast(untyped x[i], Int); // fastCodeAt
-			if (!foundAny) {
-				switch (c) {
-					case '-'.code:
-						isNeg = true;
-						continue;
-					case ' '.code, '\t'.code, '\n'.code, '\r'.code, '+'.code:
-						if (isNeg)
-							return null;
-						continue;
-				}
-			}
-
-			if (c >= '0'.code && c <= '9'.code) {
-				if (!foundAny && c == '0'.code) {
-					foundAny = true;
+		var foundCount = 0;
+		var sign = 0;
+		var firstDigitIndex = 0;
+		var lastDigitIndex = -1;
+		var previous = 0;
+
+		for(i in 0...len) {
+			var c = StringTools.fastCodeAt(x, i);
+			switch c {
+				case _ if((c > 8 && c < 14) || c == 32):
+					if(foundCount > 0) {
+						return null;
+					}
 					continue;
 					continue;
-				}
-				ret *= base;
-				foundAny = true;
-
-				ret += c - '0'.code;
-			} else if (base == 16) {
-				if (c >= 'a'.code && c <= 'f'.code) {
-					ret *= base;
-					foundAny = true;
-					ret += c - 'a'.code + 10;
-				} else if (c >= 'A'.code && c <= 'F'.code) {
-					ret *= base;
-					foundAny = true;
-					ret += c - 'A'.code + 10;
-				} else {
+				case '-'.code if(foundCount == 0):
+					sign = -1;
+				case '+'.code if(foundCount == 0):
+					sign = 1;
+				case '0'.code if(foundCount == 0 || (foundCount == 1 && sign != 0)):
+				case 'x'.code | 'X'.code if(previous == '0'.code && ((foundCount == 1 && sign == 0) || (foundCount == 2 && sign != 0))):
+					base = 16;
+				case _ if('0'.code <= c && c <= '9'.code):
+				case _ if(base == 16 && (('a'.code <= c && c <= 'z'.code) || ('A'.code <= c && c <= 'Z'.code))):
+				case _:
 					break;
 					break;
-				}
-			} else {
-				break;
 			}
 			}
+			if((foundCount == 0 && sign == 0) || (foundCount == 1 && sign != 0)) {
+				firstDigitIndex = i;
+			}
+			foundCount++;
+			lastDigitIndex = i;
+			previous = c;
 		}
 		}
-
-		if (foundAny)
-			return isNeg ? -ret : ret;
-		else
-			return null;
+		if(firstDigitIndex <= lastDigitIndex) {
+			var digits = x.substring(firstDigitIndex, lastDigitIndex + 1);
+			return try {
+				(sign == -1 ? -1 : 1) * cs.system.Convert.ToInt32(digits, base);
+			} catch(e:cs.system.FormatException) {
+				null;
+			}
+		}
+		return null;
 	}
 	}
 
 
 	public static function parseFloat(x:String):Float {
 	public static function parseFloat(x:String):Float {

+ 1 - 1
std/cs/_std/Type.hx

@@ -269,7 +269,7 @@ enum ValueType {
 		if (Std.is(v, HxEnum))
 		if (Std.is(v, HxEnum))
 			return ValueType.TEnum(cast t.BaseType); // enum constructors are subclasses of an enum type
 			return ValueType.TEnum(cast t.BaseType); // enum constructors are subclasses of an enum type
 		if (t.IsValueType) {
 		if (t.IsValueType) {
-			var vc:cs.system.IConvertible = cast v;
+			var vc = Std.downcast(v, cs.system.IConvertible);
 			if (vc != null) {
 			if (vc != null) {
 				switch (vc.GetTypeCode()) {
 				switch (vc.GetTypeCode()) {
 					case cs.system.TypeCode.Boolean:
 					case cs.system.TypeCode.Boolean:

+ 3 - 14
std/flash/Boot.hx

@@ -22,7 +22,6 @@
 
 
 package flash;
 package flash;
 
 
-#if !as3
 @:keep private class RealBoot extends Boot {
 @:keep private class RealBoot extends Boot {
 	#if swc
 	#if swc
 	public function new() {
 	public function new() {
@@ -42,7 +41,6 @@ package flash;
 	}
 	}
 	#end
 	#end
 }
 }
-#end
 
 
 @:dox(hide)
 @:dox(hide)
 @:keep
 @:keep
@@ -282,7 +280,7 @@ class Boot extends flash.display.MovieClip {
 						throw "Invalid date format : " + s;
 						throw "Invalid date format : " + s;
 				}
 				}
 			};
 			};
-			d.prototype[#if (as3 || no_flash_override) "toStringHX" #else "toString" #end] = function() {
+			d.prototype[#if no_flash_override "toStringHX" #else "toString" #end] = function() {
 				var date:Date = __this__;
 				var date:Date = __this__;
 				var m = date.getMonth() + 1;
 				var m = date.getMonth() + 1;
 				var d = date.getDate();
 				var d = date.getDate();
@@ -313,16 +311,7 @@ class Boot extends flash.display.MovieClip {
 				return true;
 				return true;
 			}
 			}
 			aproto.iterator = function() {
 			aproto.iterator = function() {
-				var cur = 0;
-				var arr:Array<Dynamic> = __this__;
-				return {
-					hasNext: function() {
-						return cur < arr.length;
-					},
-					next: function() {
-						return arr[cur++];
-					}
-				}
+				return new haxe.iterators.ArrayIterator(cast __this__);
 			};
 			};
 			aproto.resize = function(len) {
 			aproto.resize = function(len) {
 				__this__.length = len;
 				__this__.length = len;
@@ -332,7 +321,7 @@ class Boot extends flash.display.MovieClip {
 			aproto.setPropertyIsEnumerable("remove", false);
 			aproto.setPropertyIsEnumerable("remove", false);
 			aproto.setPropertyIsEnumerable("iterator", false);
 			aproto.setPropertyIsEnumerable("iterator", false);
 			aproto.setPropertyIsEnumerable("resize", false);
 			aproto.setPropertyIsEnumerable("resize", false);
-			#if (as3 || no_flash_override)
+			#if no_flash_override
 			aproto.filterHX = function(f) {
 			aproto.filterHX = function(f) {
 				var ret = [];
 				var ret = [];
 				var i = 0;
 				var i = 0;

+ 1 - 2
std/flash/NativeXml.hx

@@ -66,8 +66,7 @@ class Xml {
 		return wrap(root, Xml.Document);
 		return wrap(root, Xml.Document);
 	}
 	}
 
 
-	@:keep #if as3 @:hack
-	public #end static function compare(a:Xml, b:Xml):Bool {
+	@:keep static function compare(a:Xml, b:Xml):Bool {
 		return a == null ? b == null : (b == null ? false : a._node == b._node);
 		return a == null ? b == null : (b == null ? false : a._node == b._node);
 	}
 	}
 
 

+ 0 - 15
std/flash/_std/Reflect.hx

@@ -65,16 +65,6 @@
 		untyped {
 		untyped {
 			if (o == null)
 			if (o == null)
 				return new Array();
 				return new Array();
-			#if as3
-			var a:Array<String> = __keys__(o);
-			var i = 0;
-			while (i < a.length) {
-				if (!o.hasOwnProperty(a[i]))
-					a.splice(i, 1);
-				else
-					++i;
-			}
-			#else
 			var i = 0;
 			var i = 0;
 			var a = [];
 			var a = [];
 			while (untyped __has_next__(o, i)) {
 			while (untyped __has_next__(o, i)) {
@@ -82,7 +72,6 @@
 				if (o.hasOwnProperty(prop))
 				if (o.hasOwnProperty(prop))
 					a.push(prop);
 					a.push(prop);
 			}
 			}
-			#end
 			return a;
 			return a;
 		}
 		}
 
 
@@ -113,11 +102,7 @@
 		}
 		}
 
 
 	public static function isEnumValue(v:Dynamic):Bool {
 	public static function isEnumValue(v:Dynamic):Bool {
-		#if as3
-		return try Type.getEnum(v) != null catch (e:Dynamic) false;
-		#else
 		return try v.__enum__ == true catch (e:Dynamic) false;
 		return try v.__enum__ == true catch (e:Dynamic) false;
-		#end
 	}
 	}
 
 
 	public static function deleteField(o:Dynamic, field:String):Bool
 	public static function deleteField(o:Dynamic, field:String):Bool

+ 7 - 16
std/flash/_std/Type.hx

@@ -78,19 +78,14 @@ enum ValueType {
 				return "Float";
 				return "Float";
 			case "Boolean":
 			case "Boolean":
 				return "Bool";
 				return "Bool";
-			#if as3
-			case "Object":
-				return "Dynamic";
-			#end
-			default:
-		}
-		var parts = str.split("::");
-		#if as3
-		if (parts[parts.length - 1] == "_Object") {
-			parts[parts.length - 1] = "Object";
+			case _:
+				var idx = str.lastIndexOf("::");
+				if (idx == -1) {
+					return str;
+				} else {
+					return str.substring(0, idx) + "." + str.substring(idx + 2);
+				}
 		}
 		}
-		#end
-		return parts.join(".");
 	}
 	}
 
 
 	public static function getEnumName(e:Enum<Dynamic>):String {
 	public static function getEnumName(e:Enum<Dynamic>):String {
@@ -111,10 +106,6 @@ enum ValueType {
 						return Int;
 						return Int;
 					case "Float":
 					case "Float":
 						return Float;
 						return Float;
-					#if as3
-					case "Dynamic":
-						return Dynamic;
-					#end
 				}
 				}
 				return null;
 				return null;
 			}
 			}

+ 1 - 0
std/flash/_std/haxe/Http.hx

@@ -41,6 +41,7 @@ class HttpFlash extends haxe.http.HttpBase {
 	}
 	}
 
 
 	public override function request(?post:Bool) {
 	public override function request(?post:Bool) {
+		responseAsString = null;
 		responseBytes = null;
 		responseBytes = null;
 		var loader = req = new flash.net.URLLoader();
 		var loader = req = new flash.net.URLLoader();
 		loader.dataFormat = BINARY;
 		loader.dataFormat = BINARY;

+ 0 - 32
std/flash/_std/haxe/Resource.hx

@@ -22,37 +22,6 @@
 
 
 package haxe;
 package haxe;
 
 
-#if as3
-@:coreApi
-class Resource {
-	public static function listNames():Array<String>
-		untyped {
-			return __keys__(__resources__.list);
-		}
-
-	public static function getString(name:String):String {
-		var b = resolve(name);
-		return b == null ? null : b.readUTFBytes(b.length);
-	}
-
-	public static function getBytes(name:String):haxe.io.Bytes {
-		var b = resolve(name);
-		return b == null ? null : haxe.io.Bytes.ofData(b);
-	}
-
-	static function resolve(name:String):flash.utils.ByteArray
-		untyped {
-			var n = __resources__.list[name];
-			if (n == null)
-				return null;
-			return untyped __new__(n);
-		}
-
-	static function __init__():Void {
-		untyped __resources__.__init__();
-	}
-}
-#else
 @:coreApi
 @:coreApi
 class Resource {
 class Resource {
 	static var content:Array<{name:String}>;
 	static var content:Array<{name:String}>;
@@ -88,4 +57,3 @@ class Resource {
 		content = untyped __resources__();
 		content = untyped __resources__();
 	}
 	}
 }
 }
-#end

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels