浏览代码

Merge branch 'development' into constrained_monomorphs

# Conflicts:
#	extra/haxelib_src
#	src/typing/typeload.ml
#	src/typing/typer.ml
Simon Krajewski 5 年之前
父节点
当前提交
781606c1b5
共有 100 个文件被更改,包括 3332 次插入2662 次删除
  1. 2 1
      .gitignore
  2. 5 2
      Makefile
  3. 12 7
      Makefile.win
  4. 10 15
      README.md
  5. 2 2
      azure-pipelines.yml
  6. 64 0
      extra/CHANGES.txt
  7. 190 0
      extra/FileAssociation.nsh
  8. 132 0
      extra/WinSetup.hx
  9. 3 2
      extra/azure-pipelines/build-linux.yml
  10. 2 1
      extra/azure-pipelines/build-mac.yml
  11. 5 1
      extra/azure-pipelines/build-windows.yml
  12. 1 1
      extra/azure-pipelines/test-windows.yml
  13. 16 0
      extra/brew-flash-update.md
  14. 0 16
      extra/build-haxesetup.xml
  15. 1 1
      extra/haxelib_src
  16. 11 3
      extra/installer.nsi
  17. 0 71
      extra/setup.cpp
  18. 0 21
      extra/setup.sln
  19. 0 120
      extra/setup.vcproj
  20. 0 23
      libs/extc/extc.ml
  21. 1 140
      libs/extc/extc_stubs.c
  22. 9 0
      libs/mbedtls/dune
  23. 69 0
      libs/mbedtls/mbedtls.ml
  24. 598 0
      libs/mbedtls/mbedtls_stubs.c
  25. 5 5
      src-json/define.json
  26. 45 4
      src-json/meta.json
  27. 1 3
      src/codegen/codegen.ml
  28. 18 2
      src/codegen/gencommon/castDetect.ml
  29. 10 3
      src/codegen/gencommon/reflectionCFs.ml
  30. 1 1
      src/codegen/genxml.ml
  31. 23 16
      src/compiler/displayOutput.ml
  32. 43 30
      src/compiler/haxe.ml
  33. 14 15
      src/compiler/server.ml
  34. 24 18
      src/context/common.ml
  35. 3 2
      src/context/compilationServer.ml
  36. 66 123
      src/context/display/diagnostics.ml
  37. 105 0
      src/context/display/diagnosticsPrinter.ml
  38. 10 0
      src/context/display/diagnosticsTypes.ml
  39. 2 2
      src/context/display/display.ml
  40. 13 7
      src/context/display/displayEmitter.ml
  41. 67 37
      src/context/display/displayException.ml
  42. 1 1
      src/context/display/displayFields.ml
  43. 6 3
      src/context/display/displayJson.ml
  44. 160 0
      src/context/display/displayTexpr.ml
  45. 6 4
      src/context/display/displayToplevel.ml
  46. 21 11
      src/context/display/documentSymbols.ml
  47. 38 166
      src/context/display/findReferences.ml
  48. 7 10
      src/context/display/importHandling.ml
  49. 113 28
      src/context/display/statistics.ml
  50. 181 0
      src/context/display/syntaxExplorer.ml
  51. 2 5
      src/context/typecore.ml
  52. 8 8
      src/core/abstract.ml
  53. 22 2
      src/core/ast.ml
  54. 1 1
      src/core/display/completionItem.ml
  55. 36 21
      src/core/displayTypes.ml
  56. 2 0
      src/core/globals.ml
  57. 1 1
      src/core/json/genjson.ml
  58. 14 11
      src/core/numeric.ml
  59. 1 0
      src/core/tFunctions.ml
  60. 6 2
      src/core/tPrinting.ml
  61. 1 0
      src/core/tType.ml
  62. 1 1
      src/dune
  63. 6 37
      src/filters/filters.ml
  64. 10 0
      src/filters/filtersCommon.ml
  65. 1 1
      src/filters/jsExceptions.ml
  66. 222 0
      src/filters/tre.ml
  67. 1 1
      src/filters/tryCatchWrapper.ml
  68. 0 1322
      src/generators/genas3.ml
  69. 64 10
      src/generators/gencs.ml
  70. 49 29
      src/generators/genhl.ml
  71. 1 1
      src/generators/genjava.ml
  72. 125 55
      src/generators/genjs.ml
  73. 36 20
      src/generators/genjvm.ml
  74. 126 34
      src/generators/genphp7.ml
  75. 51 53
      src/generators/genpy.ml
  76. 1 1
      src/generators/genswf9.ml
  77. 2 0
      src/generators/hl2c.ml
  78. 3 0
      src/generators/jvm/jvmSignature.ml
  79. 12 6
      src/macro/eval/evalContext.ml
  80. 1 1
      src/macro/eval/evalDebugMisc.ml
  81. 27 20
      src/macro/eval/evalDebugSocket.ml
  82. 5 11
      src/macro/eval/evalEmitter.ml
  83. 8 1
      src/macro/eval/evalHash.ml
  84. 2 5
      src/macro/eval/evalJit.ml
  85. 2 2
      src/macro/eval/evalMain.ml
  86. 5 6
      src/macro/eval/evalPrinting.ml
  87. 2 2
      src/macro/eval/evalPrototype.ml
  88. 202 0
      src/macro/eval/evalSsl.ml
  89. 23 18
      src/macro/eval/evalStdLib.ml
  90. 4 0
      src/macro/eval/evalString.ml
  91. 35 10
      src/macro/eval/evalThread.ml
  92. 19 12
      src/macro/eval/evalValue.ml
  93. 23 8
      src/macro/macroApi.ml
  94. 6 6
      src/optimization/analyzer.ml
  95. 1 1
      src/optimization/analyzerConfig.ml
  96. 5 7
      src/optimization/analyzerTexpr.ml
  97. 1 1
      src/optimization/analyzerTexprTransformer.ml
  98. 13 7
      src/optimization/dce.ml
  99. 24 2
      src/optimization/inline.ml
  100. 3 2
      src/optimization/optimizer.ml

+ 2 - 1
.gitignore

@@ -78,6 +78,7 @@ tests/unit/compile.php.hxml
 !/extra/build-haxesetup.xml
 tests/optimization/testopt.js
 tests/misc/pythonImport/native_python/__pycache__
+tests/misc/python/pythonImport/native_python/__pycache__
 tests/unit/unit.py
 tests/unit/unit.py.res1.txt
 tests/unit/unit.py.res2.bin
@@ -114,7 +115,7 @@ Makefile.modules
 /tests/unit/compiler_loops/log.txt
 tests/benchs/mandelbrot/bin/
 
-tests/unit/pypy3-*
+tests/unit/pypy3*
 tmp.tmp
 
 dev-display.hxml

+ 5 - 2
Makefile

@@ -60,9 +60,12 @@ HAXE_VERSION=$(shell $(CURDIR)/$(HAXE_OUTPUT) -version 2>&1 | awk '{print $$1;}'
 HAXE_VERSION_SHORT=$(shell echo "$(HAXE_VERSION)" | grep -oE "^[0-9]+\.[0-9]+\.[0-9]+")
 
 ifneq ($(STATICLINK),0)
-	LIB_PARAMS= -cclib '-Wl,-Bstatic -lpcre -lz -Wl,-Bdynamic '
+	LIB_PARAMS= -cclib '-Wl,-Bstatic -lpcre -lz -lmbedtls -lmbedx509 -lmbedcrypto -Wl,-Bdynamic '
 else
-	LIB_PARAMS?= -cclib -lpcre -cclib -lz
+	LIB_PARAMS?= -cclib -lpcre -cclib -lz -cclib -lmbedtls -cclib -lmbedx509 -cclib -lmbedcrypto
+endif
+ifeq ($(SYSTEM_NAME),Mac)
+	LIB_PARAMS+= -cclib '-framework Security -framework CoreFoundation'
 endif
 
 all: haxe tools

+ 12 - 7
Makefile.win

@@ -42,7 +42,16 @@ ifdef FILTER
 CC_CMD=($(COMPILER) $(ALL_CFLAGS) -c $< 2>tmp.cmi && $(FILTER)) || ($(FILTER) && exit 1)
 endif
 
-PACKAGE_FILES=$(HAXE_OUTPUT) $(HAXELIB_OUTPUT) std "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep zlib1.dll | sed -e 's/^\s*//')" "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libpcre-1.dll | sed -e 's/^\s*//')"
+ifeq ($(STATICLINK),0)
+	LIB_PARAMS = -cclib -lpcre -cclib -lz -cclib -lcrypt32 -cclib -lmbedtls -cclib -lmbedcrypto -cclib -lmbedx509
+endif
+
+PACKAGE_FILES=$(HAXE_OUTPUT) $(HAXELIB_OUTPUT) std \
+	"$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep zlib1.dll | sed -e 's/^\s*//')" \
+	"$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libpcre-1.dll | sed -e 's/^\s*//')" \
+	"$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedcrypto.dll | sed -e 's/^\s*//')" \
+	"$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedtls.dll | sed -e 's/^\s*//')" \
+	"$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedx509.dll | sed -e 's/^\s*//')"
 
 echo_package_files:
 	echo $(PACKAGE_FILES)
@@ -85,12 +94,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
 

+ 2 - 2
azure-pipelines.yml

@@ -63,7 +63,7 @@ stages:
             php:
               TEST: php
             flash:
-              TEST: flash9,as3
+              TEST: flash9
               APT_PACKAGES: libglib2.0 libfreetype6 xvfb
               DISPLAY: ':99.0'
               AUDIODEV: 'null'
@@ -140,7 +140,7 @@ stages:
             php:
               TEST: php
             flash:
-              TEST: flash9,as3
+              TEST: flash9
             python:
               TEST: python
             lua:

+ 64 - 0
extra/CHANGES.txt

@@ -1,3 +1,67 @@
+????-??-??: 4.1.0
+
+	General improvements:
+
+	js : use abstract type name for generating its implementation class (#9006)
+	js : improve haxe.ds.StringMap implementation (#8909)
+
+2019-12-17: 4.0.5
+
+	Bugfixes:
+
+	java : fix boolean arguments for `Type.createInstance(cls, args)` (#9025)
+	jvm : fix static overloads (#9034)
+	java/cs : fixed `Reflect.makeVarArgs(fn)` for calls of `fn` without arguments (#9037)
+	js : fix multiple appearances of the first object added to `ObjectMap` is passed to `ObjectMap.set(obj, v)` multiple times (#9026)
+	js : automatically wrap compound expressions with parentheses when passed to `js.Syntax.code()` (#9024)
+	windows : fix adding neko to PATH env var running windows installer (#9021)
+
+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:

+ 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();
+	}
+}

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

@@ -15,9 +15,10 @@ jobs:
         submodules: recursive
       - script: |
           set -ex
-          sudo add-apt-repository ppa:avsm/ppa -y # provides newer version of OCaml and OPAM
+          sudo add-apt-repository ppa:avsm/ppa -y # provides OPAM 2
+          sudo add-apt-repository ppa:haxe/ocaml -y # provides newer version of mbedtls
           sudo apt-get update -qqy
-          sudo apt-get install -qqy ocaml-nox camlp5 opam libpcre3-dev zlib1g-dev libgtk2.0-dev ninja-build
+          sudo apt-get install -qqy ocaml-nox camlp5 opam libpcre3-dev zlib1g-dev libgtk2.0-dev libmbedtls-dev ninja-build
         displayName: Install dependencies
       - template: install-neko-snapshot.yaml
         parameters:

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

@@ -16,6 +16,7 @@ jobs:
       - script: |
           set -ex
           brew update || brew update || brew update
+          brew unlink python@2
           brew bundle --file=tests/Brewfile --no-upgrade
         displayName: Install dependencies
       - template: install-neko-snapshot.yaml
@@ -32,7 +33,7 @@ jobs:
         displayName: Install OCaml libraries
       - script: |
           set -ex
-          opam config exec -- make -s -j`sysctl -n hw.ncpu` STATICLINK=1 "LIB_PARAMS=/usr/local/opt/zlib/lib/libz.a /usr/local/lib/libpcre.a" haxe
+          opam config exec -- make -s -j`sysctl -n hw.ncpu` STATICLINK=1 "LIB_PARAMS=/usr/local/opt/zlib/lib/libz.a /usr/local/lib/libpcre.a /usr/local/lib/libmbedtls.a /usr/local/lib/libmbedcrypto.a /usr/local/lib/libmbedx509.a -cclib '-framework Security -framework CoreFoundation'" haxe
           opam config exec -- make -s haxelib
           make -s package_bin package_installer_mac
           ls -l out

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

@@ -30,6 +30,8 @@ jobs:
           choco install --no-progress nsis.portable --version 3.02 -y
           choco install --no-progress curl wget 7zip.portable -y
         displayName: Install dependencies
+      - powershell: Write-Host "##vso[task.prependpath]C:\ProgramData\chocolatey\bin"
+        displayName: Prepend Chocolatey path
       - template: install-neko-snapshot.yaml
         parameters:
           ${{ if eq(parameters.arch, '64') }}:
@@ -39,9 +41,11 @@ jobs:
       - powershell: |
           Set-PSDebug -Trace 1
           curl.exe -fsSL -o cygwin-setup.exe --retry 3 $(CYGWIN_SETUP)
-          Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $(CYG_ROOT) -l C:/tmp -s $(CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre-devel -P mingw64-$(MINGW_ARCH)-zlib -P mingw64-$(MINGW_ARCH)-gcc-core -P mingw64-$(MINGW_ARCH)-pcre" -Wait
+          Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $(CYG_ROOT) -l C:/tmp -s $(CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre-devel -P mbedtls-devel -P mingw64-$(MINGW_ARCH)-zlib -P mingw64-$(MINGW_ARCH)-gcc-core -P mingw64-$(MINGW_ARCH)-pcre" -Wait
           curl.exe -fsSL -o "opam.tar.xz" --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.2/opam$(ARCH).tar.xz
+          curl.exe -fsSL -o "libmbedtls.tar.xz" --retry 3 https://github.com/Simn/mingw64-mbedtls/releases/download/2.16.3/mingw64-$(MINGW_ARCH)-mbedtls-2.16.3-1.tar.xz
           & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'echo "$OLDPWD"')
+          & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -C / -xvf libmbedtls.tar.xz')
           & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -xf opam.tar.xz')
           & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && bash opam$(ARCH)/install.sh')
           & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'opam init mingw "https://github.com/fdopen/opam-repository-mingw.git#opam2" --comp 4.07.0+mingw$(ARCH)c --switch 4.07.0+mingw$(ARCH)c --auto-setup --yes 2>&1')

+ 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.

+ 16 - 0
extra/brew-flash-update.md

@@ -0,0 +1,16 @@
+# How to update flash player signatures in Brew
+
+It's easiest to use a mac to do the update since there is a developer script provided by homebrew-cask that can semi-automate the thing.
+
+Steps:
+1. clone https://github.com/Homebrew/homebrew-cask
+2. Run ./developer/bin/update_cask_family flash $NEW_VERSION_STRING
+
+If homebrew-cask's CI succeed, the PR will be automatically merged by a bot, and our CI is saved.
+
+The super annoying thing is that, homebrew-cask's CI will check Adobe's appcast for the version string, but the appcast is usually outdated until about a day after the new Flash Player release.
+
+See https://github.com/Homebrew/homebrew-cask/pull/73950#issuecomment-563920561
+
+----
+Example PR: https://github.com/Homebrew/homebrew-cask/pull/73952

+ 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 a3e2f64f417216a0e720c485844e1a6f4df7c1ab
+Subproject commit 4b27f91d8a4ff279d9903091680fee2c93a0d574

+ 11 - 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,7 @@ 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"
 
 	WriteUninstaller "$INSTDIR\Uninstall.exe"
 
@@ -144,6 +145,12 @@ Section "Neko ${NEKO_VERSION}" Neko
 
 SectionEnd
 
+Section "-Update PATH"
+
+	ExecWait '"$INSTDIR\haxe\haxe.exe" --cwd "$INSTDIR\haxe" -x WinSetup.hx'
+	SendMessage ${HWND_BROADCAST} ${WM_SETTINGCHANGE} 0 "STR:Environment" /TIMEOUT=5000
+
+SectionEnd
 
 
 
@@ -163,6 +170,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

+ 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>

+ 0 - 23
libs/extc/extc.ml

@@ -51,29 +51,6 @@ external zlib_crc32 : bytes -> int -> int32 = "zlib_crc32"
 
 external time : unit -> float = "sys_time"
 
-type library
-type sym
-type value
-
-external dlopen : string -> library = "sys_dlopen"
-external dlsym : library -> string -> sym = "sys_dlsym"
-external dlcall0 : sym -> value = "sys_dlcall0"
-external dlcall1 : sym -> value -> value = "sys_dlcall1"
-external dlcall2 : sym -> value -> value -> value = "sys_dlcall2"
-external dlcall3 : sym -> value -> value -> value -> value = "sys_dlcall3"
-external dlcall4 : sym -> value -> value -> value -> value -> value = "sys_dlcall4"
-external dlcall5 : sym -> value -> value -> value -> value -> value -> value = "sys_dlcall5_bc" "sys_dlcall5"
-external dlint : int -> value = "sys_dlint"
-external dltoint : value -> int = "sys_dltoint"
-external dlstring : string -> value = "%identity"
-external dladdr : value -> int -> value = "sys_dladdr"
-external dlptr : value -> value = "sys_dlptr"
-external dlsetptr : value -> value -> unit = "sys_dlsetptr"
-external dlalloc_string : value -> string = "sys_dlalloc_string"
-external dlmemcpy : value -> value -> int -> unit = "sys_dlmemcpy"
-external dlcallback : int -> value = "sys_dlcallback"
-external dlcaml_callback : int -> value = "sys_dlcaml_callback"
-external dlint32 : int32 -> value = "sys_dlint32"
 external getch : bool -> int = "sys_getch"
 
 external filetime : string -> float = "sys_filetime"

+ 1 - 140
libs/extc/extc_stubs.c

@@ -572,143 +572,4 @@ CAMLprim value sys_filetime( value file ) {
 		return caml_copy_double(0.);
 	return caml_copy_double( sbuf.st_mtime );
 #	endif
-}
-
-// --------------- Support for NekoVM Bridge
-
-CAMLprim value sys_dlopen( value lib ) {
-#ifdef _WIN32
-	return (value)LoadLibrary(String_val(lib));
-#else
-	return (value)dlopen(String_val(lib),RTLD_LAZY);
-#endif
-}
-
-CAMLprim value sys_dlsym( value dl, value name ) {
-#ifdef _WIN32
-	return (value)GetProcAddress((HANDLE)dl,String_val(name));
-#else
-	return (value)dlsym((void*)dl,String_val(name));
-#endif
-}
-
-CAMLprim value sys_dlint( value i ) {
-	return Int_val(i);
-}
-
-CAMLprim value sys_dltoint( value i ) {
-	return Val_int((int)i);
-}
-
-CAMLprim value sys_dlint32( value i ) {
-	return (value)Int32_val(i);
-}
-
-typedef value (*c_prim0)();
-typedef value (*c_prim1)(value);
-typedef value (*c_prim2)(value,value);
-typedef value (*c_prim3)(value,value,value);
-typedef value (*c_prim4)(value,value,value,value);
-typedef value (*c_prim5)(value,value,value,value,value);
-
-CAMLprim value sys_dlcall0( value f ) {
-	return ((c_prim0)f)();
-}
-
-CAMLprim value sys_dlcall1( value f, value a ) {
-	return ((c_prim1)f)(a);
-}
-
-CAMLprim value sys_dlcall2( value f, value a, value b ) {
-	return ((c_prim2)f)(a,b);
-}
-
-CAMLprim value sys_dlcall3( value f, value a, value b, value c ) {
-	return ((c_prim3)f)(a,b,c);
-}
-
-CAMLprim value sys_dlcall4( value f, value a, value b, value c, value d ) {
-	return ((c_prim4)f)(a,b,c,d);
-}
-
-CAMLprim value sys_dlcall5( value f, value a, value b, value c, value d, value e ) {
-	return ((c_prim5)f)(a,b,c,d,e);
-}
-
-CAMLprim value sys_dlcall5_bc( value *args, int nargs ) {
-	return ((c_prim5)args[0])(args[1],args[2],args[3],args[4],args[5]);
-}
-
-CAMLprim value sys_dladdr( value v, value a ) {
-	return (value)((char*)v + Int_val(a));
-}
-
-CAMLprim value sys_dlptr( value v ) {
-	return *((value*)v);
-}
-
-CAMLprim value sys_dlsetptr( value p, value v ) {
-	*((value*)p) = v;
-	return Val_unit;
-}
-
-CAMLprim value sys_dlalloc_string( value v ) {
-	return caml_copy_string((char*)v);
-}
-
-CAMLprim value sys_dlmemcpy( value dst, value src, value len ) {
-	memcpy((char*)dst,(char*)src,Int_val(len));
-	return Val_unit;
-}
-
-static value __callb0( value callb ) {
-	return caml_callbackN(callb,0,NULL);
-}
-
-static value __callb1( value a, value callb ) {
-	return caml_callback(callb,a);
-}
-
-static value __callb2( value a, value b, value callb ) {
-	return caml_callback2(callb,a,b);
-}
-
-static value __callb3( value a, value b, value c, value callb ) {
-	return caml_callback3(callb,a,b,c);
-}
-
-CAMLprim value sys_dlcallback( value nargs ) {
-	switch( Int_val(nargs) ) {
-	case 0:
-		return (value)__callb0;
-	case 1:
-		return (value)__callb1;
-	case 2:
-		return (value)__callb2;
-	case 3:
-		return (value)__callb3;
-	default:
-		failwith("dlcallback(too_many_args)");
-	}
-	return Val_unit;
-}
-
-static value __caml_callb1( value a ) {
-	return caml_callback(*caml_named_value("dlcallb1"),a);
-}
-
-static value __caml_callb2( value a, value b ) {
-	return caml_callback2(*caml_named_value("dlcallb2"),a,b);
-}
-
-CAMLprim value sys_dlcaml_callback( value nargs ) {
-	switch( Int_val(nargs) ) {
-	case 1:
-		return (value)__caml_callb1;
-	case 2:
-		return (value)__caml_callb2;
-	default:
-		failwith("sys_dlcaml_callback(too_many_args)");
-	}
-	return Val_unit;
-}
+}

+ 9 - 0
libs/mbedtls/dune

@@ -0,0 +1,9 @@
+(include_subdirs no)
+
+(library
+	(name mbedtls)
+	(c_names
+		mbedtls_stubs
+	)
+	(wrapped false)
+)

+ 69 - 0
libs/mbedtls/mbedtls.ml

@@ -0,0 +1,69 @@
+type mbedtls_ctr_drbg_context
+type mbedtls_entropy_context
+type mbedtls_ssl_config
+type mbedtls_ssl_context
+type mbedtls_x509_crt
+type mbedtls_pk_context
+
+type mbedtls_result = int
+
+type t_mbedtls_entropy_func = mbedtls_entropy_context -> bytes -> int -> mbedtls_result
+
+external mbedtls_strerror : int -> string = "ml_mbedtls_strerror"
+
+external mbedtls_ctr_drbg_init : unit -> mbedtls_ctr_drbg_context = "ml_mbedtls_ctr_drbg_init"
+external mbedtls_ctr_drbg_random : mbedtls_ctr_drbg_context -> bytes -> int -> mbedtls_result = "ml_mbedtls_ctr_drbg_random"
+external mbedtls_ctr_drbg_seed :
+	mbedtls_ctr_drbg_context ->
+	'a ->
+	string option ->
+	mbedtls_result = "ml_mbedtls_ctr_drbg_seed"
+
+external mbedtls_entropy_func : mbedtls_entropy_context -> bytes -> int -> mbedtls_result = "ml_mbedtls_entropy_func"
+external mbedtls_entropy_init : unit -> mbedtls_entropy_context = "ml_mbedtls_entropy_init"
+
+external mbedtls_ssl_conf_ca_chain : mbedtls_ssl_config -> mbedtls_x509_crt -> unit = "ml_mbedtls_ssl_conf_ca_chain"
+external mbedtls_ssl_config_authmode : mbedtls_ssl_config -> int -> unit = "ml_mbedtls_ssl_conf_authmode"
+external mbedtls_ssl_config_defaults : mbedtls_ssl_config -> int -> int -> int -> mbedtls_result = "ml_mbedtls_ssl_config_defaults"
+external mbedtls_ssl_config_init : unit -> mbedtls_ssl_config = "ml_mbedtls_ssl_config_init"
+external mbedtls_ssl_config_rng : mbedtls_ssl_config -> 'a -> unit = "ml_mbedtls_ssl_conf_rng"
+
+external mbedtls_ssl_init : unit -> mbedtls_ssl_context = "ml_mbedtls_ssl_init"
+external mbedtls_ssl_get_peer_cert : mbedtls_ssl_context -> mbedtls_x509_crt option = "ml_mbedtls_ssl_get_peer_cert"
+external mbedtls_ssl_handshake : mbedtls_ssl_context -> mbedtls_result = "ml_mbedtls_ssl_handshake"
+external mbedtls_ssl_read : mbedtls_ssl_context -> bytes -> int -> int -> mbedtls_result = "ml_mbedtls_ssl_read"
+external mbedtls_ssl_set_bio :
+	mbedtls_ssl_context ->
+	'a ->
+	('a -> bytes -> mbedtls_result) ->
+	('a -> bytes -> mbedtls_result) ->
+	unit = "ml_mbedtls_ssl_set_bio"
+external mbedtls_ssl_set_hostname : mbedtls_ssl_context -> string -> mbedtls_result = "ml_mbedtls_ssl_set_hostname"
+external mbedtls_ssl_setup : mbedtls_ssl_context -> mbedtls_ssl_config -> mbedtls_result = "ml_mbedtls_ssl_setup"
+external mbedtls_ssl_write : mbedtls_ssl_context -> bytes -> int -> int -> mbedtls_result = "ml_mbedtls_ssl_write"
+
+external mbedtls_pk_init : unit -> mbedtls_pk_context = "ml_mbedtls_pk_init"
+external mbedtls_pk_parse_key : mbedtls_pk_context -> bytes -> string option -> mbedtls_result = "ml_mbedtls_pk_parse_key"
+external mbedtls_pk_parse_keyfile : mbedtls_pk_context -> string -> string option -> mbedtls_result = "ml_mbedtls_pk_parse_keyfile"
+external mbedtls_pk_parse_public_keyfile : mbedtls_pk_context -> string -> mbedtls_result = "ml_mbedtls_pk_parse_public_keyfile"
+external mbedtls_pk_parse_public_key : mbedtls_pk_context -> bytes -> mbedtls_result = "ml_mbedtls_pk_parse_public_key"
+
+external mbedtls_x509_crt_init : unit -> mbedtls_x509_crt = "ml_mbedtls_x509_crt_init"
+external mbedtls_x509_next : mbedtls_x509_crt -> mbedtls_x509_crt option = "ml_mbedtls_x509_next"
+external mbedtls_x509_crt_parse : mbedtls_x509_crt -> bytes -> mbedtls_result = "ml_mbedtls_x509_crt_parse"
+external mbedtls_x509_crt_parse_file : mbedtls_x509_crt -> string -> mbedtls_result = "ml_mbedtls_x509_crt_parse_file"
+external mbedtls_x509_crt_parse_path : mbedtls_x509_crt -> string -> mbedtls_result = "ml_mbedtls_x509_crt_parse_path"
+
+external hx_cert_get_alt_names : mbedtls_x509_crt -> string array = "hx_cert_get_alt_names"
+external hx_cert_get_issuer : mbedtls_x509_crt -> string -> string option = "hx_cert_get_issuer"
+external hx_cert_get_notafter : mbedtls_x509_crt -> float = "hx_cert_get_notafter"
+external hx_cert_get_notbefore : mbedtls_x509_crt -> float = "hx_cert_get_notbefore"
+external hx_cert_get_subject : mbedtls_x509_crt -> string -> string option = "hx_cert_get_subject"
+
+(* glue *)
+
+external hx_cert_load_defaults : mbedtls_x509_crt -> int = "hx_cert_load_defaults"
+external hx_get_ssl_authmode_flags : unit -> (string * int) array = "hx_get_ssl_authmode_flags"
+external hx_get_ssl_endpoint_flags : unit -> (string * int) array = "hx_get_ssl_endpoint_flags"
+external hx_get_ssl_preset_flags : unit -> (string * int) array = "hx_get_ssl_preset_flags"
+external hx_get_ssl_transport_flags : unit -> (string * int) array = "hx_get_ssl_transport_flags"

+ 598 - 0
libs/mbedtls/mbedtls_stubs.c

@@ -0,0 +1,598 @@
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <wincrypt.h>
+#endif
+
+#ifdef __APPLE__
+#include <Security/Security.h>
+#endif
+
+#include <caml/mlvalues.h>
+#include <caml/alloc.h>
+#include <caml/memory.h>
+#include <caml/fail.h>
+#include <caml/callback.h>
+#include <caml/custom.h>
+
+#include "mbedtls/debug.h"
+#include "mbedtls/error.h"
+#include "mbedtls/config.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/certs.h"
+#include "mbedtls/oid.h"
+
+#define PVoid_val(v) (*((void**) Data_custom_val(v)))
+
+void debug(void* ctx, int debug_level, const char* file_name, int line, const char* message) {
+	printf("%s:%i: %s", file_name, line, message);
+}
+
+#define Val_none Val_int(0)
+
+static value Val_some(value v) {
+    CAMLparam1(v);
+    CAMLlocal1(some);
+    some = caml_alloc(1, 0);
+    Store_field(some, 0, v);
+    CAMLreturn(some);
+}
+
+CAMLprim value ml_mbedtls_strerror(value code) {
+	CAMLparam1(code);
+	CAMLlocal1(r);
+	char buf[128];
+	mbedtls_strerror(Int_val(code), buf, sizeof(buf));
+	r = caml_copy_string(buf);
+	CAMLreturn(r);
+}
+
+// CtrDrbg
+
+#define CtrDrbg_val(v) (*((mbedtls_ctr_drbg_context**) Data_custom_val(v)))
+
+static void ml_mbedtls_ctr_drbg_finalize(value v) {
+	mbedtls_ctr_drbg_context* ctr_drbg = CtrDrbg_val(v);
+	if (ctr_drbg != NULL) {
+		mbedtls_ctr_drbg_free(ctr_drbg);
+	}
+}
+
+static struct custom_operations ctr_drbg_ops = {
+	.identifier  = "ml_ctr_drbg",
+	.finalize    = ml_mbedtls_ctr_drbg_finalize,
+	.compare     = custom_compare_default,
+	.hash        = custom_hash_default,
+	.serialize   = custom_serialize_default,
+	.deserialize = custom_deserialize_default,
+};
+
+CAMLprim value ml_mbedtls_ctr_drbg_init(void) {
+	CAMLparam0();
+	CAMLlocal1(obj);
+	obj = caml_alloc_custom(&ctr_drbg_ops, sizeof(mbedtls_ctr_drbg_context*), 0, 1);
+	mbedtls_ctr_drbg_context* ctr_drbg = malloc(sizeof(mbedtls_ctr_drbg_context));
+	mbedtls_ctr_drbg_init(ctr_drbg);
+	CtrDrbg_val(obj) = ctr_drbg;
+	CAMLreturn(obj);
+}
+
+CAMLprim value ml_mbedtls_ctr_drbg_random(value p_rng, value output, value output_len) {
+	CAMLparam3(p_rng, output, output_len);
+	CAMLreturn(Val_int(mbedtls_ctr_drbg_random(CtrDrbg_val(p_rng), String_val(output), Int_val(output_len))));
+}
+
+CAMLprim value ml_mbedtls_ctr_drbg_seed(value ctx, value p_entropy, value custom) {
+	CAMLparam2(ctx, custom);
+	CAMLreturn(Val_int(mbedtls_ctr_drbg_seed(CtrDrbg_val(ctx), mbedtls_entropy_func, PVoid_val(p_entropy), NULL, 0)));
+}
+
+// Entropy
+
+#define Entropy_val(v) (*((mbedtls_entropy_context**) Data_custom_val(v)))
+
+static void ml_mbedtls_entropy_finalize(value v) {
+	mbedtls_entropy_context* entropy = Entropy_val(v);
+	if (entropy != NULL) {
+		mbedtls_entropy_free(entropy);
+	}
+}
+
+static struct custom_operations entropy_ops = {
+	.identifier  = "ml_entropy",
+	.finalize    = ml_mbedtls_entropy_finalize,
+	.compare     = custom_compare_default,
+	.hash        = custom_hash_default,
+	.serialize   = custom_serialize_default,
+	.deserialize = custom_deserialize_default,
+};
+
+CAMLprim value ml_mbedtls_entropy_init(void) {
+	CAMLparam0();
+	CAMLlocal1(obj);
+	obj = caml_alloc_custom(&entropy_ops, sizeof(mbedtls_entropy_context*), 0, 1);
+	mbedtls_entropy_context* entropy = malloc(sizeof(mbedtls_entropy_context));
+	mbedtls_entropy_init(entropy);
+	Entropy_val(obj) = entropy;
+	CAMLreturn(obj);
+}
+
+CAMLprim value ml_mbedtls_entropy_func(value data, value output, value len) {
+	CAMLparam3(data, output, len);
+	CAMLreturn(Val_int(mbedtls_entropy_func(PVoid_val(data), String_val(output), Int_val(len))));
+}
+
+// Certificate
+
+#define X509Crt_val(v) (*((mbedtls_x509_crt**) Data_custom_val(v)))
+
+static void ml_mbedtls_x509_crt_finalize(value v) {
+	mbedtls_x509_crt* x509_crt = X509Crt_val(v);
+	if (x509_crt != NULL) {
+		mbedtls_x509_crt_free(x509_crt);
+	}
+}
+
+static struct custom_operations x509_crt_ops = {
+	.identifier  = "ml_x509_crt",
+	.finalize    = ml_mbedtls_x509_crt_finalize,
+	.compare     = custom_compare_default,
+	.hash        = custom_hash_default,
+	.serialize   = custom_serialize_default,
+	.deserialize = custom_deserialize_default,
+};
+
+CAMLprim value ml_mbedtls_x509_crt_init(void) {
+	CAMLparam0();
+	CAMLlocal1(obj);
+	obj = caml_alloc_custom(&x509_crt_ops, sizeof(mbedtls_x509_crt*), 0, 1);
+	mbedtls_x509_crt* x509_crt = malloc(sizeof(mbedtls_x509_crt));
+	mbedtls_x509_crt_init(x509_crt);
+	X509Crt_val(obj) = x509_crt;
+	CAMLreturn(obj);
+}
+
+CAMLprim value ml_mbedtls_x509_next(value chain) {
+	CAMLparam1(chain);
+	CAMLlocal2(r, obj);
+	mbedtls_x509_crt* cert = X509Crt_val(chain);
+	if (cert->next == NULL) {
+		CAMLreturn(Val_none);
+	}
+	obj = caml_alloc_custom(&x509_crt_ops, sizeof(mbedtls_x509_crt*), 0, 1);
+	X509Crt_val(obj) = cert->next;
+	CAMLreturn(Val_some(obj));
+}
+
+CAMLprim value ml_mbedtls_x509_crt_parse(value chain, value bytes) {
+	CAMLparam2(chain, bytes);
+	const char* buf = String_val(bytes);
+	int len = caml_string_length(bytes);
+	CAMLreturn(Val_int(mbedtls_x509_crt_parse(X509Crt_val(chain), buf, len + 1)));
+}
+
+CAMLprim value ml_mbedtls_x509_crt_parse_file(value chain, value path) {
+	CAMLparam2(chain, path);
+	CAMLreturn(Val_int(mbedtls_x509_crt_parse_file(X509Crt_val(chain), String_val(path))));
+}
+
+CAMLprim value ml_mbedtls_x509_crt_parse_path(value chain, value path) {
+	CAMLparam2(chain, path);
+	CAMLreturn(Val_int(mbedtls_x509_crt_parse_path(X509Crt_val(chain), String_val(path))));
+}
+
+// Certificate Haxe API
+
+value caml_string_of_asn1_buf(mbedtls_asn1_buf* dat) {
+	CAMLparam0();
+	CAMLlocal1(s);
+	s = caml_alloc_string(dat->len);
+	memcpy(String_val(s), dat->p, dat->len);
+	CAMLreturn(s);
+}
+
+CAMLprim value hx_cert_get_alt_names(value chain) {
+	CAMLparam1(chain);
+	CAMLlocal1(obj);
+	mbedtls_x509_crt* cert = X509Crt_val(chain);
+	if (cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME == 0 || &cert->subject_alt_names == NULL) {
+		obj = Atom(0);
+	} else {
+		mbedtls_asn1_sequence* cur = &cert->subject_alt_names;
+		int i = 0;
+		while (cur != NULL) {
+			++i;
+			cur = cur->next;
+		}
+		obj = caml_alloc(i, 0);
+		cur = &cert->subject_alt_names;
+		i = 0;
+		while (cur != NULL) {
+			Store_field(obj, i, caml_string_of_asn1_buf(&cur->buf));
+			++i;
+			cur = cur->next;
+		}
+	}
+	CAMLreturn(obj);
+}
+
+CAMLprim value hx_cert_get_subject(value chain, value objname) {
+	CAMLparam2(chain, objname);
+	mbedtls_x509_name *obj;
+	mbedtls_x509_crt* cert = X509Crt_val(chain);
+	const char *oname, *rname;
+	obj = &cert->subject;
+	rname = String_val(objname);
+	while (obj != NULL) {
+		int r = mbedtls_oid_get_attr_short_name(&obj->oid, &oname);
+		if (r == 0 && strcmp(oname, rname) == 0) {
+			CAMLreturn(Val_some(caml_string_of_asn1_buf(&obj->val)));
+		}
+		obj = obj->next;
+	}
+	CAMLreturn(Val_none);
+}
+
+CAMLprim value hx_cert_get_issuer(value chain, value objname) {
+	CAMLparam2(chain, objname);
+	mbedtls_x509_name *obj;
+	mbedtls_x509_crt* cert = X509Crt_val(chain);
+	int r;
+	const char *oname, *rname;
+	obj = &cert->issuer;
+	rname = String_val(objname);
+	while (obj != NULL) {
+		r = mbedtls_oid_get_attr_short_name(&obj->oid, &oname);
+		if (r == 0 && strcmp(oname, rname) == 0) {
+			CAMLreturn(Val_some(caml_string_of_asn1_buf(&obj->val)));
+		}
+		obj = obj->next;
+	}
+	CAMLreturn(Val_none);
+}
+
+time_t time_to_time_t(mbedtls_x509_time* t) {
+	struct tm info;
+	info.tm_year = t->year - 1900;
+	info.tm_mon = t->mon - 1;
+	info.tm_mday = t->day;
+	info.tm_hour = t->hour;
+	info.tm_min = t->min;
+	info.tm_sec = t->sec;
+	return mktime(&info);
+}
+
+CAMLprim value hx_cert_get_notafter(value chain) {
+	CAMLparam1(chain);
+	mbedtls_x509_crt* cert = X509Crt_val(chain);
+	mbedtls_x509_time *t = &cert->valid_to;
+	time_t time = time_to_time_t(t);
+	CAMLreturn(caml_copy_double((double)time));
+}
+
+CAMLprim value hx_cert_get_notbefore(value chain) {
+	CAMLparam1(chain);
+	mbedtls_x509_crt* cert = X509Crt_val(chain);
+	mbedtls_x509_time *t = &cert->valid_from;
+	time_t time = time_to_time_t(t);
+	CAMLreturn(caml_copy_double((double)time));
+}
+
+// Config
+
+#define Config_val(v) (*((mbedtls_ssl_config**) Data_custom_val(v)))
+
+static void ml_mbedtls_ssl_config_finalize(value v) {
+	mbedtls_ssl_config* ssl_config = Config_val(v);
+	if (ssl_config != NULL) {
+		mbedtls_ssl_config_free(ssl_config);
+	}
+}
+
+static struct custom_operations ssl_config_ops = {
+	.identifier  = "ml_ssl_config",
+	.finalize    = ml_mbedtls_ssl_config_finalize,
+	.compare     = custom_compare_default,
+	.hash        = custom_hash_default,
+	.serialize   = custom_serialize_default,
+	.deserialize = custom_deserialize_default,
+};
+
+CAMLprim value ml_mbedtls_ssl_config_init(void) {
+	CAMLparam0();
+	CAMLlocal1(obj);
+	obj = caml_alloc_custom(&ssl_config_ops, sizeof(mbedtls_ssl_config*), 0, 1);
+	mbedtls_ssl_config* ssl_config = malloc(sizeof(mbedtls_ssl_config));
+	mbedtls_ssl_config_init(ssl_config);
+	Config_val(obj) = ssl_config;
+	CAMLreturn(obj);
+}
+
+CAMLprim value ml_mbedtls_ssl_conf_authmode(value conf, value authmode) {
+	CAMLparam2(conf, authmode);
+	mbedtls_ssl_conf_authmode(Config_val(conf), Int_val(authmode));
+	CAMLreturn(Val_unit);
+}
+
+CAMLprim value ml_mbedtls_ssl_conf_ca_chain(value conf, value ca_chain) {
+	CAMLparam2(conf, ca_chain);
+	mbedtls_ssl_conf_ca_chain(Config_val(conf), X509Crt_val(ca_chain), NULL);
+	CAMLreturn(Val_unit);
+}
+
+CAMLprim value ml_mbedtls_ssl_config_defaults(value conf, value endpoint, value transport, value preset) {
+	CAMLparam4(conf, endpoint, transport, preset);
+	CAMLreturn(Val_int(mbedtls_ssl_config_defaults(Config_val(conf), Int_val(endpoint), Int_val(transport), Int_val(preset))));
+}
+
+CAMLprim value ml_mbedtls_ssl_conf_rng(value conf, value p_rng) {
+	CAMLparam2(conf, p_rng);
+	mbedtls_ssl_conf_rng(Config_val(conf), mbedtls_ctr_drbg_random, PVoid_val(p_rng));
+	CAMLreturn(Val_unit);
+}
+
+// Pk
+
+#define PkContext_val(v) (*((mbedtls_pk_context**) Data_custom_val(v)))
+
+static void ml_mbedtls_pk_context_finalize(value v) {
+	mbedtls_pk_context* pk_context = PkContext_val(v);
+	if (pk_context != NULL) {
+		mbedtls_pk_free(pk_context);
+	}
+}
+
+static struct custom_operations pk_context_ops = {
+	.identifier  = "ml_pk_context",
+	.finalize    = ml_mbedtls_pk_context_finalize,
+	.compare     = custom_compare_default,
+	.hash        = custom_hash_default,
+	.serialize   = custom_serialize_default,
+	.deserialize = custom_deserialize_default,
+};
+
+CAMLprim value ml_mbedtls_pk_init(void) {
+	CAMLparam0();
+	CAMLlocal1(obj);
+	obj = caml_alloc_custom(&pk_context_ops, sizeof(mbedtls_pk_context*), 0, 1);
+	mbedtls_pk_context* pk_context = malloc(sizeof(mbedtls_pk_context));
+	mbedtls_pk_init(pk_context);
+	PkContext_val(obj) = pk_context;
+	CAMLreturn(obj);
+}
+
+CAMLprim value ml_mbedtls_pk_parse_key(value ctx, value key, value password) {
+	CAMLparam3(ctx, key, password);
+	const char* pwd = NULL;
+	size_t pwdlen = 0;
+	if (password != Val_none) {
+		pwd = String_val(Field(password, 0));
+		pwdlen = caml_string_length(Field(password, 0));
+	}
+	CAMLreturn(mbedtls_pk_parse_key(PkContext_val(ctx), String_val(key), caml_string_length(key) + 1, pwd, pwdlen));
+}
+
+CAMLprim value ml_mbedtls_pk_parse_keyfile(value ctx, value path, value password) {
+	CAMLparam3(ctx, path, password);
+	const char* pwd = NULL;
+	if (password != Val_none) {
+		pwd = String_val(Field(password, 0));
+	}
+	CAMLreturn(mbedtls_pk_parse_keyfile(PkContext_val(ctx), String_val(path), pwd));
+}
+
+CAMLprim value ml_mbedtls_pk_parse_public_key(value ctx, value key) {
+	CAMLparam2(ctx, key);
+	CAMLreturn(mbedtls_pk_parse_public_key(PkContext_val(ctx), String_val(key), caml_string_length(key) + 1));
+}
+
+CAMLprim value ml_mbedtls_pk_parse_public_keyfile(value ctx, value path) {
+	CAMLparam2(ctx, path);
+	CAMLreturn(mbedtls_pk_parse_public_keyfile(PkContext_val(ctx), String_val(path)));
+}
+
+// Ssl
+
+#define SslContext_val(v) (*((mbedtls_ssl_context**) Data_custom_val(v)))
+
+static void ml_mbedtls_ssl_context_finalize(value v) {
+	mbedtls_ssl_context* ssl_context = SslContext_val(v);
+	if (ssl_context != NULL) {
+		mbedtls_ssl_free(ssl_context);
+	}
+}
+
+static struct custom_operations ssl_context_ops = {
+	.identifier  = "ml_ssl_context",
+	.finalize    = ml_mbedtls_ssl_context_finalize,
+	.compare     = custom_compare_default,
+	.hash        = custom_hash_default,
+	.serialize   = custom_serialize_default,
+	.deserialize = custom_deserialize_default,
+};
+
+CAMLprim value ml_mbedtls_ssl_init(void) {
+	CAMLparam0();
+	CAMLlocal1(obj);
+	obj = caml_alloc_custom(&ssl_context_ops, sizeof(mbedtls_ssl_context*), 0, 1);
+	mbedtls_ssl_context* ssl_context = malloc(sizeof(mbedtls_ssl_context));
+	mbedtls_ssl_init(ssl_context);
+	SslContext_val(obj) = ssl_context;
+	CAMLreturn(obj);
+}
+
+CAMLprim value ml_mbedtls_ssl_get_peer_cert(value ssl) {
+	CAMLparam1(ssl);
+	CAMLlocal1(obj);
+	mbedtls_ssl_context* ssl_context = SslContext_val(ssl);
+	mbedtls_x509_crt* crt = (mbedtls_x509_crt*)mbedtls_ssl_get_peer_cert(ssl_context);
+	if (crt == NULL) {
+		CAMLreturn(Val_none);
+	}
+	obj = caml_alloc_custom(&x509_crt_ops, sizeof(mbedtls_x509_crt*), 0, 1);
+	X509Crt_val(obj) = crt;
+	CAMLreturn(Val_some(obj));
+}
+
+CAMLprim value ml_mbedtls_ssl_handshake(value ssl) {
+	CAMLparam1(ssl);
+	CAMLreturn(Val_int(mbedtls_ssl_handshake(SslContext_val(ssl))));
+}
+
+CAMLprim value ml_mbedtls_ssl_read(value ssl, value buf, value pos, value len) {
+	CAMLparam4(ssl, buf, pos, len);
+	CAMLreturn(Val_int(mbedtls_ssl_read(SslContext_val(ssl), String_val(buf) + Int_val(pos), Int_val(len))));
+}
+
+static int bio_write_cb(void* ctx, const unsigned char* buf, size_t len) {
+	CAMLparam0();
+	CAMLlocal3(r, s, vctx);
+	vctx = (value)ctx;
+	s = caml_alloc_string(len);
+	memcpy(String_val(s), buf, len);
+	r = caml_callback2(Field(vctx, 1), Field(vctx, 0), s);
+	CAMLreturn(Int_val(r));
+}
+
+static int bio_read_cb(void* ctx, unsigned char* buf, size_t len) {
+	CAMLparam0();
+	CAMLlocal3(r, s, vctx);
+	vctx = (value)ctx;
+	s = caml_alloc_string(len);
+	r = caml_callback2(Field(vctx, 2), Field(vctx, 0), s);
+	memcpy(buf, String_val(s), len);
+	CAMLreturn(Int_val(r));
+}
+
+CAMLprim value ml_mbedtls_ssl_set_bio(value ssl, value p_bio, value f_send, value f_recv) {
+	CAMLparam4(ssl, p_bio, f_send, f_recv);
+	CAMLlocal1(ctx);
+	ctx = caml_alloc(3, 0);
+	Store_field(ctx, 0, p_bio);
+	Store_field(ctx, 1, f_send);
+	Store_field(ctx, 2, f_recv);
+	mbedtls_ssl_set_bio(SslContext_val(ssl), (void*)ctx, bio_write_cb, bio_read_cb, NULL);
+	CAMLreturn(Val_unit);
+}
+
+CAMLprim value ml_mbedtls_ssl_set_hostname(value ssl, value hostname) {
+	CAMLparam2(ssl, hostname);
+	CAMLreturn(Val_int(mbedtls_ssl_set_hostname(SslContext_val(ssl), String_val(hostname))));
+}
+
+CAMLprim value ml_mbedtls_ssl_setup(value ssl, value conf) {
+	CAMLparam2(ssl, conf);
+	CAMLreturn(Val_int(mbedtls_ssl_setup(SslContext_val(ssl), Config_val(conf))));
+}
+
+CAMLprim value ml_mbedtls_ssl_write(value ssl, value buf, value pos, value len) {
+	CAMLparam4(ssl, buf, pos, len);
+	CAMLreturn(Val_int(mbedtls_ssl_write(SslContext_val(ssl), String_val(buf) + Int_val(pos), Int_val(len))));
+}
+
+// glue
+
+CAMLprim value hx_cert_load_defaults(value certificate) {
+	CAMLparam1(certificate);
+	int r = 1;
+
+	mbedtls_x509_crt *chain = X509Crt_val(certificate);
+
+	#ifdef _WIN32
+	HCERTSTORE store;
+	PCCERT_CONTEXT cert;
+
+	if (store = CertOpenSystemStore(0, "Root")) {
+		cert = NULL;
+		while (cert = CertEnumCertificatesInStore(store, cert)) {
+			r = mbedtls_x509_crt_parse_der(chain, (unsigned char *)cert->pbCertEncoded, cert->cbCertEncoded);
+			if (r != 0) {
+				CAMLreturn(Val_int(r));
+			}
+		}
+		CertCloseStore(store, 0);
+	}
+	#endif
+
+	#ifdef __APPLE__
+	CFMutableDictionaryRef search;
+	CFArrayRef result;
+	SecKeychainRef keychain;
+	SecCertificateRef item;
+	CFDataRef dat;
+	// Load keychain
+	if (SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain", &keychain) == errSecSuccess) {
+		// Search for certificates
+		search = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
+		CFDictionarySetValue(search, kSecClass, kSecClassCertificate);
+		CFDictionarySetValue(search, kSecMatchLimit, kSecMatchLimitAll);
+		CFDictionarySetValue(search, kSecReturnRef, kCFBooleanTrue);
+		CFDictionarySetValue(search, kSecMatchSearchList, CFArrayCreate(NULL, (const void **)&keychain, 1, NULL));
+		if (SecItemCopyMatching(search, (CFTypeRef *)&result) == errSecSuccess) {
+			CFIndex n = CFArrayGetCount(result);
+			for (CFIndex i = 0; i < n; i++) {
+				item = (SecCertificateRef)CFArrayGetValueAtIndex(result, i);
+
+				// Get certificate in DER format
+				dat = SecCertificateCopyData(item);
+				if (dat) {
+					r = mbedtls_x509_crt_parse_der(chain, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat));
+					CFRelease(dat);
+					if (r != 0) {
+						CAMLreturn(Val_int(r));
+					}
+				}
+			}
+		}
+		CFRelease(keychain);
+	}
+	#endif
+
+	CAMLreturn(Val_int(r));
+}
+
+static value build_fields(int num_fields, const char* names[], int values[]) {
+	CAMLparam0();
+	CAMLlocal2(ret, tuple);
+	ret = caml_alloc(num_fields, 0);
+	for (int i = 0; i < num_fields; ++i) {
+		tuple = caml_alloc_tuple(2);
+		Store_field(tuple, 0, caml_copy_string(names[i]));
+		Store_field(tuple, 1, Val_int(values[i]));
+		Store_field(ret, i, tuple);
+	}
+	CAMLreturn(ret);
+}
+
+CAMLprim value hx_get_ssl_authmode_flags(value unit) {
+	CAMLparam1(unit);
+	const char* names[] = {"SSL_VERIFY_NONE", "SSL_VERIFY_OPTIONAL", "SSL_VERIFY_REQUIRED"};
+	int values[] = {MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL, MBEDTLS_SSL_VERIFY_REQUIRED};
+	CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values));
+}
+
+CAMLprim value hx_get_ssl_endpoint_flags(value unit) {
+	CAMLparam1(unit);
+	const char* names[] = {"SSL_IS_CLIENT", "SSL_IS_SERVER"};
+	int values[] = {MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_IS_SERVER};
+	CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values));
+}
+
+CAMLprim value hx_get_ssl_preset_flags(value unit) {
+	CAMLparam1(unit);
+	const char* names[] = {"SSL_PRESET_DEFAULT", "SSL_PRESET_SUITEB"};
+	int values[] = {MBEDTLS_SSL_PRESET_DEFAULT, MBEDTLS_SSL_PRESET_SUITEB};
+	CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values));
+}
+
+CAMLprim value hx_get_ssl_transport_flags(value unit) {
+	CAMLparam1(unit);
+	const char* names[] = {"SSL_TRANSPORT_STREAM", "SSL_TRANSPORT_DATAGRAM"};
+	int values[] = {MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_TRANSPORT_DATAGRAM};
+	CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values));
+}

+ 5 - 5
src-json/define.json

@@ -10,17 +10,17 @@
 		"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": "CheckXmlProxy",
 		"define": "check_xml_proxy",

+ 45 - 4
src-json/meta.json

@@ -52,6 +52,20 @@
 		"targets": ["TAbstract", "TAbstractField"],
 		"links": ["https://haxe.org/manual/types-abstract-array-access.html"]
 	},
+	{
+		"name": "AssemblyMeta",
+		"metadata": ":cs.assemblyMeta",
+		"doc": "Used to declare a native C# assembly attribute",
+		"platforms": ["cs"],
+		"targets": ["TClass"]
+	},
+	{
+		"name": "AssemblyStrict",
+		"metadata": ":cs.assemblyStrict",
+		"doc": "Used to declare a native C# assembly attribute; is type checked",
+		"platforms": ["cs"],
+		"targets": ["TClass"]
+	},
 	{
 		"name": "Ast",
 		"metadata": ":ast",
@@ -195,6 +209,13 @@
 		"targets": ["TClass", "TEnum"],
 		"internal": true
 	},
+	{
+		"name": "CsUsing",
+		"metadata": ":cs.using",
+		"doc": "Add using directives to your module",
+		"platforms": ["cs"],
+		"targets": ["TClass"]
+	},
 	{
 		"name": "Dce",
 		"metadata": ":dce",
@@ -419,6 +440,12 @@
 		"targets": ["TClassField"],
 		"internal": true
 	},
+	{
+		"name": "GenericClassPerMethod",
+		"metadata": ":genericClassPerMethod",
+		"doc": "Makes compiler generate separate class per generic static method specialization",
+		"targets": ["TClass"]
+	},
 	{
 		"name": "Getter",
 		"metadata": ":getter",
@@ -803,7 +830,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"]
 	},
@@ -922,7 +949,7 @@
 	{
 		"name": "Property",
 		"metadata": ":property",
-		"doc": "Marks a property field to be compiled as a native C# property.",
+		"doc": "Marks a field to be compiled as a native C# property.",
 		"platforms": ["cs"],
 		"targets": ["TClassField"]
 	},
@@ -1101,6 +1128,12 @@
 		"platforms": ["java"],
 		"targets": ["TClass"]
 	},
+	{
+		"name": "TailRecursion",
+		"metadata": ":tailRecursion",
+		"doc": "Internally used for tail recursion elimination.",
+		"internal": true
+	},
 	{
 		"name": "TemplatedCall",
 		"metadata": ":templatedCall",
@@ -1191,7 +1224,15 @@
 		"name": "Value",
 		"metadata": ":value",
 		"doc": "Used to store default values for fields and function arguments.",
-		"targets": ["TClassField"]
+		"targets": ["TClassField"],
+		"internal": true
+	},
+	{
+		"name": "HaxeArguments",
+		"metadata": ":haxe.arguments",
+		"doc": "Used to store function arguments.",
+		"targets": ["TClassField"],
+		"internal": true
 	},
 	{
 		"name": "Void",
@@ -1199,4 +1240,4 @@
 		"doc": "Use Cpp native `void` return type.",
 		"platforms": ["cpp"]
 	}
-]
+]

+ 1 - 3
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 };
@@ -466,7 +464,7 @@ let default_cast ?(vtmp="$t") com e texpr t p =
 	let std = (try List.find (fun t -> t_path t = ([],"Std")) com.types with Not_found -> assert false) in
 	let fis = (try
 			let c = (match std with TClassDecl c -> c | _ -> assert false) in
-			FStatic (c, PMap.find "is" c.cl_statics)
+			FStatic (c, PMap.find "isOfType" c.cl_statics)
 		with Not_found ->
 			assert false
 	) in

+ 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))))
 				)
 			)

+ 1 - 1
src/codegen/genxml.ml

@@ -52,7 +52,7 @@ let gen_doc s =
 let gen_doc_opt d =
 	match d with
 	| None -> []
-	| Some s -> [gen_doc s]
+	| Some d -> [gen_doc (Ast.gen_doc_text d)]
 
 let gen_arg_name (name,opt,_) =
 	(if opt then "?" else "") ^ name

+ 23 - 16
src/compiler/displayOutput.ml

@@ -71,8 +71,8 @@ let print_fields fields =
 		| ITModule path -> "type",snd path,"",None
 		| ITMetadata  meta ->
 			let s,(doc,_) = Meta.get_info meta in
-			"metadata","@" ^ s,"",Some doc
-		| ITTimer(name,value) -> "timer",name,"",Some value
+			"metadata","@" ^ s,"",doc_from_string doc
+		| ITTimer(name,value) -> "timer",name,"",doc_from_string value
 		| ITLiteral s ->
 			let t = match k.ci_type with None -> t_dynamic | Some (t,_) -> t in
 			"literal",s,s_type (print_context()) t,None
@@ -83,14 +83,14 @@ let print_fields fields =
 	let fields = List.sort (fun k1 k2 -> compare (legacy_sort k1) (legacy_sort k2)) fields in
 	let fields = List.map convert fields in
 	List.iter (fun(k,n,t,d) ->
-		let d = match d with None -> "" | Some d -> d in
+		let d = match d with None -> "" | Some d -> gen_doc_text d in
 		Buffer.add_string b (Printf.sprintf "<i n=\"%s\" k=\"%s\"><t>%s</t><d>%s</d></i>\n" n k (htmlescape t) (htmlescape d))
 	) fields;
 	Buffer.add_string b "</list>\n";
 	Buffer.contents b
 
-let maybe_print_doc d =
-	Option.map_default (fun s -> Printf.sprintf " d=\"%s\"" (htmlescape s)) "" d
+let maybe_print_doc d_opt =
+	Option.map_default (fun d -> Printf.sprintf " d=\"%s\"" (htmlescape (gen_doc_text d))) "" d_opt
 
 let print_toplevel il =
 	let b = Buffer.create 0 in
@@ -155,7 +155,7 @@ let print_signatures tl =
 	let b = Buffer.create 0 in
 	List.iter (fun (((args,ret),_),doc) ->
 		Buffer.add_string b "<type";
-		Option.may (fun s -> Buffer.add_string b (Printf.sprintf " d=\"%s\"" (htmlescape s))) doc;
+		Option.may (fun d -> Buffer.add_string b (Printf.sprintf " d=\"%s\"" (htmlescape (gen_doc_text d)))) doc;
 		Buffer.add_string b ">\n";
 		Buffer.add_string b (htmlescape (s_type (print_context()) (TFun(args,ret))));
 		Buffer.add_string b "\n</type>\n";
@@ -197,7 +197,7 @@ let print_signature tl display_arg =
 			"label",JString label;
 			"parameters",JArray parameters;
 		] in
-		JObject (match doc with None -> js | Some s -> ("documentation",JString s) :: js)
+		JObject (match doc with None -> js | Some d -> ("documentation",JString (gen_doc_text d)) :: js)
 	) tl in
 	let jo = JObject [
 		"signatures",JArray siginf;
@@ -230,11 +230,12 @@ let handle_display_argument com file_pos pre_compilation did_something =
 		(try Memory.display_memory com with e -> prerr_endline (Printexc.get_backtrace ()));
 	| "diagnostics" ->
 		Common.define com Define.NoCOpt;
-		com.display <- DisplayMode.create (DMDiagnostics true);
-		Parser.display_mode := DMDiagnostics true;
+		com.display <- DisplayMode.create (DMDiagnostics []);
+		Parser.display_mode := DMDiagnostics [];
 	| _ ->
 		let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format: " ^ file_pos) in
 		let file = unquote file in
+		let file_unique = Path.unique_full_path file in
 		let pos, smode = try ExtString.String.split pos "@" with _ -> pos,"" in
 		let mode = match smode with
 			| "position" ->
@@ -258,7 +259,7 @@ let handle_display_argument com file_pos pre_compilation did_something =
 				DMModuleSymbols None;
 			| "diagnostics" ->
 				Common.define com Define.NoCOpt;
-				DMDiagnostics false;
+				DMDiagnostics [file_unique];
 			| "statistics" ->
 				Common.define com Define.NoCOpt;
 				DMStatistics
@@ -283,7 +284,7 @@ let handle_display_argument com file_pos pre_compilation did_something =
 		Parser.display_mode := mode;
 		if not com.display.dms_full_typing then Common.define_value com Define.Display (if smode <> "" then smode else "1");
 		DisplayPosition.display_position#set {
-			pfile = Path.unique_full_path file;
+			pfile = file_unique;
 			pmin = pos;
 			pmax = pos;
 		}
@@ -348,7 +349,11 @@ let process_display_file com classes =
 					| [name] ->
 						classes := path :: !classes;
 						DPKNormal path
-					| _ ->
+					| [name;target] ->
+						let path = fst path, name in
+						classes := path :: !classes;
+						DPKNormal path
+					| e ->
 						assert false
 				in
 				path
@@ -387,7 +392,7 @@ let load_display_content_standalone ctx input =
 	let file = file_input_marker in
 	let p = {pfile = file; pmin = 0; pmax = 0} in
 	let parsed = TypeloadParse.parse_file_from_string com file p input in
-	let pack,decls = TypeloadParse.handle_parser_result com file p parsed in
+	let pack,decls = TypeloadParse.handle_parser_result com p parsed in
 	ignore(TypeloadModule.type_module ctx (pack,"?DISPLAY") file ~dont_check_path:true decls p)
 
 let promote_type_hints tctx =
@@ -410,10 +415,12 @@ let process_global_display_mode com tctx =
 	match com.display.dms_kind with
 	| DMUsage with_definition ->
 		FindReferences.find_references tctx com with_definition
-	| DMDiagnostics global ->
-		Diagnostics.run com global
+	| DMImplementation ->
+		FindReferences.find_implementations tctx com
+	| DMDiagnostics _ ->
+		Diagnostics.run com
 	| DMStatistics ->
-		let stats = Statistics.collect_statistics tctx (SFFile (DisplayPosition.display_position#get).pfile) in
+		let stats = Statistics.collect_statistics tctx (SFFile (DisplayPosition.display_position#get).pfile) true in
 		raise_statistics (Statistics.Printer.print_statistics stats)
 	| DMModuleSymbols (Some "") -> ()
 	| DMModuleSymbols filter ->

+ 43 - 30
src/compiler/haxe.ml

@@ -75,14 +75,27 @@ let limit_string s offset =
 	in
 	String.concat "" (loop 0 words)
 
-let error ctx msg p =
-	let msg = try List.assoc msg deprecated with Not_found -> msg in
-	message ctx (CMError(msg,p));
-	ctx.has_error <- true
+let rec error ctx msg p =
+	match ctx.com.pending_messages with
+	| Some add -> add (fun() -> error ctx msg p)
+	| None ->
+		let msg = try List.assoc msg deprecated with Not_found -> msg in
+		message ctx (CMError(msg,p));
+		ctx.has_error <- true
+
+let rec warning ctx msg p =
+	match ctx.com.pending_messages with
+	| Some add -> add (fun() -> warning ctx msg p)
+	| None -> message ctx (CMWarning(msg,p))
+
+let rec info ctx msg p =
+	match ctx.com.pending_messages with
+	| Some add -> add (fun() -> info ctx msg p)
+	| None -> message ctx (CMInfo(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"]
@@ -308,8 +321,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 ->
@@ -386,8 +397,8 @@ let setup_common_context ctx com =
 	Common.raw_define com "haxe4";
 	Common.define_value com Define.Haxe (s_version false);
 	Common.define_value com Define.Dce "std";
-	com.info <- (fun msg p -> message ctx (CMInfo(msg,p)));
-	com.warning <- (fun msg p -> message ctx (CMWarning(msg,p)));
+	com.info <- info ctx;
+	com.warning <- warning ctx;
 	com.error <- error ctx;
 	let filter_messages = (fun keep_errors predicate -> (List.filter (fun msg ->
 		(match msg with
@@ -444,7 +455,7 @@ let process_display_configuration ctx =
 			if com.display.dms_error_policy = EPCollect then
 				(fun s p -> add_diagnostics_message com s p DKCompilerError DisplayTypes.DiagnosticsSeverity.Warning)
 			else
-				(fun msg p -> message ctx (CMWarning(msg,p)));
+				warning ctx;
 		com.error <- error ctx;
 	end;
 	Lexer.old_format := Common.defined com Define.OldErrorFormat;
@@ -460,21 +471,21 @@ let process_display_configuration ctx =
 	end
 
 let run_or_diagnose com f arg =
-	let handle_diagnostics global msg p kind =
+	let handle_diagnostics msg p kind =
 		add_diagnostics_message com msg p kind DisplayTypes.DiagnosticsSeverity.Error;
-		Diagnostics.run com global;
+		Diagnostics.run com;
 	in
 	match com.display.dms_kind with
-	| DMDiagnostics global ->
+	| DMDiagnostics _ ->
 		begin try
 			f arg
 		with
 		| Error.Error(msg,p) ->
-			handle_diagnostics global (Error.error_msg msg) p DisplayTypes.DiagnosticsKind.DKCompilerError
+			handle_diagnostics (Error.error_msg msg) p DisplayTypes.DiagnosticsKind.DKCompilerError
 		| Parser.Error(msg,p) ->
-			handle_diagnostics global (Parser.error_msg msg) p DisplayTypes.DiagnosticsKind.DKParserError
+			handle_diagnostics (Parser.error_msg msg) p DisplayTypes.DiagnosticsKind.DKParserError
 		| Lexer.Error(msg,p) ->
-			handle_diagnostics global (Lexer.error_msg msg) p DisplayTypes.DiagnosticsKind.DKParserError
+			handle_diagnostics (Lexer.error_msg msg) p DisplayTypes.DiagnosticsKind.DKParserError
 		end
 	| _ ->
 		f arg
@@ -503,6 +514,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;
 	) ();
@@ -510,7 +522,7 @@ let do_type tctx config_macros classes =
 	(* If we are trying to find references, let's syntax-explore everything we know to check for the
 		identifier we are interested in. We then type only those modules that contain the identifier. *)
 	begin match !CompilationServer.instance,com.display.dms_kind with
-		| Some cs,DMUsage _ -> FindReferences.find_possible_references tctx cs;
+		| Some cs,(DMUsage _ | DMImplementation) -> FindReferences.find_possible_references tctx cs;
 		| _ -> ()
 	end;
 	t()
@@ -646,7 +658,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 ->
@@ -677,7 +690,7 @@ let rec process_params create pl =
 
 and init ctx =
 	let usage = Printf.sprintf
-		"Haxe Compiler %s - (C)2005-2019 Haxe Foundation\nUsage: haxe%s <target> [options] [hxml files...]\n"
+		"Haxe Compiler %s - (C)2005-2020 Haxe Foundation\nUsage: haxe%s <target> [options] [hxml files...]\n"
 		(s_version true) (if Sys.os_type = "Win32" then ".exe" else "")
 	in
 	let com = ctx.com in
@@ -717,11 +730,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;
@@ -842,18 +850,18 @@ try
 				_ -> raise (Arg.Bad "Invalid SWF header format, expected width:height:fps[:color]")
 		),"<header>","define SWF header (width:height:fps:color)");
 		("Target-specific",["--flash-strict"],[], define Define.FlashStrict, "","more type strict flash API");
-		("Target-specific",[],["--swf-lib";"-swf-lib"],Arg.String (fun file ->
+		("Target-specific",["--swf-lib"],["-swf-lib"],Arg.String (fun file ->
 			process_libs(); (* linked swf order matters, and lib might reference swf as well *)
 			add_native_lib file false;
 		),"<file>","add the SWF library to the compiled SWF");
 		(* FIXME: replace with -D define *)
-		("Target-specific",[],["--swf-lib-extern";"-swf-lib-extern"],Arg.String (fun file ->
+		("Target-specific",["--swf-lib-extern"],["-swf-lib-extern"],Arg.String (fun file ->
 			add_native_lib file true;
 		),"<file>","use the SWF library for type checking");
-		("Target-specific",[],["--java-lib";"-java-lib"],Arg.String (fun file ->
+		("Target-specific",["--java-lib"],["-java-lib"],Arg.String (fun file ->
 			add_native_lib file false;
 		),"<file>","add an external JAR or class directory library");
-		("Target-specific",[],["--net-lib";"-net-lib"],Arg.String (fun file ->
+		("Target-specific",["--net-lib"],["-net-lib"],Arg.String (fun file ->
 			add_native_lib file false;
 		),"<file>[@std]","add an external .NET DLL file");
 		("Target-specific",["--net-std"],["-net-std"],Arg.String (fun file ->
@@ -938,7 +946,8 @@ 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
@@ -1198,7 +1207,11 @@ with
 	| Parser.SyntaxCompletion(kind,subj) ->
 		DisplayOutput.handle_syntax_completion com kind subj;
 		error ctx ("Error: No completion point was found") null_pos
-	| DisplayException(ModuleSymbols s | Diagnostics s | Statistics s | Metadata s) ->
+	| DisplayException(DisplayDiagnostics dctx) ->
+		let s = Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics dctx) in
+		DisplayPosition.display_position#reset;
+		raise (DisplayOutput.Completion s)
+	| DisplayException(ModuleSymbols s | Statistics s | Metadata s) ->
 		DisplayPosition.display_position#reset;
 		raise (DisplayOutput.Completion s)
 	| EvalExceptions.Sys_exit i | Hlinterp.Sys_exit i ->

+ 14 - 15
src/compiler/server.ml

@@ -38,7 +38,7 @@ let s_version with_build =
 let check_display_flush ctx f_otherwise = match ctx.com.json_out with
 	| None ->
 		begin match ctx.com.display.dms_kind with
-		| DMDiagnostics global->
+		| DMDiagnostics _->
 			List.iter (fun msg ->
 				let msg,p,kind = match msg with
 					| CMInfo(msg,p) -> msg,p,DisplayTypes.DiagnosticsSeverity.Information
@@ -47,7 +47,7 @@ let check_display_flush ctx f_otherwise = match ctx.com.json_out with
 				in
 				add_diagnostics_message ctx.com msg p DisplayTypes.DiagnosticsKind.DKCompilerError kind
 			) (List.rev ctx.messages);
-			raise (Completion (Diagnostics.print ctx.com global))
+			raise (Completion (Diagnostics.print ctx.com))
 		| _ ->
 			f_otherwise ()
 		end
@@ -142,21 +142,28 @@ let parse_file cs com file p =
 			try
 				let cfile = cc#find_file ffile in
 				if cfile.c_time <> ftime then raise Not_found;
-				Parser.ParseSuccess(cfile.c_package,cfile.c_decls)
+				Parser.ParseSuccess((cfile.c_package,cfile.c_decls),false,cfile.c_pdi)
 			with Not_found ->
 				let parse_result = TypeloadParse.parse_file com file p in
 				let info,is_unusual = match parse_result with
 					| ParseError(_,_,_) -> "not cached, has parse error",true
-					| ParseDisplayFile _ -> "not cached, is display file",true
-					| ParseSuccess data ->
-						begin try
+					| ParseSuccess(data,is_display_file,pdi) ->
+						if is_display_file then begin
+							if pdi.pd_errors <> [] then
+								"not cached, is display file with parse errors",true
+							else if com.display.dms_per_file then begin
+								cc#cache_file ffile ftime data pdi;
+								"cached, is intact display file",true
+							end else
+								"not cached, is display file",true
+						end else begin try
 							(* We assume that when not in display mode it's okay to cache stuff that has #if display
 							checks. The reasoning is that non-display mode has more information than display mode. *)
 							if not com.display.dms_display then raise Not_found;
 							let ident = Hashtbl.find Parser.special_identifier_files ffile in
 							Printf.sprintf "not cached, using \"%s\" define" ident,true
 						with Not_found ->
-							cc#cache_file ffile ftime data;
+							cc#cache_file ffile ftime data pdi;
 							"cached",false
 						end
 				in
@@ -498,14 +505,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;
-			cs#taint_modules file;
-		end;
 		try
 			if (Hashtbl.find sctx.class_paths sign) <> ctx.com.class_path then begin
 				ServerMessage.class_paths_changed ctx.com "";

+ 24 - 18
src/context/common.ml

@@ -153,14 +153,11 @@ 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;
 }
 
 type display_information = {
 	mutable unresolved_identifiers : (string * pos * (string * CompletionItem.t * int) list) list;
-	mutable interface_field_implementations : (tclass * tclass_field * tclass * tclass_field option) list;
 	mutable display_module_has_macro_defines : bool;
 }
 
@@ -215,6 +212,7 @@ type context = {
 	mutable error : string -> pos -> unit;
 	mutable info : string -> pos -> unit;
 	mutable warning : string -> pos -> unit;
+	mutable pending_messages : ((unit->unit)->unit) option;
 	mutable get_messages : unit -> compiler_message list;
 	mutable filter_messages : (compiler_message -> bool) -> unit;
 	mutable load_extern_type : (string * (path -> pos -> Ast.package option)) list; (* allow finding types which are not in sources *)
@@ -355,14 +353,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
@@ -443,14 +433,11 @@ let create version s_version args =
 		args = args;
 		shared = {
 			shared_display_information = {
-				import_positions = PMap.empty;
 				diagnostics_messages = [];
-				dead_blocks = Hashtbl.create 0;
 			}
 		};
 		display_information = {
 			unresolved_identifiers = [];
-			interface_field_implementations = [];
 			display_module_has_macro_defines = false;
 		};
 		sys_args = args;
@@ -510,8 +497,25 @@ let create version s_version args =
 		memory_marker = memory_marker;
 		parser_cache = Hashtbl.create 0;
 		json_out = None;
+		pending_messages = None;
 	}
 
+exception HoldMessages of exn * (unit->unit)
+
+let hold_messages com action =
+	let old_pending = com.pending_messages in
+	let messages = ref [] in
+	com.pending_messages <- Some (fun submit -> messages := submit :: !messages);
+	let submit_all() = List.iter (fun f -> f()) (List.rev !messages) in
+	let restore() = com.pending_messages <- old_pending; in
+	try
+		let result = action() in
+		restore();
+		result,submit_all
+	with err ->
+		restore();
+		raise (HoldMessages (err,submit_all))
+
 let log com str =
 	if com.verbose then com.print (str ^ "\n")
 
@@ -529,7 +533,6 @@ let clone com =
 		callbacks = new compiler_callbacks;
 		display_information = {
 			unresolved_identifiers = [];
-			interface_field_implementations = [];
 			display_module_has_macro_defines = false;
 		};
 		defines = {
@@ -832,9 +835,12 @@ let utf16_to_utf8 str =
 	loop 0;
 	Buffer.contents b
 
-let add_diagnostics_message com s p kind sev =
-	let di = com.shared.shared_display_information in
-	di.diagnostics_messages <- (s,p,kind,sev) :: di.diagnostics_messages
+let rec add_diagnostics_message com s p kind sev =
+	match com.pending_messages with
+	| Some add -> add (fun() -> add_diagnostics_message com s p kind sev)
+	| None ->
+		let di = com.shared.shared_display_information in
+		di.diagnostics_messages <- (s,p,kind,sev) :: di.diagnostics_messages
 
 open Printer
 

+ 3 - 2
src/context/compilationServer.ml

@@ -9,6 +9,7 @@ type cached_file = {
 	c_package : string list;
 	c_decls : type_decl list;
 	mutable c_module_name : string option;
+	mutable c_pdi : Parser.parser_display_information;
 }
 
 type cached_directory = {
@@ -33,8 +34,8 @@ class context_cache (index : int) = object(self)
 	method find_file key =
 		Hashtbl.find files key
 
-	method cache_file key time data =
-		Hashtbl.replace files key { c_time = time; c_package = fst data; c_decls = snd data; c_module_name = None }
+	method cache_file key time data pdi =
+		Hashtbl.replace files key { c_time = time; c_package = fst data; c_decls = snd data; c_module_name = None; c_pdi = pdi }
 
 	method remove_file key =
 		if Hashtbl.mem files key then begin

+ 66 - 123
src/context/display/diagnostics.ml

@@ -5,17 +5,15 @@ open Typecore
 open Common
 open Display
 open DisplayTypes.DisplayMode
-
-type diagnostics_context = {
-	com : Common.context;
-	mutable removable_code : (string * pos * pos) list;
-}
-
 open DisplayTypes
+open DisplayException
+open DiagnosticsTypes
 
 let add_removable_code ctx s p prange =
 	ctx.removable_code <- (s,p,prange) :: ctx.removable_code
 
+let is_diagnostics_run p = DiagnosticsPrinter.is_diagnostics_file p.pfile
+
 let find_unused_variables com e =
 	let vars = Hashtbl.create 0 in
 	let pmin_map = Hashtbl.create 0 in
@@ -93,137 +91,82 @@ let check_other_things com e =
 	in
 	loop true e
 
-let prepare_field dctx cf = match cf.cf_expr with
+let prepare_field dctx com cf = match cf.cf_expr with
 	| None -> ()
 	| Some e ->
 		find_unused_variables dctx e;
-		check_other_things dctx.com e;
-		DeprecationCheck.run_on_expr dctx.com e
+		check_other_things com e;
+		DeprecationCheck.run_on_expr com e
 
-let prepare com global =
+let prepare com =
 	let dctx = {
 		removable_code = [];
-		com = com;
+		import_positions = PMap.empty;
+		dead_blocks = Hashtbl.create 0;
+		diagnostics_messages = [];
+		unresolved_identifiers = [];
 	} in
 	List.iter (function
-		| TClassDecl c when global || DisplayPosition.display_position#is_in_file c.cl_pos.pfile ->
-			List.iter (prepare_field dctx) c.cl_ordered_fields;
-			List.iter (prepare_field dctx) c.cl_ordered_statics;
-			(match c.cl_constructor with None -> () | Some cf -> prepare_field dctx cf);
+		| TClassDecl c when DiagnosticsPrinter.is_diagnostics_file c.cl_pos.pfile ->
+			List.iter (prepare_field dctx com) c.cl_ordered_fields;
+			List.iter (prepare_field dctx com) c.cl_ordered_statics;
+			(match c.cl_constructor with None -> () | Some cf -> prepare_field dctx com cf);
 		| _ ->
 			()
 	) com.types;
+	let handle_dead_blocks com = match com.cache with
+		| Some cc ->
+			let macro_defines = adapt_defines_to_macro_context com.defines in
+			let display_defines = {macro_defines with values = PMap.add "display" "1" macro_defines.values} in
+			let is_true defines e =
+				ParserEntry.is_true (ParserEntry.eval defines e)
+			in
+			Hashtbl.iter (fun file cfile ->
+				if DisplayPosition.display_position#is_in_file file then begin
+					let dead_blocks = cfile.CompilationServer.c_pdi.pd_dead_blocks in
+					let dead_blocks = List.filter (fun (_,e) -> not (is_true display_defines e)) dead_blocks in
+					try
+						let dead_blocks2 = Hashtbl.find dctx.dead_blocks file in
+						(* Intersect *)
+						let dead_blocks2 = List.filter (fun (p,_) -> List.mem_assoc p dead_blocks) dead_blocks2 in
+						Hashtbl.replace dctx.dead_blocks file dead_blocks2
+					with Not_found ->
+						Hashtbl.add dctx.dead_blocks file dead_blocks
+				end
+			) cc#get_files
+		| None ->
+			()
+	in
+	handle_dead_blocks com;
+	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;
+	(* We do this at the end because some of the prepare functions might add information to the common context. *)
+	dctx.diagnostics_messages <- com.shared.shared_display_information.diagnostics_messages;
+	dctx.unresolved_identifiers <- com.display_information.unresolved_identifiers;
 	dctx
 
-let is_diagnostics_run p = match (!Parser.display_mode) with
-	| DMDiagnostics true -> true
-	| DMDiagnostics false -> DisplayPosition.display_position#is_in_file p.pfile
-	| _ -> false
-
 let secure_generated_code ctx e =
 	if is_diagnostics_run e.epos then mk (TMeta((Meta.Extern,[],e.epos),e)) e.etype e.epos else e
 
-module Printer = struct
-	open Json
-	open DiagnosticsKind
-	open DisplayTypes
-
-	type t = DiagnosticsKind.t * pos
-
-	module UnresolvedIdentifierSuggestion = struct
-		type t =
-			| UISImport
-			| UISTypo
-
-		let to_int = function
-			| UISImport -> 0
-			| UISTypo -> 1
-	end
-
-	open UnresolvedIdentifierSuggestion
-	open CompletionItem
-	open CompletionModuleType
-
-	let print_diagnostics dctx com global =
-		let diag = Hashtbl.create 0 in
-		let add dk p sev args =
-			let file = if p = null_pos then p.pfile else Path.get_real_path p.pfile in
-			let diag = try
-				Hashtbl.find diag file
-			with Not_found ->
-				let d = Hashtbl.create 0 in
-				Hashtbl.add diag file d;
-				d
-			in
-			if not (Hashtbl.mem diag p) then
-				Hashtbl.add diag p (dk,p,sev,args)
-		in
-		let add dk p sev args =
-			if global || p = null_pos || DisplayPosition.display_position#is_in_file p.pfile then add dk p sev args
-		in
-		List.iter (fun (s,p,suggestions) ->
-			let suggestions = ExtList.List.filter_map (fun (s,item,r) ->
-				match item.ci_kind with
-				| ITType(t,_) when r = 0 ->
-					let path = if t.module_name = t.name then (t.pack,t.name) else (t.pack @ [t.module_name],t.name) in
-					Some (JObject [
-						"kind",JInt (to_int UISImport);
-						"name",JString (s_type_path path);
-					])
-				| _ when r = 0 ->
-					(* TODO !!! *)
-					None
-				| _ ->
-					Some (JObject [
-						"kind",JInt (to_int UISTypo);
-						"name",JString s;
-					])
-			) suggestions in
-			add DKUnresolvedIdentifier p DiagnosticsSeverity.Error (JArray suggestions);
-		) com.display_information.unresolved_identifiers;
-		PMap.iter (fun p (r,_) ->
-			if not !r then add DKUnusedImport p DiagnosticsSeverity.Warning (JArray [])
-		) com.shared.shared_display_information.import_positions;
-		List.iter (fun (s,p,kind,sev) ->
-			add kind p sev (JString s)
-		) (List.rev com.shared.shared_display_information.diagnostics_messages);
-		List.iter (fun (s,p,prange) ->
-			add DKRemovableCode p DiagnosticsSeverity.Warning (JObject ["description",JString s;"range",if prange = null_pos then JNull else Genjson.generate_pos_as_range prange])
-		) dctx.removable_code;
-		Hashtbl.iter (fun p s ->
-			add DKDeprecationWarning p DiagnosticsSeverity.Warning (JString s);
-		) DeprecationCheck.warned_positions;
-		Hashtbl.iter (fun file ranges ->
-			List.iter (fun (p,e) ->
-				let jo = JObject [
-					"expr",JObject [
-						"string",JString (Ast.Printer.s_expr e)
-					]
-				] in
-				add DKInactiveBlock p DiagnosticsSeverity.Hint jo
-			) ranges
-		) com.shared.shared_display_information.dead_blocks;
-		let jl = Hashtbl.fold (fun file diag acc ->
-			let jl = Hashtbl.fold (fun _ (dk,p,sev,jargs) acc ->
-				(JObject [
-					"kind",JInt (DiagnosticsKind.to_int dk);
-					"severity",JInt (DiagnosticsSeverity.to_int sev);
-					"range",Genjson.generate_pos_as_range p;
-					"args",jargs
-				]) :: acc
-			) diag [] in
-			(JObject [
-				"file",if file = "?" then JNull else JString file;
-				"diagnostics",JArray jl
-			]) :: acc
-		) diag [] in
-		let js = JArray jl in
-		string_of_json js
-end
-
-let print com global =
-	let dctx = prepare com global in
-	Printer.print_diagnostics dctx com global
+let print com =
+	let dctx = prepare com in
+	Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics dctx)
 
-let run com global =
-	DisplayException.raise_diagnostics (print com global)
+let run com =
+	let dctx = prepare com in
+	DisplayException.raise_diagnostics dctx

+ 105 - 0
src/context/display/diagnosticsPrinter.ml

@@ -0,0 +1,105 @@
+open Globals
+open Json
+open DisplayTypes
+open DiagnosticsKind
+open DisplayTypes
+open DiagnosticsTypes
+
+type t = DiagnosticsKind.t * pos
+
+let is_diagnostics_file file =
+	let file = Path.unique_full_path file in
+	match (!Parser.display_mode) with
+	| DMDiagnostics [] -> true
+	| DMDiagnostics files -> List.exists (fun file' -> file = file') files
+	| _ -> false
+
+module UnresolvedIdentifierSuggestion = struct
+	type t =
+		| UISImport
+		| UISTypo
+
+	let to_int = function
+		| UISImport -> 0
+		| UISTypo -> 1
+end
+
+open UnresolvedIdentifierSuggestion
+open CompletionItem
+open CompletionModuleType
+
+let json_of_diagnostics dctx =
+	let diag = Hashtbl.create 0 in
+	let add dk p sev args =
+		let file = if p = null_pos then p.pfile else Path.get_real_path p.pfile in
+		let diag = try
+			Hashtbl.find diag file
+		with Not_found ->
+			let d = Hashtbl.create 0 in
+			Hashtbl.add diag file d;
+			d
+		in
+		if not (Hashtbl.mem diag p) then
+			Hashtbl.add diag p (dk,p,sev,args)
+	in
+	let add dk p sev args =
+		if p = null_pos || is_diagnostics_file p.pfile then add dk p sev args
+	in
+	List.iter (fun (s,p,suggestions) ->
+		let suggestions = ExtList.List.filter_map (fun (s,item,r) ->
+			match item.ci_kind with
+			| ITType(t,_) when r = 0 ->
+				let path = if t.module_name = t.name then (t.pack,t.name) else (t.pack @ [t.module_name],t.name) in
+				Some (JObject [
+					"kind",JInt (to_int UISImport);
+					"name",JString (s_type_path path);
+				])
+			| _ when r = 0 ->
+				(* TODO !!! *)
+				None
+			| _ ->
+				Some (JObject [
+					"kind",JInt (to_int UISTypo);
+					"name",JString s;
+				])
+		) suggestions in
+		add DKUnresolvedIdentifier p DiagnosticsSeverity.Error (JArray suggestions);
+	) dctx.unresolved_identifiers;
+	PMap.iter (fun p r ->
+		if not !r then add DKUnusedImport p DiagnosticsSeverity.Warning (JArray [])
+	) dctx.import_positions;
+	List.iter (fun (s,p,kind,sev) ->
+		add kind p sev (JString s)
+	) (List.rev dctx.diagnostics_messages);
+	List.iter (fun (s,p,prange) ->
+		add DKRemovableCode p DiagnosticsSeverity.Warning (JObject ["description",JString s;"range",if prange = null_pos then JNull else Genjson.generate_pos_as_range prange])
+	) dctx.removable_code;
+	Hashtbl.iter (fun p s ->
+		add DKDeprecationWarning p DiagnosticsSeverity.Warning (JString s);
+	) DeprecationCheck.warned_positions;
+	Hashtbl.iter (fun file ranges ->
+		List.iter (fun (p,e) ->
+			let jo = JObject [
+				"expr",JObject [
+					"string",JString (Ast.Printer.s_expr e)
+				]
+			] in
+			add DKInactiveBlock p DiagnosticsSeverity.Hint jo
+		) ranges
+	) dctx.dead_blocks;
+	let jl = Hashtbl.fold (fun file diag acc ->
+		let jl = Hashtbl.fold (fun _ (dk,p,sev,jargs) acc ->
+			(JObject [
+				"kind",JInt (DiagnosticsKind.to_int dk);
+				"severity",JInt (DiagnosticsSeverity.to_int sev);
+				"range",Genjson.generate_pos_as_range p;
+				"args",jargs
+			]) :: acc
+		) diag [] in
+		(JObject [
+			"file",if file = "?" then JNull else JString file;
+			"diagnostics",JArray jl
+		]) :: acc
+	) diag [] in
+	let js = JArray jl in
+	js

+ 10 - 0
src/context/display/diagnosticsTypes.ml

@@ -0,0 +1,10 @@
+open Globals
+open Ast
+
+type diagnostics_context = {
+	mutable removable_code : (string * pos * pos) list;
+	mutable import_positions : (pos,bool ref) PMap.t;
+	mutable dead_blocks : (string,(pos * expr) list) Hashtbl.t;
+	mutable unresolved_identifiers : (string * pos * (string * CompletionItem.t * int) list) list;
+	mutable diagnostics_messages : (string * pos * DisplayTypes.DiagnosticsKind.t * DisplayTypes.DiagnosticsSeverity.t) list;
+}

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

@@ -22,7 +22,7 @@ let parse_module ctx m p =
 	display_position#run_outside (fun () -> TypeloadParse.parse_module ctx m p)
 
 module ReferencePosition = struct
-	let reference_position = ref ("",null_pos,KVar)
+	let reference_position = ref ("",null_pos,SKOther)
 	let set (s,p,k) = reference_position := (s,{p with pfile = Path.unique_full_path p.pfile},k)
 	let get () = !reference_position
 end
@@ -248,7 +248,7 @@ module ExprPreprocessing = struct
 
 
 	let process_expr com e = match com.display.dms_kind with
-		| DMDefinition | DMTypeDefinition | DMUsage _ | DMHover | DMDefault -> find_before_pos com.display.dms_kind e
+		| DMDefinition | DMTypeDefinition | DMUsage _ | DMImplementation | DMHover | DMDefault -> find_before_pos com.display.dms_kind e
 		| DMSignature -> find_display_call e
 		| _ -> e
 end

+ 13 - 7
src/context/display/displayEmitter.ml

@@ -13,6 +13,12 @@ open Common
 open Display
 open DisplayPosition
 
+let symbol_of_module_type = function
+	| TClassDecl c -> SKClass c
+	| TEnumDecl en -> SKEnum en
+	| TTypeDecl td -> SKTypedef td
+	| TAbstractDecl a -> SKAbstract a
+
 let display_module_type ctx mt p = match ctx.com.display.dms_kind with
 	| DMDefinition | DMTypeDefinition ->
 		begin match mt with
@@ -22,9 +28,9 @@ let display_module_type ctx mt p = match ctx.com.display.dms_kind with
 		| _ ->
 			raise_positions [(t_infos mt).mt_name_pos];
 		end
-	| DMUsage _ ->
+	| DMUsage _ | DMImplementation ->
 		let infos = t_infos mt in
-		ReferencePosition.set (snd infos.mt_path,infos.mt_name_pos,KModuleType)
+		ReferencePosition.set (snd infos.mt_path,infos.mt_name_pos,symbol_of_module_type mt)
 	| DMHover ->
 		let t = type_of_module_type mt in
 		let ct = CompletionType.from_type (get_import_status ctx) t in
@@ -81,7 +87,7 @@ let raise_position_of_type t =
 let display_variable ctx v p = match ctx.com.display.dms_kind with
 	| DMDefinition -> raise_positions [v.v_pos]
 	| DMTypeDefinition -> raise_position_of_type v.v_type
-	| DMUsage _ -> ReferencePosition.set (v.v_name,v.v_pos,KVar)
+	| DMUsage _ -> ReferencePosition.set (v.v_name,v.v_pos,SKVariable v)
 	| DMHover ->
 		let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta v.v_meta) v.v_type in
 		raise_hover (make_ci_local v (v.v_type,ct)) None p
@@ -90,13 +96,13 @@ let display_variable ctx v p = match ctx.com.display.dms_kind with
 let display_field ctx origin scope cf p = match ctx.com.display.dms_kind with
 	| DMDefinition -> raise_positions [cf.cf_name_pos]
 	| DMTypeDefinition -> raise_position_of_type cf.cf_type
-	| DMUsage _ ->
+	| DMUsage _ | DMImplementation ->
 		let name,kind = match cf.cf_name,origin with
 			| "new",(Self (TClassDecl c) | Parent(TClassDecl c)) ->
 				(* For constructors, we care about the class name so we don't end up looking for "new". *)
-				snd c.cl_path,KConstructor
+				snd c.cl_path,SKConstructor cf
 			| _ ->
-				cf.cf_name,KClassField
+				cf.cf_name,SKField cf
 		in
 		ReferencePosition.set (name,cf.cf_name_pos,kind)
 	| DMHover ->
@@ -119,7 +125,7 @@ let maybe_display_field ctx origin scope cf p =
 let display_enum_field ctx en ef p = match ctx.com.display.dms_kind with
 	| DMDefinition -> raise_positions [ef.ef_name_pos]
 	| DMTypeDefinition -> raise_position_of_type ef.ef_type
-	| DMUsage _ -> ReferencePosition.set (ef.ef_name,ef.ef_name_pos,KEnumField)
+	| DMUsage _ -> ReferencePosition.set (ef.ef_name,ef.ef_name_pos,SKEnumField ef)
 	| DMHover ->
 		let ct = CompletionType.from_type (get_import_status ctx) ef.ef_type in
 		raise_hover (make_ci_enum_field (CompletionEnumField.make ef (Self (TEnumDecl en)) true) (ef.ef_type,ct)) None p

+ 67 - 37
src/context/display/displayException.ml

@@ -22,7 +22,7 @@ type signature_kind =
 	| SKArrayAccess
 
 type kind =
-	| Diagnostics of string
+	| DisplayDiagnostics of DiagnosticsTypes.diagnostics_context
 	| Statistics of string
 	| ModuleSymbols of string
 	| Metadata of string
@@ -34,7 +34,7 @@ type kind =
 
 exception DisplayException of kind
 
-let raise_diagnostics s = raise (DisplayException(Diagnostics s))
+let raise_diagnostics s = raise (DisplayException(DisplayDiagnostics s))
 let raise_statistics s = raise (DisplayException(Statistics s))
 let raise_module_symbols s = raise (DisplayException(ModuleSymbols s))
 let raise_metadata s = raise (DisplayException(Metadata s))
@@ -50,51 +50,80 @@ let last_completion_pos = ref None
 let max_completion_items = ref 0
 
 let filter_somehow ctx items kind subj =
-	let ret = DynArray.create () in
-	let acc_types = DynArray.create () in
 	let subject = match subj.s_name with
 		| None -> ""
 		| Some name-> String.lowercase name
 	in
-	let subject_matches s =
-		let rec loop i o =
-			if i < String.length subject then begin
-				let o = String.index_from s o subject.[i] in
-				loop (i + 1) o
+	let subject_length = String.length subject in
+	let determine_cost s =
+		let get_initial_cost o =
+			if o = 0 then
+				0 (* Term starts with subject - perfect *)
+			else begin
+				(* Consider `.` as anchors and determine distance from closest one. Penalize starting distance by factor 2. *)
+				try
+					let last_anchor = String.rindex_from s o '.' in
+					(o - (last_anchor + 1)) * 2
+				with Not_found ->
+					o * 2
 			end
 		in
-		try
-			loop 0 0;
-			true
-		with Not_found ->
-			false
+		let index_from o c =
+			let rec loop o cost =
+				let c' = s.[o] in
+				if c' = c then
+					o,cost
+				else
+					loop (o + 1) (cost + 3) (* Holes are bad, penalize by 3. *)
+			in
+			loop o 0
+		in
+		let rec loop i o cost =
+			if i < subject_length then begin
+				let o',new_cost = index_from o subject.[i] in
+				loop (i + 1) o' (cost + new_cost)
+			end else
+				cost + (if o = String.length s - 1 then 0 else 1) (* Slightly penalize for not-exact matches. *)
+		in
+		if subject_length = 0 then
+			0
+		else try
+			let o = String.index s subject.[0] in
+			loop 1 o (get_initial_cost o);
+		with Not_found | Invalid_argument _ ->
+			-1
 	in
-	let rec loop items index =
+	let rec loop acc items index =
 		match items with
-		| _ when DynArray.length ret >= !max_completion_items ->
-			()
 		| item :: items ->
 			let name = String.lowercase (get_filter_name item) in
-			if subject_matches name then begin
-				(* Treat types with lowest priority. The assumption is that they are the only kind
-				   which actually causes the limit to be hit, so we show everything else and then
-				   fill in types. *)
-				match item.ci_kind with
-				| ITType _ ->
-					if DynArray.length ret + DynArray.length acc_types < !max_completion_items then
-						DynArray.add acc_types (item,index);
-				| _ ->
-					DynArray.add ret (CompletionItem.to_json ctx (Some index) item);
-			end;
-			loop items (index + 1)
+			let cost = determine_cost name in
+			let acc = if cost >= 0 then
+				(item,index,cost) :: acc
+			else
+				acc
+			in
+			loop acc items (index + 1)
 		| [] ->
-			()
+			acc
 	in
-	loop items 0;
-	DynArray.iter (fun (item,index) ->
-		if DynArray.length ret < !max_completion_items then
+	let acc = loop [] items 0 in
+	let acc = if subject_length = 0 then
+		List.rev acc
+	else
+		List.sort (fun (_,_,cost1) (_,_,cost2) ->
+			compare cost1 cost2
+		) acc
+	in
+	let ret = DynArray.create () in
+	let rec loop acc_types = match acc_types with
+		| (item,index,_) :: acc_types when DynArray.length ret < !max_completion_items ->
 			DynArray.add ret (CompletionItem.to_json ctx (Some index) item);
-	) acc_types;
+			loop acc_types
+		| _ ->
+			()
+	in
+	loop acc;
 	DynArray.to_list ret,DynArray.length ret
 
 let patch_completion_subject subj =
@@ -143,18 +172,19 @@ let fields_to_json ctx fields kind subj =
 
 let to_json ctx de =
 	match de with
-	| Diagnostics _
 	| Statistics _
 	| ModuleSymbols _
 	| Metadata _ -> assert false
 	| DisplaySignatures None ->
 		jnull
+	| DisplayDiagnostics dctx ->
+		DiagnosticsPrinter.json_of_diagnostics dctx
 	| DisplaySignatures Some(sigs,isig,iarg,kind) ->
 		(* We always want full info for signatures *)
 		let ctx = Genjson.create_context GMFull in
 		let fsig ((_,signature),doc) =
 			let fl = CompletionType.generate_function' ctx signature in
-			let fl = (match doc with None -> fl | Some s -> ("documentation",jstring s) :: fl) in
+			let fl = (match doc with None -> fl | Some d -> ("documentation",jstring (gen_doc_text d)) :: fl) in
 			jobject fl
 		in
 		let sigkind = match kind with
@@ -196,7 +226,7 @@ let to_json ctx de =
 			| _ -> jnull
 		in
 		jobject [
-			"documentation",jopt jstring (CompletionItem.get_documentation hover.hitem);
+			"documentation",jopt jstring (gen_doc_text_opt (CompletionItem.get_documentation hover.hitem));
 			"range",generate_pos_as_range hover.hpos;
 			"item",CompletionItem.to_json ctx None hover.hitem;
 			"expected",expected;

+ 1 - 1
src/context/display/displayFields.ml

@@ -265,7 +265,7 @@ let collect ctx e_ast e dk with_type p =
 	let items = match fst e_ast with
 		| EConst(String(s,_)) when String.length s = 1 ->
 			let cf = mk_field "code" ctx.t.tint e.epos null_pos in
-			cf.cf_doc <- Some "The character code of this character (inlined at compile-time).";
+			cf.cf_doc <- doc_from_string "The character code of this character (inlined at compile-time).";
 			cf.cf_kind <- Var { v_read = AccNormal; v_write = AccNever };
 			let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) cf.cf_type in
 			let item = make_ci_class_field (CompletionClassField.make cf CFSMember BuiltIn true) (cf.cf_type,ct) in

+ 6 - 3
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;
@@ -104,7 +102,7 @@ let handler =
 				];
 				"protocolVersion",jobject [
 					"major",jint 0;
-					"minor",jint 3;
+					"minor",jint 4;
 					"patch",jint 0;
 				]
 			])
@@ -128,6 +126,11 @@ let handler =
 			hctx.display#set_display_file false true;
 			hctx.display#enable_display DMDefinition;
 		);
+		"display/implementation", (fun hctx ->
+			Common.define hctx.com Define.NoCOpt;
+			hctx.display#set_display_file false true;
+			hctx.display#enable_display (DMImplementation);
+		);
 		"display/typeDefinition", (fun hctx ->
 			Common.define hctx.com Define.NoCOpt;
 			hctx.display#set_display_file false true;

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

@@ -0,0 +1,160 @@
+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 context_init = new TypeloadFields.context_init in
+	let ctx,cctx = TypeloadFields.create_class_context ctx c context_init cf.cf_pos in
+	let cff = TypeloadFields.transform_field (ctx,cctx) c cff (ref []) (pos cff.cff_name) in
+	let ctx,fctx = TypeloadFields.create_field_context (ctx,cctx) c cff in
+	let cf = TypeloadFields.init_field (ctx,cctx,fctx) cff in
+	flush_pass ctx PTypeField "check_display_field";
+	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
+			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
+			TypeloadParse.PdiHandler.handle_pdi ctx.com cfile.c_pdi;
+			(* 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 ->
+			if ctx.com.display.dms_display 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 ->
+		()

+ 6 - 4
src/context/display/displayToplevel.ml

@@ -189,7 +189,7 @@ let pack_contains pack1 pack2 =
 let is_pack_visible pack =
 	not (List.exists (fun s -> String.length s > 0 && s.[0] = '_') pack)
 
-let collect ctx tk with_type =
+let collect ctx tk with_type sort =
 	let t = Timer.timer ["display";"toplevel"] in
 	let cctx = CollectionContext.create ctx in
 	let curpack = fst ctx.curclass.cl_path in
@@ -471,8 +471,10 @@ let collect ctx tk with_type =
 	let l = DynArray.to_list cctx.items in
 	let l = if is_legacy_completion then
 		List.sort (fun item1 item2 -> compare (get_name item1) (get_name item2)) l
-	else
+	else if sort then
 		Display.sort_fields l with_type tk
+	else
+		l
 	in
 	t();
 	l
@@ -482,12 +484,12 @@ let collect_and_raise ctx tk with_type cr (name,pname) pinsert =
 	| Some p' when pname.pmin = p'.pmin ->
 		Array.to_list (!DisplayException.last_completion_result)
 	| _ ->
-		collect ctx tk with_type
+		collect ctx tk with_type (name = "")
 	in
 	DisplayException.raise_fields fields cr (make_subject (Some name) ~start_pos:(Some pname) pinsert)
 
 let handle_unresolved_identifier ctx i p only_types =
-	let l = collect ctx (if only_types then TKType else TKExpr p) NoValue in
+	let l = collect ctx (if only_types then TKType else TKExpr p) NoValue false in
 	let cl = List.map (fun it ->
 		let s = CompletionItem.get_name it in
 		let i = StringError.levenshtein i s in

+ 21 - 11
src/context/display/documentSymbols.ml

@@ -1,5 +1,5 @@
 open Ast
-
+open Globals
 open DisplayTypes.SymbolKind
 
 let collect_module_symbols with_locals (pack,decls) =
@@ -56,26 +56,36 @@ let collect_module_symbols with_locals (pack,decls) =
 			add_field Property;
 			if with_locals then expr_opt field_parent eo
 	in
-	List.iter (fun (td,p) -> match td with
+	List.iter (fun (td,p) ->
+		let add_type d kind =
+			let module_name = Path.module_name_of_file p.pfile in
+			let pack = String.concat "." pack in
+			let type_name = fst d.d_name in
+			let primary_type = type_name = module_name in
+			let type_path = if primary_type then pack else pack ^ "." ^ module_name in
+			add type_name kind p type_path (is_deprecated d.d_meta);
+			if type_path = "" then type_name else type_path ^ "." ^ type_name
+		in
+		match td with
 		| EImport _ | EUsing _ ->
-			() (* TODO: Can we do anything with these? *)
+			()
 		| EClass d ->
-			add (fst d.d_name) (if List.mem HInterface d.d_flags then Interface else Class) p "" (is_deprecated d.d_meta);
-			List.iter (field (fst d.d_name)) d.d_data
+			let parent = add_type d (if List.mem HInterface d.d_flags then Interface else Class) in
+			List.iter (field parent) d.d_data
 		| EEnum d ->
-			add (fst d.d_name) Enum p "" (is_deprecated d.d_meta);
+			let parent = add_type d Enum in
 			List.iter (fun ef ->
-				add (fst ef.ec_name) Method ef.ec_pos (fst d.d_name) (is_deprecated ef.ec_meta)
+				add (fst ef.ec_name) Method ef.ec_pos parent (is_deprecated ef.ec_meta)
 			) d.d_data
 		| ETypedef d ->
-			add (fst d.d_name) Typedef p "" (is_deprecated d.d_meta);
+			let parent = add_type d Typedef in
 			(match d.d_data with
 			| CTAnonymous fields,_ ->
-				List.iter (field (fst d.d_name)) fields
+				List.iter (field parent) fields
 			| _ -> ())
 		| EAbstract d ->
-			add (fst d.d_name) Abstract p "" (is_deprecated d.d_meta);
-			List.iter (field (fst d.d_name)) d.d_data
+			let parent = add_type d Abstract in
+			List.iter (field parent) d.d_data
 	) decls;
 	l
 

+ 38 - 166
src/context/display/findReferences.ml

@@ -6,173 +6,13 @@ open Typecore
 open CompilationServer
 open ImportHandling
 
-let find_possible_references kind name (pack,decls) =
-	(* Employ some heuristics: We know what kind of symbol we are looking for, so let's
-	   filter where we can. *)
-	let check kind' name' =
-		if name = name' then match kind',kind with
-			| KIdent,_
-			| KAnyField,(KAnyField | KClassField | KEnumField)
-			| KClassField,KClassField
-			| KEnumField,KEnumField
-			| KModuleType,KModuleType
-			| KConstructor,(KConstructor | KModuleType) ->
-				raise Exit
-			| _ ->
-				()
-	in
-	let rec type_path kind path =
-		check KModuleType path.tname;
-		Option.may (check KModuleType) path.tsub;
-		List.iter (function
-			| TPType th -> type_hint th
-			| TPExpr e -> expr e
-		) path.tparams
-	and type_hint th = match fst th with
-		| CTPath path -> type_path KModuleType path
-		| CTParent th | CTOptional th | CTNamed(_,th) -> type_hint th
-		| CTFunction(thl,th) ->
-			List.iter type_hint thl;
-			type_hint th;
-		| CTAnonymous cffl ->
-			List.iter field cffl
-		| CTExtend(tl,cffl) ->
-			List.iter (fun (path,_) -> type_path KModuleType path) tl;
-			List.iter field cffl;
-		| CTIntersection tl ->
-			List.iter type_hint tl
-	and type_param tp =
-		List.iter type_param tp.tp_params;
-		Option.may type_hint tp.tp_constraints
-	and expr (e,p) =
-		begin match e with
-		| EConst(Ident s) ->
-			check KIdent s
-		| EField(e1,s) ->
-			expr e1;
-			check KAnyField s;
-		| EVars vl ->
-			List.iter (fun (_,_,tho,eo) ->
-				Option.may type_hint tho;
-				expr_opt eo
-			) vl;
-		| ECast(e1,tho) ->
-			expr e1;
-			Option.may type_hint tho;
-		| ENew((path,_),el) ->
-			type_path KConstructor path;
-			List.iter expr el;
-		| EFunction(_,f) ->
-			func f
-		| ETry(e1,catches) ->
-			expr e1;
-			List.iter (fun (_,th,e,_) ->
-				type_hint th;
-				expr e
-			) catches;
-		| ECheckType(e1,th) ->
-			expr e1;
-			type_hint th;
-		| _ ->
-			iter_expr expr (e,p)
-		end
-	and expr_opt eo = match eo with
-		| None -> ()
-		| Some e -> expr e
-	and func f =
-		List.iter (fun ((s,p),_,_,tho,eo) ->
-			Option.may type_hint tho;
-			expr_opt eo
-		) f.f_args;
-		List.iter type_param f.f_params;
-		Option.may type_hint f.f_type;
-		expr_opt f.f_expr
-	and field cff =
-		check KClassField (fst cff.cff_name);
-		match cff.cff_kind with
-		| FVar(tho,eo) ->
-			Option.may type_hint tho;
-			expr_opt eo
-		| FFun f ->
-			func f
-		| FProp(_,_,tho,eo) ->
-			Option.may type_hint tho;
-			expr_opt eo
-	in
-	List.iter (fun (td,p) -> match td with
-		| EImport(path,_) | EUsing path ->
-			begin match fst (ImportHandling.convert_import_to_something_usable null_pos path) with
-			| IDKModule(_,s) -> check KModuleType s
-			| IDKSubType(_,s1,s2) ->
-				check KModuleType s1;
-				check KModuleType s2;
-			| IDKSubTypeField(_,s1,s2,s3) ->
-				check KModuleType s1;
-				check KModuleType s2;
-				check KAnyField s3;
-			| IDKModuleField(_,s1,s2) ->
-				check KModuleType s1;
-				check KAnyField s2;
-			| IDKPackage _ | IDK ->
-				()
-			end;
-		| EClass d ->
-			check KModuleType (fst d.d_name);
-			List.iter (function
-				| HExtends(path,_) | HImplements(path,_) -> type_path KModuleType path
-				| _ -> ()
-			) d.d_flags;
-			List.iter type_param d.d_params;
-			List.iter field d.d_data
-		| EEnum d ->
-			check KModuleType (fst d.d_name);
-			List.iter (fun ef ->
-				Option.may type_hint ef.ec_type;
-				check KEnumField (fst ef.ec_name);
-				List.iter type_param ef.ec_params;
-			) d.d_data;
-			List.iter type_param d.d_params;
-		| ETypedef d ->
-			check KModuleType (fst d.d_name);
-			List.iter type_param d.d_params;
-			type_hint d.d_data;
-		| EAbstract d ->
-			check KModuleType (fst d.d_name);
-			List.iter field d.d_data;
-			List.iter type_param d.d_params;
-			List.iter (function
-				| AbFrom th | AbTo th | AbOver th -> type_hint th
-				| _ -> ()
-			) d.d_flags;
-	) decls
-
 let find_possible_references tctx cs =
-	let name,pos,kind = Display.ReferencePosition.get () in
-	DisplayToplevel.init_or_update_server cs tctx.com ["display";"references"];
-	let cc = CommonCache.get_cache cs tctx.com in
-	let files = cc#get_files in
-	let modules = cc#get_modules in
-	let t = Timer.timer ["display";"references";"candidates"] in
-	Hashtbl.iter (fun file cfile ->
-		let module_name = CompilationServer.get_module_name_of_cfile file cfile in
-		if not (Hashtbl.mem modules (cfile.c_package,module_name)) then try
-			find_possible_references kind name (cfile.c_package,cfile.c_decls);
-		with Exit ->
-			begin try
-				ignore(tctx.g.do_load_module tctx (cfile.c_package,module_name) null_pos);
-				(* We have to flush immediately so we catch exceptions from weird modules *)
-				Typecore.flush_pass tctx Typecore.PFinal "final";
-			with _ ->
-				()
-			end
-	) files;
-	t();
-	()
+	let name,_,kind = Display.ReferencePosition.get () in
+	ignore(SyntaxExplorer.explore_uncached_modules tctx cs [name,kind])
 
-let find_references tctx com with_definition =
-	let name,pos,kind = Display.ReferencePosition.get () in
+let find_references tctx com with_definition name pos kind =
 	let t = Timer.timer ["display";"references";"collect"] in
-	let symbols,relations = Statistics.collect_statistics tctx (SFPos pos) in
+	let symbols,relations = Statistics.collect_statistics tctx (SFPos pos) true in
 	t();
 	let rec loop acc relations = match relations with
 		| (Statistics.Referenced,p) :: relations -> loop (p :: acc) relations
@@ -190,5 +30,37 @@ let find_references tctx com with_definition =
 		if c <> 0 then c else compare p1.pmin p2.pmin
 	) usages in
 	t();
-	Display.ReferencePosition.set ("",null_pos,KVar);
-	DisplayException.raise_positions usages
+	Display.ReferencePosition.set ("",null_pos,SKOther);
+	DisplayException.raise_positions usages
+
+let find_references tctx com with_definition =
+	let name,pos,kind = Display.ReferencePosition.get () in
+	if pos <> null_pos then find_references tctx com with_definition name pos kind
+	else DisplayException.raise_positions []
+
+let find_implementations tctx com name pos kind =
+	let t = Timer.timer ["display";"implementations";"collect"] in
+	let symbols,relations = Statistics.collect_statistics tctx (SFPos pos) false in
+	t();
+	let rec loop acc relations = match relations with
+		| ((Statistics.Implemented | Statistics.Overridden | Statistics.Extended),p) :: relations -> loop (p :: acc) relations
+		| _ :: relations -> loop acc relations
+		| [] -> acc
+	in
+	let t = Timer.timer ["display";"implementations";"filter"] in
+	let usages = Hashtbl.fold (fun p sym acc ->
+		(try loop acc (Hashtbl.find relations p)
+		with Not_found -> acc)
+	) symbols [] in
+	let usages = List.sort (fun p1 p2 ->
+		let c = compare p1.pfile p2.pfile in
+		if c <> 0 then c else compare p1.pmin p2.pmin
+	) usages in
+	t();
+	Display.ReferencePosition.set ("",null_pos,SKOther);
+	DisplayException.raise_positions usages
+
+let find_implementations tctx com =
+	let name,pos,kind = Display.ReferencePosition.get () in
+	if pos <> null_pos then find_implementations tctx com name pos kind
+	else DisplayException.raise_positions []

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

@@ -43,17 +43,14 @@ 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
+		()

+ 113 - 28
src/context/display/statistics.ml

@@ -3,6 +3,7 @@ open Ast
 open Type
 open Common
 open Typecore
+open DisplayTypes
 
 open ImportHandling
 
@@ -12,22 +13,12 @@ type relation =
 	| Overridden
 	| Referenced
 
-type symbol =
-	| SKClass of tclass
-	| SKInterface of tclass
-	| SKEnum of tenum
-	| SKTypedef of tdef
-	| SKAbstract of tabstract
-	| SKField of tclass_field
-	| SKEnumField of tenum_field
-	| SKVariable of tvar
-
 type statistics_filter =
 	| SFNone
 	| SFPos of pos
 	| SFFile of string
 
-let collect_statistics ctx pfilter =
+let collect_statistics ctx pfilter with_expressions =
 	let relations = Hashtbl.create 0 in
 	let symbols = Hashtbl.create 0 in
 	let handled_modules = Hashtbl.create 0 in
@@ -67,16 +58,36 @@ let collect_statistics ctx pfilter =
 				| Some (c,_) ->
 					begin try
 						let cf' = PMap.find cf.cf_name c.cl_fields in
-						add_relation cf'.cf_name_pos (Overridden,cf.cf_pos)
+						add_relation cf'.cf_name_pos (Overridden,cf.cf_name_pos)
 					with Not_found ->
-						loop c
-					end
+						()
+					end;
+					loop c
 				| _ ->
 					()
 			in
 			loop c
 		) c.cl_overrides
 	in
+	let collect_implementations c =
+		List.iter (fun cf ->
+			let rec loop c =
+				begin try
+					let cf' = PMap.find cf.cf_name c.cl_fields in
+					add_relation cf.cf_name_pos (Implemented,cf'.cf_name_pos)
+				with Not_found ->
+					()
+				end;
+				List.iter loop c.cl_descendants
+			in
+			List.iter loop c.cl_descendants
+		) c.cl_ordered_fields;
+		let rec loop c' =
+			add_relation c.cl_name_pos ((if c'.cl_interface then Extended else Implemented),c'.cl_name_pos);
+			List.iter loop c'.cl_descendants
+		in
+		List.iter loop c.cl_descendants
+	in
 	let rec find_real_constructor c = match c.cl_constructor,c.cl_super with
 		(* The pos comparison might be a bit weak, not sure... *)
 		| Some cf,_ when not (Meta.has Meta.CompilerGenerated cf.cf_meta) && c.cl_pos <> cf.cf_pos -> cf
@@ -85,8 +96,49 @@ let collect_statistics ctx pfilter =
 	in
 	let var_decl v = declare (SKVariable v) v.v_pos in
 	let patch_string_pos p s = { p with pmin = p.pmax - String.length s } in
-	let field_reference cf p =
-		add_relation cf.cf_name_pos (Referenced,patch_string_pos p cf.cf_name)
+	let related_fields = Hashtbl.create 0 in
+	let field_reference co cf p =
+		let p' = patch_string_pos p cf.cf_name in
+		add_relation cf.cf_name_pos (Referenced,p');
+		(* extend to related classes for instance fields *)
+		if check_pos cf.cf_name_pos then match co with
+		| Some c ->
+			let id = (c.cl_path,cf.cf_name) in
+			begin try
+				let cfl = Hashtbl.find related_fields id in
+				List.iter (fun cf -> add_relation cf.cf_name_pos (Referenced,p')) cfl
+			with Not_found ->
+				let cfl = ref [] in
+				let check c =
+					try
+						let cf = PMap.find cf.cf_name c.cl_fields in
+						add_relation cf.cf_name_pos (Referenced,p');
+						cfl := cf :: !cfl
+					with Not_found ->
+						()
+				in
+				(* to children *)
+				let rec loop c =
+					List.iter (fun c ->
+						check c;
+						loop c;
+					) c.cl_descendants
+				in
+				loop c;
+				(* to parents *)
+				let rec loop c =
+					let f (c,_) =
+						check c;
+						loop c;
+					in
+					List.iter f c.cl_implements;
+					Option.may f c.cl_super
+				in
+				loop c;
+				Hashtbl.add related_fields id !cfl
+			end
+		| None ->
+			()
 	in
 	let collect_references c e =
 		let rec loop e = match e.eexpr with
@@ -96,11 +148,13 @@ let collect_statistics ctx pfilter =
 				if e1.epos.pmin = e.epos.pmin && e1.epos.pmax <> e.epos.pmax then
 					loop e1;
 				begin match fa with
-					| FStatic(_,cf) | FInstance(_,_,cf) | FClosure(_,cf) ->
-						field_reference cf e.epos
+					| FStatic(_,cf) | FClosure(None,cf) ->
+						field_reference None cf e.epos
+					| FInstance(c,_,cf) | FClosure(Some(c,_),cf) ->
+						field_reference (Some c) cf e.epos
 					| FAnon cf ->
 						declare  (SKField cf) cf.cf_name_pos;
-						field_reference cf e.epos
+						field_reference None cf e.epos
 					| FEnum(_,ef) ->
 						add_relation ef.ef_name_pos (Referenced,patch_string_pos e.epos ef.ef_name)
 					| FDynamic _ ->
@@ -144,20 +198,45 @@ let collect_statistics ctx pfilter =
 			List.iter (fun (p,pn) -> add_relation pn (Referenced,p)) m.m_extra.m_display.m_type_hints
 		end
 	in
+	(* set up descendants *)
+	let f = function
+		| TClassDecl c ->
+				List.iter (fun (iface,_) -> add_descendant iface c) c.cl_implements;
+				begin match c.cl_super with
+					| Some (csup,_) -> add_descendant csup c
+					| None -> ()
+				end;
+		| _ ->
+			()
+	in
+	let rec loop com =
+		List.iter f com.types;
+		Option.may loop (com.get_macros())
+	in
+	loop ctx.com;
+	(* find things *)
 	let f = function
 		| TClassDecl c ->
 			check_module c.cl_module;
 			declare (if c.cl_interface then (SKInterface c) else (SKClass c)) c.cl_name_pos;
-			List.iter (fun (c',_) -> add_relation c'.cl_name_pos ((if c.cl_interface then Extended else Implemented),c.cl_name_pos)) c.cl_implements;
 			begin match c.cl_super with
 				| None -> ()
-				| Some (c',_) -> add_relation c'.cl_name_pos (Extended,c.cl_name_pos);
+				| Some (c',_) ->
+					let rec loop c' =
+						add_relation c'.cl_name_pos (Extended,c.cl_name_pos);
+						Option.may (fun (c',_) -> loop c') c'.cl_super
+					in
+					loop c'
 			end;
 			collect_overrides c;
+			if c.cl_interface then
+				collect_implementations c;
 			let field cf =
 				if cf.cf_pos.pmin > c.cl_name_pos.pmin then declare (SKField cf) cf.cf_name_pos;
-				let _ = follow cf.cf_type in
-				match cf.cf_expr with None -> () | Some e -> collect_references c e
+				if with_expressions then begin
+					let _ = follow cf.cf_type in
+					match cf.cf_expr with None -> () | Some e -> collect_references c e
+				end
 			in
 			Option.may field c.cl_constructor;
 			List.iter field c.cl_ordered_fields;
@@ -178,11 +257,15 @@ let collect_statistics ctx pfilter =
 		Option.may loop (com.get_macros())
 	in
 	loop ctx.com;
-	let l = List.fold_left (fun acc (_,cfi,_,cfo) -> match cfo with
-		| Some cf -> if List.mem_assoc cf.cf_name_pos acc then acc else (cf.cf_name_pos,cfi.cf_name_pos) :: acc
-		| None -> acc
-	) [] ctx.com.display_information.interface_field_implementations in
-	List.iter (fun (p,p') -> add_relation p' (Implemented,p)) l;
+	(* TODO: Using syntax-exploration here is technically fine, but I worry about performance in real codebases. *)
+	(* let find_symbols = Hashtbl.fold (fun _ kind acc ->
+		let name = string_of_symbol kind in
+		(name,kind) :: acc
+	) symbols [] in
+	let additional_modules = SyntaxExplorer.explore_uncached_modules ctx (CompilationServer.force()) find_symbols in
+	List.iter (fun md ->
+		List.iter f md.m_types
+	) additional_modules; *)
 	(* let deal_with_imports paths =
 		let check_subtype m s p =
 			try
@@ -242,8 +325,10 @@ module Printer = struct
 		| SKTypedef _ -> "typedef"
 		| SKAbstract _ -> "abstract"
 		| SKField _ -> "class field"
+		| SKConstructor _ -> "constructor"
 		| SKEnumField _ -> "enum field"
 		| SKVariable _ -> "variable"
+		| SKOther -> "other"
 
 	let print_statistics (kinds,relations) =
 		let files = Hashtbl.create 0 in

+ 181 - 0
src/context/display/syntaxExplorer.ml

@@ -0,0 +1,181 @@
+open Globals
+open Ast
+open DisplayTypes
+open Typecore
+
+type reference_kind =
+	| KVar
+	| KIdent
+	| KAnyField
+	| KClassField
+	| KEnumField
+	| KModuleType
+	| KConstructor
+
+let find_in_syntax symbols (pack,decls) =
+	(* Employ some heuristics: We know what kind of symbol we are looking for, so let's
+	   filter where we can. *)
+	let check kind' name' =
+		List.iter (fun (name,kind) ->
+			if name = name' then match kind',kind with
+				| KIdent,_
+				| KAnyField,(SKField _ | SKConstructor _ | SKEnumField _)
+				| KClassField,SKField _
+				| KEnumField,SKEnumField _
+				| KModuleType,(SKClass _ | SKEnum _ | SKTypedef _ | SKAbstract _)
+				| KConstructor,(SKConstructor _ | SKClass _) ->
+					raise Exit
+				| _ ->
+					()
+		) symbols
+	in
+	let rec type_path kind path =
+		check KModuleType path.tname;
+		Option.may (check KModuleType) path.tsub;
+		List.iter (function
+			| TPType th -> type_hint th
+			| TPExpr e -> expr e
+		) path.tparams
+	and type_hint th = match fst th with
+		| CTPath path -> type_path KModuleType path
+		| CTParent th | CTOptional th | CTNamed(_,th) -> type_hint th
+		| CTFunction(thl,th) ->
+			List.iter type_hint thl;
+			type_hint th;
+		| CTAnonymous cffl ->
+			List.iter field cffl
+		| CTExtend(tl,cffl) ->
+			List.iter (fun (path,_) -> type_path KModuleType path) tl;
+			List.iter field cffl;
+		| CTIntersection tl ->
+			List.iter type_hint tl
+	and type_param tp =
+		List.iter type_param tp.tp_params;
+		Option.may type_hint tp.tp_constraints
+	and expr (e,p) =
+		begin match e with
+		| EConst(Ident s) ->
+			check KIdent s
+		| EField(e1,s) ->
+			expr e1;
+			check KAnyField s;
+		| EVars vl ->
+			List.iter (fun (_,_,tho,eo) ->
+				Option.may type_hint tho;
+				expr_opt eo
+			) vl;
+		| ECast(e1,tho) ->
+			expr e1;
+			Option.may type_hint tho;
+		| ENew((path,_),el) ->
+			type_path KConstructor path;
+			List.iter expr el;
+		| EFunction(_,f) ->
+			func f
+		| ETry(e1,catches) ->
+			expr e1;
+			List.iter (fun (_,th,e,_) ->
+				type_hint th;
+				expr e
+			) catches;
+		| ECheckType(e1,th) ->
+			expr e1;
+			type_hint th;
+		| _ ->
+			iter_expr expr (e,p)
+		end
+	and expr_opt eo = match eo with
+		| None -> ()
+		| Some e -> expr e
+	and func f =
+		List.iter (fun ((s,p),_,_,tho,eo) ->
+			Option.may type_hint tho;
+			expr_opt eo
+		) f.f_args;
+		List.iter type_param f.f_params;
+		Option.may type_hint f.f_type;
+		expr_opt f.f_expr
+	and field cff =
+		check KClassField (fst cff.cff_name);
+		match cff.cff_kind with
+		| FVar(tho,eo) ->
+			Option.may type_hint tho;
+			expr_opt eo
+		| FFun f ->
+			func f
+		| FProp(_,_,tho,eo) ->
+			Option.may type_hint tho;
+			expr_opt eo
+	in
+	List.iter (fun (td,p) -> match td with
+		| EImport(path,_) | EUsing path ->
+			begin match fst (ImportHandling.convert_import_to_something_usable null_pos path) with
+			| IDKModule(_,s) -> check KModuleType s
+			| IDKSubType(_,s1,s2) ->
+				check KModuleType s1;
+				check KModuleType s2;
+			| IDKSubTypeField(_,s1,s2,s3) ->
+				check KModuleType s1;
+				check KModuleType s2;
+				check KAnyField s3;
+			| IDKModuleField(_,s1,s2) ->
+				check KModuleType s1;
+				check KAnyField s2;
+			| IDKPackage _ | IDK ->
+				()
+			end;
+		| EClass d ->
+			check KModuleType (fst d.d_name);
+			List.iter (function
+				| HExtends(path,_) | HImplements(path,_) -> type_path KModuleType path
+				| _ -> ()
+			) d.d_flags;
+			List.iter type_param d.d_params;
+			List.iter field d.d_data
+		| EEnum d ->
+			check KModuleType (fst d.d_name);
+			List.iter (fun ef ->
+				Option.may type_hint ef.ec_type;
+				check KEnumField (fst ef.ec_name);
+				List.iter type_param ef.ec_params;
+			) d.d_data;
+			List.iter type_param d.d_params;
+		| ETypedef d ->
+			check KModuleType (fst d.d_name);
+			List.iter type_param d.d_params;
+			type_hint d.d_data;
+		| EAbstract d ->
+			check KModuleType (fst d.d_name);
+			List.iter field d.d_data;
+			List.iter type_param d.d_params;
+			List.iter (function
+				| AbFrom th | AbTo th | AbOver th -> type_hint th
+				| _ -> ()
+			) d.d_flags;
+	) decls
+
+let explore_uncached_modules tctx cs symbols =
+	DisplayToplevel.init_or_update_server cs tctx.com ["display";"references"];
+	let cc = CommonCache.get_cache cs tctx.com in
+	let files = cc#get_files in
+	let modules = cc#get_modules in
+	let t = Timer.timer ["display";"references";"candidates"] in
+	let acc = Hashtbl.fold (fun file cfile acc ->
+		let module_name = CompilationServer.get_module_name_of_cfile file cfile in
+		if Hashtbl.mem modules (cfile.c_package,module_name) then
+			acc
+		else try
+			find_in_syntax symbols (cfile.c_package,cfile.c_decls);
+			acc
+		with Exit ->
+			begin try
+				let m = tctx.g.do_load_module tctx (cfile.c_package,module_name) null_pos in
+				(* We have to flush immediately so we catch exceptions from weird modules *)
+				Typecore.flush_pass tctx Typecore.PFinal "final";
+				m :: acc
+			with _ ->
+				acc
+			end
+	) files [] in
+	t();
+	acc

+ 2 - 5
src/context/typecore.ml

@@ -465,16 +465,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;

+ 22 - 2
src/core/ast.ml

@@ -234,7 +234,12 @@ and type_param = {
 	tp_meta : metadata;
 }
 
-and documentation = string option
+and doc_block = {
+	doc_own: string option;
+	mutable doc_inherited: (unit -> (string option)) list
+}
+
+and documentation = doc_block option
 
 and metadata_entry = (Meta.strict_meta * expr list * pos)
 and metadata = metadata_entry list
@@ -337,6 +342,21 @@ let is_lower_ident i =
 
 let pos = snd
 
+let doc_from_string s = Some { doc_own = Some s; doc_inherited = []; }
+
+let doc_from_string_opt = Option.map (fun s -> { doc_own = Some s; doc_inherited = []; })
+
+let gen_doc_text d =
+	let docs =
+		match d.doc_own with Some s -> [s] | None -> []
+	in
+	String.concat "\n" docs
+
+
+let gen_doc_text_opt = Option.map gen_doc_text
+
+let get_own_doc_opt = Option.map_default (fun d -> d.doc_own) None
+
 let rec is_postfix (e,_) op = match op with
 	| Increment | Decrement | Not -> true
 	| Neg | NegBits -> false
@@ -805,7 +825,7 @@ module Printer = struct
 		| CTIntersection tl -> String.concat "&" (List.map (fun (t,_) -> s_complex_type tabs t) tl)
 	and s_class_field tabs f =
 		match f.cff_doc with
-		| Some s -> "/**\n\t" ^ tabs ^ s ^ "\n**/\n"
+		| Some d -> "/**\n\t" ^ tabs ^ (gen_doc_text d) ^ "\n**/\n"
 		| None -> "" ^
 		if List.length f.cff_meta > 0 then String.concat ("\n" ^ tabs) (List.map (s_metadata tabs) f.cff_meta) else "" ^
 		if List.length f.cff_access > 0 then String.concat " " (List.map s_placed_access f.cff_access) else "" ^

+ 1 - 1
src/core/display/completionItem.ml

@@ -235,7 +235,7 @@ module CompletionModuleType = struct
 				("params",jlist (generate_ast_type_param ctx) cm.params) ::
 				("isExtern",jbool cm.is_extern) ::
 				("isFinal",jbool cm.is_final) ::
-				(if ctx.generation_mode = GMFull then ["doc",jopt jstring cm.doc] else [])
+				(if ctx.generation_mode = GMFull then ["doc",jopt jstring (gen_doc_text_opt cm.doc)] else [])
 			| GMMinimum ->
 				match generate_minimum_metadata ctx cm.meta with
 					| None -> []

+ 36 - 21
src/core/displayTypes.ml

@@ -183,11 +183,12 @@ module DisplayMode = struct
 		| DMUsage of bool (* true = also report definition *)
 		| DMDefinition
 		| DMTypeDefinition
+		| DMImplementation
 		| DMResolve of string
 		| DMPackage
 		| DMHover
 		| DMModuleSymbols of string option
-		| DMDiagnostics of bool (* true = global, false = only in display file *)
+		| DMDiagnostics of string list
 		| DMStatistics
 		| DMSignature
 
@@ -207,11 +208,11 @@ module DisplayMode = struct
 		dms_full_typing : bool;
 		dms_force_macro_typing : bool;
 		dms_error_policy : error_policy;
-		dms_collect_data : bool;
 		dms_check_core_api : bool;
 		dms_inline : bool;
 		dms_display_file_policy : display_file_policy;
 		dms_exit_during_typing : bool;
+		dms_per_file : bool;
 	}
 
 	let default_display_settings = {
@@ -220,11 +221,11 @@ module DisplayMode = struct
 		dms_full_typing = false;
 		dms_force_macro_typing = false;
 		dms_error_policy = EPIgnore;
-		dms_collect_data = false;
 		dms_check_core_api = false;
 		dms_inline = false;
 		dms_display_file_policy = DFPOnly;
 		dms_exit_during_typing = true;
+		dms_per_file = false;
 	}
 
 	let default_compilation_settings = {
@@ -233,11 +234,11 @@ module DisplayMode = struct
 		dms_full_typing = true;
 		dms_force_macro_typing = true;
 		dms_error_policy = EPShow;
-		dms_collect_data = false;
 		dms_check_core_api = true;
 		dms_inline = true;
 		dms_display_file_policy = DFPNo;
 		dms_exit_during_typing = false;
+		dms_per_file = false;
 	}
 
 	let create dm =
@@ -245,10 +246,9 @@ module DisplayMode = struct
 		match dm with
 		| DMNone -> default_compilation_settings
 		| DMDefault | DMDefinition | DMTypeDefinition | DMResolve _ | DMPackage | DMHover | DMSignature -> settings
-		| DMUsage _ -> { settings with
+		| DMUsage _ | DMImplementation -> { settings with
 				dms_full_typing = true;
 				dms_force_macro_typing = true;
-				dms_collect_data = true;
 				dms_display_file_policy = DFPAlso;
 				dms_exit_during_typing = false
 			}
@@ -256,20 +256,21 @@ module DisplayMode = struct
 				dms_display_file_policy = if filter = None then DFPOnly else DFPNo;
 				dms_exit_during_typing = false;
 				dms_force_macro_typing = false;
+				dms_per_file = true;
 			}
-		| DMDiagnostics global -> { default_compilation_settings with
-				dms_kind = DMDiagnostics global;
+		| DMDiagnostics files -> { default_compilation_settings with
+				dms_kind = DMDiagnostics files;
 				dms_error_policy = EPCollect;
-				dms_collect_data = true;
-				dms_display_file_policy = if global then DFPNo else DFPAlso;
+				dms_display_file_policy = if files = [] then DFPNo else DFPAlso;
+				dms_per_file = true;
 			}
 		| DMStatistics -> { settings with
 				dms_full_typing = true;
-				dms_collect_data = true;
 				dms_inline = false;
 				dms_display_file_policy = DFPAlso;
 				dms_exit_during_typing = false;
 				dms_force_macro_typing = true;
+				dms_per_file = true;
 			}
 
 	let to_string = function
@@ -277,6 +278,7 @@ module DisplayMode = struct
 		| DMDefault -> "field"
 		| DMDefinition -> "position"
 		| DMTypeDefinition -> "type-definition"
+		| DMImplementation -> "implementation"
 		| DMResolve s -> "resolve " ^ s
 		| DMPackage -> "package"
 		| DMHover -> "type"
@@ -284,19 +286,22 @@ module DisplayMode = struct
 		| DMUsage false -> "references"
 		| DMModuleSymbols None -> "module-symbols"
 		| DMModuleSymbols (Some s) -> "workspace-symbols " ^ s
-		| DMDiagnostics b -> (if b then "global " else "") ^ "diagnostics"
+		| DMDiagnostics _ -> "diagnostics"
 		| DMStatistics -> "statistics"
 		| DMSignature -> "signature"
 end
 
-type reference_kind =
-	| KVar
-	| KIdent
-	| KAnyField
-	| KClassField
-	| KEnumField
-	| KModuleType
-	| KConstructor
+type symbol =
+	| SKClass of tclass
+	| SKInterface of tclass
+	| SKEnum of tenum
+	| SKTypedef of tdef
+	| SKAbstract of tabstract
+	| SKField of tclass_field
+	| SKConstructor of tclass_field
+	| SKEnumField of tenum_field
+	| SKVariable of tvar
+	| SKOther
 
 type completion_subject = {
 	s_name : string option;
@@ -308,4 +313,14 @@ let make_subject name ?(start_pos=None) insert_pos = {
 	s_name = name;
 	s_start_pos = (match start_pos with None -> insert_pos | Some p -> p);
 	s_insert_pos = insert_pos;
-}
+}
+
+let string_of_symbol = function
+	| SKClass c | SKInterface c -> snd c.cl_path
+	| SKEnum en -> snd en.e_path
+	| SKTypedef td -> snd td.t_path
+	| SKAbstract a -> snd a.a_path
+	| SKField cf | SKConstructor cf -> cf.cf_name
+	| SKEnumField ef -> ef.ef_name
+	| SKVariable v -> v.v_name
+	| SKOther -> ""

+ 2 - 0
src/core/globals.ml

@@ -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 =

+ 1 - 1
src/core/json/genjson.ml

@@ -72,7 +72,7 @@ let generate_expr_pos ctx p =
 	jtodo
 
 let generate_doc ctx d = match ctx.generation_mode with
-	| GMFull -> jopt jstring d
+	| GMFull -> jopt jstring (gen_doc_text_opt d)
 	| GMWithoutDoc | GMMinimum -> jnull
 
 (** return a range JSON structure for given position

+ 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;

+ 6 - 2
src/core/tPrinting.ml

@@ -463,7 +463,10 @@ module Printer = struct
 	let s_pmap fk fv pm =
 		"{" ^ (String.concat ", " (PMap.foldi (fun k v acc -> (Printf.sprintf "%s = %s" (fk k) (fv v)) :: acc) pm [])) ^ "}"
 
-	let s_doc = s_opt (fun s -> s)
+	let s_doc doc_opt =
+		match doc_opt with
+		| None -> "None"
+		| Some d -> gen_doc_text d
 
 	let s_metadata_entry (s,el,_) =
 		Printf.sprintf "@%s%s" (Meta.to_string s) (match el with [] -> "" | el -> "(" ^ (String.concat ", " (List.map Ast.Printer.s_expr el)) ^ ")")
@@ -594,6 +597,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
@@ -648,7 +652,7 @@ module Printer = struct
 	let s_class_field cff =
 		s_record_fields "" [
 			"cff_name",s_placed (fun s -> s) cff.cff_name;
-			"cff_doc",s_opt (fun s -> s) cff.cff_doc;
+			"cff_doc",s_doc cff.cff_doc;
 			"cff_pos",s_pos cff.cff_pos;
 			"cff_meta",s_metadata cff.cff_meta;
 			"cff_access",s_list ", " Ast.s_placed_access cff.cff_access;

+ 1 - 0
src/core/tType.ml

@@ -323,6 +323,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 = {

+ 1 - 1
src/dune

@@ -9,7 +9,7 @@
 (library
 	(name haxe)
 	(libraries
-		extc extproc extlib_leftovers ilib javalib neko objsize pcre swflib ttflib ziplib
+		extc extproc extlib_leftovers ilib javalib mbedtls neko objsize pcre swflib ttflib ziplib
 		json
 		unix str threads dynlink
 		xml-light extlib ptmap sha

+ 6 - 37
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)
@@ -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,6 +820,7 @@ let run com tctx main =
 		fix_return_dynamic_from_void_function tctx true;
 		check_local_vars_init;
 		check_abstract_as_value;
+		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;
@@ -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

+ 1 - 1
src/filters/jsExceptions.ml

@@ -147,7 +147,7 @@ let init ctx =
 					let etype = make_typeexpr (module_type_of_type t) e.epos in
 					let args = [eunwrapped;etype] in
 					let echeck =
-						match Inline.api_inline ctx cStd "is" args e.epos with
+						match Inline.api_inline ctx cStd "isOfType" args e.epos with
 						| Some e -> e
 						| None ->
 							let eBoot = make_static_this cBoot e.epos in

+ 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

+ 1 - 1
src/filters/tryCatchWrapper.ml

@@ -150,7 +150,7 @@ let configure_cs com =
 	let gen_typecheck e t pos =
 		let std = make_static_this std_cl pos in
 		let e_type = make_typeexpr (module_type_of_type t) pos in
-		fcall std "is" [e; e_type] com.basic.tbool pos
+		fcall std "isOfType" [e; e_type] com.basic.tbool pos
 	in
 	init com should_wrap wrap_throw unwrap_expr rethrow_expr base_exception_t hx_exception_t catch_map gen_typecheck
 

+ 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

+ 64 - 10
src/generators/gencs.ml

@@ -243,12 +243,12 @@ struct
 			match e.eexpr with
 				(* Std.is() *)
 				| TCall(
-						{ eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) },
+						{ eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = ("is" | "isOfType") })) },
 						[ obj; { eexpr = TTypeExpr(TClassDecl { cl_path = [], "Dynamic" } | TAbstractDecl { a_path = [], "Dynamic" }) }]
 					) ->
 						Type.map_expr run e
 				| TCall(
-						{ eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is"}) ) },
+						{ eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = ("is" | "isOfType") }) ) },
 						[ obj; { eexpr = TTypeExpr(md) }]
 					) ->
 					let md = change_md md in
@@ -272,7 +272,7 @@ struct
 						match obj.eexpr with
 							| TLocal(v) -> f obj
 							| _ ->
-								let var = mk_temp "is" obj.etype in
+								let var = mk_temp "isOfType" obj.etype in
 								let added = { obj with eexpr = TVar(var, Some(obj)); etype = basic.tvoid } in
 								let local = mk_local var obj.epos in
 								{
@@ -1878,6 +1878,22 @@ let generate con =
 				gen.gcon.error "Invalid expression inside @:meta metadata" p
 		in
 
+		let gen_assembly_attributes w metadata =
+			List.iter (function
+				| Meta.AssemblyMeta, [EConst(String(s,_)), _], _ ->
+					write w "[assembly:";
+					write w s;
+					write w "]";
+					newline w
+				| Meta.AssemblyMeta, [meta], _ ->
+					write w "[assembly:";
+					gen_spart w meta;
+					write w "]";
+					newline w
+				| _ -> ()
+			) metadata
+		in
+
 		let gen_attributes w metadata =
 			List.iter (function
 				| Meta.Meta, [EConst(String(s,_)), _], _ ->
@@ -2188,9 +2204,12 @@ let generate con =
 							| Some e ->
 								write w " = ";
 								expr_s true w e;
-							| None -> ()
+								write w ";"
+							| None when (Meta.has Meta.Property cf.cf_meta) ->
+								write w " { get; set; }";
+							| None ->
+								write w ";"
 						);
-						write w ";"
 					end (* TODO see how (get,set) variable handle when they are interfaces *)
 				| Method _ when not (Type.is_physical_field cf) || (match cl.cl_kind, cf.cf_expr with | KAbstractImpl _, None -> true | _ -> false) ->
 					List.iter (fun cf -> if cl.cl_interface || cf.cf_expr <> None then
@@ -2519,12 +2538,28 @@ let generate con =
 			end
 		in
 
-		let gen_class w cl =
+		let gen_class w cl is_first_type =
+			if (is_first_type == false) then begin
+				if Meta.has Meta.AssemblyStrict cl.cl_meta then
+					gen.gcon.error "@:cs.assemblyStrict can only be used on the first class of a module" cl.cl_pos
+				else if Meta.has Meta.AssemblyMeta cl.cl_meta then
+					gen.gcon.error "@:cs.assemblyMeta can only be used on the first class of a module" cl.cl_pos;
+			end;
+
 			write w "#pragma warning disable 109, 114, 219, 429, 168, 162";
 			newline w;
 			let should_close = match change_ns (TClassDecl cl) (fst (cl.cl_path)) with
-				| [] -> false
+				| [] ->
+					(* Should the assembly annotations be added to the class in this case? *)
+
+					if Meta.has Meta.AssemblyStrict cl.cl_meta then
+						gen.gcon.error "@:cs.assemblyStrict cannot be used on top level modules" cl.cl_pos
+					else if Meta.has Meta.AssemblyMeta cl.cl_meta then
+						gen.gcon.error "@:cs.assemblyMeta cannot be used on top level modules" cl.cl_pos;
+
+					false
 				| ns ->
+					gen_assembly_attributes w cl.cl_meta;
 					print w "namespace %s " (String.concat "." ns);
 					begin_block w;
 					true
@@ -2779,7 +2814,7 @@ let generate con =
 			if should_close then end_block w
 		in
 
-		let module_type_gen w md_tp =
+		let module_type_gen w md_tp is_first_type =
 			let file_start = len w = 0 in
 			let requires_root = no_root && file_start in
 			if file_start then
@@ -2789,7 +2824,24 @@ let generate con =
 				| TClassDecl cl ->
 					if not cl.cl_extern then begin
 						(if requires_root then write w "using haxe.root;\n"; newline w;);
-						gen_class w cl;
+
+						(if (Meta.has Meta.CsUsing cl.cl_meta) then
+							match (Meta.get Meta.CsUsing cl.cl_meta) with
+								| _,_,p when not !is_first_type ->
+									gen.gcon.error "@:cs.using can only be used on the first type of a module" p
+								| _,[],p ->
+									gen.gcon.error "One or several string constants expected" p
+								| _,e,_ ->
+									(List.iter (fun e ->
+										match e with
+										| (EConst(String(s,_))),_ -> write w (Printf.sprintf "using %s;\n" s)
+										| _,p -> gen.gcon.error "One or several string constants expected" p
+									) e);
+									newline w
+						);
+
+						gen_class w cl !is_first_type;
+						is_first_type := false;
 						newline w;
 						newline w
 					end;
@@ -2798,6 +2850,7 @@ let generate con =
 					if not e.e_extern && not (Meta.has Meta.Class e.e_meta) then begin
 						(if requires_root then write w "using haxe.root;\n"; newline w;);
 						gen_enum w e;
+						is_first_type := false;
 						newline w;
 						newline w
 					end;
@@ -3422,7 +3475,8 @@ let generate con =
 		List.iter (fun md_def ->
 			let source_dir = gen.gcon.file ^ "/src/" ^ (String.concat "/" (fst (path_of_md_def md_def))) in
 			let w = SourceWriter.new_source_writer() in
-			let should_write = List.fold_left (fun should md -> module_type_gen w md || should) false md_def.m_types in
+			let is_first_type = ref true in
+			let should_write = List.fold_left (fun should md -> module_type_gen w md is_first_type || should) false md_def.m_types in
 			if should_write then begin
 				let path = path_of_md_def md_def in
 				write_file gen w source_dir path "cs" out_files

+ 49 - 29
src/generators/genhl.ml

@@ -104,6 +104,7 @@ type context = {
 	mutable method_wrappers : ((ttype * ttype), int) PMap.t;
 	mutable rec_cache : (Type.t * ttype option ref) list;
 	mutable cached_tuples : (ttype list, ttype) PMap.t;
+	mutable tstring : ttype;
 	macro_typedefs : (string, ttype) Hashtbl.t;
 	array_impl : array_impl;
 	base_class : tclass;
@@ -139,6 +140,10 @@ let is_to_string t =
 	| TFun([],r) -> (match follow r with TInst({ cl_path=[],"String" },[]) -> true | _ -> false)
 	| _ -> false
 
+let is_string = function
+	| HObj { pname = "String"} -> true
+	| _ -> false
+
 let is_extern_field f =
 	not (Type.is_physical_field f) || (match f.cf_kind with Method MethNormal -> List.exists (fun (m,_,_) -> m = Meta.HlNative) f.cf_meta | _ -> false) || has_class_field_flag f CfExtern
 
@@ -1054,52 +1059,57 @@ let rec eval_to ctx e (t:ttype) =
 		let r = eval_expr ctx e in
 		cast_to ctx r t e.epos
 
-and cast_to ?(force=false) ctx (r:reg) (t:ttype) p =
+and to_string ctx (r:reg) p =
 	let rt = rtype ctx r in
-	if safe_cast rt t then r else
-	match rt, t with
-	| _, HVoid ->
-		alloc_tmp ctx HVoid
-	| HVirtual _, HVirtual _ ->
-		let tmp = alloc_tmp ctx HDyn in
-		op ctx (OMov (tmp,r));
-		cast_to ctx tmp t p
-	| (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64), (HF32 | HF64) ->
-		let tmp = alloc_tmp ctx t in
-		op ctx (OToSFloat (tmp, r));
-		tmp
-	| (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64), (HUI8 | HUI16 | HI32 | HI64) ->
-		let tmp = alloc_tmp ctx t in
-		op ctx (OToInt (tmp, r));
-		tmp
-	| (HUI8 | HUI16 | HI32), HObj { pname = "String" } ->
+	if safe_cast rt ctx.tstring then r else
+	match rt with
+	| HUI8 | HUI16 | HI32 ->
 		let len = alloc_tmp ctx HI32 in
 		hold ctx len;
 		let lref = alloc_tmp ctx (HRef HI32) in
 		let bytes = alloc_tmp ctx HBytes in
 		op ctx (ORef (lref,len));
 		op ctx (OCall2 (bytes,alloc_std ctx "itos" [HI32;HRef HI32] HBytes,cast_to ctx r HI32 p,lref));
-		let out = alloc_tmp ctx t in
+		let out = alloc_tmp ctx ctx.tstring in
 		op ctx (OCall2 (out,alloc_fun_path ctx ([],"String") "__alloc__",bytes,len));
 		free ctx len;
 		out
-	| (HF32 | HF64), HObj { pname = "String" } ->
+	| HF32 | HF64 ->
 		let len = alloc_tmp ctx HI32 in
 		let lref = alloc_tmp ctx (HRef HI32) in
 		let bytes = alloc_tmp ctx HBytes in
 		op ctx (ORef (lref,len));
 		op ctx (OCall2 (bytes,alloc_std ctx "ftos" [HF64;HRef HI32] HBytes,cast_to ctx r HF64 p,lref));
-		let out = alloc_tmp ctx t in
+		let out = alloc_tmp ctx ctx.tstring in
 		op ctx (OCall2 (out,alloc_fun_path ctx ([],"String") "__alloc__",bytes,len));
 		out
-	| _, HObj { pname = "String" } ->
+	| _ ->
 		let r = cast_to ctx r HDyn p in
-		let out = alloc_tmp ctx t in
+		let out = alloc_tmp ctx ctx.tstring in
 		op ctx (OJNotNull (r,2));
 		op ctx (ONull out);
 		op ctx (OJAlways 1);
 		op ctx (OCall1 (out,alloc_fun_path ctx ([],"Std") "string",r));
 		out
+
+and cast_to ?(force=false) ctx (r:reg) (t:ttype) p =
+	let rt = rtype ctx r in
+	if safe_cast rt t then r else
+	match rt, t with
+	| _, HVoid ->
+		alloc_tmp ctx HVoid
+	| HVirtual _, HVirtual _ ->
+		let tmp = alloc_tmp ctx HDyn in
+		op ctx (OMov (tmp,r));
+		cast_to ctx tmp t p
+	| (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64), (HF32 | HF64) ->
+		let tmp = alloc_tmp ctx t in
+		op ctx (OToSFloat (tmp, r));
+		tmp
+	| (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64), (HUI8 | HUI16 | HI32 | HI64) ->
+		let tmp = alloc_tmp ctx t in
+		op ctx (OToInt (tmp, r));
+		tmp
 	| HObj o, HVirtual _ ->
 		let out = alloc_tmp ctx t in
 		(try
@@ -1506,7 +1516,7 @@ and make_const ctx c p =
 		let fields, t = (match c with
 		| CString s ->
 			let str, len = to_utf8 s p in
-			[alloc_string ctx str; alloc_i32 ctx (Int32.of_int len)], to_type ctx ctx.com.basic.tstring
+			[alloc_string ctx str; alloc_i32 ctx (Int32.of_int len)], ctx.tstring
 		) in
 		let g = lookup_alloc ctx.cglobals t in
 		g, Array.of_list fields
@@ -1515,7 +1525,7 @@ and make_const ctx c p =
 	g
 
 and make_string ctx s p =
-	let r = alloc_tmp ctx (to_type ctx ctx.com.basic.tstring) in
+	let r = alloc_tmp ctx ctx.tstring in
 	op ctx (OGetGlobal (r, make_const ctx (CString s) p));
 	r
 
@@ -2285,7 +2295,7 @@ and eval_expr ctx e =
 					| HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 ->
 						op ctx (OAdd (r,a,b))
 					| HObj { pname = "String" } ->
-						op ctx (OCall2 (r,alloc_fun_path ctx ([],"String") "__add__",a,b))
+						op ctx (OCall2 (r,alloc_fun_path ctx ([],"String") "__add__",to_string ctx a e1.epos,to_string ctx b e2.epos))
 					| HDyn ->
 						op ctx (OCall2 (r,alloc_fun_path ctx ([],"Std") "__add__",a,b))
 					| t ->
@@ -2346,10 +2356,18 @@ and eval_expr ctx e =
 			r
 		| OpAdd | OpSub | OpMult | OpDiv | OpMod | OpShl | OpShr | OpUShr | OpAnd | OpOr | OpXor ->
 			let t = (match to_type ctx e.etype with HNull t -> t | t -> t) in
+			let conv_string = bop = OpAdd && is_string t in
+			let eval e =
+				if conv_string then
+					let r = eval_expr ctx e in
+					to_string ctx r e.epos
+				else
+					eval_to ctx e t
+			in
 			let r = alloc_tmp ctx t in
-			let a = eval_to ctx e1 t in
+			let a = eval e1 in
 			hold ctx a;
-			let b = eval_to ctx e2 t in
+			let b = eval e2 in
 			free ctx a;
 			binop r a b;
 			r
@@ -2459,7 +2477,7 @@ and eval_expr ctx e =
 			| acc ->
 				gen_assign_op ctx acc e1 (fun r ->
 					hold ctx r;
-					let b = eval_to ctx e2 (rtype ctx r) in
+					let b = if bop = OpAdd && is_string (rtype ctx r) then to_string ctx (eval_expr ctx e2) e2.epos else eval_to ctx e2 (rtype ctx r) in
 					free ctx r;
 					binop r r b;
 					r))
@@ -3939,6 +3957,7 @@ let create_context com is_macro dump =
 		cached_tuples = PMap.empty;
 		cfids = new_lookup();
 		defined_funs = Hashtbl.create 0;
+		tstring = HVoid;
 		array_impl = {
 			aall = get_class "ArrayAccess";
 			abase = get_class "ArrayBase";
@@ -3963,6 +3982,7 @@ let create_context com is_macro dump =
 		ct_delayed = [];
 		ct_depth = 0;
 	} in
+	ctx.tstring <- to_type ctx ctx.com.basic.tstring;
 	ignore(alloc_string ctx "");
 	ignore(class_type ctx ctx.base_class [] false);
 	ctx

+ 1 - 1
src/generators/genjava.ml

@@ -254,7 +254,7 @@ struct
 
 				(* Std.is() *)
 				| TCall(
-						{ eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) },
+						{ eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = ("is" | "isOfType") })) },
 						[ obj; { eexpr = TTypeExpr(md) } ]
 					) ->
 					let mk_is is_basic obj md =

+ 125 - 55
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
@@ -371,6 +371,14 @@ let gen_constant ctx p = function
 let print_deprecation_message com msg p =
 	com.warning msg p
 
+let is_code_injection_function e =
+	match e.eexpr with
+	| TIdent "__js__"
+	| TField (_, FStatic ({ cl_path = ["js"],"Syntax" }, { cf_name = "code" | "plainCode" }))
+		-> true
+	| _ ->
+		false
+
 let rec gen_call ctx e el in_value =
 	match e.eexpr , el with
 	| TConst TSuper , params when ctx.es_version < 6 ->
@@ -390,7 +398,7 @@ let rec gen_call ctx e el in_value =
 			List.iter (fun p -> print ctx ","; gen_value ctx p) params;
 			spr ctx ")";
 		);
-	| TCall (x,_) , el when (match x.eexpr with TIdent "__js__" -> false | _ -> true) ->
+	| TCall (x,_) , el when not (is_code_injection_function x) ->
 		spr ctx "(";
 		gen_value ctx e;
 		spr ctx ")";
@@ -958,15 +966,35 @@ and gen_syntax ctx meth args pos =
 		let code, code_pos =
 			match code.eexpr with
 			| TConst (TString s) -> s, code.epos
-			| _ -> abort "The `code` argument for js.Syntax must be a string constant" code.epos
+			| _ -> abort "The `code` argument for js.Syntax.code must be a string constant" code.epos
 		in
 		begin
 			match args with
 			| [] when code = "this" ->
 				spr ctx (this ctx)
 			| _ ->
+				let rec reveal_expr expr =
+					match expr.eexpr with
+						| TCast (e, _) | TMeta (_, e) -> reveal_expr e
+						| _ -> expr
+				in
+				let args = List.map
+					(fun arg ->
+						match (reveal_expr arg).eexpr with
+							| TIf _ | TBinop _ | TUnop _ -> { arg with eexpr = TParenthesis arg }
+							| _ -> arg
+					)
+					args
+				in
 				Codegen.interpolate_code ctx.com code args (spr ctx) (gen_value ctx) code_pos
 		end
+	| "plainCode", [code] ->
+		let code =
+			match code.eexpr with
+			| TConst (TString s) -> s
+			| _ -> abort "The `code` argument for js.Syntax.plainCode must be a string constant" code.epos
+		in
+		spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n"))
 	| "field" , [eobj;efield] ->
 		gen_value ctx eobj;
 		(match Texpr.skip efield with
@@ -1019,20 +1047,20 @@ let path_to_brackets path =
 	let parts = ExtString.String.nsplit path "." in
 	"[\"" ^ (String.concat "\"][\"" parts) ^ "\"]"
 
-let gen_class_static_field ctx c f =
+let gen_class_static_field ctx c cl_path f =
 	match f.cf_expr with
 	| None | Some { eexpr = TConst TNull } when not (has_feature ctx "Type.getClassFields") ->
 		()
 	| None when not (is_physical_field f) ->
 		()
 	| None ->
-		print ctx "%s%s = null" (s_path ctx c.cl_path) (static_field ctx c f.cf_name);
+		print ctx "%s%s = null" (s_path ctx cl_path) (static_field ctx c f.cf_name);
 		newline ctx
 	| Some e ->
 		match e.eexpr with
 		| TFunction _ ->
-			let path = (s_path ctx c.cl_path) ^ (static_field ctx c f.cf_name) in
-			let dot_path = (dot_path c.cl_path) ^ (static_field ctx c f.cf_name) in
+			let path = (s_path ctx cl_path) ^ (static_field ctx c f.cf_name) in
+			let dot_path = (dot_path cl_path) ^ (static_field ctx c f.cf_name) in
 			ctx.id_counter <- 0;
 			print ctx "%s = " path;
 			(match (get_exposed ctx dot_path f.cf_meta) with [s] -> print ctx "$hx_exports%s = " (path_to_brackets s) | _ -> ());
@@ -1061,14 +1089,14 @@ let gen_class_field ctx c f =
 		gen_value ctx e;
 		ctx.separator <- false
 
-let generate_class___name__ ctx c =
+let generate_class___name__ ctx cl_path =
 	if has_feature ctx "js.Boot.isClass" then begin
-		let p = s_path ctx c.cl_path in
+		let p = s_path ctx cl_path in
 		print ctx "%s.__name__ = " p;
-		(match has_feature ctx "Type.getClassName", c.cl_path with
+		(match has_feature ctx "Type.getClassName", cl_path with
 			| true, _
 			| _, ([], ("Array" | "String")) ->
-				print ctx "\"%s\"" (dot_path c.cl_path)
+				print ctx "\"%s\"" (dot_path cl_path)
 			| _ ->
 				print ctx "true"
 		);
@@ -1082,33 +1110,59 @@ let generate_class___isInterface__ ctx c =
 		newline ctx;
 	end
 
+let get_generated_class_path = function
+	(* we want to generate abstract implementations with the path of the abstract itself, unless there is @:native involved *)
+	| { cl_kind = KAbstractImpl a; cl_meta = m } when not (Meta.has Meta.Native m) ->
+		a.a_path
+	| { cl_path = p } ->
+		p
+
+let is_abstract_impl c = match c.cl_kind with KAbstractImpl _ -> true | _ -> false
+
 let generate_class_es3 ctx c =
-	let p = s_path ctx c.cl_path in
+	let cl_path = get_generated_class_path c in
+	let is_abstract_impl = is_abstract_impl c in
+
 	if ctx.js_flatten then
 		print ctx "var "
 	else
-		generate_package_create ctx c.cl_path;
-	if ctx.js_modern || not ctx.has_resolveClass then
+		generate_package_create ctx cl_path;
+
+	let p = s_path ctx cl_path in
+	let dotp = dot_path cl_path in
+
+	let added_to_hxClasses = ctx.has_resolveClass && not is_abstract_impl in
+
+	if ctx.js_modern || not added_to_hxClasses then
 		print ctx "%s = " p
 	else
-		print ctx "%s = $hxClasses[\"%s\"] = " p (dot_path c.cl_path);
-	(match (get_exposed ctx (dot_path c.cl_path) c.cl_meta) with [s] -> print ctx "$hx_exports%s = " (path_to_brackets s) | _ -> ());
-	(match c.cl_kind with
-		| KAbstractImpl _ ->
-			(* abstract implementations only contain static members and don't need to have constructor functions *)
-			print ctx "{}"; ctx.separator <- true
-		| _ ->
-			(match c.cl_constructor with
-			| Some { cf_expr = Some e } -> gen_expr ctx e
-			| _ -> (print ctx "function() { }"); ctx.separator <- true)
-	);
+		print ctx "%s = $hxClasses[\"%s\"] = " p dotp;
+
+	(match (get_exposed ctx dotp c.cl_meta) with
+	| [s] -> print ctx "$hx_exports%s = " (path_to_brackets s)
+	| _ -> ());
+
+	if is_abstract_impl then begin
+		(* abstract implementations only contain static members and don't need to have constructor functions *)
+		print ctx "{}";
+		ctx.separator <- true
+	end else begin
+		match c.cl_constructor with
+		| Some { cf_expr = Some e } -> gen_expr ctx e
+		| _ -> (print ctx "function() { }"); ctx.separator <- true
+	end;
+
 	newline ctx;
-	if ctx.js_modern && ctx.has_resolveClass then begin
-		print ctx "$hxClasses[\"%s\"] = %s" (dot_path c.cl_path) p;
+
+	if ctx.js_modern && added_to_hxClasses then begin
+		print ctx "$hxClasses[\"%s\"] = %s" dotp p;
 		newline ctx;
 	end;
-	generate_class___name__ ctx c;
-	generate_class___isInterface__ ctx c;
+
+	if not is_abstract_impl then begin
+		generate_class___name__ ctx cl_path;
+		generate_class___isInterface__ ctx c;
+	end;
 
 	if ctx.has_interface_check then
 		(match c.cl_implements with
@@ -1132,7 +1186,7 @@ let generate_class_es3 ctx c =
 			newline ctx);
 	end;
 
-	List.iter (gen_class_static_field ctx c) c.cl_ordered_statics;
+	List.iter (gen_class_static_field ctx c cl_path) c.cl_ordered_statics;
 
 	let has_class = has_feature ctx "js.Boot.getClass" && (c.cl_super <> None || c.cl_ordered_fields <> [] || c.cl_constructor <> None) in
 	let has_prototype = c.cl_super <> None || has_class || List.exists (can_gen_class_field ctx) c.cl_ordered_fields in
@@ -1174,13 +1228,15 @@ let generate_class_es3 ctx c =
 	flush ctx
 
 let generate_class_es6 ctx c =
-	let p = s_path ctx c.cl_path in
+	let cl_path = get_generated_class_path c in
+	let p = s_path ctx cl_path in
+	let dotp = dot_path cl_path in
 
 	let cls_name =
-		if not ctx.js_flatten && (fst c.cl_path) <> [] then begin
-			generate_package_create ctx c.cl_path;
+		if not ctx.js_flatten && (fst cl_path) <> [] then begin
+			generate_package_create ctx cl_path;
 			print ctx "%s = " p;
-			Path.flat_path c.cl_path
+			Path.flat_path cl_path
 		end else
 			p
 	in
@@ -1229,7 +1285,7 @@ let generate_class_es6 ctx c =
 				gen_function ~keyword:("static " ^ (method_def_name cf)) ctx f pos;
 				ctx.separator <- false;
 
-				(match get_exposed ctx ((dot_path c.cl_path) ^ (static_field ctx c cf.cf_name)) cf.cf_meta with
+				(match get_exposed ctx (dotp ^ (static_field ctx c cf.cf_name)) cf.cf_meta with
 				| [s] -> exposed_static_methods := (s,cf.cf_name) :: !exposed_static_methods;
 				| _ -> ());
 
@@ -1248,12 +1304,15 @@ let generate_class_es6 ctx c =
 		newline ctx
 	) !exposed_static_methods;
 
-	List.iter (gen_class_static_field ctx c) nonmethod_statics;
+	List.iter (gen_class_static_field ctx c cl_path) nonmethod_statics;
+
+	let is_abstract_impl = is_abstract_impl c in
+	let added_to_hxClasses = ctx.has_resolveClass && not is_abstract_impl in
 
-	let expose = (match get_exposed ctx (dot_path c.cl_path) c.cl_meta with [s] -> "$hx_exports" ^ (path_to_brackets s) | _ -> "") in
-	if expose <> "" || ctx.has_resolveClass then begin
-		if ctx.has_resolveClass then begin
-			print ctx "$hxClasses[\"%s\"] = " (dot_path c.cl_path)
+	let expose = (match get_exposed ctx dotp c.cl_meta with [s] -> "$hx_exports" ^ (path_to_brackets s) | _ -> "") in
+	if expose <> "" || added_to_hxClasses then begin
+		if added_to_hxClasses then begin
+			print ctx "$hxClasses[\"%s\"] = " dotp
 		end;
 		if expose <> "" then begin
 			print ctx "%s = " expose
@@ -1262,8 +1321,10 @@ let generate_class_es6 ctx c =
 		newline ctx;
 	end;
 
-	generate_class___name__ ctx c;
-	generate_class___isInterface__ ctx c;
+	if not is_abstract_impl then begin
+		generate_class___name__ ctx cl_path;
+		generate_class___isInterface__ ctx c;
+	end;
 
 	if ctx.has_interface_check then
 		(match c.cl_implements with
@@ -1364,7 +1425,7 @@ let generate_enum ctx e =
 	(if as_objects then
 		print ctx "$hxEnums[\"%s\"] = " dotp
 	else if has_feature ctx "Type.resolveEnum" then
-		print ctx "$hxClasses[\"%s\"] = " (dot_path e.e_path));
+		print ctx "$hxClasses[\"%s\"] = " dotp);
 	spr ctx "{";
 	if has_feature ctx "js.Boot.isEnum" then print ctx " __ename__ : %s," (if has_feature ctx "Type.getEnumName" then "\"" ^ dotp ^ "\"" else "true");
 	print ctx " __constructs__ : [%s]" (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" s) e.e_names));
@@ -1443,9 +1504,10 @@ let generate_enum ctx e =
 	flush ctx
 
 let generate_static ctx (c,f,e) =
-	let dot_path = (dot_path c.cl_path) ^ (static_field ctx c f.cf_name) in
+	let cl_path = get_generated_class_path c in
+	let dot_path = (dot_path cl_path) ^ (static_field ctx c f.cf_name) in
 	(match (get_exposed ctx dot_path f.cf_meta) with [s] -> print ctx "$hx_exports%s = " (path_to_brackets s) | _ -> ());
-	print ctx "%s%s = " (s_path ctx c.cl_path) (static_field ctx c f.cf_name);
+	print ctx "%s%s = " (s_path ctx cl_path) (static_field ctx c f.cf_name);
 	gen_value ctx e;
 	newline ctx
 
@@ -1481,7 +1543,7 @@ let generate_type ctx = function
 			ctx.inits <- e :: ctx.inits);
 		(* Special case, want to add Math.__name__ only when required, handle here since Math is extern *)
 		let p = s_path ctx c.cl_path in
-		if p = "Math" then generate_class___name__ ctx c;
+		if p = "Math" then generate_class___name__ ctx c.cl_path;
 		(* Another special case for Std because we do not want to generate it if it's empty. *)
 		if p = "Std" && c.cl_ordered_statics = [] then
 			()
@@ -1489,7 +1551,7 @@ let generate_type ctx = function
 			if (not c.cl_interface) || (need_to_generate_interface ctx c) then
 				generate_class ctx c
 		end else if Meta.has Meta.JsRequire c.cl_meta && is_directly_used ctx.com c.cl_meta then
-			generate_require ctx c.cl_path c.cl_meta
+			generate_require ctx (get_generated_class_path c) c.cl_meta
 		else if not ctx.js_flatten && Meta.has Meta.InitPackage c.cl_meta then
 			(match c.cl_path with
 			| ([],_) -> ()
@@ -1541,14 +1603,20 @@ let alloc_ctx com es_version =
 		separator = false;
 		found_expose = false;
 	} in
+
 	ctx.type_accessor <- (fun t ->
-		let p = t_path t in
 		match t with
-		| TClassDecl ({ cl_extern = true } as c) when not (Meta.has Meta.JsRequire c.cl_meta)
-			-> dot_path p
-		| TEnumDecl ({ e_extern = true } as e) when not (Meta.has Meta.JsRequire e.e_meta)
-			-> dot_path p
-		| _ -> s_path ctx p);
+		| TEnumDecl ({ e_extern = true } as e) when not (Meta.has Meta.JsRequire e.e_meta) ->
+			dot_path e.e_path
+		| TClassDecl c ->
+			let p = get_generated_class_path c in
+			if c.cl_extern && not (Meta.has Meta.JsRequire c.cl_meta) then
+				dot_path p
+			else
+				s_path ctx p
+		| _ ->
+			s_path ctx (t_path t)
+	);
 	ctx
 
 let gen_single_expr ctx e expr =
@@ -1747,11 +1815,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

+ 36 - 20
src/generators/genjvm.ml

@@ -36,6 +36,9 @@ open JvmBuilder
 
 (* hacks *)
 
+let is_really_int t =
+	not (is_nullable t) && ExtType.is_int (follow t)
+
 let rec pow a b = match b with
 	| 0 -> Int32.one
 	| 1 -> a
@@ -82,6 +85,18 @@ let find_overload map_type c cf el =
 	in
 	loop (cf :: cf.cf_overloads)
 
+let filter_overloads candidates =
+	match Overloads.Resolution.reduce_compatible candidates with
+	| [_,_,(c,cf)] -> Some(c,cf)
+	| [] -> None
+	| ((_,_,(c,cf)) :: _) (* as resolved *) ->
+		(* let st = s_type (print_context()) in
+		print_endline (Printf.sprintf "Ambiguous overload for %s(%s)" name (String.concat ", " (List.map (fun e -> st e.etype) el)));
+		List.iter (fun (_,t,(c,cf)) ->
+			print_endline (Printf.sprintf "\tCandidate: %s.%s(%s)" (s_type_path c.cl_path) cf.cf_name (st t));
+		) resolved; *)
+		Some(c,cf)
+
 let find_overload_rec' is_ctor map_type c name el =
 	let candidates = ref [] in
 	let has_function t1 (_,t2,_) =
@@ -114,16 +129,7 @@ let find_overload_rec' is_ctor map_type c name el =
 		end;
 	in
 	loop map_type c;
-	match Overloads.Resolution.reduce_compatible (List.rev !candidates) with
-	| [_,_,(c,cf)] -> Some(c,cf)
-	| [] -> None
-	| ((_,_,(c,cf)) :: _) (* as resolved *) ->
-		(* let st = s_type (print_context()) in
-		print_endline (Printf.sprintf "Ambiguous overload for %s(%s)" name (String.concat ", " (List.map (fun e -> st e.etype) el)));
-		List.iter (fun (_,t,(c,cf)) ->
-			print_endline (Printf.sprintf "\tCandidate: %s.%s(%s)" (s_type_path c.cl_path) cf.cf_name (st t));
-		) resolved; *)
-		Some(c,cf)
+	filter_overloads (List.rev !candidates)
 
 let find_overload_rec is_ctor map_type c cf el =
 	if Meta.has Meta.Overload cf.cf_meta || cf.cf_overloads <> [] then
@@ -203,6 +209,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)
@@ -577,11 +584,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
@@ -1275,12 +1279,12 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 		| OpAssignOp op ->
 			let jsig1 = jsignature_of_type e1.etype in
 			begin match op,(Texpr.skip e1).eexpr,(Texpr.skip e2).eexpr with
-			| OpAdd,TLocal v,TConst (TInt i32) when ExtType.is_int v.v_type && in_range false Int8Range (Int32.to_int i32) && self#var_slot_is_in_int8_range v->
+			| OpAdd,TLocal v,TConst (TInt i32) when is_really_int v.v_type && in_range false Int8Range (Int32.to_int i32) && self#var_slot_is_in_int8_range v->
 				let slot,load,_ = self#get_local v in
 				let i = Int32.to_int i32 in
 				code#iinc slot i;
 				if ret <> RVoid then load();
-			| OpSub,TLocal v,TConst (TInt i32) when ExtType.is_int v.v_type && in_range false Int8Range (-Int32.to_int i32) && self#var_slot_is_in_int8_range v ->
+			| OpSub,TLocal v,TConst (TInt i32) when is_really_int v.v_type && in_range false Int8Range (-Int32.to_int i32) && self#var_slot_is_in_int8_range v ->
 				let slot,load,_ = self#get_local v in
 				let i = -Int32.to_int i32 in
 				code#iinc slot i;
@@ -1298,7 +1302,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 
 	method unop ret op flag e =
 		match op,(Texpr.skip e).eexpr with
-		| (Increment | Decrement),TLocal v when ExtType.is_int v.v_type && self#var_slot_is_in_int8_range v ->
+		| (Increment | Decrement),TLocal v when is_really_int v.v_type && self#var_slot_is_in_int8_range v ->
 			let slot,load,_ = self#get_local v in
 			if flag = Postfix && ret <> RVoid then load();
 			code#iinc slot (if op = Increment then 1 else -1);
@@ -1510,6 +1514,14 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 				Error.error (Printf.sprintf "Bad __array__ type: %s" (s_type (print_context()) tr)) e1.epos;
 			end
 		| TField(e1,FStatic(c,({cf_kind = Method (MethNormal | MethInline)} as cf))) ->
+			let c,cf = match cf.cf_overloads with
+				| [] -> c,cf
+				| _ -> match filter_overloads (find_overload (fun t -> t) c cf el) with
+					| None ->
+						Error.error "Could not find overload" e1.epos
+					| Some(c,cf) ->
+						c,cf
+			in
 			let tl,tr = self#call_arguments cf.cf_type el in
 			jm#invokestatic c.cl_path cf.cf_name (method_sig tl tr);
 			tr
@@ -1837,7 +1849,9 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 			let _,load,_ = self#get_local v in
 			load()
 		| TTypeExpr mt ->
-			self#type_expr (jsignature_of_type (type_of_module_type mt))
+			let t = type_of_module_type mt in
+			if ExtType.is_void (follow t) then self#basic_type_path "Void"
+			else self#type_expr (jsignature_of_type t)
 		| TUnop(op,flag,e1) ->
 			begin match op with
 			| Not | Neg | NegBits when ret = RVoid -> self#texpr ret e1
@@ -2761,7 +2775,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 () ->

+ 126 - 34
src/generators/genphp7.ml

@@ -178,20 +178,10 @@ end
 *)
 let is_keyword str = Hashtbl.mem php_keywords_tbl (String.lowercase str)
 
-(**
-	Check if specified type is Void
-*)
-let is_void_type t = match follow t with TAbstract ({ a_path = void_type_path }, _) -> true | _ -> false
-
-(**
-	Check if specified type is Bool
-*)
-let is_bool_type t = match follow t with TAbstract ({ a_path = bool_type_path }, _) -> true | _ -> false
-
 (**
 	Check if specified type is php.NativeArray
 *)
-let is_native_array_type t = match follow t with TAbstract ({ a_path = native_array_type_path }, _) -> true | _ -> false
+let is_native_array_type t = match follow t with TAbstract ({ a_path = tp }, _) -> tp = native_array_type_path | _ -> false
 
 (**
 	If `name` is not a reserved word in PHP then `name` is returned as-is.
@@ -298,17 +288,12 @@ let is_int expr = match follow expr.etype with TAbstract ({ a_path = ([], "Int")
 (**
 	Check if specified expression is of `Float` type
 *)
-let is_float expr = match follow expr.etype with TAbstract ({ a_path = ([], "Float") }, _) -> true | _ -> false
-
-(**
-	Check if specified type is String
-*)
-let is_string_type t = match follow t with TInst ({ cl_path = ([], "String") }, _) -> true | _ -> false
+let is_float expr = ExtType.is_float (follow expr.etype)
 
 (**
 	Check if specified expression is of String type
 *)
-let is_string expr = is_string_type expr.etype
+let is_string expr = ExtType.is_string (follow expr.etype)
 
 (**
 	Check if specified type is Array
@@ -393,6 +378,17 @@ let needs_dereferencing for_assignment expr =
 		| TArray (target_expr, _) -> is_create target_expr
 		| _ -> false
 
+(**
+	Check if the value of `expr` needs to be stored to a temporary variable to be
+	reused.
+*)
+let rec needs_temp_var expr =
+	match (reveal_expr_with_parenthesis expr).eexpr with
+		| TConst _ | TLocal _ -> false
+		| TField (target, FInstance _) | TField (target, FStatic _) -> needs_temp_var target
+		| TArray (target, index) -> needs_temp_var target || needs_temp_var index
+		| _ -> true
+
 (**
 	@return (arguments_list, return_type)
 *)
@@ -799,7 +795,7 @@ let field_name field =
 *)
 let is_std_is expr =
 	match expr.eexpr with
-		| TField (_, FStatic ({ cl_path = path }, { cf_name = "is" })) -> path = boot_type_path || path = std_type_path
+		| TField (_, FStatic ({ cl_path = path }, { cf_name = ("is" | "isOfType") })) -> path = boot_type_path || path = std_type_path
 		| _ -> false
 
 (**
@@ -1625,7 +1621,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 					self#write ")"
 				| TObjectDecl fields -> self#write_expr_object_declaration fields
 				| TArrayDecl exprs -> self#write_expr_array_decl exprs
-				| TCall (target, [arg1; arg2]) when is_std_is target && instanceof_compatible arg1 arg2 -> self#write_expr_syntax_instanceof [arg1; arg2]
+				| TCall (target, [arg1; arg2]) when is_std_is target -> self#write_expr_std_is target arg1 arg2
 				| TCall (_, [arg]) when is_native_struct_array_cast expr && is_object_declaration arg ->
 					(match (reveal_expr arg).eexpr with TObjectDecl fields -> self#write_assoc_array_decl fields | _ -> fail self#pos __POS__)
 				| TCall ({ eexpr = TIdent name}, args) when is_magic expr ->
@@ -2640,6 +2636,44 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 					write_args self#write self#write_expr args;
 					self#write ")"
 				end
+		(**
+			Writes `Std.isOfType(value, type)` to output buffer
+		*)
+		method write_expr_std_is target_expr value_expr type_expr =
+			if instanceof_compatible value_expr type_expr then
+				self#write_expr_syntax_instanceof [value_expr; type_expr]
+			else
+				let no_optimisation() =
+					self#write_expr_call target_expr [value_expr; type_expr]
+				in
+				match (reveal_expr type_expr).eexpr with
+					| TTypeExpr mtype ->
+						let t = follow (type_of_module_type mtype) in
+						if ExtType.is_string t then
+							begin
+								self#write "is_string(";
+								self#write_expr value_expr;
+								self#write ")"
+							end
+						else if ExtType.is_bool t then
+							begin
+								self#write "is_bool(";
+								self#write_expr value_expr;
+								self#write ")"
+							end
+						else if ExtType.is_float t && not (needs_temp_var value_expr) then
+							begin
+								self#write "(is_float(";
+								self#write_expr value_expr;
+								self#write ") || is_int(";
+								self#write_expr value_expr;
+								self#write "))"
+							end
+						else
+							no_optimisation()
+					| _ ->
+						no_optimisation()
+
 		(**
 			Writes a name of a function or a constant from global php namespace
 		*)
@@ -2886,6 +2920,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"
@@ -3076,10 +3116,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
 		*)
@@ -3095,15 +3135,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.
@@ -3166,7 +3233,7 @@ class enum_builder ctx (enm:tenum) =
 			E.g. "class SomeClass extends Another implements IFace"
 		*)
 		method private write_declaration =
-			self#write_doc (DocClass enm.e_doc);
+			self#write_doc (DocClass (gen_doc_text_opt enm.e_doc));
 			writer#write ("class " ^ self#get_name ^ " extends " ^ (writer#use hxenum_type_path))
 		(**
 			Writes type body to output buffer.
@@ -3195,7 +3262,7 @@ class enum_builder ctx (enm:tenum) =
 					| _ -> fail field.ef_pos __POS__
 			in
 			writer#indent 1;
-			self#write_doc (DocMethod (args, TEnum (enm, []), field.ef_doc));
+			self#write_doc (DocMethod (args, TEnum (enm, []), (gen_doc_text_opt field.ef_doc)));
 			writer#write_with_indentation ("static public function " ^ name ^ " (");
 			write_args writer#write (writer#write_arg true) args;
 			writer#write ") {\n";
@@ -3316,6 +3383,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`
 		*)
@@ -3361,7 +3453,7 @@ class class_builder ctx (cls:tclass) =
 			E.g. "class SomeClass extends Another implements IFace"
 		*)
 		method private write_declaration =
-			self#write_doc (DocClass cls.cl_doc);
+			self#write_doc (DocClass (gen_doc_text_opt cls.cl_doc));
 			if self#is_final then writer#write "final ";
 			writer#write (if cls.cl_interface then "interface " else "class ");
 			writer#write self#get_name;
@@ -3594,7 +3686,7 @@ class class_builder ctx (cls:tclass) =
 		*)
 		method private write_var field is_static =
 			writer#indent 1;
-			self#write_doc (DocVar (writer#use_t field.cf_type, field.cf_doc));
+			self#write_doc (DocVar (writer#use_t field.cf_type, (gen_doc_text_opt field.cf_doc)));
 			writer#write_indentation;
 			if is_static then writer#write "static ";
 			let visibility = get_visibility field.cf_meta in
@@ -3621,7 +3713,7 @@ class class_builder ctx (cls:tclass) =
 				| Some expr when not (is_constant expr) -> ()
 				| Some expr ->
 					writer#indent 1;
-					self#write_doc (DocVar (writer#use_t field.cf_type, field.cf_doc));
+					self#write_doc (DocVar (writer#use_t field.cf_type, (gen_doc_text_opt field.cf_doc)));
 					writer#write_with_indentation ("const " ^ (field_name field) ^ " = ");
 					writer#write_expr expr;
 					writer#write ";\n"
@@ -3634,20 +3726,20 @@ class class_builder ctx (cls:tclass) =
 			writer#indent 1;
 			let (args, return_type) = get_function_signature field in
 			List.iter (fun (arg_name, _, _) -> writer#declared_local_var arg_name) args;
-			self#write_doc (DocMethod (args, return_type, field.cf_doc));
+			self#write_doc (DocMethod (args, return_type, (gen_doc_text_opt 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__
 		(**
@@ -3660,7 +3752,7 @@ class class_builder ctx (cls:tclass) =
 			writer#indent 1;
 			let (args, return_type) = get_function_signature field in
 			List.iter (fun (arg_name, _, _) -> writer#declared_local_var arg_name) args;
-			self#write_doc (DocMethod (args, return_type, field.cf_doc));
+			self#write_doc (DocMethod (args, return_type, (gen_doc_text_opt field.cf_doc)));
 			writer#write_with_indentation ((get_visibility field.cf_meta) ^ " function " ^ (field_name field));
 			(match field.cf_expr with
 				| None -> (* interface *)

+ 51 - 53
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
 
@@ -2440,6 +2434,10 @@ module Generator = struct
 				spr ctx "        self.__dict__ = fields\n";
 				spr ctx "    def __repr__(self):\n";
 				spr ctx "        return repr(self.__dict__)\n";
+				spr ctx "    def __contains__(self, item):\n";
+				spr ctx "        return item in self.__dict__\n";
+				spr ctx "    def __getitem__(self, item):\n";
+				spr ctx "        return self.__dict__[item]\n";
 				spr ctx "    def __getattr__(self, name):\n";
 				spr ctx "        if (self._hx_disable_getattr):\n";
 				spr ctx "            raise AttributeError('field does not exist')\n";

+ 1 - 1
src/generators/genswf9.ml

@@ -1405,7 +1405,7 @@ and gen_call ctx retval e el r =
 		gen_expr ctx true e;
 		gen_expr ctx true t;
 		write ctx (HOp A3OIs)
-	| TField (_,FStatic ({ cl_path = [],"Std" },{ cf_name = "is" })),[e;{ eexpr = TTypeExpr (TClassDecl _) } as t] ->
+	| TField (_,FStatic ({ cl_path = [],"Std" },{ cf_name = ("is" | "isOfType") })),[e;{ eexpr = TTypeExpr (TClassDecl _) } as t] ->
 		(* fast inlining of Std.is with known values *)
 		gen_expr ctx true e;
 		gen_expr ctx true t;

+ 2 - 0
src/generators/hl2c.ml

@@ -87,6 +87,8 @@ let keywords =
 	"auto";"break";"case";"char";"const";"continue";"default";"do";"double";"else";"enum";"extern";"float";"for";"goto";
 	"if";"int";"long";"register";"return";"short";"signed";"sizeof";"static";"struct";"switch";"typedef";"union";"unsigned";
 	"void";"volatile";"while";
+	(* Values *)
+	"NULL";"true";"false";
 	(* MS specific *)
 	"__asm";"dllimport2";"__int8";"naked2";"__based1";"__except";"__int16";"__stdcall";"__cdecl";"__fastcall";"__int32";
 	"thread2";"__declspec";"__finally";"__int64";"__try";"dllexport2";"__inline";"__leave";"asm";

+ 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;

+ 1 - 1
src/macro/eval/evalDebugMisc.ml

@@ -81,7 +81,7 @@ exception Parse_expr_error of string
 let parse_expr ctx s p =
 	let error s = raise (Parse_expr_error s) in
 	match ParserEntry.parse_expr_string (ctx.curapi.get_com()).Common.defines s p error true with
-	| ParseSuccess data | ParseDisplayFile(data,_) -> data
+	| ParseSuccess(data,_,_) -> data
 	| ParseError(_,(msg,_),_) -> error (Parser.error_msg msg)
 
 (* Vars *)

+ 27 - 20
src/macro/eval/evalDebugSocket.ml

@@ -14,6 +14,32 @@ open EvalDebugMisc
 
 (* Printing *)
 
+
+let handle_in_temp_thread ctx env f =
+	let channel = Event.new_channel () in
+	let _ = EvalThread.spawn ctx (fun () ->
+		let eval = get_eval ctx in
+		eval.env <- Some env;
+		let v = try
+			f()
+		with
+		| RunTimeException(v,stack,p) ->
+			prerr_endline (EvalExceptions.get_exc_error_message ctx v stack p);
+			vnull
+		| exc ->
+			prerr_endline (Printexc.to_string exc);
+			vnull
+		in
+		Event.poll (Event.send channel v)
+	) in
+	Event.sync (Event.receive channel)
+
+let thread_safe_value_string env v =
+	let ctx = get_ctx() in
+	match handle_in_temp_thread ctx env (fun () -> VString (EvalPrinting.s_value 0 v)) with
+	| VString s -> s.sstring
+	| _ -> assert false
+
 let var_to_json name value vio env =
 	let jv t v num_children =
 		let id = if num_children = 0 then 0 else (get_ctx()).debug.debug_context#add_value value env in
@@ -95,7 +121,7 @@ let var_to_json name value vio env =
 		| VArray va -> jv "Array" (array_elems (EvalArray.to_list va)) va.alength
 		| VVector vv -> jv "Vector" (array_elems (Array.to_list vv)) (Array.length vv)
 		| VInstance vi ->
-			let class_name () = EvalDebugMisc.safe_call env.env_eval EvalPrinting.value_string v in
+			let class_name () = thread_safe_value_string env v in
 			let num_children,class_name = match vi.ikind with
 			| IMutex _ -> 1,class_name()
 			| IThread _ -> 1,class_name()
@@ -299,25 +325,6 @@ let output_inner_vars v env =
 	let vars = List.map (fun (n,v) -> var_to_json n v None env) children in
 	JArray vars
 
-let handle_in_temp_thread ctx env f =
-	let channel = Event.new_channel () in
-	let _ = EvalThread.spawn ctx (fun () ->
-		let eval = get_eval ctx in
-		eval.env <- Some env;
-		let v = try
-			f()
-		with
-		| RunTimeException(v,stack,p) ->
-			prerr_endline (EvalExceptions.get_exc_error_message ctx v stack p);
-			vnull
-		| exc ->
-			prerr_endline (Printexc.to_string exc);
-			vnull
-		in
-		Event.poll (Event.send channel v)
-	) in
-	Event.sync (Event.receive channel)
-
 module ValueCompletion = struct
 	let prototype_instance_fields proto =
 		let rec loop acc proto =

+ 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

+ 8 - 1
src/macro/eval/evalHash.ml

@@ -112,7 +112,7 @@ let key___init__ = hash "__init__"
 let key_new = hash "new"
 let key_questionmark = hash "?"
 let key_haxe_StackItem = hash "haxe.StackItem"
-let key_sys_net__Socket_NativeSocket = hash "sys.net._Socket.NativeSocket"
+let key_eval_vm_NativeSocket = hash "eval.vm.NativeSocket"
 let key_ip = hash "ip"
 let key_port = hash "port"
 let key_sys_net_Socket = hash "sys.net.Socket"
@@ -130,3 +130,10 @@ let key_sys_net_Mutex = hash "sys.thread.Mutex"
 let key_sys_net_Lock = hash "sys.thread.Lock"
 let key_sys_net_Tls = hash "sys.thread.Tls"
 let key_sys_net_Deque = hash "sys.thread.Deque"
+
+let key_mbedtls_Config = hash "mbedtls.Config"
+let key_mbedtls_CtrDrbg = hash "mbedtls.CtrDrbg"
+let key_mbedtls_Entropy = hash "mbedtls.Entropy"
+let key_mbedtls_PkContext = hash "mbedtls.PkContext"
+let key_mbedtls_Ssl = hash "mbedtls.Ssl"
+let key_mbedtls_X509Crt = hash "mbedtls.X509Crt"

+ 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
 

+ 202 - 0
src/macro/eval/evalSsl.ml

@@ -0,0 +1,202 @@
+open EvalHash
+open EvalValue
+open EvalEncode
+open EvalDecode
+open EvalExceptions
+open Mbedtls
+
+let as_x509_crt vthis = match vthis with
+	| VInstance {ikind = IMbedtlsX509Crt i} -> i
+	| _ -> unexpected_value vthis "X509Crt"
+
+let as_config vthis = match vthis with
+	| VInstance {ikind = IMbedtlsConfig i} -> i
+	| _ -> unexpected_value vthis "Config"
+
+let as_socket vthis = match vthis with
+	| VInstance {ikind = ISocket sock} -> sock
+	| _ -> unexpected_value vthis "NativeSocket"
+
+let as_ctr_drbg vthis = match vthis with
+	| VInstance {ikind = IMbedtlsCtrDrbg i} -> i
+	| _ -> unexpected_value vthis "CtrDrbg"
+
+let as_entropy vthis = match vthis with
+	| VInstance {ikind = IMbedtlsEntropy i} -> i
+	| _ -> unexpected_value vthis "Entropy"
+
+let as_pk_context vthis = match vthis with
+	| VInstance {ikind = IMbedtlsPkContext i} -> i
+	| _ -> unexpected_value vthis "PkContext"
+
+let as_ssl vthis = match vthis with
+	| VInstance {ikind = IMbedtlsSsl ctx} -> ctx
+	| _ -> unexpected_value vthis "Ssl"
+
+let init_constructors add =
+	add key_mbedtls_Config
+		(fun _ ->
+			let cfg = mbedtls_ssl_config_init() in
+			encode_instance key_mbedtls_Config ~kind:(IMbedtlsConfig cfg)
+		);
+	add key_mbedtls_CtrDrbg
+		(fun _ ->
+			let ctr = mbedtls_ctr_drbg_init() in
+			encode_instance key_mbedtls_CtrDrbg ~kind:(IMbedtlsCtrDrbg ctr)
+		);
+	add key_mbedtls_Entropy
+		(fun _ ->
+			let entropy = mbedtls_entropy_init() in
+			encode_instance key_mbedtls_Entropy ~kind:(IMbedtlsEntropy entropy)
+		);
+	add key_mbedtls_PkContext
+		(fun _ ->
+			let pk = mbedtls_pk_init() in
+			encode_instance key_mbedtls_PkContext ~kind:(IMbedtlsPkContext pk)
+		);
+	add key_mbedtls_Ssl
+		(fun _ ->
+			let ssl = mbedtls_ssl_init() in
+			encode_instance key_mbedtls_Ssl ~kind:(IMbedtlsSsl ssl)
+		);
+	add key_mbedtls_X509Crt
+		(fun _ ->
+			let cert = mbedtls_x509_crt_init() in
+			encode_instance key_mbedtls_X509Crt ~kind:(IMbedtlsX509Crt cert)
+		)
+
+let init_fields init_fields builtins =
+	let socket_send socket bytes =
+		Unix.send socket bytes 0 (Bytes.length bytes) []
+	in
+	let socket_receive socket bytes =
+		Unix.recv socket bytes 0 (Bytes.length bytes) []
+	in
+	let native_cert this =
+		as_x509_crt (EvalField.field this (hash "native"))
+	in
+	init_fields builtins (["sys";"ssl"],"Certificate") [] [
+		"get_altNames",vifun0 (fun this ->
+			let x509_crt = native_cert this  in
+			let a = hx_cert_get_alt_names x509_crt in
+			VArray (EvalArray.create (Array.map encode_string a))
+		);
+		"get_notAfter",vifun0 (fun this ->
+			let x509_crt = native_cert this  in
+			let f = hx_cert_get_notafter x509_crt in
+			encode_instance key_Date ~kind:(IDate f)
+		);
+		"get_notBefore",vifun0 (fun this ->
+			let x509_crt = native_cert this in
+			let f = hx_cert_get_notbefore x509_crt in
+			encode_instance key_Date ~kind:(IDate f)
+		);
+		"issuer",vifun1 (fun this field ->
+			let x509_crt = native_cert this in
+			match hx_cert_get_issuer x509_crt (decode_string field) with
+			| Some s -> encode_string s
+			| None -> vnull
+		);
+		"subject",vifun1 (fun this field ->
+			let x509_crt = native_cert this in
+			match hx_cert_get_subject x509_crt (decode_string field) with
+			| Some s -> encode_string s
+			| None -> vnull
+		);
+	];
+	init_fields builtins (["sys";"ssl"],"Mbedtls") [
+		"loadDefaults",vfun1 (fun this ->
+			vint (hx_cert_load_defaults (as_x509_crt this));
+		);
+		"setSocket",vfun2 (fun this socket ->
+			let ctx = as_ssl this in
+			let socket = as_socket socket in
+			mbedtls_ssl_set_bio ctx socket socket_send socket_receive;
+			vnull
+		);
+	] [];
+	init_fields builtins (["mbedtls"],"X509Crt") [] [
+		"next",vifun0 (fun this ->
+			match mbedtls_x509_next (as_x509_crt this) with
+			| None -> vnull
+			| Some cert -> encode_instance key_mbedtls_X509Crt ~kind:(IMbedtlsX509Crt cert)
+		);
+		"parse",vifun1 (fun this bytes ->
+			vint (mbedtls_x509_crt_parse (as_x509_crt this) (decode_bytes bytes));
+		);
+		"parse_file",vifun1 (fun this path ->
+			vint (mbedtls_x509_crt_parse_file (as_x509_crt this) (decode_string path));
+		);
+		"parse_path",vifun1 (fun this path ->
+			vint (mbedtls_x509_crt_parse_path (as_x509_crt this) (decode_string path));
+		);
+	];
+	init_fields builtins (["mbedtls"],"Config") [] [
+		"authmode",vifun1 (fun this authmode ->
+			mbedtls_ssl_config_authmode (as_config this) (decode_int authmode);
+			vnull;
+		);
+		"ca_chain",vifun1 (fun this ca_chain ->
+			mbedtls_ssl_conf_ca_chain (as_config this) (as_x509_crt ca_chain);
+			vnull;
+		);
+		"defaults",vifun3 (fun this endpoint transport preset ->
+			vint (mbedtls_ssl_config_defaults (as_config this) (decode_int endpoint) (decode_int transport) (decode_int preset));
+		);
+		"rng",vifun1(fun this p_rng ->
+			mbedtls_ssl_config_rng (as_config this) (as_ctr_drbg p_rng);
+			vnull
+		)
+	];
+	init_fields builtins (["mbedtls"],"CtrDrbg") [] [
+		"random",vifun2 (fun this output output_len ->
+			vint (mbedtls_ctr_drbg_random (as_ctr_drbg this) (decode_bytes output) (decode_int output_len));
+		);
+		"seed",vifun2(fun this entropy custom ->
+			vint (mbedtls_ctr_drbg_seed (as_ctr_drbg this) (as_entropy entropy) (match custom with VString s -> Some s.sstring | _ -> None))
+		)
+	];
+	init_fields builtins (["mbedtls"],"Error") [
+		"strerror",vfun1 (fun code -> encode_string (mbedtls_strerror (decode_int code)));
+	] [];
+	init_fields builtins (["mbedtls"],"PkContext") [] [
+		"parse_key",vifun2 (fun this key password ->
+			vint (mbedtls_pk_parse_key (as_pk_context this) (decode_bytes key) (match password with VNull -> None | _ -> Some (decode_string password)));
+		);
+		"parse_keyfile",vifun2 (fun this path password ->
+			vint (mbedtls_pk_parse_keyfile (as_pk_context this) (decode_string path) (match password with VNull -> None | _ -> Some (decode_string password)));
+		);
+		"parse_public_key",vifun1 (fun this key ->
+			vint (mbedtls_pk_parse_public_key (as_pk_context this) (decode_bytes key));
+		);
+		"parse_public_keyfile",vifun1 (fun this path ->
+			vint (mbedtls_pk_parse_public_keyfile (as_pk_context this) (decode_string path));
+		);
+	];
+	init_fields builtins (["mbedtls"],"Ssl") [] [
+		"get_peer_cert",vifun0 (fun this ->
+			match mbedtls_ssl_get_peer_cert (as_ssl this) with
+			| None -> vnull
+			| Some cert -> encode_instance key_mbedtls_X509Crt ~kind:(IMbedtlsX509Crt cert)
+		);
+		"handshake",vifun0 (fun this ->
+			vint (mbedtls_ssl_handshake (as_ssl this));
+		);
+		"read",vifun3(fun this buf pos len ->
+			vint (mbedtls_ssl_read (as_ssl this) (decode_bytes buf) (decode_int pos) (decode_int len);)
+		);
+		"set_hostname",vifun1 (fun this hostname ->
+			vint (mbedtls_ssl_set_hostname (as_ssl this) (decode_string hostname));
+		);
+		"setup",vifun1 (fun this conf ->
+			vint (mbedtls_ssl_setup (as_ssl this) (as_config conf))
+		);
+		"write",vifun3(fun this buf pos len ->
+			vint (mbedtls_ssl_write (as_ssl this) (decode_bytes buf) (decode_int pos) (decode_int len);)
+		);
+	];
+	let statics a = List.map (fun (s,i) -> s,vint i) (Array.to_list a) in
+	init_fields builtins (["mbedtls"],"SslAuthmode") (statics (hx_get_ssl_authmode_flags())) [];
+	init_fields builtins (["mbedtls"],"SslEndpoint") (statics (hx_get_ssl_endpoint_flags())) [];
+	init_fields builtins (["mbedtls"],"SslPreset") (statics (hx_get_ssl_preset_flags())) [];
+	init_fields builtins (["mbedtls"],"SslTransport") (statics (hx_get_ssl_transport_flags())) [];

+ 23 - 18
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
 	)
 
@@ -1999,7 +1999,7 @@ module StdSocket = struct
 	let accept = vifun0 (fun vthis ->
 		let this = this vthis in
 		let socket,_ = catch_unix_error Unix.accept this in
-		encode_instance key_sys_net__Socket_NativeSocket ~kind:(ISocket socket)
+		encode_instance key_eval_vm_NativeSocket ~kind:(ISocket socket)
 	)
 
 	let bind = vifun2 (fun vthis host port ->
@@ -2145,12 +2145,14 @@ module StdSocket = struct
 end
 
 module StdStd = struct
-	let is' = vfun2 (fun v t -> match t with
+	let isOfType = vfun2 (fun v t -> match t with
 		| VNull -> vfalse
 		| VPrototype proto -> vbool (is v proto.ppath)
 		| _ -> vfalse
 	)
 
+	let is' = isOfType
+
 	let downcast = vfun2 (fun v t -> match t with
 		| VPrototype proto ->
 			if is v proto.ppath then v else vnull
@@ -2190,7 +2192,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 +2290,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 +2322,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
@@ -3175,9 +3177,9 @@ let init_constructors builtins =
 				encode_instance key_sys_io__Process_NativeProcess ~kind:(IProcess (try Process.run cmd args with Failure msg -> exc_string msg))
 			| _ -> assert false
 		);
-	add key_sys_net__Socket_NativeSocket
+	add key_eval_vm_NativeSocket
 		(fun _ ->
-			encode_instance key_sys_net__Socket_NativeSocket ~kind:(ISocket ((catch_unix_error Unix.socket Unix.PF_INET Unix.SOCK_STREAM) 0))
+			encode_instance key_eval_vm_NativeSocket ~kind:(ISocket ((catch_unix_error Unix.socket Unix.PF_INET Unix.SOCK_STREAM) 0))
 		);
 	add key_haxe_zip_Compress
 		(fun vl -> match vl with
@@ -3228,7 +3230,8 @@ let init_constructors builtins =
 	add key_sys_net_Deque
 		(fun _ ->
 			encode_instance key_sys_net_Deque ~kind:(IDeque (Deque.create()))
-		)
+		);
+	EvalSsl.init_constructors add
 
 let init_empty_constructors builtins =
 	let h = builtins.empty_constructor_builtins in
@@ -3236,7 +3239,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))));
@@ -3524,7 +3527,7 @@ let init_standard_library builtins =
 		"encode",StdSha1.encode;
 		"make",StdSha1.make;
 	] [];
-	init_fields builtins (["sys";"net";"_Socket"],"NativeSocket") [
+	init_fields builtins (["eval";"vm"],"NativeSocket") [
 		"select",StdSocket.select;
 	] [
 		"accept",StdSocket.accept;
@@ -3548,6 +3551,7 @@ let init_standard_library builtins =
 		"instance",StdStd.instance;
 		"int",StdStd.int;
 		"is",StdStd.is';
+		"isOfType",StdStd.isOfType;
 		"parseFloat",StdStd.parseFloat;
 		"parseInt",StdStd.parseInt;
 		"string",StdStd.string;
@@ -3660,4 +3664,5 @@ let init_standard_library builtins =
 	] [
 		"addChar",StdUtf8.addChar;
 		"toString",StdUtf8.toString;
-	]
+	];
+	EvalSsl.init_fields init_fields builtins

+ 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;

+ 19 - 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 = {
@@ -165,6 +165,13 @@ and vinstance_kind =
 	| ITypeDecl of Type.module_type
 	| ILazyType of (Type.tlazy ref) * (unit -> value)
 	| IRef of Obj.t
+	(* SSL *)
+	| IMbedtlsConfig of Mbedtls.mbedtls_ssl_config
+	| IMbedtlsCtrDrbg of Mbedtls.mbedtls_ctr_drbg_context
+	| IMbedtlsEntropy of Mbedtls.mbedtls_entropy_context
+	| IMbedtlsPkContext of Mbedtls.mbedtls_pk_context
+	| IMbedtlsSsl of Mbedtls.mbedtls_ssl_context
+	| IMbedtlsX509Crt of Mbedtls.mbedtls_x509_crt
 	| INormal
 
 and vinstance = {

+ 23 - 8
src/macro/macroApi.ml

@@ -336,7 +336,7 @@ and encode_field (f:class_field) =
 	encode_obj [
 		"name",encode_placed_name f.cff_name;
 		"name_pos", encode_pos (pos f.cff_name);
-		"doc", null encode_string f.cff_doc;
+		"doc", null encode_string (gen_doc_text_opt f.cff_doc);
 		"pos", encode_pos f.cff_pos;
 		"kind", encode_enum IField tag pl;
 		"meta", encode_meta_content f.cff_meta;
@@ -673,6 +673,8 @@ and decode_meta_entry v =
 
 and decode_meta_content m = decode_opt_array decode_meta_entry m
 
+and decode_doc = opt (fun s -> { doc_own = Some (decode_string s); doc_inherited = [] })
+
 and decode_field v =
 	let fkind = match decode_enum (field v "kind") with
 		| 0, [t;e] ->
@@ -687,7 +689,7 @@ and decode_field v =
 	let pos = decode_pos (field v "pos") in
 	{
 		cff_name = (decode_string (field v "name"),decode_pos_default (field v "name_pos") pos);
-		cff_doc = opt decode_string (field v "doc");
+		cff_doc = decode_doc (field v "doc");
 		cff_pos = pos;
 		cff_kind = fkind;
 		cff_access = List.map decode_access (opt_list decode_array (field v "access"));
@@ -880,7 +882,7 @@ let rec encode_mtype t fields =
 		"module", encode_string (s_type_path i.mt_module.m_path);
 		"isPrivate", vbool i.mt_private;
 		"meta", encode_meta i.mt_meta (fun m -> i.mt_meta <- m);
-		"doc", null encode_string i.mt_doc;
+		"doc", null encode_string (get_own_doc_opt i.mt_doc);
 		"params", encode_type_params i.mt_params;
 	] @ fields)
 
@@ -916,7 +918,7 @@ and encode_efield f =
 		"namePos", encode_pos f.ef_name_pos;
 		"index", vint f.ef_index;
 		"meta", encode_meta f.ef_meta (fun m -> f.ef_meta <- m);
-		"doc", null encode_string f.ef_doc;
+		"doc", null encode_string (get_own_doc_opt f.ef_doc);
 		"params", encode_type_params f.ef_params;
 	]
 
@@ -934,7 +936,7 @@ and encode_cfield f =
 		"kind", encode_field_kind f.cf_kind;
 		"pos", encode_pos f.cf_pos;
 		"namePos",encode_pos f.cf_name_pos;
-		"doc", null encode_string f.cf_doc;
+		"doc", null encode_string (get_own_doc_opt f.cf_doc);
 		"overloads", encode_ref f.cf_overloads (encode_and_map_array encode_cfield) (fun() -> "overloads");
 		"isExtern", vbool (has_class_field_flag f CfExtern);
 		"isFinal", vbool (has_class_field_flag f CfFinal);
@@ -1307,7 +1309,7 @@ let decode_cfield v =
 		cf_type = decode_type (field v "type");
 		cf_pos = decode_pos (field v "pos");
 		cf_name_pos = decode_pos (field v "namePos");
-		cf_doc = opt decode_string (field v "doc");
+		cf_doc = decode_doc (field v "doc");
 		cf_meta = []; (* TODO *)
 		cf_kind = decode_field_kind (field v "kind");
 		cf_params = decode_type_params (field v "params");
@@ -1329,7 +1331,7 @@ let decode_efield v =
 		ef_name_pos = decode_pos (field v "namePos");
 		ef_index = decode_int (field v "index");
 		ef_meta = []; (* TODO *)
-		ef_doc = opt decode_string (field v "doc");
+		ef_doc = decode_doc (field v "doc");
 		ef_params = decode_type_params (field v "params")
 	}
 
@@ -1413,7 +1415,7 @@ let decode_type_def v =
 	let pos = decode_pos (field v "pos") in
 	let isExtern = decode_opt_bool (field v "isExtern") in
 	let fields = List.map decode_field (decode_array (field v "fields")) in
-	let doc = opt decode_string (field v "doc") in
+	let doc = decode_doc (field v "doc") in
 	let mk fl dl =
 		{
 			d_name = name;
@@ -1517,6 +1519,19 @@ let rec make_const e =
 
 let macro_api ccom get_api =
 	[
+		"contains_display_position", vfun1 (fun p ->
+			let p = decode_pos p in
+			let display_pos = DisplayPosition.display_position in
+			let same_file() =
+				let dfile = display_pos#get.pfile in
+				dfile = p.pfile
+				|| (
+					(Filename.is_relative p.pfile || Filename.is_relative dfile)
+					&& (Path.unique_full_path dfile = Path.unique_full_path p.pfile)
+				)
+			in
+			vbool (display_pos#enclosed_in p && same_file())
+		);
 		"current_pos", vfun0 (fun() ->
 			encode_pos (get_api()).pos
 		);

+ 6 - 6
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
@@ -1098,9 +1098,9 @@ module Run = struct
 		let com = ctx.Typecore.com in
 		let config = get_base_config com in
 		with_timer config.detail_times ["other"] (fun () ->
-			let cfl = if config.optimize && config.purity_inference then with_timer config.detail_times ["optimize";"purity-inference"] (fun () -> Purity.infer com) else [] in
-			List.iter (run_on_type ctx config) types;
-			List.iter (fun cf -> cf.cf_meta <- List.filter (fun (m,_,_) -> m <> Meta.Pure) cf.cf_meta) cfl
+			if config.optimize && config.purity_inference then
+				with_timer config.detail_times ["optimize";"purity-inference"] (fun () -> Purity.infer com);
+			List.iter (run_on_type ctx config) types
 		)
 end
 ;;

+ 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");

+ 5 - 7
src/optimization/analyzerTexpr.ml

@@ -1286,12 +1286,10 @@ module Purity = struct
 				end
 			| _ -> ()
 		) com.types;
-		Hashtbl.fold (fun _ node acc ->
+		Hashtbl.iter (fun _ node ->
 			match node.pn_purity with
-			| Pure | MaybePure ->
-				node.pn_field.cf_meta <- (Meta.Pure,[EConst(Ident "true"),node.pn_field.cf_pos],node.pn_field.cf_pos) :: node.pn_field.cf_meta;
-				node.pn_field :: acc
-			| _ ->
-				acc
-		) node_lut [];
+			| Pure | MaybePure when not (List.exists (fun (m,_,_) -> m = Meta.Pure) node.pn_field.cf_meta) ->
+				node.pn_field.cf_meta <- (Meta.Pure,[EConst(Ident "true"),node.pn_field.cf_pos],node.pn_field.cf_pos) :: node.pn_field.cf_meta
+			| _ -> ()
+		) node_lut;
 end

+ 1 - 1
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 =

+ 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;

+ 24 - 2
src/optimization/inline.ml

@@ -124,7 +124,7 @@ let api_inline ctx c field params p =
 	let tint = ctx.com.basic.tint in
 
 	match c.cl_path, field, params with
-	| ([],"Std"),"is",[o;t] | (["js"],"Boot"),"__instanceof",[o;t] when ctx.com.platform = Js ->
+	| ([],"Std"),("is" | "isOfType"),[o;t] | (["js"],"Boot"),"__instanceof",[o;t] when ctx.com.platform = Js ->
 		let is_trivial e =
 			match e.eexpr with
 			| TConst _ | TLocal _ -> true
@@ -244,6 +244,28 @@ let inline_default_config cf t =
 	let tparams = fst tparams @ cf.cf_params in
 	tparams <> [], apply_params tparams tmonos
 
+let inline_config cls_opt cf call_args return_type =
+	match cls_opt with
+	| Some ({cl_kind = KAbstractImpl _}) when Meta.has Meta.Impl cf.cf_meta ->
+		let t = if cf.cf_name = "_new" then
+			return_type
+		else if call_args = [] then
+			error "Invalid abstract implementation function" cf.cf_pos
+		else
+			follow (List.hd call_args).etype
+		in
+		begin match t with
+			| TAbstract(a,pl) ->
+				let has_params = a.a_params <> [] || cf.cf_params <> [] in
+				let monos = List.map (fun _ -> mk_mono()) cf.cf_params in
+				let map_type = fun t -> apply_params a.a_params pl (apply_params cf.cf_params monos t) in
+				Some (has_params,map_type)
+			| _ ->
+				None
+		end
+	| _ ->
+		None
+
 let inline_metadata e meta =
 	let inline_meta e meta = match meta with
 		| (Meta.Deprecated | Meta.Pure),_,_ -> mk (TMeta(meta,e)) e.etype e.epos
@@ -585,7 +607,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

+ 3 - 2
src/optimization/optimizer.ml

@@ -291,11 +291,12 @@ let rec reduce_loop ctx e =
 				(match inl with
 				| None -> reduce_expr ctx e
 				| Some e -> reduce_loop ctx e)
-			| {eexpr = TField(ef,(FStatic(_,cf) | FInstance(_,_,cf)))} when cf.cf_kind = Method MethInline && not (rec_stack_memq cf inline_stack) ->
+			| {eexpr = TField(ef,(FStatic(cl,cf) | FInstance(cl,_,cf)))} when cf.cf_kind = Method MethInline && not (rec_stack_memq cf inline_stack) ->
 				begin match cf.cf_expr with
 				| Some {eexpr = TFunction tf} ->
+					let config = inline_config (Some cl) cf el e.etype in
 					let rt = (match follow e1.etype with TFun (_,rt) -> rt | _ -> assert false) in
-					let inl = (try type_inline ctx cf tf ef el rt None e.epos false with Error (Custom _,_) -> None) in
+					let inl = (try type_inline ctx cf tf ef el rt config e.epos false with Error (Custom _,_) -> None) in
 					(match inl with
 					| None -> reduce_expr ctx e
 					| Some e ->

部分文件因为文件数量过多而无法显示