瀏覽代碼

Merge branch 'development' into feature/asys

Aleksandr Kuzmenko 5 年之前
父節點
當前提交
8c0de2aaa2
共有 100 個文件被更改,包括 1817 次插入2250 次删除
  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=
 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
 
 ADD_REVISION?=0
@@ -61,6 +74,11 @@ haxe:
 	$(DUNE_COMMAND) build --workspace dune-workspace.dev src/haxe.exe
 	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:
 ifdef SYSTEMROOT
 	-@taskkill /F /IM haxe.exe 2>/dev/null
@@ -143,7 +161,7 @@ $(INSTALLER_TMP_DIR):
 	mkdir -p $(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
 

+ 3 - 7
Makefile.win

@@ -72,7 +72,7 @@ package_choco:
 	rm -rf out/choco
 
 $(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
 	$(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
 	7z x -y $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_bin.zip -o$(INSTALLER_TMP_DIR)/resources
 	mv $(INSTALLER_TMP_DIR)/resources/haxe* $(INSTALLER_TMP_DIR)/resources/haxe
-	# haxesetup.exe
-	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
 	cp extra/*.nsi $(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#
  * Java
+ * JVM
  * Lua
- * PHP
+ * PHP 7
  * Python 3
  * [HashLink](https://hashlink.haxe.org/)
  * [NekoVM](https://nekovm.org/)
  * Flash (SWF Bytecode)
- * ActionScript 3
  * 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)!
@@ -88,19 +88,14 @@ You can get help and talk with fellow Haxers from around the world via:
 
 ## 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
 

+ 18 - 5
azure-pipelines.yml

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

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

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

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

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

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

@@ -37,7 +37,7 @@ jobs:
           TEST: php
         # TODO. flash has never been enabled on our AppVeyor builds.
         # flash:
-        #   TEST: flash9,as3
+        #   TEST: flash9
         python:
           TEST: python
         # 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 "winmessages.nsh"
 !include "EnvVarUpdate.nsh"
+!include "FileAssociation.nsh"
 
 ;--------------------------------
 
@@ -20,12 +21,12 @@
 !define VERLONG "%%VERLONG%%"
 
 ; Define Neko info
-!define NEKO_VERSION "2.2.0"
+!define NEKO_VERSION "2.3.0"
 
 ; Installer details
 VIAddVersionKey "CompanyName" "Haxe Foundation"
 VIAddVersionKey "ProductName" "Haxe Installer"
-VIAddVersionKey "LegalCopyright" "Haxe Foundation 2005-2018"
+VIAddVersionKey "LegalCopyright" "Haxe Foundation 2005-2019"
 VIAddVersionKey "FileDescription" "Haxe Installer"
 VIAddVersionKey "ProductVersion" "${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\*.*"
 
-	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"
 
@@ -163,6 +166,7 @@ SectionEnd
 Section "un.Haxe" UninstMain
 
 	RMDir /r "$INSTDIR\haxe"
+	${unregisterExtension} ".hxml" "Haxe compiler arguments list"
 	${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "%HAXEPATH%"
 	DeleteRegValue ${env_hklm} HAXEPATH
 	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
 - Make sure to update the haxelib submodule
 - 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
 

+ 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
 	(name ilib)
 	(modules_without_implementation ilData ilMeta)
+	(modules (:standard \ dump))
 	(libraries extlib)
 	(wrapped false)
 )

+ 2 - 1
libs/ttflib/dune

@@ -2,6 +2,7 @@
 
 (library
 	(name ttflib)
-	(libraries extlib extlib_leftovers swflib)
+	(libraries extlib extlib_leftovers swflib unix)
+	(modules (:standard \ main))
 	(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.",
 		"platforms": ["flash"]
 	},
+	{
+		"name": "AnalyzerOptimize",
+		"define": "analyzer_optimize",
+		"doc": "Perform advanced optimizations."
+	},
 	{
 		"name": "AnnotateSource",
 		"define": "annotate_source",
 		"doc": "Add additional comments to generated source code.",
 		"platforms": ["cpp"]
 	},
-	{
-		"name": "As3",
-		"define": "as3",
-		"doc": "Defined when outputting flash9 as3 source code."
-	},
 	{
 		"name": "Asys",
 		"define": "asys",
 		"doc": "Defined for all platforms that support the libuv-based asys package."
 	},
-	{
 		"name": "CheckXmlProxy",
 		"define": "check_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.",
 		"platforms": ["eval"]
 	},
+	{
+		"name": "FilterTimes",
+		"define": "filter_times",
+		"doc": "Record per-filter execution times upon --times."
+	},
 	{
 		"name": "FastCast",
 		"define": "fast_cast",
@@ -555,6 +559,12 @@
 		"define": "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",
 		"define": "swc",

+ 7 - 1
src-json/meta.json

@@ -803,7 +803,7 @@
 		"name": "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.",
-		"params": ["Off | Loose | Strict"],
+		"params": ["Off | Loose | Strict | StrictThreaded"],
 		"targets": ["TClass", "TClassField", "TExpr"],
 		"links": ["https://haxe.org/manual/cr-null-safety.html"]
 	},
@@ -1101,6 +1101,12 @@
 		"platforms": ["java"],
 		"targets": ["TClass"]
 	},
+	{
+		"name": "TailRecursion",
+		"metadata": ":tailRecursion",
+		"doc": "Internally used for tail recursion elimination.",
+		"internal": true
+	},
 	{
 		"name": "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) }
 				);
 			} 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 fde = (match f.cf_expr with None -> assert false | Some e -> e) in
 			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 handle e tto tfrom = gen.ghandle_cast (gen.greal_type tto) (gen.greal_type tfrom) e 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 was_in_value = !in_value in
@@ -103,16 +111,19 @@ struct
 				(match field_access_esp gen (gen.greal_type tf.etype) (f) with
 					| 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 = binop_right_expr_type op actual_t in
 						let e1 = extract_expr (run e1) in
 						{ e with eexpr = TBinop(op, e1, handle (run e2) actual_t e2.etype); etype = e1.etype }
 					| _ ->
 						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.OpAssignOp _ as op),e1,e2) ->
 				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
 		in
 		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, _) ->
 				{ 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 ) ->
 				let e1 = run ~just_type:true e1 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;
 			let i = ref 0 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 mk_this_call cf params =
@@ -1177,10 +1179,15 @@ let implement_invokeField ctx slow_invoke cl =
 			in
 			(cases,
 				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;
-						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))))
 				)
 			)

+ 9 - 11
src/compiler/haxe.ml

@@ -82,7 +82,7 @@ let error ctx msg p =
 
 let reserved_flags = [
 	"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"]
@@ -104,9 +104,10 @@ let expand_env ?(h=None) path  =
 	) path
 
 let add_libs com libs =
+	let global_repo = List.exists (fun a -> a = "--haxelib-global") com.args in
 	let call_haxelib() =
 		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 lines = Std.input_list pin in
 		let err = Std.input_list perr in
@@ -307,8 +308,6 @@ let generate tctx ext interp swf_header =
 		()
 	else begin
 		let generate,name = match com.platform with
-		| Flash when Common.defined com Define.As3 ->
-			Genas3.generate,"AS3"
 		| Flash ->
 			Genswf.generate swf_header,"swf"
 		| Neko ->
@@ -502,6 +501,7 @@ let do_type tctx config_macros classes =
 	CommonCache.lock_signature com "after_init_macros";
 	List.iter (fun f -> f ()) (List.rev com.callbacks#get_after_init_macros);
 	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);
 		Finalization.finalize tctx;
 	) ();
@@ -645,7 +645,8 @@ let rec process_params create pl =
 		| "--cwd" :: dir :: l | "-C" :: dir :: l ->
 			(* we need to change it immediately since it will affect hxml loading *)
 			(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 ->
 			(match CompilationServer.get() with
 			| None ->
@@ -716,11 +717,6 @@ try
 		("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",["--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",["--php"],["-php"],Arg.String (fun dir ->
 			classes := (["php"],"Boot") :: !classes;
@@ -937,8 +933,10 @@ try
 			assert false
 		),"<[host:]port>","connect on the given port and run commands there");
 		("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");
+		("Compilation",["--haxelib-global"],[], Arg.Unit (fun () -> ()),"","pass --global argument to haxelib");
 	] in
 	let args_callback cl =
 		begin try

+ 1 - 29
src/compiler/server.ml

@@ -183,8 +183,6 @@ module ServerCompilationContext = struct
 		mutable compilation_mark : int;
 		(* A list of delays which are run after compilation *)
 		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 *)
 		mutable was_compilation : bool;
 	}
@@ -198,7 +196,6 @@ module ServerCompilationContext = struct
 		compilation_mark = 0;
 		mark_loop = 0;
 		delays = [];
-		removed_modules = [];
 		was_compilation = false;
 	}
 
@@ -210,9 +207,6 @@ module ServerCompilationContext = struct
 		sctx.delays <- [];
 		List.iter (fun f -> f()) fl
 
-	let is_removed_module sctx m =
-		List.exists (fun (_,_,m') -> m == m') sctx.removed_modules
-
 	let reset sctx =
 		Hashtbl.clear sctx.changed_directories;
 		sctx.was_compilation <- false
@@ -417,8 +411,6 @@ let add_modules sctx ctx m p =
 			| MCode, MMacro | MMacro, MCode ->
 				(* 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;
-			| _ when is_removed_module sctx m ->
-				()
 			| _ ->
 				ServerMessage.reusing com tabs m;
 				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. *)
 let create sctx write params =
 	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 =
 		if com.display.dms_full_typing then begin
 			CommonCache.cache_context sctx.cs com;
 			ServerMessage.cached_modules com "" (List.length com.modules);
-			sctx.removed_modules <- [];
-		end else
-			recache_removed_modules ()
+		end
 	in
 	let ctx = create_context params in
 	ctx.flush <- (fun() ->
@@ -517,15 +498,6 @@ let create sctx write params =
 		ServerMessage.defines ctx.com "";
 		ServerMessage.signature ctx.com "" sign;
 		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
 			if (Hashtbl.find sctx.class_paths sign) <> ctx.com.class_path then begin
 				ServerMessage.class_paths_changed ctx.com "";

+ 0 - 10
src/context/common.ml

@@ -155,7 +155,6 @@ class compiler_callbacks = object(self)
 end
 
 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 dead_blocks : (string,(pos * expr) list) Hashtbl.t;
 }
@@ -358,14 +357,6 @@ let get_config com =
 			pf_supports_threads = true;
 			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 ->
 		{
 			default_config with
@@ -446,7 +437,6 @@ let create version s_version args =
 		args = args;
 		shared = {
 			shared_display_information = {
-				import_positions = PMap.empty;
 				diagnostics_messages = [];
 				dead_blocks = Hashtbl.create 0;
 			}

+ 0 - 11
src/context/compilationServer.ml

@@ -164,17 +164,6 @@ class cache = object(self)
 			) cc#get_modules
 		) 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 *)
 
 	method find_haxelib key =

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

@@ -9,6 +9,7 @@ open DisplayTypes.DisplayMode
 type diagnostics_context = {
 	com : Common.context;
 	mutable removable_code : (string * pos * pos) list;
+	mutable import_positions : (pos,bool ref) PMap.t;
 }
 
 open DisplayTypes
@@ -104,6 +105,7 @@ let prepare com global =
 	let dctx = {
 		removable_code = [];
 		com = com;
+		import_positions = PMap.empty;
 	} in
 	List.iter (function
 		| TClassDecl c when global || DisplayPosition.display_position#is_in_file c.cl_pos.pfile ->
@@ -113,6 +115,23 @@ let prepare com global =
 		| _ ->
 			()
 	) 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
 
 let is_diagnostics_run p = match (!Parser.display_mode) with
@@ -181,9 +200,9 @@ module Printer = struct
 			) suggestions in
 			add DKUnresolvedIdentifier p DiagnosticsSeverity.Error (JArray suggestions);
 		) 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 [])
-		) com.shared.shared_display_information.import_positions;
+		) dctx.import_positions;
 		List.iter (fun (s,p,kind,sev) ->
 			add kind p sev (JString s)
 		) (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 () ->
 			let s = jsonrpc#get_string_param "contents" in
 			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
 		) None;
 		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
 	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
-		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
 	with Not_found ->
 		()
 
 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)
 		with Not_found -> false
 	in
-	let b = loop c
+	loop c
 	(* access is also allowed of we access a type parameter which is constrained to our (base) class *)
 	|| (match c.cl_kind with
 		| KTypeParameter tl ->
 			List.exists (fun t -> match follow t with TInst(c,_) -> loop c | _ -> false) tl
 		| _ -> 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 *)
 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
 					error ("Abstract chain detected: " ^ s) a.a_pos
 				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
 		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
 	try
 		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
 	| Eval
 
-let version = 4000
+let version = 4100
 let version_major = version / 1000
 let version_minor = (version mod 1000) / 100
 let version_revision = (version mod 100)
-let version_pre = Some "rc.5"
+let version_pre = Some "rc.1"
 
 let macro_platform = ref Neko
 
@@ -71,6 +71,8 @@ let platform_list_help = function
 
 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 starts_with s c =

+ 14 - 11
src/core/numeric.ml

@@ -56,19 +56,22 @@ let parse_float s =
 	float_of_string (loop 0 0)
 
 let parse_int s =
-	let rec loop_hex i =
-		if i = String.length s then s else
-		match String.unsafe_get s i with
-		| '0'..'9' | 'a'..'f' | 'A'..'F' -> loop_hex (i + 1)
-		| _ -> String.sub s 0 i
+	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
-	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
 		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)
 	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_inline_calls = [];
 			m_type_hints = [];
+			m_import_positions = PMap.empty;
 		};
 		m_dirty = None;
 		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_extra",s_opt s_tvar_extra v.v_extra;
 			"v_meta",s_metadata v.v_meta;
+			"v_pos",s_pos v.v_pos;
 		]
 
 	let s_module_kind = function

+ 1 - 0
src/core/tType.ml

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

+ 11 - 3
src/dune

@@ -6,18 +6,26 @@
 	)
 )
 
-(executable
+(library
 	(name haxe)
-	(public_name haxe)
-	(package haxe)
 	(libraries
 		extc extproc extlib_leftovers ilib javalib neko objsize pcre swflib ttflib ziplib
 		json
 		unix str threads dynlink
 		xml-light extlib ptmap sha
 	)
+	(modules (:standard \ haxe))
 	(preprocess (per_module
 		((pps sedlex.ppx) json lexer)
 	))
+	(wrapped false)
+)
+
+(executable
+	(name haxe)
+	(public_name haxe)
+	(package haxe)
+	(libraries haxe)
+	(modules haxe)
 	(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 *)
 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 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 *)
@@ -553,28 +552,7 @@ let add_field_inits reserved ctx t =
 		let need_this = ref false in
 		let inits,fields = List.fold_left (fun (inits,fields) cf ->
 			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)
 		) ([],[]) c.cl_ordered_fields in
 		c.cl_ordered_fields <- (List.rev fields);
@@ -587,12 +565,7 @@ let add_field_inits reserved ctx t =
 				| 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
 					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
 			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
@@ -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
 			cf.cf_expr <- Some e;
 			let can_deal_with_interface_metadata () = match ctx.com.platform with
-				| Flash when Common.defined ctx.com Define.As3 -> false
 				| Cs | Java -> false
 				| _ -> true
 			in
@@ -699,7 +671,7 @@ let check_cs_events com t = match t with
 
 					(* 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
-						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
 				process_event_method ("add_" ^ f.cf_name);
 				process_event_method ("remove_" ^ f.cf_name)
@@ -809,7 +781,7 @@ module ForRemap = struct
 end
 
 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 cached = is_cached t in
 		begin match t with
@@ -837,7 +809,7 @@ let run com tctx main =
 	NullSafety.run com new_types;
 	(* PASS 1: general expression filters *)
 	let filters = [
-		(* ForRemap.apply tctx; *)
+		ForRemap.apply tctx;
 		VarLazifier.apply com;
 		AbstractCast.handle_abstract_casts tctx;
 	] in
@@ -848,8 +820,9 @@ let run com tctx main =
 		fix_return_dynamic_from_void_function tctx true;
 		check_local_vars_init;
 		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;
+		if Common.defined com Define.OldConstructorInline then Optimizer.inline_constructors tctx else InlineConstructors.inline_constructors tctx;
 		CapturedVars.captured_vars com;
 	] in
 	let filters =
@@ -929,11 +902,7 @@ let run com tctx main =
 	com.stage <- CDceStart;
 	let t = filter_timer detail_times ["dce"] in
 	(* 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
 		| "full" -> if Common.defined com Define.Interp then Dce.DceNo else DceFull
 		| "std" -> DceStd

+ 10 - 0
src/filters/filtersCommon.ml

@@ -38,6 +38,16 @@ let rec is_removable_class c =
 	| _ ->
 		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 e =
 		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)
 			| _ -> false
 		in
-		has_feature ctx "HxOverrides.iter" && loop x.etype
+		has_feature ctx "haxe.iterators.ArrayIterator.*" && loop x.etype
 	in
 	match e.eexpr with
 	| TField (x,f) when field_name f = "iterator" -> check x
@@ -962,11 +962,8 @@ and gen_syntax ctx meth args pos =
 		in
 		begin
 			match args with
-			| [] ->
-				if code = "this" then
-					spr ctx (this ctx)
-				else
-					spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n"))
+			| [] when code = "this" ->
+				spr ctx (this ctx)
 			| _ ->
 				Codegen.interpolate_code ctx.com code args (spr ctx) (gen_value ctx) code_pos
 		end
@@ -1750,11 +1747,13 @@ let generate com =
 	List.iter (fun (_,_,e) -> chk_features e) ctx.statics;
 	if has_feature ctx "use.$iterator" then begin
 		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;
 	end;
 	if has_feature ctx "use.$getIterator" then begin
-		print ctx "function $getIterator(o) { if( o instanceof Array ) return HxOverrides.iter(o); else return o.iterator(); }";
+		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;
 	end;
 	if has_feature ctx "use.$bind" then begin
@@ -1776,7 +1775,7 @@ let generate com =
 	end;
 	if has_feature ctx "$global.$haxeUID" then begin
 		add_feature ctx "js.Lib.global";
-		print ctx "if(typeof $global.$haxeUID == \"undefined\") $global.$haxeUID = 0;\n";
+		print ctx "$global.$haxeUID |= 0;\n";
 	end;
 	List.iter (gen_block_element ~after:true ctx) (List.rev ctx.inits);
 	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 h = ref Int32.zero in
-	let l = String.length s in
+	let l = UTF8.length s 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;
 	!h
 
@@ -201,6 +203,7 @@ let rec jsignature_of_type stack t =
 			| ["java"],"Char16" -> TChar
 			| [],"Single" -> TFloat
 			| [],"Float" -> TDouble
+			| [],"Void" -> void_sig
 			| [],"Null" ->
 				begin match tl with
 				| [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 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
 		| 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
 	| 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 =
 	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 (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");
     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 *)
     println ctx "_hx_array_mt.__index = Array.prototype";
     newline ctx;

+ 89 - 25
src/generators/genphp7.ml

@@ -911,20 +911,18 @@ class class_wrapper (cls) =
 				match cls.cl_init with
 					| Some _ -> true
 					| None ->
-						let needs = ref false in
-						PMap.iter
-							(fun _ field ->
+						List.exists
+							(fun field ->
 								(* 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
 			@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
 		*)
 		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.
 			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
 		*)
-		method private write_method name func =
+		method private write_method name func is_static =
 			match name with
 				| "__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
 		*)
@@ -3097,15 +3101,42 @@ class virtual type_builder ctx (wrapper:type_wrapper) =
 			writer#indent_less;
 			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
 			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 ") ";
 			if not (self#write_body_if_special_method name) then
 				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.
 			Returns `true` if `field` is such a method.
@@ -3318,6 +3349,31 @@ class class_builder ctx (cls:tclass) =
 					ctx.pgc_common.types;
 				not !hacked
 			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`
 		*)
@@ -3531,13 +3587,13 @@ class class_builder ctx (cls:tclass) =
 				);
 				writer#write ";\n"
 			in
-			PMap.iter
-				(fun _ field ->
+			List.iter
+				(fun field ->
 					match field.cf_kind with
 						| Method MethDynamic -> write_dynamic_method_initialization field
 						| _ -> ()
 				)
-				cls.cl_statics;
+				cls.cl_ordered_statics;
 			(* `static var` initialization *)
 			let write_var_initialization field =
 				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.
 					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
 						| None -> ()
 						(* There can be not-inlined blocks when compiling with `-debug` *)
@@ -3569,6 +3625,11 @@ class class_builder ctx (cls:tclass) =
 					);
 					writer#write ";\n"
 				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
 			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
 			writer#write (visibility ^ " $" ^ (field_name field));
 			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 ->
 					match expr.eexpr with
 						| TConst _ ->
@@ -3631,17 +3695,17 @@ class class_builder ctx (cls:tclass) =
 			self#write_doc (DocMethod (args, return_type, field.cf_doc));
 			writer#write_indentation;
 			if self#is_final_field field then writer#write "final ";
-			if is_static then writer#write "static ";
 			writer#write ((get_visibility field.cf_meta) ^ " ");
 			match field.cf_expr with
 				| None ->
+					if is_static then writer#write "static ";
 					writer#write ("function " ^ (field_name field) ^ " (");
 					write_args writer#write (writer#write_arg true) args;
 					writer#write ")";
 					writer#write " ;\n"
 				| Some { eexpr = TFunction fn } ->
 					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"
 				| _ -> 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])}
 
-	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_blocks = blocks;
@@ -172,7 +166,7 @@ module Transformer = struct
 		}
 
 	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
 
@@ -331,7 +325,7 @@ module Transformer = struct
 				let eb = mk (TBlock (List.rev assigns)) t_dynamic p in
 				Type.concat eb tf.tf_expr
 		in
-		let e1 = to_expr (transform_expr ~next_id:(Some ae.a_next_id) body) in
+		let e1 = to_expr (transform_expr ae.a_next_id body) in
 		let fn = mk (TFunction({
 			tf_expr = e1;
 			tf_args = tf.tf_args;
@@ -345,7 +339,7 @@ module Transformer = struct
 			let def = mk (TVar(new_var,Some fn)) fn.etype p in
 			lift_expr1 false ae.a_next_id [def] new_local
 		end else
-			lift_expr fn
+			lift_expr ae.a_next_id fn
 
 	and transform_var_expr ae eo v =
 		KeywordHandler.check_var_declaration v;
@@ -358,18 +352,18 @@ module Transformer = struct
 				b,Some(f.a_expr)
 		in
 		let e = mk (TVar(v,new_expr)) ae.a_expr.etype ae.a_expr.epos in
-		lift_expr ~next_id:(Some ae.a_next_id) ~blocks:b e
+		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 =
-		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 =
 		match el with
 			| [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 res = DynArray.create () in
@@ -382,13 +376,13 @@ module Transformer = struct
 						| _ -> false
 					in
 					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;
 						DynArray.add res ae.a_expr
 					else
 						()
 				) 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 =
 		let case_functions = ref [] in
@@ -485,7 +479,7 @@ module Transformer = struct
 			forward_transform e ae
 
 	and transform_op_assign_op ae e1 op one is_value post =
-		let e1_ = transform_expr e1 ~is_value:true ~next_id:(Some ae.a_next_id) in
+		let e1_ = transform_expr ae.a_next_id e1 ~is_value:true in
 		let handle_as_local temp_local =
 			let ex = ae.a_expr 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
 			if is_value then begin
 				let f = exprs_to_func block (ae.a_next_id()) ae in
-				lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks
+				lift_expr ae.a_next_id f.a_expr ~is_value:true ~blocks:f.a_blocks
 			end else begin
 				let block = e1_.a_blocks @ [assign_expr] in
 				transform_exprs_to_block block ex.etype false ex.epos ae.a_next_id
@@ -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
 				if is_value then begin
 					let f = exprs_to_func block (ae.a_next_id()) ae in
-					lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks
+					lift_expr ae.a_next_id f.a_expr ~is_value:true ~blocks:f.a_blocks
 				end else
 					transform_exprs_to_block block ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
 			| TField(e1,fa) ->
@@ -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
 				if is_value then begin
 					let f = exprs_to_func block (ae.a_next_id()) ae in
-					lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks
+					lift_expr ae.a_next_id f.a_expr ~is_value:true ~blocks:f.a_blocks
 				end else
 					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 call_expr = (mk (TLocal fvar) fexpr.etype ex.epos ) in
 			let substitute = mk (TCall(call_expr, [])) ex.etype ex.epos in
-			lift_expr ~blocks:[assign] substitute)
+			lift_expr base.a_next_id ~blocks:[assign] substitute)
 		in
 		match exprs with
 		| [{ eexpr = TFunction({ tf_args = []} as f) } as x] ->
 			let l = to_tlocal_expr name f.tf_type f.tf_expr.epos in
 			let substitute = mk (TCall(l, [])) f.tf_type f.tf_expr.epos in
-			lift_expr ~blocks:[x] substitute
+			lift_expr base.a_next_id ~blocks:[x] substitute
 		| _ -> def
 
 	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 params = List.map (fun (p) -> p.a_expr) params in
 			let e = { ae.a_expr with eexpr = TCall(e.a_expr, params) } in
-			lift_expr ~blocks:blocks e
+			lift_expr ae.a_next_id ~blocks:blocks e
 		in
 		match e, params with
 		(* the foreach block should not be handled as a value *)
@@ -648,9 +642,9 @@ module Transformer = struct
 		| (is_value,TBlock [x]) ->
 			trans is_value [] x
 		| (false,TBlock []) ->
-			lift_expr a_expr
+			lift_expr ae.a_next_id a_expr
 		| (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) ->
 			transform_exprs_to_block el ae.a_expr.etype false ae.a_expr.epos ae.a_next_id
 		| (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 ev = mk (TLocal t_var) ae.a_expr.etype ae.a_expr.epos in
 			let substitute = mk (TCall(ev,[])) ae.a_expr.etype ae.a_expr.epos in
-			lift_expr ~blocks:[fn_assign] substitute
+			lift_expr ae.a_next_id ~blocks:[fn_assign] substitute
 		| (is_value,TFunction(f)) ->
 			transform_function f ae is_value
 		| (_,TVar(v,None)) ->
@@ -714,7 +708,7 @@ module Transformer = struct
 
 			let blocks = a1.a_blocks @ [var_decl] in
 
-			lift_expr ~blocks: blocks twhile
+			lift_expr ae.a_next_id ~blocks: blocks twhile
 		| (_,TReturn None) ->
 			ae
 		| (_,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 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 ->
 				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)) ->
 			let econd = trans true [] econd in
 			let eif = to_expr (trans false [] eif) in
@@ -842,20 +836,20 @@ module Transformer = struct
 		(* anon field access on optional params *)
 		| (is_value, TField(e,FAnon cf)) when Meta.has Meta.Optional cf.cf_meta ->
 			let e = dynamic_field_read e cf.cf_name 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 ->
 			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 ->
 			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  ->
 			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})) ->
 			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
 		*)
@@ -872,17 +866,17 @@ module Transformer = struct
 		| (_, TUnop(op, Prefix, e)) ->
 			let e1 = trans true [] e in
 			let r = { a_expr with eexpr = TUnop(op, Prefix, e1.a_expr) } in
-			lift_expr ~blocks:e1.a_blocks r
+			lift_expr ae.a_next_id ~blocks:e1.a_blocks r
 
 		| (is_value, TField(e,FDynamic s)) ->
 			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)) ->
 			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)) ->
 			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))->
 			(let left = trans true [] left in
 			let right = trans true [] right in
@@ -925,7 +919,7 @@ module Transformer = struct
 			let e2 = trans true [] e2 in
 			let r = { a_expr with eexpr = TArray(e1.a_expr, e2.a_expr)} in
 			let blocks = List.append e1.a_blocks e2.a_blocks in
-			lift_expr ~blocks:blocks r
+			lift_expr ae.a_next_id ~blocks:blocks r
 		| (false, TTry(etry, catches)) ->
 			let etry = trans false [] etry 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 fields = List.map (fun (name,ex) -> name, ex.a_expr) fields in
 			let r = { a_expr with eexpr = (TObjectDecl(fields) )} in
-			lift_expr ~blocks r
+			lift_expr ae.a_next_id ~blocks r
 		| (_, TArrayDecl(values)) ->
 			let values = List.map (trans true []) values in
 			let blocks = List.flatten (List.map (fun (v) -> v.a_blocks) values) in
 			let exprs = List.map (fun (v) -> v.a_expr) values in
 			let r = { a_expr with eexpr = TArrayDecl exprs } in
-			lift_expr ~blocks:blocks r
+			lift_expr ae.a_next_id ~blocks:blocks r
 		| (is_value, TCast(e1,Some mt)) ->
 			let e = Codegen.default_cast ~vtmp:(ae.a_next_id()) (match !como with Some com -> com | None -> assert false) e1 mt ae.a_expr.etype ae.a_expr.epos in
-			transform_expr ~is_value:is_value e
+			transform_expr ae.a_next_id ~is_value:is_value e
 		| (is_value, TCast(e,None)) ->
 			let e = trans is_value [] e in
 			let r = { a_expr with eexpr = TCast(e.a_expr, None)} in
-			lift_expr ~blocks:e.a_blocks r
+			lift_expr ae.a_next_id ~blocks:e.a_blocks r
 		| (_, TField(e,f)) ->
 			let e = trans true [] e in
 			let r = { a_expr with eexpr = TField(e.a_expr, f) } in
-			lift_expr ~blocks:e.a_blocks r
+			lift_expr ae.a_next_id ~blocks:e.a_blocks r
 		| (is_value, TMeta(m, e)) ->
 			let e = trans is_value [] e in
 			let r = { a_expr with eexpr = TMeta(m, e.a_expr); etype = e.a_expr.etype } in
-			lift_expr ~blocks:e.a_blocks r
-		| ( _, TLocal _ ) -> lift_expr a_expr
+			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
 		| ( true, TWhile(econd, ebody, DoWhile) ) ->
 			let new_expr = trans false [] a_expr in
 			let f = exprs_to_func (new_expr.a_blocks @ [new_expr.a_expr]) (ae.a_next_id()) ae in
-			lift_expr ~is_value:true ~blocks:f.a_blocks f.a_expr
+			lift_expr ae.a_next_id ~is_value:true ~blocks:f.a_blocks f.a_expr
 
 		| ( _, TBreak ) | ( _, TContinue ) | ( _, TIdent _) ->
-			lift_expr a_expr
+			lift_expr ae.a_next_id a_expr
 
 	and transform e =
-		to_expr (transform1 (lift_expr e))
+		to_expr (transform1 (lift_expr (new_counter()) e))
 
 	and forward_transform e base =
 		transform1 (lift_expr1 base.a_is_value base.a_next_id base.a_blocks e)
 
 	let transform_to_value e =
-		to_expr (transform1 (lift_expr e ~is_value:true))
+		to_expr (transform1 (lift_expr (new_counter()) e ~is_value:true))
 
 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)" (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) ->
-				(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 *)
 					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
 			spr ctx "from functools import partial as _hx_partial\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_resources 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_sig = TObject(haxe_empty_constructor_path,[])
 
+	let void_path = ["java";"lang"],"Void"
+	let void_sig = TObject(void_path,[])
+
 	(* numeric *)
 
 	let number_path = ["java";"lang"],"Number"

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

@@ -59,6 +59,10 @@ type env_info = {
 	kind : env_kind;
 	(* The name of capture variables. Maps local slots to variable names. Only filled in debug mode. *)
 	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. *)
@@ -405,17 +409,19 @@ let no_debug = {
 	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 = {
 		static = static;
 		kind = kind;
 		pfile = hash pfile;
 		pfile_unique = hash (Path.unique_full_path pfile);
 		capture_infos = capture_infos;
+		num_locals = num_locals;
+		num_captures = num_captures;
 	} in
 	info
 
-let push_environment ctx info num_locals num_captures =
+let push_environment ctx info =
 	let eval = get_eval ctx in
 	let timer = if ctx.detail_times then
 		Timer.timer ["macro";"execution";kind_name eval info.kind]
@@ -427,15 +433,15 @@ let push_environment ctx info num_locals num_captures =
 	else
 		no_debug
 	in
-	let locals = if num_locals = 0 then
+	let locals = if info.num_locals = 0 then
 		empty_array
 	else
-		Array.make num_locals vnull
+		Array.make info.num_locals vnull
 	in
-	let captures = if num_captures = 0 then
+	let captures = if info.num_captures = 0 then
 		empty_array
 	else
-		Array.make num_captures vnull
+		Array.make info.num_captures vnull
 	in
 	let stack_depth = match eval.env with
 		| None -> 1;

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

@@ -333,28 +333,34 @@ module ValueCompletion = struct
 		loop IntMap.empty 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 =
 		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
 			JObject fields
 		) l)
 
 	let collect_idents ctx env =
 		let acc = Hashtbl.create 0 in
-		let add key =
+		let add key kind =
 			if not (Hashtbl.mem acc key) then
-				Hashtbl.add acc key (key,"value",None)
+				Hashtbl.add acc key (key,kind,None)
 		in
 		(* 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 *)
 		let rec loop scopes = match scopes with
 			| 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
 			| [] ->
 				()
@@ -362,7 +368,7 @@ module ValueCompletion = struct
 		loop env.env_debug.scopes;
 		(* 2. Captures *)
 		Hashtbl.iter (fun slot vi ->
-			add (hash vi.vi_name)
+			add (hash vi.vi_name) "variable"
 		) env.env_info.capture_infos;
 		(* 3. Instance *)
 		if not env.env_info.static then begin
@@ -370,7 +376,7 @@ module ValueCompletion = struct
 			begin match v with
 			| VInstance vi ->
 				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
@@ -380,7 +386,7 @@ module ValueCompletion = struct
 			| EKMethod(i1,_) ->
 				let proto = get_static_prototype_raise ctx i1 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
 		end;
@@ -388,7 +394,18 @@ module ValueCompletion = struct
 		begin match ctx.toplevel with
 		| VObject o ->
 			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;
@@ -487,8 +504,13 @@ module ValueCompletion = struct
 		with _ ->
 			save();
 			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
 
 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 *)
 
-type env_creation = {
-	ec_info : env_info;
-	ec_num_locals : int;
-	ec_num_captures : int;
-}
-
 let execute_set_local i env v =
 	env.env_locals.(i) <- v
 
@@ -743,21 +737,21 @@ let process_arguments fl vl env =
 [@@inline]
 
 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;
 	let v = exec env in
 	pop_environment ctx env;
 	v
 
 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;
 	let v = try exec env with Return v -> v in
 	pop_environment ctx env;
 	v
 
 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;
 	process_arguments fl vl env;
 	let v = exec env in
@@ -765,7 +759,7 @@ let create_closure_noret ctx eci refs exec fl vl =
 	v
 
 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;
 	process_arguments fl vl env;
 	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 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
 		| false,0 -> create_function_noret
 		| _ -> create_closure refs

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

@@ -684,11 +684,8 @@ and jit_tfunction jit static pos tf =
 	pop_scope jit;
 	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. *)
 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 vfield = field vtype (hash f) 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_pmax <- p.pmax;
 			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 EvalString
 
-let rempty = create_ascii ""
 let rbropen = create_ascii "{"
 let rbrclose = 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)
 
 and s_array depth va =
-	join rempty [
+	join empty_string [
 		rbkopen;
 		EvalArray.join va (s_value depth) rcomma;
 		rbkclose;
 	]
 
 and s_vector depth vv =
-	join rempty [
+	join empty_string [
 		rbkopen;
 		EvalArray.join (EvalArray.create vv) (s_value depth) rcomma;
 		rbkclose;
@@ -90,7 +89,7 @@ and s_enum_value depth ve =
 	match ve.eargs with
 	| [||] -> create_ascii name
 	| vl ->
-		join rempty [
+		join empty_string [
 			create_ascii name;
 			rpopen;
 			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
-	| 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
 
 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 () ->
 		let jit,f = jit_expr ctx e 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
 	) e.Type.epos
 

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

@@ -952,7 +952,7 @@ module StdEReg = struct
 	let split = vifun1 (fun vthis s ->
 		let this = this vthis 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
 			let max = if this.r_global then -1 else 2 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 this = this vthis in
 		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 rempty [rbropen;s;rbrclose] in
+		let s = join empty_string [rbropen;s;rbrclose] in
 		vstring s
 	)
 
@@ -1599,9 +1599,9 @@ module StdStringMap = struct
 	let toString = vifun0 (fun vthis ->
 		let this = this vthis in
 		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 rempty [rbropen;s;rbrclose] in
+		let s = join empty_string [rbropen;s;rbrclose] in
 		vstring s
 	)
 
@@ -1657,9 +1657,9 @@ module StdObjectMap = struct
 	let toString = vifun0 (fun vthis ->
 		let this = this vthis in
 		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 rempty [rbropen;s;rbrclose] in
+		let s = join empty_string [rbropen;s;rbrclose] in
 		vstring s
 	)
 
@@ -2190,7 +2190,7 @@ module StdString = struct
 	let charAt = vifun1 (fun vthis index ->
 		let this = this vthis 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))
 	)
 
@@ -2288,7 +2288,7 @@ module StdString = struct
 		let cl_this = this.slength in
 		let c_pos = decode_int pos in
 		if c_pos >= cl_this then
-			encode_string ""
+			v_empty_string
 		else begin
 			let c_pos = if c_pos < 0 then begin
 				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_last = if c_last > cl_this then cl_this else c_last in
 		if c_first > cl_this || c_first = c_last then
-			encode_string ""
+			v_empty_string
 		else begin
 			begin
 				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_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_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_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))));

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

@@ -34,6 +34,10 @@ let create_with_length s length = {
 	soffsets = [];
 }
 
+let empty_string = create_ascii ""
+
+let v_empty_string = VString empty_string
+
 let create_unknown 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
 
 	let pop this blocking =
-		let rec loop () =
+		if not blocking then begin
 			Mutex.lock this.dmutex;
 			match this.dvalues with
 			| v :: vl ->
@@ -24,16 +24,41 @@ module Deque = struct
 				Mutex.unlock this.dmutex;
 				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();
-					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 =
 		Mutex.lock this.dmutex;

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

@@ -60,18 +60,18 @@ module StringHashtbl = struct
 end
 
 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
 
 type vregex = {

+ 3 - 3
src/optimization/analyzer.ml

@@ -365,11 +365,11 @@ module ConstPropagation = DataFlow(struct
 	let top = Top
 	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
 		| Const ct1,Const ct2 -> ct1 = ct2
 		| 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
 		| _ -> false
 
@@ -517,7 +517,7 @@ end)
 (*
 	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
 	open BasicBlock

+ 1 - 1
src/optimization/analyzerConfig.ml

@@ -64,7 +64,7 @@ let is_ignored meta =
 
 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");
 		copy_propagation = not (Common.raw_defined com "analyzer-no-copy-propagation");
 		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
 		bb,e
 	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 *)
 		let rec loop bb e = match e.eexpr with
 			| TParenthesis e1 ->
@@ -264,7 +265,6 @@ let rec func ctx bb tf t p =
 				bb,e
 		in
 		let generate bb e =
-			no_void v.v_type p;
 			let ev = mk (TLocal v) v.v_type p in
 			let was_assigned = ref false in
 			let assign e =
@@ -475,7 +475,7 @@ let rec func ctx bb tf t p =
 			let bb_next = if bb_breaks = [] then begin
 				(* 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. *)
-				add_cfg_edge bb_loop_body_next bb_exit CFGMaybeThrow;
+				add_cfg_edge bb_loop_body bb_exit CFGMaybeThrow;
 				g.g_unreachable
 			end else
 				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));
 			close_node g bb_loop_pre;
 			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;
 			close_node g bb_loop_body_next;
 			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
 	|| 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.
 	`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 =
 	let add cf =
 		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.marked_fields <- cf :: dce.marked_fields;
 			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 *)
 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));
 	update_marked_class_fields dce c;
 end
 
 let rec mark_enum dce e = if not (Meta.has Meta.Used e.e_meta) then begin
-	e.e_meta <- (Meta.Used,[],e.e_pos) :: e.e_meta;
+	e.e_meta <- (mk_used_meta e.e_pos) :: e.e_meta;
 	check_and_add_feature dce "has_enum";
 	check_feature dce (Printf.sprintf "%s.*" (s_type_path e.e_path));
 	PMap.iter (fun _ ef -> mark_t dce ef.ef_pos ef.ef_type) e.e_constrs;
@@ -209,7 +215,7 @@ end
 
 and mark_abstract dce a = if not (Meta.has Meta.Used a.a_meta) then begin
 	check_feature dce (Printf.sprintf "%s.*" (s_type_path a.a_path));
-	a.a_meta <- (Meta.Used,[],a.a_pos) :: a.a_meta
+	a.a_meta <- (mk_used_meta a.a_pos) :: a.a_meta
 end
 
 (* mark a type as kept *)
@@ -219,7 +225,7 @@ and mark_t dce p t =
 		begin match follow t with
 		| TInst({cl_kind = KTypeParameter tl} as c,pl) ->
 			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;
 			end;
 			List.iter (mark_t dce p) pl
@@ -779,7 +785,7 @@ let sweep dce com =
 				end;
 			in
 			(* 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 ->
 				let b = keep_field dce cf c true in
 				if not b then begin
@@ -843,7 +849,7 @@ let run com main mode =
 	} in
 	begin match main with
 		| 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;

+ 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
 		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 *)
 		| TTypeExpr (TClassDecl ({ cl_path = [],"String" })) -> Some (typeof "string")
 		| 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" })) ->
 			(* generate (o instanceof Array) && o.__enum__ == null check *)
 			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) ->
 			if cls.cl_interface then
 				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 _ }) ->
 				(try
 					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
 				with Not_found ->
 					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
 			| [< '(DblDot,_); s >] ->
 				(match s with parser
+				| [< '(POpen,p1); t = parse_complex_type; '(PClose,p2) >] -> Some t
 				| [< t = parse_complex_type >] -> Some t
 				| [< >] -> serror())
 			| [< >] -> None

+ 1 - 1
src/syntax/parserEntry.ml

@@ -32,7 +32,7 @@ type small_type =
 	| TVersion of (version * version * version) * (version list option)
 
 let is_true = function
-	| TBool false | TNull | TFloat 0. | TString "" -> false
+	| TBool false | TNull | TFloat 0. -> false
 	| _ -> true
 
 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
 			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 gen_to_string e =
 		(* 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
 		gen_to_string e
 	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
 		if needs_temp_var e then
 			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
 				)
 			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 | _ -> ());
 				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 "Add @:isVar here to enable it" f.cf_pos;
 				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
 				if mode = MSet then begin
 					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
 	with Not_found -> try
 		(* 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
 	with Not_found | Exit -> try
 		(* global using *)

+ 33 - 4
src/typing/forLoop.ml

@@ -9,13 +9,42 @@ open Error
 open Texpr.Builder
 
 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
 	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 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
 		| TBlock el -> { e2 with eexpr = TBlock (enext :: el) }
 		| _ -> mk (TBlock [enext;e2]) ctx.t.tvoid p

+ 96 - 59
src/typing/nullSafety.ml

@@ -34,6 +34,7 @@ type safety_mode =
 	| SMOff
 	| SMLoose
 	| SMStrict
+	| SMStrictThreaded
 
 (**
 	Terminates compiler process and prints user-friendly instructions about filing an issue in compiler repo.
@@ -136,18 +137,18 @@ type safety_subject =
 	*)
 	| SNotSuitable
 
-let rec get_subject loose_safety expr =
+let rec get_subject mode expr =
 	match (reveal_expr expr).eexpr with
 		| TLocal v ->
 			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])
-		| 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]
-		| 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])
-		| 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)
 				| SFieldOfThis fields -> SFieldOfThis (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
 
-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
 		| TField ({ eexpr = TConst TThis }, FInstance _)
 		| TField ({ eexpr = TLocal _ }, (FInstance _ | FAnon _))
 		| TField ({ eexpr = TTypeExpr _ }, FStatic _)
 		| 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
 
 class unificator =
@@ -341,7 +346,7 @@ let rec can_pass_type src dst =
 	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`.
 *)
-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 []
 	and not_nulls = ref [] in
 	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 =
 		match e.eexpr with
 			| 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
-			| 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
-			| 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
-			| 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
-			| 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
-			| 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
 			| TBinop (OpBoolAnd, left_expr, right_expr) when positive ->
 				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 ->
 				List.iter
 					(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
 					)
 					[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 ->
 				List.iter
 					(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
 					)
 					[left_expr; right_expr]
@@ -406,7 +411,7 @@ let rec contains_safe_meta metadata =
 	match metadata with
 		| [] -> false
 		| (Meta.NullSafety, [], _) :: _
-		| (Meta.NullSafety, [(EConst (Ident ("Loose" | "Strict")), _)], _) :: _  -> true
+		| (Meta.NullSafety, [(EConst (Ident ("Loose" | "Strict" | "StrictThreaded")), _)], _) :: _  -> true
 		| _ :: rest -> contains_safe_meta rest
 
 let safety_enabled meta =
@@ -423,6 +428,8 @@ let safety_mode (metadata:Ast.metadata) =
 				traverse (Some SMLoose) rest
 			| _, (Meta.NullSafety, [(EConst (Ident "Strict"), _)], _) :: rest ->
 				traverse (Some SMStrict) rest
+			| _, (Meta.NullSafety, [(EConst (Ident "StrictThreaded"), _)], _) :: rest ->
+				traverse (Some SMStrictThreaded) rest
 			| _, _ :: rest ->
 				traverse mode rest
 	in
@@ -435,7 +442,7 @@ let rec validate_safety_meta report (metadata:Ast.metadata) =
 		| [] -> ()
 		| (Meta.NullSafety, args, pos) :: rest ->
 			(match args with
-				| ([] | [(EConst (Ident ("Off" | "Loose" | "Strict")), _)]) -> ()
+				| ([] | [(EConst (Ident ("Off" | "Loose" | "Strict" | "StrictThreaded")), _)]) -> ()
 				| _ -> add_error report "Invalid argument for @:nullSafety meta" pos
 			);
 			validate_safety_meta report rest
@@ -450,16 +457,6 @@ let should_be_initialized field =
 		| Var _ -> Meta.has Meta.IsVar field.cf_meta
 		| _ -> 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.
 *)
@@ -504,7 +501,7 @@ class immediate_execution =
 							(* known to be pure *)
 							| { cl_path = ([], "Array") }, _ -> true
 							(* 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
 									false
 								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
 				| SNotSuitable -> ()
 				| 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
-							Hashtbl.remove safe_locals safe_subj
+							safe_subj :: to_remove
+						else
+							to_remove
 					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
 		*)
 		method private get_subject =
-			get_subject (mode <> SMStrict)
+			get_subject mode
 	end
 
 (**
@@ -765,12 +798,12 @@ class local_safety (mode:safety_mode) =
 				| TWhile (condition, body, DoWhile) ->
 					let original_safe_locals = self#get_safe_locals_copy in
 					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
 						(fun () ->
 							List.iter
 								(fun not_null ->
-									match get_subject (mode <> SMStrict) not_null with
+									match get_subject mode not_null with
 										| SNotSuitable -> ()
 										| subj ->
 											if Hashtbl.mem original_safe_locals subj then
@@ -781,7 +814,7 @@ class local_safety (mode:safety_mode) =
 						body
 				| TWhile (condition, body, NormalWhile) ->
 					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 *)
 					List.iter self#get_current_scope#add_to_safety not_nulls;
 					body_callback
@@ -833,7 +866,7 @@ class local_safety (mode:safety_mode) =
 				| TIf (condition, if_body, else_body) ->
 					condition_callback condition;
 					let (_, not_nulls) =
-						process_condition (mode <> SMStrict) condition is_nullable_expr (fun _ -> ())
+						process_condition mode condition is_nullable_expr (fun _ -> ())
 					in
 					(* Don't touch expressions, which already was safe before this `if` *)
 					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 }
 					in
 					let (_, else_not_nulls) =
-						process_condition (mode <> SMStrict) not_condition is_nullable_expr (fun _ -> ())
+						process_condition mode not_condition is_nullable_expr (fun _ -> ())
 					in
 					let else_not_nulls = filter else_not_nulls in
 					(** 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) =
 			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;
 			callback right_expr;
 			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.
 		*)
 		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;
 			callback right_expr;
 			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.
 		*)
 		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;
 				if is_nullable_expr right_expr then
 					match left_expr.eexpr with
@@ -911,6 +944,8 @@ class local_safety (mode:safety_mode) =
 						| _ -> ()
 				else if is_nullable_type left_expr.etype then
 					self#get_current_scope#add_to_safety left_expr
+		method call_made =
+			self#get_current_scope#call_made
 	end
 
 (**
@@ -1282,11 +1317,11 @@ class expr_checker mode immediate_execution report =
 			Make sure nobody tries to access a field on a nullable value
 		*)
 		method private check_field target access p =
+			self#check_expr target;
 			if self#is_nullable_expr target then
 				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 =
 			match e_new.eexpr with
@@ -1321,7 +1356,7 @@ class expr_checker mode immediate_execution report =
 				| _ ->
 					self#check_expr callee
 			);
-			match follow callee.etype with
+			(match follow callee.etype with
 				| TFun (types, _) ->
 					if is_trace callee then
 						let real_args =
@@ -1343,6 +1378,8 @@ class expr_checker mode immediate_execution report =
 						self#check_args callee args types
 				| _ ->
 					List.iter self#check_expr args
+			);
+			local_safety#call_made
 		(**
 			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 ->
 			(* Check the local imports *)
 			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
 	with
 	| Not_found when no_pack ->
@@ -134,7 +134,7 @@ let load_type_def ctx p t =
 				| (pack,ppack) :: l ->
 					begin try
 						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
 					with Not_found ->
 						loop l

+ 1 - 1
src/typing/typeloadCheck.ml

@@ -436,7 +436,7 @@ module Inheritance = struct
 						List.find path_matches ctx.m.curmod.m_types
 					with Not_found ->
 						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
 					in
 					{ 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 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
+			| Var { v_write = AccNever } -> args,el,tl
 			| Var _ ->
 				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
@@ -202,8 +203,6 @@ let transform_abstract_field com this_t a_t a f =
 	let p = f.cff_pos in
 	match f.cff_kind with
 	| 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 }
 	| FProp _ when not stat ->
 		error "Member property accessors must be get/set or never" p;
@@ -325,6 +324,11 @@ type enum_abstract_mode =
 	| EAInt of int ref
 	| EAOther
 
+type enum_constructor_visibility =
+	| VUnknown
+	| VPublic of placed_access
+	| VPrivate of placed_access
+
 let build_enum_abstract ctx c a fields p =
 	let mode =
 		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 ->
 		match field.cff_kind with
 		| 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;
 			let ct = match ct with
 				| 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;
 				| (Meta.To,_,_) :: _ ->
 					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... *)
 					if not (Meta.has Meta.Impl cf.cf_meta) then cf.cf_meta <- (Meta.Impl,[],null_pos) :: cf.cf_meta;
 					let resolve_m args =
@@ -1216,8 +1255,6 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 						), p))
 			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
 				| Method MethMacro ->
 					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
 	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
 	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 =
 		try List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types with Not_found -> assert false
 	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. *)
 		| 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 ->
-			ImportHandling.add_import_position ctx.com p path;
+			ImportHandling.add_import_position ctx p path;
 		| 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
@@ -617,56 +669,8 @@ let init_module_type ctx context_init do_init (decl,p) =
 		let is_flat = ref true in
 		let fields = ref PMap.empty in
 		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);
-			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;
 			fields := PMap.add cf.cf_name cf !fields;
 			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
 				loop (AKExpr e)
 			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 _ ->
 			error "This kind of operation is not supported" p
 		| AKFieldSet _ ->

+ 3 - 1
std/Array.hx

@@ -265,7 +265,9 @@ extern class Array<T> {
 	/**
 		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`.

+ 1 - 1
std/DateTools.hx

@@ -194,7 +194,7 @@ class DateTools {
 	/**
 		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;
 	}
 

+ 1 - 1
std/Math.hx

@@ -233,7 +233,7 @@ extern class Math {
 	**/
 	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`.
 

+ 0 - 6
std/Reflect.hx

@@ -47,9 +47,6 @@ extern class Reflect {
 		to `Reflect.getProperty` for a function supporting property accessors.
 
 		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;
 
@@ -60,9 +57,6 @@ extern class Reflect {
 		work for anonymous structures.
 
 		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;
 

+ 0 - 4
std/Type.hx

@@ -189,8 +189,6 @@ extern class Type {
 		The order of the fields in the returned Array 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>;
 
@@ -202,8 +200,6 @@ extern class Type {
 		The order of the fields in the returned Array 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>;
 

+ 4 - 2
std/cs/Boot.hx

@@ -41,8 +41,10 @@ import Reflect;
 @:dox(hide)
 class Boot {
 	@: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();
 	}
 }

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

@@ -415,8 +415,8 @@ final class Array<T> implements ArrayAccess<T> {
 		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 {
@@ -460,21 +460,3 @@ final class Array<T> implements ArrayAccess<T> {
 		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)
 			return null;
 
-		var ret = 0;
 		var base = 10;
-		var i = -1;
 		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;
-				}
-				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;
-				}
-			} 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 {

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

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

+ 3 - 14
std/flash/Boot.hx

@@ -22,7 +22,6 @@
 
 package flash;
 
-#if !as3
 @:keep private class RealBoot extends Boot {
 	#if swc
 	public function new() {
@@ -42,7 +41,6 @@ package flash;
 	}
 	#end
 }
-#end
 
 @:dox(hide)
 @:keep
@@ -282,7 +280,7 @@ class Boot extends flash.display.MovieClip {
 						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 m = date.getMonth() + 1;
 				var d = date.getDate();
@@ -313,16 +311,7 @@ class Boot extends flash.display.MovieClip {
 				return true;
 			}
 			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) {
 				__this__.length = len;
@@ -332,7 +321,7 @@ class Boot extends flash.display.MovieClip {
 			aproto.setPropertyIsEnumerable("remove", false);
 			aproto.setPropertyIsEnumerable("iterator", false);
 			aproto.setPropertyIsEnumerable("resize", false);
-			#if (as3 || no_flash_override)
+			#if no_flash_override
 			aproto.filterHX = function(f) {
 				var ret = [];
 				var i = 0;

+ 1 - 2
std/flash/NativeXml.hx

@@ -66,8 +66,7 @@ class Xml {
 		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);
 	}
 

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

@@ -65,16 +65,6 @@
 		untyped {
 			if (o == null)
 				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 a = [];
 			while (untyped __has_next__(o, i)) {
@@ -82,7 +72,6 @@
 				if (o.hasOwnProperty(prop))
 					a.push(prop);
 			}
-			#end
 			return a;
 		}
 
@@ -113,11 +102,7 @@
 		}
 
 	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;
-		#end
 	}
 
 	public static function deleteField(o:Dynamic, field:String):Bool

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

@@ -78,19 +78,14 @@ enum ValueType {
 				return "Float";
 			case "Boolean":
 				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 {
@@ -111,10 +106,6 @@ enum ValueType {
 						return Int;
 					case "Float":
 						return Float;
-					#if as3
-					case "Dynamic":
-						return Dynamic;
-					#end
 				}
 				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) {
+		responseAsString = null;
 		responseBytes = null;
 		var loader = req = new flash.net.URLLoader();
 		loader.dataFormat = BINARY;

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

@@ -22,37 +22,6 @@
 
 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
 class Resource {
 	static var content:Array<{name:String}>;
@@ -88,4 +57,3 @@ class Resource {
 		content = untyped __resources__();
 	}
 }
-#end

部分文件因文件數量過多而無法顯示