Browse Source

Merge branch 'development' into out_of_curiosity

# Conflicts:
#	src/codegen/gencommon/castDetect.ml
#	src/codegen/gencommon/gencommon.ml
#	src/codegen/gencommon/initFunction.ml
#	src/context/nativeLibraryHandler.ml
#	src/dune
#	src/generators/gencs.ml
#	src/generators/genjava.ml
#	std/cs/Pointer.hx
Simon Krajewski 1 year ago
parent
commit
63907c3321
100 changed files with 6093 additions and 3938 deletions
  1. 3 10
      .github/workflows/main.yml
  2. 3 10
      extra/github-actions/build-mac.yml
  3. 1 1
      extra/haxelib_src
  4. 1 0
      extra/release-checklist.txt
  5. 1 2
      libs/Makefile
  6. 0 66
      libs/ocamake/ocamake.dsp
  7. 0 29
      libs/ocamake/ocamake.dsw
  8. 0 94
      libs/ocamake/ocamake.html
  9. 0 661
      libs/ocamake/ocamake.ml
  10. 0 21
      libs/swflib/swflib.sln
  11. 0 80
      libs/swflib/swflib.vcproj
  12. 0 31
      libs/ttflib/Makefile
  13. 0 14
      libs/ttflib/dune
  14. 0 139
      libs/ttflib/main.ml
  15. 0 50
      libs/ttflib/tTFCanvasWriter.ml
  16. 0 360
      libs/ttflib/tTFData.ml
  17. 0 49
      libs/ttflib/tTFJsonWriter.ml
  18. 0 688
      libs/ttflib/tTFParser.ml
  19. 0 211
      libs/ttflib/tTFSwfWriter.ml
  20. 0 275
      libs/ttflib/tTFTools.ml
  21. 12 6
      src-json/meta.json
  22. 10 2
      src-json/warning.json
  23. 4 9
      src/codegen/codegen.ml
  24. 1 1
      src/codegen/genxml.ml
  25. 19 7
      src/compiler/args.ml
  26. 49 17
      src/compiler/compilationCache.ml
  27. 5 0
      src/compiler/compilationContext.ml
  28. 50 28
      src/compiler/compiler.ml
  29. 4 1
      src/compiler/displayOutput.ml
  30. 7 6
      src/compiler/displayProcessing.ml
  31. 82 9
      src/compiler/generate.ml
  32. 127 0
      src/compiler/hxb/hxbData.ml
  33. 63 0
      src/compiler/hxb/hxbLib.ml
  34. 2002 0
      src/compiler/hxb/hxbReader.ml
  35. 12 0
      src/compiler/hxb/hxbReaderApi.ml
  36. 2330 0
      src/compiler/hxb/hxbWriter.ml
  37. 18 8
      src/compiler/messageReporting.ml
  38. 0 277
      src/compiler/retyper.ml
  39. 235 94
      src/compiler/server.ml
  40. 2 2
      src/compiler/serverCompilationContext.ml
  41. 6 6
      src/compiler/serverMessage.ml
  42. 53 123
      src/context/common.ml
  43. 28 9
      src/context/commonCache.ml
  44. 1 1
      src/context/display/deprecationCheck.ml
  45. 1 1
      src/context/display/diagnostics.ml
  46. 7 7
      src/context/display/displayEmitter.ml
  47. 43 42
      src/context/display/displayFields.ml
  48. 57 7
      src/context/display/displayJson.ml
  49. 3 4
      src/context/display/displayPath.ml
  50. 15 4
      src/context/display/displayTexpr.ml
  51. 32 8
      src/context/display/displayToplevel.ml
  52. 1 1
      src/context/display/importHandling.ml
  53. 1 1
      src/context/display/syntaxExplorer.ml
  54. 0 11
      src/context/feature.ml
  55. 10 6
      src/context/memory.ml
  56. 6 1
      src/context/nativeLibraryHandler.ml
  57. 63 59
      src/context/typecore.ml
  58. 62 0
      src/core/classPath.ml
  59. 181 0
      src/core/classPaths.ml
  60. 1 1
      src/core/define.ml
  61. 15 0
      src/core/ds/ring.ml
  62. 0 4
      src/core/globals.ml
  63. 11 13
      src/core/json/genjson.ml
  64. 12 1
      src/core/stringHelper.ml
  65. 37 35
      src/core/tFunctions.ml
  66. 24 0
      src/core/tOther.ml
  67. 3 3
      src/core/tPrinting.ml
  68. 15 5
      src/core/tType.ml
  69. 112 71
      src/core/tUnification.ml
  70. 2 2
      src/core/texpr.ml
  71. 1 1
      src/core/timer.ml
  72. 18 0
      src/core/zip_output.ml
  73. 1 1
      src/dune
  74. 1 1
      src/filters/exceptions.ml
  75. 2 3
      src/filters/filters.ml
  76. 2 2
      src/filters/filtersCommon.ml
  77. 14 21
      src/generators/gencpp.ml
  78. 6 5
      src/generators/genhl.ml
  79. 1 1
      src/generators/genhxold.ml
  80. 2 2
      src/generators/genjs.ml
  81. 6 28
      src/generators/genjvm.ml
  82. 2 2
      src/generators/genlua.ml
  83. 6 5
      src/generators/genneko.ml
  84. 5 5
      src/generators/genphp7.ml
  85. 2 2
      src/generators/genpy.ml
  86. 1 1
      src/generators/genshared.ml
  87. 1 56
      src/generators/genswf.ml
  88. 4 4
      src/generators/genswf9.ml
  89. 1 2
      src/macro/eval/evalMain.ml
  90. 1 1
      src/macro/eval/evalPrototype.ml
  91. 0 0
      src/macro/eval/evalStackTrace.ml
  92. 2 2
      src/macro/eval/evalStdLib.ml
  93. 12 15
      src/macro/macroApi.ml
  94. 2 2
      src/optimization/analyzer.ml
  95. 66 38
      src/optimization/dce.ml
  96. 0 2
      src/typing/callUnification.ml
  97. 38 25
      src/typing/fields.ml
  98. 2 2
      src/typing/finalization.ml
  99. 34 11
      src/typing/generic.ml
  100. 17 14
      src/typing/macroContext.ml

+ 3 - 10
.github/workflows/main.yml

@@ -616,23 +616,16 @@ jobs:
       - name: Install dependencies
         env:
           # For compatibility with macOS 10.13
-          ZLIB_VERSION: 1.3
+          ZLIB_VERSION: 1.3.1
           MBEDTLS_VERSION: 2.28.5
           PCRE2_VERSION: 10.42
         run: |
           set -ex
-          brew uninstall [email protected] || echo
-          brew uninstall [email protected] || echo
-          brew untap local/openssl || echo
-          brew untap local/python2 || echo
           brew update
-          # brew unlink python@2
-          brew bundle --file=tests/Brewfile --no-upgrade || brew link --overwrite awscli
-          brew install libunistring
-          brew install cpanminus
+          brew bundle --file=tests/Brewfile --no-upgrade
           cpanm IPC::System::Simple
           cpanm String::ShellQuote
-          curl -L https://www.zlib.net/zlib-$ZLIB_VERSION.tar.gz | tar xz
+          curl -L https://github.com/madler/zlib/releases/download/v$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz | tar xz
           cd zlib-$ZLIB_VERSION
           ./configure
           make && make install

+ 3 - 10
extra/github-actions/build-mac.yml

@@ -1,23 +1,16 @@
 - name: Install dependencies
   env:
     # For compatibility with macOS 10.13
-    ZLIB_VERSION: 1.3
+    ZLIB_VERSION: 1.3.1
     MBEDTLS_VERSION: 2.28.5
     PCRE2_VERSION: 10.42
   run: |
     set -ex
-    brew uninstall [email protected] || echo
-    brew uninstall [email protected] || echo
-    brew untap local/openssl || echo
-    brew untap local/python2 || echo
     brew update
-    # brew unlink python@2
-    brew bundle --file=tests/Brewfile --no-upgrade || brew link --overwrite awscli
-    brew install libunistring
-    brew install cpanminus
+    brew bundle --file=tests/Brewfile --no-upgrade
     cpanm IPC::System::Simple
     cpanm String::ShellQuote
-    curl -L https://www.zlib.net/zlib-$ZLIB_VERSION.tar.gz | tar xz
+    curl -L https://github.com/madler/zlib/releases/download/v$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz | tar xz
     cd zlib-$ZLIB_VERSION
     ./configure
     make && make install

+ 1 - 1
extra/haxelib_src

@@ -1 +1 @@
-Subproject commit 70ff6b69a5b35049d767056555c0bf7a54e8ad4e
+Subproject commit 98637027327d8cf385d302acaaf104bd6107d2bf

+ 1 - 0
extra/release-checklist.txt

@@ -23,6 +23,7 @@
 	- If everything was working, run the command again without `--dry`
 - Update https://github.com/HaxeFoundation/haxe.org/blob/staging/downloads/versions.json
 - Wait for staging to update, check everything related to release and merge to master
+- Update https://github.com/HaxeFoundation/api.haxe.org/blob/master/theme/templates/topbar.mtt
 
 # Cleanup
 

+ 1 - 2
libs/Makefile

@@ -1,7 +1,7 @@
 OCAMLOPT = ocamlopt
 OCAMLC = ocamlc
 TARGET_FLAG = all
-LIBS=extlib-leftovers extc neko javalib ilib swflib ttflib objsize pcre2 ziplib
+LIBS=extlib-leftovers extc neko javalib ilib swflib objsize pcre2 ziplib
 
 all: $(LIBS)
 $(LIBS):
@@ -14,7 +14,6 @@ clean:
 	$(MAKE) -C javalib clean
 	$(MAKE) -C ilib clean
 	$(MAKE) -C swflib clean
-	$(MAKE) -C ttflib clean
 	$(MAKE) -C objsize clean
 	$(MAKE) -C pcre2 clean
 	$(MAKE) -C ziplib clean

+ 0 - 66
libs/ocamake/ocamake.dsp

@@ -1,66 +0,0 @@
-# Microsoft Developer Studio Project File - Name="ocamake" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) External Target" 0x0106
-
-CFG=ocamake - Win32 Native code
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE 
-!MESSAGE NMAKE /f "ocamake.mak".
-!MESSAGE 
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE 
-!MESSAGE NMAKE /f "ocamake.mak" CFG="ocamake - Win32 Native code"
-!MESSAGE 
-!MESSAGE Possible choices for configuration are:
-!MESSAGE 
-!MESSAGE "ocamake - Win32 Native code" (based on "Win32 (x86) External Target")
-!MESSAGE 
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir ""
-# PROP BASE Intermediate_Dir ""
-# PROP BASE Cmd_Line "ocamake -opt ocamake.dsp -o ocamake.exe"
-# PROP BASE Rebuild_Opt "-all"
-# PROP BASE Target_File "ocamake_opt.exe"
-# PROP BASE Bsc_Name ""
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir ""
-# PROP Intermediate_Dir ""
-# PROP Cmd_Line "ocamake str.cmxa unix.cmxa -opt ocamake.dsp -o ocadbg.exe"
-# PROP Rebuild_Opt "-all"
-# PROP Target_File "ocadbg.exe"
-# PROP Bsc_Name ""
-# PROP Target_Dir ""
-# Begin Target
-
-# Name "ocamake - Win32 Native code"
-
-!IF  "$(CFG)" == "ocamake - Win32 Native code"
-
-!ENDIF 
-
-# Begin Group "ML Files"
-
-# PROP Default_Filter "ml;mly;mll"
-# Begin Source File
-
-SOURCE=.\ocamake.ml
-# End Source File
-# End Group
-# Begin Group "MLI Files"
-
-# PROP Default_Filter "mli"
-# End Group
-# End Target
-# End Project

+ 0 - 29
libs/ocamake/ocamake.dsw

@@ -1,29 +0,0 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "ocamake"=.\ocamake.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-

+ 0 - 94
libs/ocamake/ocamake.html

@@ -1,94 +0,0 @@
-<html>
-<body bgcolor="#ffffff" link="Black" vlink="Black">
-<center><b><font color="#000099" size="+2">OCamake</font></b></center>
-<br>
-<font color="#777777">
-	OCamake - Copyright (c)2002-2003 Nicolas Cannasse & Motion Twin.<br>
-	The last version of this software can be found at : <a href="http://tech.motion-twin.com">http://tech.motion-twin.com</a><br><br>
-	This software is provided "AS IS" without any warranty of any kind, merchantability or fitness for a particular purpose. You should use it at your own risks, as the author and his company won't be responsible for any problem that the usage of this software could raise.
-</font>
-<br>
-<br>
-
-<ul>
-
-<li><b><font color="#000099">Introduction:</font></b><br>
-<br>
-OCamake is an automatic compiler for the Objective Caml language. It removes pain from the user which does not need anymore to write a Makefile. OCamake can work either as an application which compile your program or as a Makefile generator (using the <code>-mak</code> flag). OCamake has also special features for integration under Microsoft Visual Studio.
-<br>
-<br>
-<li><b><font color="#000099">Installation:</font></b><br>
-<br>
-OCamake is a source-only distribution, so you need to compile it first. Type the following command-line:<br>
-&nbsp;&nbsp;<code>ocamlc unix.cma str.cma ocamake.ml -o ocamake.exe</code><br>
-This should produce a file "<code>ocamake.exe</code>". Copy this file in your <code>ocaml/bin</code> directory.<br>
-<br>
-<li><b><font color="#000099">Usage:</font></b><br>
-<br>
-To compile your project, simply call OCamake with the files you want to compile:<br>
-&nbsp;&nbsp;<code>ocamake *.ml *.mli</code><br>
-<br>
-To remove all intermediate files that have been produced by the compiler :<br>
-&nbsp;&nbsp;<code>ocamake -clean *.ml *.mli</code><br>
-<br>
-To generate a Makefile:<br>
-&nbsp;&nbsp;<code>ocamake -mak *.ml *.mli</code><br>
-&nbsp;&nbsp;<code>make all</code><br>
-&nbsp;&nbsp;<code>...</code><br>
-&nbsp;&nbsp;<code>make clean</code><br>
-<br>
-(Windows users can use <code>nmake</code> instead of make and should use <code>nmake wclean</code> to remove intermediate files)
-<br>
-<br>
-<li><b><font color="#000099">Features:</font></b><br>
-<br>
-OCamake works with the following files :
-<ul>
-	<li><code>ml, mli</code> : theses files are added to the list of files to build
-	<li><code>cmo, cmx, cma, cmxa, dll, so, lib, a, o, obj</code> : theses files are added to the library list
-	<li><code>mll, mly</code> : theses files are compiled using <code>ocamllex</code> and <code>ocamlyacc</code>, and their result are added to the list of files to build.
-	<li><code>dsp, vcproj</code> (Visual Studio Project) : all the files included in the project are added to the ocamake file list.
-</ul>
-<br>
-Once the final file list is made, OCamake run <code>ocamldep</code> to build module dependencies tree, and then build and link the tree in the good order (for more information on the algorithm used, see sources).
-Only modified sources files or files with one dependency modified are rebuilt.<br>
-<br>
-If one <code>dsp</code> file has been found or if the <code>-epp</code> flag has been set, then all compilation errors are processed by OCamake to transform them into a Visual Studio compatible format.<br>
-If one <code>dsp</code> file has been found or if the <code>-cpp</code> flag has been set, the character ranges in Ocaml errors are replaced by the corresponding expression found in the source file.
-<br>
-<br>
-<li><b><font color="#000099">Options:</font></b><br>
-<br>
-The following command-line options are available :
-<ul>
-	<li><code>-clean</code> : delete all the intermediate and ouput files for the target build.
-	<li><code>-mak</code> : generate a <code>Makefile</code> for this project (<i>still experimental</i>).
-	<li><code>-opt</code> : turn on native compilation.
-	<li><code>-a</code> : build a library (<code>cma or cmxa</code>).
-	<li><code>-o &lt;output&gt;</code> : set the output file for the project.
-	<li><code>-all</code> : rebuild the entire project.
-	<li><code>-cpp</code> : convert characters range in errors to file expression.
-	<li><code>-epp</code> : use MSVC error messages format.
-	<li><code>-g</code> : compile and link in debug mode.
-	<li><code>-pp &lt;command&gt;</code> : pipe source through preprocessor.
-	<li><code>-cp &lt;flag&gt;</code> : add this flag to the compiler command line paramaters.
-	<li><code>-lp &lt;flag&gt;</code> : add this flag to the linker command line paramaters.
-	<li><code>-I &lt;path&gt;</code> : add the path to the list of include directories.
-	<li><code>-n &lt;file&gt;</code> : remove that file from the file list : this can be useful when you want to have all the files but one (<code>ocamake -n myfile.ml *.ml *.mli</code>).
-	<li><code>-v</code> : verbose mode - this print all the commands that ocamake is running in order to build the project.
-	<li><code>-P &lt;file&gt;</code> : add priority to a given file when having cycle between modules.
-</ul>
-<br>
-<li><b><font color="#000099">Licence:</font></b><br>
-<br>
-The full source code of OCamake is included, so you can modify, use, and redistribute it as you want for any usage conform to the licence. This code is under the LGPL (GNU Lesser General Public Licence), you can get more information on www.gnu.org.<br>
-<br>
-<li><b><font color="#000099">Author:</font></b><br>
-<br>
-Nicolas Cannasse <a href="mailto:[email protected]">[email protected]</a><br>
-Website : <a href="http://tech.motion-twin.com">http://tech.motion-twin.com</a><br>
-Thanks to <a href="http://www.lexifi.com">Lexifi</a>.
-<br>
-<br>
-</body>
-</html>

+ 0 - 661
libs/ocamake/ocamake.ml

@@ -1,661 +0,0 @@
-(* ************************************************************************ *)
-(*                                                                          *)
-(* OCAMAKE - OCaml Automatic compilation                                    *)
-(*      (c)2002 Nicolas Cannasse                                            *)
-(*      (c)2002 Motion-Twin                                                 *)
-(*                                                                          *)
-(* Last version : http://tech.motion-twin.com                               *)
-(*                                                                          *)
-(* ************************************************************************ *)
-open Unix
-open Printf
-open Arg
-
-type compile_mode =
-	| CM_DEFAULT
-	| CM_BYTE
-	| CM_OPT
-
-type file_ext =
-	| ML | MLI | MLL | MLY
-	| CMO | CMX | CMA | CMXA
-	| DLL | SO | EXE | LIB
-	| CMI | O | OBJ | A
-
-type file = {
-	name : string;
-	ext : file_ext;
-	target : string;
-	deps : string list;
-}
-
-(* ************************************************************************ *)
-(* GLOBALS *)
-
-let verbose = ref false (* print command calls in verbose mode *)
-let project_name = ref None (* for VC++ DSP *)
-let error_process = ref false (* VC++ error message processing *)
-let chars_process = ref false (* replace chars range in errors by file data *)
-
-(* ************************************************************************ *)
-(* USEFUL FUNCTIONS *)
-
-let if_some f opt def =
-	match opt with
-	| None -> def
-	| Some v -> f v
-
-let print str = print_endline str; flush Pervasives.stdout
-
-let (???) file =
-	failwith ("Don't know what to do with file " ^ file)
-
-let str_suffix = function
-	| ML -> "ml" | MLI -> "mli" | MLL -> "mll" | MLY -> "mly" | CMO -> "cmo"
-	| CMX -> "cmx" | CMA -> "cma" | CMXA -> "cmxa" | DLL -> "dll" | SO -> "so"
-	| EXE -> "exe" | CMI -> "cmi" | O -> "o" | A -> "a" | OBJ -> "obj"
-	| LIB -> "lib"
-
-let unescape file =
-	let l = String.length file in
-	if l >= 2 && file.[0] = '"' && file.[l-1] = '"' then String.sub file 1 (l-2) else file
-
-let extension file =
-	let rsplit_char str ch =
-		let p = String.rindex str ch in
-		let len = String.length str in
-		(String.sub str 0 p, String.sub str (p + 1) (len - p - 1))	
-	in
-	let file = unescape file in
-	let s = try snd(rsplit_char file '.') with Not_found -> "" in
-	String.uppercase s
-
-let (+!) file suff =
-	let base = Filename.chop_extension file in
-	base ^ "." ^ str_suffix suff
-
-let filter_all_in func ic =
-	let rec treat acc =
-	try
-		match func (input_line ic) with
-		| None -> treat acc
-		| Some data -> treat (data :: acc)
-	with
-		End_of_file -> close_in ic; acc
-	in
-	List.rev (treat [])
-
-let rec remove_duplicates = function
-	| [] -> []
-	| item :: q when List.exists ((=) item) q -> remove_duplicates q
-	| item :: q -> item :: remove_duplicates q
-
-let file_time fname =
-	try (Unix.stat fname).st_mtime with Unix_error _ -> 0.
-
-let flatten = String.concat " "
-
-let escape str =
-	try
-		ignore(String.index str ' ');
-		"\"" ^ str ^ "\"";
-	with Not_found -> str
-
-let delete_file file =
-	try Sys.remove file with Sys_error _ -> ()
-
-let check_existence (ext,name) =
-	match ext with
-	| ML | MLI ->
-		if not (Sys.file_exists name) then
-			failwith ("No such file : "^(escape name))
-	| _ -> ()
-		(* Others files can be found in Ocaml stdlib or
-		   user -I paths *)
-
-exception Found_pos of int
-
-let print_errors output msg =
-	let split str sep =
-		let find_sub str sub =
-			let len = String.length sub in
-			try
-				for i = 0 to String.length str - len do
-					if String.sub str i len = sub then raise (Found_pos i);
-				done;
-				raise Not_found
-			with Found_pos i -> i 
-		in
-		let p = find_sub str sep in
-		let len = String.length sep in
-		let slen = String.length str in
-		(String.sub str 0 p, String.sub str (p + len) (slen - p - len))
-	in
-	let process_chars file chars line =
-		let cmin, cmax = split chars "-" in
-		let cmin, cmax = int_of_string cmin, int_of_string cmax in
-		if cmax > cmin then begin
-			let f = open_in file in
-			for i = 1 to line-1 do ignore(input_line f) done;
-			seek_in f ((pos_in f)+cmin);
-			let s = String.create (cmax - cmin) in
-			ignore(input f s 0 (cmax - cmin));
-			prerr_endline (try
-					(String.sub s 0 (String.index s '\n'))^"..."
-				with
-					Not_found -> s);
-		end
-	in
-	let printer =
-		(match !error_process , !chars_process with
-		| true , _ -> (function line ->
-			try
-				let data, chars = split line ", characters " in
-				let data, lnumber = split data "\", line " in
-				let _, file = split data "File \"" in
-				prerr_string (file ^ "(" ^ lnumber ^ ") : ");
-				let chars, _ = split chars ":" in
-				if !chars_process then
-					(try process_chars file chars (int_of_string lnumber) with _ -> raise Not_found)
- 			with
-				Not_found ->
-					prerr_endline line)
-		| false , true -> (function line ->
-			try
-				let edata, chars = split line ", characters " in
-				let data, lnumber = split edata "\", line " in
-				let _, file = split data "File \"" in
-				let chars, _ = split chars ":" in
-				prerr_string (edata^" : ");
-				if !chars_process then
-					process_chars file chars (int_of_string lnumber);
- 			with
-				Not_found ->
-					prerr_endline line)
-
-		| false , false ->
-		      prerr_endline)
-	in
-	List.iter printer output;
-	failwith msg
-
-let exec ?(stdout=false) ?(outfirst=false) cmd errmsg =
-	if !verbose then print cmd;
-	let pout, pin, perr = open_process_full cmd (Unix.environment()) in
-	let read = filter_all_in (fun s -> Some s) in
-	let data, edata = 
-	(* this is made to prevent the program lock when one
-	   buffer is full and the process is waiting for us
-	   to read it before exiting... while we're reading
-	   the other output buffer ! *)
-	(if outfirst then
-		let d = read pout in
-		let ed = read perr in
-		d,ed
-	else	
-		let ed = read perr in
-		let d = read pout in
-		d,ed) in
-	match close_process_full (pout, pin, perr) with
-	| WEXITED 0 -> data,edata
-	| WEXITED exitcode -> print_errors (if stdout then edata @ data else edata) errmsg
-	| _ -> failwith "Build aborted by signal"
-
-(* ************************************************************************ *)
-(* DEPENDENCIES *)
-
-let line_regexp = Str.regexp "^\\([0-9A-Za-z:_\\./\\\\-]+\\.cm[oi]\\):\\( .*\\)$"
-let dep_regexp = Str.regexp " \\([0-9A-Za-z:_\\./\\\\-]+\\.cm[oi]\\)"
-
-let build_graph opt paramlist files =
-	let srcfiles = List.filter (fun (e,_) ->
-		match e with
-		| ML | MLI -> true
-		| _ -> false) files in
-	let get_name (_,f) = escape f in
-	let file_names = flatten (List.map get_name srcfiles) in
-	let params = flatten paramlist in
-	let command = sprintf "ocamldep %s %s" params file_names in	
-	let output,_ = exec command "Failed to make dependencies" ~outfirst:true in
-	let data = String.concat "\n" output in	
-	let data = Str.global_replace (Str.regexp "\\\\\r\n") "" data in (* win *)
-	let data = Str.global_replace (Str.regexp "\\\\\n") "" data in (* unix *)		
-	let rec get_deps data p =
-		try
-			let newp = Str.search_forward dep_regexp data p in
-			let file = Str.matched_group 1 data in
-			if opt && extension file = "CMO" then 
-				(file +! CMX)::(get_deps data (newp+1))
-			else
-				file::(get_deps data (newp+1))
-		with
-			Not_found -> []
-	in
-	let rec get_lines p =		
-		try
-			let newp = Str.search_forward line_regexp data p in	
-			let file = Str.matched_group 1 data in			
-			let lines = get_deps (Str.matched_group 2 data) 0 in			
-			(Filename.basename file,lines)::(get_lines (newp+1))
-		with
-			Not_found -> []
-	in
-	let lines = get_lines 0 in
-	let init_infos (ext,fname) =
-		let deptarget = Filename.basename (match ext with
-			| ML ->  fname +! CMO
-			| MLI -> fname +! CMI
-			| _ -> fname) in
-		let target = (match ext with
-			| ML -> fname +! (if opt then CMX else CMO)
-			| MLI -> fname +! CMI
-			| _ -> fname) in
-		{
-			name = fname;
-			ext = ext;
-			target = target;
-			deps =
-				(try
-					snd (List.find (fun (n,_) -> n = deptarget) lines)
-				with
-					Not_found -> []);
-		}
-	in	
-	let deps = List.map init_infos files in
-	match !verbose with
-	| false -> deps
-	| true ->
-		let print_dep d =
-			let dl = String.concat " " (List.map Filename.basename d.deps) in
-			printf "%s: %s\n" (Filename.basename d.target) dl;
-		in
-		List.iter print_dep deps;
-		deps
-
-let rec graph_topological_sort all g priority acc =
-	let has_dep where dep =	
-		List.exists (fun f -> Filename.basename f.target =
-							Filename.basename dep) where
-	in
-	let modified a b = (file_time a) < (file_time b) in
-	let is_free file = not(List.exists (has_dep g) file.deps) in
-	let rec has_priority = function
-		| [] -> raise Not_found
-		| x :: l ->
-			try
-				List.find (fun f -> x = (Filename.basename f.name)) g
-			with
-				Not_found -> has_priority l
-	in
-	let to_build file =
-		all || (* rebuild all *)
-		List.exists (has_dep acc) file.deps || (* a dep is rebuild *)
-		List.exists (modified file.target) file.deps || (* dep modified *)
-		(file_time file.target) < (file_time file.name) (* is modified *)
-	in
-	match g with
-	| [] -> acc
-	| _ ->
-		let free,g = List.partition is_free g in
-		match free with 
-		| [] ->
-			(try
-				let free = has_priority priority in
-				let g = List.filter ((<>) free) g in
-				if to_build free then
-					graph_topological_sort all g priority (acc@[free])
-				else
-					graph_topological_sort all g priority acc;
-			with Not_found ->
-				List.iter (fun f -> prerr_endline f.name) g;
-				failwith "Cycle detected in file dependencies !")
-		| _ ->
-			let to_build = List.filter to_build free in
-			graph_topological_sort all g priority (acc@to_build)
-
-(* ************************************************************************ *)
-(* COMPILATION *)
-
-let compile ?(precomp=false) opt paramlist f =
-	try
-		let command = (match f.ext with
-		| ML | MLI ->
-			let params = flatten paramlist in
-			let compiler = (if opt then "ocamlopt" else "ocamlc") in
-			sprintf "%s -c %s %s" compiler params (escape f.name)
-		| MLL when precomp -> "ocamllex " ^ (escape f.name)
-		| MLY when precomp -> "ocamlyacc " ^ (escape f.name)
-		| _ -> raise Exit) in
-		print (Filename.basename (unescape f.name));
-		let stdout,stderr = exec command "Build failed" in
-		try
-			print_errors (stderr@stdout) "";
-		with
-			Failure _ -> ()
-	with
-		Exit -> ()
-
-let pre_compile all (ext,name) =
-	match ext with
-	| MLL | MLY ->
-		let time = file_time name in
-		if time = 0. then failwith ("No such file : "^(escape name));
-		if all || (file_time (name +! ML)) < time then
-			compile ~precomp:true false [] {
-				name = name;
-				ext = ext;
-				deps = [];
-				target = "";
-			}
-	| _ -> () (* other files type does not need pre-compilation *)
-
-let clean_targets opt acc (ext,name) =	
-	match ext with
-	| MLY ->
-		(name +! ML) :: (name +! MLI) :: acc
-	| MLL ->
-		(name +! ML) :: acc
-	| ML when opt ->
-		(name +! (if Sys.os_type = "Win32" then OBJ else O)) :: (name +! CMX) :: (name +! CMI) :: acc
-	| ML ->
-		(name +! CMO) :: (name +! CMI) :: acc
-	| MLI ->
-		(name +! CMI) :: acc
-	| _ ->
-		acc
-
-(*
-	In order to link, we need to order the CMO files.
-	We currently have a ML/MLI dependency graph (in fact, tree) generated
-	by ocamldep.
-
-	To build the CMO list, we are reducing the dep-tree into one graph merging
-	corresponding ML & MLI nodes. ML-ML edges are keeped, ML-MLI edges
-	become ML-ML edges only if they do not create a cycle in the reduced
-	graph.
-
-	Then we sort the graph using topological ordering.
-*)
-let graph_reduce opt g =
-	let ext = (if opt then CMX else CMO) in
-	let rec path_exists g a b =
-		if a = b then true else
-		try
-			let f = List.find (fun f -> f.target = a) g in
-			List.exists (fun d -> path_exists g d b) f.deps
-		with
-			Not_found -> false
-	in
-	let rec deps_reduce f g = function		
-		| [] -> []
-		| dep::deps ->
-			match extension dep with
-			| "CMI" when not(path_exists g (dep +! ext) f.target) ->				
-				(dep +! ext)::(deps_reduce f g deps)
-			| "CMO" | "CMX" ->
-				dep::(deps_reduce f g deps)
-			| _ -> deps_reduce f g deps
-	in
-	let rec do_reduce g acc =
-		match g with
-		| [] -> acc
-		| f::g' ->			
-			let f = { f with deps = deps_reduce f (g@acc) f.deps } in
-			do_reduce g' (f::acc)
-	in
-	do_reduce g []	
-
-let is_lib f = match f.ext with
-	| CMA | CMXA | CMO | CMX | DLL | SO | LIB | A | O | OBJ -> true
-	| _ -> false
-
-let link opt paramlist files priority output =
-	print "Linking...";
-	let sources = List.filter (fun f -> f.ext = ML) files in
-	let libs = List.filter is_lib files in
-	let sources = graph_topological_sort true (graph_reduce opt sources) priority [] in
-	let lparams = flatten (List.map (fun f -> escape f.name) libs) in
-	let sparams = flatten (List.map (fun f -> escape f.target) sources) in
-	let params = flatten paramlist in
-	let cc = (if opt then "ocamlopt" else "ocamlc") in
-	let cmd = sprintf "%s %s %s %s -o %s" cc params lparams sparams output in
-	ignore(exec ~stdout:true cmd "Linking failed")
-
-(* ************************************************************************ *)
-(* FILE PROCESSING *)
-
-let dsp_get_files dsp_file =
-	let get_file line =
-		if String.length line > 7 && String.sub line 0 7 = "SOURCE=" then
-			Some (unescape (String.sub line 7 (String.length line-7)))
-		else
-			None
-	in
-	filter_all_in get_file (open_in dsp_file)
-
-let vcproj_get_files vcp_file =
-	let get_file line =
-		let len = String.length line in
-		let p = ref 0 in
-		while !p < len && (line.[!p] = ' ' || line.[!p] = '\t') do
-			incr p;
-		done;
-		let line = String.sub line !p (len - !p) in		
-		if String.length line > 13 && String.sub line 0 13 = "RelativePath=" then begin
-			let str = String.sub line 13 (String.length line - 14) in
-			Some (unescape str)
-		end else
-			None
-	in
-	filter_all_in get_file (open_in vcp_file)
-
-let rec list_files errors file =
-	match extension file with
-	| "ML" -> [(ML,file)]
-	| "MLI" -> [(MLI,file)]
-	| "VCPROJ" ->
-		project_name := Some (Filename.basename file);
-		error_process := true;
-		chars_process := true;
-		List.concat (List.map (list_files false) (vcproj_get_files file))
-	| "DSP" ->
-		project_name := Some (Filename.basename file);
-		error_process := true;
-		chars_process := true;
-		List.concat (List.map (list_files false) (dsp_get_files file))
-	| "CMA" -> [(CMA,file)]
-	| "CMXA" -> [(CMXA,file)]
-	| "CMX" -> [(CMX,file)]	
-	| "CMO" -> [(CMO,file)]
-	| "DLL" -> [(DLL,file)]
-	| "LIB" -> [(LIB,file)]
-	| "A" -> [(A,file)]
-	| "O" -> [(O,file)]
-	| "OBJ" -> [(OBJ,file)]
-	| "SO" -> [(SO,file)]
-	| "MLY" -> [(MLY,file);(ML,file +! ML);(MLI,file +! MLI)]
-	| "MLL" -> [(MLL,file);(ML,file +! ML)]	
-	| _ -> if errors then ??? file else []
-
-let rec get_compile_mode cm = function
-	| [] -> cm
-	| (ext,name)::files ->
-		let error() = failwith "Mixed bytecode and native compilation files." in
-		match ext with
-		| ML | MLI | MLL | MLY | DLL | SO ->
-			get_compile_mode cm files
-		| CMA | CMO ->
-			if cm = CM_OPT then error() else get_compile_mode CM_BYTE files
-		| CMXA | CMX | A | O | OBJ | LIB ->
-			if cm = CM_BYTE then error() else get_compile_mode CM_OPT files
-		| EXE | CMI ->
-			assert false
-
-let rec get_output_file islib cm =
-	match !project_name,islib,cm with
-	| None, _ , _ -> None
-	| Some name,false,_ -> Some (name +! EXE)
-	| Some name,true,CM_OPT -> Some (name +! CMXA)
-	| Some name,true,_ -> Some (name +! CMA)
-
-(* ************************************************************************ *)
-(* MAIN *)
-
-;;
-try
-
-let usage =
-	"OCAMAKE v1.4 - Copyright (C)2002-2005 Nicolas Cannasse"
-	^"\r\nLast version : http://tech.motion-twin.com" in
-let compile_mode = ref CM_DEFAULT in
-let compile_cma = ref false in
-let do_clean = ref false in
-let gen_make = ref false in
-let rebuild_all = ref false in
-let output_file = ref None in
-let preprocessor = ref None in
-let argfiles = ref [] in
-let paths = ref [] in
-let cflags = ref [] in
-let lflags = ref [] in
-let remf = ref [] in
-let priority = ref [] in
-let arg_spec = [
-  ("-all", Unit (fun () -> rebuild_all := true), ": rebuild all files");
-  ("-o", String (fun f -> output_file := Some f), "<file> : set output");
-  ("-a", Unit (fun () -> compile_cma := true), ": build a library");
-  ("-opt", Unit (fun () -> compile_mode := CM_OPT), ": native compilation");
-  ("-clean", Unit (fun () -> do_clean := true), ": delete intermediate files");
-  ("-I", String (fun p -> paths := p::!paths), "<path> : additional path");
-  ("-v", Unit (fun () -> verbose := true), ": turn on verbose mode");
-  ("-n", String (fun f -> remf := f::!remf),"<file>: don't compile this file");
-  ("-mak", Unit (fun () -> gen_make := true), ": generate Makefile");
-  ("-lp", String (fun f -> lflags := f::!lflags), "<p> : linker parameter");
-  ("-cp", String (fun f -> cflags := f::!cflags), "<p> : compiler parameter");
-  ("-pp", String (fun c -> preprocessor := Some c), "<cmd> : preprocessor");
-  ("-epp", Unit (fun() -> error_process := true), ": use MSVC error messages format");
-  ("-cpp", Unit (fun() -> chars_process := true), ": convert characters range in errors to file expression");
-  ("-g", Unit (fun () -> lflags := "-g"::!lflags; cflags := "-g"::!cflags), ": compile/link in debug mode");
-  ("-P", String (fun f -> priority := f::!priority), ": give linking priority to a file when linking ordering failed");
-] in
-Arg.parse arg_spec (fun arg -> argfiles := arg :: !argfiles) usage;
-let files = List.concat (List.map (list_files true) (List.rev !argfiles)) in
-let files = List.filter (fun (_,f) ->
-	let name = Filename.basename f in
-	not(List.exists (fun f -> Filename.basename f = name) !remf)) files in
-let compile_mode = get_compile_mode !compile_mode files in
-let output_file , compile_mode = (match !output_file with
-	| None -> get_output_file !compile_cma compile_mode , compile_mode
-	| Some file ->
-		match extension file , compile_mode with
-		| "CMA" , CM_OPT
-		| "CMXA", CM_BYTE -> failwith "Mixed bytecode and native compilation files."
-		| "CMA" , _ ->
-			compile_cma := true;
-			Some file , CM_BYTE
-		| "CMXA" , _ ->
-			compile_cma := true;
-			Some file , CM_OPT
-		| _ , _ ->
-			Some file , compile_mode)
-in
-let opt = (compile_mode = CM_OPT) in
-if !compile_cma then lflags := "-a"::!lflags;
-match files with
-  | [] -> Arg.usage arg_spec usage
-  | _ ->
-	let files = remove_duplicates files in
-	let get_path (_,f) = "-I " ^ escape (Filename.dirname f) in
-	let paths = List.map (fun p -> "-I " ^ (escape p)) !paths in
-	let paths = remove_duplicates (paths@(List.map get_path files)) in
-	let p4param = if_some (fun cmd -> "-pp " ^ (escape cmd)) !preprocessor "" in
-	match !do_clean,!gen_make with
-	| true,true ->
-		failwith "Cannot have -mak & -clean at the same time"
-	| false,false ->
-		if_some delete_file output_file ();
-		List.iter (pre_compile !rebuild_all) files;
-		List.iter check_existence files;
-		let g = build_graph opt (p4param::paths) files in
-		let files = graph_topological_sort !rebuild_all g [] [] in
-		List.iter (compile opt (!cflags @ p4param::paths)) files;
-		if_some (link opt (!lflags @ paths) g (List.rev !priority)) output_file ();
-		print "Done";
-	| true,false ->
-		print "Cleaning...";
-		if_some delete_file output_file ();
-		let to_clean = List.fold_left (clean_targets opt) [] files in
-		List.iter delete_file to_clean;
-		if opt && !compile_cma then
-			if_some (fun f -> delete_file (f +! (if Sys.os_type = "Win32" then LIB else A))) output_file ();
-	| false,true ->
-		List.iter (pre_compile !rebuild_all) files;
-		let g = build_graph opt (p4param::paths) files in
-		let out = open_out "Makefile" in
-		let fprint s = output_string out (s^"\n") in
-		let genmak f =
-			let ext = if opt then CMX else CMO in
-			match f.ext with
-			| MLL ->
-				fprint ((f.name +! ext)^": "^(f.name +! ML)^"\n")
-			| MLY ->
-				fprint ((f.name +! ext)^": "^(f.name +! ML)^"\n");
-				fprint ((f.name +! CMI)^": "^(f.name +! ML)^" "^(f.name +! MLI)^"\n")
-			| _ when f.deps <> [] ->
-				fprint (f.target^": "^(flatten f.deps)^"\n")
-			| _ ->
-				()
-		in
-		let compiles = graph_topological_sort true g [] [] in
-		let libs = List.filter is_lib compiles in
-		let cmos = List.filter (fun f -> f.ext = ML) compiles in
-		fprint "# Makefile generated by OCamake ";
-		fprint "# http://tech.motion-twin.com";
-		fprint ".SUFFIXES : .ml .mli .cmo .cmi .cmx .mll .mly";
-		fprint "";
-		fprint ("ALL_CFLAGS= $(CFLAGS) "^(flatten (!cflags @ p4param::paths)));
-		fprint ("LIBS="^(flatten (List.map (fun f -> f.name) libs)));
-		let targets = flatten (List.map (fun f -> f.target) cmos) in
-		(match output_file with
-		| None ->
-			fprint "";
-			fprint ("all: "^targets^"\n");
-		| Some out ->
-			fprint ("LFLAGS= -o "^out^" "^(flatten (!lflags @ paths)));
-			fprint "";
-			fprint ("all: "^out^"\n");
-			fprint (out^": "^targets);
-			(* I need to reuse the list of targets since $^ is for Make and $** for NMake *)
-			fprint ("\t"^(if opt then "ocamlopt" else "ocamlc")^" $(LFLAGS) $(LIBS) "^targets^"\n"));
-		List.iter genmak g;
-		fprint "";
-		fprint "clean:";
-		let cleanfiles = flatten (List.fold_left (clean_targets opt) [] files) in
-		if_some (fun o ->
-				fprint ("\trm -f "^o);
-				if opt && !compile_cma then fprint ("\trm -f "^(o +! LIB)^" "^(o +! A));
-			) output_file ();
-		fprint ("\trm -f "^cleanfiles);
-		fprint "";
-		fprint "wclean:";
-		if_some (fun o ->
-				fprint ("\t-@del "^o^" 2>NUL");
-				if opt && !compile_cma then fprint ("\t-@del "^(o +! LIB)^" "^(o +! A)^" 2>NUL");
-		) output_file ();
-		fprint ("\t-@del "^cleanfiles^" 2>NUL");
-		fprint "";
-		fprint "# SUFFIXES";
-		fprint ".ml.cmo:\n\tocamlc $(ALL_CFLAGS) -c $<\n";
-		fprint ".ml.cmx:\n\tocamlopt $(ALL_CFLAGS) -c $<\n";
-		fprint ".mli.cmi:\n\tocamlc $(ALL_CFLAGS) $<\n";
-		fprint ".mll.ml:\n\tocamllex $<\n";
-		fprint ".mly.ml:\n\tocamlyacc $<\n";
-		close_out out
-with
-	Failure msg ->
-		Pervasives.flush Pervasives.stdout;
-		prerr_endline msg;
-		Pervasives.flush Pervasives.stderr;
-		exit 1;
-
-(* ************************************************************************ *)

+ 0 - 21
libs/swflib/swflib.sln

@@ -1,21 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swflib", "swflib.vcproj", "{A9DD9D90-85E1-4FCF-8C09-42BF78942849}"
-	ProjectSection(ProjectDependencies) = postProject
-	EndProjectSection
-EndProject
-Global
-	GlobalSection(SolutionConfiguration) = preSolution
-		Bytecode = Bytecode
-		Native code = Native code
-	EndGlobalSection
-	GlobalSection(ProjectConfiguration) = postSolution
-		{A9DD9D90-85E1-4FCF-8C09-42BF78942849}.Bytecode.ActiveCfg = Bytecode|Win32
-		{A9DD9D90-85E1-4FCF-8C09-42BF78942849}.Bytecode.Build.0 = Bytecode|Win32
-		{A9DD9D90-85E1-4FCF-8C09-42BF78942849}.Native code.ActiveCfg = Native code|Win32
-		{A9DD9D90-85E1-4FCF-8C09-42BF78942849}.Native code.Build.0 = Native code|Win32
-	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-	EndGlobalSection
-	GlobalSection(ExtensibilityAddIns) = postSolution
-	EndGlobalSection
-EndGlobal

+ 0 - 80
libs/swflib/swflib.vcproj

@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="7.10"
-	Name="swflib"
-	SccProjectName=""
-	SccLocalPath=""
-	Keyword="MakeFileProj">
-	<Platforms>
-		<Platform
-			Name="Win32"/>
-	</Platforms>
-	<Configurations>
-		<Configuration
-			Name="Native code|Win32"
-			OutputDirectory="."
-			IntermediateDirectory="."
-			ConfigurationType="0"
-			UseOfMFC="0"
-			ATLMinimizesCRunTimeLibraryUsage="FALSE">
-			<Tool
-				Name="VCNMakeTool"
-				BuildCommandLine="ocamake -opt swfLib.vcproj -a -g"
-				ReBuildCommandLine="ocamake -opt swfLib.vcproj -a -g -all"
-				Output="swflib.exe"/>
-		</Configuration>
-		<Configuration
-			Name="Bytecode|Win32"
-			OutputDirectory="."
-			IntermediateDirectory="."
-			ConfigurationType="0"
-			UseOfMFC="0"
-			ATLMinimizesCRunTimeLibraryUsage="FALSE">
-			<Tool
-				Name="VCNMakeTool"
-				BuildCommandLine="ocamake -a swfLib.vcproj"
-				ReBuildCommandLine="ocamake -a swfLib.vcproj -all"
-				Output="swflib.exe"/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<File
-			RelativePath=".\actionScript.ml">
-		</File>
-		<File
-			RelativePath=".\as3.mli">
-		</File>
-		<File
-			RelativePath=".\as3code.ml">
-		</File>
-		<File
-			RelativePath=".\as3hl.mli">
-		</File>
-		<File
-			RelativePath=".\as3hlparse.ml">
-		</File>
-		<File
-			RelativePath=".\as3parse.ml">
-		</File>
-		<File
-			RelativePath=".\png.ml">
-		</File>
-		<File
-			RelativePath=".\png.mli">
-		</File>
-		<File
-			RelativePath=".\swf.ml">
-		</File>
-		<File
-			RelativePath=".\swfParser.ml">
-		</File>
-		<File
-			RelativePath=".\swfPic.ml">
-		</File>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>

+ 0 - 31
libs/ttflib/Makefile

@@ -1,31 +0,0 @@
-OCAMLOPT=ocamlopt
-OCAMLC=ocamlc
-
-FLAGS=-package extlib -safe-string -I ../extlib-leftovers -I ../swflib
-FILES=tTFData tTFParser tTFTools tTFSwfWriter tTFCanvasWriter tTFJsonWriter
-LIBS=extLib swflib unix
-
-OUTPUT=ttf
-
-all: native bytecode
-
-native: ttflib.cmxa
-
-bytecode: ttflib.cma
-
-ttflib.cmxa: $(FILES:=.ml)
-	ocamlfind $(OCAMLOPT) $(FLAGS) $(FILES:=.ml) -g -a -o ttflib.cmxa
-
-ttflib.cma: $(FILES:=.ml)
-	ocamlfind $(OCAMLC) $(FLAGS) $(FILES:=.ml) -g -a -o ttflib.cma
-
-exec:
-	ocamlfind $(OCAMLOPT) $(FLAGS) $(LIBS:=.cmxa) $(FILES:=.ml) main.ml -g -o $(OUTPUT)
-
-clean:
-	rm -rf ttflib.cmxa ttflib.cma ttflib.lib ttflib.a $(wildcard *.cmx) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) $(wildcard *.cmo)
-
-.PHONY: all native bytecode clean exec
-
-Makefile: ;
-$(FILES:=.ml): ;

+ 0 - 14
libs/ttflib/dune

@@ -1,14 +0,0 @@
-(include_subdirs no)
-
-(env
-	(_
-		(flags (-w -3 -w -27 -w -35))
-	)
-)
-
-(library
-	(name ttflib)
-	(libraries extlib extlib_leftovers swflib unix)
-	(modules (:standard \ main))
-	(wrapped false)
-)

+ 0 - 139
libs/ttflib/main.ml

@@ -1,139 +0,0 @@
-open TTFData
-
-exception Abort
-
-let gen_hxswfml_debug fontname =
-	let xml = "<?xml version=\"1.0\" ?>
-	<swf>
-		<FileAttributes/>
-		<Custom tagId=\"75\" file=\"" ^ fontname ^ ".dat\" comment=\"DefineFont3\"/>
-		<SymbolClass id=\"1\" class=\"TestFont\" base=\"flash.text.Font\"/>
-		<DefineABC file=\"Main.swf\" isBoot=\"true\"/>
-		<ShowFrame/>
-	</swf>"
-	in
-	Std.output_file (fontname ^ ".fxml") xml;
-	if Sys.command "haxe -main Main -swf main.swf" <> 0 then failwith "Error while executing haxe";
-	if Sys.command ("hxswfml xml2swf \"" ^ fontname ^ ".fxml\" \"" ^ fontname ^ ".swf\" -no-strict") <> 0 then failwith "Error while executing hxswfml";
-	Unix.unlink (fontname ^ ".fxml");
-	Unix.unlink "main.swf"
-
-let normalize_path p =
-	let l = String.length p in
-	if l = 0 then
-		"./"
-	else begin
-		let p = String.concat "/" (ExtString.String.nsplit p "\\") in
-		match p.[l-1] with
-		| '/' -> p
-		| _ -> p ^ "/"
-	end
-
-let mk_dir_rec dir =
-	let dir = normalize_path dir in
-	let parts = ExtString.String.nsplit dir "/" in
-	let rec create 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 (d :: acc) l
-	in
-	create [] parts
-
-let exit msg =
-	prerr_endline msg;
-	raise Abort
-
-let process args =
-	let fonts = ref [] in
-	let range_str = ref "" in
-	let targets = ref [] in
-	let debug_hxswfml = ref false in
-	let args_callback s = fonts := s :: !fonts in
-	let usage = Printf.sprintf
-		"Ttf <font paths> (-swf|-canvas)"
-	in
-	let basic_args = [
-		("-range",Arg.String (fun str ->
-			range_str := str;
-		),"<str> : specifies the character range");
-		("-swf",Arg.String (fun dir ->
-			mk_dir_rec dir;
- 			let f ttf range_str =
- 				let config = {
- 					ttfc_range_str = range_str;
- 					ttfc_font_name = None;
-					ttfc_font_weight = TFWRegular;
-					ttfc_font_posture = TFPNormal;
- 				} in
-				let f2 = TTFSwfWriter.to_swf ttf config in
-				let ch = IO.output_channel (open_out_bin (dir ^ "/" ^ ttf.ttf_font_name ^ ".dat")) in
-				let b = IO.output_bits ch in
-				IO.write_i16 ch 1;
-				TTFSwfWriter.write_font2 ch b f2;
-				IO.close_out ch;
-				if !debug_hxswfml then begin
-					if not (Sys.file_exists "Main.hx") then failwith "Could not find Main.hx required for -hxswfml-debug";
-					let main = Std.input_file "Main.hx" in
-					let old = Sys.getcwd () in
-					Sys.chdir dir;
-					Std.output_file ~filename:"Main.hx" ~text:main;
-					gen_hxswfml_debug ttf.ttf_font_name;
-					Unix.unlink "Main.hx";
-					Sys.chdir old;
-				end
-			in
-			targets := f :: !targets;
-		),"<dir> : generate swf tag data to <dir>");
-		("-canvas", Arg.String (fun dir ->
-			mk_dir_rec dir;
- 			let f ttf range_str =
- 				let glyphs = TTFCanvasWriter.to_canvas ttf range_str in
-				let ch = IO.output_channel (open_out_bin (dir ^ "/" ^ ttf.ttf_font_name ^ ".js")) in
-				TTFCanvasWriter.write_font ch ttf glyphs;
-				IO.close_out ch;
-			in
-			targets := f :: !targets;
-		),"<dir> : generate canvas draw commands to <dir>");
-		("-json", Arg.String (fun dir ->
-			mk_dir_rec dir;
- 			let f ttf range_str =
- 				let glyphs = TTFJsonWriter.to_json ttf range_str in
-				let ch = IO.output_channel (open_out_bin (dir ^ "/" ^ ttf.ttf_font_name ^ ".js")) in
-				TTFJsonWriter.write_font ch ttf glyphs;
-				IO.close_out ch;
-			in
-			targets := f :: !targets;
-		),"<dir> : generate json-encoded glyph information to <dir>");
-		("-hxswfml-debug", Arg.Unit (fun () ->
-			debug_hxswfml := true;
-		),": generate debug swf with hxswfml")
-	] in
-	if Array.length Sys.argv = 1 then
-		Arg.usage basic_args usage
-	else begin
-		Arg.parse basic_args args_callback usage;
-		match !fonts,!targets with
-		| [],_ ->
-			prerr_endline "Missing font argument";
-			Arg.usage basic_args usage
-		| _,[] ->
-			prerr_endline "No targets specified (-swf|-canvas|-json)";
-			Arg.usage basic_args usage
-		| fonts,targets ->
-			List.iter (fun font ->
-				let ch = try open_in_bin font with _ -> exit ("No such file: " ^ font) in
-				let ttf = TTFParser.parse ch in
-				List.iter (fun target ->
-					target ttf !range_str
-				) targets;
-				close_in ch;
-			) fonts;
-	end
-;;
-try
-	process Sys.argv;
-with Abort ->
-	()

+ 0 - 50
libs/ttflib/tTFCanvasWriter.ml

@@ -1,50 +0,0 @@
-(*
- * Copyright (C)2005-2014 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *)
-
-open TTFData
-open TTFTools
-
-let rec write_glyph ttf key glyf =
-	key,TTFTools.build_glyph_paths ttf false glyf
-
-let write_font ch ttf glyphs =
-	let scale = 1024. /. (float_of_int ttf.ttf_head.hd_units_per_em) in
-	List.iter (fun (key,paths) ->
-		IO.nwrite_string ch (Printf.sprintf "\tfunction key%i(ctx) {\n" key);
-		IO.nwrite_string ch "\t\tctx.beginPath();\n";
-		List.iter (fun path ->
-			IO.nwrite_string ch (match path.gp_type with
-			| 0 -> Printf.sprintf "\t\tctx.moveTo(%.2f,%.2f);\n" (path.gp_x *. scale) (path.gp_y *. scale *. (-1.))
-			| 1 -> Printf.sprintf "\t\tctx.lineTo(%.2f,%.2f);\n" (path.gp_x *. scale) (path.gp_y *. scale *. (-1.))
-			| 2 -> Printf.sprintf "\t\tctx.quadraticCurveTo(%.2f,%.2f,%.2f,%.2f);\n" (path.gp_cx *. scale) (path.gp_cy *. scale *. (-1.)) (path.gp_x *. scale) (path.gp_y *. scale *. (-1.))
-			| _ -> assert false)
-		) paths;
-		IO.nwrite_string ch "\t\tctx.fill();\n";
-		IO.nwrite_string ch "\t}\n";
-	) glyphs;
-	()
-
-let to_canvas ttf range_str =
-	let lut = TTFTools.build_lut ttf range_str in
-	let glyfs = Hashtbl.fold (fun k v acc -> (k,ttf.ttf_glyfs.(v)) :: acc) lut [] in
-	let glyfs = List.stable_sort (fun a b -> compare (fst a) (fst b)) glyfs in
-	List.map (fun (k,g) -> write_glyph ttf k g) glyfs

+ 0 - 360
libs/ttflib/tTFData.ml

@@ -1,360 +0,0 @@
-(*
- * Copyright (C)2005-2014 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *)
-
-type header = {
-	hd_major_version : int;
-	hd_minor_version : int;
-	hd_num_tables : int;
-	hd_search_range : int;
-	hd_entry_selector : int;
-	hd_range_shift : int;
-}
-
-type entry = {
-	entry_table_name : string;
-	entry_checksum : int32;
-	entry_offset : int32;
-	entry_length: int32;
-}
-
-(* GLYF *)
-
-type glyf_header = {
-	gh_num_contours : int;
-	gh_xmin : int;
-	gh_ymin : int;
-	gh_xmax : int;
-	gh_ymax : int;
-}
-
-type glyf_simple = {
-	gs_end_pts_of_contours : int array;
-	gs_instruction_length : int;
-	gs_instructions : char array;
-	gs_flags : int array;
-	gs_x_coordinates : int array;
-	gs_y_coordinates : int array;
-}
-
-type transformation_option =
-	| NoScale
-	| Scale of float
-	| ScaleXY of float * float
-	| ScaleMatrix of float * float * float * float
-
-type glyf_component = {
-	gc_flags : int;
-	gc_glyf_index : int;
-	gc_arg1 : int;
-	gc_arg2 : int;
-	gc_transformation : transformation_option;
-}
-
-type glyf =
-	| TGlyfSimple of glyf_header * glyf_simple
-	| TGlyfComposite of glyf_header * glyf_component list
-	| TGlyfNull
-
-(* HMTX *)
-
-type hmtx = {
-	advance_width : int;
-	left_side_bearing : int;
-}
-
-(* CMAP *)
-
-type cmap_subtable_header = {
-	csh_platform_id : int;
-	csh_platform_specific_id : int;
-	csh_offset : int32;
-}
-
-type cmap_format_0 = {
-	c0_format : int;
-	c0_length : int;
-	c0_language : int;
-	c0_glyph_index_array : char array;
-}
-
-type cmap_format_4 = {
-	c4_format : int;
-	c4_length : int;
-	c4_language : int;
-	c4_seg_count_x2 : int;
-	c4_search_range : int;
-	c4_entry_selector : int;
-	c4_range_shift : int;
-	c4_end_code : int array;
-	c4_reserved_pad : int;
-	c4_start_code : int array;
-	c4_id_delta : int array;
-	c4_id_range_offset : int array;
-	c4_glyph_index_array : int array;
-}
-
-type cmap_format_6 = {
-	c6_format : int;
-	c6_length : int;
-	c6_language : int;
-	c6_first_code : int;
-	c6_entry_count : int;
-	c6_glyph_index_array : int array;
-}
-
-type cmap_format_12_group = {
-	c12g_start_char_code : int32;
-	c12g_end_char_code : int32;
-	c12g_start_glyph_code : int32;
-}
-
-type cmap_format_12 = {
-	c12_format : int32;
-	c12_length : int32;
-	c12_language : int32;
-	c12_num_groups : int32;
-	c12_groups : cmap_format_12_group list;
-}
-
-type cmap_subtable_def =
-	| Cmap0 of cmap_format_0
-	| Cmap4 of cmap_format_4
-	| Cmap6 of cmap_format_6
-	| Cmap12 of cmap_format_12
-	| CmapUnk of string
-
-type cmap_subtable = {
-	cs_header : cmap_subtable_header;
-	cs_def : cmap_subtable_def;
-}
-
-type cmap = {
-	cmap_version : int;
-	cmap_num_subtables : int;
-	cmap_subtables : cmap_subtable list;
-}
-
-(* KERN *)
-
-type kern_subtable_header = {
-	ksh_length : int32;
-	ksh_coverage : int;
-	ksh_tuple_index : int;
-}
-
-type kern_pair = {
-	kern_left : int;
-	kern_right : int;
-	kern_value : int;
-}
-
-type kern_format_0 = {
-	k0_num_pairs : int;
-	k0_search_range : int;
-	k0_entry_selector : int;
-	k0_range_shift : int;
-	k0_pairs : kern_pair list;
-}
-
-type kern_format_2 = {
-	k2_row_width : int;
-	k2_left_offset_table : int;
-	k2_right_offset_table : int;
-	k2_array : int;
-	k2_first_glyph : int;
-	k2_num_glyphs : int;
-	k2_offsets : int list;
-}
-
-type kern_subtable_def =
-	| Kern0 of kern_format_0
-	| Kern2 of kern_format_2
-
-type kern_subtable = {
-	ks_header : kern_subtable_header;
-	ks_def : kern_subtable_def;
-}
-
-type kern = {
-	kern_version : int32;
-	kern_num_tables : int32;
-	kern_subtables : kern_subtable list;
-}
-
-(* NAME *)
-
-type name_record = {
-	nr_platform_id : int;
-	nr_platform_specific_id : int;
-	nr_language_id : int;
-	nr_name_id : int;
-	nr_length : int;
-	nr_offset : int;
-	mutable nr_value : string;
-}
-
-type name = {
-	name_format : int;
-	name_num_records : int;
-	name_offset : int;
-	name_records : name_record array;
-}
-
-(* HEAD *)
-
-type head = {
-	hd_version : int32;
-	hd_font_revision : int32;
-	hd_checksum_adjustment : int32;
-	hd_magic_number : int32;
-	hd_flags : int;
-	hd_units_per_em : int;
-	hd_created : float;
-	hd_modified : float;
-	hd_xmin : int;
-	hd_ymin : int;
-	hd_xmax : int;
-	hd_ymax : int;
-	hd_mac_style : int;
-	hd_lowest_rec_ppem : int;
-	hd_font_direction_hint : int;
-	hd_index_to_loc_format : int;
-	hd_glyph_data_format : int;
-}
-
-(* HHEA *)
-
-type hhea = {
-	hhea_version : int32;
-	hhea_ascent : int;
-	hhea_descent : int;
-	hhea_line_gap : int;
-	hhea_advance_width_max : int;
-	hhea_min_left_side_bearing : int;
-	hhea_min_right_side_bearing : int;
-	hhea_x_max_extent : int;
-	hhea_caret_slope_rise : int;
-	hhea_caret_slope_run : int;
-	hhea_caret_offset : int;
-	hhea_reserved : string;
-	hhea_metric_data_format : int;
-	hhea_number_of_hmetrics :int;
-}
-
-(* LOCA *)
-
-type loca = int32 array
-
-(* MAXP *)
-
-type maxp = {
-	maxp_version_number : int32;
-	maxp_num_glyphs : int;
-	maxp_max_points : int;
-	maxp_max_contours : int;
-	maxp_max_component_points : int;
-	maxp_max_component_contours : int;
-	maxp_max_zones : int;
-	maxp_max_twilight_points : int;
-	maxp_max_storage : int;
-	maxp_max_function_defs : int;
-	maxp_max_instruction_defs :int;
-	maxp_max_stack_elements : int;
-	maxp_max_size_of_instructions :int;
-	maxp_max_component_elements :int;
-	maxp_max_component_depth :int;
-}
-
-(* OS2 *)
-
-type os2 = {
-	os2_version : int;
-	os2_x_avg_char_width : int;
-	os2_us_weight_class : int;
-	os2_us_width_class : int;
-	os2_fs_type : int;
-	os2_y_subscript_x_size : int;
-	os2_y_subscript_y_size : int;
-	os2_y_subscript_x_offset : int;
-	os2_y_subscript_y_offset : int;
-	os2_y_superscript_x_size : int;
-	os2_y_superscript_y_size : int;
-	os2_y_superscript_x_offset : int;
-	os2_y_superscript_y_offset : int;
-	os2_y_strikeout_size : int;
-	os2_y_strikeout_position : int;
-	os2_s_family_class : int;
-	os2_b_family_type : int;
-	os2_b_serif_style : int;
-	os2_b_weight : int;
-	os2_b_proportion : int;
-	os2_b_contrast : int;
-	os2_b_stroke_variation : int;
-	os2_b_arm_style : int;
-	os2_b_letterform : int;
-	os2_b_midline : int;
-	os2_b_x_height : int;
-	os2_ul_unicode_range_1 : int32;
-	os2_ul_unicode_range_2 : int32;
-	os2_ul_unicode_range_3 : int32;
-	os2_ul_unicode_range_4 : int32;
-	os2_ach_vendor_id : int32;
-	os2_fs_selection : int;
-	os2_us_first_char_index : int;
-	os2_us_last_char_index : int;
-	os2_s_typo_ascender : int;
-	os2_s_typo_descender : int;
-	os2_s_typo_line_gap : int;
-	os2_us_win_ascent : int;
-	os2_us_win_descent : int;
-}
-
-type ttf = {
-	ttf_header : header;
-	ttf_font_name : string;
-	ttf_directory: (string,entry) Hashtbl.t;
-	ttf_glyfs : glyf array;
-	ttf_hmtx : hmtx array;
-	ttf_cmap : cmap;
-	ttf_head : head;
-	ttf_loca : loca;
-	ttf_hhea : hhea;
-	ttf_maxp : maxp;
-	ttf_name : name;
-	ttf_os2 : os2;
-	ttf_kern : kern option;
-}
-
-type ttf_font_weight =
-	| TFWRegular
-	| TFWBold
-
-type ttf_font_posture =
-	| TFPNormal
-	| TFPItalic
-
-type ttf_config = {
-	mutable ttfc_range_str : string;
-	mutable ttfc_font_name : string option;
-	mutable ttfc_font_weight : ttf_font_weight;
-	mutable ttfc_font_posture : ttf_font_posture;
-}

+ 0 - 49
libs/ttflib/tTFJsonWriter.ml

@@ -1,49 +0,0 @@
-(*
- * Copyright (C)2005-2014 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *)
-
-open TTFData
-open TTFTools
-
-let rec write_glyph ttf key glyf =
-	key,TTFTools.build_glyph_paths ttf false glyf
-
-let write_font ch ttf glyphs =
-	let scale = 1024. /. (float_of_int ttf.ttf_head.hd_units_per_em) in
-	IO.nwrite_string ch "{\n\t";
-	IO.nwrite_string ch (String.concat ",\n\t" (List.map (fun (key,paths) ->
-		(Printf.sprintf "\"g%i\":[" key)
-		^ (String.concat "," (List.map (fun path ->
-			match path.gp_type with
-			| 0 -> Printf.sprintf "[0,%.2f,%.2f]" (path.gp_x *. scale) (path.gp_y *. scale *. (-1.))
-			| 1 -> Printf.sprintf "[1,%.2f,%.2f]" (path.gp_x *. scale) (path.gp_y *. scale *. (-1.))
-			| 2 -> Printf.sprintf "[2,%.2f,%.2f,%.2f,%.2f]" (path.gp_cx *. scale) (path.gp_cy *. scale *. (-1.)) (path.gp_x *. scale) (path.gp_y *. scale *. (-1.))
-			| _ -> assert false
-		) paths))
-		^ "]";
-	) glyphs));
-	IO.nwrite_string ch "\n}"
-
-let to_json ttf range_str =
-	let lut = TTFTools.build_lut ttf range_str in
-	let glyfs = Hashtbl.fold (fun k v acc -> (k,ttf.ttf_glyfs.(v)) :: acc) lut [] in
-	let glyfs = List.stable_sort (fun a b -> compare (fst a) (fst b)) glyfs in
-	List.map (fun (k,g) -> write_glyph ttf k g) glyfs

+ 0 - 688
libs/ttflib/tTFParser.ml

@@ -1,688 +0,0 @@
-(*
- * Copyright (C)2005-2014 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *)
-
-open TTFData
-open IO
-
-type ctx = {
-	file : Stdlib.in_channel;
-	ch : input;
-	mutable entry : entry;
-}
-
-let rd16 = BigEndian.read_i16
-let rdu16 = BigEndian.read_ui16
-let rd32 = BigEndian.read_i32
-let rd32r = BigEndian.read_real_i32
-
-let parse_header ctx =
-	let ch = ctx.ch in
-	let major_version = rdu16 ch in
-	let minor_version = rdu16 ch in
-	let num_tables = rdu16 ch in
-	let search_range = rdu16 ch in
-	let entry_selector = rdu16 ch in
-	let range_shift = rdu16 ch in
-	{
-		hd_major_version = major_version;
-		hd_minor_version = minor_version;
-		hd_num_tables = num_tables;
-		hd_search_range = search_range;
-		hd_entry_selector = entry_selector;
-		hd_range_shift = range_shift;
-	}
-
-let parse_directory ctx header =
-	let ch = ctx.ch in
-	let directory = Hashtbl.create 0 in
-	for i = 0 to header.hd_num_tables - 1 do
-		let name = nread_string ch 4 in
-		let cs = rd32r ch in
-		let off = rd32r ch in
-		let length = rd32r ch in
-		Hashtbl.add directory name {
-			entry_table_name = name;
-			entry_checksum = cs;
-			entry_offset = off;
-			entry_length = length;
-		}
-	done;
-	directory
-
-let parse_head_table ctx =
-	let ch = ctx.ch in
-	let version = rd32r ch in
-	let font_revision = rd32r ch in
-	let checksum_adjustment = rd32r ch in
-	let magic_number = rd32r ch in
-	let flags = rdu16 ch in
-	let units_per_em = rdu16 ch in
-	let created = BigEndian.read_double ch in
-	let modified = BigEndian.read_double ch in
-	let xmin = rd16 ch in
-	let ymin = rd16 ch in
-	let xmax = rd16 ch in
-	let ymax = rd16 ch in
-	let mac_style = rdu16 ch in
-	let lowest_rec_ppem = rdu16 ch in
-	let font_direction_hint = rd16 ch in
-	let index_to_loc_format = rd16 ch in
-	let glyph_data_format = rd16 ch in
-	{
-		hd_version = version;
-		hd_font_revision = font_revision;
-		hd_checksum_adjustment = checksum_adjustment;
-		hd_magic_number = magic_number;
-		hd_flags = flags;
-		hd_units_per_em = units_per_em;
-		hd_created = created;
-		hd_modified = modified;
-		hd_xmin = xmin;
-		hd_ymin = ymin;
-		hd_xmax = xmax;
-		hd_ymax = ymax;
-		hd_mac_style = mac_style;
-		hd_lowest_rec_ppem = lowest_rec_ppem;
-		hd_font_direction_hint = font_direction_hint;
-		hd_index_to_loc_format = index_to_loc_format;
-		hd_glyph_data_format = glyph_data_format;
-	}
-
-let parse_hhea_table ctx =
-	let ch = ctx.ch in
-	let version = rd32r ch in
-	let ascender = rd16 ch in
-	let descender = rd16 ch in
-	let line_gap = rd16 ch in
-	let advance_width_max = rdu16 ch in
-	let min_left_side_bearing = rd16 ch in
-	let min_right_side_bearing = rd16 ch in
-	let x_max_extent = rd16 ch in
-	let caret_slope_rise = rd16 ch in
-	let caret_slope_run = rd16 ch in
-	let caret_offset = rd16 ch in
-	let reserved = nread_string ch 8 in
-	let metric_data_format = rd16 ch in
-	let number_of_hmetrics = rdu16 ch in
-	{
-		hhea_version = version;
-		hhea_ascent = ascender;
-		hhea_descent = descender;
-		hhea_line_gap = line_gap;
-		hhea_advance_width_max = advance_width_max;
-		hhea_min_left_side_bearing = min_left_side_bearing;
-		hhea_min_right_side_bearing = min_right_side_bearing;
-		hhea_x_max_extent = x_max_extent;
-		hhea_caret_slope_rise = caret_slope_rise;
-		hhea_caret_slope_run = caret_slope_run;
-		hhea_caret_offset = caret_offset;
-		hhea_reserved = reserved;
-		hhea_metric_data_format = metric_data_format;
-		hhea_number_of_hmetrics = number_of_hmetrics;
-	}
-
-let parse_maxp_table ctx =
-	let ch = ctx.ch in
-	let version_number = rd32r ch in
-	let num_glyphs = rdu16 ch in
-	let max_points = rdu16 ch in
-	let max_contours = rdu16 ch in
-	let max_component_points = rdu16 ch in
-	let max_component_contours = rdu16 ch in
-	let max_zones = rdu16 ch in
-	let max_twilight_points = rdu16 ch in
-	let max_storage = rdu16 ch in
-	let max_function_defs = rdu16 ch in
-	let max_instruction_defs = rdu16 ch in
-	let max_stack_elements = rdu16 ch in
-	let max_size_of_instructions = rdu16 ch in
-	let max_component_elements = rdu16 ch in
-	let max_component_depth = rdu16 ch in
-	{
-		maxp_version_number = version_number;
-		maxp_num_glyphs = num_glyphs;
-		maxp_max_points = max_points;
-		maxp_max_contours = max_contours;
-		maxp_max_component_points = max_component_points;
-		maxp_max_component_contours = max_component_contours;
-		maxp_max_zones = max_zones;
-		maxp_max_twilight_points = max_twilight_points;
-		maxp_max_storage = max_storage;
-		maxp_max_function_defs = max_function_defs;
-		maxp_max_instruction_defs = max_instruction_defs;
-		maxp_max_stack_elements = max_stack_elements;
-		maxp_max_size_of_instructions = max_size_of_instructions;
-		maxp_max_component_elements = max_component_elements;
-		maxp_max_component_depth = max_component_depth;
-	}
-
-let parse_loca_table head maxp ctx =
-	let ch = ctx.ch in
-	if head.hd_index_to_loc_format = 0 then
-		Array.init (maxp.maxp_num_glyphs + 1) (fun _ -> Int32.of_int ((rdu16 ch) * 2))
-	else
-		Array.init (maxp.maxp_num_glyphs + 1) (fun _ -> rd32r ch)
-
-let parse_hmtx_table maxp hhea ctx =
-	let ch = ctx.ch in
-	let last_advance_width = ref 0 in (* check me 1/2*)
-	Array.init maxp.maxp_num_glyphs (fun i ->
-		let advance_width = if i > hhea.hhea_number_of_hmetrics-1 then (* check me 2/2*)
-			!last_advance_width
-		else
-			rdu16 ch
-		in
-		last_advance_width := advance_width;
-		let left_side_bearing = rd16 ch in
-		{
-			advance_width = advance_width;
-			left_side_bearing = left_side_bearing;
-		}
-	)
-
-let parse_cmap_table ctx =
-	let ch = ctx.ch in
-	let version = rdu16 ch in
-	let num_subtables = rdu16 ch in
-	let dir = ExtList.List.init num_subtables (fun _ ->
-		let platform_id = rdu16 ch in
-		let platform_specific_id = rdu16 ch in
-		let offset = rd32r ch in
-		{
-			csh_platform_id = platform_id;
-			csh_platform_specific_id = platform_specific_id;
-			csh_offset = offset;
-		}
-	) in
-	let dir = List.stable_sort (fun csh1 csh2 ->
-		if csh1.csh_platform_id < csh2.csh_platform_id then -1
-		else if csh1.csh_platform_id > csh2.csh_platform_id then 1
-		else compare csh1.csh_platform_specific_id csh2.csh_platform_specific_id
-	) dir in
-	let parse_sub entry =
-		seek_in ctx.file ((Int32.to_int ctx.entry.entry_offset) + (Int32.to_int entry.csh_offset));
-		let format = rdu16 ch in
-		let def = match format with
-			| 0 ->
-				let length = rdu16 ch in
-				let language = rdu16 ch in
-				let glyph_index = Array.init 256 (fun _ -> read ch) in
-				Cmap0 {
-					c0_format = 0;
-					c0_length = length;
-					c0_language = language;
-					c0_glyph_index_array = glyph_index;
-				}
-			| 4 ->
-				let length = rdu16 ch in
-				let language = rdu16 ch in
-				let seg_count_x2 = rdu16 ch in
-				let seg_count = seg_count_x2 / 2 in
-				let search_range = rdu16 ch in
-				let entry_selector = rdu16 ch in
-				let range_shift = rdu16 ch in
-				let end_code = Array.init seg_count (fun _ -> rdu16 ch) in
-				let reserved = rdu16 ch in
-				assert (reserved = 0);
-				let start_code = Array.init seg_count (fun _ -> rdu16 ch) in
-				let id_delta = Array.init seg_count (fun _ -> rdu16 ch) in
-				let id_range_offset = Array.init seg_count (fun _ -> rdu16 ch) in
-				let count = (length - (8 * seg_count + 16)) / 2 in
-				let glyph_index = Array.init count (fun _ -> rdu16 ch) in
-				Cmap4 {
-					c4_format = format;
-					c4_length = length;
-					c4_language = language;
-					c4_seg_count_x2 = seg_count_x2;
-					c4_search_range = search_range;
-					c4_entry_selector = entry_selector;
-					c4_range_shift = range_shift;
-					c4_end_code = end_code;
-					c4_reserved_pad = reserved;
-					c4_start_code = start_code;
-					c4_id_delta = id_delta;
-					c4_id_range_offset = id_range_offset;
-					c4_glyph_index_array = glyph_index;
-				}
-			| 6 ->
-				let length = rdu16 ch in
-				let language = rdu16 ch in
-				let first_code = rdu16 ch in
-				let entry_count = rdu16 ch in
-				let glyph_index = Array.init entry_count (fun _ -> rdu16 ch) in
-				Cmap6 {
-					c6_format = format;
-					c6_length = length;
-					c6_language = language;
-					c6_first_code = first_code;
-					c6_entry_count = entry_count;
-					c6_glyph_index_array = glyph_index;
-				}
-  			| 12 ->
-				ignore (rd16 ch);
-				let length = rd32r ch in
-				let language = rd32r ch in
-				let num_groups = rd32r ch in
-				let groups = ExtList.List.init (Int32.to_int num_groups) (fun _ ->
-					let start = rd32r ch in
-					let stop = rd32r ch in
-					let start_glyph = rd32r ch in
-					{
-						c12g_start_char_code = start;
-						c12g_end_char_code = stop;
-						c12g_start_glyph_code = start_glyph;
-					}
-				) in
-				Cmap12 {
-					c12_format = Int32.of_int 12;
-					c12_length = length;
-					c12_language = language;
-					c12_num_groups = num_groups;
-					c12_groups = groups;
-				}
-			| x ->
-				failwith ("Not implemented format: " ^ (string_of_int x));
-		in
-		{
-			cs_def = def;
-			cs_header = entry;
-		}
-
-	in
-	{
-		cmap_version = version;
-		cmap_num_subtables = num_subtables;
-		cmap_subtables = List.map parse_sub dir;
-	}
-
-let parse_glyf_table maxp loca cmap hmtx ctx =
-	let ch = ctx.ch in
-	let parse_glyf i =
-		seek_in ctx.file ((Int32.to_int ctx.entry.entry_offset) + (Int32.to_int loca.(i)));
-		let num_contours = rd16 ch in
-		let xmin = rd16 ch in
-		let ymin = rd16 ch in
-		let xmax = rd16 ch in
-		let ymax = rd16 ch in
-		let header = {
-			gh_num_contours = num_contours;
-			gh_xmin = xmin;
-			gh_ymin = ymin;
-			gh_xmax = xmax;
-			gh_ymax = ymax;
-		} in
-		if num_contours >= 0 then begin
-			let num_points = ref 0 in
-			let end_pts_of_contours = Array.init num_contours (fun i ->
-				let v = rdu16 ch in
-				if i = num_contours - 1 then num_points := v + 1;
-				v
-			) in
-			let instruction_length = rdu16 ch in
-			let instructions = Array.init instruction_length (fun _ ->
-				read ch
-			) in
-			let flags = DynArray.create () in
-			let rec loop index =
-				if index >= !num_points then () else begin
-					let v = read_byte ch in
-					let incr = if (v land 8) == 0 then begin
-						DynArray.add flags v;
-						1
-					end else begin
-						let r = (int_of_char (read ch)) in
-						for i = 0 to r do DynArray.add flags v done;
-						r + 1
-					end in
-					loop (index + incr)
-				end
-			in
-			loop 0;
-			assert (DynArray.length flags = !num_points);
-			let x_coordinates = Array.init !num_points (fun i ->
-				let flag = DynArray.get flags i in
-				if flag land 0x10 <> 0 then begin
-					if flag land 0x02 <> 0 then read_byte ch
-					else 0
-				end else begin
-					if flag land 0x02 <> 0 then -read_byte ch
-					else rd16 ch
-				end
-			) in
-			let y_coordinates = Array.init !num_points (fun i ->
-				let flag = DynArray.get flags i in
-				if flag land 0x20 <> 0 then begin
-					if flag land 0x04 <> 0 then read_byte ch
-					else 0
-				end else begin
-					if flag land 0x04 <> 0 then -read_byte ch
-					else rd16 ch
-				end;
-			) in
-			TGlyfSimple (header, {
-				gs_end_pts_of_contours = end_pts_of_contours;
-				gs_instruction_length = instruction_length;
-				gs_instructions = instructions;
-				gs_flags = DynArray.to_array flags;
-				gs_x_coordinates = x_coordinates;
-				gs_y_coordinates = y_coordinates;
-			})
-		end else if num_contours = -1 then begin
-			let acc = DynArray.create () in
-			let rec loop () =
-				let flags = rdu16 ch in
-				let glyph_index = rdu16 ch in
-				let arg1,arg2 = if flags land 1 <> 0 then begin
-					let arg1 = rd16 ch in
-					let arg2 = rd16 ch in
-					arg1,arg2
-				end else begin
-					let arg1 = read_byte ch in
-					let arg2 = read_byte ch in
-					arg1,arg2
-				end in
-				let fmt214 i = (float_of_int i) /. (float_of_int 0x4000) in
-				let fmode =	if flags land 8 <> 0 then
-					Scale (fmt214 (rd16 ch))
-				else if flags land 64 <> 0 then begin
-					let s1 = fmt214 (rd16 ch) in
-					let s2 = fmt214 (rd16 ch) in
-					ScaleXY (s1,s2)
-				end else if flags land 128 <> 0 then begin
-					let a = fmt214 (rd16 ch) in
-					let b = fmt214 (rd16 ch) in
-					let c = fmt214 (rd16 ch) in
-					let d = fmt214 (rd16 ch) in
-					ScaleMatrix (a,b,c,d)
-				end else
-					NoScale
-				in
-				DynArray.add acc {
-					gc_flags = flags;
-					gc_glyf_index = glyph_index;
-					gc_arg1 = if flags land 2 <> 0 then arg1 else 0;
-					gc_arg2 = if flags land 2 <> 0 then arg2 else 0;
-					gc_transformation = fmode;
-				};
-				if flags land 0x20 <> 0 then loop ();
-			in
-			loop ();
-			TGlyfComposite (header,(DynArray.to_list acc))
-		end else
-			failwith "Unknown Glyf"
-	in
-	Array.init maxp.maxp_num_glyphs (fun i ->
-		let len = (Int32.to_int loca.(i + 1)) - (Int32.to_int loca.(i)) in
-		if len > 0 then parse_glyf i else TGlyfNull
-	)
-
-let parse_kern_table ctx =
-	let ch = ctx.ch in
-	let version = Int32.of_int (rd16 ch) in
-	let num_tables = Int32.of_int (rd16 ch) in
-	let tables = ExtList.List.init (Int32.to_int num_tables) (fun _ ->
-		let length = Int32.of_int (rdu16 ch) in
-		let tuple_index = rdu16 ch in
-		let coverage = rdu16 ch in
-		let def = match coverage lsr 8 with
-		| 0 ->
-			let num_pairs = rdu16 ch in
-			let search_range = rdu16 ch in
-			let entry_selector = rdu16 ch in
-			let range_shift = rdu16 ch in
-			let kerning_pairs = ExtList.List.init num_pairs (fun _ ->
-				let left = rdu16 ch in
-				let right = rdu16 ch in
-				let value = rd16 ch in
-				{
-					kern_left = left;
-					kern_right = right;
-					kern_value = value;
-				}
-			) in
-			Kern0 {
-				k0_num_pairs = num_pairs;
-				k0_search_range = search_range;
-				k0_entry_selector = entry_selector;
-				k0_range_shift = range_shift;
-				k0_pairs = kerning_pairs;
-			}
-		| 2 ->
-			let row_width = rdu16 ch in
-			let left_offset_table = rdu16 ch in
-			let right_offset_table = rdu16 ch in
-			let array_offset = rdu16 ch in
-			let first_glyph = rdu16 ch in
-			let num_glyphs = rdu16 ch in
-			let offsets = ExtList.List.init num_glyphs (fun _ ->
-				rdu16 ch
-			) in
-			Kern2 {
-				k2_row_width = row_width;
-				k2_left_offset_table = left_offset_table;
-				k2_right_offset_table = right_offset_table;
-				k2_array = array_offset;
-				k2_first_glyph = first_glyph;
-				k2_num_glyphs = num_glyphs;
-				k2_offsets = offsets;
-			}
-		| i ->
-			failwith ("Unknown kerning: " ^ (string_of_int i));
-		in
-		{
-			ks_def = def;
-			ks_header = {
-				ksh_length = length;
-				ksh_coverage = coverage;
-				ksh_tuple_index = tuple_index;
-			}
-		}
-	) in
-	{
-		kern_version = version;
-		kern_num_tables = num_tables;
-		kern_subtables = tables;
-	}
-
-let parse_name_table ctx =
-	let ch = ctx.ch in
-	let format = rdu16 ch in
-	let num_records = rdu16 ch in
-	let offset = rdu16 ch in
-	let records = Array.init num_records (fun _ ->
-		let platform_id = rdu16 ch in
-		let platform_specific_id = rdu16 ch in
-		let language_id = rdu16 ch in
-		let name_id = rdu16 ch in
-		let length = rdu16 ch in
-		let offset = rdu16 ch in
-		{
-			nr_platform_id = platform_id;
-			nr_platform_specific_id = platform_specific_id;
-			nr_language_id = language_id;
-			nr_name_id = name_id;
-			nr_length = length;
-			nr_offset = offset;
-			nr_value = "";
-		}
-	) in
-	let ttf_name = ref "" in
-	(* TODO: use real utf16 conversion *)
-	let set_name n =
-		let l = ExtList.List.init (String.length n / 2) (fun i -> String.make 1 n.[i * 2 + 1]) in
-		ttf_name := String.concat "" l
-	in
-	let records = Array.map (fun r ->
-		seek_in ctx.file ((Int32.to_int ctx.entry.entry_offset) + offset + r.nr_offset);
-		r.nr_value <- nread_string ch r.nr_length;
-		if r.nr_name_id = 4 && r.nr_platform_id = 3 || r.nr_platform_id = 0 then set_name r.nr_value;
-		r
-	) records in
-	{
-		name_format = format;
-		name_num_records = num_records;
-		name_offset = offset;
-		name_records = records;
-	},!ttf_name
-
-let parse_os2_table ctx =
-	let ch = ctx.ch in
-	let version = rdu16 ch in
-	let x_avg_char_width = rd16 ch in
-	let us_weight_class = rdu16 ch in
-	let us_width_class = rdu16 ch in
-	let fs_type = rd16 ch in
-	let y_subscript_x_size = rd16 ch in
-	let y_subscript_y_size = rd16 ch in
-	let y_subscript_x_offset = rd16 ch in
-	let y_subscript_y_offset = rd16 ch in
-	let y_superscript_x_size = rd16 ch in
-	let y_superscript_y_size = rd16 ch in
-	let y_superscript_x_offset = rd16 ch in
-	let y_superscript_y_offset = rd16 ch in
-	let y_strikeout_size = rd16 ch in
-	let y_strikeout_position = rd16 ch in
-	let s_family_class = rd16 ch in
-
-	let b_family_type = read_byte ch in
-	let b_serif_style = read_byte ch in
-	let b_weight = read_byte ch in
-	let b_proportion = read_byte ch in
-	let b_contrast = read_byte ch in
-	let b_stroke_variation = read_byte ch in
-	let b_arm_style = read_byte ch in
-	let b_letterform = read_byte ch in
-	let b_midline = read_byte ch in
-	let b_x_height = read_byte ch in
-
-	let ul_unicode_range_1 = rd32r ch in
-	let ul_unicode_range_2 = rd32r ch in
-	let ul_unicode_range_3 = rd32r ch in
-	let ul_unicode_range_4 = rd32r ch in
-	let ach_vendor_id = rd32r ch in
-	let fs_selection = rd16 ch in
-	let us_first_char_index = rdu16 ch in
-	let us_last_char_index = rdu16 ch in
-	let s_typo_ascender = rd16 ch in
-	let s_typo_descender = rd16 ch in
-	let s_typo_line_gap = rd16 ch in
-	let us_win_ascent = rdu16 ch in
-	let us_win_descent = rdu16 ch in
-	{
-		os2_version = version;
-		os2_x_avg_char_width = x_avg_char_width;
-		os2_us_weight_class = us_weight_class;
-		os2_us_width_class = us_width_class;
-		os2_fs_type = fs_type;
-		os2_y_subscript_x_size = y_subscript_x_size;
-		os2_y_subscript_y_size = y_subscript_y_size;
-		os2_y_subscript_x_offset = y_subscript_x_offset;
-		os2_y_subscript_y_offset = y_subscript_y_offset;
-		os2_y_superscript_x_size = y_superscript_x_size;
-		os2_y_superscript_y_size = y_superscript_y_size;
-		os2_y_superscript_x_offset = y_superscript_x_offset;
-		os2_y_superscript_y_offset = y_superscript_y_offset;
-		os2_y_strikeout_size = y_strikeout_size;
-		os2_y_strikeout_position = y_strikeout_position;
-		os2_s_family_class = s_family_class;
-		os2_b_family_type = b_family_type;
-		os2_b_serif_style = b_serif_style;
-		os2_b_weight = b_weight;
-		os2_b_proportion = b_proportion;
-		os2_b_contrast = b_contrast;
-		os2_b_stroke_variation = b_stroke_variation;
-		os2_b_arm_style = b_arm_style;
-		os2_b_letterform = b_letterform;
-		os2_b_midline = b_midline;
-		os2_b_x_height = b_x_height;
-		os2_ul_unicode_range_1 = ul_unicode_range_1;
-		os2_ul_unicode_range_2 = ul_unicode_range_2;
-		os2_ul_unicode_range_3 = ul_unicode_range_3;
-		os2_ul_unicode_range_4 = ul_unicode_range_4;
-		os2_ach_vendor_id = ach_vendor_id;
-		os2_fs_selection = fs_selection;
-		os2_us_first_char_index = us_first_char_index;
-		os2_us_last_char_index = us_last_char_index;
-		os2_s_typo_ascender = s_typo_ascender;
-		os2_s_typo_descender = s_typo_descender;
-		os2_s_typo_line_gap = s_typo_line_gap;
-		os2_us_win_ascent = us_win_ascent;
-		os2_us_win_descent = us_win_descent;
-	}
-
-let parse file : ttf =
-	let ctx = {
-		file = file;
-		ch = input_channel file;
-		entry = {
-			entry_table_name = "";
-			entry_offset = Int32.of_int 0;
-			entry_length = Int32.of_int 0;
-			entry_checksum = Int32.of_int 0;
-		}
-	} in
-	let header = parse_header ctx in
-	let directory = parse_directory ctx header in
-	let parse_table entry f =
-		seek_in file (Int32.to_int entry.entry_offset);
-		ctx.entry <- entry;
-		f ctx
-	in
-	let parse_req_table name f =
-		try
-			let entry = Hashtbl.find directory name in
-			parse_table entry f
-		with Not_found ->
-			failwith (Printf.sprintf "Required table %s could not be found" name)
-	in
-	let parse_opt_table name f =
-		try
-			let entry = Hashtbl.find directory name in
-			Some (parse_table entry f)
-		with Not_found ->
-			None
-	in
-	let head = parse_req_table "head" parse_head_table in
-	let hhea = parse_req_table "hhea" parse_hhea_table in
-	let maxp = parse_req_table "maxp" parse_maxp_table in
-	let loca = parse_req_table "loca" (parse_loca_table head maxp) in
-	let hmtx = parse_req_table "hmtx" (parse_hmtx_table maxp hhea) in
-	let cmap = parse_req_table "cmap" (parse_cmap_table) in
-	let glyfs = parse_req_table "glyf" (parse_glyf_table maxp loca cmap hmtx) in
-	let kern = parse_opt_table "kern" (parse_kern_table) in
-	let name,ttf_name = parse_req_table "name" (parse_name_table) in
-	let os2 = parse_req_table "OS/2" (parse_os2_table) in
-	{
-		ttf_header = header;
-		ttf_font_name = ttf_name;
-		ttf_directory = directory;
-		ttf_head = head;
-		ttf_hhea = hhea;
-		ttf_maxp = maxp;
-		ttf_loca = loca;
-		ttf_hmtx = hmtx;
-		ttf_cmap = cmap;
-		ttf_glyfs = glyfs;
-		ttf_name = name;
-		ttf_os2 = os2;
-		ttf_kern = kern;
-	}

+ 0 - 211
libs/ttflib/tTFSwfWriter.ml

@@ -1,211 +0,0 @@
-(*
- * Copyright (C)2005-2014 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *)
-
-open TTFData
-open Swf
-
-let num_bits x =
-	if x = 0 then
-		0
-	else
-		let rec loop n v =
-			if v = 0 then n else loop (n + 1) (v lsr 1)
-		in
-		loop 1 (abs x)
-
-let round x = int_of_float (floor (x +. 0.5))
-
-let to_twips v = round (v *. 20.)
-
-type ctx = {
-	ttf : ttf;
-}
-
-let begin_fill =
-	SRStyleChange {
-		scsr_move = None;
-		scsr_fs0 = Some(1);
-		scsr_fs1 = None;
-		scsr_ls = None;
-		scsr_new_styles = None;
-	}
-
-let end_fill =
-	SRStyleChange {
-		scsr_move = None;
-		scsr_fs0 = None;
-		scsr_fs1 = None;
-		scsr_ls = None;
-		scsr_new_styles = None;
-	}
-
-let align_bits x nbits = x land ((1 lsl nbits ) - 1)
-
-let move_to ctx x y =
-	let x = to_twips x in
-	let y = to_twips y in
-	let nbits = max (num_bits x) (num_bits y) in
-	SRStyleChange {
-		scsr_move = Some (nbits, align_bits x nbits, align_bits y nbits);
-		scsr_fs0 = Some(1);
-		scsr_fs1 = None;
-		scsr_ls = None;
-		scsr_new_styles = None;
-	}
-
-let line_to ctx x y =
-	let x = to_twips x in
-	let y = to_twips y in
-	if x = 0 && y = 0 then raise Exit;
-	let nbits = max (num_bits x) (num_bits y) in
-	SRStraightEdge {
-		sser_nbits = nbits;
-		sser_line = (if x = 0 then None else Some(align_bits x nbits)), (if y = 0 then None else Some(align_bits y nbits));
-	}
-
-let curve_to ctx cx cy ax ay =
-	let cx = to_twips cx in
-	let cy = to_twips cy in
-	let ax = to_twips ax in
-	let ay = to_twips ay in
-	let nbits = max (max (num_bits cx) (num_bits cy)) (max (num_bits ax) (num_bits ay)) in
-	SRCurvedEdge {
-		scer_nbits = nbits;
-		scer_cx = align_bits cx nbits;
-		scer_cy = align_bits cy nbits;
-		scer_ax = align_bits ax nbits;
-		scer_ay = align_bits ay nbits;
-	}
-
-open TTFTools
-
-let write_paths ctx paths =
-	let scale = 1024. /. (float_of_int ctx.ttf.ttf_head.hd_units_per_em) in
-	let srl = DynArray.create () in
-	List.iter (fun path ->
-		try
-			DynArray.add srl (match path.gp_type with
-			| 0 -> move_to ctx (path.gp_x *. scale) ((-1.) *. path.gp_y *. scale);
-			| 1 -> line_to ctx (path.gp_x *. scale) ((-1.) *. path.gp_y *. scale);
-			| 2 -> curve_to ctx (path.gp_cx *. scale) ((-1.) *. path.gp_cy *. scale) (path.gp_x *. scale) ((-1.) *. path.gp_y *. scale);
-			| _ -> assert false)
-		with Exit ->
-			()
-	) paths;
-	DynArray.add srl (end_fill);
-	{
-		srs_nfbits = 1;
-		srs_nlbits = 0;
-		srs_records = DynArray.to_list srl;
-	}
-
-let rec write_glyph ctx key glyf =
-	{
-		font_char_code = key;
-		font_shape = write_paths ctx (TTFTools.build_glyph_paths ctx.ttf true glyf);
-	}
-
-let write_font_layout ctx lut =
-	let scale = 1024. /. (float_of_int ctx.ttf.ttf_head.hd_units_per_em) in
-	let hmtx = Hashtbl.fold (fun k v acc -> (k,ctx.ttf.ttf_hmtx.(v)) :: acc) lut [] in
-	let hmtx = List.stable_sort (fun a b -> compare (fst a) (fst b)) hmtx in
-	let hmtx = List.map (fun (k,g) -> g) hmtx in
-	{
-			font_ascent = round((float_of_int ctx.ttf.ttf_os2.os2_us_win_ascent) *. scale *. 20.);
-			font_descent = round((float_of_int ctx.ttf.ttf_os2.os2_us_win_descent) *. scale *. 20.);
-			font_leading = round(((float_of_int(ctx.ttf.ttf_os2.os2_us_win_ascent + ctx.ttf.ttf_os2.os2_us_win_descent - ctx.ttf.ttf_head.hd_units_per_em)) *. scale) *. 20.);
-			font_glyphs_layout = Array.of_list( ExtList.List.mapi (fun i h ->
-			{
-				font_advance = round((float_of_int h.advance_width) *. scale *. 20.);
-				font_bounds = {rect_nbits=0; left=0; right=0; top=0; bottom=0};
-			}) hmtx );
-			font_kerning = [];
-	}
-
-let bi v = if v then 1 else 0
-
-let int_from_langcode lc =
-	match lc with
-	| LCNone -> 0
-	| LCLatin -> 1
-	| LCJapanese -> 2
-	| LCKorean -> 3
-	| LCSimplifiedChinese -> 4
-	| LCTraditionalChinese -> 5
-
-let write_font2 ch b f2 =
-	IO.write_bits b 1 (bi true);
-	IO.write_bits b 1 (bi f2.font_shift_jis);
-	IO.write_bits b 1 (bi f2.font_is_small);
-	IO.write_bits b 1 (bi f2.font_is_ansi);
-	IO.write_bits b 1 (bi f2.font_wide_offsets);
-	IO.write_bits b 1 (bi f2.font_wide_codes);
-	IO.write_bits b 1 (bi f2.font_is_italic);
-	IO.write_bits b 1 (bi f2.font_is_bold);
-	IO.write_byte ch (int_from_langcode f2.font_language);
-	IO.write_byte ch ((String.length f2.font_name) + 1);
-	IO.nwrite_string ch f2.font_name;
-	IO.write_byte ch 0;
-	IO.write_ui16 ch (Array.length f2.font_glyphs);
-	let glyph_offset = ref (((Array.length f2.font_glyphs) * 4)+4) in
-	Array.iter (fun g ->
-		IO.write_i32 ch !glyph_offset;
-		glyph_offset := !glyph_offset + SwfParser.font_shape_records_length g.font_shape;
-	)f2.font_glyphs;
-	IO.write_i32 ch !glyph_offset;
-	Array.iter (fun g -> SwfParser.write_shape_without_style ch g.font_shape;) f2.font_glyphs;
-	Array.iter (fun g -> IO.write_ui16 ch g.font_char_code; )f2.font_glyphs;
-	IO.write_i16 ch f2.font_layout.font_ascent;
-	IO.write_i16 ch f2.font_layout.font_descent;
-	IO.write_i16 ch f2.font_layout.font_leading;
-	Array.iter (fun g ->
-		let fa = ref g.font_advance in
-		if (!fa) <  -32767 then fa := -32768;(* fix or check *)
-		if (!fa) > 32766 then fa := 32767;
-		IO.write_i16 ch !fa;) f2.font_layout.font_glyphs_layout;
-	Array.iter (fun g -> SwfParser.write_rect ch g.font_bounds;) f2.font_layout.font_glyphs_layout;
-	IO.write_ui16 ch 0 (* TODO: optional FontKerningTable *)
-
-let to_swf ttf config =
-	let ctx = {
-		ttf = ttf;
-	} in
-	let lut = TTFTools.build_lut ttf config.ttfc_range_str in
-	let glyfs = Hashtbl.fold (fun k v acc -> (k,ctx.ttf.ttf_glyfs.(v)) :: acc) lut [] in
-	let glyfs = List.stable_sort (fun a b -> compare (fst a) (fst b)) glyfs in
-	let glyfs = List.map (fun (k,g) -> write_glyph ctx k g) glyfs in
-	let glyfs_font_layout = write_font_layout ctx lut in
-	let glyfs = Array.of_list glyfs in
-	{
-		font_shift_jis = false;
-		font_is_small = false;
-		font_is_ansi = false;
-		font_wide_offsets = true;
-		font_wide_codes = true;
-		font_is_italic = config.ttfc_font_posture = TFPItalic;
-		font_is_bold = config.ttfc_font_weight = TFWBold;
-		font_language = LCNone;
-		font_name = (match config.ttfc_font_name with Some s -> s | None -> ttf.ttf_font_name);
-		font_glyphs = glyfs;
-		font_layout = glyfs_font_layout;
-	}
-;;

+ 0 - 275
libs/ttflib/tTFTools.ml

@@ -1,275 +0,0 @@
-(*
- * Copyright (C)2005-2014 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *)
-open Extlib_leftovers
-open TTFData
-
-type glyf_transformation_matrix = {
-	mutable a : float;
-	mutable b : float;
-	mutable c : float;
-	mutable d : float;
-	mutable tx : float;
-	mutable ty : float;
-}
-
-type glyf_path = {
-	gp_type : int;
-	gp_x : float;
-	gp_y : float;
-	gp_cx : float;
-	gp_cy : float;
-}
-
-type simple_point = {
-	x : float;
-	y : float;
-}
-
-let mk_path t x y cx cy = {
-	gp_type = t;
-	gp_x = x;
-	gp_y = y;
-	gp_cx = cx;
-	gp_cy = cy;
-}
-
-let identity () = {
-	a = 1.0;
-	b = 0.0;
-	c = 0.0;
-	d = 1.0;
-	tx = 0.0;
-	ty = 0.0;
-}
-
-let multiply m x y =
-	x *. m.a +. y *. m.b +. m.tx,
-	x *. m.c +. y *. m.d +. m.ty
-
-(* TODO: check if this can be done in the parser directly *)
-let matrix_from_composite gc =
-	let a,b,c,d = match gc.gc_transformation with
-		| NoScale -> 1.0,0.0,0.0,1.0
-		| Scale f -> f,0.0,0.0,f
-		| ScaleXY(fx,fy) -> fx,0.0,0.0,fy
-		| ScaleMatrix (a,b,c,d) -> a,b,c,d
-	in
-	let arg1 = float_of_int gc.gc_arg1 in
-	let arg2 = float_of_int gc.gc_arg2 in
-	{
-		a = a;
-		b = b;
-		c = c;
-		d = d;
-		(* TODO: point offsets *)
-		tx = arg1 *. a +. arg2 *. b;
-		ty = arg1 *. c +. arg2 *. d;
-	}
-
-let relative_matrix m = {m with tx = 0.0; ty = 0.0}
-
-let make_coords relative mo g = match mo with
-	| None ->
-		Array.init (Array.length g.gs_x_coordinates) (fun i -> float_of_int g.gs_x_coordinates.(i),float_of_int g.gs_y_coordinates.(i))
-	| Some m ->
-		let m = if relative then relative_matrix m else m in
-		Array.init (Array.length g.gs_x_coordinates) (fun i ->
-			let x,y = float_of_int g.gs_x_coordinates.(i),float_of_int g.gs_y_coordinates.(i) in
-			multiply m x y
-		)
-
-let build_paths relative mo g =
-	let len = Array.length g.gs_x_coordinates in
-	let current_end = ref 0 in
-	let end_pts = Array.init len (fun i ->
-		if g.gs_end_pts_of_contours.(!current_end) = i then begin
-			incr current_end;
-			true
-		end else
-			false
-	) in
-	let is_on i = g.gs_flags.(i) land 0x01 <> 0 in
-	let is_end i = end_pts.(i) in
-	let arr = DynArray.create () in
-	let tx,ty = match mo with None -> 0.0,0.0 | Some m -> m.tx,m.ty in
-	let last_added = ref {
-		x = 0.0;
-		y = 0.0;
-	} in
-	let add_rel t x y cx cy =
-		let p = match t with
-			| 0 ->
-				mk_path t (x +. tx) (y +. ty) cx cy
-			| 1 ->
-				mk_path t (x -. !last_added.x) (y -. !last_added.y) cx cy
-			| 2 ->
-				mk_path t (x -. cx) (y -. cy) (cx -. !last_added.x) (cy -. !last_added.y)
-			| _ ->
-				assert false
-		in
-		last_added := { x = x; y = y; };
-		DynArray.add arr p
-	in
-	let add_abs t x y cx cy = DynArray.add arr (mk_path t x y cx cy) in
-	let add = if relative then add_rel else add_abs in
-	let coords = make_coords relative mo g in
-
-	let left = ref [] in
-	let right = ref [] in
-	let new_contour = ref true in
-	let p = ref { x = 0.0; y = 0.0 } in
-	for i = 0 to len - 1 do
-		p := {
-			x = !p.x +. fst coords.(i);
-			y = !p.y +. snd coords.(i);
-		};
-		let p = !p in
-		let is_on = is_on i in
-		let is_end = is_end i in
-		let rec flush pl = match pl with
-			| c :: a :: [] -> add 2 a.x a.y c.x c.y
-			| a :: [] -> add 1 a.x a.y 0.0 0.0
-			| c1 :: c2 :: pl ->
-				add 2 (c1.x +. (c2.x -. c1.x) /. 2.0) (c1.y +. (c2.y -. c1.y) /. 2.0) c1.x c1.y;
-				flush (c2 :: pl)
-			| _ ->
-				Printf.printf "Fail, len: %i\n" (List.length pl);
-		in
-		if !new_contour then begin
-			if is_on then begin
-				new_contour := false;
-				add 0 p.x p.y 0.0 0.0;
-			end;
-			left := p :: !left
-		end else if is_on || is_end then begin
-			right := p :: !right;
-			if is_on then begin
-				flush (List.rev !right);
-				right := []
-			end;
-			if is_end then begin
-				new_contour := true;
-				flush ((List.rev !right) @ (List.rev !left));
-				left := [];
-				right := [];
-			end
-		end else
-			right := p :: !right
-	done;
-	DynArray.to_list arr
-
-let rec build_glyph_paths ttf relative ?(transformation=None) glyf =
-	match glyf with
-	| TGlyfSimple (h,g) ->
-		build_paths relative transformation g
-	| TGlyfComposite (h,gl) ->
-		List.concat (List.map (fun g ->
-			let t = Some (matrix_from_composite g) in
-			build_glyph_paths ttf relative ~transformation:t (ttf.ttf_glyfs.(g.gc_glyf_index))
-		) gl)
-	| TGlyfNull ->
-		[]
-
-let map_char_code cc c4 =
-	let index = ref 0 in
-	let seg_count = c4.c4_seg_count_x2 / 2 in
-	if cc >= 0xFFFF then 0 else begin
-		for i = 0 to seg_count - 1 do
-			if c4.c4_end_code.(i) >= cc && c4.c4_start_code.(i) <= cc then begin
-				if c4.c4_id_range_offset.(i) > 0 then
-					let v = c4.c4_id_range_offset.(i)/2 + cc - c4.c4_start_code.(i) - seg_count + i in
-					index := c4.c4_glyph_index_array.(v)
-				else
-					index := (c4.c4_id_delta.(i) + cc) mod 65536
-			end
-		done;
-		!index
-	end
-
-let parse_range_str str =
-	let last = ref (Char.code '\\') in
-	let range = ref false in
-	let lut = Hashtbl.create 0 in
-	UTF8.iter (fun code ->
-		let code = UCharExt.code code in
-		if code = Char.code '-' && !last <> Char.code '\\' then
-			range := true
-		else if !range then begin
-			range := false;
-			for i = !last to code do
-				Hashtbl.replace lut i true;
-			done;
-		end else begin
-			Hashtbl.replace lut code true;
-			last := code;
-		end
-	) str;
-	if !range then Hashtbl.replace lut (Char.code '-') true;
-	lut
-
-let build_lut ttf range_str =
-	let lut = Hashtbl.create 0 in
-	Hashtbl.add lut 0 0;
-	Hashtbl.add lut 1 1;
-	Hashtbl.add lut 2 2;
-	let add_character = if range_str = "" then
-			fun k v -> Hashtbl.replace lut k v
-		else begin
-			let range = parse_range_str range_str in
-			fun k v -> if Hashtbl.mem range k then Hashtbl.replace lut k v
-		end
-	in
-	let make_cmap4_map c4 =
-		let seg_count = c4.c4_seg_count_x2 / 2 in
-		for i = 0 to seg_count - 1 do
-			for j = c4.c4_start_code.(i) to c4.c4_end_code.(i) do
-				let index = map_char_code j c4 in
-				add_character j index;
-			done;
-		done
-	in
-(*  	let make_cmap12_map c12 =
-		List.iter (fun group ->
-			let rec loop cc gi =
-				add_character cc gi;
-				if cc < (Int32.to_int group.c12g_end_char_code) then loop (cc + 1) (gi + 1)
-			in
-			loop (Int32.to_int group.c12g_start_char_code) (Int32.to_int group.c12g_start_glyph_code)
-		) c12.c12_groups
-	in *)
-	List.iter (fun st -> match st.cs_def with
-		| Cmap0 c0 ->
-			Array.iteri (fun i c -> add_character i (int_of_char c)) c0.c0_glyph_index_array;
-		| Cmap4 c4 ->
-			make_cmap4_map c4;
-		| Cmap12 c12 ->
-			(*
-				TODO: this causes an exception with some fonts:
-				Fatal error: exception IO.Overflow("write_ui16")
-			*)
-			(* make_cmap12_map ctx lut c12; *)
-			()
-		| _ ->
-			(* TODO *)
-			()
-	) ttf.ttf_cmap.cmap_subtables;
-	lut

+ 12 - 6
src-json/meta.json

@@ -316,6 +316,12 @@
 		"targets": ["TAbstract"],
 		"links": ["https://haxe.org/manual/types-abstract-forward.html"]
 	},
+	{
+		"name": "ForwardAccessOnAbstract",
+		"metadata": ":forward.accessOnAbstract",
+		"doc": "Generates @:forward field access on the abstract itself instead of the underlying type.",
+		"targets": ["TAbstract"]
+	},
 	{
 		"name": "ForwardNew",
 		"metadata": ":forward.new",
@@ -431,6 +437,12 @@
 		"platforms": ["hl"],
 		"targets": ["TClass", "TClassField"]
 	},
+	{
+		"name": "HxbId",
+		"metadata": ":hxb.id",
+		"doc": "Internally used by hxb",
+		"internal": true
+	},
 	{
 		"name": "HxCompletion",
 		"metadata": ":hx.completion",
@@ -602,12 +614,6 @@
 		"metadata": ":macro",
 		"doc": "(deprecated)"
 	},
-	{
-		"name": "MaybeUsed",
-		"metadata": ":maybeUsed",
-		"doc": "Internally used by DCE to mark fields that might be kept.",
-		"internal": true
-	},
 	{
 		"name": "MergeBlock",
 		"metadata": ":mergeBlock",

+ 10 - 2
src-json/warning.json

@@ -117,6 +117,14 @@
 		"name": "WConstructorInliningCancelled",
 		"doc": "Constructor call could not be inlined because a field is uninitialized",
 		"parent": "WTyper"
+	},
+	{
+		"name": "WHxb",
+		"doc": "Hxb (either --hxb output or haxe compiler cache) related warnings"
+	},
+	{
+		"name": "WUnboundTypeParameter",
+		"doc": "Hxb (either --hxb output or haxe compiler cache) failed to link a type parameter to an actual type",
+		"parent": "WHxb"
 	}
-
-]
+]

+ 4 - 9
src/codegen/codegen.ml

@@ -307,7 +307,7 @@ module Dump = struct
 				| Some f -> print_field false f);
 				List.iter (print_field false) c.cl_ordered_fields;
 				List.iter (print_field true) c.cl_ordered_statics;
-				(match c.cl_init with
+				(match TClass.get_cl_init c with
 				| None -> ()
 				| Some e ->
 					print "\n\tstatic function __init__() ";
@@ -388,8 +388,8 @@ module Dump = struct
 		let dep = Hashtbl.create 0 in
 		List.iter (fun m ->
 			print "%s:\n" (Path.UniqueKey.lazy_path m.m_extra.m_file);
-			PMap.iter (fun _ (sign,mpath) ->
-				let m2 = com.module_lut#find mpath in
+			PMap.iter (fun _ mdep ->
+				let m2 = com.module_lut#find mdep.md_path in
 				let file = Path.UniqueKey.lazy_path m2.m_extra.m_file in
 				print "\t%s\n" file;
 				let l = try Hashtbl.find dep file with Not_found -> [] in
@@ -490,14 +490,9 @@ let map_source_header com f =
 
 (* Static extensions for classes *)
 module ExtClass = struct
-
-	let add_cl_init c e = match c.cl_init with
-			| None -> c.cl_init <- Some e
-			| Some e' -> c.cl_init <- Some (concat e' e)
-
 	let add_static_init c cf e p =
 		let ethis = Texpr.Builder.make_static_this c p in
 		let ef1 = mk (TField(ethis,FStatic(c,cf))) cf.cf_type p in
 		let e_assign = mk (TBinop(OpAssign,ef1,e)) e.etype p in
-		add_cl_init c e_assign
+		TClass.add_cl_init c e_assign
 end

+ 1 - 1
src/codegen/genxml.ml

@@ -81,7 +81,7 @@ let rec follow_param t =
 		t
 
 let gen_meta meta =
-	let meta = List.filter (fun (m,_,_) -> match m with Meta.Used | Meta.MaybeUsed | Meta.RealPath | Meta.Pure -> false | _ -> true) meta in
+	let meta = List.filter (fun (m,_,_) -> match m with Meta.Used | Meta.RealPath | Meta.Pure | Meta.HxbId -> false | _ -> true) meta in
 	match meta with
 	| [] -> []
 	| _ ->

+ 19 - 7
src/compiler/args.ml

@@ -48,6 +48,7 @@ let parse_args com =
 	let actx = {
 		classes = [([],"Std")];
 		xml_out = None;
+		hxb_out = None;
 		json_out = None;
 		cmds = [];
 		config_macros = [];
@@ -58,6 +59,7 @@ let parse_args com =
 		interp = false;
 		jvm_flag = false;
 		swf_version = false;
+		hxb_libs = [];
 		native_libs = [];
 		raise_usage = (fun () -> ());
 		display_arg = None;
@@ -105,29 +107,36 @@ let parse_args com =
 		),"<name[=path]>","generate code for a custom target");
 		("Target",[],["-x"], Arg.String (fun cl ->
 			let cpath = Path.parse_type_path cl in
-			(match com.main_class with
+			(match com.main.main_class with
 				| Some c -> if cpath <> c then raise (Arg.Bad "Multiple --main classes specified")
-				| None -> com.main_class <- Some cpath);
+				| None -> com.main.main_class <- Some cpath);
 			actx.classes <- cpath :: actx.classes;
 			Common.define com Define.Interp;
-			set_platform com (!Globals.macro_platform) "";
+			set_platform com Eval "";
 			actx.interp <- true;
 		),"<class>","interpret the program using internal macro system");
 		("Target",["--interp"],[], Arg.Unit (fun() ->
 			Common.define com Define.Interp;
-			set_platform com (!Globals.macro_platform) "";
+			set_platform com Eval "";
 			actx.interp <- true;
 		),"","interpret the program using internal macro system");
 		("Target",["--run"],[], Arg.Unit (fun() ->
 			raise (Arg.Bad "--run requires an argument: a Haxe module name")
 		), "<module> [args...]","interpret a Haxe module with command line arguments");
 		("Compilation",["-p";"--class-path"],["-cp"],Arg.String (fun path ->
-			com.class_path <- Path.add_trailing_slash path :: com.class_path
+			com.class_paths#add (new ClassPath.directory_class_path (Path.add_trailing_slash path) User);
 		),"<path>","add a directory to find source files");
+		("Compilation",[],["-libcp"],Arg.String (fun path ->
+			com.class_paths#add (new ClassPath.directory_class_path (Path.add_trailing_slash path) Lib);
+		),"<path>","add a directory to find source files");
+		("Compilation",["--hxb-lib"],["-hxb-lib"],Arg.String (fun file ->
+			let lib = create_native_lib file false HxbLib in
+			actx.hxb_libs <- lib :: actx.hxb_libs
+		),"<path>","add a hxb library");
 		("Compilation",["-m";"--main"],["-main"],Arg.String (fun cl ->
-			if com.main_class <> None then raise (Arg.Bad "Multiple --main classes specified");
+			if com.main.main_class <> None then raise (Arg.Bad "Multiple --main classes specified");
 			let cpath = Path.parse_type_path cl in
-			com.main_class <- Some cpath;
+			com.main.main_class <- Some cpath;
 			actx.classes <- cpath :: actx.classes
 		),"<class>","select startup class");
 		("Compilation",["-L";"--library"],["-lib"],Arg.String (fun _ -> ()),"<name[:ver]>","use a haxelib library");
@@ -256,6 +265,9 @@ let parse_args com =
 		("Services",["--json"],[],Arg.String (fun file ->
 			actx.json_out <- Some file
 		),"<file>","generate JSON types description");
+		("Services",["--hxb"],[], Arg.String (fun dir ->
+			actx.hxb_out <- Some dir;
+		),"<directory>", "generate haxe binary representation in target directory");
 		("Optimization",["--no-output"],[], Arg.Unit (fun() -> actx.no_output <- true),"","compiles but does not generate any file");
 		("Debug",["--times"],[], Arg.Unit (fun() -> Timer.measure_times := true),"","measure compilation times");
 		("Optimization",["--no-inline"],[],Arg.Unit (fun () ->

+ 49 - 17
src/compiler/compilationCache.ml

@@ -5,7 +5,7 @@ open Type
 open Define
 
 type cached_file = {
-	c_file_path : string;
+	c_file_path : ClassPaths.resolved_file;
 	c_time : float;
 	c_package : string list;
 	c_decls : type_decl list;
@@ -23,9 +23,18 @@ type cached_native_lib = {
 	c_nl_files : (path,Ast.package) Hashtbl.t;
 }
 
-class context_cache (index : int) = object(self)
+let get_module_name_of_cfile file cfile = match cfile.c_module_name with
+	| None ->
+		let name = Path.module_name_of_file file in
+		cfile.c_module_name <- Some name;
+		name
+	| Some name ->
+		name
+
+class context_cache (index : int) (sign : Digest.t) = object(self)
 	val files : (Path.UniqueKey.t,cached_file) Hashtbl.t = Hashtbl.create 0
 	val modules : (path,module_def) Hashtbl.t = Hashtbl.create 0
+	val binary_cache : (path,HxbData.module_cache) Hashtbl.t = Hashtbl.create 0
 	val removed_files = Hashtbl.create 0
 	val mutable json = JNull
 	val mutable initialized = false
@@ -57,17 +66,41 @@ class context_cache (index : int) = object(self)
 	method find_module_opt path =
 		Hashtbl.find_opt modules path
 
-	method cache_module path value =
-		Hashtbl.replace modules path value
+	method find_module_extra path =
+		try (Hashtbl.find modules path).m_extra with Not_found -> (Hashtbl.find binary_cache path).mc_extra
+
+	method cache_module warn anon_identification hxb_writer_stats path m =
+		match m.m_extra.m_kind with
+		| MImport ->
+			Hashtbl.add modules m.m_path m
+		| _ ->
+			let writer = HxbWriter.create warn anon_identification hxb_writer_stats in
+			HxbWriter.write_module writer m;
+			let chunks = HxbWriter.get_chunks writer in
+			Hashtbl.replace binary_cache path {
+				mc_path = path;
+				mc_id = m.m_id;
+				mc_chunks = chunks;
+				mc_extra = { m.m_extra with m_cache_state = MSGood }
+			}
+
+	method clear_cache =
+		Hashtbl.clear modules
 
 	(* initialization *)
 
 	method is_initialized = initialized
 	method set_initialized value = initialized <- value
 
+	method get_sign = sign
 	method get_index = index
 	method get_files = files
 	method get_modules = modules
+
+	method get_hxb = binary_cache
+	method get_hxb_module path = Hashtbl.find binary_cache path
+
+	(* TODO handle hxb cache there too *)
 	method get_removed_files = removed_files
 
 	method get_json = json
@@ -75,7 +108,7 @@ class context_cache (index : int) = object(self)
 
 (* Pointers for memory inspection. *)
 	method get_pointers : unit array =
-		[|Obj.magic files;Obj.magic modules|]
+		[|Obj.magic files;Obj.magic modules;Obj.magic binary_cache|]
 end
 
 let create_directory path mtime = {
@@ -115,18 +148,18 @@ class cache = object(self)
 		try
 			Hashtbl.find contexts sign
 		with Not_found ->
-			let cache = new context_cache (Hashtbl.length contexts) in
+			let cache = new context_cache (Hashtbl.length contexts) sign in
 			context_list <- cache :: context_list;
 			Hashtbl.add contexts sign cache;
 			cache
 
-	method add_info sign desc platform class_path defines =
+	method add_info sign desc platform (class_paths : ClassPaths.class_paths) defines =
 		let cc = self#get_context sign in
 		let jo = JObject [
 			"index",JInt cc#get_index;
 			"desc",JString desc;
 			"platform",JString (platform_name platform);
-			"classPaths",JArray (List.map (fun s -> JString s) class_path);
+			"classPaths",JArray (List.map (fun s -> JString s) class_paths#as_string_list);
 			"signature",JString (Digest.to_hex sign);
 			"defines",JArray (PMap.foldi (fun k v acc -> JObject [
 				"key",JString k;
@@ -174,7 +207,14 @@ class cache = object(self)
 		Hashtbl.iter (fun _ cc ->
 			Hashtbl.iter (fun _ m ->
 				if Path.UniqueKey.lazy_key m.m_extra.m_file = file_key then m.m_extra.m_cache_state <- MSBad (Tainted reason)
-			) cc#get_modules
+			) cc#get_modules;
+			let open HxbData in
+			Hashtbl.iter (fun _ mc ->
+				if Path.UniqueKey.lazy_key mc.mc_extra.m_file = file_key then
+					mc.mc_extra.m_cache_state <- match reason, mc.mc_extra.m_cache_state with
+					| CheckDisplayFile, (MSBad _ as state) -> state
+					| _ -> MSBad (Tainted reason)
+			) cc#get_hxb
 		) contexts
 
 	(* haxelibs *)
@@ -267,11 +307,3 @@ type context_options =
 	| NormalContext
 	| MacroContext
 	| NormalAndMacroContext
-
-let get_module_name_of_cfile file cfile = match cfile.c_module_name with
-	| None ->
-		let name = Path.module_name_of_file file in
-		cfile.c_module_name <- Some name;
-		name
-	| Some name ->
-		name

+ 5 - 0
src/compiler/compilationContext.ml

@@ -10,6 +10,7 @@ type server_mode =
 type native_lib_kind =
 	| JavaLib
 	| SwfLib
+	| HxbLib
 
 type native_lib_arg = {
 	lib_file : string;
@@ -20,6 +21,7 @@ type native_lib_arg = {
 type arg_context = {
 	mutable classes : Globals.path list;
 	mutable xml_out : string option;
+	mutable hxb_out : string option;
 	mutable json_out : string option;
 	mutable cmds : string list;
 	mutable config_macros : string list;
@@ -30,6 +32,7 @@ type arg_context = {
 	mutable interp : bool;
 	mutable jvm_flag : bool;
 	mutable swf_version : bool;
+	mutable hxb_libs : native_lib_arg list;
 	mutable native_libs : native_lib_arg list;
 	mutable raise_usage : unit -> unit;
 	mutable display_arg : string option;
@@ -50,11 +53,13 @@ and compilation_context = {
 	mutable has_next : bool;
 	mutable has_error : bool;
 	comm : communication;
+	mutable runtime_args : string list;
 }
 
 type compilation_callbacks = {
 	before_anything : compilation_context -> unit;
 	after_target_init : compilation_context -> unit;
+	after_save : compilation_context -> unit;
 	after_compilation : compilation_context -> unit;
 }
 

+ 50 - 28
src/compiler/compiler.ml

@@ -78,8 +78,15 @@ let run_command ctx cmd =
 module Setup = struct
 	let initialize_target ctx com actx =
 		init_platform com;
+		com.class_paths#lock_context (platform_name com.platform) false;
 		let add_std dir =
-			com.class_path <- List.filter (fun s -> not (List.mem s com.std_path)) com.class_path @ List.map (fun p -> p ^ dir ^ "/_std/") com.std_path @ com.std_path
+			com.class_paths#modify_inplace (fun cp -> match cp#scope with
+				| Std ->
+					let cp' = new ClassPath.directory_class_path (cp#path ^ dir ^ "/_std/") StdTarget in
+					cp :: [cp']
+				| _ ->
+					[cp]
+			);
 		in
 		match com.platform with
 			| Cross ->
@@ -156,9 +163,14 @@ module Setup = struct
 				add_std "eval";
 				"eval"
 
-	let create_typer_context ctx macros native_libs =
+	let init_native_libs com native_libs =
+		(* Native lib pass 1: Register *)
+		let fl = List.map (fun lib -> NativeLibraryHandler.add_native_lib com lib) (List.rev native_libs) in
+		(* Native lib pass 2: Initialize *)
+		List.iter (fun f -> f()) fl
+
+	let create_typer_context ctx macros =
 		let com = ctx.com in
-		Common.log com ("Classpath: " ^ (String.concat ";" com.class_path));
 		let buffer = Buffer.create 64 in
 		Buffer.add_string buffer "Defines: ";
 		PMap.iter (fun k v -> match v with
@@ -168,15 +180,13 @@ module Setup = struct
 		Buffer.truncate buffer (Buffer.length buffer - 1);
 		Common.log com (Buffer.contents buffer);
 		com.callbacks#run com.error_ext com.callbacks#get_before_typer_create;
-		(* Native lib pass 1: Register *)
-		let fl = List.map (fun lib -> NativeLibraryHandler.add_native_lib com lib) (List.rev native_libs) in
-		(* Native lib pass 2: Initialize *)
-		List.iter (fun f -> f()) fl;
 		TyperEntry.create com macros
 
 	let executable_path() =
 		Extc.executable_path()
 
+	open ClassPath
+
 	let get_std_class_paths () =
 		try
 			let p = Sys.getenv "HAXE_STD_PATH" in
@@ -190,7 +200,7 @@ module Setup = struct
 					l
 			in
 			let parts = Str.split_delim (Str.regexp "[;:]") p in
-			"" :: List.map Path.add_trailing_slash (loop parts)
+			List.map (fun s -> s,Std) (loop parts)
 		with Not_found ->
 			let base_path = Path.get_real_path (try executable_path() with _ -> "./") in
 			if Sys.os_type = "Unix" then
@@ -198,17 +208,24 @@ module Setup = struct
 				let lib_path = Filename.concat prefix_path "lib" in
 				let share_path = Filename.concat prefix_path "share" in
 				[
-					"";
-					Path.add_trailing_slash (Filename.concat share_path "haxe/std");
-					Path.add_trailing_slash (Filename.concat lib_path "haxe/std");
-					Path.add_trailing_slash (Filename.concat base_path "std");
+					(Filename.concat share_path "haxe/std"),Std;
+					(Filename.concat lib_path "haxe/std"),Std;
+					(Filename.concat base_path "std"),Std;
 				]
 			else
 				[
-					"";
-					Path.add_trailing_slash (Filename.concat base_path "std");
+					(Filename.concat base_path "std"),Std;
 				]
 
+	let init_std_class_paths com =
+		List.iter (fun (s,scope) ->
+			try if Sys.is_directory s then
+				let cp = new ClassPath.directory_class_path (Path.add_trailing_slash s) scope in
+				com.class_paths#add cp
+			with Sys_error _ -> ()
+		) (List.rev (get_std_class_paths ()));
+		com.class_paths#add com.empty_class_path
+
 	let setup_common_context ctx =
 		let com = ctx.com in
 		ctx.com.print <- ctx.comm.write_out;
@@ -248,8 +265,7 @@ module Setup = struct
 		) (filter_messages false (fun _ -> true))));
 		com.filter_messages <- (fun predicate -> (ctx.messages <- (List.rev (filter_messages true predicate))));
 		com.run_command <- run_command ctx;
-		com.class_path <- get_std_class_paths ();
-		com.std_path <- List.filter (fun p -> ExtString.String.ends_with p "std/" || ExtString.String.ends_with p "std\\") com.class_path
+		init_std_class_paths com
 
 end
 
@@ -266,23 +282,23 @@ let check_defines com =
 	end
 
 (** Creates the typer context and types [classes] into it. *)
-let do_type ctx mctx actx display_file_dot_path macro_cache_enabled =
+let do_type ctx mctx actx display_file_dot_path =
 	let com = ctx.com in
 	let t = Timer.timer ["typing"] in
 	let cs = com.cs in
 	CommonCache.maybe_add_context_sign cs com "before_init_macros";
 	enter_stage com CInitMacrosStart;
 	ServerMessage.compiler_stage com;
-
+	Setup.init_native_libs com actx.hxb_libs;
 	let mctx = List.fold_left (fun mctx path ->
 		Some (MacroContext.call_init_macro ctx.com mctx path)
 	) mctx (List.rev actx.config_macros) in
 	enter_stage com CInitMacrosDone;
 	ServerMessage.compiler_stage com;
-	MacroContext.macro_enable_cache := macro_cache_enabled;
 
 	let macros = match mctx with None -> None | Some mctx -> mctx.g.macros in
-	let tctx = Setup.create_typer_context ctx macros actx.native_libs in
+	Setup.init_native_libs com actx.native_libs;
+	let tctx = Setup.create_typer_context ctx macros in
 	let display_file_dot_path = DisplayProcessing.maybe_load_display_file_before_typing tctx display_file_dot_path in
 	check_defines ctx.com;
 	CommonCache.lock_signature com "after_init_macros";
@@ -314,7 +330,7 @@ let finalize_typing ctx tctx =
 	enter_stage com CFilteringStart;
 	ServerMessage.compiler_stage com;
 	let main, types, modules = run_or_diagnose ctx (fun () -> Finalization.generate tctx) in
-	com.main <- main;
+	com.main.main_expr <- main;
 	com.types <- types;
 	com.modules <- modules;
 	t()
@@ -322,7 +338,7 @@ let finalize_typing ctx tctx =
 let filter ctx tctx before_destruction =
 	let t = Timer.timer ["filters"] in
 	DeprecationCheck.run ctx.com;
-	run_or_diagnose ctx (fun () -> Filters.run tctx ctx.com.main before_destruction);
+	run_or_diagnose ctx (fun () -> Filters.run tctx ctx.com.main.main_expr before_destruction);
 	t()
 
 let compile ctx actx callbacks =
@@ -330,8 +346,6 @@ let compile ctx actx callbacks =
 	(* Set up display configuration *)
 	DisplayProcessing.process_display_configuration ctx;
 	let display_file_dot_path = DisplayProcessing.process_display_file com actx in
-	let macro_cache_enabled = !MacroContext.macro_enable_cache in
-	MacroContext.macro_enable_cache := true;
 	let mctx = match com.platform with
 		| CustomTarget name ->
 			begin try
@@ -356,9 +370,14 @@ let compile ctx actx callbacks =
 		if actx.cmds = [] && not actx.did_something then actx.raise_usage();
 	end else begin
 		(* Actual compilation starts here *)
-		let (tctx,display_file_dot_path) = do_type ctx mctx actx display_file_dot_path macro_cache_enabled in
+		let (tctx,display_file_dot_path) = do_type ctx mctx actx display_file_dot_path in
 		DisplayProcessing.handle_display_after_typing ctx tctx display_file_dot_path;
 		finalize_typing ctx tctx;
+		let is_compilation = is_compilation com in
+		com.callbacks#add_after_save (fun () ->
+			callbacks.after_save ctx;
+			if is_compilation then Generate.check_hxb_output ctx actx;
+		);
 		if is_diagnostics com then
 			filter ctx tctx (fun () -> DisplayProcessing.handle_display_after_finalization ctx tctx display_file_dot_path)
 		else begin
@@ -366,9 +385,10 @@ let compile ctx actx callbacks =
 			filter ctx tctx (fun () -> ());
 		end;
 		if ctx.has_error then raise Abort;
-		Generate.check_auxiliary_output com actx;
+		if is_compilation then Generate.check_auxiliary_output com actx;
 		enter_stage com CGenerationStart;
 		ServerMessage.compiler_stage com;
+		Generate.maybe_generate_dump ctx tctx;
 		if not actx.no_output then Generate.generate ctx tctx ext actx;
 		enter_stage com CGenerationDone;
 		ServerMessage.compiler_stage com;
@@ -426,6 +446,7 @@ with
 
 let finalize ctx =
 	ctx.comm.flush ctx;
+	List.iter (fun lib -> lib#close) ctx.com.hxb_libs;
 	(* In server mode any open libs are closed by the lib_build_task. In offline mode
 		we should do it here to be safe. *)
 	if not ctx.comm.is_server then begin
@@ -481,6 +502,7 @@ let create_context comm cs compilation_step params = {
 	has_next = false;
 	has_error = false;
 	comm = comm;
+	runtime_args = [];
 }
 
 module HighLevel = struct
@@ -524,7 +546,7 @@ module HighLevel = struct
 				if l = "" then
 					acc
 				else if l.[0] <> '-' then
-					"-cp" :: l :: acc
+					"-libcp" :: l :: acc
 				else match (try ExtString.String.split l " " with _ -> l, "") with
 				| ("-L",dir) ->
 					"--neko-lib-path" :: (String.sub l 3 (String.length l - 3)) :: acc
@@ -586,7 +608,7 @@ module HighLevel = struct
 			| "--run" :: cl :: args ->
 				let acc = cl :: "-x" :: acc in
 				let ctx = create_context (List.rev acc) in
-				ctx.com.sys_args <- args;
+				ctx.runtime_args <- args;
 				[],Some ctx
 			| ("-L" | "--library" | "-lib") :: name :: args ->
 				let libs,args = find_subsequent_libs [name] args in

+ 4 - 1
src/compiler/displayOutput.ml

@@ -326,7 +326,10 @@ let handle_display_exception_json ctx dex api =
 		let ctx = DisplayJson.create_json_context api.jsonrpc (match dex with DisplayFields _ -> true | _ -> false) in
 		api.send_result (DisplayException.to_json ctx dex)
 	| DisplayNoResult ->
-		api.send_result JNull
+		(match ctx.com.display.dms_kind with
+			| DMDefault -> api.send_error [jstring "No completion point"]
+			| _ -> api.send_result JNull
+		)
 	| _ ->
 		handle_display_exception_old ctx dex
 

+ 7 - 6
src/compiler/displayProcessing.ml

@@ -121,6 +121,7 @@ let process_display_file com actx =
 		let rec loop = function
 			| [] -> None
 			| cp :: l ->
+				let cp = cp#path in
 				let cp = (if cp = "" then "./" else cp) in
 				let c = Path.add_trailing_slash (Path.get_real_path cp) in
 				let clen = String.length c in
@@ -135,14 +136,14 @@ let process_display_file com actx =
 				end else
 					loop l
 		in
-		loop com.class_path
+		loop com.class_paths#as_list
 	in
 	match com.display.dms_display_file_policy with
 		| DFPNo ->
 			DPKNone
 		| DFPOnly when (DisplayPosition.display_position#get).pfile = file_input_marker ->
 			actx.classes <- [];
-			com.main_class <- None;
+			com.main.main_class <- None;
 			begin match com.file_contents with
 			| [_, Some input] ->
 				com.file_contents <- [];
@@ -153,7 +154,7 @@ let process_display_file com actx =
 		| dfp ->
 			if dfp = DFPOnly then begin
 				actx.classes <- [];
-				com.main_class <- None;
+				com.main.main_class <- None;
 			end;
 			let real = Path.get_real_path (DisplayPosition.display_position#get).pfile in
 			let path = match get_module_path_from_file_path com real with
@@ -223,7 +224,7 @@ let load_display_module_in_macro tctx display_file_dot_path clear = match displa
 
 let load_display_file_standalone (ctx : Typecore.typer) file =
 	let com = ctx.com in
-	let pack,decls = TypeloadParse.parse_module_file com file null_pos in
+	let pack,decls = TypeloadParse.parse_module_file com (ClassPaths.create_resolved_file file ctx.com.empty_class_path) null_pos in
 	let path = Path.FilePath.parse file in
 	let name = match path.file_name with
 		| None -> "?DISPLAY"
@@ -236,7 +237,7 @@ let load_display_file_standalone (ctx : Typecore.typer) file =
 			let parts = ExtString.String.nsplit dir (if path.backslash then "\\" else "/") in
 			let parts = List.rev (ExtList.List.drop (List.length pack) (List.rev parts)) in
 			let dir = ExtString.String.join (if path.backslash then "\\" else "/") parts in
-			com.class_path <- dir :: com.class_path
+			com.class_paths#add (new ClassPath.directory_class_path dir User)
 	end;
 	ignore(TypeloadModule.type_module ctx (pack,name) file ~dont_check_path:true decls null_pos)
 
@@ -318,7 +319,7 @@ let process_global_display_mode com tctx =
 		let symbols =
 			let l = cs#get_context_files ((Define.get_signature com.defines) :: (match com.get_macros() with None -> [] | Some com -> [Define.get_signature com.defines])) in
 			List.fold_left (fun acc (file_key,cfile) ->
-				let file = cfile.c_file_path in
+				let file = cfile.c_file_path.file in
 				if (filter <> None || DisplayPosition.display_position#is_in_file (com.file_keys#get file)) then
 					(file,DocumentSymbols.collect_module_symbols (Some (file,get_module_name_of_cfile file cfile)) (filter = None) (cfile.c_package,cfile.c_decls)) :: acc
 				else

+ 82 - 9
src/compiler/generate.ml

@@ -1,5 +1,7 @@
 open Globals
 open CompilationContext
+open TType
+open Tanon_identification
 
 let check_auxiliary_output com actx =
 	begin match actx.xml_out with
@@ -19,6 +21,67 @@ let check_auxiliary_output com actx =
 			Genjson.generate com.types file
 	end
 
+let export_hxb com cc platform zip m =
+	let open HxbData in
+	match m.m_extra.m_kind with
+		| MCode | MMacro | MFake | MExtern -> begin
+			(* Printf.eprintf "Export module %s\n" (s_type_path m.m_path); *)
+			let l = platform :: (fst m.m_path @ [snd m.m_path]) in
+			let path = (String.concat "/" l) ^ ".hxb" in
+
+			try
+				let hxb_cache = cc#get_hxb_module m.m_path in
+				let out = IO.output_string () in
+				write_header out;
+				List.iter (fun (kind,data) ->
+					write_chunk_prefix kind (Bytes.length data) out;
+					IO.nwrite out data
+				) hxb_cache.mc_chunks;
+				let data = IO.close_out out in
+				zip#add_entry data path;
+			with Not_found ->
+				let anon_identification = new tanon_identification in
+				let warn w s p = com.Common.warning w com.warning_options s p in
+				let writer = HxbWriter.create warn anon_identification com.hxb_writer_stats in
+				HxbWriter.write_module writer m;
+				let out = IO.output_string () in
+				HxbWriter.export writer out;
+				zip#add_entry (IO.close_out out) path;
+		end
+	| _ ->
+		()
+
+let check_hxb_output ctx actx =
+	let com = ctx.com in
+	let try_write path =
+		let t = Timer.timer ["generate";"hxb"] in
+		Path.mkdir_from_path path;
+		let zip = new Zip_output.zip_output path 6 in
+		let export com =
+			let cc = CommonCache.get_cache com in
+			let target = Common.platform_name_macro com in
+			List.iter (fun m ->
+				let t = Timer.timer ["generate";"hxb";s_type_path m.m_path] in
+				Std.finally t (export_hxb com cc target zip) m
+			) com.modules;
+		in
+		Std.finally (fun () ->
+			zip#close;
+			t()
+		) (fun () ->
+			export com;
+			Option.may export (com.get_macros());
+		) ()
+	in
+	begin match actx.hxb_out with
+		| None ->
+			()
+		| Some path ->
+			try
+				try_write path
+			with Sys_error s ->
+				error ctx (Printf.sprintf "Could not write to %s: %s" path s) null_pos
+	end
 
 let parse_swf_header ctx h = match ExtString.String.nsplit h ":" with
 		| [width; height; fps] ->
@@ -32,12 +95,8 @@ let parse_swf_header ctx h = match ExtString.String.nsplit h ":" with
 
 let delete_file f = try Sys.remove f with _ -> ()
 
-let generate ctx tctx ext actx =
+let maybe_generate_dump ctx tctx =
 	let com = tctx.Typecore.com in
-	(* check file extension. In case of wrong commandline, we don't want
-		to accidentaly delete a source file. *)
-	if Path.file_extension com.file = ext then delete_file com.file;
-	if com.platform = Flash || com.platform = Cpp || com.platform = Hl then List.iter (Codegen.fix_overrides com) com.types;
 	if Common.defined com Define.Dump then begin
 		Codegen.Dump.dump_types com;
 		Option.may Codegen.Dump.dump_types (com.get_macros())
@@ -47,16 +106,30 @@ let generate ctx tctx ext actx =
 		if not com.is_macro_context then match tctx.Typecore.g.Typecore.macros with
 			| None -> ()
 			| Some(_,ctx) -> Codegen.Dump.dump_dependencies ~target_override:(Some "macro") ctx.Typecore.com
-	end;
+	end
+
+let generate ctx tctx ext actx =
+	let com = tctx.Typecore.com in
+	(* check file extension. In case of wrong commandline, we don't want
+		to accidentaly delete a source file. *)
+	if Path.file_extension com.file = ext then delete_file com.file;
+	if com.platform = Flash || com.platform = Cpp || com.platform = Hl then List.iter (Codegen.fix_overrides com) com.types;
 	begin match com.platform with
 		| Neko | Hl | Eval when actx.interp -> ()
 		| Cpp when Common.defined com Define.Cppia -> ()
 		| Cpp | Php -> Path.mkdir_from_path (com.file ^ "/.")
 		| _ -> Path.mkdir_from_path com.file
 	end;
-	if actx.interp then
-		Std.finally (Timer.timer ["interp"]) MacroContext.interpret tctx
-	else begin
+	if actx.interp then begin
+		let timer = Timer.timer ["interp"] in
+		let old = tctx.com.args in
+		tctx.com.args <- ctx.runtime_args;
+		let restore () =
+			tctx.com.args <- old;
+			timer ()
+		in
+		Std.finally restore MacroContext.interpret tctx
+	end else begin
 		let generate,name = match com.platform with
 		| Flash ->
 			let header = try

+ 127 - 0
src/compiler/hxb/hxbData.ml

@@ -0,0 +1,127 @@
+open Globals
+open Type
+
+exception HxbFailure of string
+
+(*
+	MD = module
+	MT = module type
+	CL = class
+	EN = enum
+	AB = abstract
+	TD = typedef
+	AN = anon
+	CF = class field
+	EF = enum field
+	AF = anon field
+	EX = expression
+	EO = end of (Types | Fields | Module)
+	..F = forward definition
+	..R = reference
+	..D = definition
+*)
+
+type chunk_kind =
+	| STR (* string pool *)
+	| DOC (* doc pool *)
+	| MDF (* module foward *)
+	| MTF (* module types forward *)
+	(* Module type references *)
+	| MDR (* module references *)
+	| CLR (* class references *)
+	| ENR (* enum references *)
+	| ABR (* abstract references *)
+	| TDR (* typedef references *)
+	(* Field references *)
+	| AFR (* anon field references *)
+	(* Own module type definitions *)
+	| CLD (* class definition *)
+	| END (* enum definition *)
+	| ABD (* abstract definition *)
+	| TDD (* typedef definition *)
+	| EOT (* end of module types *)
+	(* Field references *)
+	| EFR (* enum field references *)
+	| CFR (* class field references *)
+	(* Own field definitions *)
+	| CFD (* class fields *)
+	| EFD (* enum fields *)
+	| AFD (* abstract fields *)
+	| EOF (* end of fields *)
+	| EXD (* class field expressions *)
+	| EOM (* end of module *)
+
+type cached_chunk = chunk_kind * bytes
+type cached_chunks = cached_chunk list
+
+type module_cache = {
+	mc_path : path;
+	mc_id : int;
+	mc_chunks : cached_chunks;
+	mc_extra : module_def_extra;
+}
+
+let string_of_chunk_kind = function
+	| STR -> "STR"
+	| DOC -> "DOC"
+	| MDF -> "MDF"
+	| MTF -> "MTF"
+	| MDR -> "MDR"
+	| CLR -> "CLR"
+	| ENR -> "ENR"
+	| ABR -> "ABR"
+	| TDR -> "TDR"
+	| AFR -> "AFR"
+	| EFR -> "EFR"
+	| CFR -> "CFR"
+	| CLD -> "CLD"
+	| END -> "END"
+	| ABD -> "ABD"
+	| TDD -> "TDD"
+	| EOT -> "EOT"
+	| CFD -> "CFD"
+	| EFD -> "EFD"
+	| AFD -> "AFD"
+	| EOF -> "EOF"
+	| EXD -> "EXD"
+	| EOM -> "EOM"
+
+let chunk_kind_of_string = function
+	| "STR" -> STR
+	| "DOC" -> DOC
+	| "MDF" -> MDF
+	| "MTF" -> MTF
+	| "MDR" -> MDR
+	| "CLR" -> CLR
+	| "ENR" -> ENR
+	| "ABR" -> ABR
+	| "TDR" -> TDR
+	| "AFR" -> AFR
+	| "EFR" -> EFR
+	| "CFR" -> CFR
+	| "CLD" -> CLD
+	| "END" -> END
+	| "ABD" -> ABD
+	| "TDD" -> TDD
+	| "EOT" -> EOT
+	| "CFD" -> CFD
+	| "EFD" -> EFD
+	| "AFD" -> AFD
+	| "EOF" -> EOF
+	| "EXD" -> EXD
+	| "EOM" -> EOM
+	| name -> raise (HxbFailure ("Invalid chunk name: " ^ name))
+
+let error (s : string) =
+	Printf.eprintf "[error] %s\n" s;
+	raise (HxbFailure s)
+
+let hxb_version = 1
+
+let write_header ch =
+	IO.nwrite_string ch "hxb";
+	IO.write_byte ch hxb_version
+
+let write_chunk_prefix kind length ch =
+	IO.nwrite ch (Bytes.unsafe_of_string (string_of_chunk_kind kind));
+	IO.write_real_i32 ch (Int32.of_int length)

+ 63 - 0
src/compiler/hxb/hxbLib.ml

@@ -0,0 +1,63 @@
+open Globals
+open Common
+open ExtString
+
+class hxb_library file_path = object(self)
+	inherit abstract_hxb_lib
+	val zip = lazy (Zip.open_in file_path)
+
+	val mutable cached_files = []
+	val modules = Hashtbl.create 0
+	val mutable closed = false
+	val mutable loaded = false
+
+	method load =
+		if not loaded then begin
+			loaded <- true;
+			let close = Timer.timer ["hxblib";"read"] in
+			List.iter (function
+				| ({ Zip.is_directory = false; Zip.filename = filename } as entry) when String.ends_with filename ".hxb" ->
+					let pack = String.nsplit filename "/" in
+					begin match List.rev pack with
+						| [] -> ()
+						| name :: pack ->
+							let name = String.sub name 0 (String.length name - 4) in
+							let pack = List.rev pack in
+							Hashtbl.add modules (pack,name) (filename,entry);
+						end
+				| _ -> ()
+			) (Zip.entries (Lazy.force zip));
+			close();
+		end
+
+	method get_bytes (target : string) (path : path) =
+		try
+			let path = (target :: fst path,snd path) in
+			let (filename,entry) = Hashtbl.find modules path in
+			let close = Timer.timer ["hxblib";"get bytes"] in
+			let zip = Lazy.force zip in
+			let data = Zip.read_entry zip entry in
+			close();
+			Some (Bytes.unsafe_of_string data)
+		with Not_found ->
+			None
+
+	method close =
+		if not closed then begin
+			closed <- true;
+			Zip.close_in (Lazy.force zip)
+		end
+
+	method get_file_path = file_path
+end
+
+
+let create_hxb_lib com file_path =
+	let file = if Sys.file_exists file_path then
+		file_path
+	else try
+		Common.find_file com file_path
+	with Not_found ->
+		failwith ("hxb lib " ^ file_path ^ " not found")
+	in
+	new hxb_library file

+ 2002 - 0
src/compiler/hxb/hxbReader.ml

@@ -0,0 +1,2002 @@
+open Globals
+open Ast
+open Type
+open HxbData
+open HxbReaderApi
+
+type field_reader_context = {
+	t_pool : Type.t Array.t;
+	pos : pos ref;
+	vars : tvar Array.t;
+	mutable tthis : Type.t option;
+}
+
+let create_field_reader_context p ts vars tthis = {
+	t_pool = ts;
+	pos = ref p;
+	vars = vars;
+	tthis = tthis;
+}
+
+type hxb_reader_stats = {
+	modules_fully_restored : int ref;
+	modules_partially_restored : int ref;
+}
+
+let create_hxb_reader_stats () = {
+	modules_fully_restored = ref 0;
+	modules_partially_restored = ref 0;
+}
+
+module ClassFieldInfo = struct
+	type t = {
+		type_parameters : typed_type_param array;
+	}
+
+	let create params = {
+		type_parameters = params;
+	}
+end
+
+module ClassFieldInfos = struct
+	type t = {
+		infos : ClassFieldInfo.t DynArray.t;
+	}
+
+	let meta = Meta.HxbId
+
+	let create () = {
+		infos = DynArray.create ()
+	}
+
+	let get infos cf =
+		let _,_,p = Meta.get meta cf.cf_meta in
+		DynArray.get infos.infos p.pmin
+
+	let unset infos cf =
+		cf.cf_meta <- Meta.remove meta cf.cf_meta
+
+	let set infos info cf =
+		let index = DynArray.length infos.infos in
+		DynArray.add infos.infos info;
+		cf.cf_meta <- (meta,[],{null_pos with pmin = index}) :: cf.cf_meta
+end
+
+module BytesWithPosition = struct
+	type t = {
+		bytes : bytes;
+		mutable pos : int;
+	}
+
+	let create bytes = {
+		bytes;
+		pos = 0;
+	}
+
+	let read_byte b =
+		let i = Bytes.unsafe_get b.bytes b.pos in
+		b.pos <- b.pos + 1;
+		int_of_char i
+
+	let read_bytes b length =
+		let out = Bytes.create length in
+		Bytes.blit b.bytes b.pos out 0 length;
+		b.pos <- b.pos + length;
+		out
+
+	let read_i16 i =
+		let ch2 = read_byte i in
+		let ch1 = read_byte i in
+		let n = ch1 lor (ch2 lsl 8) in
+		if ch2 land 128 <> 0 then
+			n - 65536
+		else
+			n
+
+	let read_real_i32 ch =
+		let ch1 = read_byte ch in
+		let ch2 = read_byte ch in
+		let ch3 = read_byte ch in
+		let base = Int32.of_int (ch1 lor (ch2 lsl 8) lor (ch3 lsl 16)) in
+		let big = Int32.shift_left (Int32.of_int (read_byte ch)) 24 in
+		Int32.logor base big
+
+		let read_i64 ch =
+			let big = Int64.of_int32 (read_real_i32 ch) in
+			let ch4 = read_byte ch in
+			let ch3 = read_byte ch in
+			let ch2 = read_byte ch in
+			let ch1 = read_byte ch in
+			let base = Int64.of_int (ch1 lor (ch2 lsl 8) lor (ch3 lsl 16)) in
+			let small = Int64.logor base (Int64.shift_left (Int64.of_int ch4) 24) in
+			Int64.logor (Int64.shift_left big 32) small
+
+	let read_double ch =
+		Int64.float_of_bits (read_i64 ch)
+end
+
+open BytesWithPosition
+
+let rec read_uleb128 ch =
+	let b = read_byte ch in
+	if b >= 0x80 then
+		(b land 0x7F) lor ((read_uleb128 ch) lsl 7)
+	else
+		b
+
+let read_leb128 ch =
+	let rec read acc shift =
+		let b = read_byte ch in
+		let acc = ((b land 0x7F) lsl shift) lor acc in
+		if b >= 0x80 then
+			read acc (shift + 7)
+		else
+			(b, acc, shift + 7)
+	in
+	let last, acc, shift = read 0 0 in
+	let res = (if (last land 0x40) <> 0 then
+		acc lor ((lnot 0) lsl shift)
+	else
+		acc) in
+	res
+
+let dump_stats name stats =
+	print_endline (Printf.sprintf "hxb_reader stats for %s" name);
+	print_endline (Printf.sprintf "  modules partially restored: %i" (!(stats.modules_fully_restored) - !(stats.modules_partially_restored)));
+	print_endline (Printf.sprintf "  modules fully restored: %i" !(stats.modules_fully_restored));
+
+class hxb_reader
+	(mpath : path)
+	(stats : hxb_reader_stats)
+= object(self)
+	val mutable api = Obj.magic ""
+	val mutable current_module = null_module
+
+	val mutable ch = BytesWithPosition.create (Bytes.create 0)
+	val mutable string_pool = Array.make 0 ""
+	val mutable doc_pool = Array.make 0 ""
+
+	val mutable classes = Array.make 0 null_class
+	val mutable abstracts = Array.make 0 null_abstract
+	val mutable enums = Array.make 0 null_enum
+	val mutable typedefs = Array.make 0 null_typedef
+	val mutable anons = Array.make 0 null_tanon
+	val mutable anon_fields = Array.make 0 null_field
+	val mutable tmonos = Array.make 0 (mk_mono())
+	val mutable class_fields = Array.make 0 null_field
+	val mutable enum_fields = Array.make 0 null_enum_field
+
+	val mutable type_type_parameters = Array.make 0 (mk_type_param null_class TPHType None None)
+	val mutable field_type_parameters = Array.make 0 (mk_type_param null_class TPHMethod None None)
+	val mutable local_type_parameters = Array.make 0 (mk_type_param null_class TPHLocal None None)
+
+	val mutable field_type_parameter_offset = 0
+	val empty_anon = mk_anon (ref Closed)
+
+	method resolve_type pack mname tname =
+		try
+			api#resolve_type pack mname tname
+		with Not_found ->
+			dump_backtrace();
+			error (Printf.sprintf "[HXB] [%s] Cannot resolve type %s" (s_type_path current_module.m_path) (s_type_path ((pack @ [mname]),tname)))
+
+	(* Primitives *)
+
+	method read_i32 =
+		read_real_i32 ch
+
+	method read_i16 =
+		read_i16 ch
+
+	method read_f64 =
+		read_double ch
+
+	method read_bool =
+		read_byte ch <> 0
+
+	method read_from_string_pool pool =
+		pool.(read_uleb128 ch)
+
+	method read_string =
+		self#read_from_string_pool string_pool
+
+	method read_raw_string =
+		let l = read_uleb128 ch in
+		Bytes.unsafe_to_string (read_bytes ch l)
+
+	(* Basic compounds *)
+
+	method read_list : 'a . (unit -> 'a) -> 'a list = fun f ->
+		let l = read_uleb128 ch in
+		List.init l (fun _ -> f ())
+
+	method read_option : 'a . (unit -> 'a) -> 'a option = fun f ->
+		match read_byte ch with
+		| 0 ->
+			None
+		| _ ->
+			Some (f())
+
+	method read_path =
+		let pack = self#read_list (fun () -> self#read_string) in
+		let name = self#read_string in
+		(pack,name)
+
+	method read_full_path =
+		let pack = self#read_list (fun () -> self#read_string) in
+		let mname = self#read_string in
+		let tname = self#read_string in
+		(pack,mname,tname)
+
+	method read_documentation =
+		let doc_own = self#read_option (fun () ->
+			self#read_from_string_pool doc_pool
+		) in
+		let doc_inherited = self#read_list (fun () ->
+			self#read_from_string_pool doc_pool
+		) in
+		{doc_own;doc_inherited}
+
+	method read_pos =
+		let file = self#read_string in
+		let min = read_leb128 ch in
+		let max = read_leb128 ch in
+		let pos = {
+			pfile = file;
+			pmin = min;
+			pmax = max;
+		} in
+		pos
+
+	method read_pos_pair =
+		let file = self#read_string in
+		let min1 = read_leb128 ch in
+		let max1 = read_leb128 ch in
+		let min2 = read_leb128 ch in
+		let max2 = read_leb128 ch in
+		let pos1 = {
+			pfile = file;
+			pmin = min1;
+			pmax = max1;
+		} in
+		let pos2 = {
+			pos1 with
+			pmin = pos1.pmin + min2;
+			pmax = pos1.pmin + max2;
+		} in
+		pos1,pos2
+
+	method read_metadata_entry : metadata_entry =
+		let name = self#read_string in
+		let p = self#read_pos in
+		let el = self#read_list (fun () -> self#read_expr) in
+		(Meta.from_string name,el,p)
+
+	method read_metadata =
+		self#read_list (fun () -> self#read_metadata_entry)
+
+	(* References *)
+
+	method read_class_ref =
+		classes.(read_uleb128 ch)
+
+	method read_abstract_ref =
+		abstracts.(read_uleb128 ch)
+
+	method read_enum_ref =
+		enums.(read_uleb128 ch)
+
+	method read_typedef_ref =
+		typedefs.(read_uleb128 ch)
+
+	method read_field_ref =
+		class_fields.(read_uleb128 ch)
+
+	method read_enum_field_ref =
+		enum_fields.(read_uleb128 ch)
+
+	method read_anon_ref =
+		match read_byte ch with
+		| 0 ->
+			anons.(read_uleb128 ch)
+		| 1 ->
+			let an = anons.(read_uleb128 ch) in
+			self#read_anon an
+		| _ ->
+			assert false
+
+	method read_anon_field_ref =
+		match read_byte ch with
+		| 0 ->
+			anon_fields.(read_uleb128 ch)
+		| 1 ->
+			let cf = anon_fields.(read_uleb128 ch) in
+			self#read_class_field_and_overloads_data cf;
+			cf
+		| _ ->
+			assert false
+
+	(* Expr *)
+
+	method get_binop i = match i with
+		| 0 -> OpAdd
+		| 1 -> OpMult
+		| 2 -> OpDiv
+		| 3 -> OpSub
+		| 4 -> OpAssign
+		| 5 -> OpEq
+		| 6 -> OpNotEq
+		| 7 -> OpGt
+		| 8 -> OpGte
+		| 9 -> OpLt
+		| 10 -> OpLte
+		| 11 -> OpAnd
+		| 12 -> OpOr
+		| 13 -> OpXor
+		| 14 -> OpBoolAnd
+		| 15 -> OpBoolOr
+		| 16 -> OpShl
+		| 17 -> OpShr
+		| 18 -> OpUShr
+		| 19 -> OpMod
+		| 20 -> OpInterval
+		| 21 -> OpArrow
+		| 22 -> OpIn
+		| 23 -> OpNullCoal
+		| _ -> OpAssignOp (self#get_binop (i - 30))
+
+	method get_unop i = match i with
+		| 0 -> Increment,Prefix
+		| 1 -> Decrement,Prefix
+		| 2 -> Not,Prefix
+		| 3 -> Neg,Prefix
+		| 4 -> NegBits,Prefix
+		| 5 -> Spread,Prefix
+		| 6 -> Increment,Postfix
+		| 7 -> Decrement,Postfix
+		| 8 -> Not,Postfix
+		| 9 -> Neg,Postfix
+		| 10 -> NegBits,Postfix
+		| 11 -> Spread,Postfix
+		| _ -> assert false
+
+	method read_placed_name =
+		let s = self#read_string in
+		let p = self#read_pos in
+		(s,p)
+
+	method read_type_path =
+		let pack = self#read_list (fun () -> self#read_string) in
+		let name = self#read_string in
+		let tparams = self#read_list (fun () -> self#read_type_param_or_const) in
+		let tsub = self#read_option (fun () -> self#read_string) in
+		{
+			tpackage = pack;
+			tname = name;
+			tparams = tparams;
+			tsub = tsub;
+		}
+
+	method read_placed_type_path =
+		let tp = self#read_type_path in
+		let pfull,ppath = self#read_pos_pair in
+		{
+			path = tp;
+			pos_full = pfull;
+			pos_path = ppath;
+		}
+
+	method read_type_param =
+		let pn = self#read_placed_name in
+		let ttp = self#read_list (fun () -> self#read_type_param) in
+		let tho = self#read_option (fun () -> self#read_type_hint) in
+		let def = self#read_option (fun () -> self#read_type_hint) in
+		let meta = self#read_metadata in
+		{
+			tp_name = pn;
+			tp_params = ttp;
+			tp_constraints = tho;
+			tp_meta = meta;
+			tp_default = def;
+		}
+
+	method read_type_param_or_const =
+		match read_byte ch with
+		| 0 -> TPType (self#read_type_hint)
+		| 1 -> TPExpr (self#read_expr)
+		| _ -> assert false
+
+	method read_func_arg =
+		let pn = self#read_placed_name in
+		let b = self#read_bool in
+		let meta = self#read_metadata in
+		let tho = self#read_option (fun () -> self#read_type_hint) in
+		let eo = self#read_option (fun () -> self#read_expr) in
+		(pn,b,meta,tho,eo)
+
+	method read_func =
+		let params = self#read_list (fun () -> self#read_type_param) in
+		let args = self#read_list (fun () -> self#read_func_arg) in
+		let tho = self#read_option (fun () -> self#read_type_hint) in
+		let eo = self#read_option (fun () -> self#read_expr) in
+		{
+			f_params = params;
+			f_args = args;
+			f_type = tho;
+			f_expr = eo;
+		}
+
+	method read_complex_type =
+		match read_byte ch with
+		| 0 -> CTPath (self#read_placed_type_path)
+		| 1 ->
+			let thl = self#read_list (fun () -> self#read_type_hint) in
+			let th = self#read_type_hint in
+			CTFunction(thl,th)
+		| 2 -> CTAnonymous (self#read_list (fun () -> self#read_cfield))
+		| 3 -> CTParent (self#read_type_hint)
+		| 4 ->
+			let ptp = self#read_list (fun () -> self#read_placed_type_path) in
+			let cffl = self#read_list (fun () -> self#read_cfield) in
+			CTExtend(ptp,cffl)
+		| 5 -> CTOptional (self#read_type_hint)
+		| 6 ->
+			let pn = self#read_placed_name in
+			let th = self#read_type_hint in
+			CTNamed(pn,th)
+		| 7 -> CTIntersection (self#read_list (fun () -> self#read_type_hint))
+		| _ -> assert false
+
+	method read_type_hint =
+		let ct = self#read_complex_type in
+		let p = self#read_pos in
+		(ct,p)
+
+	method read_access =
+		match read_byte ch with
+		| 0 -> APublic
+		| 1 -> APrivate
+		| 2 -> AStatic
+		| 3 -> AOverride
+		| 4 -> ADynamic
+		| 5 -> AInline
+		| 6 -> AMacro
+		| 7 -> AFinal
+		| 8 -> AExtern
+		| 9 -> AAbstract
+		| 10 -> AOverload
+		| 11 -> AEnum
+		| _ -> assert false
+
+	method read_placed_access =
+		let ac = self#read_access in
+		let p = self#read_pos in
+		(ac,p)
+
+	method read_cfield_kind =
+		match read_byte ch with
+		| 0 ->
+			let tho = self#read_option (fun () -> self#read_type_hint) in
+			let eo = self#read_option (fun () -> self#read_expr) in
+			FVar(tho,eo)
+		| 1 -> FFun (self#read_func)
+		| 2 ->
+			let pn1 = self#read_placed_name in
+			let pn2 = self#read_placed_name in
+			let tho = self#read_option (fun () -> self#read_type_hint) in
+			let eo = self#read_option (fun () -> self#read_expr) in
+			FProp(pn1,pn2,tho,eo)
+		| _ -> assert false
+
+	method read_cfield =
+		let pn = self#read_placed_name in
+		let doc = self#read_option (fun () -> self#read_documentation) in
+		let pos = self#read_pos in
+		let meta = self#read_metadata in
+		let access = self#read_list (fun () -> self#read_placed_access) in
+		let kind = self#read_cfield_kind in
+		{
+			cff_name = pn;
+			cff_doc = doc;
+			cff_pos = pos;
+			cff_meta = meta;
+			cff_access = access;
+			cff_kind = kind;
+		}
+
+	method read_expr =
+		let p = self#read_pos in
+		let e = match read_byte ch with
+		| 0 ->
+			let s = self#read_string in
+			let suffix = self#read_option (fun () -> self#read_string) in
+			EConst (Int (s, suffix))
+		| 1 ->
+			let s = self#read_string in
+			let suffix = self#read_option (fun () -> self#read_string) in
+			EConst (Float (s, suffix))
+		| 2 ->
+			let s = self#read_string in
+			let qs = begin match read_byte ch with
+			| 0 -> SDoubleQuotes
+			| 1 -> SSingleQuotes
+			| _ -> assert false
+			end in
+			EConst (String (s,qs))
+		| 3 ->
+			EConst (Ident (self#read_string))
+		| 4 ->
+			let s1 = self#read_string in
+			let s2 = self#read_string in
+			EConst (Regexp(s1,s2))
+		| 5 ->
+			let e1 = self#read_expr in
+			let e2 = self#read_expr in
+			EArray(e1,e2)
+		| 6 ->
+			let op = self#get_binop (read_byte ch) in
+			let e1 = self#read_expr in
+			let e2 = self#read_expr in
+			EBinop(op,e1,e2)
+		| 7 ->
+			let e = self#read_expr in
+			let s = self#read_string in
+			let kind = begin match read_byte ch with
+			| 0 -> EFNormal
+			| 1 -> EFSafe
+			| _ -> assert false
+			end in
+			EField(e,s,kind)
+		| 8 ->
+			EParenthesis (self#read_expr)
+		| 9 ->
+			let fields = self#read_list (fun () ->
+				let n = self#read_string in
+				let p = self#read_pos in
+				let qs = begin match read_byte ch with
+				| 0 -> NoQuotes
+				| 1 -> DoubleQuotes
+				| _ -> assert false
+				end in
+				let e = self#read_expr in
+				((n,p,qs),e)
+			) in
+			EObjectDecl fields
+		| 10 ->
+			let el = self#read_list (fun () -> self#read_expr) in
+			EArrayDecl el
+		| 11 ->
+			let e = self#read_expr in
+			let el = self#read_list (fun () -> self#read_expr) in
+			ECall(e,el)
+		| 12 ->
+			let ptp = self#read_placed_type_path in
+			let el = self#read_list (fun () -> self#read_expr) in
+			ENew(ptp,el)
+		| 13 ->
+			let (op,flag) = self#get_unop (read_byte ch) in
+			let e = self#read_expr in
+			EUnop(op,flag,e)
+		| 14 ->
+			let vl = self#read_list (fun () ->
+				let name = self#read_placed_name in
+				let final = self#read_bool in
+				let static = self#read_bool in
+				let t = self#read_option (fun () -> self#read_type_hint) in
+				let expr = self#read_option (fun () -> self#read_expr) in
+				let meta = self#read_metadata in
+				{
+					ev_name = name;
+					ev_final = final;
+					ev_static = static;
+					ev_type = t;
+					ev_expr = expr;
+					ev_meta = meta;
+				}
+			) in
+			EVars vl
+		| 15 ->
+			let fk = begin match read_byte ch with
+			| 0 -> FKAnonymous
+			| 1 ->
+				let pn = self#read_placed_name in
+				let b = self#read_bool in
+				FKNamed(pn,b)
+			| 2 -> FKArrow
+			| _ -> assert false end in
+			let f = self#read_func in
+			EFunction(fk,f)
+		| 16 ->
+			EBlock (self#read_list (fun () -> self#read_expr))
+		| 17 ->
+			let e1 = self#read_expr in
+			let e2 = self#read_expr in
+			EFor(e1,e2)
+		| 18 ->
+			let e1 = self#read_expr in
+			let e2 = self#read_expr in
+			EIf(e1,e2,None)
+		| 19 ->
+			let e1 = self#read_expr in
+			let e2 = self#read_expr in
+			let e3 = self#read_expr in
+			EIf(e1,e2,Some e3)
+		| 20 ->
+			let e1 = self#read_expr in
+			let e2 = self#read_expr in
+			EWhile(e1,e2,NormalWhile)
+		| 21 ->
+			let e1 = self#read_expr in
+			let e2 = self#read_expr in
+			EWhile(e1,e2,DoWhile)
+		| 22 ->
+			let e1 = self#read_expr in
+			let cases = self#read_list (fun () ->
+				let el = self#read_list (fun () -> self#read_expr) in
+				let eg = self#read_option (fun () -> self#read_expr) in
+				let eo = self#read_option (fun () -> self#read_expr) in
+				let p = self#read_pos in
+				(el,eg,eo,p)
+			) in
+			let def = self#read_option (fun () ->
+				let eo = self#read_option (fun () -> self#read_expr) in
+				let p = self#read_pos in
+				(eo,p)
+			) in
+			ESwitch(e1,cases,def)
+		| 23 ->
+			let e1 = self#read_expr in
+			let catches = self#read_list (fun () ->
+				let pn = self#read_placed_name in
+				let th = self#read_option (fun () -> self#read_type_hint) in
+				let e = self#read_expr in
+				let p = self#read_pos in
+				(pn,th,e,p)
+			) in
+			ETry(e1,catches)
+		| 24 -> EReturn None
+		| 25 -> EReturn (Some (self#read_expr))
+		| 26 -> EBreak
+		| 27 -> EContinue
+		| 28 -> EUntyped (self#read_expr)
+		| 29 -> EThrow (self#read_expr)
+		| 30 -> ECast ((self#read_expr),None)
+		| 31 ->
+			let e1 = self#read_expr in
+			let th = self#read_type_hint in
+			ECast(e1,Some th)
+		| 32 ->
+			let e1 = self#read_expr in
+			let th = self#read_type_hint in
+			EIs(e1,th)
+		| 33 ->
+			let e1 = self#read_expr in
+			let dk = begin match read_byte ch with
+			| 0 -> DKCall
+			| 1 -> DKDot
+			| 2 -> DKStructure
+			| 3 -> DKMarked
+			| 4 -> DKPattern (self#read_bool)
+			| _ -> assert false end in
+			EDisplay(e1,dk)
+		| 34 ->
+			let e1 = self#read_expr in
+			let e2 = self#read_expr in
+			let e3 = self#read_expr in
+			ETernary(e1,e2,e3)
+		| 35 ->
+			let e1 = self#read_expr in
+			let th = self#read_type_hint in
+			ECheckType(e1,th)
+		| 36 ->
+			let m = self#read_metadata_entry in
+			let e = self#read_expr in
+			EMeta(m,e)
+		| _ -> assert false
+		in
+		(e,p)
+
+	(* Type instances *)
+
+	method resolve_ttp_ref = function
+		| 1 ->
+			let i = read_uleb128 ch in
+			(type_type_parameters.(i))
+		| 2 ->
+			let i = read_uleb128 ch in
+			(field_type_parameters.(i))
+		| 3 ->
+			let k = read_uleb128 ch in
+			local_type_parameters.(k)
+		| _ ->
+			die "" __LOC__
+
+	method read_type_instance =
+		let read_fun_arg () =
+			let name = self#read_string in
+			let opt = self#read_bool in
+			let t = self#read_type_instance in
+			(name,opt,t)
+		in
+		match (read_byte ch) with
+		| 0 ->
+			let i = read_uleb128 ch in
+			tmonos.(i)
+		| 1 ->
+			let i = read_uleb128 ch in
+			(type_type_parameters.(i)).ttp_type
+		| 2 ->
+			let i = read_uleb128 ch in
+			(field_type_parameters.(i)).ttp_type
+		| 3 ->
+			let k = read_uleb128 ch in
+			local_type_parameters.(k).ttp_type
+		| 4 ->
+			t_dynamic
+		| 10 ->
+			let c = self#read_class_ref in
+			c.cl_type
+		| 11 ->
+			let en = self#read_enum_ref in
+			en.e_type
+		| 12 ->
+			let a = self#read_abstract_ref in
+			TType(abstract_module_type a [],[])
+		| 13 ->
+			let e = self#read_expr in
+			let c = {null_class with cl_kind = KExpr e; cl_module = current_module } in
+			TInst(c, [])
+		| 20 ->
+			TFun([],api#basic_types.tvoid)
+		| 21 ->
+			let arg1 = read_fun_arg () in
+			TFun([arg1],api#basic_types.tvoid)
+		| 22 ->
+			let arg1 = read_fun_arg () in
+			let arg2 = read_fun_arg () in
+			TFun([arg1;arg2],api#basic_types.tvoid)
+		| 23 ->
+			let arg1 = read_fun_arg () in
+			let arg2 = read_fun_arg () in
+			let arg3 = read_fun_arg () in
+			TFun([arg1;arg2;arg3],api#basic_types.tvoid)
+		| 24 ->
+			let arg1 = read_fun_arg () in
+			let arg2 = read_fun_arg () in
+			let arg3 = read_fun_arg () in
+			let arg4 = read_fun_arg () in
+			TFun([arg1;arg2;arg3;arg4],api#basic_types.tvoid)
+		| 29 ->
+			let args = self#read_list read_fun_arg in
+			TFun(args,api#basic_types.tvoid)
+		| 30 ->
+			let ret = self#read_type_instance in
+			TFun([],ret)
+		| 31 ->
+			let arg1 = read_fun_arg () in
+			let ret = self#read_type_instance in
+			TFun([arg1],ret)
+		| 32 ->
+			let arg1 = read_fun_arg () in
+			let arg2 = read_fun_arg () in
+			let ret = self#read_type_instance in
+			TFun([arg1;arg2],ret)
+		| 33 ->
+			let arg1 = read_fun_arg () in
+			let arg2 = read_fun_arg () in
+			let arg3 = read_fun_arg () in
+			let ret = self#read_type_instance in
+			TFun([arg1;arg2;arg3],ret)
+		| 34 ->
+			let arg1 = read_fun_arg () in
+			let arg2 = read_fun_arg () in
+			let arg3 = read_fun_arg () in
+			let arg4 = read_fun_arg () in
+			let ret = self#read_type_instance in
+			TFun([arg1;arg2;arg3;arg4],ret)
+		| 39 ->
+			let args = self#read_list read_fun_arg in
+			let ret = self#read_type_instance in
+			TFun(args,ret)
+		| 40 ->
+			let c = self#read_class_ref in
+			TInst(c,[])
+		| 41 ->
+			let c = self#read_class_ref in
+			let t1 = self#read_type_instance in
+			TInst(c,[t1])
+		| 42 ->
+			let c = self#read_class_ref in
+			let t1 = self#read_type_instance in
+			let t2 = self#read_type_instance in
+			TInst(c,[t1;t2])
+		| 49 ->
+			let c = self#read_class_ref in
+			let tl = self#read_types in
+			TInst(c,tl)
+		| 50 ->
+			let en = self#read_enum_ref in
+			TEnum(en,[])
+		| 51 ->
+			let en = self#read_enum_ref in
+			let t1 = self#read_type_instance in
+			TEnum(en,[t1])
+		| 52 ->
+			let en = self#read_enum_ref in
+			let t1 = self#read_type_instance in
+			let t2 = self#read_type_instance in
+			TEnum(en,[t1;t2])
+		| 59 ->
+			let e = self#read_enum_ref in
+			let tl = self#read_types in
+			TEnum(e,tl)
+		| 60 ->
+			let td = self#read_typedef_ref in
+			TType(td,[])
+		| 61 ->
+			let td = self#read_typedef_ref in
+			let t1 = self#read_type_instance in
+			TType(td,[t1])
+		| 62 ->
+			let td = self#read_typedef_ref in
+			let t1 = self#read_type_instance in
+			let t2 = self#read_type_instance in
+			TType(td,[t1;t2])
+		| 69 ->
+			let t = self#read_typedef_ref in
+			let tl = self#read_types in
+			TType(t,tl)
+		| 70 ->
+			let a = self#read_abstract_ref in
+			TAbstract(a,[])
+		| 71 ->
+			let a = self#read_abstract_ref in
+			let t1 = self#read_type_instance in
+			TAbstract(a,[t1])
+		| 72 ->
+			let a = self#read_abstract_ref in
+			let t1 = self#read_type_instance in
+			let t2 = self#read_type_instance in
+			TAbstract(a,[t1;t2])
+		| 79 ->
+			let a = self#read_abstract_ref in
+			let tl = self#read_types in
+			TAbstract(a,tl)
+		| 80 ->
+			empty_anon
+		| 81 ->
+			TAnon self#read_anon_ref
+		| 89 ->
+			TDynamic (Some self#read_type_instance)
+		| 100 ->
+			api#basic_types.tvoid
+		| 101 ->
+			api#basic_types.tint
+		| 102 ->
+			api#basic_types.tfloat
+		| 103 ->
+			api#basic_types.tbool
+		| 104 ->
+			api#basic_types.tstring
+		| i ->
+			error (Printf.sprintf "Bad type instance id: %i" i)
+
+	method read_types =
+		self#read_list (fun () -> self#read_type_instance)
+
+	method read_type_parameters_forward =
+		let length = read_uleb128 ch in
+		Array.init length (fun _ ->
+			let path = self#read_path in
+			let pos = self#read_pos in
+			let host = match read_byte ch with
+				| 0 -> TPHType
+				| 1 -> TPHConstructor
+				| 2 -> TPHMethod
+				| 3 -> TPHEnumConstructor
+				| 4 -> TPHAnonField
+				| 5 -> TPHLocal
+				| i -> die (Printf.sprintf "Invalid type paramter host: %i" i) __LOC__
+			in
+			let c = mk_class current_module path pos pos in
+			let ttp = mk_type_param c host None None in
+			c.cl_kind <- KTypeParameter ttp;
+			ttp
+		)
+
+	method read_type_parameters_data (a : typed_type_param array) =
+		Array.iter (fun ttp ->
+			let meta = self#read_metadata in
+			let constraints = self#read_types in
+			let def = self#read_option (fun () -> self#read_type_instance) in
+			let c = ttp.ttp_class in
+			ttp.ttp_default <- def;
+			ttp.ttp_constraints <- Some (Lazy.from_val constraints);
+			c.cl_meta <- meta;
+		) a
+
+	(* Fields *)
+
+	method read_field_kind = match read_byte ch with
+		| 0 -> Method MethNormal
+		| 1 -> Method MethInline
+		| 2 -> Method MethDynamic
+		| 3 -> Method MethMacro
+		| 10 -> Var {v_read = AccNormal;v_write = AccNormal}
+		| 11 -> Var {v_read = AccNormal;v_write = AccNo}
+		| 12 -> Var {v_read = AccNormal;v_write = AccNever}
+		| 13 -> Var {v_read = AccNormal;v_write = AccCtor}
+		| 14 -> Var {v_read = AccNormal;v_write = AccCall}
+		| 20 -> Var {v_read = AccInline;v_write = AccNever}
+		| 30 -> Var {v_read = AccCall;v_write = AccNormal}
+		| 31 -> Var {v_read = AccCall;v_write = AccNo}
+		| 32 -> Var {v_read = AccCall;v_write = AccNever}
+		| 33 -> Var {v_read = AccCall;v_write = AccCtor}
+		| 34 -> Var {v_read = AccCall;v_write = AccCall}
+		| 100 ->
+			let f = function
+				| 0 -> AccNormal
+				| 1 -> AccNo
+				| 2 -> AccNever
+				| 3 -> AccCtor
+				| 4 -> AccCall
+				| 5 -> AccInline
+				| 6 ->
+					let s = self#read_string in
+					let so = self#read_option (fun () -> self#read_string) in
+					AccRequire(s,so)
+				| i ->
+					error (Printf.sprintf "Bad accessor kind: %i" i)
+			in
+			let r = f (read_byte ch) in
+			let w = f (read_byte ch) in
+			Var {v_read = r;v_write = w}
+		| i ->
+			error (Printf.sprintf "Bad field kind: %i" i)
+
+	method read_var_kind =
+		match read_byte ch with
+			| 0 -> VUser TVOLocalVariable
+			| 1 -> VUser TVOArgument
+			| 2 -> VUser TVOForVariable
+			| 3 -> VUser TVOPatternVariable
+			| 4 -> VUser TVOCatchVariable
+			| 5 -> VUser TVOLocalFunction
+			| 6 -> VGenerated
+			| 7 -> VInlined
+			| 8 -> VInlinedConstructorVariable
+			| 9 -> VExtractorVariable
+			| 10 -> VAbstractThis
+			| _ -> assert false
+
+	method read_var =
+		let id = read_uleb128 ch in
+		let name = self#read_string in
+		let kind = self#read_var_kind in
+		let flags = read_uleb128 ch in
+		let meta = self#read_metadata in
+		let pos = self#read_pos in
+		let v = {
+			v_id = api#get_var_id id;
+			v_name = name;
+			v_type = t_dynamic;
+			v_kind = kind;
+			v_meta = meta;
+			v_pos = pos;
+			v_extra = None;
+			v_flags = flags;
+		} in
+		v
+
+	method read_texpr fctx =
+
+		let declare_local () =
+			let v = fctx.vars.(read_uleb128 ch) in
+			v.v_extra <- self#read_option (fun () ->
+				let params = self#read_list (fun () ->
+					let i = read_uleb128 ch in
+					local_type_parameters.(i)
+				) in
+				let vexpr = self#read_option (fun () -> self#read_texpr fctx) in
+				{
+					v_params = params;
+					v_expr = vexpr;
+				};
+			);
+			v.v_type <- self#read_type_instance;
+			v
+		in
+		let update_pmin () =
+			fctx.pos := {!(fctx.pos) with pmin = read_leb128 ch};
+		in
+		let update_pmax () =
+			fctx.pos := {!(fctx.pos) with pmax = read_leb128 ch};
+		in
+		let update_pminmax () =
+			let pmin = read_leb128 ch in
+			let pmax = read_leb128 ch in
+			fctx.pos := {!(fctx.pos) with pmin; pmax};
+		in
+		let update_p () =
+			fctx.pos := self#read_pos;
+		in
+		let read_relpos () =
+			begin match read_byte ch with
+				| 0 ->
+					()
+				| 1 ->
+					update_pmin ()
+				| 2 ->
+					update_pmax ()
+				| 3 ->
+					update_pminmax ()
+				| 4 ->
+					update_p ()
+				| _ ->
+					assert false
+			end;
+			!(fctx.pos)
+		in
+		let rec loop () =
+			let loop2 () =
+				match read_byte ch with
+					(* values 0-19 *)
+					| 0 -> TConst TNull,None
+					| 1 -> TConst TThis,fctx.tthis
+					| 2 -> TConst TSuper,None
+					| 3 -> TConst (TBool false),(Some api#basic_types.tbool)
+					| 4 -> TConst (TBool true),(Some api#basic_types.tbool)
+					| 5 -> TConst (TInt self#read_i32),(Some api#basic_types.tint)
+					| 6 -> TConst (TFloat self#read_string),(Some api#basic_types.tfloat)
+					| 7 -> TConst (TString self#read_string),(Some api#basic_types.tstring)
+					| 13 -> TConst (TBool false),None
+					| 14 -> TConst (TBool true),None
+					| 15 -> TConst (TInt self#read_i32),None
+					| 16 -> TConst (TFloat self#read_string),None
+					| 17 -> TConst (TString self#read_string),None
+
+					(* vars 20-29 *)
+					| 20 ->
+						TLocal (fctx.vars.(read_uleb128 ch)),None
+					| 21 ->
+						let v = declare_local () in
+						TVar (v,None),(Some api#basic_types.tvoid)
+					| 22 ->
+						let v = declare_local () in
+						let e = loop () in
+						TVar (v, Some e),(Some api#basic_types.tvoid)
+
+					(* blocks 30-49 *)
+					| 30 ->
+						TBlock [],None
+					| 31 | 32 | 33 | 34 | 35 as i ->
+						let l = i - 30 in
+						let el = List.init l (fun _ -> loop ()) in
+						TBlock el,None
+					| 36 ->
+						let l = read_byte ch in
+						let el = List.init l (fun _ -> loop ()) in
+						TBlock el,None
+					| 39 ->
+						let el = self#read_list loop in
+						TBlock el,None
+
+					(* function 50-59 *)
+					| 50 ->
+						let read_tfunction_arg () =
+							let v = declare_local () in
+							let cto = self#read_option loop in
+							(v,cto)
+						in
+						let args = self#read_list read_tfunction_arg in
+						let r = self#read_type_instance in
+						let e = loop () in
+						TFunction {
+							tf_args = args;
+							tf_type = r;
+							tf_expr = e;
+						},None
+					(* texpr compounds 60-79 *)
+					| 60 ->
+						let e1 = loop () in
+						let e2 = loop () in
+						TArray (e1,e2),None
+					| 61 ->
+						let e = loop () in
+						TParenthesis e,Some e.etype
+					| 62 ->
+						TArrayDecl (loop_el()),None
+					| 63 ->
+						let fl = self#read_list (fun () ->
+							let name = self#read_string in
+							let p = self#read_pos in
+							let qs = match read_byte ch with
+								| 0 -> NoQuotes
+								| 1 -> DoubleQuotes
+								| _ -> assert false
+							in
+							let e = loop () in
+							((name,p,qs),e)
+						) in
+						TObjectDecl fl,None
+					| 65 ->
+						let m = self#read_metadata_entry in
+						let e1 = loop () in
+						TMeta (m,e1),None
+
+					(* calls 70 - 79 *)
+					| 70 ->
+						let e1 = loop () in
+						TCall(e1,[]),None
+					| 71 | 72 | 73 | 74 as i ->
+						let e1 = loop () in
+						let el = List.init (i - 70) (fun _ -> loop ()) in
+						TCall(e1,el),None
+					| 79 ->
+						let e1 = loop () in
+						let el = self#read_list loop in
+						TCall(e1,el),None
+
+					(* branching 80-89 *)
+					| 80 ->
+						let e1 = loop () in
+						let e2 = loop () in
+						TIf(e1,e2,None),(Some api#basic_types.tvoid)
+					| 81 ->
+						let e1 = loop () in
+						let e2 = loop () in
+						let e3 = loop () in
+						TIf(e1,e2,Some e3),None
+					| 82 ->
+						let subject = loop () in
+						let cases = self#read_list (fun () ->
+							let patterns = loop_el() in
+							let ec = loop () in
+							{ case_patterns = patterns; case_expr = ec}
+						) in
+						let def = self#read_option (fun () -> loop ()) in
+						TSwitch {
+							switch_subject = subject;
+							switch_cases = cases;
+							switch_default = def;
+							switch_exhaustive = true;
+						},None
+					| 83 ->
+						let e1 = loop () in
+						let catches = self#read_list (fun () ->
+							let v = declare_local () in
+							let e = loop () in
+							(v,e)
+						) in
+						TTry(e1,catches),None
+					| 84 ->
+						let e1 = loop () in
+						let e2 = loop () in
+						TWhile(e1,e2,NormalWhile),(Some api#basic_types.tvoid)
+					| 85 ->
+						let e1 = loop () in
+						let e2 = loop () in
+						TWhile(e1,e2,DoWhile),(Some api#basic_types.tvoid)
+					| 86 ->
+						let v  = declare_local () in
+						let e1 = loop () in
+						let e2 = loop () in
+						TFor(v,e1,e2),(Some api#basic_types.tvoid)
+
+					(* control flow 90-99 *)
+					| 90 ->
+						TReturn None,None
+					| 91 ->
+						TReturn (Some (loop ())),None
+					| 92 ->
+						TContinue,None
+					| 93 ->
+						TBreak,None
+					| 94 ->
+						TThrow (loop ()),None
+
+					(* access 100-119 *)
+					| 100 ->
+						TEnumIndex (loop ()),(Some api#basic_types.tint)
+					| 101 ->
+						let e1 = loop () in
+						let ef = self#read_enum_field_ref in
+						let i = read_uleb128 ch in
+						TEnumParameter(e1,ef,i),None
+					| 102 ->
+						let e1 = loop () in
+						let c = self#read_class_ref in
+						let tl = self#read_types in
+						let cf = self#read_field_ref in
+						TField(e1,FInstance(c,tl,cf)),None
+					| 103 ->
+						let e1 = loop () in
+						let c = self#read_class_ref in
+						let cf = self#read_field_ref in
+						TField(e1,FStatic(c,cf)),None
+					| 104 ->
+						let e1 = loop () in
+						let cf = self#read_anon_field_ref in
+						TField(e1,FAnon(cf)),None
+					| 105 ->
+						let e1 = loop () in
+						let c = self#read_class_ref in
+						let tl = self#read_types in
+						let cf = self#read_field_ref in
+						TField(e1,FClosure(Some(c,tl),cf)),None
+					| 106 ->
+						let e1 = loop () in
+						let cf = self#read_anon_field_ref in
+						TField(e1,FClosure(None,cf)),None
+					| 107 ->
+						let e1 = loop () in
+						let en = self#read_enum_ref in
+						let ef = self#read_enum_field_ref in
+						TField(e1,FEnum(en,ef)),None
+					| 108 ->
+						let e1 = loop () in
+						let s = self#read_string in
+						TField(e1,FDynamic s),None
+
+					| 110 ->
+						let p = read_relpos () in
+						let c = self#read_class_ref in
+						let cf = self#read_field_ref in
+						let e1 = Texpr.Builder.make_static_this c p in
+						TField(e1,FStatic(c,cf)),None
+					| 111 ->
+						let p = read_relpos () in
+						let c = self#read_class_ref in
+						let tl = self#read_types in
+						let cf = self#read_field_ref in
+						let ethis = mk (TConst TThis) (Option.get fctx.tthis) p in
+						TField(ethis,FInstance(c,tl,cf)),None
+
+					(* module types 120-139 *)
+					| 120 ->
+						let c = self#read_class_ref in
+						TTypeExpr (TClassDecl c),(Some c.cl_type)
+					| 121 ->
+						let en = self#read_enum_ref in
+						TTypeExpr (TEnumDecl en),(Some en.e_type)
+					| 122 ->
+						TTypeExpr (TAbstractDecl self#read_abstract_ref),None
+					| 123 ->
+						TTypeExpr (TTypeDecl self#read_typedef_ref),None
+					| 124 ->
+						TCast(loop (),None),None
+					| 125 ->
+						let e1 = loop () in
+						let (pack,mname,tname) = self#read_full_path in
+						let mt = self#resolve_type pack mname tname in
+						TCast(e1,Some mt),None
+					| 126 ->
+						let c = self#read_class_ref in
+						let tl = self#read_types in
+						let el = loop_el() in
+						TNew(c,tl,el),None
+					| 127 ->
+						let ttp = self#resolve_ttp_ref (read_uleb128 ch) in
+						let tl = self#read_types in
+						let el = loop_el() in
+						TNew(ttp.ttp_class,tl,el),None
+					| 128 ->
+						let ttp = self#resolve_ttp_ref (read_uleb128 ch) in
+						TTypeExpr (TClassDecl ttp.ttp_class),None
+
+					(* unops 140-159 *)
+					| i when i >= 140 && i < 160 ->
+						let (op,flag) = self#get_unop (i - 140) in
+						let e = loop () in
+						TUnop(op,flag,e),None
+
+					(* binops 160-219 *)
+					| i when i >= 160 && i < 220 ->
+						let op = self#get_binop (i - 160) in
+						let e1 = loop () in
+						let e2 = loop () in
+						TBinop(op,e1,e2),None
+					(* rest 250-254 *)
+					| 250 ->
+						TIdent (self#read_string),None
+
+					| i ->
+						die (Printf.sprintf "  [ERROR] Unhandled texpr %d at:" i) __LOC__
+				in
+				let e,t = loop2 () in
+				let t = match t with
+					| None -> fctx.t_pool.(read_uleb128 ch)
+					| Some t -> t
+				in
+				let p = read_relpos () in
+				let e = {
+					eexpr = e;
+					etype = t;
+					epos = p;
+				} in
+				e
+		and loop_el () =
+			self#read_list loop
+		in
+		loop()
+
+	method read_class_field_forward =
+		let name = self#read_string in
+		let pos,name_pos = self#read_pos_pair in
+		let overloads = self#read_list (fun () -> self#read_class_field_forward) in
+		{ null_field with cf_name = name; cf_pos = pos; cf_name_pos = name_pos; cf_overloads = overloads }
+
+	method start_texpr =
+		begin match read_byte ch with
+			| 0 ->
+				()
+			| 1 ->
+				let a = self#read_type_parameters_forward in
+				local_type_parameters <- a;
+				self#read_type_parameters_data a;
+			| i ->
+				die "" __LOC__
+		end;
+		let tthis = self#read_option (fun () -> self#read_type_instance) in
+		let l = read_uleb128 ch in
+		let ts = Array.init l (fun _ ->
+			self#read_type_instance
+		) in
+		let l = read_uleb128 ch in
+		let vars = Array.init l (fun _ ->
+			self#read_var
+		) in
+		create_field_reader_context self#read_pos ts vars tthis
+
+	method read_field_type_parameters =
+		let num_params = read_uleb128 ch in
+		begin match read_byte ch with
+			| 0 ->
+				()
+			| 1 ->
+				let a = self#read_type_parameters_forward in
+				field_type_parameters <- a;
+				self#read_type_parameters_data a;
+				field_type_parameter_offset <- 0; (* num_params is added below *)
+			| i ->
+				die "" __LOC__
+		end;
+		let params = List.init num_params (fun offset ->
+			field_type_parameters.(field_type_parameter_offset + offset)
+		) in
+		field_type_parameter_offset <- field_type_parameter_offset + num_params;
+		params
+
+	method read_expression (fctx : field_reader_context) =
+		let e = self#read_texpr fctx in
+		let e_unopt = self#read_option (fun () -> self#read_texpr fctx) in
+		e,e_unopt
+
+	val class_field_infos = ClassFieldInfos.create ()
+
+	method read_class_field_data (cf : tclass_field) : unit =
+		let params = self#read_field_type_parameters in
+
+		let t = self#read_type_instance in
+
+		let flags = read_uleb128 ch in
+
+		let doc = self#read_option (fun () -> self#read_documentation) in
+		cf.cf_meta <- self#read_metadata;
+		let kind = self#read_field_kind in
+
+		let expr,expr_unoptimized = match read_byte ch with
+			| 0 ->
+				None,None
+			| 1 ->
+				let fctx = self#start_texpr in
+				let e,e_unopt = self#read_expression fctx in
+				(Some e,e_unopt)
+			| 2 ->
+				(* store type parameter info for EXD *)
+				let info = ClassFieldInfo.create field_type_parameters in
+				ClassFieldInfos.set class_field_infos info cf;
+				None,None
+			| _ ->
+				die "" __LOC__
+		in
+
+		cf.cf_type <- t;
+		cf.cf_doc <- doc;
+		cf.cf_kind <- kind;
+		cf.cf_expr <- expr;
+		cf.cf_expr_unoptimized <- expr_unoptimized;
+		cf.cf_params <- params;
+		cf.cf_flags <- flags
+
+	method read_class_field_and_overloads_data (cf : tclass_field) =
+		let rec loop depth cfl = match cfl with
+			| cf :: cfl ->
+				assert (depth > 0);
+				self#read_class_field_data cf;
+				loop (depth - 1) cfl
+			| [] ->
+				assert (depth = 0)
+		in
+		loop (read_uleb128 ch) (cf :: cf.cf_overloads);
+
+	method select_class_type_parameters (c: tclass) =
+		match c.cl_kind with
+		| KAbstractImpl a ->
+			type_type_parameters <- Array.of_list a.a_params
+		| _ ->
+			type_type_parameters <- Array.of_list c.cl_params
+
+	method read_class_fields (c : tclass) =
+		self#select_class_type_parameters c;
+		let _ = self#read_option (fun f ->
+			let cf = Option.get c.cl_constructor in
+			self#read_class_field_and_overloads_data cf
+		) in
+		let _ = self#read_option (fun f ->
+			let cf = Option.get c.cl_init in
+			self#read_class_field_and_overloads_data cf
+		) in
+		let rec loop ref_kind num cfl = match cfl with
+			| cf :: cfl ->
+				assert (num > 0);
+				self#read_class_field_and_overloads_data cf;
+				loop ref_kind (num - 1) cfl
+			| [] ->
+				assert (num = 0)
+		in
+		loop CfrMember (read_uleb128 ch) c.cl_ordered_fields;
+		loop CfrStatic (read_uleb128 ch) c.cl_ordered_statics;
+		(match c.cl_kind with KModuleFields md -> md.m_statics <- Some c; | _ -> ());
+
+	method read_enum_fields (e : tenum) =
+		type_type_parameters <- Array.of_list e.e_params;
+		ignore(self#read_list (fun () ->
+			let name = self#read_string in
+			let ef = PMap.find name e.e_constrs in
+			ef.ef_params <- self#read_field_type_parameters;
+			ef.ef_type <- self#read_type_instance;
+			ef.ef_doc <- self#read_option (fun () -> self#read_documentation);
+			ef.ef_meta <- self#read_metadata;
+		))
+
+	(* Module types *)
+
+	method read_common_module_type (infos : tinfos) =
+		infos.mt_private <- self#read_bool;
+		infos.mt_doc <- self#read_option (fun () -> self#read_documentation);
+		infos.mt_meta <- self#read_metadata;
+		let params = Array.of_list infos.mt_params in
+		type_type_parameters <- params;
+		self#read_type_parameters_data params;
+		infos.mt_params <- Array.to_list type_type_parameters;
+		infos.mt_using <- self#read_list (fun () ->
+			let c = self#read_class_ref in
+			let p = self#read_pos in
+			(c,p)
+		)
+
+	method read_class_kind = match read_byte ch with
+		| 0 -> KNormal
+		| 1 -> die "" __LOC__
+		| 2 -> KExpr self#read_expr
+		| 3 -> KGeneric
+		| 4 ->
+			let c = self#read_class_ref in
+			let tl = self#read_types in
+			KGenericInstance(c,tl)
+		| 5 -> KMacroType
+		| 6 -> KGenericBuild (self#read_list (fun () -> self#read_cfield))
+		| 7 -> KAbstractImpl self#read_abstract_ref
+		| 8 -> KModuleFields current_module
+		| i ->
+			error (Printf.sprintf "Invalid class kind id: %i" i)
+
+	method read_class (c : tclass) =
+		self#read_common_module_type (Obj.magic c);
+		c.cl_kind <- self#read_class_kind;
+		let read_relation () =
+			let c = self#read_class_ref in
+			let tl = self#read_types in
+			(c,tl)
+		in
+		c.cl_super <- self#read_option read_relation;
+		c.cl_implements <- self#read_list read_relation;
+		c.cl_dynamic <- self#read_option (fun () -> self#read_type_instance);
+		c.cl_array_access <- self#read_option (fun () -> self#read_type_instance);
+
+	method read_abstract (a : tabstract) =
+		self#read_common_module_type (Obj.magic a);
+		a.a_impl <- self#read_option (fun () -> self#read_class_ref);
+		begin match read_byte ch with
+			| 0 ->
+				a.a_this <- TAbstract(a,extract_param_types a.a_params)
+			| _ ->
+				a.a_this <- self#read_type_instance;
+		end;
+		a.a_from <- self#read_list (fun () -> self#read_type_instance);
+		a.a_to <- self#read_list (fun () -> self#read_type_instance);
+		a.a_enum <- self#read_bool;
+
+	method read_abstract_fields (a : tabstract) =
+		a.a_array <- self#read_list (fun () -> self#read_field_ref);
+		a.a_read <- self#read_option (fun () -> self#read_field_ref);
+		a.a_write <- self#read_option (fun () -> self#read_field_ref);
+		a.a_call <- self#read_option (fun () -> self#read_field_ref);
+
+		a.a_ops <- self#read_list (fun () ->
+			let i = read_byte ch in
+			let op = self#get_binop i in
+			let cf = self#read_field_ref in
+			(op, cf)
+		);
+
+		a.a_unops <- self#read_list (fun () ->
+			let i = read_byte ch in
+			let (op, flag) = self#get_unop i in
+			let cf = self#read_field_ref in
+			(op, flag, cf)
+		);
+
+		a.a_from_field <- self#read_list (fun () ->
+			let cf = self#read_field_ref in
+			let t = match cf.cf_type with
+				| TFun((_,_,t) :: _, _) -> t
+				| _ -> die "" __LOC__
+			in
+			(t,cf)
+		);
+
+		a.a_to_field <- self#read_list (fun () ->
+			let cf = self#read_field_ref in
+			let t = match cf.cf_type with
+				| TFun(_, t) -> t
+				| _ -> die "" __LOC__
+			in
+			(t,cf)
+		);
+
+	method read_enum (e : tenum) =
+		self#read_common_module_type (Obj.magic e);
+		e.e_extern <- self#read_bool;
+		e.e_names <- self#read_list (fun () -> self#read_string);
+
+	method read_typedef (td : tdef) =
+		self#read_common_module_type (Obj.magic td);
+		let t = self#read_type_instance in
+		match td.t_type with
+		| TMono r ->
+			(match r.tm_type with
+			| None -> Monomorph.bind r t;
+			| Some t' -> die (Printf.sprintf "typedef %s is already initialized to %s, but new init to %s was attempted" (s_type_path td.t_path) (s_type_kind t') (s_type_kind t)) __LOC__)
+		| _ ->
+			die "" __LOC__
+
+	(* Chunks *)
+
+	method read_string_pool =
+		let l = read_uleb128 ch in
+		Array.init l (fun i ->
+			self#read_raw_string;
+		);
+
+	method read_efr =
+		let l = read_uleb128 ch in
+		let a = Array.init l (fun i ->
+			let en = self#read_enum_ref in
+			let name = self#read_string in
+			PMap.find name en.e_constrs
+		) in
+		enum_fields <- a
+
+	method read_afr =
+		let l = read_uleb128 ch in
+		let a = Array.init l (fun _ -> self#read_class_field_forward) in
+		anon_fields <- a
+
+	method read_cfr =
+		let l = read_uleb128 ch in
+		let a = Array.init l (fun i ->
+			let c = self#read_class_ref in
+			let kind = match read_byte ch with
+				| 0 -> CfrStatic
+				| 1 -> CfrMember
+				| 2 -> CfrConstructor
+				| 3 -> CfrInit
+				| _ -> die "" __LOC__
+			in
+			let cf =  match kind with
+				| CfrStatic ->
+					let name = self#read_string in
+					begin try
+						PMap.find name c.cl_statics
+					with Not_found ->
+						raise (HxbFailure (Printf.sprintf "Could not read static field %s on %s while hxbing %s" name (s_type_path c.cl_path) (s_type_path current_module.m_path)))
+					end;
+				| CfrMember ->
+					let name = self#read_string in
+					begin try
+						PMap.find name c.cl_fields
+					with Not_found ->
+						raise (HxbFailure (Printf.sprintf "Could not read instance field %s on %s while hxbing %s" name (s_type_path c.cl_path) (s_type_path current_module.m_path)))
+					end
+				| CfrConstructor ->
+					Option.get c.cl_constructor
+				| CfrInit ->
+					Option.get c.cl_init
+			in
+			let pick_overload cf depth =
+				let rec loop depth cfl = match cfl with
+					| cf :: cfl ->
+						if depth = 0 then
+							cf
+						else
+							loop (depth - 1) cfl
+					| [] ->
+						raise (HxbFailure (Printf.sprintf "Bad overload depth for %s on %s: %i" cf.cf_name (s_type_path c.cl_path) depth))
+				in
+				let cfl = cf :: cf.cf_overloads in
+				loop depth cfl
+			in
+			let depth = read_uleb128 ch in
+			if depth = 0 then
+				cf
+			else
+				pick_overload cf depth;
+		) in
+		class_fields <- a
+
+	method read_cfd =
+		let l = read_uleb128 ch in
+		for i = 0 to l - 1 do
+			let c = classes.(i) in
+			self#read_class_fields c;
+		done
+
+	method read_exd =
+		ignore(self#read_list (fun () ->
+			let c = self#read_class_ref in
+			self#read_list (fun () ->
+				let cf = self#read_field_ref in
+				let length = read_uleb128 ch in
+				let bytes = read_bytes ch length in
+				let ch_cf = BytesWithPosition.create bytes in
+				let read_expressions () =
+					self#select_class_type_parameters c;
+					field_type_parameters <- (ClassFieldInfos.get class_field_infos cf).type_parameters;
+					ClassFieldInfos.unset class_field_infos cf;
+					field_type_parameter_offset <- 0;
+					let old = ch in
+					ch <- ch_cf;
+					let fctx = self#start_texpr in
+					let e,e_unopt = self#read_expression fctx in
+					ch <- old;
+					cf.cf_expr <- Some e;
+					cf.cf_expr_unoptimized <- e_unopt;
+				in
+				if api#read_expression_eagerly cf then
+					read_expressions ()
+				else begin
+					let t = cf.cf_type in
+					let r = ref (lazy_available t) in
+					r := lazy_wait (fun() ->
+						cf.cf_type <- t;
+						r := lazy_available t;
+						read_expressions ();
+						t
+					);
+					cf.cf_type <- TLazy r
+				end
+			)
+		))
+
+	method read_afd =
+		let l = read_uleb128 ch in
+		for i = 0 to l - 1 do
+			let a = abstracts.(i) in
+			self#read_abstract_fields a;
+		done
+
+	method read_cld =
+		let l = read_uleb128 ch in
+		for i = 0 to l - 1 do
+			let c = classes.(i) in
+			self#read_class c;
+		done
+
+	method read_abd =
+		let l = read_uleb128 ch in
+		for i = 0 to l - 1 do
+			let a = abstracts.(i) in
+			self#read_abstract a;
+		done
+
+	method read_end =
+		let l = read_uleb128 ch in
+		for i = 0 to l - 1 do
+			let en = enums.(i) in
+			self#read_enum en;
+		done
+
+	method read_efd =
+		let l = read_uleb128 ch in
+		for i = 0 to l - 1 do
+			let e = enums.(i) in
+			self#read_enum_fields e;
+			Type.unify (TType(enum_module_type e,[])) e.e_type
+		done
+
+	method read_anon an =
+		let read_fields () =
+			let rec loop acc i =
+				if i = 0 then
+					acc
+				else begin
+					let cf = self#read_anon_field_ref in
+					loop (PMap.add cf.cf_name cf acc) (i - 1)
+				end
+			in
+			an.a_fields <- loop PMap.empty (read_uleb128 ch)
+		in
+
+		begin match read_byte ch with
+		| 0 ->
+			an.a_status := Closed;
+			read_fields ()
+		| 1 ->
+			an.a_status := Const;
+			read_fields ()
+		| 2 ->
+			an.a_status := Extend self#read_types;
+			read_fields ()
+		| _ -> assert false
+		end;
+
+		an
+
+	method read_tdd =
+		let l = read_uleb128 ch in
+		for i = 0 to l - 1 do
+			let t = typedefs.(i) in
+			self#read_typedef t;
+		done
+
+	method read_clr =
+		let l = read_uleb128 ch in
+		classes <- (Array.init l (fun i ->
+				let (pack,mname,tname) = self#read_full_path in
+				match self#resolve_type pack mname tname with
+				| TClassDecl c ->
+					c
+				| _ ->
+					error ("Unexpected type where class was expected: " ^ (s_type_path (pack,tname)))
+		))
+
+	method read_abr =
+		let l = read_uleb128 ch in
+		abstracts <- (Array.init l (fun i ->
+			let (pack,mname,tname) = self#read_full_path in
+			match self#resolve_type pack mname tname with
+			| TAbstractDecl a ->
+				a
+			| _ ->
+				error ("Unexpected type where abstract was expected: " ^ (s_type_path (pack,tname)))
+		))
+
+	method read_enr =
+		let l = read_uleb128 ch in
+		enums <- (Array.init l (fun i ->
+			let (pack,mname,tname) = self#read_full_path in
+			match self#resolve_type pack mname tname with
+			| TEnumDecl en ->
+				en
+			| _ ->
+				error ("Unexpected type where enum was expected: " ^ (s_type_path (pack,tname)))
+		))
+
+	method read_tdr =
+		let l = read_uleb128 ch in
+		typedefs <- (Array.init l (fun i ->
+			let (pack,mname,tname) = self#read_full_path in
+			match self#resolve_type pack mname tname with
+			| TTypeDecl tpd ->
+				tpd
+			| _ ->
+				error ("Unexpected type where typedef was expected: " ^ (s_type_path (pack,tname)))
+		))
+
+	method read_mdr =
+		let length = read_uleb128 ch in
+		for _ = 0 to length - 1 do
+			let path = self#read_path in
+			ignore(api#resolve_module path)
+		done
+
+	method read_mtf =
+		self#read_list (fun () ->
+			let kind = read_byte ch in
+			let path = self#read_path in
+			let pos,name_pos = self#read_pos_pair in
+			let params = self#read_type_parameters_forward in
+			let mt = match kind with
+			| 0 ->
+				let c = mk_class current_module path pos name_pos in
+				c.cl_params <- Array.to_list params;
+				c.cl_flags <- read_uleb128 ch;
+
+				let read_field () =
+					self#read_class_field_forward;
+				in
+
+				c.cl_constructor <- self#read_option read_field;
+				c.cl_init <- self#read_option read_field;
+				let read_fields i =
+					let rec loop acc_l acc_pm i =
+						if i = 0 then
+							acc_l,acc_pm
+						else begin
+							let cf = self#read_class_field_forward in
+							loop (cf :: acc_l) (PMap.add cf.cf_name cf acc_pm) (i - 1)
+						end
+					in
+					loop [] PMap.empty i
+				in
+				let num_fields = read_uleb128 ch in
+				let num_statics = read_uleb128 ch in
+				let l,pm = read_fields num_fields in
+				c.cl_ordered_fields <- l;
+				c.cl_fields <- pm;
+				let l,pm = read_fields num_statics in
+				c.cl_ordered_statics <- l;
+				c.cl_statics <- pm;
+
+				TClassDecl c
+			| 1 ->
+				let en = mk_enum current_module path pos name_pos in
+				en.e_params <- Array.to_list params;
+
+				let read_field () =
+					let name = self#read_string in
+					let pos,name_pos = self#read_pos_pair in
+					let index = read_byte ch in
+
+					{ null_enum_field with
+						ef_name = name;
+						ef_pos = pos;
+						ef_name_pos = name_pos;
+						ef_index = index;
+					}
+				in
+				let rec loop acc i =
+					if i = 0 then
+						acc
+					else begin
+						let ef = read_field () in
+						loop (PMap.add ef.ef_name ef acc) (i - 1)
+					end
+				in
+				en.e_constrs <- loop PMap.empty (read_uleb128 ch);
+				TEnumDecl en
+			| 2 ->
+				let td = mk_typedef current_module path pos name_pos (mk_mono()) in
+				td.t_params <- Array.to_list params;
+				typedefs <- Array.append typedefs (Array.make 1 td);
+				TTypeDecl td
+			| 3 ->
+				let a = mk_abstract current_module path pos name_pos in
+				a.a_params <- Array.to_list params;
+				abstracts <- Array.append abstracts (Array.make 1 a);
+				TAbstractDecl a
+			| _ ->
+				error ("Invalid type kind: " ^ (string_of_int kind));
+			in
+			mt
+		)
+
+	method read_mdf =
+		let path = self#read_path in
+		let file = self#read_string in
+
+		let l = read_uleb128 ch in
+		anons <- Array.init l (fun _ -> { a_fields = PMap.empty; a_status = ref Closed });
+		tmonos <- Array.init (read_uleb128 ch) (fun _ -> mk_mono());
+		api#make_module path file
+
+	method private read_chunk_prefix =
+		let name = Bytes.unsafe_to_string (read_bytes ch 3) in
+		let size = Int32.to_int self#read_i32 in
+		(name,size)
+
+	method private read_chunk_data' (kind : chunk_kind) =
+		match kind with
+		| STR ->
+			string_pool <- self#read_string_pool;
+		| DOC ->
+			doc_pool <- self#read_string_pool;
+		| MDF ->
+			current_module <- self#read_mdf;
+		| MTF ->
+			current_module.m_types <- self#read_mtf;
+			api#add_module current_module;
+		| MDR ->
+			self#read_mdr;
+		| CLR ->
+			self#read_clr;
+		| ENR ->
+			self#read_enr;
+		| ABR ->
+			self#read_abr;
+		| TDR ->
+			self#read_tdr;
+		| AFR ->
+			self#read_afr;
+		| CLD ->
+			self#read_cld;
+		| END ->
+			self#read_end;
+		| ABD ->
+			self#read_abd;
+		| TDD ->
+			self#read_tdd;
+		| EOT ->
+			()
+		| EFR ->
+			self#read_efr;
+		| CFR ->
+			self#read_cfr;
+		| CFD ->
+			self#read_cfd;
+		| EFD ->
+			self#read_efd;
+		| AFD ->
+			self#read_afd;
+		| EOF ->
+			()
+		| EXD ->
+			self#read_exd;
+		| EOM ->
+			incr stats.modules_fully_restored;
+
+	method private read_chunk_data kind =
+		let path = String.concat "_" (ExtLib.String.nsplit (s_type_path mpath) ".") in
+		let id = ["hxb";"read";string_of_chunk_kind kind;path] in
+		let close = Timer.timer id in
+		self#read_chunk_data' kind;
+		close()
+
+	method read_chunks (new_api : hxb_reader_api) (chunks : cached_chunks) =
+		fst (self#read_chunks_until new_api chunks EOM)
+
+	method read_chunks_until (new_api : hxb_reader_api) (chunks : cached_chunks) end_chunk =
+		api <- new_api;
+		let rec loop = function
+			| (kind,data) :: chunks ->
+				ch <- BytesWithPosition.create data;
+				self#read_chunk_data kind;
+				if kind = end_chunk then chunks else loop chunks
+			| [] -> die "" __LOC__
+		in
+		let remaining = loop chunks in
+		(current_module, remaining)
+
+	method read (new_api : hxb_reader_api) (bytes : bytes) =
+		api <- new_api;
+		ch <- BytesWithPosition.create bytes;
+		if (Bytes.to_string (read_bytes ch 3)) <> "hxb" then
+			raise (HxbFailure "magic");
+		let version = read_byte ch in
+		if version <> hxb_version then
+			raise (HxbFailure (Printf.sprintf "version mismatch: hxb version %i, reader version %i" version hxb_version));
+		(fun end_chunk ->
+			let rec loop () =
+				let (name,size) = self#read_chunk_prefix in
+				let kind = chunk_kind_of_string name in
+				self#read_chunk_data kind;
+				if kind <> end_chunk then begin
+					loop()
+				end
+			in
+			loop();
+			current_module
+		)
+end

+ 12 - 0
src/compiler/hxb/hxbReaderApi.ml

@@ -0,0 +1,12 @@
+open Globals
+open Type
+
+class virtual hxb_reader_api = object(self)
+	method virtual make_module : path -> string -> module_def
+	method virtual add_module : module_def -> unit
+	method virtual resolve_type : string list -> string -> string -> module_type
+	method virtual resolve_module : path -> module_def
+	method virtual basic_types : basic_types
+	method virtual get_var_id : int -> int
+	method virtual read_expression_eagerly : tclass_field -> bool
+end

+ 2330 - 0
src/compiler/hxb/hxbWriter.ml

@@ -0,0 +1,2330 @@
+open Globals
+open Ast
+open Type
+open HxbData
+open Tanon_identification
+
+let rec binop_index op = match op with
+	| OpAdd -> 0
+	| OpMult -> 1
+	| OpDiv -> 2
+	| OpSub -> 3
+	| OpAssign -> 4
+	| OpEq -> 5
+	| OpNotEq -> 6
+	| OpGt -> 7
+	| OpGte -> 8
+	| OpLt -> 9
+	| OpLte -> 10
+	| OpAnd -> 11
+	| OpOr -> 12
+	| OpXor -> 13
+	| OpBoolAnd -> 14
+	| OpBoolOr -> 15
+	| OpShl -> 16
+	| OpShr -> 17
+	| OpUShr -> 18
+	| OpMod -> 19
+	| OpInterval -> 20
+	| OpArrow -> 21
+	| OpIn -> 22
+	| OpNullCoal -> 23
+	| OpAssignOp op -> 30 + binop_index op
+
+let unop_index op flag = match op,flag with
+	| Increment,Prefix -> 0
+	| Decrement,Prefix -> 1
+	| Not,Prefix -> 2
+	| Neg,Prefix -> 3
+	| NegBits,Prefix -> 4
+	| Spread,Prefix -> 5
+	| Increment,Postfix -> 6
+	| Decrement,Postfix -> 7
+	| Not,Postfix -> 8
+	| Neg,Postfix -> 9
+	| NegBits,Postfix -> 10
+	| Spread,Postfix -> 11
+
+type hxb_writer_stats = {
+	type_instance_kind_writes : int array;
+	texpr_writes : int array;
+	type_instance_immediate : int ref;
+	type_instance_cache_hits : int ref;
+	type_instance_cache_misses : int ref;
+	pos_writes_full : int ref;
+	pos_writes_min : int ref;
+	pos_writes_max : int ref;
+	pos_writes_minmax : int ref;
+	pos_writes_eq : int ref;
+	chunk_sizes : (string,int ref * int ref) Hashtbl.t;
+}
+
+let create_hxb_writer_stats () = {
+	type_instance_kind_writes = Array.make 255 0;
+	texpr_writes = Array.make 255 0;
+	type_instance_immediate = ref 0;
+	type_instance_cache_hits = ref 0;
+	type_instance_cache_misses = ref 0;
+	pos_writes_full = ref 0;
+	pos_writes_min = ref 0;
+	pos_writes_max = ref 0;
+	pos_writes_minmax = ref 0;
+	pos_writes_eq = ref 0;
+	chunk_sizes = Hashtbl.create 0;
+}
+
+let dump_stats name stats =
+	let sort_and_filter_array a =
+		let _,kind_writes = Array.fold_left (fun (index,acc) writes ->
+			(index + 1,if writes = 0 then acc else (index,writes) :: acc)
+		) (0,[]) a in
+		let kind_writes = List.sort (fun (_,writes1) (_,writes2) -> compare writes2 writes1) kind_writes in
+		List.map (fun (index,writes) -> Printf.sprintf "    %3i: %9i" index writes) kind_writes
+	in
+	let t_kind_writes = sort_and_filter_array stats.type_instance_kind_writes in
+	print_endline (Printf.sprintf "hxb_writer stats for %s" name);
+	print_endline "  type instance kind writes:";
+	List.iter print_endline t_kind_writes;
+	let texpr_writes = sort_and_filter_array stats.texpr_writes in
+	print_endline "  texpr writes:";
+	List.iter print_endline texpr_writes;
+
+	print_endline "  type instance writes:";
+	print_endline (Printf.sprintf "     immediate: %9i" !(stats.type_instance_immediate));
+	print_endline (Printf.sprintf "    cache hits: %9i" !(stats.type_instance_cache_hits));
+	print_endline (Printf.sprintf "    cache miss: %9i" !(stats.type_instance_cache_misses));
+	print_endline "  pos writes:";
+	print_endline (Printf.sprintf "      full: %9i\n       min: %9i\n       max: %9i\n    minmax: %9i\n     equal: %9i" !(stats.pos_writes_full) !(stats.pos_writes_min) !(stats.pos_writes_max) !(stats.pos_writes_minmax) !(stats.pos_writes_eq));
+	(* let chunk_sizes = Hashtbl.fold (fun name (imin,imax) acc -> (name,!imin,!imax) :: acc) stats.chunk_sizes [] in
+	let chunk_sizes = List.sort (fun (_,imin1,imax1) (_,imin2,imax2) -> compare imax1 imax2) chunk_sizes in
+	print_endline "chunk sizes:";
+	List.iter (fun (name,imin,imax) ->
+		print_endline (Printf.sprintf "    %s: %i - %i" name imin imax)
+	) chunk_sizes *)
+
+module StringHashtbl = Hashtbl.Make(struct
+	type t = string
+
+	let equal =
+		String.equal
+
+	let hash s =
+		(* What's the best here? *)
+		Hashtbl.hash s
+end)
+
+module StringPool = struct
+	type t = {
+		lut : int StringHashtbl.t;
+		items : string DynArray.t;
+		mutable closed : bool;
+	}
+
+	let create () = {
+		lut = StringHashtbl.create 16;
+		items = DynArray.create ();
+		closed = false;
+	}
+
+	let add sp s =
+		assert (not sp.closed);
+		let index = DynArray.length sp.items in
+		StringHashtbl.add sp.lut s index;
+		DynArray.add sp.items s;
+		index
+
+	let get sp s =
+		StringHashtbl.find sp.lut s
+
+	let get_or_add sp s =
+		try
+			get sp s
+		with Not_found ->
+			add sp s
+
+	let finalize sp =
+		assert (not sp.closed);
+		sp.closed <- true;
+		DynArray.to_list sp.items,DynArray.length sp.items
+end
+
+module Pool = struct
+	type ('key,'value) t = {
+		lut : ('key,int) Hashtbl.t;
+		items : 'value DynArray.t;
+		mutable closed : bool;
+	}
+
+	let create () = {
+		lut = Hashtbl.create 0;
+		items = DynArray.create ();
+		closed = false;
+	}
+
+	let add pool (key : 'key) (value : 'value) =
+		assert (not pool.closed);
+		let index = DynArray.length pool.items in
+		DynArray.add pool.items value;
+		Hashtbl.add pool.lut key index;
+		index
+
+	let get pool (key : 'key) =
+		Hashtbl.find pool.lut key
+
+	let extract pool (key : 'key) =
+		DynArray.get pool.items (get pool key)
+
+	let has pool (key : 'key) =
+		Hashtbl.mem pool.lut key
+
+	let get_or_add pool (key : 'key) (value : 'value) =
+		try
+			get pool key
+		with Not_found ->
+			add pool key value
+
+	let is_empty pool =
+		DynArray.length pool.items = 0
+
+	let advance pool dummy =
+		DynArray.add pool.items dummy
+
+	let finalize pool =
+		assert (not pool.closed);
+		pool.closed <- true;
+		pool.items
+end
+
+module IdentityPool = struct
+	type ('key,'value) t = {
+		items : ('key * 'value) DynArray.t;
+		mutable closed : bool;
+	}
+
+	let create () = {
+		items = DynArray.create ();
+		closed = false;
+	}
+
+	let add pool (key : 'key) (value : 'value) =
+		assert (not pool.closed);
+		let index = DynArray.length pool.items in
+		DynArray.add pool.items (key,value);
+		index
+
+	let get pool (key : 'key) =
+		DynArray.index_of (fun (key',_) -> key == key') pool.items
+
+	let get_or_add pool (key : 'key) (value : 'value) =
+		try
+			get pool key
+		with Not_found ->
+			add pool key value
+
+	let to_list pool =
+		DynArray.to_list pool.items
+
+	let finalize pool =
+		assert (not pool.closed);
+		pool.closed <- true;
+		pool.items
+
+	let length pool = DynArray.length pool.items
+end
+
+module HashedIdentityPool = struct
+	type ('hkey,'key,'value) t = {
+		lut : ('hkey,('key * int)) Hashtbl.t;
+		items : ('key * 'value) DynArray.t;
+		mutable closed : bool;
+	}
+
+	let create () = {
+		lut = Hashtbl.create 16;
+		items = DynArray.create ();
+		closed = false;
+	}
+
+	let add pool (hkey : 'hkey) (key : 'key) (value : 'value) =
+		assert (not pool.closed);
+		let index = DynArray.length pool.items in
+		DynArray.add pool.items (key,value);
+		Hashtbl.add pool.lut hkey (key,index);
+		index
+
+	let get pool (hkey : 'hkey) (key : 'key) =
+		let l = Hashtbl.find_all pool.lut hkey in
+		List.assq key l
+
+	let finalize pool =
+		assert (not pool.closed);
+		pool.closed <- true;
+		pool.items
+end
+
+module SimnBuffer = struct
+	type t = {
+		buffer_size : int;
+		mutable buffer : bytes;
+		mutable buffers : bytes Queue.t;
+		mutable offset : int;
+	}
+
+	let create buffer_size = {
+		buffer = Bytes.create buffer_size;
+		buffers = Queue.create ();
+		offset = 0;
+		buffer_size = buffer_size;
+	}
+
+	let reset sb =
+		sb.buffer <- Bytes.create sb.buffer_size;
+		sb.buffers <- Queue.create ();
+		sb.offset <- 0
+
+	let promote_buffer sb =
+		Queue.add sb.buffer sb.buffers;
+		sb.buffer <- Bytes.create sb.buffer_size;
+		sb.offset <- 0
+
+	let add_u8 sb i =
+		if sb.offset = sb.buffer_size then begin
+			(* Current buffer is full, promote it. *)
+			promote_buffer sb;
+			Bytes.unsafe_set sb.buffer 0 i;
+			sb.offset <- 1;
+		end else begin
+			(* There's room, put it in. *)
+			Bytes.unsafe_set sb.buffer sb.offset i;
+			sb.offset <- sb.offset + 1
+		end
+
+	let add_bytes sb bytes =
+		let rec loop offset left =
+			let space = sb.buffer_size - sb.offset in
+			if left > space then begin
+				(* We need more than we have. Blit as much as we can, promote buffer, recurse. *)
+				Bytes.unsafe_blit bytes offset sb.buffer sb.offset space;
+				promote_buffer sb;
+				loop (offset + space) (left - space)
+			end else begin
+				(* It fits, blit it. *)
+				Bytes.unsafe_blit bytes offset sb.buffer sb.offset left;
+				sb.offset <- sb.offset + left;
+			end
+		in
+		loop 0 (Bytes.length bytes)
+
+	let contents sb =
+		let size = sb.offset + sb.buffer_size * Queue.length sb.buffers in
+		let out = Bytes.create size in
+		let offset = ref 0 in
+		(* We know that all sb.buffers are of sb.buffer_size length, so blit them together. *)
+		Queue.iter (fun bytes ->
+			Bytes.unsafe_blit bytes 0 out !offset sb.buffer_size;
+			offset := !offset + sb.buffer_size;
+		) sb.buffers;
+		(* Append our current buffer until sb.offset *)
+		Bytes.unsafe_blit sb.buffer 0 out !offset sb.offset;
+		out
+end
+
+module Chunk = struct
+	type t = {
+		kind : chunk_kind;
+		cp : StringPool.t;
+		ch : SimnBuffer.t;
+	}
+
+	let create kind cp initial_size = {
+		kind;
+		cp;
+		ch = SimnBuffer.create initial_size;
+	}
+
+	let reset chunk =
+		SimnBuffer.reset chunk.ch
+
+	let write_u8 io v =
+		SimnBuffer.add_u8 io.ch (Char.unsafe_chr v)
+
+	let write_i32 io v =
+		let base = Int32.to_int v in
+		let big = Int32.to_int (Int32.shift_right_logical v 24) in
+		write_u8 io base;
+		write_u8 io (base lsr 8);
+		write_u8 io (base lsr 16);
+		write_u8 io big
+
+	let write_i64 io v =
+		write_i32 io (Int64.to_int32 v);
+		write_i32 io (Int64.to_int32 (Int64.shift_right_logical v 32))
+
+	let write_f64 io v =
+		write_i64 io (Int64.bits_of_float v)
+
+	let write_bytes io b =
+		SimnBuffer.add_bytes io.ch b
+
+	let write_ui16 io i =
+		write_u8 io i;
+		write_u8 io (i lsr 8)
+
+	let get_bytes io =
+		SimnBuffer.contents io.ch
+
+	let rec write_uleb128 io v =
+		let b = v land 0x7F in
+		let rest = v lsr 7 in
+		if rest = 0 then
+			write_u8 io b
+		else begin
+			write_u8 io (b lor 0x80);
+			write_uleb128 io rest
+		end
+
+	let rec write_leb128 io v =
+		let b = v land 0x7F in
+		let rest = v asr 7 in
+		if (rest = 0 && (b land 0x40 = 0)) || (rest = -1 && (b land 0x40 = 0x40)) then
+			write_u8 io b
+		else begin
+			write_u8 io (b lor 0x80);
+			write_leb128 io rest
+		end
+
+	let write_bytes_length_prefixed io b =
+		write_uleb128 io (Bytes.length b);
+		write_bytes io b
+
+	let write_bool io b =
+		write_u8 io (if b then 1 else 0)
+
+	let export : 'a . hxb_writer_stats -> t -> 'a IO.output -> unit = fun stats io chex ->
+		let bytes = get_bytes io in
+		let length = Bytes.length bytes in
+		write_chunk_prefix io.kind length chex;
+		(* begin try
+			let (imin,imax) = Hashtbl.find stats.chunk_sizes io.name in
+			if length < !imin then imin := length;
+			if length > !imax then imax := length
+		with Not_found ->
+			Hashtbl.add stats.chunk_sizes io.name (ref length,ref length);
+		end; *)
+		IO.nwrite chex bytes
+
+	let write_string chunk s =
+		write_uleb128 chunk (StringPool.get_or_add chunk.cp s)
+
+	let write_list : 'b . t -> 'b list -> ('b -> unit) -> unit = fun chunk l f ->
+		write_uleb128 chunk (List.length l);
+		List.iter f l
+
+	let write_dynarray chunk d f =
+		write_uleb128 chunk (DynArray.length d);
+		DynArray.iter f d
+
+	let write_option : 'b . t -> 'b option -> ('b -> unit) -> unit = fun chunk v f -> match v with
+	| None ->
+		write_u8 chunk 0
+	| Some v ->
+		write_u8 chunk 1;
+		f v
+
+	let export_data chunk_from chunk_to =
+		let bytes = get_bytes chunk_from in
+		write_bytes chunk_to bytes
+end
+
+module PosWriter = struct
+	type t = {
+		stats : hxb_writer_stats;
+		mutable p_file : string;
+		mutable p_min : int;
+		mutable p_max : int;
+	}
+
+	let do_write_pos (chunk : Chunk.t) (p : pos) =
+		(* incr stats.pos_writes_full; *)
+		Chunk.write_string chunk p.pfile;
+		Chunk.write_leb128 chunk p.pmin;
+		Chunk.write_leb128 chunk p.pmax
+
+	let create stats chunk p =
+		do_write_pos chunk p;
+	{
+		stats;
+		p_file = p.pfile;
+		p_min = p.pmin;
+		p_max = p.pmax;
+	}
+
+	let write_pos pw (chunk : Chunk.t) (write_equal : bool) (offset : int) (p : pos) =
+		if p.pfile != pw.p_file then begin
+			(* File changed, write full pos *)
+			Chunk.write_u8 chunk (4 + offset);
+			do_write_pos chunk p;
+			pw.p_file <- p.pfile;
+			pw.p_min <- p.pmin;
+			pw.p_max <- p.pmax;
+		end else if p.pmin <> pw.p_min then begin
+			if p.pmax <> pw.p_max then begin
+				(* pmin and pmax changed *)
+				(* incr stats.pos_writes_minmax; *)
+				Chunk.write_u8 chunk (3 + offset);
+				Chunk.write_leb128 chunk p.pmin;
+				Chunk.write_leb128 chunk p.pmax;
+				pw.p_min <- p.pmin;
+				pw.p_max <- p.pmax;
+			end else begin
+				(* pmin changed *)
+				(* incr stats.pos_writes_min; *)
+				Chunk.write_u8 chunk (1 + offset);
+				Chunk.write_leb128 chunk p.pmin;
+				pw.p_min <- p.pmin;
+			end
+		end else if p.pmax <> pw.p_max then begin
+			(* pmax changed *)
+			(* incr stats.pos_writes_max; *)
+			Chunk.write_u8 chunk (2 + offset);
+			Chunk.write_leb128 chunk p.pmax;
+			pw.p_max <- p.pmax;
+		end else begin
+			(* incr stats.pos_writes_eq; *)
+			if write_equal then
+				Chunk.write_u8 chunk offset;
+		end
+end
+
+type field_writer_context = {
+	t_pool : StringPool.t;
+	pos_writer : PosWriter.t;
+	mutable texpr_this : texpr option;
+	vars : (tvar * int) DynArray.t;
+}
+
+let create_field_writer_context pos_writer = {
+	t_pool = StringPool.create ();
+	pos_writer = pos_writer;
+	texpr_this = None;
+	vars = DynArray.create ();
+}
+
+type hxb_writer = {
+	warn : Warning.warning -> string -> Globals.pos -> unit;
+	anon_id : Type.t Tanon_identification.tanon_identification;
+	stats : hxb_writer_stats;
+	mutable current_module : module_def;
+	chunks : Chunk.t DynArray.t;
+	cp : StringPool.t;
+	docs : StringPool.t;
+	mutable chunk : Chunk.t;
+
+	classes : (path,tclass) Pool.t;
+	enums : (path,tenum) Pool.t;
+	typedefs : (path,tdef) Pool.t;
+	abstracts : (path,tabstract) Pool.t;
+	anons : (path,tanon) Pool.t;
+	anon_fields : (string,tclass_field,unit) HashedIdentityPool.t;
+	tmonos : (tmono,unit) IdentityPool.t;
+
+	own_classes : (path,tclass) Pool.t;
+	own_enums : (path,tenum) Pool.t;
+	own_typedefs : (path,tdef) Pool.t;
+	own_abstracts : (path,tabstract) Pool.t;
+	type_param_lut : (path,(string,typed_type_param) Pool.t) Pool.t;
+	class_fields : (string,tclass_field,(tclass * class_field_ref_kind * int)) HashedIdentityPool.t;
+	enum_fields : ((path * string),(tenum * tenum_field)) Pool.t;
+	mutable type_type_parameters : (string,typed_type_param) Pool.t;
+	mutable field_type_parameters : (typed_type_param,unit) IdentityPool.t;
+	mutable local_type_parameters : (typed_type_param,unit) IdentityPool.t;
+	mutable field_stack : unit list;
+	unbound_ttp : (typed_type_param,unit) IdentityPool.t;
+	t_instance_chunk : Chunk.t;
+}
+
+module HxbWriter = struct
+	let in_nested_scope writer = match writer.field_stack with
+		| [] -> false (* can happen for cl_init and in EXD *)
+		| [_] -> false
+		| _ -> true
+
+	(* Chunks *)
+
+	let start_chunk writer (kind : chunk_kind) =
+		let initial_size = match kind with
+			| EOT | EOF | EOM -> 0
+			| MDF -> 16
+			| MTF | MDR | CLR | END | ABD | ENR | ABR | TDR | EFR | CFR | AFD -> 64
+			| AFR | CLD | TDD | EFD -> 128
+			| STR | DOC -> 256
+			| CFD | EXD -> 512
+		in
+		let new_chunk = Chunk.create kind writer.cp initial_size in
+		DynArray.add writer.chunks new_chunk;
+		writer.chunk <- new_chunk
+
+	let start_temporary_chunk : 'a . hxb_writer -> int -> (Chunk.t -> 'a) -> 'a = fun writer initial_size ->
+		let new_chunk = Chunk.create EOM (* TODO: something else? *) writer.cp initial_size in
+		let old_chunk = writer.chunk in
+		writer.chunk <- new_chunk;
+		(fun f ->
+			writer.chunk <- old_chunk;
+			f new_chunk
+		)
+
+	let write_inlined_list : 'a . hxb_writer -> int -> int -> (int -> unit) -> (unit -> unit) -> ('a -> unit) -> 'a list -> unit
+		= fun writer offset max f_byte f_first f_elt l ->
+		let length = List.length l in
+		if length > max then begin
+			f_byte (offset + 9);
+			f_first ();
+			Chunk.write_list writer.chunk l f_elt
+		end else begin
+			f_byte (offset + length);
+			f_first();
+			List.iter (fun elt ->
+				f_elt elt
+			) l
+		end
+
+	(* Basic compounds *)
+
+	let write_path writer (path : path) =
+		Chunk.write_list writer.chunk (fst path) (Chunk.write_string writer.chunk);
+		Chunk.write_string writer.chunk (snd path)
+
+	let write_full_path writer (pack : string list) (mname : string) (tname : string) =
+		Chunk.write_list writer.chunk pack (Chunk.write_string writer.chunk);
+		if mname = "" || tname = "" then
+			die (Printf.sprintf "write_full_path: pack = %s, mname = %s, tname = %s" (String.concat "." pack) mname tname) __LOC__;
+		Chunk.write_string writer.chunk mname;
+		Chunk.write_string writer.chunk tname
+
+	let write_documentation writer (doc : doc_block) =
+		Chunk.write_option writer.chunk doc.doc_own (fun s ->
+			Chunk.write_uleb128 writer.chunk (StringPool.get_or_add writer.docs s)
+		);
+		Chunk.write_list writer.chunk doc.doc_inherited (fun s ->
+			Chunk.write_uleb128 writer.chunk (StringPool.get_or_add writer.docs s)
+		)
+
+	let write_pos writer (p : pos) =
+		Chunk.write_string writer.chunk p.pfile;
+		Chunk.write_leb128 writer.chunk p.pmin;
+		Chunk.write_leb128 writer.chunk p.pmax
+
+	let write_pos_pair writer (p1 : pos) (p2 : pos) =
+		(* Write second position offset relative to first position's pmin, which is often within 1 byte range. *)
+		Chunk.write_string writer.chunk p1.pfile;
+		Chunk.write_leb128 writer.chunk p1.pmin;
+		Chunk.write_leb128 writer.chunk p1.pmax;
+		Chunk.write_leb128 writer.chunk (p2.pmin - p1.pmin);
+		Chunk.write_leb128 writer.chunk (p2.pmax - p1.pmin)
+
+	let rec write_metadata_entry writer ((meta,el,p) : metadata_entry) =
+		Chunk.write_string writer.chunk (Meta.to_string meta);
+		write_pos writer p;
+		Chunk.write_list writer.chunk el (write_expr writer)
+
+	and write_metadata writer ml =
+		Chunk.write_list writer.chunk ml (write_metadata_entry writer)
+
+	(* expr *)
+
+	and write_object_field_key writer (n,p,qs) =
+		Chunk.write_string writer.chunk n;
+		write_pos writer p;
+		begin match qs with
+			| NoQuotes -> Chunk.write_u8 writer.chunk 0
+			| DoubleQuotes -> Chunk.write_u8 writer.chunk 1
+		end
+
+	and write_type_path writer tp =
+		Chunk.write_list writer.chunk tp.tpackage (Chunk.write_string writer.chunk);
+		Chunk.write_string writer.chunk tp.tname;
+		Chunk.write_list writer.chunk tp.tparams (write_type_param_or_const writer);
+		Chunk.write_option writer.chunk tp.tsub (Chunk.write_string writer.chunk)
+
+	and write_placed_type_path writer ptp =
+		write_type_path writer ptp.path;
+		write_pos_pair writer ptp.pos_full ptp.pos_path
+
+	and write_type_param_or_const writer = function
+		| TPType th ->
+			Chunk.write_u8 writer.chunk 0;
+			write_type_hint writer th
+		| TPExpr e ->
+			Chunk.write_u8 writer.chunk 1;
+			write_expr writer e
+
+	and write_complex_type writer = function
+		| CTPath tp ->
+			Chunk.write_u8 writer.chunk 0;
+			write_placed_type_path writer tp
+		| CTFunction(thl,th) ->
+			Chunk.write_u8 writer.chunk 1;
+			Chunk.write_list writer.chunk thl (write_type_hint writer);
+			write_type_hint writer th
+		| CTAnonymous cffl ->
+			Chunk.write_u8 writer.chunk 2;
+			Chunk.write_list writer.chunk cffl (write_cfield writer);
+		| CTParent th ->
+			Chunk.write_u8 writer.chunk 3;
+			write_type_hint writer th
+		| CTExtend(ptp,cffl) ->
+			Chunk.write_u8 writer.chunk 4;
+			Chunk.write_list writer.chunk ptp (write_placed_type_path writer);
+			Chunk.write_list writer.chunk cffl (write_cfield writer);
+		| CTOptional th ->
+			Chunk.write_u8 writer.chunk 5;
+			write_type_hint writer th
+		| CTNamed(pn,th) ->
+			Chunk.write_u8 writer.chunk 6;
+			write_placed_name writer pn;
+			write_type_hint writer th
+		| CTIntersection(thl) ->
+			Chunk.write_u8 writer.chunk 7;
+			Chunk.write_list writer.chunk thl (write_type_hint writer)
+
+	and write_type_hint writer (ct,p) =
+		write_complex_type writer ct;
+		write_pos writer p
+
+	and write_type_param writer tp =
+		write_placed_name writer tp.tp_name;
+		Chunk.write_list writer.chunk tp.tp_params (write_type_param writer);
+		Chunk.write_option writer.chunk tp.tp_constraints (write_type_hint writer);
+		Chunk.write_option writer.chunk tp.tp_default (write_type_hint writer);
+		Chunk.write_list writer.chunk tp.tp_meta (write_metadata_entry writer)
+
+	and write_func_arg writer (pn,b,meta,tho,eo) =
+		write_placed_name writer pn;
+		Chunk.write_bool writer.chunk b;
+		write_metadata writer meta;
+		Chunk.write_option writer.chunk tho (write_type_hint writer);
+		Chunk.write_option writer.chunk eo (write_expr writer);
+
+	and write_func writer f =
+		Chunk.write_list writer.chunk f.f_params (write_type_param writer);
+		Chunk.write_list writer.chunk f.f_args (write_func_arg writer);
+		Chunk.write_option writer.chunk f.f_type (write_type_hint writer);
+		Chunk.write_option writer.chunk f.f_expr (write_expr writer)
+
+	and write_placed_name writer (s,p) =
+		Chunk.write_string writer.chunk s;
+		write_pos writer p
+
+	and write_access writer ac =
+		let i = match ac with
+		| APublic -> 0
+		| APrivate -> 1
+		| AStatic -> 2
+		| AOverride -> 3
+		| ADynamic -> 4
+		| AInline -> 5
+		| AMacro -> 6
+		| AFinal -> 7
+		| AExtern -> 8
+		| AAbstract -> 9
+		| AOverload -> 10
+		| AEnum -> 11
+		in
+		Chunk.write_u8 writer.chunk i
+
+	and write_placed_access writer (ac,p) =
+		write_access writer ac;
+		write_pos writer p
+
+	and write_cfield_kind writer = function
+		| FVar(tho,eo) ->
+			Chunk.write_u8 writer.chunk 0;
+			Chunk.write_option writer.chunk tho (write_type_hint writer);
+			Chunk.write_option writer.chunk eo (write_expr writer);
+		| FFun f ->
+			Chunk.write_u8 writer.chunk 1;
+			write_func writer f;
+		| FProp(pn1,pn2,tho,eo) ->
+			Chunk.write_u8 writer.chunk 2;
+			write_placed_name writer pn1;
+			write_placed_name writer pn2;
+			Chunk.write_option writer.chunk tho (write_type_hint writer);
+			Chunk.write_option writer.chunk eo (write_expr writer)
+
+	and write_cfield writer cff =
+		write_placed_name writer cff.cff_name;
+		Chunk.write_option writer.chunk cff.cff_doc (write_documentation writer);
+		write_pos writer cff.cff_pos;
+		write_metadata writer cff.cff_meta;
+		Chunk.write_list writer.chunk cff.cff_access (write_placed_access writer);
+		write_cfield_kind writer cff.cff_kind
+
+	and write_expr writer (e,p) =
+		write_pos writer p;
+		match e with
+		| EConst (Int (s, suffix)) ->
+			Chunk.write_u8 writer.chunk 0;
+			Chunk.write_string writer.chunk s;
+			Chunk.write_option writer.chunk suffix (Chunk.write_string writer.chunk);
+		| EConst (Float (s, suffix)) ->
+			Chunk.write_u8 writer.chunk 1;
+			Chunk.write_string writer.chunk s;
+			Chunk.write_option writer.chunk suffix (Chunk.write_string writer.chunk);
+		| EConst (String (s,qs)) ->
+			Chunk.write_u8 writer.chunk 2;
+			Chunk.write_string writer.chunk s;
+			begin match qs with
+			| SDoubleQuotes -> Chunk.write_u8 writer.chunk 0;
+			| SSingleQuotes -> Chunk.write_u8 writer.chunk 1;
+			end
+		| EConst (Ident s) ->
+			Chunk.write_u8 writer.chunk 3;
+			Chunk.write_string writer.chunk s;
+		| EConst (Regexp(s1,s2)) ->
+			Chunk.write_u8 writer.chunk 4;
+			Chunk.write_string writer.chunk s1;
+			Chunk.write_string writer.chunk s2;
+		| EArray(e1,e2) ->
+			Chunk.write_u8 writer.chunk 5;
+			write_expr writer e1;
+			write_expr writer e2;
+		| EBinop(op,e1,e2) ->
+			Chunk.write_u8 writer.chunk 6;
+			Chunk.write_u8 writer.chunk (binop_index op);
+			write_expr writer e1;
+			write_expr writer e2;
+		| EField(e1,s,kind) ->
+			Chunk.write_u8 writer.chunk 7;
+			write_expr writer e1;
+			Chunk.write_string writer.chunk s;
+			begin match kind with
+			| EFNormal -> Chunk.write_u8 writer.chunk 0;
+			| EFSafe -> Chunk.write_u8 writer.chunk 1;
+			end
+		| EParenthesis e1 ->
+			Chunk.write_u8 writer.chunk 8;
+			write_expr writer e1;
+		| EObjectDecl fl ->
+			Chunk.write_u8 writer.chunk 9;
+			let write_field (k,e1) =
+				write_object_field_key writer k;
+				write_expr writer e1
+			in
+			Chunk.write_list writer.chunk fl write_field;
+		| EArrayDecl el ->
+			Chunk.write_u8 writer.chunk 10;
+			Chunk.write_list writer.chunk el (write_expr writer);
+		| ECall(e1,el) ->
+			Chunk.write_u8 writer.chunk 11;
+			write_expr writer e1;
+			Chunk.write_list writer.chunk el (write_expr writer)
+		| ENew(ptp,el) ->
+			Chunk.write_u8 writer.chunk 12;
+			write_placed_type_path writer ptp;
+			Chunk.write_list writer.chunk el (write_expr writer);
+		| EUnop(op,flag,e1) ->
+			Chunk.write_u8 writer.chunk 13;
+			Chunk.write_u8 writer.chunk (unop_index op flag);
+			write_expr writer e1;
+		| EVars vl ->
+			Chunk.write_u8 writer.chunk 14;
+			let write_var v =
+				write_placed_name writer v.ev_name;
+				Chunk.write_bool writer.chunk v.ev_final;
+				Chunk.write_bool writer.chunk v.ev_static;
+				Chunk.write_option writer.chunk v.ev_type (write_type_hint writer);
+				Chunk.write_option writer.chunk v.ev_expr (write_expr writer);
+				write_metadata writer v.ev_meta;
+			in
+			Chunk.write_list writer.chunk vl write_var
+		| EFunction(fk,f) ->
+			Chunk.write_u8 writer.chunk 15;
+			begin match fk with
+			| FKAnonymous -> Chunk.write_u8 writer.chunk 0;
+			| FKNamed (pn,inline) ->
+				Chunk.write_u8 writer.chunk 1;
+				write_placed_name writer pn;
+				Chunk.write_bool writer.chunk inline;
+			| FKArrow -> Chunk.write_u8 writer.chunk 2;
+			end;
+			write_func writer f;
+		| EBlock el ->
+			Chunk.write_u8 writer.chunk 16;
+			Chunk.write_list writer.chunk el (write_expr writer)
+		| EFor(e1,e2) ->
+			Chunk.write_u8 writer.chunk 17;
+			write_expr writer e1;
+			write_expr writer e2;
+		| EIf(e1,e2,None) ->
+			Chunk.write_u8 writer.chunk 18;
+			write_expr writer e1;
+			write_expr writer e2;
+		| EIf(e1,e2,Some e3) ->
+			Chunk.write_u8 writer.chunk 19;
+			write_expr writer e1;
+			write_expr writer e2;
+			write_expr writer e3;
+		| EWhile(e1,e2,NormalWhile) ->
+			Chunk.write_u8 writer.chunk 20;
+			write_expr writer e1;
+			write_expr writer e2;
+		| EWhile(e1,e2,DoWhile) ->
+			Chunk.write_u8 writer.chunk 21;
+			write_expr writer e1;
+			write_expr writer e2;
+		| ESwitch(e1,cases,def) ->
+			Chunk.write_u8 writer.chunk 22;
+			write_expr writer e1;
+			let write_case (el,eg,eo,p) =
+				Chunk.write_list writer.chunk el (write_expr writer);
+				Chunk.write_option writer.chunk eg (write_expr writer);
+				Chunk.write_option writer.chunk eo (write_expr writer);
+				write_pos writer p;
+			in
+			Chunk.write_list writer.chunk cases write_case;
+			let write_default (eo,p) =
+				Chunk.write_option writer.chunk eo (write_expr writer);
+				write_pos writer p
+			in
+			Chunk.write_option writer.chunk def write_default;
+		| ETry(e1,catches) ->
+			Chunk.write_u8 writer.chunk 23;
+			write_expr writer e1;
+			let write_catch (pn,th,e,p) =
+				write_placed_name writer pn;
+				Chunk.write_option writer.chunk th (write_type_hint writer);
+				write_expr writer e;
+				write_pos writer p;
+			in
+			Chunk.write_list writer.chunk catches write_catch;
+		| EReturn None ->
+			Chunk.write_u8 writer.chunk 24;
+		| EReturn (Some e1) ->
+			Chunk.write_u8 writer.chunk 25;
+			write_expr writer e1;
+		| EBreak ->
+			Chunk.write_u8 writer.chunk 26;
+		| EContinue ->
+			Chunk.write_u8 writer.chunk 27;
+		| EUntyped e1 ->
+			Chunk.write_u8 writer.chunk 28;
+			write_expr writer e1;
+		| EThrow e1 ->
+			Chunk.write_u8 writer.chunk 29;
+			write_expr writer e1;
+		| ECast(e1,None) ->
+			Chunk.write_u8 writer.chunk 30;
+			write_expr writer e1;
+		| ECast(e1,Some th) ->
+			Chunk.write_u8 writer.chunk 31;
+			write_expr writer e1;
+			write_type_hint writer th;
+		| EIs(e1,th) ->
+			Chunk.write_u8 writer.chunk 32;
+			write_expr writer e1;
+			write_type_hint writer th;
+		| EDisplay(e1,dk) ->
+			Chunk.write_u8 writer.chunk 33;
+			write_expr writer e1;
+			begin match dk with
+			| DKCall -> Chunk.write_u8 writer.chunk 0;
+			| DKDot -> Chunk.write_u8 writer.chunk 1;
+			| DKStructure -> Chunk.write_u8 writer.chunk 2;
+			| DKMarked -> Chunk.write_u8 writer.chunk 3;
+			| DKPattern b ->
+				Chunk.write_u8 writer.chunk 4;
+				Chunk.write_bool writer.chunk b;
+			end
+		| ETernary(e1,e2,e3) ->
+			Chunk.write_u8 writer.chunk 34;
+			write_expr writer e1;
+			write_expr writer e2;
+			write_expr writer e3;
+		| ECheckType(e1,th) ->
+			Chunk.write_u8 writer.chunk 35;
+			write_expr writer e1;
+			write_type_hint writer th;
+		| EMeta(m,e1) ->
+			Chunk.write_u8 writer.chunk 36;
+			write_metadata_entry writer m;
+			write_expr writer e1
+
+	(* References *)
+
+	let write_class_ref writer (c : tclass) =
+		let i = Pool.get_or_add writer.classes c.cl_path c in
+		Chunk.write_uleb128 writer.chunk i
+
+	let write_enum_ref writer (en : tenum) =
+		let i = Pool.get_or_add writer.enums en.e_path en in
+		Chunk.write_uleb128 writer.chunk i
+
+	let write_typedef_ref writer (td : tdef) =
+		let i = Pool.get_or_add writer.typedefs td.t_path td in
+		Chunk.write_uleb128 writer.chunk i
+
+	let write_abstract_ref writer (a : tabstract) =
+		let i = Pool.get_or_add writer.abstracts a.a_path a in
+		Chunk.write_uleb128 writer.chunk i
+
+	let write_tmono_ref writer (mono : tmono) =
+		let index = IdentityPool.get_or_add writer.tmonos mono () in
+		Chunk.write_uleb128 writer.chunk index
+
+	let write_field_ref writer (c : tclass) (kind : class_field_ref_kind)  (cf : tclass_field) =
+		let index = try
+			HashedIdentityPool.get writer.class_fields cf.cf_name cf
+		with Not_found ->
+			let find_overload c cf_base =
+				let rec loop depth cfl = match cfl with
+					| cf' :: cfl ->
+						if cf' == cf then
+							Some(c,depth)
+						else
+							loop (depth + 1) cfl
+					| [] ->
+						None
+				in
+				let cfl = cf_base :: cf_base.cf_overloads in
+				loop 0 cfl
+			in
+			let find_overload c =
+				try
+					find_overload c (find_field c cf.cf_name kind)
+				with Not_found ->
+					None
+			in
+			let r = match kind with
+				| CfrStatic | CfrConstructor ->
+					find_overload c;
+				| CfrInit ->
+					Some(c,0)
+				| CfrMember ->
+					(* For member overloads we need to find the correct class, which is a mess. *)
+					let rec loop c = match find_overload c with
+						| Some _ as r ->
+							r
+						| None ->
+							if has_class_flag c CInterface then
+								let rec loopi l = match l with
+									| [] ->
+										None
+									| (c,_) :: l ->
+										match loop c with
+										| Some _ as r ->
+											r
+										| None ->
+											loopi l
+								in
+								loopi c.cl_implements
+							else match c.cl_super with
+								| Some(c,_) ->
+									loop c
+								| None ->
+									None
+					in
+					loop c;
+			in
+			let c,depth = match r with
+				| None ->
+					print_endline (Printf.sprintf "Could not resolve %s overload for %s on %s" (s_class_field_ref_kind kind) cf.cf_name (s_type_path c.cl_path));
+					c,0
+				| Some(c,depth) ->
+					c,depth
+			in
+			HashedIdentityPool.add writer.class_fields cf.cf_name cf (c,kind,depth)
+		in
+		Chunk.write_uleb128 writer.chunk index
+
+	let write_enum_field_ref writer (en : tenum) (ef : tenum_field) =
+		let key = (en.e_path,ef.ef_name) in
+		try
+			Chunk.write_uleb128 writer.chunk (Pool.get writer.enum_fields key)
+		with Not_found ->
+			ignore(Pool.get_or_add writer.enums en.e_path en);
+			Chunk.write_uleb128 writer.chunk (Pool.add writer.enum_fields key (en,ef))
+
+	let write_var_kind writer vk =
+		let b = match vk with
+			| VUser TVOLocalVariable -> 0
+			| VUser TVOArgument -> 1
+			| VUser TVOForVariable -> 2
+			| VUser TVOPatternVariable -> 3
+			| VUser TVOCatchVariable -> 4
+			| VUser TVOLocalFunction -> 5
+			| VGenerated -> 6
+			| VInlined -> 7
+			| VInlinedConstructorVariable -> 8
+			| VExtractorVariable -> 9
+			| VAbstractThis -> 10
+		in
+		Chunk.write_u8 writer.chunk b
+
+	let write_var writer fctx v =
+		Chunk.write_uleb128 writer.chunk v.v_id;
+		Chunk.write_string writer.chunk v.v_name;
+		write_var_kind writer v.v_kind;
+		Chunk.write_uleb128 writer.chunk v.v_flags;
+		write_metadata writer v.v_meta;
+		write_pos writer v.v_pos
+
+	let rec write_anon writer (an : tanon) (ttp : type_params) =
+		let write_fields () =
+			let restore = start_temporary_chunk writer 256 in
+			let i = ref 0 in
+			PMap.iter (fun _ cf ->
+				write_anon_field_ref writer cf;
+				incr i;
+			) an.a_fields;
+			let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in
+			Chunk.write_uleb128 writer.chunk !i;
+			Chunk.write_bytes writer.chunk bytes;
+		in
+		begin match !(an.a_status) with
+		| Closed ->
+			Chunk.write_u8 writer.chunk 0;
+			write_fields ()
+		| Const ->
+			Chunk.write_u8 writer.chunk 1;
+			write_fields ()
+		| Extend tl ->
+			Chunk.write_u8 writer.chunk 2;
+			write_types writer tl;
+			write_fields ()
+		| ClassStatics _ ->
+			assert false
+		| EnumStatics _ ->
+			assert false
+		| AbstractStatics _ ->
+			assert false
+		end
+
+	and write_anon_ref writer (an : tanon) (ttp : type_params) =
+		let pfm = Option.get (writer.anon_id#identify_anon ~strict:true an) in
+		try
+			let index = Pool.get writer.anons pfm.pfm_path in
+			Chunk.write_u8 writer.chunk 0;
+			Chunk.write_uleb128 writer.chunk index
+		with Not_found ->
+			let index = Pool.add writer.anons pfm.pfm_path an in
+			Chunk.write_u8 writer.chunk 1;
+			Chunk.write_uleb128 writer.chunk index;
+			write_anon writer an ttp
+
+	and write_anon_field_ref writer cf =
+		try
+			let index = HashedIdentityPool.get writer.anon_fields cf.cf_name cf in
+			Chunk.write_u8 writer.chunk 0;
+			Chunk.write_uleb128 writer.chunk index
+		with Not_found ->
+			let index = HashedIdentityPool.add writer.anon_fields cf.cf_name cf () in
+			Chunk.write_u8 writer.chunk 1;
+			Chunk.write_uleb128 writer.chunk index;
+			ignore(write_class_field_and_overloads_data writer true cf)
+
+	(* Type instances *)
+
+	and write_type_parameter_ref writer (ttp : typed_type_param) =
+		begin try
+			begin match ttp.ttp_host with
+			| TPHType ->
+				let i = Pool.get writer.type_type_parameters ttp.ttp_name in
+				Chunk.write_u8 writer.chunk 1;
+				Chunk.write_uleb128 writer.chunk i
+			| TPHMethod | TPHEnumConstructor | TPHAnonField | TPHConstructor ->
+				let i = IdentityPool.get writer.field_type_parameters ttp in
+				Chunk.write_u8 writer.chunk 2;
+				Chunk.write_uleb128 writer.chunk i;
+			| TPHLocal ->
+				let index = IdentityPool.get writer.local_type_parameters ttp in
+				Chunk.write_u8 writer.chunk 3;
+				Chunk.write_uleb128 writer.chunk index;
+		end with Not_found ->
+			(try ignore(IdentityPool.get writer.unbound_ttp ttp) with Not_found -> begin
+				ignore(IdentityPool.add writer.unbound_ttp ttp ());
+				let p = { null_pos with pfile = (Path.UniqueKey.lazy_path writer.current_module.m_extra.m_file) } in
+				let msg = Printf.sprintf "Unbound type parameter %s" (s_type_path ttp.ttp_class.cl_path) in
+				writer.warn WUnboundTypeParameter msg p
+			end);
+			Chunk.write_u8 writer.chunk 4; (* TDynamic None *)
+		end
+
+	(*
+		simple references:
+			0 - mono
+			1 -> type ttp
+			2 -> field ttp
+			3 -> local ttp
+			4 -> Dynamic
+
+		special references:
+			10 - class statics
+			11 - enum statics
+			12 - abstract statics
+			13 - KExpr
+
+		void functions:
+			20: () -> Void
+			21: (A) -> Void
+			22: (A, B) -> Void
+			23: (A, B, C) -> Void
+			24: (A, B, C) -> Void
+			29: (?) -> Void
+
+		non-void functions:
+			30: () -> T
+			31: (A) -> T
+			32: (A, B) -> T
+			33: (A, B, C) -> T
+			34: (A, B, C, D) -> T
+			39: (?) -> T
+
+		class:
+			40: C
+			41: C<A>
+			42: C<A, B>
+			49: C<?>
+
+		enum:
+			50: E
+			51: E<A>
+			52: E<A, B>
+			59: E<?>
+
+		typedef:
+			60: T
+			61: T<A>
+			62: T<A, B>
+			69: T<?>
+
+		abstract:
+			70: A
+			71: A<A>
+			72: A<A, B>
+			79: A<?>
+
+		anons:
+			80: {}
+			81: any anon
+			89: Dynamic<T>
+
+		concrete types:
+			100: Void
+			101: Int
+			102: Float
+			103: Bool
+			104: String
+	*)
+	and write_type_instance writer t =
+		let write_function_arg (n,o,t) =
+			Chunk.write_string writer.chunk n;
+			Chunk.write_bool writer.chunk o;
+			write_type_instance writer t;
+		in
+		let write_inlined_list offset max f_first f_elt l =
+			write_inlined_list writer offset max (Chunk.write_u8 writer.chunk) f_first f_elt l
+		in
+		match t with
+			| TAbstract ({a_path = ([],"Void")},[]) ->
+				Chunk.write_u8 writer.chunk 100;
+			| TAbstract ({a_path = ([],"Int")},[]) ->
+				Chunk.write_u8 writer.chunk 101;
+			| TAbstract ({a_path = ([],"Float")},[]) ->
+				Chunk.write_u8 writer.chunk 102;
+			| TAbstract ({a_path = ([],"Bool")},[]) ->
+				Chunk.write_u8 writer.chunk 103;
+			| TInst ({cl_path = ([],"String")},[]) ->
+				Chunk.write_u8 writer.chunk 104;
+			| TMono r ->
+				Monomorph.close r;
+				begin match r.tm_type with
+				| None ->
+					Chunk.write_u8 writer.chunk 0;
+					write_tmono_ref writer r;
+				| Some t ->
+					(* Don't write bound monomorphs, write underlying type directly *)
+					write_type_instance writer t
+				end
+			| TLazy f ->
+				write_type_instance writer (lazy_type f)
+			| TInst({cl_kind = KTypeParameter ttp},[]) ->
+				write_type_parameter_ref writer ttp;
+			| TInst({cl_kind = KExpr e},[]) ->
+				Chunk.write_u8 writer.chunk 13;
+				write_expr writer e;
+			| TInst(c,[]) ->
+				Chunk.write_u8 writer.chunk 40;
+				write_class_ref writer c;
+			| TEnum(en,[]) ->
+				Chunk.write_u8 writer.chunk 50;
+				write_enum_ref writer en;
+			| TType(td,[]) ->
+				let default () =
+					Chunk.write_u8 writer.chunk 60;
+					write_typedef_ref writer td;
+				in
+				begin match td.t_type with
+				| TAnon an ->
+					begin match !(an.a_status) with
+						| ClassStatics c ->
+							Chunk.write_u8 writer.chunk 10;
+							write_class_ref writer c
+						| EnumStatics en ->
+							Chunk.write_u8 writer.chunk 11;
+							write_enum_ref writer en;
+						| AbstractStatics a ->
+							Chunk.write_u8 writer.chunk 12;
+							write_abstract_ref writer a
+						| _ ->
+							default()
+					end
+				| _ ->
+					default()
+				end;
+			| TAbstract(a,[]) ->
+				Chunk.write_u8 writer.chunk 70;
+				write_abstract_ref writer a;
+			| TDynamic None ->
+				Chunk.write_u8 writer.chunk 4;
+			| TFun([],t) when ExtType.is_void (follow_lazy_and_mono t) ->
+				Chunk.write_u8 writer.chunk 20;
+			| TFun(args,t) when ExtType.is_void (follow_lazy_and_mono t) ->
+				write_inlined_list 20 4 (fun () -> ()) write_function_arg args;
+			| TFun(args,t) ->
+				write_inlined_list 30 4 (fun () -> ()) write_function_arg args;
+				write_type_instance writer t;
+			| TInst(c,tl) ->
+				write_inlined_list 40 2 (fun () -> write_class_ref writer c) (write_type_instance writer) tl;
+			| TEnum(en,tl) ->
+				write_inlined_list 50 2 (fun () -> write_enum_ref writer en) (write_type_instance writer) tl;
+			| TType(td,tl) ->
+				write_inlined_list 60 2 (fun () -> write_typedef_ref writer td) (write_type_instance writer) tl;
+			| TAbstract(a,tl) ->
+				write_inlined_list 70 2 (fun () -> write_abstract_ref writer a) (write_type_instance writer) tl;
+			| TAnon an when PMap.is_empty an.a_fields ->
+				Chunk.write_u8 writer.chunk 80;
+			| TAnon an ->
+				Chunk.write_u8 writer.chunk 81;
+				write_anon_ref writer an []
+			| TDynamic (Some t) ->
+				Chunk.write_u8 writer.chunk 89;
+				write_type_instance writer t
+
+	and write_types writer tl =
+		Chunk.write_list writer.chunk tl (write_type_instance writer)
+
+	(* texpr *)
+
+	and write_texpr_type_instance writer (fctx : field_writer_context) (t: Type.t) =
+		let old_chunk = writer.chunk in
+		writer.chunk <- writer.t_instance_chunk;
+		Chunk.reset writer.chunk;
+		write_type_instance writer t;
+		let t_bytes = Chunk.get_bytes writer.chunk in
+		writer.chunk <- old_chunk;
+		let index = StringPool.get_or_add fctx.t_pool (Bytes.unsafe_to_string t_bytes) in
+		Chunk.write_uleb128 writer.chunk index
+
+	and write_texpr writer (fctx : field_writer_context) (e : texpr) =
+		let declare_var v =
+			let index = if has_var_flag v VHxb then begin
+				(* Duplicate var declaration! Can happen when writing both cf_expr and cf_expr_unoptimized,
+				   although it arguably shouldn't. In this case we don't add the var again and instead write
+				   out the existing ID.*)
+				   v.v_id
+			end else begin
+				let index = DynArray.length fctx.vars in
+				DynArray.add fctx.vars (v,v.v_id);
+				(* Store local index in v_id so we find it easily for all the TLocal expressions.
+				   This is set back by the var writer in start_texpr. *)
+				v.v_id <- index;
+				add_var_flag v VHxb;
+				index;
+			end in
+			Chunk.write_uleb128 writer.chunk index;
+			Chunk.write_option writer.chunk v.v_extra (fun ve ->
+				Chunk.write_list writer.chunk ve.v_params (fun ttp ->
+					let index = IdentityPool.add writer.local_type_parameters ttp () in
+					Chunk.write_uleb128 writer.chunk index
+				);
+				Chunk.write_option writer.chunk ve.v_expr (write_texpr writer fctx);
+			);
+			write_type_instance writer v.v_type;
+		in
+		let rec loop e =
+			let write_type = match e.eexpr with
+			(* values 0-19 *)
+			| TConst ct ->
+				begin match ct with
+				| TNull ->
+					Chunk.write_u8 writer.chunk 0;
+					true
+				| TThis ->
+					fctx.texpr_this <- Some e;
+					Chunk.write_u8 writer.chunk 1;
+					false;
+				| TSuper ->
+					Chunk.write_u8 writer.chunk 2;
+					true;
+				| TBool false when (ExtType.is_bool (follow_lazy_and_mono e.etype)) ->
+					Chunk.write_u8 writer.chunk 3;
+					false;
+				| TBool true when (ExtType.is_bool (follow_lazy_and_mono e.etype)) ->
+					Chunk.write_u8 writer.chunk 4;
+					false;
+				| TInt i32 when (ExtType.is_int (follow_lazy_and_mono e.etype)) ->
+					Chunk.write_u8 writer.chunk 5;
+					Chunk.write_i32 writer.chunk i32;
+					false;
+				| TFloat f when (ExtType.is_float (follow_lazy_and_mono e.etype)) ->
+					Chunk.write_u8 writer.chunk 6;
+					Chunk.write_string writer.chunk f;
+					false;
+				| TString s when (ExtType.is_string (follow_lazy_and_mono e.etype)) ->
+					Chunk.write_u8 writer.chunk 7;
+					Chunk.write_string writer.chunk s;
+					false
+				| TBool false ->
+					Chunk.write_u8 writer.chunk 13;
+					true;
+				| TBool true ->
+					Chunk.write_u8 writer.chunk 14;
+					true;
+				| TInt i32 ->
+					Chunk.write_u8 writer.chunk 15;
+					Chunk.write_i32 writer.chunk i32;
+					true;
+				| TFloat f ->
+					Chunk.write_u8 writer.chunk 16;
+					Chunk.write_string writer.chunk f;
+					true;
+				| TString s ->
+					Chunk.write_u8 writer.chunk 17;
+					Chunk.write_string writer.chunk s;
+					true;
+				end
+			(* vars 20-29 *)
+			| TLocal v ->
+				Chunk.write_u8 writer.chunk 20;
+				Chunk.write_uleb128 writer.chunk v.v_id;
+				true; (* I think there are cases where v_type != etype *)
+			| TVar(v,None) ->
+				Chunk.write_u8 writer.chunk 21;
+				declare_var v;
+				false;
+			| TVar(v,Some e1) ->
+				Chunk.write_u8 writer.chunk 22;
+				declare_var v;
+				loop e1;
+				false;
+			(* blocks 30-49 *)
+			| TBlock [] ->
+				Chunk.write_u8 writer.chunk 30;
+				true;
+			| TBlock el ->
+				let restore = start_temporary_chunk writer 256 in
+				let i = ref 0 in
+				List.iter (fun e ->
+					incr i;
+					loop e;
+				) el;
+				let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in
+				let l = !i in
+				begin match l with
+				| 1 -> Chunk.write_u8 writer.chunk 31;
+				| 2 -> Chunk.write_u8 writer.chunk 32;
+				| 3 -> Chunk.write_u8 writer.chunk 33;
+				| 4 -> Chunk.write_u8 writer.chunk 34;
+				| 5 -> Chunk.write_u8 writer.chunk 35;
+				| _ ->
+					if l <= 0xFF then begin
+						Chunk.write_u8 writer.chunk 36;
+						Chunk.write_u8 writer.chunk l;
+					end else begin
+						Chunk.write_u8 writer.chunk 39;
+						Chunk.write_uleb128 writer.chunk l;
+					end;
+				end;
+				Chunk.write_bytes writer.chunk bytes;
+				true;
+			(* function 50-59 *)
+			| TFunction tf ->
+				Chunk.write_u8 writer.chunk 50;
+				Chunk.write_list writer.chunk tf.tf_args (fun (v,eo) ->
+					declare_var v;
+					Chunk.write_option writer.chunk eo loop;
+				);
+				write_type_instance writer tf.tf_type;
+				loop tf.tf_expr;
+				true;
+			(* texpr compounds 60-79 *)
+			| TArray(e1,e2) ->
+				Chunk.write_u8 writer.chunk 60;
+				loop e1;
+				loop e2;
+				true;
+			| TParenthesis e1 ->
+				Chunk.write_u8 writer.chunk 61;
+				loop e1;
+				false; (* surely this is always the nested type *)
+			| TArrayDecl el ->
+				Chunk.write_u8 writer.chunk 62;
+				loop_el el;
+				true;
+			| TObjectDecl fl ->
+				Chunk.write_u8 writer.chunk 63;
+				Chunk.write_list writer.chunk fl (fun ((name,p,qs),e) ->
+					Chunk.write_string writer.chunk name;
+					write_pos writer p;
+					begin match qs with
+					| NoQuotes -> Chunk.write_u8 writer.chunk 0;
+					| DoubleQuotes -> Chunk.write_u8 writer.chunk 1;
+					end;
+					loop e
+				);
+				true;
+			| TCall(e1,el) ->
+				write_inlined_list writer 70 4 (Chunk.write_u8 writer.chunk) (fun () -> loop e1) loop el;
+				true;
+			| TMeta(m,e1) ->
+				Chunk.write_u8 writer.chunk 65;
+				write_metadata_entry writer m;
+				loop e1;
+				true;
+			(* branching 80-89 *)
+			| TIf(e1,e2,None) ->
+				Chunk.write_u8 writer.chunk 80;
+				loop e1;
+				loop e2;
+				false;
+			| TIf(e1,e2,Some e3) ->
+				Chunk.write_u8 writer.chunk 81;
+				loop e1;
+				loop e2;
+				loop e3;
+				true;
+			| TSwitch s ->
+				Chunk.write_u8 writer.chunk 82;
+				loop s.switch_subject;
+				Chunk.write_list writer.chunk s.switch_cases (fun c ->
+					loop_el c.case_patterns;
+					loop c.case_expr;
+				);
+				Chunk.write_option writer.chunk s.switch_default loop;
+				true;
+			| TTry(e1,catches) ->
+				Chunk.write_u8 writer.chunk 83;
+				loop e1;
+				Chunk.write_list writer.chunk catches  (fun (v,e) ->
+					declare_var v;
+					loop e
+				);
+				true;
+			| TWhile(e1,e2,flag) ->
+				Chunk.write_u8 writer.chunk (if flag = NormalWhile then 84 else 85);
+				loop e1;
+				loop e2;
+				false;
+			| TFor(v,e1,e2) ->
+				Chunk.write_u8 writer.chunk 86;
+				declare_var v;
+				loop e1;
+				loop e2;
+				false;
+			(* control flow 90-99 *)
+			| TReturn None ->
+				Chunk.write_u8 writer.chunk 90;
+				true;
+			| TReturn (Some e1) ->
+				Chunk.write_u8 writer.chunk 91;
+				loop e1;
+				true;
+			| TContinue ->
+				Chunk.write_u8 writer.chunk 92;
+				true;
+			| TBreak ->
+				Chunk.write_u8 writer.chunk 93;
+				true;
+			| TThrow e1 ->
+				Chunk.write_u8 writer.chunk 94;
+				loop e1;
+				true;
+			(* access 100-119 *)
+			| TEnumIndex e1 ->
+				Chunk.write_u8 writer.chunk 100;
+				loop e1;
+				false;
+			| TEnumParameter(e1,ef,i) ->
+				Chunk.write_u8 writer.chunk 101;
+				loop e1;
+				let en = match follow ef.ef_type with
+					| TFun(_,tr) ->
+						begin match follow tr with
+							| TEnum(en,_) -> en
+							| _ -> die "" __LOC__
+						end
+					| _ ->
+						die "" __LOC__
+				in
+				write_enum_field_ref writer en ef;
+				Chunk.write_uleb128 writer.chunk i;
+				true;
+			| TField({eexpr = TConst TThis; epos = p1},FInstance(c,tl,cf)) when fctx.texpr_this <> None ->
+				Chunk.write_u8 writer.chunk 111;
+				PosWriter.write_pos fctx.pos_writer writer.chunk true 0 p1;
+				write_class_ref writer c;
+				write_types writer tl;
+				write_field_ref writer c CfrMember cf;
+				true;
+			| TField(e1,FInstance(c,tl,cf)) ->
+				Chunk.write_u8 writer.chunk 102;
+				loop e1;
+				write_class_ref writer c;
+				write_types writer tl;
+				write_field_ref writer c CfrMember cf;
+				true;
+			| TField({eexpr = TTypeExpr (TClassDecl c'); epos = p1},FStatic(c,cf)) when c == c' ->
+				Chunk.write_u8 writer.chunk 110;
+				PosWriter.write_pos fctx.pos_writer writer.chunk true 0 p1;
+				write_class_ref writer c;
+				write_field_ref writer c CfrStatic cf;
+				true;
+			| TField(e1,FStatic(c,cf)) ->
+				Chunk.write_u8 writer.chunk 103;
+				loop e1;
+				write_class_ref writer c;
+				write_field_ref writer c CfrStatic cf;
+				true;
+			| TField(e1,FAnon cf) ->
+				Chunk.write_u8 writer.chunk 104;
+				loop e1;
+				write_anon_field_ref writer cf;
+				true;
+			| TField(e1,FClosure(Some(c,tl),cf)) ->
+				Chunk.write_u8 writer.chunk 105;
+				loop e1;
+				write_class_ref writer c;
+				write_types writer tl;
+				write_field_ref writer c CfrMember cf;
+				true;
+			| TField(e1,FClosure(None,cf)) ->
+				Chunk.write_u8 writer.chunk 106;
+				loop e1;
+				write_anon_field_ref writer cf;
+				true;
+			| TField(e1,FEnum(en,ef)) ->
+				Chunk.write_u8 writer.chunk 107;
+				loop e1;
+				write_enum_ref writer en;
+				write_enum_field_ref writer en ef;
+				true;
+			| TField(e1,FDynamic s) ->
+				Chunk.write_u8 writer.chunk 108;
+				loop e1;
+				Chunk.write_string writer.chunk s;
+				true;
+			(* module types 120-139 *)
+			| TTypeExpr (TClassDecl ({cl_kind = KTypeParameter ttp})) ->
+				Chunk.write_u8 writer.chunk 128;
+				write_type_parameter_ref writer ttp;
+				true;
+			| TTypeExpr (TClassDecl c) ->
+				Chunk.write_u8 writer.chunk 120;
+				write_class_ref writer c;
+				false;
+			| TTypeExpr (TEnumDecl en) ->
+				Chunk.write_u8 writer.chunk 121;
+				write_enum_ref writer en;
+				false;
+			| TTypeExpr (TAbstractDecl a) ->
+				Chunk.write_u8 writer.chunk 122;
+				write_abstract_ref writer a;
+				true;
+			| TTypeExpr (TTypeDecl td) ->
+				Chunk.write_u8 writer.chunk 123;
+				write_typedef_ref writer td;
+				true;
+			| TCast(e1,None) ->
+				Chunk.write_u8 writer.chunk 124;
+				loop e1;
+				true;
+			| TCast(e1,Some md) ->
+				Chunk.write_u8 writer.chunk 125;
+				loop e1;
+				let infos = t_infos md in
+				let m = infos.mt_module in
+				write_full_path writer (fst m.m_path) (snd m.m_path) (snd infos.mt_path);
+				true;
+			| TNew(({cl_kind = KTypeParameter ttp}),tl,el) ->
+				Chunk.write_u8 writer.chunk 127;
+				write_type_parameter_ref writer ttp;
+				write_types writer tl;
+				loop_el el;
+				true;
+			| TNew(c,tl,el) ->
+				Chunk.write_u8 writer.chunk 126;
+				write_class_ref writer c;
+				write_types writer tl;
+				loop_el el;
+				true;
+			(* unops 140-159 *)
+			| TUnop(op,flag,e1) ->
+				Chunk.write_u8 writer.chunk (140 + unop_index op flag);
+				loop e1;
+				true;
+			(* binops 160-219 *)
+			| TBinop(op,e1,e2) ->
+				Chunk.write_u8 writer.chunk (160 + binop_index op);
+				loop e1;
+				loop e2;
+				true;
+			(* rest 250-254 *)
+			| TIdent s ->
+				Chunk.write_u8 writer.chunk 250;
+				Chunk.write_string writer.chunk s;
+				true;
+			in
+			if write_type then
+				write_texpr_type_instance writer fctx e.etype;
+			PosWriter.write_pos fctx.pos_writer writer.chunk true 0 e.epos;
+
+		and loop_el el =
+			Chunk.write_list writer.chunk el loop
+		in
+		loop e
+
+	and write_type_parameters_forward writer (ttps : typed_type_param list) =
+		let write_type_parameter_forward ttp =
+			write_path writer ttp.ttp_class.cl_path;
+			write_pos writer ttp.ttp_class.cl_name_pos;
+			let i = match ttp.ttp_host with
+				| TPHType -> 0
+				| TPHConstructor -> 1
+				| TPHMethod -> 2
+				| TPHEnumConstructor -> 3
+				| TPHAnonField -> 4
+				| TPHLocal -> 5
+			in
+			Chunk.write_u8 writer.chunk i
+		in
+		Chunk.write_list writer.chunk ttps write_type_parameter_forward
+
+	and write_type_parameters_data writer (ttps : typed_type_param list) =
+		let write_type_parameter_data ttp =
+			let c = ttp.ttp_class in
+			write_metadata writer c.cl_meta;
+			write_types writer (get_constraints ttp);
+			Chunk.write_option writer.chunk ttp.ttp_default (write_type_instance writer)
+		in
+		List.iter write_type_parameter_data ttps
+
+	and write_type_parameters writer (ttps : typed_type_param list) =
+		write_type_parameters_forward writer ttps;
+		write_type_parameters_data writer ttps;
+
+	(* Fields *)
+
+	and write_field_kind writer = function
+		| Method MethNormal -> Chunk.write_u8 writer.chunk 0;
+		| Method MethInline -> Chunk.write_u8 writer.chunk 1;
+		| Method MethDynamic -> Chunk.write_u8 writer.chunk 2;
+		| Method MethMacro -> Chunk.write_u8 writer.chunk 3;
+		(* normal read *)
+		| Var {v_read = AccNormal; v_write = AccNormal } -> Chunk.write_u8 writer.chunk 10
+		| Var {v_read = AccNormal; v_write = AccNo } -> Chunk.write_u8 writer.chunk 11
+		| Var {v_read = AccNormal; v_write = AccNever } -> Chunk.write_u8 writer.chunk 12
+		| Var {v_read = AccNormal; v_write = AccCtor } -> Chunk.write_u8 writer.chunk 13
+		| Var {v_read = AccNormal; v_write = AccCall } -> Chunk.write_u8 writer.chunk 14
+		(* inline read *)
+		| Var {v_read = AccInline; v_write = AccNever } -> Chunk.write_u8 writer.chunk 20
+		(* getter read *)
+		| Var {v_read = AccCall; v_write = AccNormal } -> Chunk.write_u8 writer.chunk 30
+		| Var {v_read = AccCall; v_write = AccNo } -> Chunk.write_u8 writer.chunk 31
+		| Var {v_read = AccCall; v_write = AccNever } -> Chunk.write_u8 writer.chunk 32
+		| Var {v_read = AccCall; v_write = AccCtor } -> Chunk.write_u8 writer.chunk 33
+		| Var {v_read = AccCall; v_write = AccCall } -> Chunk.write_u8 writer.chunk 34
+		(* weird/overlooked combinations *)
+		| Var {v_read = r;v_write = w } ->
+			Chunk.write_u8 writer.chunk 100;
+			let f = function
+				| AccNormal -> Chunk.write_u8 writer.chunk 0
+				| AccNo -> Chunk.write_u8 writer.chunk 1
+				| AccNever -> Chunk.write_u8 writer.chunk 2
+				| AccCtor -> Chunk.write_u8 writer.chunk 3
+				| AccCall -> Chunk.write_u8 writer.chunk 4
+				| AccInline -> Chunk.write_u8 writer.chunk 5
+				| AccRequire(s,so) ->
+					Chunk.write_u8 writer.chunk 6;
+					Chunk.write_string writer.chunk s;
+					Chunk.write_option writer.chunk so (Chunk.write_string writer.chunk)
+			in
+			f r;
+			f w
+
+	and open_field_scope writer (params : type_params) =
+		writer.field_stack <- () :: writer.field_stack;
+		let nested = in_nested_scope writer in
+		let old_field_params = writer.field_type_parameters in
+		let old_local_params = writer.local_type_parameters in
+		if not nested then begin
+			writer.local_type_parameters <- IdentityPool.create ();
+			writer.field_type_parameters <- IdentityPool.create ();
+		end;
+		List.iter (fun ttp ->
+			ignore(IdentityPool.add writer.field_type_parameters ttp ());
+		) params;
+		(fun () ->
+			writer.field_type_parameters <- old_field_params;
+			writer.local_type_parameters <- old_local_params;
+			writer.field_stack <- List.tl writer.field_stack
+		)
+
+	and write_class_field_forward writer cf =
+		Chunk.write_string writer.chunk cf.cf_name;
+		write_pos_pair writer cf.cf_pos cf.cf_name_pos;
+		Chunk.write_list writer.chunk cf.cf_overloads (fun cf ->
+			write_class_field_forward writer cf;
+		);
+
+	and start_texpr writer (p: pos) =
+		let restore = start_temporary_chunk writer 512 in
+		let fctx = create_field_writer_context (PosWriter.create writer.stats writer.chunk p) in
+		fctx,(fun () ->
+			restore(fun new_chunk ->
+				let restore = start_temporary_chunk writer 512 in
+				if in_nested_scope writer then
+					Chunk.write_u8 writer.chunk 0
+				else begin
+					Chunk.write_u8 writer.chunk 1;
+					let ltp = List.map fst (IdentityPool.to_list writer.local_type_parameters) in
+					write_type_parameters writer ltp
+				end;
+				Chunk.write_option writer.chunk fctx.texpr_this (fun e -> write_type_instance writer e.etype);
+				let items,length = StringPool.finalize fctx.t_pool in
+				Chunk.write_uleb128 writer.chunk length;
+				List.iter (fun bytes ->
+					Chunk.write_bytes writer.chunk (Bytes.unsafe_of_string bytes)
+				) items;
+				Chunk.write_uleb128 writer.chunk (DynArray.length fctx.vars);
+				DynArray.iter (fun (v,v_id) ->
+					v.v_id <- v_id;
+					remove_var_flag v VHxb;
+					write_var writer fctx v;
+				) fctx.vars;
+				restore(fun newer_chunk -> newer_chunk,new_chunk)
+			)
+		)
+
+	and commit_field_type_parameters writer (params : type_params) =
+		Chunk.write_uleb128 writer.chunk (List.length params);
+		if in_nested_scope writer then
+			Chunk.write_u8 writer.chunk 0
+		else begin
+			Chunk.write_u8 writer.chunk 1;
+			let ftp = List.map fst (IdentityPool.to_list writer.field_type_parameters) in
+			write_type_parameters writer ftp
+		end
+
+	and write_class_field_data writer (write_expr_immediately : bool) (cf : tclass_field) =
+		let restore = start_temporary_chunk writer 512 in
+		write_type_instance writer cf.cf_type;
+		Chunk.write_uleb128 writer.chunk cf.cf_flags;
+		Chunk.write_option writer.chunk cf.cf_doc (write_documentation writer);
+		write_metadata writer cf.cf_meta;
+		write_field_kind writer cf.cf_kind;
+		let expr_chunk = match cf.cf_expr with
+			| None ->
+				Chunk.write_u8 writer.chunk 0;
+				None
+			| Some e when not write_expr_immediately ->
+				Chunk.write_u8 writer.chunk 2;
+				let fctx,close = start_texpr writer e.epos in
+				write_texpr writer fctx e;
+				Chunk.write_option writer.chunk cf.cf_expr_unoptimized (write_texpr writer fctx);
+				let expr_chunk = close() in
+				Some expr_chunk
+			| Some e ->
+				Chunk.write_u8 writer.chunk 1;
+				let fctx,close = start_texpr writer e.epos in
+				write_texpr writer fctx e;
+				Chunk.write_option writer.chunk cf.cf_expr_unoptimized (write_texpr writer fctx);
+				let expr_pre_chunk,expr_chunk = close() in
+				Chunk.export_data expr_pre_chunk writer.chunk;
+				Chunk.export_data expr_chunk writer.chunk;
+				None
+		in
+		restore (fun new_chunk ->
+			commit_field_type_parameters writer cf.cf_params;
+			Chunk.export_data new_chunk writer.chunk
+		);
+		expr_chunk
+
+	and write_class_field_and_overloads_data writer (write_expr_immediately : bool) (cf : tclass_field) =
+		let cfl = cf :: cf.cf_overloads in
+		Chunk.write_uleb128 writer.chunk (List.length cfl);
+		ExtList.List.filter_map (fun cf ->
+			let close = open_field_scope writer cf.cf_params in
+			let expr_chunk = write_class_field_data writer write_expr_immediately cf in
+			close();
+			Option.map (fun expr_chunk -> (cf,expr_chunk)) expr_chunk
+		) cfl
+
+	(* Module types *)
+
+	let select_type writer (path : path) =
+		writer.type_type_parameters <- Pool.extract writer.type_param_lut path
+
+	let write_common_module_type writer (infos : tinfos) : unit =
+		Chunk.write_bool writer.chunk infos.mt_private;
+		Chunk.write_option writer.chunk infos.mt_doc (write_documentation writer);
+		write_metadata writer infos.mt_meta;
+		write_type_parameters_data writer infos.mt_params;
+		Chunk.write_list writer.chunk infos.mt_using (fun (c,p) ->
+			write_class_ref writer c;
+			write_pos writer p;
+		)
+
+	let write_class_kind writer = function
+		| KNormal ->
+			Chunk.write_u8 writer.chunk 0
+		| KTypeParameter ttp ->
+			die "" __LOC__
+		| KExpr e ->
+			Chunk.write_u8 writer.chunk 2;
+			write_expr writer e;
+		| KGeneric ->
+			Chunk.write_u8 writer.chunk 3;
+		| KGenericInstance(c,tl) ->
+			Chunk.write_u8 writer.chunk 4;
+			write_class_ref writer c;
+			write_types writer tl
+		| KMacroType ->
+			Chunk.write_u8 writer.chunk 5;
+		| KGenericBuild l ->
+			Chunk.write_u8 writer.chunk 6;
+			Chunk.write_list writer.chunk l (write_cfield writer);
+		| KAbstractImpl a ->
+			Chunk.write_u8 writer.chunk 7;
+			write_abstract_ref writer a;
+		| KModuleFields md ->
+			Chunk.write_u8 writer.chunk 8
+
+	let write_class writer (c : tclass) =
+		begin match c.cl_kind with
+		| KAbstractImpl a ->
+			select_type writer a.a_path
+		| _ ->
+			select_type writer c.cl_path;
+		end;
+		write_common_module_type writer (Obj.magic c);
+		write_class_kind writer c.cl_kind;
+		Chunk.write_option writer.chunk c.cl_super (fun (c,tl) ->
+			write_class_ref writer c;
+			write_types writer tl
+		);
+		Chunk.write_list writer.chunk c.cl_implements (fun (c,tl) ->
+			write_class_ref writer c;
+			write_types writer tl
+		);
+		Chunk.write_option writer.chunk c.cl_dynamic (write_type_instance writer);
+		Chunk.write_option writer.chunk c.cl_array_access (write_type_instance writer)
+
+	let write_abstract writer (a : tabstract) =
+		begin try
+			select_type writer a.a_path
+		with Not_found ->
+			prerr_endline ("Could not select abstract " ^ (s_type_path a.a_path));
+		end;
+		write_common_module_type writer (Obj.magic a);
+		Chunk.write_option writer.chunk a.a_impl (write_class_ref writer);
+		if Meta.has Meta.CoreType a.a_meta then
+			Chunk.write_u8 writer.chunk 0
+		else begin
+			Chunk.write_u8 writer.chunk 1;
+			write_type_instance writer a.a_this;
+		end;
+		Chunk.write_list writer.chunk a.a_from (write_type_instance writer);
+		Chunk.write_list writer.chunk a.a_to (write_type_instance writer);
+		Chunk.write_bool writer.chunk a.a_enum
+
+	let write_abstract_fields writer (a : tabstract) =
+		let c = match a.a_impl with
+			| None ->
+				null_class
+			| Some c ->
+				c
+		in
+
+		Chunk.write_list writer.chunk a.a_array (write_field_ref writer c CfrStatic);
+		Chunk.write_option writer.chunk a.a_read (write_field_ref writer c CfrStatic );
+		Chunk.write_option writer.chunk a.a_write (write_field_ref writer c CfrStatic);
+		Chunk.write_option writer.chunk a.a_call (write_field_ref writer c CfrStatic);
+
+		Chunk.write_list writer.chunk a.a_ops (fun (op, cf) ->
+			Chunk.write_u8 writer.chunk (binop_index op);
+			write_field_ref writer c CfrStatic cf
+		);
+
+		Chunk.write_list writer.chunk a.a_unops (fun (op, flag, cf) ->
+			Chunk.write_u8 writer.chunk (unop_index op flag);
+			write_field_ref writer c CfrStatic cf
+		);
+
+		Chunk.write_list writer.chunk a.a_from_field (fun (t,cf) ->
+			write_field_ref writer c CfrStatic cf;
+		);
+
+		Chunk.write_list writer.chunk a.a_to_field (fun (t,cf) ->
+			write_field_ref writer c CfrStatic cf;
+		)
+
+	let write_enum writer (e : tenum) =
+		select_type writer e.e_path;
+		write_common_module_type writer (Obj.magic e);
+		Chunk.write_bool writer.chunk e.e_extern;
+		Chunk.write_list writer.chunk e.e_names (Chunk.write_string writer.chunk)
+
+	let write_typedef writer (td : tdef) =
+		select_type writer td.t_path;
+		write_common_module_type writer (Obj.magic td);
+		write_type_instance writer td.t_type
+
+	(* Module *)
+
+	let forward_declare_type writer (mt : module_type) =
+		let name = ref "" in
+		let i = match mt with
+		| TClassDecl c ->
+			ignore(Pool.add writer.classes c.cl_path c);
+			ignore(Pool.add writer.own_classes c.cl_path c);
+			name := snd c.cl_path;
+			0
+		| TEnumDecl e ->
+			ignore(Pool.add writer.enums e.e_path e);
+			ignore(Pool.add writer.own_enums e.e_path e);
+			name := snd e.e_path;
+			1
+		| TTypeDecl t ->
+			ignore(Pool.add writer.typedefs t.t_path t);
+			ignore(Pool.add writer.own_typedefs t.t_path t);
+			name := snd t.t_path;
+			2
+		| TAbstractDecl a ->
+			ignore(Pool.add writer.abstracts a.a_path a);
+			ignore(Pool.add writer.own_abstracts a.a_path a);
+			name := snd a.a_path;
+			3
+		in
+
+		let infos = t_infos mt in
+		Chunk.write_u8 writer.chunk i;
+		write_path writer (fst infos.mt_path, !name);
+		write_pos_pair writer infos.mt_pos infos.mt_name_pos;
+		write_type_parameters_forward writer infos.mt_params;
+		let params = Pool.create () in
+		writer.type_type_parameters <- params;
+		ignore(Pool.add writer.type_param_lut infos.mt_path params);
+		List.iter (fun ttp ->
+			ignore(Pool.add writer.type_type_parameters ttp.ttp_name ttp)
+		) infos.mt_params;
+
+		(* Forward declare fields *)
+		match mt with
+		| TClassDecl c ->
+			Chunk.write_uleb128 writer.chunk c.cl_flags;
+			Chunk.write_option writer.chunk c.cl_constructor (write_class_field_forward writer);
+			Chunk.write_option writer.chunk c.cl_init (write_class_field_forward writer);
+
+			(* Write in reverse order so reader can read tail-recursively without List.rev *)
+			let write_fields cfl =
+				let i = ref 0 in
+				let rec loop cfl = match cfl with
+					| [] ->
+						()
+					| cf :: cfl ->
+						loop cfl;
+						write_class_field_forward writer cf;
+						incr i;
+				in
+				let restore = start_temporary_chunk writer 256 in
+				loop cfl;
+				let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in
+				!i,bytes
+			in
+			let num_fields,field_bytes = write_fields c.cl_ordered_fields in
+			let num_statics,static_bytes = write_fields c.cl_ordered_statics in
+			Chunk.write_uleb128 writer.chunk num_fields;
+			Chunk.write_uleb128 writer.chunk num_statics;
+			Chunk.write_bytes writer.chunk field_bytes;
+			Chunk.write_bytes writer.chunk static_bytes;
+
+		| TEnumDecl e ->
+			Chunk.write_list writer.chunk (PMap.foldi (fun s f acc -> (s,f) :: acc) e.e_constrs []) (fun (s,ef) ->
+				Chunk.write_string writer.chunk s;
+				write_pos_pair writer ef.ef_pos ef.ef_name_pos;
+				Chunk.write_u8 writer.chunk ef.ef_index
+			);
+		| TAbstractDecl a ->
+			()
+		| TTypeDecl t ->
+			()
+
+	let write_module writer (m : module_def) =
+		writer.current_module <- m;
+
+		start_chunk writer MTF;
+		Chunk.write_list writer.chunk m.m_types (forward_declare_type writer);
+
+		let items = Pool.finalize writer.own_abstracts in
+		if DynArray.length items > 0 then begin
+			start_chunk writer ABD;
+			Chunk.write_dynarray writer.chunk items (write_abstract writer);
+			start_chunk writer AFD;
+			Chunk.write_dynarray writer.chunk items (write_abstract_fields writer);
+		end;
+		let items = Pool.finalize writer.own_classes in
+		if DynArray.length items > 0 then begin
+			start_chunk writer CLD;
+			Chunk.write_dynarray writer.chunk items (write_class writer);
+			start_chunk writer CFD;
+			let expr_chunks = DynArray.create () in
+			Chunk.write_dynarray writer.chunk items (fun c ->
+				begin match c.cl_kind with
+				| KAbstractImpl a ->
+					select_type writer a.a_path
+				| _ ->
+					select_type writer c.cl_path;
+				end;
+
+				let c_expr_chunks = DynArray.create () in
+				let write_field ref_kind cf =
+					let l = write_class_field_and_overloads_data writer false cf in
+					List.iter (fun (cf,e) ->
+						DynArray.add c_expr_chunks (cf,ref_kind,e);
+					) l
+				in
+
+				Chunk.write_option writer.chunk c.cl_constructor (write_field CfrConstructor);
+				Chunk.write_option writer.chunk c.cl_init (write_field CfrInit);
+				Chunk.write_list writer.chunk c.cl_ordered_fields (write_field CfrMember);
+				Chunk.write_list writer.chunk c.cl_ordered_statics (write_field CfrStatic);
+				if DynArray.length c_expr_chunks > 0 then
+					DynArray.add expr_chunks (c,c_expr_chunks)
+			);
+			if DynArray.length expr_chunks > 0 then begin
+				start_chunk writer EXD;
+				Chunk.write_dynarray writer.chunk expr_chunks (fun (c,l) ->
+					write_class_ref writer c;
+					Chunk.write_dynarray writer.chunk l (fun (cf,ref_kind,(e_pre,e)) ->
+						write_field_ref writer c ref_kind cf;
+						let bytes_pre = Chunk.get_bytes e_pre in
+						let bytes_e = Chunk.get_bytes e in
+						Chunk.write_uleb128 writer.chunk (Bytes.length bytes_pre + Bytes.length bytes_e);
+						Chunk.write_bytes writer.chunk bytes_pre;
+						Chunk.write_bytes writer.chunk bytes_e;
+					)
+				)
+			end
+		end;
+		let items = Pool.finalize writer.own_enums in
+		if DynArray.length items > 0 then begin
+			start_chunk writer END;
+			Chunk.write_dynarray writer.chunk items (write_enum writer);
+			start_chunk writer EFD;
+			Chunk.write_dynarray writer.chunk items (fun e ->
+				Chunk.write_list writer.chunk (PMap.foldi (fun s f acc -> (s,f) :: acc) e.e_constrs []) (fun (s,ef) ->
+					select_type writer e.e_path;
+					let close = open_field_scope writer ef.ef_params in
+					Chunk.write_string writer.chunk s;
+					let restore = start_temporary_chunk writer 32 in
+					write_type_instance writer ef.ef_type;
+					let t_bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in
+					commit_field_type_parameters writer ef.ef_params;
+					Chunk.write_bytes writer.chunk t_bytes;
+					Chunk.write_option writer.chunk ef.ef_doc (write_documentation writer);
+					write_metadata writer ef.ef_meta;
+					close();
+				);
+			)
+		end;
+		let items = Pool.finalize writer.own_typedefs in
+		if DynArray.length items > 0 then begin
+			start_chunk writer TDD;
+			Chunk.write_dynarray writer.chunk items (write_typedef writer);
+		end;
+
+		let items = HashedIdentityPool.finalize writer.class_fields in
+		if DynArray.length items > 0 then begin
+			start_chunk writer CFR;
+			Chunk.write_uleb128 writer.chunk (DynArray.length items);
+			DynArray.iter (fun (cf,(c,kind,depth)) ->
+				write_class_ref writer c;
+				begin match kind with
+				| CfrStatic ->
+					Chunk.write_u8 writer.chunk 0;
+					Chunk.write_string writer.chunk cf.cf_name
+				| CfrMember ->
+					Chunk.write_u8 writer.chunk 1;
+					Chunk.write_string writer.chunk cf.cf_name
+				| CfrConstructor ->
+					Chunk.write_u8 writer.chunk 2;
+				| CfrInit ->
+					Chunk.write_u8 writer.chunk 3;
+				end;
+				Chunk.write_uleb128 writer.chunk depth
+			) items;
+		end;
+
+		let items = Pool.finalize writer.enum_fields in
+		if DynArray.length items > 0 then begin
+			start_chunk writer EFR;
+			Chunk.write_uleb128 writer.chunk (DynArray.length items);
+			DynArray.iter (fun (en,ef) ->
+				write_enum_ref writer en;
+				Chunk.write_string writer.chunk ef.ef_name;
+			) items;
+		end;
+
+		let items = HashedIdentityPool.finalize writer.anon_fields in
+		if DynArray.length items > 0 then begin
+			start_chunk writer AFR;
+			Chunk.write_uleb128 writer.chunk (DynArray.length items);
+			DynArray.iter (fun (cf,_) ->
+				write_class_field_forward writer cf
+			) items;
+		end;
+
+		let items = Pool.finalize writer.classes in
+		if DynArray.length items > 0 then begin
+			start_chunk writer CLR;
+			Chunk.write_dynarray writer.chunk items (fun c ->
+				let m = c.cl_module in
+				write_full_path writer (fst m.m_path) (snd m.m_path) (snd c.cl_path);
+			)
+		end;
+		let items = Pool.finalize writer.abstracts in
+		if DynArray.length items > 0 then begin
+			start_chunk writer ABR;
+			Chunk.write_dynarray writer.chunk items (fun a ->
+				let m = a.a_module in
+				write_full_path writer (fst m.m_path) (snd m.m_path) (snd a.a_path);
+			)
+		end;
+		let items = Pool.finalize writer.enums in
+		if DynArray.length items > 0 then begin
+			start_chunk writer ENR;
+			Chunk.write_dynarray writer.chunk items (fun en ->
+				let m = en.e_module in
+				write_full_path writer (fst m.m_path) (snd m.m_path) (snd en.e_path);
+			)
+		end;
+		let items = Pool.finalize writer.typedefs in
+		if DynArray.length items > 0 then begin
+			start_chunk writer TDR;
+			Chunk.write_dynarray writer.chunk items (fun td ->
+				let m = td.t_module in
+				write_full_path writer (fst m.m_path) (snd m.m_path) (snd td.t_path);
+			)
+		end;
+
+		start_chunk writer MDF;
+		write_path writer m.m_path;
+		Chunk.write_string writer.chunk (Path.UniqueKey.lazy_path m.m_extra.m_file);
+		Chunk.write_uleb128 writer.chunk (DynArray.length (Pool.finalize writer.anons));
+		Chunk.write_uleb128 writer.chunk (DynArray.length (IdentityPool.finalize writer.tmonos));
+
+		begin
+			let deps = DynArray.create () in
+			PMap.iter (fun _ mdep ->
+				match mdep.md_kind with
+				| MCode | MExtern when mdep.md_sign = m.m_extra.m_sign ->
+					DynArray.add deps mdep.md_path;
+				| _ ->
+					()
+			) m.m_extra.m_deps;
+			if DynArray.length deps > 0 then begin
+				start_chunk writer MDR;
+				Chunk.write_uleb128 writer.chunk (DynArray.length deps);
+				DynArray.iter (fun path ->
+					write_path writer path
+				) deps
+			end
+		end;
+
+		start_chunk writer EOT;
+		start_chunk writer EOF;
+		start_chunk writer EOM;
+
+		let finalize_string_pool kind items length =
+			start_chunk writer kind;
+			Chunk.write_uleb128 writer.chunk length;
+			List.iter (fun s ->
+				let b = Bytes.unsafe_of_string s in
+				Chunk.write_bytes_length_prefixed writer.chunk b;
+			) items
+		in
+		begin
+			let items,length = StringPool.finalize writer.cp in
+			finalize_string_pool STR items length
+		end;
+		begin
+			let items,length = StringPool.finalize writer.docs in
+			if length > 0 then
+				finalize_string_pool DOC items length
+		end
+
+	let get_sorted_chunks writer =
+		let l = DynArray.to_list writer.chunks in
+		let l = List.sort (fun chunk1 chunk2 ->
+			(Obj.magic chunk1.Chunk.kind - (Obj.magic chunk2.kind))
+		) l in
+		l
+end
+
+let create warn anon_id stats =
+	let cp = StringPool.create () in
+	{
+		warn;
+		anon_id;
+		stats;
+		current_module = null_module;
+		chunks = DynArray.create ();
+		cp = cp;
+		docs = StringPool.create ();
+		chunk = Obj.magic ();
+		classes = Pool.create ();
+		enums = Pool.create ();
+		typedefs = Pool.create ();
+		abstracts = Pool.create ();
+		anons = Pool.create ();
+		anon_fields = HashedIdentityPool.create ();
+		tmonos = IdentityPool.create ();
+		own_classes = Pool.create ();
+		own_abstracts = Pool.create ();
+		own_enums = Pool.create ();
+		own_typedefs = Pool.create ();
+		type_param_lut = Pool.create ();
+		class_fields = HashedIdentityPool.create ();
+		enum_fields = Pool.create ();
+		type_type_parameters = Pool.create ();
+		field_type_parameters = IdentityPool.create ();
+		local_type_parameters = IdentityPool.create ();
+		field_stack = [];
+		unbound_ttp = IdentityPool.create ();
+		t_instance_chunk = Chunk.create EOM cp 32;
+	}
+
+let write_module writer m =
+	HxbWriter.write_module writer m
+
+let get_chunks writer =
+	List.map (fun chunk ->
+		(chunk.Chunk.kind,Chunk.get_bytes chunk)
+	) (HxbWriter.get_sorted_chunks writer)
+
+let export : 'a . hxb_writer -> 'a IO.output -> unit = fun writer ch ->
+	write_header ch;
+	let l = HxbWriter.get_sorted_chunks writer in
+	List.iter (fun io ->
+		Chunk.export writer.stats io ch
+	) l

+ 18 - 8
src/compiler/messageReporting.ml

@@ -54,13 +54,13 @@ let resolve_source file l1 p1 l2 p2 =
 	List.rev !lines
 
 let resolve_file ctx f =
-		let ext = Common.extension f in
-		let second_ext = Common.extension (Common.remove_extension f) in
-		let platform_ext = "." ^ (platform_name_macro ctx) in
-		if platform_ext = second_ext then
-			(Common.remove_extension (Common.remove_extension f)) ^ ext
-		else
-			f
+	let ext = StringHelper.extension f in
+	let second_ext = StringHelper.extension (StringHelper.remove_extension f) in
+	let platform_ext = "." ^ (platform_name_macro ctx) in
+	if platform_ext = second_ext then
+		(StringHelper.remove_extension (StringHelper.remove_extension f)) ^ ext
+	else
+		f
 
 let error_printer file line = Printf.sprintf "%s:%d:" file line
 
@@ -183,6 +183,7 @@ let compiler_pretty_message_string com ectx cm =
 		(* Error source *)
 		if display_source then out := List.fold_left (fun out (l, line) ->
 			let nb_len = String.length (string_of_int l) in
+			let gutter = gutter_len - nb_len - 1 in
 
 			(* Replace tabs with 1 space to avoid column misalignments *)
 			let line = String.concat " " (ExtString.String.nsplit line "\t") in
@@ -190,7 +191,7 @@ let compiler_pretty_message_string com ectx cm =
 
 			out ^ Printf.sprintf "%s%s | %s\n"
 				(* left-padded line number *)
-				(String.make (gutter_len-nb_len-1) ' ')
+				(if gutter < 1 then "" else String.make gutter ' ')
 				(if l = 0 then "-" else Printf.sprintf "%d" l)
 				(* Source code at that line *)
 				(
@@ -308,6 +309,15 @@ let get_max_line max_lines messages =
 		else max_lines
 	) max_lines messages
 
+let display_source_at com p =
+	let absolute_positions = Define.defined com.defines Define.MessageAbsolutePositions in
+	let ectx = create_error_context absolute_positions in
+	let msg = make_compiler_message "" p 0 MessageKind.DKCompilerMessage MessageSeverity.Information in
+	ectx.max_lines <- get_max_line ectx.max_lines [msg];
+	match compiler_pretty_message_string com ectx msg with
+		| None -> ()
+		| Some s -> prerr_endline s
+
 exception ConfigError of string
 
 let get_formatter com def default =

+ 0 - 277
src/compiler/retyper.ml

@@ -1,277 +0,0 @@
-open Globals
-open Ast
-open Typecore
-open Type
-open TypeloadModule
-open TypeloadFields
-
-exception Fail of string
-
-type retyping_context = {
-	typer : typer;
-	print_stack : string list;
-}
-
-let fail rctx s =
-	let stack = String.concat " " (List.rev rctx.print_stack) in
-	raise (Fail (Printf.sprintf "%s: %s" stack s))
-
-let disable_typeloading rctx ctx f =
-	let old = ctx.g.load_only_cached_modules in
-	ctx.g.load_only_cached_modules <- true;
-	try
-		Std.finally (fun () -> ctx.g.load_only_cached_modules <- old) f ()
-	with (Error.Error { err_message = Module_not_found path }) ->
-		fail rctx (Printf.sprintf "Could not load [Module %s]" (s_type_path path))
-
-let pair_type th t = match th with
-	| None ->
-		TExprToExpr.convert_type t,null_pos
-	| Some t ->
-		t
-
-let pair_class_field rctx ctx cctx fctx cf cff p =
-	match cff.cff_kind with
-	| FFun fd ->
-		let targs,tret = match follow cf.cf_type with
-			| TFun(args,ret) ->
-				args,ret
-			| _ ->
-				fail rctx "Type change"
-		in
-		let args = try
-			List.map2 (fun (name,opt,meta,th,eo) (_,_,t) ->
-				(name,opt,meta,Some (pair_type th t),eo)
-			) fd.f_args targs
-		with Invalid_argument _ ->
-			fail rctx "Type change"
-		in
-		let ret = pair_type fd.f_type tret in
-		let fd = {
-			fd with
-			f_args = args;
-			f_type = Some ret
-		} in
-		let load_args_ret () =
-			setup_args_ret ctx cctx fctx (fst cff.cff_name) fd p
-		in
-		let args,ret = disable_typeloading rctx ctx load_args_ret in
-		let t = TFun(args#for_type,ret) in
-		(fun () ->
-			(* This is the only part that should actually modify anything. *)
-			cf.cf_type <- t;
-			TypeBinding.bind_method ctx cctx fctx cf t args ret fd.f_expr (match fd.f_expr with Some e -> snd e | None -> cff.cff_pos);
-			if ctx.com.display.dms_full_typing then
-				remove_class_field_flag cf CfPostProcessed;
-		)
-	| FVar(th,eo) | FProp(_,_,th,eo) ->
-		let th = Some (pair_type th cf.cf_type) in
-		let t = disable_typeloading rctx ctx (fun () -> load_variable_type_hint ctx fctx eo (pos cff.cff_name) th) in
-		(fun () ->
-			cf.cf_type <- t;
-			TypeBinding.bind_var ctx cctx fctx cf eo;
-			if ctx.com.display.dms_full_typing then
-				remove_class_field_flag cf CfPostProcessed;
-		)
-
-let pair_classes rctx c d p =
-	let rctx = {rctx with
-		print_stack = (Printf.sprintf "[Class %s]" (s_type_path c.cl_path)) :: rctx.print_stack
-	} in
-	c.cl_restore();
-	(* TODO: What do we do with build macros? *)
-	let cctx = create_class_context c p in
-	let ctx = create_typer_context_for_class rctx.typer cctx p in
-	let _ =
-		let rctx = {rctx with
-			print_stack = (Printf.sprintf "[Relations]") :: rctx.print_stack
-		} in
-		let has_extends = ref false in
-		let implements = ref c.cl_implements in
-		List.iter (function
-			| HExtends ptp ->
-				has_extends := true;
-				begin match c.cl_super with
-				| None ->
-					fail rctx (Printf.sprintf "parent %s appeared" (Ast.Printer.s_complex_type_path "" ptp))
-				| Some(c,tl) ->
-					let th = pair_type (Some(CTPath ptp,ptp.pos_full)) (TInst(c,tl)) in
-					ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false th))
-				end
-			| HImplements ptp ->
-				begin match !implements with
-					| (c,tl) :: rest ->
-						(* TODO: I think this should somehow check if it's actually the same interface. There could be cases
-						   where the order changes or something like that... Maybe we can compare the loaded type.
-						   However, this doesn't matter until we start retyping invalidated modules.
-						*)
-						implements := rest;
-						let th = pair_type (Some(CTPath ptp,ptp.pos_full)) (TInst(c,tl)) in
-						ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false th));
-					| [] ->
-						fail rctx (Printf.sprintf "interface %s appeared" (Ast.Printer.s_complex_type_path "" ptp))
-				end
-			| _ ->
-				()
-		) d.d_flags;
-		(* TODO: There are probably cases where the compiler generates a cl_super even though it's not in syntax *)
-		if not !has_extends then begin match c.cl_super with
-			| None -> ()
-			| Some(c,_) -> fail rctx (Printf.sprintf "parent %s disappeared" (s_type_path c.cl_path))
-		end;
-		begin match !implements with
-			| (c,_) :: _ -> fail rctx (Printf.sprintf "interface %s disappeared" (s_type_path c.cl_path))
-			| [] -> ()
-		end
-	in
-	let fl = List.map (fun cff ->
-		let name = fst cff.cff_name in
-		let rctx = {rctx with
-			print_stack = (Printf.sprintf "[Field %s]" name) :: rctx.print_stack
-		} in
-		let display_modifier = Typeload.check_field_access ctx cff in
-		let fctx = create_field_context ctx cctx cff ctx.is_display_file display_modifier in
-		let cf = match fctx.field_kind with
-			| FKConstructor ->
-				begin match c.cl_constructor with
-				| None ->
-					fail rctx "Constructor not found"
-				| Some cf ->
-					cf
-				end
-			| FKNormal ->
-				begin try
-					PMap.find name (if fctx.is_static then c.cl_statics else c.cl_fields)
-				with Not_found ->
-					fail rctx "Field not found"
-				end
-			| FKInit ->
-				fail rctx "TODO"
-		in
-		pair_class_field rctx ctx cctx fctx cf cff p
-	) d.d_data in
-	fl @ [fun () -> TypeloadFields.finalize_class ctx cctx]
-
-let pair_enums ctx rctx en d =
-	let ctx = { ctx with type_params = en.e_params } in
-	let rctx = {rctx with
-		print_stack = (Printf.sprintf "[Enum %s]" (s_type_path en.e_path)) :: rctx.print_stack
-	} in
-	List.iter (fun eff ->
-		let name = fst eff.ec_name in
-		let rctx = {rctx with
-			print_stack = (Printf.sprintf "[Field %s]" name) :: rctx.print_stack
-		} in
-		let ef = try
-			PMap.find name en.e_constrs
-		with Not_found ->
-			fail rctx "Field not found"
-		in
-		let th = pair_type eff.ec_type ef.ef_type in
-		ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false th))
-	) d.d_data;
-	[]
-
-let pair_typedefs ctx rctx td d =
-	let rctx = {rctx with
-		print_stack = (Printf.sprintf "[Typedef %s]" (s_type_path td.t_path)) :: rctx.print_stack
-	} in
-	let ctx = { ctx with type_params = td.t_params } in
-	ignore (disable_typeloading rctx ctx (fun () -> Typeload.load_complex_type ctx false d.d_data));
-	[]
-
-let pair_abstracts ctx rctx a d p =
-	let rctx = {rctx with
-		print_stack = (Printf.sprintf "[Abstract %s]" (s_type_path a.a_path)) :: rctx.print_stack
-	} in
-	match a.a_impl with
-	| Some c ->
-		c.cl_restore();
-		let cctx = create_class_context c p in
-		let ctx = create_typer_context_for_class rctx.typer cctx p in
-		let fl = List.map (fun cff ->
-			let cff = TypeloadFields.transform_abstract_field2 ctx a cff in
-			let name = fst cff.cff_name in
-			let rctx = {rctx with
-				print_stack = (Printf.sprintf "[Field %s]" name) :: rctx.print_stack
-			} in
-			let display_modifier = Typeload.check_field_access ctx cff in
-			let fctx = create_field_context ctx cctx cff ctx.is_display_file display_modifier in
-			let cf = try
-				PMap.find name c.cl_statics
-			with Not_found ->
-				fail rctx "Field not found"
-			in
-			pair_class_field rctx ctx cctx fctx cf cff p
-		) d.d_data in
-		fl @ [fun () -> TypeloadFields.finalize_class ctx cctx]
-	| None ->
-		(* ?*)
-		[]
-
-let attempt_retyping ctx m p =
-	let com = ctx.com in
-	let file,_,_,decls = TypeloadParse.parse_module' com m.m_path p in
-	let ctx = create_typer_context_for_module ctx m in
-	let rctx = {
-		typer = ctx;
-		print_stack = [Printf.sprintf "[Module %s]" (s_type_path m.m_path)];
-	} in
-	(* log rctx 0 (Printf.sprintf "Retyping module %s" (s_type_path m.m_path)); *)
-	let find_type name = try
-		List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types
-	with Not_found ->
-		fail rctx (Printf.sprintf "Type %s not found" name)
-	in
-	let rec loop acc decls = match decls with
-		| [] ->
-			List.rev acc
-		| (d,p) :: decls ->
-			begin match d with
-			| EImport (path,mode) ->
-				ImportHandling.init_import ctx path mode p;
-				ImportHandling.commit_import ctx path mode p;
-				loop acc decls
-			| EUsing path ->
-				ImportHandling.init_using ctx path p;
-				loop acc decls
-			| EClass c ->
-				let mt = find_type (fst c.d_name) in
-				loop ((d,mt) :: acc) decls
-			| EEnum en ->
-				let mt = find_type (fst en.d_name) in
-				loop ((d,mt) :: acc) decls
-			| ETypedef td ->
-				let mt = find_type (fst td.d_name) in
-				loop ((d,mt) :: acc) decls
-			| EAbstract a ->
-				let mt = find_type (fst a.d_name) in
-				loop ((d,mt) :: acc) decls
-			| _ ->
-				loop acc decls
-			end;
-	in
-	try
-		m.m_extra.m_cache_state <- MSUnknown;
-		let pairs = loop [] decls in
-		let fl = List.map (fun (d,mt) -> match d,mt with
-			| EClass d,TClassDecl c ->
-				pair_classes rctx c d p
-			| EEnum d,TEnumDecl en ->
-				pair_enums ctx rctx en d
-			| ETypedef d,TTypeDecl td ->
-				pair_typedefs ctx rctx td d
-			| EAbstract d,TAbstractDecl a ->
-				pair_abstracts ctx rctx a d p
-			| _ ->
-				fail rctx "?"
-		) pairs in
-		(* If we get here we know that the everything is ok. *)
-		List.iter (fun fl ->
-			List.iter (fun f -> f()) fl
-		) fl;
-		m.m_extra.m_cache_state <- MSGood;
-		m.m_extra.m_time <- Common.file_time file;
-		None
-	with Fail s ->
-		Some s

+ 235 - 94
src/compiler/server.ml

@@ -3,11 +3,13 @@ open Common
 open CompilationCache
 open Timer
 open Type
+open Typecore
 open DisplayProcessingGlobals
 open Ipaddr
 open Json
 open CompilationContext
 open MessageReporting
+open HxbData
 
 exception Dirty of module_skip_reason
 exception ServerError of string
@@ -41,9 +43,10 @@ let check_display_flush ctx f_otherwise = match ctx.com.json_out with
 
 let current_stdin = ref None
 
-let parse_file cs com file p =
+let parse_file cs com (rfile : ClassPaths.resolved_file) p =
 	let cc = CommonCache.get_cache com in
-	let ffile = Path.get_full_path file
+	let file = rfile.file in
+	let ffile = Path.get_full_path rfile.file
 	and fkey = com.file_keys#get file in
 	let is_display_file = DisplayPosition.display_position#is_in_file (com.file_keys#get ffile) in
 	match is_display_file, !current_stdin with
@@ -57,7 +60,7 @@ let parse_file cs com file p =
 				if cfile.c_time <> ftime then raise Not_found;
 				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 parse_result = TypeloadParse.parse_file com rfile p in
 				let info,is_unusual = match parse_result with
 					| ParseError(_,_,_) -> "not cached, has parse error",true
 					| ParseSuccess(data,is_display_file,pdi) ->
@@ -65,7 +68,7 @@ let parse_file cs com file p =
 							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 fkey ffile ftime data pdi;
+								cc#cache_file fkey rfile ftime data pdi;
 								"cached, is intact display file",true
 							end else
 								"not cached, is display file",true
@@ -76,7 +79,7 @@ let parse_file cs com file p =
 							let ident = Hashtbl.find Parser.special_identifier_files fkey in
 							Printf.sprintf "not cached, using \"%s\" define" ident,true
 						with Not_found ->
-							cc#cache_file fkey ffile ftime data pdi;
+							cc#cache_file fkey (ClassPaths.create_resolved_file ffile rfile.class_path) ftime data pdi;
 							"cached",false
 						end
 				in
@@ -124,7 +127,7 @@ module Communication = struct
 	let create_pipe sctx write =
 		let rec self = {
 			write_out = (fun s ->
-				write ("\x01" ^ String.concat "\n\x01" (ExtString.String.nsplit s "\n") ^ "\n")
+				write ("\x01" ^ String.concat "\x01" (ExtString.String.nsplit s "\n") ^ "\n")
 			);
 			write_err = (fun s ->
 				write s
@@ -208,8 +211,9 @@ let get_changed_directories sctx (ctx : Typecore.typer) =
 					with Unix.Unix_error _ ->
 						()
 				in
-				List.iter add_dir com.class_path;
-				List.iter add_dir (Path.find_directories (platform_name com.platform) true com.class_path);
+				let class_path_strings = com.class_paths#as_string_list in
+				List.iter add_dir class_path_strings;
+				List.iter add_dir (Path.find_directories (platform_name com.platform) true class_path_strings);
 				ServerMessage.found_directories com "" !dirs;
 				cs#add_directories sign !dirs
 			) :: sctx.delays;
@@ -225,27 +229,27 @@ let get_changed_directories sctx (ctx : Typecore.typer) =
 
 (* Checks if module [m] can be reused from the cache and returns None in that case. Otherwise, returns
    [Some m'] where [m'] is the module responsible for [m] not being reusable. *)
-let check_module sctx ctx m p =
+let check_module sctx ctx m_path m_extra p =
 	let com = ctx.Typecore.com in
 	let cc = CommonCache.get_cache com in
-	let content_changed m file =
+	let content_changed m_path file =
 		let fkey = ctx.com.file_keys#get file in
 		try
 			let cfile = cc#find_file fkey in
 			(* We must use the module path here because the file path is absolute and would cause
 				positions in the parsed declarations to differ. *)
-			let new_data = TypeloadParse.parse_module ctx m.m_path p in
+			let new_data = TypeloadParse.parse_module ctx m_path p in
 			cfile.c_decls <> snd new_data
 		with Not_found ->
 			true
 	in
-	let check_module_shadowing paths m =
+	let check_module_shadowing paths m_path m_extra =
 		List.iter (fun dir ->
-			let file = (dir.c_path ^ (snd m.m_path)) ^ ".hx" in
+			let file = (dir.c_path ^ (snd m_path)) ^ ".hx" in
 			if Sys.file_exists file then begin
 				let time = file_time file in
-				if time > m.m_extra.m_time then begin
-					ServerMessage.module_path_changed com "" (m,time,file);
+				if time > m_extra.m_time then begin
+					ServerMessage.module_path_changed com "" (m_path,m_extra,time,file);
 					raise (Dirty (Shadowed file))
 				end
 			end
@@ -253,33 +257,33 @@ let check_module sctx ctx m p =
 	in
 	let start_mark = sctx.compilation_step in
 	let unknown_state_modules = ref [] in
-	let rec check m =
+	let rec check m_path m_extra =
 		let check_module_path () =
 			let directories = get_changed_directories sctx ctx in
-			match m.m_extra.m_kind with
+			match m_extra.m_kind with
 			| MFake | MImport -> () (* don't get classpath *)
 			| MExtern ->
 				(* if we have a file then this will override our extern type *)
-				check_module_shadowing directories m;
+				check_module_shadowing directories m_path m_extra;
 				let rec loop = function
 					| [] ->
-						if sctx.verbose then print_endline ("No library file was found for " ^ s_type_path m.m_path); (* TODO *)
+						if sctx.verbose then print_endline ("No library file was found for " ^ s_type_path m_path); (* TODO *)
 						raise (Dirty LibraryChanged)
 					| (file,load) :: l ->
-						match load m.m_path p with
+						match load m_path p with
 						| None ->
 							loop l
 						| Some _ ->
-							if com.file_keys#get file <> (Path.UniqueKey.lazy_key m.m_extra.m_file) then begin
-								if sctx.verbose then print_endline ("Library file was changed for " ^ s_type_path m.m_path); (* TODO *)
+							if com.file_keys#get file <> (Path.UniqueKey.lazy_key m_extra.m_file) then begin
+								if sctx.verbose then print_endline ("Library file was changed for " ^ s_type_path m_path); (* TODO *)
 								raise (Dirty LibraryChanged)
 							end
 				in
 				loop com.load_extern_type
 			| MCode ->
-				check_module_shadowing directories m
+				check_module_shadowing directories m_path m_extra
 			| MMacro when com.is_macro_context ->
-				check_module_shadowing directories m
+				check_module_shadowing directories m_path m_extra
 			| MMacro ->
 				(*
 					Creating another context while the previous one is incomplete means we have an infinite loop in the compiler.
@@ -292,40 +296,45 @@ let check_module sctx ctx m p =
 						^ "Probably caused by shadowing a module of the standard library. "
 						^ "Make sure shadowed module does not pull macro context."));
 				let mctx = MacroContext.get_macro_context ctx in
-				check_module_shadowing (get_changed_directories sctx mctx) m
+				check_module_shadowing (get_changed_directories sctx mctx) m_path m_extra
 		in
-		let has_policy policy = List.mem policy m.m_extra.m_check_policy || match policy with
+		let has_policy policy = List.mem policy m_extra.m_check_policy || match policy with
 			| NoCheckShadowing | NoCheckFileTimeModification when !ServerConfig.do_not_check_modules && !Parser.display_mode <> DMNone -> true
 			| _ -> false
 		in
 		let check_file () =
-			let file = Path.UniqueKey.lazy_path m.m_extra.m_file in
-			if file_time file <> m.m_extra.m_time then begin
-				if has_policy CheckFileContentModification && not (content_changed m file) then begin
+			let file = Path.UniqueKey.lazy_path m_extra.m_file in
+			if file_time file <> m_extra.m_time then begin
+				if has_policy CheckFileContentModification && not (content_changed m_path file) then begin
 					ServerMessage.unchanged_content com "" file;
 				end else begin
-					ServerMessage.not_cached com "" m;
-					if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules (Path.UniqueKey.lazy_key m.m_extra.m_file);
+					ServerMessage.not_cached com "" m_path;
+					if m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules (Path.UniqueKey.lazy_key m_extra.m_file);
 					raise (Dirty (FileChanged file))
 				end
 			end
 		in
+		let find_module_extra sign mpath =
+			(com.cs#get_context sign)#find_module_extra mpath
+		in
 		let check_dependencies () =
-			PMap.iter (fun _ (sign,mpath) ->
-				let m2 = try
-					(com.cs#get_context sign)#find_module mpath
+			PMap.iter (fun _ mdep ->
+				let sign = mdep.md_sign in
+				let mpath = mdep.md_path in
+				let m2_extra = try
+					find_module_extra sign mpath
 				with Not_found ->
-					die (Printf.sprintf "Could not find dependency %s of %s in the cache" (s_type_path mpath) (s_type_path m.m_path)) __LOC__;
+					die (Printf.sprintf "Could not find dependency %s of %s in the cache" (s_type_path mpath) (s_type_path m_path)) __LOC__;
 				in
-				match check m2 with
+				match check mpath m2_extra with
 				| None -> ()
-				| Some reason -> raise (Dirty (DependencyDirty(m2.m_path,reason)))
-			) m.m_extra.m_deps;
+				| Some reason -> raise (Dirty (DependencyDirty(mpath,reason)))
+			) m_extra.m_deps;
 		in
 		let check () =
 			try
 				if not (has_policy NoCheckShadowing) then check_module_path();
-				if not (has_policy NoCheckFileTimeModification) || Path.file_extension (Path.UniqueKey.lazy_path m.m_extra.m_file) <> "hx" then check_file();
+				if not (has_policy NoCheckFileTimeModification) || Path.file_extension (Path.UniqueKey.lazy_path m_extra.m_file) <> "hx" then check_file();
 				if not (has_policy NoCheckDependencies) then check_dependencies();
 				None
 			with
@@ -333,15 +342,15 @@ let check_module sctx ctx m p =
 				Some reason
 		in
 		(* If the module mark matches our compilation mark, we are done *)
-		if m.m_extra.m_checked = start_mark then begin match m.m_extra.m_cache_state with
+		if m_extra.m_checked = start_mark then begin match m_extra.m_cache_state with
 			| MSGood | MSUnknown ->
 				None
 			| MSBad reason ->
 				Some reason
 		end else begin
 			(* Otherwise, set to current compilation mark for recursion *)
-			m.m_extra.m_checked <- start_mark;
-			let dirty = match m.m_extra.m_cache_state with
+			m_extra.m_checked <- start_mark;
+			let dirty = match m_extra.m_cache_state with
 				| MSBad reason ->
 					(* If we are already dirty, stick to it. *)
 					Some reason
@@ -350,55 +359,110 @@ let check_module sctx ctx m p =
 					die "" __LOC__
 				| MSGood ->
 					(* Otherwise, run the checks *)
-					m.m_extra.m_cache_state <- MSUnknown;
+					m_extra.m_cache_state <- MSUnknown;
 					check ()
 			in
-			let dirty = match dirty with
-				| Some (DependencyDirty _) when has_policy Retype ->
-					let result = Retyper.attempt_retyping ctx m p in
-					begin match result with
-					| None ->
-						ServerMessage.retyper_ok com "" m;
-						None
-					| Some reason ->
-						ServerMessage.retyper_fail com "" m reason;
-						dirty
-					end
-				| _ ->
-					dirty
-			in
 			(* Update the module now. It will use this dirty status for the remainder of this compilation. *)
 			begin match dirty with
 			| Some reason ->
 				(* Update the state if we're dirty. *)
-				m.m_extra.m_cache_state <- MSBad reason;
+				m_extra.m_cache_state <- MSBad reason;
 			| None ->
 				(* We cannot update if we're clean because at this point it might just be an assumption.
 				   Instead We add the module to a list which is updated at the end of handling this subgraph. *)
-				unknown_state_modules := m :: !unknown_state_modules;
+				unknown_state_modules := m_extra :: !unknown_state_modules;
 			end;
 			dirty
 		end
 	in
-	let state = check m in
+	let state = check m_path m_extra in
 	begin match state with
 	| None ->
 		(* If the entire subgraph is clean, we can set all modules to good state *)
-		List.iter (fun m -> m.m_extra.m_cache_state <- MSGood) !unknown_state_modules;
+		List.iter (fun m_extra -> m_extra.m_cache_state <- MSGood) !unknown_state_modules;
 	| Some _ ->
 		(* Otherwise, unknown state module may or may not be dirty. We didn't check everything eagerly, so we have
 		   to make sure that the module is checked again if it appears in a different check. This is achieved by
 		   setting m_checked to a lower value and assuming Good state again. *)
-		List.iter (fun m -> match m.m_extra.m_cache_state with
+		List.iter (fun m_extra -> match m_extra.m_cache_state with
 			| MSUnknown ->
-				m.m_extra.m_checked <- start_mark - 1;
-				m.m_extra.m_cache_state <- MSGood;
+				m_extra.m_checked <- start_mark - 1;
+				m_extra.m_cache_state <- MSGood;
 			| MSGood | MSBad _ ->
 				()
 		) !unknown_state_modules
 	end;
 	state
 
+class hxb_reader_api_server
+	(ctx : Typecore.typer)
+	(cc : context_cache)
+= object(self)
+
+	method make_module (path : path) (file : string) =
+		let mc = cc#get_hxb_module path in
+		{
+			m_id = mc.mc_id;
+			m_path = path;
+			m_types = [];
+			m_statics = None;
+			m_extra = mc.mc_extra
+		}
+
+	method add_module (m : module_def) =
+		ctx.com.module_lut#add m.m_path m
+
+	method resolve_type (pack : string list) (mname : string) (tname : string) =
+		let path = (pack,mname) in
+		let m = self#resolve_module path in
+		List.find (fun t -> snd (t_path t) = tname) m.m_types
+
+	method resolve_module (path : path) =
+		match self#find_module path with
+		| GoodModule m ->
+			m
+		| BinaryModule mc ->
+			let reader = new HxbReader.hxb_reader path ctx.com.hxb_reader_stats in
+			let f_next chunks until =
+				let t_hxb = Timer.timer ["server";"module cache";"hxb read"] in
+				let r = reader#read_chunks_until (self :> HxbReaderApi.hxb_reader_api) chunks until in
+				t_hxb();
+				r
+			in
+			let m,chunks = f_next mc.mc_chunks EOF in
+
+			(* We try to avoid reading expressions as much as possible, so we only do this for
+				 our current display file if we're in display mode. *)
+			let is_display_file = DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key m.m_extra.m_file) in
+			if is_display_file || ctx.com.display.dms_full_typing then ignore(f_next chunks EOM);
+			m
+		| BadModule reason ->
+			die (Printf.sprintf "Unexpected BadModule %s" (s_type_path path)) __LOC__
+		| NoModule ->
+			die (Printf.sprintf "Unexpected NoModule %s" (s_type_path path)) __LOC__
+
+	method find_module (m_path : path) =
+		try
+			GoodModule (ctx.com.module_lut#find m_path)
+		with Not_found -> try
+			let mc = cc#get_hxb_module m_path in
+			begin match mc.mc_extra.m_cache_state with
+				| MSBad reason -> BadModule reason
+				| _ -> BinaryModule mc
+			end
+		with Not_found ->
+			NoModule
+
+	method basic_types =
+		ctx.com.basic
+
+	method get_var_id (i : int) =
+		i
+
+	method read_expression_eagerly (cf : tclass_field) =
+		ctx.com.display.dms_full_typing
+end
+
 let handle_cache_bound_objects com cbol =
 	DynArray.iter (function
 		| Resource(name,data) ->
@@ -411,25 +475,44 @@ let handle_cache_bound_objects com cbol =
 
 (* Adds module [m] and all its dependencies (recursively) from the cache to the current compilation
    context. *)
-let add_modules sctx ctx m p =
+let rec add_modules sctx ctx (m : module_def) (from_binary : bool) (p : pos) =
 	let com = ctx.Typecore.com in
+	let own_sign = CommonCache.get_cache_sign com in
 	let rec add_modules tabs m0 m =
 		if m.m_extra.m_added < ctx.com.compilation_step then begin
+			m.m_extra.m_added <- ctx.com.compilation_step;
 			(match m0.m_extra.m_kind, m.m_extra.m_kind with
 			| MCode, MMacro | MMacro, MCode ->
 				(* this was just a dependency to check : do not add to the context *)
 				handle_cache_bound_objects com m.m_extra.m_cache_bound_objects;
 			| _ ->
-				m.m_extra.m_added <- ctx.com.compilation_step;
 				ServerMessage.reusing com tabs m;
 				List.iter (fun t ->
 					(t_infos t).mt_restore()
 				) m.m_types;
-				TypeloadModule.ModuleLevel.add_module ctx m p;
+				(* The main module gets added when reading hxb already, so let's not add it again. Note that we
+				   can't set its m_added ahead of time because we want the rest of the logic here to run. *)
+				if not from_binary || m != m then
+					com.module_lut#add m.m_path m;
 				handle_cache_bound_objects com m.m_extra.m_cache_bound_objects;
-				PMap.iter (fun _ (sign,mpath) ->
-					let m2 = (com.cs#get_context sign)#find_module mpath in
-					add_modules (tabs ^ "  ") m0 m2
+				PMap.iter (fun _ mdep ->
+					let mpath = mdep.md_path in
+					if mdep.md_sign = own_sign then begin
+						let m2 = try
+							com.module_lut#find mpath
+						with Not_found ->
+							match type_module sctx ctx mpath p with
+							| GoodModule m ->
+								m
+							| BinaryModule mc ->
+								failwith (Printf.sprintf "Unexpectedly found unresolved binary module %s as a dependency of %s" (s_type_path mpath) (s_type_path m0.m_path))
+							| NoModule ->
+								failwith (Printf.sprintf "Unexpectedly could not find module %s as a dependency of %s" (s_type_path mpath) (s_type_path m0.m_path))
+							| BadModule reason ->
+								failwith (Printf.sprintf "Unexpected bad module %s (%s) as a dependency of %s" (s_type_path mpath) (Printer.s_module_skip_reason reason) (s_type_path m0.m_path))
+						in
+						add_modules (tabs ^ "  ") m0 m2
+					end
 				) m.m_extra.m_deps
 			)
 		end
@@ -438,29 +521,83 @@ let add_modules sctx ctx m p =
 
 (* Looks up the module referred to by [mpath] in the cache. If it exists, a check is made to
    determine if it's still valid. If this function returns None, the module is re-typed. *)
-let type_module sctx (ctx:Typecore.typer) mpath p =
+and type_module sctx (ctx:Typecore.typer) mpath p =
 	let t = Timer.timer ["server";"module cache"] in
 	let com = ctx.Typecore.com in
 	let cc = CommonCache.get_cache com in
-	try
-		let m = cc#find_module mpath in
-		let tcheck = Timer.timer ["server";"module cache";"check"] in
-		begin match check_module sctx ctx m p with
-		| None -> ()
-		| Some reason ->
-			ServerMessage.skipping_dep com "" (m,(Printer.s_module_skip_reason reason));
-			tcheck();
-			raise Not_found;
-		end;
-		tcheck();
+	let skip m_path reason =
+		ServerMessage.skipping_dep com "" (m_path,(Printer.s_module_skip_reason reason));
+		BadModule reason
+	in
+	let add_modules from_binary m =
 		let tadd = Timer.timer ["server";"module cache";"add modules"] in
-		add_modules sctx ctx m p;
+		add_modules sctx ctx m from_binary p;
 		tadd();
-		t();
-		Some m
-	with Not_found ->
-		t();
-		None
+		GoodModule m
+	in
+	let check_module sctx ctx m_path m_extra p =
+		let tcheck = Timer.timer ["server";"module cache";"check"] in
+		let r = check_module sctx ctx mpath m_extra p in
+		tcheck();
+		r
+	in
+	let find_module_in_cache ctx cc m_path p =
+		try
+			let m = cc#find_module m_path in
+			begin match m.m_extra.m_cache_state with
+				| MSBad reason -> BadModule reason
+				| _ -> GoodModule m
+			end;
+		with Not_found -> try
+			let mc = cc#get_hxb_module m_path in
+			begin match mc.mc_extra.m_cache_state with
+				| MSBad reason -> BadModule reason
+				| _ -> BinaryModule mc
+			end
+		with Not_found ->
+			NoModule
+	in
+	(* Should not raise anything! *)
+	let m = match find_module_in_cache ctx cc mpath p with
+		| GoodModule m ->
+			(* "Good" here is an assumption, it only means that the module wasn't explicitly invalidated
+			   in the cache. The true cache state will be known after check_module. *)
+			begin match check_module sctx ctx mpath m.m_extra p with
+				| None ->
+					add_modules false m;
+				| Some reason ->
+					skip m.m_path reason
+			end
+		| BinaryModule mc ->
+			(* Similarly, we only know that a binary module wasn't explicitly tainted. Decode it only after
+			   checking dependencies. This means that the actual decoding never has any reason to fail. *)
+			begin match check_module sctx ctx mpath mc.mc_extra p with
+				| None ->
+					let reader = new HxbReader.hxb_reader mpath com.hxb_reader_stats in
+					let api = (new hxb_reader_api_server ctx cc :> HxbReaderApi.hxb_reader_api) in
+					let f_next chunks until =
+						let t_hxb = Timer.timer ["server";"module cache";"hxb read"] in
+						let r = reader#read_chunks_until api chunks until in
+						t_hxb();
+						r
+					in
+					let m,chunks = f_next mc.mc_chunks EOF in
+					(* We try to avoid reading expressions as much as possible, so we only do this for
+					   our current display file if we're in display mode. *)
+					let is_display_file = DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key m.m_extra.m_file) in
+					if is_display_file || ctx.com.display.dms_full_typing then ignore(f_next chunks EOM);
+					add_modules true m;
+				| Some reason ->
+					skip mpath reason
+			end
+		| BadModule reason ->
+			(* A BadModule state here means that the module is already invalidated in the cache, e.g. from server/invalidate. *)
+			skip mpath reason
+		| NoModule as mr ->
+			mr
+	in
+	t();
+	m
 
 let before_anything sctx ctx =
 	ensure_macro_setup sctx
@@ -472,21 +609,25 @@ let after_target_init sctx ctx =
 	ServerMessage.defines com "";
 	ServerMessage.signature com "" sign;
 	ServerMessage.display_position com "" (DisplayPosition.display_position#get);
+	let class_path_strings = com.class_paths#as_string_list in
 	try
-		if (Hashtbl.find sctx.class_paths sign) <> com.class_path then begin
+		if (Hashtbl.find sctx.class_paths sign) <> class_path_strings then begin
 			ServerMessage.class_paths_changed com "";
-			Hashtbl.replace sctx.class_paths sign com.class_path;
+			Hashtbl.replace sctx.class_paths sign class_path_strings;
 			cs#clear_directories sign;
 			(cs#get_context sign)#set_initialized false;
 		end;
 	with Not_found ->
-		Hashtbl.add sctx.class_paths sign com.class_path;
+		Hashtbl.add sctx.class_paths sign class_path_strings;
 		()
 
-let after_compilation sctx ctx =
-	if not (has_error ctx) then
+let after_save sctx ctx =
+	if ctx.comm.is_server && not (has_error ctx) then
 		maybe_cache_context sctx ctx.com
 
+let after_compilation sctx ctx =
+	()
+
 let mk_length_prefixed_communication allow_nonblock chin chout =
 	let sin = Unix.descr_of_in_channel chin in
 	let chin = IO.input_channel chin in
@@ -619,7 +760,6 @@ let do_connect ip port args =
 
 let enable_cache_mode sctx =
 	TypeloadModule.type_module_hook := type_module sctx;
-	MacroContext.macro_enable_cache := true;
 	ServerCompilationContext.ensure_macro_setup sctx;
 	TypeloadParse.parse_hook := parse_file sctx.cs
 
@@ -636,6 +776,7 @@ let rec process sctx comm args =
 		callbacks = {
 			before_anything = before_anything sctx;
 			after_target_init = after_target_init sctx;
+			after_save = after_save sctx;
 			after_compilation = after_compilation sctx;
 		};
 		init_wait_socket = init_wait_socket;

+ 2 - 2
src/compiler/serverCompilationContext.ml

@@ -1,4 +1,3 @@
-open Globals
 open Common
 open Timer
 open CompilationCache
@@ -46,7 +45,6 @@ let reset sctx =
 	Hashtbl.clear sctx.changed_directories;
 	sctx.was_compilation <- false;
 	Parser.reset_state();
-	return_partial_type := false;
 	measure_times := false;
 	Hashtbl.clear DeprecationCheck.warned_positions;
 	close_times();
@@ -59,7 +57,9 @@ let reset sctx =
 
 let maybe_cache_context sctx com =
 	if com.display.dms_full_typing && com.display.dms_populate_cache then begin
+		let t = Timer.timer ["server";"cache context"] in
 		CommonCache.cache_context sctx.cs com;
+		t();
 		ServerMessage.cached_modules com "" (List.length com.modules);
 	end
 

+ 6 - 6
src/compiler/serverMessage.ml

@@ -75,12 +75,12 @@ let found_directories com tabs dirs =
 let changed_directories com tabs dirs =
 	if config.print_changed_directories then print_endline (Printf.sprintf "%schanged directories: [%s]" (sign_string com) (String.concat ", " (List.map (fun dir -> "\"" ^ dir.c_path ^ "\"") dirs)))
 
-let module_path_changed com tabs (m,time,file) =
+let module_path_changed com tabs (m_path,m_extra,time,file) =
 	if config.print_module_path_changed then print_endline (Printf.sprintf "%smodule path might have changed: %s\n\twas: %2.0f %s\n\tnow: %2.0f %s"
-		(sign_string com) (s_type_path m.m_path) m.m_extra.m_time (Path.UniqueKey.lazy_path m.m_extra.m_file) time file)
+		(sign_string com) (s_type_path m_path) m_extra.m_time (Path.UniqueKey.lazy_path m_extra.m_file) time file)
 
-let not_cached com tabs m =
-	if config.print_not_cached then print_endline (Printf.sprintf "%s%s not cached (%s)" (sign_string com) (s_type_path m.m_path) "modified")
+let not_cached com tabs m_path =
+	if config.print_not_cached then print_endline (Printf.sprintf "%s%s not cached (%s)" (sign_string com) (s_type_path m_path) "modified")
 
 let parsed com tabs (ffile,info) =
 	if config.print_parsed then print_endline (Printf.sprintf "%sparsed %s (%s)" (sign_string com) ffile info)
@@ -100,8 +100,8 @@ let retyper_fail com tabs m reason =
 		print_endline (Printf.sprintf "%s%s%s" (sign_string com) (tabs ^ "  ") reason);
 	end
 
-let skipping_dep com tabs (m,reason) =
-	if config.print_skipping_dep then print_endline (Printf.sprintf "%sskipping %s (%s)" (sign_string com) (s_type_path m.m_path) reason)
+let skipping_dep com tabs (mpath,reason) =
+	if config.print_skipping_dep then print_endline (Printf.sprintf "%sskipping %s (%s)" (sign_string com) (s_type_path mpath) reason)
 
 let unchanged_content com tabs file =
 	if config.print_unchanged_content then print_endline (Printf.sprintf "%s%s changed time not but content, reusing" (sign_string com) file)

+ 53 - 123
src/context/common.ml

@@ -27,7 +27,6 @@ open Warning
 
 type package_rule =
 	| Forbidden
-	| Directory of string
 	| Remap of string
 
 type pos = Globals.pos
@@ -334,6 +333,18 @@ class module_lut = object(self)
 	method get_type_lut = type_lut
 end
 
+class virtual abstract_hxb_lib = object(self)
+	method virtual load : unit
+	method virtual get_bytes : string -> path -> bytes option
+	method virtual close : unit
+	method virtual get_file_path : string
+end
+
+type context_main = {
+	mutable main_class : path option;
+	mutable main_expr : texpr option;
+}
+
 type context = {
 	compilation_step : int;
 	mutable stage : compiler_stage;
@@ -343,17 +354,16 @@ type context = {
 	mutable json_out : json_api option;
 	(* config *)
 	version : int;
-	args : string list;
-	mutable sys_args : string list;
+	mutable args : string list;
 	mutable display : DisplayTypes.DisplayMode.settings;
 	mutable debug : bool;
 	mutable verbose : bool;
 	mutable foptimize : bool;
 	mutable platform : platform;
 	mutable config : platform_config;
-	mutable std_path : string list;
-	mutable class_path : string list;
-	mutable main_class : path option;
+	empty_class_path : ClassPath.class_path;
+	class_paths : ClassPaths.class_paths;
+	main : context_main;
 	mutable package_rules : (string,package_rule) PMap.t;
 	mutable report_mode : report_mode;
 	(* communication *)
@@ -379,12 +389,10 @@ type context = {
 	mutable global_metadata : (string list * metadata_entry * (bool * bool * bool)) list;
 	shared : shared_context;
 	display_information : display_information;
-	file_lookup_cache : (string,string option) lookup;
 	file_keys : file_keys;
 	mutable file_contents : (Path.UniqueKey.t * string option) list;
-	readdir_cache : (string * string,(string array) option) lookup;
 	parser_cache : (string,(type_def * pos) list) lookup;
-	module_to_file : (path,string) lookup;
+	module_to_file : (path,ClassPaths.resolved_file) lookup;
 	cached_macros : (path * string,(((string * bool * t) list * t * tclass * Type.tclass_field) * module_def)) lookup;
 	stored_typed_exprs : (int, texpr) lookup;
 	overload_cache : ((path * string),(Type.t * tclass_field) list) lookup;
@@ -396,7 +404,6 @@ type context = {
 	mutable file : string;
 	mutable features : (string,bool) Hashtbl.t;
 	mutable modules : Type.module_def list;
-	mutable main : Type.texpr option;
 	mutable types : Type.module_type list;
 	mutable resources : (string,string) Hashtbl.t;
 	(* target-specific *)
@@ -404,12 +411,15 @@ type context = {
 	mutable neko_lib_paths : string list;
 	mutable include_files : (string * string) list;
 	mutable native_libs : native_libraries;
+	mutable hxb_libs : abstract_hxb_lib list;
 	mutable net_std : string list;
 	net_path_map : (path,string list * string list * string) Hashtbl.t;
 	mutable js_gen : (unit -> unit) option;
 	(* misc *)
 	mutable basic : basic_types;
 	memory_marker : float array;
+	hxb_reader_stats : HxbReader.hxb_reader_stats;
+	hxb_writer_stats : HxbWriter.hxb_writer_stats;
 }
 
 let enter_stage com stage =
@@ -761,7 +771,6 @@ let create compilation_step cs version args display_mode =
 			display_module_has_macro_defines = false;
 			module_diagnostics = [];
 		};
-		sys_args = args;
 		debug = false;
 		display = display_mode;
 		verbose = false;
@@ -772,9 +781,12 @@ let create compilation_step cs version args display_mode =
 		print = (fun s -> print_string s; flush stdout);
 		run_command = Sys.command;
 		run_command_args = (fun s args -> com.run_command (Printf.sprintf "%s %s" s (String.concat " " args)));
-		std_path = [];
-		class_path = [];
-		main_class = None;
+		empty_class_path = new ClassPath.directory_class_path "" User;
+		class_paths = new ClassPaths.class_paths;
+		main = {
+			main_class = None;
+			main_expr = None;
+		};
 		package_rules = PMap.empty;
 		file = "";
 		types = [];
@@ -783,11 +795,11 @@ let create compilation_step cs version args display_mode =
 		modules = [];
 		module_lut = new module_lut;
 		module_nonexistent_lut = new hashtbl_lookup;
-		main = None;
 		flash_version = 10.;
 		resources = Hashtbl.create 0;
 		net_std = [];
 		native_libs = create_native_libs();
+		hxb_libs = [];
 		net_path_map = Hashtbl.create 0;
 		neko_lib_paths = [];
 		include_files = [];
@@ -818,10 +830,8 @@ let create compilation_step cs version args display_mode =
 			tarray = (fun _ -> die "Could not locate class Array<T> (was it redefined?)" __LOC__);
 		};
 		std = null_class;
-		file_lookup_cache = new hashtbl_lookup;
 		file_keys = new file_keys;
 		file_contents = [];
-		readdir_cache = new hashtbl_lookup;
 		module_to_file = new hashtbl_lookup;
 		stored_typed_exprs = new hashtbl_lookup;
 		cached_macros = new hashtbl_lookup;
@@ -832,6 +842,8 @@ let create compilation_step cs version args display_mode =
 		has_error = false;
 		report_mode = RMNone;
 		is_macro_context = false;
+		hxb_reader_stats = HxbReader.create_hxb_reader_stats ();
+		hxb_writer_stats = HxbWriter.create_hxb_writer_stats ();
 	} in
 	com
 
@@ -839,6 +851,8 @@ let is_diagnostics com = match com.report_mode with
 	| RMLegacyDiagnostics _ | RMDiagnostics _ -> true
 	| _ -> false
 
+let is_compilation com = com.display.dms_kind = DMNone && not (is_diagnostics com)
+
 let disable_report_mode com =
 	let old = com.report_mode in
 	com.report_mode <- RMNone;
@@ -852,12 +866,16 @@ let clone com is_macro_context =
 	{ com with
 		cache = None;
 		basic = { t with
+			tvoid = mk_mono();
 			tint = mk_mono();
 			tfloat = mk_mono();
 			tbool = mk_mono();
 			tstring = mk_mono();
 		};
-		main_class = None;
+		main = {
+			main_class = None;
+			main_expr = None;
+		};
 		features = Hashtbl.create 0;
 		callbacks = new compiler_callbacks;
 		display_information = {
@@ -871,13 +889,15 @@ let clone com is_macro_context =
 		};
 		native_libs = create_native_libs();
 		is_macro_context = is_macro_context;
-		file_lookup_cache = new hashtbl_lookup;
-		readdir_cache = new hashtbl_lookup;
 		parser_cache = new hashtbl_lookup;
 		module_to_file = new hashtbl_lookup;
 		overload_cache = new hashtbl_lookup;
 		module_lut = new module_lut;
+		hxb_reader_stats = HxbReader.create_hxb_reader_stats ();
+		hxb_writer_stats = HxbWriter.create_hxb_writer_stats ();
 		std = null_class;
+		empty_class_path = new ClassPath.directory_class_path "" User;
+		class_paths = new ClassPaths.class_paths;
 	}
 
 let file_time file = Extc.filetime file
@@ -1006,9 +1026,15 @@ let rec has_feature com f =
 				(match List.find (fun t -> t_path t = path && not (Meta.has Meta.RealPath (t_infos t).mt_meta)) com.types with
 				| t when field = "*" ->
 					not (has_dce com) ||
-					(match t with TAbstractDecl a -> Meta.has Meta.ValueUsed a.a_meta | _ -> Meta.has Meta.Used (t_infos t).mt_meta)
+					begin match t with
+						| TClassDecl c ->
+							has_class_flag c CUsed;
+						| TAbstractDecl a ->
+							Meta.has Meta.ValueUsed a.a_meta
+						| _ -> Meta.has Meta.Used (t_infos t).mt_meta
+					end;
 				| TClassDecl c when (has_class_flag c CExtern) && (com.platform <> Js || cl <> "Array" && cl <> "Math") ->
-					not (has_dce com) || Meta.has Meta.Used (try PMap.find field c.cl_statics with Not_found -> PMap.find field c.cl_fields).cf_meta
+					not (has_dce com) || has_class_field_flag (try PMap.find field c.cl_statics with Not_found -> PMap.find field c.cl_fields) CfUsed
 				| TClassDecl c ->
 					PMap.exists field c.cl_statics || PMap.exists field c.cl_fields
 				| _ ->
@@ -1031,104 +1057,8 @@ let platform_name_macro com =
 	if defined com Define.Macro then "macro"
 	else platform_name com.platform
 
-let remove_extension file =
-	try String.sub file 0 (String.rindex file '.')
-	with Not_found -> file
-
-let extension file =
-	try
-		let dot_pos = String.rindex file '.' in
-		String.sub file dot_pos (String.length file - dot_pos)
-	with Not_found -> file
-
-let cache_directory ctx class_path dir f_dir =
-	let platform_ext = "." ^ (platform_name_macro ctx)
-	and is_loading_core_api = defined ctx Define.CoreApi in
-	let dir_listing =
-		try Some (Sys.readdir dir);
-		with Sys_error _ -> None
-	in
-	ctx.readdir_cache#add (class_path,dir) dir_listing;
-	(*
-		This function is invoked for each file in the `dir`.
-		Each file is checked if it's specific for current platform
-		(e.g. ends with `.js.hx` while compiling for JS).
-		If it's not platform-specific:
-			Check the lookup cache and if the file is not there store full file path in the cache.
-		If the file is platform-specific:
-			Store the full file path in the lookup cache probably replacing the cached path to a
-			non-platform-specific file.
-	*)
-	let prepare_file file_own_name =
-		let relative_to_classpath = if f_dir = "." then file_own_name else f_dir ^ "/" ^ file_own_name in
-		(* `representation` is how the file is referenced to. E.g. when it's deduced from a module path. *)
-		let is_platform_specific,representation =
-			(* Platform specific file extensions are not allowed for loading @:coreApi types. *)
-			if is_loading_core_api then
-				false,relative_to_classpath
-			else begin
-				let ext = extension relative_to_classpath in
-				let second_ext = extension (remove_extension relative_to_classpath) in
-				(* The file contains double extension and the secondary one matches current platform *)
-				if platform_ext = second_ext then
-					true,(remove_extension (remove_extension relative_to_classpath)) ^ ext
-				else
-					false,relative_to_classpath
-			end
-		in
-		(*
-			Store current full path for `representation` if
-			- we're loading @:coreApi
-			- or this is a platform-specific file for `representation`
-			- this `representation` was never found before
-		*)
-		if is_loading_core_api || is_platform_specific || not (ctx.file_lookup_cache#mem representation) then begin
-			let full_path = if dir = "." then file_own_name else dir ^ "/" ^ file_own_name in
-			ctx.file_lookup_cache#add representation (Some full_path);
-		end
-	in
-	Option.may (Array.iter prepare_file) dir_listing
-
-let find_file ctx ?(class_path=ctx.class_path) f =
-	try
-		match ctx.file_lookup_cache#find f with
-		| None -> raise Exit
-		| Some f -> f
-	with
-	| Exit ->
-		raise Not_found
-	| Not_found when Path.is_absolute_path f ->
-		ctx.file_lookup_cache#add f (Some f);
-		f
-	| Not_found ->
-		let f_dir = Filename.dirname f in
-		let rec loop had_empty = function
-			| [] when had_empty -> raise Not_found
-			| [] -> loop true [""]
-			| p :: l ->
-				let file = p ^ f in
-				let dir = Filename.dirname file in
-				(* If we have seen the directory before, we can assume that the file isn't in there because the else case
-				   below would have added it to `file_lookup_cache`, which we check before we get here. *)
-				if ctx.readdir_cache#mem (p,dir) then
-					loop (had_empty || p = "") l
-				else begin
-					cache_directory ctx p dir f_dir;
-					(* Caching might have located the file we're looking for, so check the lookup cache again. *)
-					try
-						begin match ctx.file_lookup_cache#find f with
-						| Some f -> f
-						| None -> raise Not_found
-						end
-					with Not_found ->
-						loop (had_empty || p = "") l
-				end
-		in
-		let r = try Some (loop false class_path) with Not_found -> None in
-		ctx.file_lookup_cache#add f r;
-		match r with
-		| None -> raise Not_found
-		| Some f -> f
+let find_file ctx f =
+	(ctx.class_paths#find_file f).file
 
 (* let find_file ctx f =
 	let timer = Timer.timer ["find_file"] in
@@ -1257,7 +1187,7 @@ let adapt_defines_to_macro_context defines =
 		defines_signature = None
 	} in
 	Define.define macro_defines Define.Macro;
-	Define.raw_define macro_defines (platform_name !Globals.macro_platform);
+	Define.raw_define macro_defines (platform_name Eval);
 	macro_defines
 
 let adapt_defines_to_display_context defines =
@@ -1277,6 +1207,6 @@ let get_entry_point com =
 			| Some c when (PMap.mem "main" c.cl_statics) -> c
 			| _ -> Option.get (ExtList.List.find_map (fun t -> match t with TClassDecl c when c.cl_path = path -> Some c | _ -> None) m.m_types)
 		in
-		let e = Option.get com.main in (* must be present at this point *)
+		let e = Option.get com.main.main_expr in (* must be present at this point *)
 		(snd path, c, e)
-	) com.main_class
+	) com.main.main_class

+ 28 - 9
src/context/commonCache.ml

@@ -26,7 +26,15 @@ end
 
 let handle_native_lib com lib =
 	com.native_libs.all_libs <- lib#get_file_path :: com.native_libs.all_libs;
-	com.load_extern_type <- com.load_extern_type @ [lib#get_file_path,lib#build];
+	let build path =
+		(* The first build has to load, afterwards we install a direct lib#build call. *)
+		lib#load;
+		com.load_extern_type <- List.map (fun (name,f) ->
+			name,if name = lib#get_file_path then lib#build else f
+		) com.load_extern_type;
+		lib#build path;
+	in
+	com.load_extern_type <- com.load_extern_type @ [lib#get_file_path,build];
 	if not (Define.raw_defined com.defines "haxe.noNativeLibsCache") then begin
 		let cs = com.cs in
 		let init () =
@@ -54,7 +62,7 @@ let handle_native_lib com lib =
 					name,if name = lib#get_file_path then build else f
 				) com.load_extern_type
 			| None ->
-				lib#load
+				()
 		)
 	end else
 		(* Offline mode, just read library as usual. *)
@@ -69,24 +77,35 @@ let get_cache com = match com.Common.cache with
 	| Some cache ->
 		cache
 
+let get_cache_sign com = match com.Common.cache with
+	| None -> Define.get_signature com.defines
+	| Some cache -> cache#get_sign
+
 let rec cache_context cs com =
 	let cc = get_cache com in
 	let sign = Define.get_signature com.defines in
+	let anon_identification = new Tanon_identification.tanon_identification in
 	let cache_module m =
 		(* If we have a signature mismatch, look-up cache for module. Physical equality check is fine as a heueristic. *)
-		let cc = if m.m_extra.m_sign == sign then cc else cs#get_context m.m_extra.m_sign in
-		cc#cache_module m.m_path m;
+		let cc = if m.m_extra.m_sign = sign then cc else cs#get_context m.m_extra.m_sign in
+		let warn w s p = com.warning w com.warning_options s p in
+		cc#cache_module warn anon_identification com.hxb_writer_stats m.m_path m;
 	in
 	List.iter cache_module com.modules;
-	match com.get_macros() with
-	| None -> ()
-	| Some com -> cache_context cs com
+	begin match com.get_macros() with
+		| None -> ()
+		| Some com -> cache_context cs com
+	end;
+	if Define.raw_defined com.defines "hxb.stats" then begin
+		HxbReader.dump_stats (platform_name com.platform) com.hxb_reader_stats;
+		HxbWriter.dump_stats (platform_name com.platform) com.hxb_writer_stats
+	end
 
 let maybe_add_context_sign cs com desc =
 	let sign = Define.get_signature com.defines in
-	ignore(cs#add_info sign desc com.platform com.class_path com.defines)
+	ignore(cs#add_info sign desc com.platform com.class_paths com.defines)
 
 let lock_signature com name =
 	let cs = com.cs in
 	maybe_add_context_sign cs com name;
-	com.cache <- Some (get_cache com)
+	com.cache <- Some (get_cache com)

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

@@ -107,7 +107,7 @@ let run com =
 		| TClassDecl c when not (Meta.has Meta.Deprecated c.cl_meta) ->
 			let dctx = {dctx with class_meta = c.cl_meta; curmod = c.cl_module} in
 			(match c.cl_constructor with None -> () | Some cf -> run_on_field dctx cf);
-			(match c.cl_init with None -> () | Some e -> run_on_expr dctx e);
+			(match TClass.get_cl_init c with None -> () | Some e -> run_on_expr dctx e);
 			List.iter (run_on_field dctx) c.cl_ordered_statics;
 			List.iter (run_on_field dctx) c.cl_ordered_fields;
 		| _ ->

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

@@ -121,7 +121,7 @@ let collect_diagnostics dctx com =
 				ParserEntry.is_true (ParserEntry.eval defines e)
 			in
 			Hashtbl.iter (fun file_key cfile ->
-				if DisplayPosition.display_position#is_in_file (com.file_keys#get cfile.c_file_path) then begin
+				if DisplayPosition.display_position#is_in_file (com.file_keys#get cfile.c_file_path.file) then begin
 					let dead_blocks = cfile.c_pdi.pd_dead_blocks in
 					let dead_blocks = List.filter (fun (_,e) -> not (is_true display_defines e)) dead_blocks in
 					try

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

@@ -54,9 +54,9 @@ let rec display_type ctx t p =
 	try
 		display_module_type ctx (module_type_of_type t) p
 	with Exit ->
-		match follow t,follow !t_dynamic_def with
+		match follow t,follow ctx.g.t_dynamic_def with
 		| _,TDynamic _ -> () (* sanity check in case it's still t_dynamic *)
-		| TDynamic _,_ -> display_type ctx !t_dynamic_def p
+		| TDynamic _,_ -> display_type ctx ctx.g.t_dynamic_def p
 		| _ ->
 			match dm.dms_kind with
 			| DMHover ->
@@ -77,14 +77,14 @@ let check_display_type ctx t ptp =
 	add_type_hint();
 	maybe_display_type()
 
-let raise_position_of_type t =
+let raise_position_of_type ctx t =
 	let mt =
 		let rec follow_null t =
 			match t with
 				| TMono r -> (match r.tm_type with None -> raise_positions [null_pos] | Some t -> follow_null t)
 				| TLazy f -> follow_null (lazy_type f)
 				| TAbstract({a_path = [],"Null"},[t]) -> follow_null t
-				| TDynamic _ -> !t_dynamic_def
+				| TDynamic _ -> ctx.g.t_dynamic_def
 				| _ -> t
 		in
 		try
@@ -96,7 +96,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
+	| DMTypeDefinition -> raise_position_of_type ctx v.v_type
 	| 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
@@ -105,7 +105,7 @@ 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
+	| DMTypeDefinition -> raise_position_of_type ctx cf.cf_type
 	| DMUsage _ | DMImplementation ->
 		let name,kind = match cf.cf_name,origin with
 			| "new",(Self (TClassDecl c) | Parent(TClassDecl c)) ->
@@ -136,7 +136,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
+	| DMTypeDefinition -> raise_position_of_type ctx ef.ef_type
 	| 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

+ 43 - 42
src/context/display/displayFields.ml

@@ -39,9 +39,9 @@ let collect_static_extensions ctx items e p =
 	let opt_type t =
 		match t with
 		| TLazy f ->
-			return_partial_type := true;
+			ctx.g.return_partial_type <- true;
 			let t = lazy_type f in
-			return_partial_type := false;
+			ctx.g.return_partial_type <- false;
 			t
 		| _ ->
 			t
@@ -250,50 +250,51 @@ let collect ctx e_ast e dk with_type p =
 					end
 				| _ -> items
 			in
-			(* Anon own fields *)
-			PMap.foldi (fun name cf acc ->
-				if is_new_item acc name then begin
-					let allow_static_abstract_access c cf =
+			let iter_fields origin fields f_allow f_make =
+				let items = PMap.fold (fun cf acc ->
+					if is_new_item acc cf.cf_name && f_allow cf then begin
+						let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) cf.cf_type in
+						PMap.add cf.cf_name (f_make (CompletionClassField.make cf CFSMember origin true) (cf.cf_type,ct)) acc
+					end else
+						acc
+				) fields items in
+				items
+			in
+			begin match !(an.a_status) with
+				| ClassStatics ({cl_kind = KAbstractImpl a} as c) ->
+					Display.merge_core_doc ctx (TClassDecl c);
+					let f_allow cf =
 						should_access c cf false &&
 						(not (has_class_field_flag cf CfImpl) || has_class_field_flag cf CfEnum)
 					in
-					let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) cf.cf_type in
-					let add origin make_field =
-						PMap.add name (make_field (CompletionClassField.make cf CFSMember origin true) (cf.cf_type,ct)) acc
+					let f_make ccf =
+						if has_class_field_flag ccf.CompletionClassField.field CfEnum then
+							make_ci_enum_abstract_field a ccf
+						else
+							make_ci_class_field ccf
 					in
-					match !(an.a_status) with
-						| ClassStatics ({cl_kind = KAbstractImpl a} as c) ->
-							if allow_static_abstract_access c cf then
-								let make = if has_class_field_flag cf CfEnum then
-										(make_ci_enum_abstract_field a)
-									else
-										make_ci_class_field
-								in
-								add (Self (TAbstractDecl a)) make
-							else
-								acc;
-						| ClassStatics c ->
-							Display.merge_core_doc ctx (TClassDecl c);
-							if should_access c cf true then add (Self (TClassDecl c)) make_ci_class_field else acc;
-						| EnumStatics en ->
-							let ef = PMap.find name en.e_constrs in
-							PMap.add name (make_ci_enum_field (CompletionEnumField.make ef (Self (TEnumDecl en)) true) (cf.cf_type,ct)) acc
-						| AbstractStatics a ->
-							Display.merge_core_doc ctx (TAbstractDecl a);
-							let check = match a.a_impl with
-								| None -> true
-								| Some c -> allow_static_abstract_access c cf
-							in
-							if check then add (Self (TAbstractDecl a)) make_ci_class_field else acc;
-						| _ ->
-							let origin = match t with
-								| TType(td,_) -> Self (TTypeDecl td)
-								| _ -> AnonymousStructure an
-							in
-							add origin make_ci_class_field;
-				end else
-					acc
-			) an.a_fields items
+					iter_fields (Self (TClassDecl c)) c.cl_statics f_allow f_make
+				| ClassStatics c ->
+					Display.merge_core_doc ctx (TClassDecl c);
+					let f_allow cf = should_access c cf true in
+					iter_fields (Self (TClassDecl c)) c.cl_statics f_allow make_ci_class_field
+				| AbstractStatics ({a_impl = Some c} as a) ->
+					Display.merge_core_doc ctx (TAbstractDecl a);
+					let f_allow cf = should_access c cf true in
+					iter_fields (Self (TAbstractDecl a)) c.cl_statics f_allow make_ci_class_field
+				| EnumStatics en ->
+					PMap.fold (fun ef acc ->
+						let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta ef.ef_meta) ef.ef_type in
+						let cef = CompletionEnumField.make ef (Self (TEnumDecl en)) true in
+						PMap.add ef.ef_name (make_ci_enum_field cef (ef.ef_type,ct)) acc
+					) en.e_constrs items
+				| _ ->
+					let origin = match t with
+						| TType(td,_) -> Self (TTypeDecl td)
+						| _ -> AnonymousStructure an
+					in
+					iter_fields origin an.a_fields (fun _ -> true) make_ci_class_field
+			end
 		| TFun (args,ret) ->
 			(* A function has no field except the magic .bind one. *)
 			if is_new_item items "bind" then begin

+ 57 - 7
src/context/display/displayJson.ml

@@ -104,6 +104,55 @@ class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationCache.t)
 		end
 end
 
+class hxb_reader_api_com
+	~(headers_only : bool)
+	(com : Common.context)
+	(cc : CompilationCache.context_cache)
+= object(self)
+	method make_module (path : path) (file : string) =
+		let mc = cc#get_hxb_module path in
+		{
+			m_id = mc.mc_id;
+			m_path = path;
+			m_types = [];
+			m_statics = None;
+			m_extra = mc.mc_extra
+		}
+
+	method add_module (m : module_def) =
+		com.module_lut#add m.m_path m;
+
+	method resolve_type (pack : string list) (mname : string) (tname : string) =
+		let path = (pack,mname) in
+		let m = self#find_module path in
+		List.find (fun t -> snd (t_path t) = tname) m.m_types
+
+	method resolve_module (path : path) =
+		self#find_module path
+
+	method find_module (m_path : path) =
+		try
+			com.module_lut#find m_path
+		with Not_found -> try
+			cc#find_module m_path
+		with Not_found ->
+			let mc = cc#get_hxb_module m_path in
+			let reader = new HxbReader.hxb_reader mc.mc_path com.hxb_reader_stats in
+			fst (reader#read_chunks_until (self :> HxbReaderApi.hxb_reader_api) mc.mc_chunks (if headers_only then MTF else EOM))
+
+	method basic_types =
+		com.basic
+
+	method get_var_id (i : int) =
+		i
+
+	method read_expression_eagerly (cf : tclass_field) =
+		false
+end
+
+let find_module ~(headers_only : bool) com cc path =
+	(new hxb_reader_api_com ~headers_only com cc)#find_module path
+
 type handler_context = {
 	com : Common.context;
 	jsonrpc : jsonrpc_handler;
@@ -280,9 +329,10 @@ let handler =
 		"server/modules", (fun hctx ->
 			let sign = Digest.from_hex (hctx.jsonrpc#get_string_param "signature") in
 			let cc = hctx.display#get_cs#get_context sign in
+			let open HxbData in
 			let l = Hashtbl.fold (fun _ m acc ->
-				if m.m_extra.m_kind <> MFake then jstring (s_type_path m.m_path) :: acc else acc
-			) cc#get_modules [] in
+				if m.mc_extra.m_kind <> MFake then jstring (s_type_path m.mc_path) :: acc else acc
+			) cc#get_hxb [] in
 			hctx.send_result (jarray l)
 		);
 		"server/module", (fun hctx ->
@@ -291,11 +341,11 @@ let handler =
 			let cs = hctx.display#get_cs in
 			let cc = cs#get_context sign in
 			let m = try
-				cc#find_module path
+				find_module ~headers_only:true hctx.com cc path
 			with Not_found ->
 				hctx.send_error [jstring "No such module"]
 			in
-			hctx.send_result (generate_module cs cc m)
+			hctx.send_result (generate_module (cc#get_hxb) (find_module ~headers_only:true hctx.com cc) m)
 		);
 		"server/type", (fun hctx ->
 			let sign = Digest.from_hex (hctx.jsonrpc#get_string_param "signature") in
@@ -303,7 +353,7 @@ let handler =
 			let typeName = hctx.jsonrpc#get_string_param "typeName" in
 			let cc = hctx.display#get_cs#get_context sign in
 			let m = try
-				cc#find_module path
+				find_module ~headers_only:true hctx.com cc path
 			with Not_found ->
 				hctx.send_error [jstring "No such module"]
 			in
@@ -355,7 +405,7 @@ let handler =
 			let key = hctx.com.file_keys#get file in
 			let cs = hctx.display#get_cs in
 			List.iter (fun cc ->
-				Hashtbl.replace cc#get_removed_files key file
+				Hashtbl.replace cc#get_removed_files key (ClassPaths.create_resolved_file file hctx.com.empty_class_path)
 			) cs#get_contexts;
 			hctx.send_result (jstring file);
 		);
@@ -366,7 +416,7 @@ let handler =
 			let files = List.sort (fun (file1,_) (file2,_) -> compare file1 file2) files in
 			let files = List.map (fun (fkey,cfile) ->
 				jobject [
-					"file",jstring cfile.c_file_path;
+					"file",jstring cfile.c_file_path.file;
 					"time",jfloat cfile.c_time;
 					"pack",jstring (String.concat "." cfile.c_package);
 					"moduleName",jopt jstring cfile.c_module_name;

+ 3 - 4
src/context/display/displayPath.ml

@@ -26,14 +26,14 @@ module TypePathHandler = struct
 			| x :: l ->
 				(try
 					match PMap.find x com.package_rules with
-					| Directory d -> d :: l
 					| Remap s -> s :: l
 					| _ -> p
 				with
 					Not_found -> p)
 			| _ -> p
 		) in
-		List.iter (fun path ->
+		com.class_paths#iter (fun path ->
+			let path = path#path in
 			let dir = path ^ String.concat "/" p in
 			let r = (try Sys.readdir dir with _ -> [||]) in
 			Array.iter (fun f ->
@@ -47,7 +47,6 @@ module TypePathHandler = struct
 									match PMap.find f com.package_rules with
 									| Forbidden -> ()
 									| Remap f -> packages := f :: !packages
-									| Directory _ -> raise Not_found
 								with Not_found ->
 									packages := f :: !packages
 						else
@@ -61,7 +60,7 @@ module TypePathHandler = struct
 						if String.length c < 2 || String.sub c (String.length c - 2) 2 <> "__" then classes := c :: !classes;
 				end;
 			) r;
-		) com.class_path;
+		);
 		let process_lib lib =
 			List.iter (fun (path,name) ->
 				if path = p then classes := name :: !classes else

+ 15 - 4
src/context/display/displayTexpr.ml

@@ -170,10 +170,21 @@ let check_display_file ctx cs =
 			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 cfile.c_decls m
-			end
+			let m = try
+				ctx.com.module_lut#find path
+			with Not_found ->
+				begin match !TypeloadModule.type_module_hook ctx path null_pos with
+				| NoModule | BadModule _ -> raise Not_found
+				| BinaryModule mc ->
+					let api = (new TypeloadModule.hxb_reader_api_typeload ctx TypeloadModule.load_module' p :> HxbReaderApi.hxb_reader_api) in
+					let reader = new HxbReader.hxb_reader path ctx.com.hxb_reader_stats in
+					let m = reader#read_chunks api mc.mc_chunks in
+					m
+				| GoodModule m ->
+					m
+				end
+			in
+			check_display_module ctx cfile.c_decls m
 		with Not_found ->
 			let fkey = DisplayPosition.display_position#get_file_key in
 			(* force parsing again : if the completion point have been changed *)

+ 32 - 8
src/context/display/displayToplevel.ml

@@ -74,7 +74,6 @@ class explore_class_path_task com checked recursive f_pack f_module dir pack = o
 						begin try
 							begin match PMap.find file com.package_rules with
 								| Forbidden | Remap _ -> ()
-								| _ -> raise Not_found
 							end
 						with Not_found ->
 							f_pack (List.rev pack,file);
@@ -112,8 +111,12 @@ let explore_class_paths com timer class_paths recursive f_pack f_module =
 	let cs = com.cs in
 	let t = Timer.timer (timer @ ["class path exploration"]) in
 	let checked = Hashtbl.create 0 in
-	let tasks = List.map (fun dir ->
-		new explore_class_path_task com checked recursive f_pack f_module dir []
+	let tasks = ExtList.List.filter_map (fun path ->
+		match path#get_directory_path with
+			| Some path ->
+				Some (new explore_class_path_task com checked recursive f_pack f_module path [])
+			| None ->
+				None
 	) class_paths in
 	let task = new arbitrary_task ["explore"] 50 (fun () ->
 		List.iter (fun task -> task#run) tasks
@@ -122,10 +125,10 @@ let explore_class_paths com timer class_paths recursive f_pack f_module =
 	t()
 
 let read_class_paths com timer =
-	explore_class_paths com timer (List.filter ((<>) "") com.class_path) true (fun _ -> ()) (fun file path ->
+	explore_class_paths com timer (com.class_paths#filter (fun cp -> cp#path <> "")) true (fun _ -> ()) (fun file path ->
 		(* Don't parse the display file as that would maybe overwrite the content from stdin with the file contents. *)
 		if not (DisplayPosition.display_position#is_in_file (com.file_keys#get file)) then begin
-			let file,_,pack,_ = Display.parse_module' com path Globals.null_pos in
+			let rfile,_,pack,_ = Display.parse_module' com path Globals.null_pos in
 			if pack <> fst path then begin
 				let file_key = com.file_keys#get file in
 				(CommonCache.get_cache com)#remove_file_for_real file_key
@@ -222,7 +225,7 @@ let is_pack_visible pack =
 	not (List.exists (fun s -> String.length s > 0 && s.[0] = '_') pack)
 
 let collect ctx tk with_type sort =
-	let t = Timer.timer ["display";"toplevel"] in
+	let t = Timer.timer ["display";"toplevel collect"] in
 	let cctx = CollectionContext.create ctx in
 	let curpack = fst ctx.curclass.cl_path in
 	(* Note: This checks for the explicit `ServerConfig.legacy_completion` setting instead of using
@@ -295,10 +298,12 @@ let collect ctx tk with_type sort =
 	| TKType | TKOverride -> ()
 	| TKExpr p | TKPattern p | TKField p ->
 		(* locals *)
+		let t = Timer.timer ["display";"toplevel collect";"locals"] in
 		PMap.iter (fun _ v ->
 			if not (is_gen_local v) then
 				add (make_ci_local v (tpair ~values:(get_value_meta v.v_meta) v.v_type)) (Some v.v_name)
 		) ctx.locals;
+		t();
 
 		let add_field scope origin cf =
 			let origin,cf = match origin with
@@ -323,6 +328,8 @@ let collect ctx tk with_type sort =
 		let maybe_add_field scope origin cf =
 			if not (Meta.has Meta.NoCompletion cf.cf_meta) then add_field scope origin cf
 		in
+
+		let t = Timer.timer ["display";"toplevel collect";"fields"] in
 		(* member fields *)
 		if ctx.curfun <> FunStatic then begin
 			let all_fields = Type.TClass.get_all_fields ctx.curclass (extract_param_types ctx.curclass.cl_params) in
@@ -350,7 +357,9 @@ let collect ctx tk with_type sort =
 		| _ ->
 			List.iter (maybe_add_field CFSStatic (Self (TClassDecl ctx.curclass))) ctx.curclass.cl_ordered_statics
 		end;
+		t();
 
+		let t = Timer.timer ["display";"toplevel collect";"enum ctors"] in
 		(* enum constructors *)
 		let rec enum_ctors t =
 			match t with
@@ -385,7 +394,9 @@ let collect ctx tk with_type sort =
 				(try enum_ctors (module_type_of_type (follow t)) with Exit -> ())
 			| _ -> ()
 		end;
+		t();
 
+		let t = Timer.timer ["display";"toplevel collect";"globals"] in
 		(* imported globals *)
 		PMap.iter (fun name (mt,s,_) ->
 			try
@@ -415,7 +426,9 @@ let collect ctx tk with_type sort =
 			with Not_found ->
 				()
 		) ctx.m.import_resolution#extract_field_imports;
+		t();
 
+		let t = Timer.timer ["display";"toplevel collect";"rest"] in
 		(* literals *)
 		add (make_ci_literal "null" (tpair t_dynamic)) (Some "null");
 		add (make_ci_literal "true" (tpair ctx.com.basic.tbool)) (Some "true");
@@ -445,7 +458,8 @@ let collect ctx tk with_type sort =
 
 			(* builtins *)
 			add (make_ci_literal "trace" (tpair (TFun(["value",false,t_dynamic],ctx.com.basic.tvoid)))) (Some "trace")
-		end
+		end;
+		t()
 	end;
 
 	(* type params *)
@@ -459,6 +473,7 @@ let collect ctx tk with_type sort =
 	(* module imports *)
 	List.iter add_type (List.rev_map fst ctx.m.import_resolution#extract_type_imports); (* reverse! *)
 
+	let t_syntax = Timer.timer ["display";"toplevel collect";"syntax"] in
 	(* types from files *)
 	let cs = ctx.com.cs in
 	(* online: iter context files *)
@@ -476,7 +491,7 @@ let collect ctx tk with_type sort =
 		| s :: sl -> add_package (List.rev sl,s)
 	in
 	List.iter (fun ((file_key,cfile),_) ->
-		let module_name = CompilationCache.get_module_name_of_cfile cfile.c_file_path cfile in
+		let module_name = CompilationCache.get_module_name_of_cfile cfile.c_file_path.file cfile in
 		let dot_path = s_type_path (cfile.c_package,module_name) in
 		(* In legacy mode we only show toplevel types. *)
 		if is_legacy_completion && cfile.c_package <> [] then begin
@@ -491,6 +506,9 @@ let collect ctx tk with_type sort =
 			if process_decls cfile.c_package module_name cfile.c_decls then check_package cfile.c_package;
 		end
 	) files;
+	t_syntax();
+
+	let t_native_lib = Timer.timer ["display";"toplevel collect";"native lib"] in
 	List.iter (fun file ->
 		match cs#get_native_lib file with
 		| Some lib ->
@@ -500,13 +518,19 @@ let collect ctx tk with_type sort =
 		| None ->
 			()
 	) ctx.com.native_libs.all_libs;
+	t_native_lib();
 
+	let t_packages = Timer.timer ["display";"toplevel collect";"packages"] in
 	(* packages *)
 	Hashtbl.iter (fun path _ ->
 		let full_pack = fst path @ [snd path] in
 		if is_pack_visible full_pack then add (make_ci_package path []) (Some (snd path))
 	) packages;
+	t_packages();
+
+	t();
 
+	let t = Timer.timer ["display";"toplevel sorting"] in
 	(* sorting *)
 	let l = DynArray.to_list cctx.items in
 	let l = if is_legacy_completion then

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

@@ -152,7 +152,7 @@ let init_import ctx path mode p =
 				| Some(newname,pname) ->
 					let mt = get_type tname in
 					check_alias mt newname pname;
-					ctx.m.import_resolution#add (module_type_resolution mt (Some newname) p2)
+					ctx.m.import_resolution#add (module_type_resolution mt (Some newname) p)
 				end
 			| [tsub,p2] ->
 				let pu = punion p1 p2 in

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

@@ -167,7 +167,7 @@ let explore_uncached_modules tctx cs symbols =
 	let modules = cc#get_modules in
 	let t = Timer.timer ["display";"references";"candidates"] in
 	let acc = Hashtbl.fold (fun file_key cfile acc ->
-		let module_name = get_module_name_of_cfile cfile.c_file_path cfile in
+		let module_name = get_module_name_of_cfile cfile.c_file_path.file cfile in
 		if Hashtbl.mem modules (cfile.c_package,module_name) then
 			acc
 		else try

+ 0 - 11
src/context/feature.ml

@@ -1,11 +0,0 @@
-open Ast
-open Type
-open Error
-
-let rec check_if_feature = function
-	| [] -> []
-	| (Meta.IfFeature,el,_) :: _ -> List.map (fun (e,p) -> match e with EConst (String(s,_)) -> s | _ -> raise_typing_error "String expected" p) el
-	| _ :: l -> check_if_feature l
-
-let set_feature m cf_ref s =
-	m.m_extra.m_if_feature <- (s, cf_ref) :: m.m_extra.m_if_feature

+ 10 - 6
src/context/memory.ml

@@ -38,9 +38,10 @@ let rec scan_module_deps cs m h =
 		()
 	else begin
 		Hashtbl.add h m.m_id m;
-		PMap.iter (fun _ (sign,mpath) ->
-			let m = (cs#get_context sign)#find_module mpath in
-			scan_module_deps cs m h) m.m_extra.m_deps
+		PMap.iter (fun _ mdep ->
+			let m = (cs#get_context mdep.md_sign)#find_module mdep.md_path in
+			scan_module_deps cs m h
+		) m.m_extra.m_deps
 	end
 
 let module_sign key md =
@@ -168,6 +169,9 @@ let get_memory_json (cs : CompilationCache.t) mreq =
 				"size",jint (mem_size cache_mem.(1));
 				"list",jarray l;
 			];
+			"binaryCache",jobject [
+				"size",jint (mem_size cache_mem.(2));
+			];
 		]
 	| MModule(sign,path) ->
 		let cc = cs#get_context sign in
@@ -274,9 +278,9 @@ let display_memory com =
 			());
 		if verbose then begin
 			print (Printf.sprintf "      %d total deps" (List.length deps));
-			PMap.iter (fun _ (sign,mpath) ->
-				let md = (com.cs#get_context sign)#find_module mpath in
-				print (Printf.sprintf "      dep %s%s" (s_type_path mpath) (module_sign key md));
+			PMap.iter (fun _ mdep ->
+				let md = (com.cs#get_context mdep.md_sign)#find_module mdep.md_path in
+				print (Printf.sprintf "      dep %s%s" (s_type_path mdep.md_path) (module_sign key md));
 			) m.m_extra.m_deps;
 		end;
 		flush stdout

+ 6 - 1
src/context/nativeLibraryHandler.ml

@@ -17,7 +17,6 @@
 	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *)
 
-open Globals
 open Common
 open CompilationContext
 
@@ -39,3 +38,9 @@ let add_native_lib com lib =
 			) (Sys.readdir file))
 		else
 			add file
+	| HxbLib ->
+		let hxb_lib = HxbLib.create_hxb_lib com file in
+		com.hxb_libs <- hxb_lib :: com.hxb_libs;
+		(fun () ->
+			hxb_lib#load
+		)

+ 63 - 59
src/context/typecore.ml

@@ -60,6 +60,12 @@ type typer_pass =
 	| PForce				(* usually ensure that lazy have been evaluated *)
 	| PFinal				(* not used, only mark for finalize *)
 
+let all_typer_passes = [
+	PBuildModule;PBuildClass;PConnectField;PTypeField;PCheckConstraint;PForce;PFinal
+]
+
+let all_typer_passes_length = List.length all_typer_passes
+
 type typer_module = {
 	curmod : module_def;
 	import_resolution : resolution_list;
@@ -69,11 +75,6 @@ type typer_module = {
 	mutable import_statements : import list;
 }
 
-type delay = {
-	delay_pass : typer_pass;
-	delay_functions : (unit -> unit) list;
-}
-
 type build_kind =
 	| BuildNormal
 	| BuildGeneric of tclass
@@ -93,8 +94,13 @@ type macro_result =
 	| MError
 	| MMacroInMacro
 
+type typer_pass_tasks = {
+	mutable tasks : (unit -> unit) list;
+}
+
 type typer_globals = {
-	mutable delayed : delay list;
+	mutable delayed : typer_pass_tasks Array.t;
+	mutable delayed_min_index : int;
 	mutable debug_delayed : (typer_pass * ((unit -> unit) * (string * string list) * typer) list) list;
 	doinline : bool;
 	retain_meta : bool;
@@ -109,6 +115,9 @@ type typer_globals = {
 	mutable type_hints : (module_def_display * pos * t) list;
 	mutable load_only_cached_modules : bool;
 	functional_interface_lut : (path,tclass_field) lookup;
+	mutable return_partial_type : bool;
+	mutable build_count : int;
+	mutable t_dynamic_def : Type.t;
 	(* api *)
 	do_macro : typer -> macro_mode -> path -> string -> expr list -> pos -> macro_result;
 	do_load_macro : typer -> bool -> path -> string -> pos -> ((string * bool * t) list * t * tclass * Type.tclass_field);
@@ -202,6 +211,12 @@ type dot_path_part = {
 	pos : pos
 }
 
+type find_module_result =
+	| GoodModule of module_def
+	| BadModule of module_skip_reason
+	| BinaryModule of HxbData.module_cache
+	| NoModule
+
 let make_build_info kind path params extern apply = {
 	build_kind = kind;
 	build_path = path;
@@ -216,8 +231,6 @@ exception WithTypeError of error
 
 let memory_marker = [|Unix.time()|]
 
-let locate_macro_error = ref true
-
 let make_call_ref : (typer -> texpr -> texpr list -> t -> ?force_inline:bool -> pos -> texpr) ref = ref (fun _ _ _ _ ?force_inline:bool _ -> die "" __LOC__)
 let type_expr_ref : (?mode:access_mode -> typer -> expr -> WithType.t -> texpr) ref = ref (fun ?(mode=MGet) _ _ _ -> die "" __LOC__)
 let type_block_ref : (typer -> expr list -> WithType.t -> pos -> texpr) ref = ref (fun _ _ _ _ -> die "" __LOC__)
@@ -317,7 +330,7 @@ let add_local ctx k n t p =
 			begin try
 				let v' = PMap.find n ctx.locals in
 				(* ignore std lib *)
-				if not (List.exists (ExtLib.String.starts_with p.pfile) ctx.com.std_path) then begin
+				if not (List.exists (fun path -> ExtLib.String.starts_with p.pfile (path#path)) ctx.com.class_paths#get_std_paths) then begin
 					warning ctx WVarShadow "This variable shadows a previously declared variable" p;
 					warning ~depth:1 ctx WVarShadow (compl_msg "Previous variable was here") v'.v_pos
 				end
@@ -395,36 +408,19 @@ let is_gen_local v = match v.v_kind with
 	| _ ->
 		false
 
-let make_delay pass fl = {
-	delay_pass = pass;
-	delay_functions = fl;
-}
-
 let delay ctx p f =
-	let rec loop = function
-		| [] ->
-			[make_delay p [f]]
-		| delay :: rest ->
-			if delay.delay_pass = p then
-				(make_delay p (f :: delay.delay_functions)) :: rest
-			else if delay.delay_pass < p then
-				delay :: loop rest
-			else
-				(make_delay p [f]) :: delay :: rest
-	in
-	ctx.g.delayed <- loop ctx.g.delayed
+	let p = Obj.magic p in
+	let tasks = ctx.g.delayed.(p) in
+	tasks.tasks <- f :: tasks.tasks;
+	if p < ctx.g.delayed_min_index then
+		ctx.g.delayed_min_index <- p
 
 let delay_late ctx p f =
-	let rec loop = function
-		| [] ->
-			[make_delay p [f]]
-		| delay :: rest ->
-			if delay.delay_pass <= p then
-				delay :: loop rest
-			else
-				(make_delay p [f]) :: delay :: rest
-	in
-	ctx.g.delayed <- loop ctx.g.delayed
+	let p = Obj.magic p in
+	let tasks = ctx.g.delayed.(p) in
+	tasks.tasks <- tasks.tasks @ [f];
+	if p < ctx.g.delayed_min_index then
+		ctx.g.delayed_min_index <- p
 
 let delay_if_mono ctx p t f = match follow t with
 	| TMono _ ->
@@ -433,17 +429,24 @@ let delay_if_mono ctx p t f = match follow t with
 		f()
 
 let rec flush_pass ctx p where =
-	match ctx.g.delayed with
-	| delay :: rest when delay.delay_pass <= p ->
-		(match delay.delay_functions with
-		| [] ->
-			ctx.g.delayed <- rest;
-		| f :: l ->
-			ctx.g.delayed <- (make_delay delay.delay_pass l) :: rest;
-			f());
-		flush_pass ctx p where
-	| _ ->
-		()
+	let rec loop i =
+		if i > (Obj.magic p) then
+			()
+		else begin
+			let tasks = ctx.g.delayed.(i) in
+			match tasks.tasks with
+			| f :: l ->
+				tasks.tasks <- l;
+				f();
+				flush_pass ctx p where
+			| [] ->
+				(* Done with this pass (for now), update min index to next one *)
+				let i = i + 1 in
+				ctx.g.delayed_min_index <- i;
+				loop i
+		end
+	in
+	loop ctx.g.delayed_min_index
 
 let make_pass ctx f = f
 
@@ -506,6 +509,18 @@ let is_forced_inline c cf =
 let needs_inline ctx c cf =
 	cf.cf_kind = Method MethInline && ctx.allow_inline && (ctx.g.doinline || is_forced_inline c cf)
 
+let clone_type_parameter map path ttp =
+	let c = ttp.ttp_class in
+	let c = {c with cl_path = path} in
+	let def = Option.map map ttp.ttp_default in
+	let constraints = match ttp.ttp_constraints with
+		| None -> None
+		| Some constraints -> Some (lazy (List.map map (Lazy.force constraints)))
+	in
+	let ttp' = mk_type_param c ttp.ttp_host def constraints in
+	c.cl_kind <- KTypeParameter ttp';
+	ttp'
+
 (** checks if we can access to a given class field using current context *)
 let can_access ctx c cf stat =
 	if (has_class_field_flag cf CfPublic) then
@@ -683,18 +698,7 @@ let safe_mono_close ctx m p =
 			raise_or_display ctx l p
 
 let relative_path ctx file =
-	let slashes path = String.concat "/" (ExtString.String.nsplit path "\\") in
-	let fpath = slashes (Path.get_full_path file) in
-	let fpath_lower = String.lowercase_ascii fpath in
-	let flen = String.length fpath_lower in
-	let rec loop = function
-		| [] -> file
-		| path :: l ->
-			let spath = String.lowercase_ascii (slashes path) in
-			let slen = String.length spath in
-			if slen > 0 && slen < flen && String.sub fpath_lower 0 slen = spath then String.sub fpath slen (flen - slen) else loop l
-	in
-	loop ctx.com.Common.class_path
+	ctx.com.class_paths#relative_path file
 
 let mk_infos ctx p params =
 	let file = if ctx.com.is_macro_context then p.pfile else if Common.defined ctx.com Define.AbsolutePath then Path.get_full_path p.pfile else relative_path ctx p.pfile in

+ 62 - 0
src/core/classPath.ml

@@ -0,0 +1,62 @@
+type class_path_scope =
+	| Std
+	| StdTarget
+	| Lib
+	| User
+
+type file_kind =
+	| FFile
+
+class virtual class_path (path : string) (scope : class_path_scope) (file_kind : file_kind) = object(self)
+	method path = path;
+	method scope = scope;
+	method file_kind = file_kind;
+
+	method virtual clone : class_path
+	method virtual clear_cache : unit
+	method virtual get_directory_path : string option
+	method virtual get_uncached_dir_listing : string -> (string * string array) option
+	method virtual dump : unit
+
+	method is_std_path = match scope with
+		| Std -> true
+		| _ -> false
+
+	method scope_string = match scope with
+		| Std -> "Std"
+		| StdTarget -> "StdTarget"
+		| Lib -> "Lib"
+		| User -> "User"
+end
+
+class directory_class_path (path : string) (scope : class_path_scope) = object(self)
+	inherit class_path path scope FFile
+
+	val readdir_cache = new Lookup.hashtbl_lookup
+
+	method clear_cache =
+		readdir_cache#clear
+
+	method get_directory_path =
+		Some path
+
+	method clone =
+		new directory_class_path path scope
+
+	method get_uncached_dir_listing (f : string) =
+		let file = path ^ f in
+		let dir = Filename.dirname file in
+		if readdir_cache#mem dir then
+			None
+		else begin
+			let dir_listing =
+				try Some (dir,Sys.readdir dir);
+				with Sys_error _ -> None
+			in
+			readdir_cache#add dir dir_listing;
+			dir_listing
+		end
+
+	method dump =
+		print_endline (Printf.sprintf "    dir %-9s: %s" (self#scope_string) path)
+end

+ 181 - 0
src/core/classPaths.ml

@@ -0,0 +1,181 @@
+open StringHelper
+open ClassPath
+
+type resolved_file = {
+	file : string;
+	class_path : class_path;
+}
+
+let create_resolved_file file class_path = {
+	file;
+	class_path;
+}
+
+(* We need to clean-up absolute ("") vs. cwd ("."). *)
+let absolute_class_path = new directory_class_path "" User
+
+class class_paths = object(self)
+	val mutable l = []
+	val file_lookup_cache = new Lookup.hashtbl_lookup;
+	val mutable platform_ext = ""
+	val mutable is_loading_core_api = false
+
+	method lock_context (platform_name : string) (core_api : bool) : unit =
+		platform_ext <- "." ^ platform_name;
+		is_loading_core_api <- core_api;
+		self#clear_cache
+
+	method as_string_list =
+		List.map (fun cp -> cp#path) l
+
+	method add (cp : class_path) =
+		l <- cp :: l;
+		self#clear_cache
+
+	method push (cp : class_path) =
+		l <- l @ [cp];
+		self#clear_cache
+
+	method find (f : class_path -> bool) =
+		List.find f l
+
+	method iter (f : class_path -> unit) =
+		List.iter f l
+
+	method exists (f : class_path -> bool) =
+		List.exists f l
+
+	method filter (f : class_path -> bool) =
+		List.filter f l
+
+	method modify (f : class_path -> class_path list) (cpl : class_path list) =
+		let rec loop acc l = match l with
+			| [] ->
+				List.rev acc
+			| cp :: l ->
+				let cpl = f cp in
+				loop (cpl @ acc) l
+		in
+		l <- loop [] cpl;
+		self#clear_cache
+
+	method modify_inplace (f : class_path -> class_path list) =
+		self#modify f l
+
+	method get_std_paths =
+		self#filter (fun cp -> cp#is_std_path)
+
+	method as_list =
+		l
+
+	method clear_cache =
+		file_lookup_cache#clear;
+		List.iter (fun cp -> cp#clear_cache) l
+
+	method cache_directory (cp : class_path) (dir : string) (f_search : string) (dir_listing : string array) =
+		(*
+			This function is invoked for each file in the `dir`.
+			Each file is checked if it's specific for current platform
+			(e.g. ends with `.js.hx` while compiling for JS).
+			If it's not platform-specific:
+				Check the lookup cache and if the file is not there store full file path in the cache.
+			If the file is platform-specific:
+				Store the full file path in the lookup cache probably replacing the cached path to a
+				non-platform-specific file.
+		*)
+		let found = ref None in
+		let f_dir = Filename.dirname f_search in
+		let prepare_file file_own_name =
+			let relative_to_classpath = if f_dir = "." then file_own_name else f_dir ^ "/" ^ file_own_name in
+			(* `representation` is how the file is referenced to. E.g. when it's deduced from a module path. *)
+			let is_platform_specific,representation =
+				(* Platform specific file extensions are not allowed for loading @:coreApi types. *)
+				if is_loading_core_api then
+					false,relative_to_classpath
+				else begin
+					let ext = extension relative_to_classpath in
+					let second_ext = extension (remove_extension relative_to_classpath) in
+					(* The file contains double extension and the secondary one matches current platform *)
+					if platform_ext = second_ext then
+						true,(remove_extension (remove_extension relative_to_classpath)) ^ ext
+					else
+						false,relative_to_classpath
+				end
+			in
+			(*
+				Store current full path for `representation` if
+				- we're loading @:coreApi
+				- or this is a platform-specific file for `representation`
+				- this `representation` was never found before
+			*)
+			if is_loading_core_api || is_platform_specific || not (file_lookup_cache#mem representation) then begin
+				let full_path = if dir = "." then file_own_name else dir ^ "/" ^ file_own_name in
+				let full_path = Some(create_resolved_file full_path cp) in
+				file_lookup_cache#add representation full_path;
+				if representation = f_search then found := full_path
+			end
+		in
+		Array.iter prepare_file dir_listing;
+		!found
+
+	method find_file_noraise (f : string) =
+		try
+			match file_lookup_cache#find f with
+			| None ->
+				None
+			| Some f ->
+				Some f
+		with
+		| Not_found when Path.is_absolute_path f ->
+			let r = if Sys.file_exists f then
+				Some (create_resolved_file f absolute_class_path)
+			else
+				None
+			in
+			file_lookup_cache#add f r;
+			r
+		| Not_found ->
+			let rec loop = function
+				| [] ->
+					None
+				| cp :: l ->
+					begin match cp#get_uncached_dir_listing f with
+						| None ->
+							loop l
+						| Some(dir,dir_listing) ->
+							match self#cache_directory cp dir f dir_listing with
+								| Some f ->
+									Some f
+								| None ->
+									loop l
+					end
+			in
+			let r = loop l in
+			file_lookup_cache#add f r;
+			r
+
+	method find_file (f : string) =
+		match self#find_file_noraise f with
+		| None -> raise Not_found
+		| Some f -> f
+
+	method relative_path file =
+		let slashes path = String.concat "/" (ExtString.String.nsplit path "\\") in
+		let fpath = slashes (Path.get_full_path file) in
+		let fpath_lower = String.lowercase_ascii fpath in
+		let flen = String.length fpath_lower in
+		let rec loop = function
+			| [] ->
+				file
+			| path :: l ->
+				let path = path#path in
+				let spath = String.lowercase_ascii (slashes path) in
+				let slen = String.length spath in
+				if slen > 0 && slen < flen && String.sub fpath_lower 0 slen = spath then String.sub fpath slen (flen - slen) else loop l
+		in
+		loop l
+
+	method dump =
+		print_endline (Printf.sprintf "Class paths for %s%s:" platform_ext (if is_loading_core_api then " (coreApi)" else ""));
+		List.iter (fun cp -> cp#dump) l
+end

+ 1 - 1
src/core/define.ml

@@ -152,7 +152,7 @@ let get_signature def =
 			   Parser.parse_macro_ident as well (issue #5682).
 			   Note that we should removed flags like use_rtti_doc here.
 			*)
-			| "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" | "display_stdin"
+			| "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" | "display_stdin" | "hxb.stats"
 			| "message.reporting" | "message.log_file" | "message.log_format" | "message.no_color"
 			| "dump" | "dump_dependencies" | "dump_ignore_var_ids" -> acc
 			| _ -> (k ^ "=" ^ v) :: acc

+ 15 - 0
src/core/ds/ring.ml

@@ -39,6 +39,21 @@ let fold r acc f =
 	in
 	loop 0 acc
 
+let find r f =
+	let len = Array.length r.values in
+	let rec loop i =
+		if i = len then
+			raise Not_found
+		else begin
+			let v = r.values.(i) in
+			if f v then
+				v
+			else
+				loop (i + 1)
+		end
+	in
+	loop 0
+
 let is_filled r =
 	r.num_filled >= Array.length r.values
 

+ 0 - 4
src/core/globals.ml

@@ -67,10 +67,6 @@ let trace_call_stack ?(n:int = 5) () =
 		Option.may (fun loc -> print_endline (Printf.sprintf "  called from %s" (loc_to_string loc))) loc;
 	done
 
-let macro_platform = ref Neko
-
-let return_partial_type = ref false
-
 let is_windows = Sys.os_type = "Win32" || Sys.os_type = "Cygwin"
 
 let max_custom_target_len = 16

+ 11 - 13
src/core/json/genjson.ml

@@ -215,9 +215,7 @@ let rec generate_type ctx t =
 			| Some t -> loop t
 			end
 		| TLazy f ->
-			(* return_partial_type := true; *)
 			let t = lazy_type f in
-			(* return_partial_type := false; *)
 			loop t
 		| TDynamic None -> "TDynamic", Some jnull
 		| TDynamic (Some t) -> "TDynamic",Some (generate_type ctx t)
@@ -623,7 +621,7 @@ let generate_class ctx c =
 		"fields",jlist (generate_class_field ctx CFSMember) c.cl_ordered_fields;
 		"statics",jlist (generate_class_field ctx CFSStatic) c.cl_ordered_statics;
 		"constructor",jopt (generate_class_field ctx CFSConstructor) c.cl_constructor;
-		"init",jopt (generate_texpr ctx) c.cl_init;
+		"init",jopt (generate_texpr ctx) (TClass.get_cl_init c);
 		"overrides",jlist (classfield_ref ctx) (List.filter (fun cf -> has_class_field_flag cf CfOverride) c.cl_ordered_fields);
 		"isExtern",jbool (has_class_flag c CExtern);
 		"isFinal",jbool (has_class_flag c CFinal);
@@ -703,7 +701,7 @@ let generate_module_type ctx mt =
 
 (* module *)
 
-let generate_module cs cc m =
+let generate_module modules find_module m =
 	jobject [
 		"id",jint m.m_id;
 		"path",generate_module_path m.m_path;
@@ -714,19 +712,19 @@ let generate_module cs cc m =
 			| MSGood -> "Good"
 			| MSBad reason -> Printer.s_module_skip_reason reason
 			| MSUnknown -> "Unknown");
-		"dependencies",jarray (PMap.fold (fun (sign,mpath) acc ->
+		"dependencies",jarray (PMap.fold (fun mdep acc ->
 			(jobject [
-				"path",jstring (s_type_path mpath);
-				"sign",jstring (Digest.to_hex ((cs#get_context sign)#find_module mpath).m_extra.m_sign);
+				"path",jstring (s_type_path mdep.md_path);
+				"sign",jstring (Digest.to_hex (find_module mdep.md_path).m_extra.m_sign);
 			]) :: acc
 		) m.m_extra.m_deps []);
-		"dependents",jarray (List.map (fun m -> (jobject [
-			"path",jstring (s_type_path m.m_path);
-			"sign",jstring (Digest.to_hex m.m_extra.m_sign);
-		])) (Hashtbl.fold (fun _ m' acc ->
-			if PMap.mem m.m_id m'.m_extra.m_deps then m' :: acc
+		"dependents",jarray (List.map (fun (path, sign) -> (jobject [
+			"path",jstring (s_type_path path);
+			"sign",jstring (Digest.to_hex sign);
+		])) (Hashtbl.fold (fun _ (m':HxbData.module_cache) acc ->
+			if PMap.mem m.m_id m'.mc_extra.m_deps then (m'.mc_path, m'.mc_extra.m_sign) :: acc
 			else acc
-		) cc#get_modules []));
+		) modules []));
 	]
 
 let create_context ?jsonrpc gm = {

+ 12 - 1
src/core/stringHelper.ml

@@ -57,4 +57,15 @@ let escape_res_name name allowed =
 		else if List.mem chr allowed then
 			Char.escaped chr
 		else
-			"-x" ^ (string_of_int (Char.code chr))) name
+			"-x" ^ (string_of_int (Char.code chr))) name
+
+let remove_extension file =
+	try String.sub file 0 (String.rindex file '.')
+	with Not_found -> file
+
+let extension file =
+	try
+		let dot_pos = String.rindex file '.' in
+		String.sub file dot_pos (String.length file - dot_pos)
+	with Not_found ->
+		file

+ 37 - 35
src/core/tFunctions.ml

@@ -58,9 +58,9 @@ let has_var_flag v (flag : flag_tvar) =
 
 (* ======= General utility ======= *)
 
-let alloc_var =
+let alloc_var' =
 	let uid = ref 0 in
-	(fun kind n t p ->
+	uid,(fun kind n t p ->
 		incr uid;
 		{
 			v_kind = kind;
@@ -74,6 +74,10 @@ let alloc_var =
 		}
 	)
 
+let alloc_var =
+	let _,alloc_var = alloc_var' in
+	alloc_var
+
 let alloc_mid =
 	let mid = ref 0 in
 	(fun() -> incr mid; !mid)
@@ -97,18 +101,32 @@ let mk_anon ?fields status =
 	let fields = match fields with Some fields -> fields | None -> PMap.empty in
 	TAnon { a_fields = fields; a_status = status; }
 
-(* We use this for display purposes because otherwise we never see the Dynamic type that
-   is defined in StdTypes.hx. This is set each time a typer is created, but this is fine
-   because Dynamic is the same in all contexts. If this ever changes we'll have to review
-   how we handle this. *)
-let t_dynamic_def = ref t_dynamic
-
 let tfun pl r = TFun (List.map (fun t -> "",false,t) pl,r)
 
 let fun_args l = List.map (fun (a,c,t) -> a, c <> None, t) l
 
-let mk_class m path pos name_pos =
+let mk_typedef m path pos name_pos t =
 	{
+		t_path = path;
+		t_module = m;
+		t_pos = pos;
+		t_name_pos = name_pos;
+		t_private = false;
+		t_doc = None;
+		t_meta = [];
+		t_params = [];
+		t_using = [];
+		t_type = t;
+		t_restore = (fun () -> ());
+	}
+
+let class_module_type c =
+	let path = ([],"Class<" ^ (s_type_path c.cl_path) ^ ">") in
+	let t = mk_anon ~fields:c.cl_statics (ref (ClassStatics c)) in
+	{ (mk_typedef c.cl_module path c.cl_pos null_pos t) with t_private = true}
+
+let mk_class m path pos name_pos =
+	let c = {
 		cl_path = path;
 		cl_module = m;
 		cl_pos = pos;
@@ -118,6 +136,7 @@ let mk_class m path pos name_pos =
 		cl_private = false;
 		cl_kind = KNormal;
 		cl_flags = 0;
+		cl_type = t_dynamic;
 		cl_params = [];
 		cl_using = [];
 		cl_super = None;
@@ -133,22 +152,9 @@ let mk_class m path pos name_pos =
 		cl_build = (fun() -> Built);
 		cl_restore = (fun() -> ());
 		cl_descendants = [];
-	}
-
-let mk_typedef m path pos name_pos t =
-	{
-		t_path = path;
-		t_module = m;
-		t_pos = pos;
-		t_name_pos = name_pos;
-		t_private = false;
-		t_doc = None;
-		t_meta = [];
-		t_params = [];
-		t_using = [];
-		t_type = t;
-		t_restore = (fun () -> ());
-	}
+	} in
+	c.cl_type <- TType(class_module_type c,[]);
+	c
 
 let module_extra file sign time kind added policy =
 	{
@@ -167,7 +173,6 @@ let module_extra file sign time kind added policy =
 		m_deps = PMap.empty;
 		m_kind = kind;
 		m_cache_bound_objects = DynArray.create ();
-		m_if_feature = [];
 		m_features = Hashtbl.create 0;
 		m_check_policy = policy;
 	}
@@ -206,6 +211,8 @@ let find_field c name kind =
 		PMap.find name c.cl_statics
 	| CfrMember ->
 		PMap.find name c.cl_fields
+	| CfrInit ->
+		begin match c.cl_init with Some cf -> cf | None -> raise Not_found end
 
 let null_module = {
 	m_id = alloc_mid();
@@ -284,7 +291,7 @@ let null_abstract = {
 
 let add_dependency ?(skip_postprocess=false) m mdep =
 	if m != null_module && mdep != null_module && (m.m_path != mdep.m_path || m.m_extra.m_sign != mdep.m_extra.m_sign) then begin
-		m.m_extra.m_deps <- PMap.add mdep.m_id (mdep.m_extra.m_sign, mdep.m_path) m.m_extra.m_deps;
+		m.m_extra.m_deps <- PMap.add mdep.m_id ({md_sign = mdep.m_extra.m_sign; md_path = mdep.m_path; md_kind = mdep.m_extra.m_kind}) m.m_extra.m_deps;
 		(* In case the module is cached, we'll have to run post-processing on it again (issue #10635) *)
 		if not skip_postprocess then m.m_extra.m_processed <- 0
 	end
@@ -940,14 +947,9 @@ let var_extra params e = {
 	v_expr = e;
 }
 
-let class_module_type c =
-	let path = ([],"Class<" ^ (s_type_path c.cl_path) ^ ">") in
-	let t = mk_anon ~fields:c.cl_statics (ref (ClassStatics c)) in
-	{ (mk_typedef c.cl_module path c.cl_pos null_pos t) with t_private = true}
-
-let enum_module_type en fields =
+let enum_module_type en =
 	let path = ([], "Enum<" ^ (s_type_path en.e_path) ^ ">") in
-	let t = mk_anon ~fields (ref (EnumStatics en)) in
+	let t = mk_anon (ref (EnumStatics en)) in
 	{(mk_typedef en.e_module path en.e_pos null_pos t) with t_private = true}
 
 let abstract_module_type a tl =
@@ -963,4 +965,4 @@ let class_field_of_enum_field ef = {
 	);
 	cf_doc = ef.ef_doc;
 	cf_params = ef.ef_params;
-}
+}

+ 24 - 0
src/core/tOther.ml

@@ -412,6 +412,30 @@ module TClass = struct
 		in
 		let apply = apply_params c.cl_params tl in
 		loop apply c
+
+
+	let get_cl_init c = match c.cl_init with
+		| Some {cf_expr = Some e} -> Some e
+		| _ -> None
+
+	let modify_cl_init c e append = match c.cl_init with
+		| Some cf ->
+			begin match cf.cf_expr with
+				| Some e' when append ->
+					cf.cf_expr <- Some (concat e' e)
+				| _ ->
+					cf.cf_expr <- Some e
+			end
+		| None ->
+			let cf = mk_field "__init__" t_dynamic null_pos null_pos in
+			cf.cf_expr <- Some e;
+			c.cl_init <- Some cf
+
+	let add_cl_init c e =
+		modify_cl_init c e true
+
+	let set_cl_init c e =
+		modify_cl_init c e false
 end
 
 let s_class_path c =

+ 3 - 3
src/core/tPrinting.ml

@@ -413,6 +413,7 @@ let s_class_field_ref_kind = function
 	| CfrStatic -> "CfrStatic"
 	| CfrMember -> "CfrMember"
 	| CfrConstructor -> "CfrConstructor"
+	| CfrInit -> "CfrInit"
 
 module Printer = struct
 
@@ -506,7 +507,7 @@ module Printer = struct
 			"cl_super",s_opt (fun (c,tl) -> s_type (TInst(c,tl))) c.cl_super;
 			"cl_implements",s_list ", " (fun (c,tl) -> s_type (TInst(c,tl))) c.cl_implements;
 			"cl_array_access",s_opt s_type c.cl_array_access;
-			"cl_init",s_opt (s_expr_ast true "" s_type) c.cl_init;
+			"cl_init",s_opt (s_expr_ast true "" s_type) (TOther.TClass.get_cl_init c);
 			"cl_constructor",s_opt (s_tclass_field (tabs ^ "\t")) c.cl_constructor;
 			"cl_ordered_fields",s_list "\n\t" (s_tclass_field (tabs ^ "\t")) c.cl_ordered_fields;
 			"cl_ordered_statics",s_list "\n\t" (s_tclass_field (tabs ^ "\t")) c.cl_ordered_statics;
@@ -640,11 +641,10 @@ module Printer = struct
 			"m_cache_state",s_module_cache_state me.m_cache_state;
 			"m_added",string_of_int me.m_added;
 			"m_checked",string_of_int me.m_checked;
-			"m_deps",s_pmap string_of_int (fun (_,m) -> snd m) me.m_deps;
+			"m_deps",s_pmap string_of_int (fun mdep -> snd mdep.md_path) me.m_deps;
 			"m_processed",string_of_int me.m_processed;
 			"m_kind",s_module_kind me.m_kind;
 			"m_binded_res",""; (* TODO *)
-			"m_if_feature",""; (* TODO *)
 			"m_features",""; (* TODO *)
 		]
 

+ 15 - 5
src/core/tType.ml

@@ -30,7 +30,6 @@ type module_check_policy =
 	| CheckFileContentModification
 	| NoCheckDependencies
 	| NoCheckShadowing
-	| Retype
 
 type module_tainting_reason =
 	| CheckDisplayFile
@@ -289,6 +288,7 @@ and tclass = {
 	mutable cl_using : (tclass * pos) list;
 	mutable cl_restore : unit -> unit;
 	(* do not insert any fields above *)
+	mutable cl_type : t;
 	mutable cl_kind : tclass_kind;
 	mutable cl_flags : int;
 	mutable cl_super : (tclass * tparams) option;
@@ -300,7 +300,7 @@ and tclass = {
 	mutable cl_dynamic : t option;
 	mutable cl_array_access : t option;
 	mutable cl_constructor : tclass_field option;
-	mutable cl_init : texpr option;
+	mutable cl_init : tclass_field option;
 
 	mutable cl_build : unit -> build_state;
 	(*
@@ -401,6 +401,12 @@ and module_def_display = {
 	mutable m_import_positions : (pos,bool ref) PMap.t;
 }
 
+and module_dep = {
+	md_sign : Digest.t;
+	md_kind : module_kind;
+	md_path : path;
+}
+
 and module_def_extra = {
 	m_file : Path.UniqueKey.lazy_t;
 	m_sign : Digest.t;
@@ -411,10 +417,9 @@ and module_def_extra = {
 	mutable m_added : int;
 	mutable m_checked : int;
 	mutable m_processed : int;
-	mutable m_deps : (int,(Digest.t (* sign *) * path)) PMap.t;
+	mutable m_deps : (int,module_dep) PMap.t;
 	mutable m_kind : module_kind;
 	mutable m_cache_bound_objects : cache_bound_object DynArray.t;
-	mutable m_if_feature : (string * class_field_ref) list;
 	mutable m_features : (string,bool) Hashtbl.t;
 }
 
@@ -422,6 +427,7 @@ and class_field_ref_kind =
 	| CfrStatic
 	| CfrMember
 	| CfrConstructor
+	| CfrInit
 
 and class_field_ref = {
 	cfr_sign : string;
@@ -464,6 +470,7 @@ type flag_tclass =
 	| CInterface
 	| CAbstract
 	| CFunctionalInterface
+	| CUsed (* Marker for DCE *)
 
 type flag_tclass_field =
 	| CfPublic
@@ -479,10 +486,12 @@ type flag_tclass_field =
 	| CfGeneric
 	| CfDefault (* Interface field with default implementation (only valid on Java) *)
 	| CfPostProcessed (* Marker to indicate the field has been post-processed *)
+	| CfUsed (* Marker for DCE *)
+	| CfMaybeUsed (* Marker for DCE *)
 
 (* Order has to match declaration for printing*)
 let flag_tclass_field_names = [
-	"CfPublic";"CfStatic";"CfExtern";"CfFinal";"CfModifiesThis";"CfOverride";"CfAbstract";"CfOverload";"CfImpl";"CfEnum";"CfGeneric";"CfDefault";"CfPostProcessed"
+	"CfPublic";"CfStatic";"CfExtern";"CfFinal";"CfModifiesThis";"CfOverride";"CfAbstract";"CfOverload";"CfImpl";"CfEnum";"CfGeneric";"CfDefault";"CfPostProcessed";"CfUsed";"CfMaybeUsed"
 ]
 
 type flag_tvar =
@@ -493,6 +502,7 @@ type flag_tvar =
 	| VCaught
 	| VStatic
 	| VUsedByTyper (* Set if the typer looked up this variable *)
+	| VHxb (* Flag used by hxb *)
 
 let flag_tvar_names = [
 	"VCaptured";"VFinal";"VAnalyzed";"VAssigned";"VCaught";"VStatic";"VUsedByTyper"

+ 112 - 71
src/core/tUnification.ml

@@ -29,13 +29,16 @@ type eq_kind =
 	| EqRightDynamic
 	| EqBothDynamic
 	| EqDoNotFollowNull (* like EqStrict, but does not follow Null<T> *)
+	| EqStricter
 
 type unification_context = {
-	allow_transitive_cast : bool;
-	allow_abstract_cast   : bool; (* allows a non-transitive abstract cast (from,to,@:from,@:to) *)
-	allow_dynamic_to_cast : bool; (* allows a cast from dynamic to non-dynamic *)
-	equality_kind         : eq_kind;
-	equality_underlying   : bool;
+	allow_transitive_cast   : bool;
+	allow_abstract_cast     : bool; (* allows a non-transitive abstract cast (from,to,@:from,@:to) *)
+	allow_dynamic_to_cast   : bool; (* allows a cast from dynamic to non-dynamic *)
+	allow_arg_name_mismatch : bool;
+	equality_kind           : eq_kind;
+	equality_underlying     : bool;
+	strict_field_kind       : bool;
 }
 
 type unify_min_result =
@@ -54,11 +57,13 @@ let unify_ref : (unification_context -> t -> t -> unit) ref = ref (fun _ _ _ ->
 let unify_min_ref : (unification_context -> t -> t list -> unify_min_result) ref = ref (fun _ _ _ -> assert false)
 
 let default_unification_context = {
-	allow_transitive_cast = true;
-	allow_abstract_cast   = true;
-	allow_dynamic_to_cast = true;
-	equality_kind         = EqStrict;
-	equality_underlying   = false;
+	allow_transitive_cast   = true;
+	allow_abstract_cast     = true;
+	allow_dynamic_to_cast   = true;
+	allow_arg_name_mismatch = true;
+	equality_kind           = EqStrict;
+	equality_underlying     = false;
+	strict_field_kind       = false;
 }
 
 module Monomorph = struct
@@ -338,6 +343,13 @@ let fast_eq_check type_param_check a b =
 		c1 == c2 && List.for_all2 type_param_check l1 l2
 	| TAbstract (a1,l1), TAbstract (a2,l2) ->
 		a1 == a2 && List.for_all2 type_param_check l1 l2
+	| TAnon an1,TAnon an2 ->
+		begin match !(an1.a_status),!(an2.a_status) with
+			| ClassStatics c, ClassStatics c2 -> c == c2
+			| EnumStatics e, EnumStatics e2 -> e == e2
+			| AbstractStatics a, AbstractStatics a2 -> a == a2
+			| _ -> false
+		end
 	| _ , _ ->
 		false
 
@@ -386,9 +398,6 @@ let rec shallow_eq a b =
 					loop (List.sort sort_compare fields1) (List.sort sort_compare fields2)
 				in
 				(match !(a2.a_status), !(a1.a_status) with
-				| ClassStatics c, ClassStatics c2 -> c == c2
-				| EnumStatics e, EnumStatics e2 -> e == e2
-				| AbstractStatics a, AbstractStatics a2 -> a == a2
 				| Extend tl1, Extend tl2 -> fields_eq() && List.for_all2 shallow_eq tl1 tl2
 				| Closed, Closed -> fields_eq()
 				| Const, Const -> fields_eq()
@@ -423,15 +432,20 @@ let direct_access = function
 	| AccNo | AccNever | AccNormal | AccInline | AccRequire _ | AccCtor -> true
 	| AccCall -> false
 
-let unify_kind k1 k2 =
+let unify_kind ~(strict:bool) k1 k2 =
 	k1 = k2 || match k1, k2 with
 		| Var v1, Var v2 -> unify_access v1.v_read v2.v_read && unify_access v1.v_write v2.v_write
-		| Var v, Method m ->
+		| Method m1, Method m2 ->
+			(match m1,m2 with
+			| MethInline, MethNormal
+			| MethDynamic, MethNormal -> true
+			| _ -> false)
+		| Var v, Method m when not strict ->
 			(match v.v_read, v.v_write, m with
 			| AccNormal, _, MethNormal -> true
 			| AccNormal, AccNormal, MethDynamic -> true
 			| _ -> false)
-		| Method m, Var v ->
+		| Method m, Var v when not strict ->
 			(match m with
 			| MethDynamic -> direct_access v.v_read && direct_access v.v_write
 			| MethMacro -> false
@@ -439,11 +453,7 @@ let unify_kind k1 k2 =
 				match v.v_read,v.v_write with
 				| AccNormal,(AccNo | AccNever) -> true
 				| _ -> false)
-		| Method m1, Method m2 ->
-			match m1,m2 with
-			| MethInline, MethNormal
-			| MethDynamic, MethNormal -> true
-			| _ -> false
+		| _ -> false
 
 type 'a rec_stack = {
 	mutable rec_stack : 'a list;
@@ -485,7 +495,12 @@ let rec_stack_default stack value fcheck frun def =
 
 let rec type_eq uctx a b =
 	let param = uctx.equality_kind in
+	let can_follow_null = match param with
+		| EqStricter | EqDoNotFollowNull -> false
+		| _ -> true
+	in
 	let can_follow t = match param with
+		| EqStricter -> false
 		| EqCoreType -> false
 		| EqDoNotFollowNull -> not (is_explicit_null t)
 		| _ -> true
@@ -501,11 +516,11 @@ let rec type_eq uctx a b =
 	| _ , TLazy f -> type_eq uctx a (lazy_type f)
 	| TMono t , _ ->
 		(match t.tm_type with
-		| None -> if param = EqCoreType || not (link t a b) then error [cannot_unify a b]
+		| None -> if param = EqCoreType || param = EqStricter || not (link t a b) then error [cannot_unify a b]
 		| Some t -> type_eq uctx t b)
 	| _ , TMono t ->
 		(match t.tm_type with
-		| None -> if param = EqCoreType || not (link t b a) then error [cannot_unify a b]
+		| None -> if param = EqCoreType || param = EqStricter || not (link t b a) then error [cannot_unify a b]
 		| Some t -> type_eq uctx a t)
 	| TDynamic None, TDynamic None ->
 		()
@@ -517,9 +532,9 @@ let rec type_eq uctx a b =
 		()
 	| TAbstract ({a_path=[],"Null"},[t1]),TAbstract ({a_path=[],"Null"},[t2]) ->
 		type_eq uctx t1 t2
-	| TAbstract ({a_path=[],"Null"},[t]),_ when param <> EqDoNotFollowNull ->
+	| TAbstract ({a_path=[],"Null"},[t]),_ when can_follow_null ->
 		type_eq uctx t b
-	| _,TAbstract ({a_path=[],"Null"},[t]) when param <> EqDoNotFollowNull ->
+	| _,TAbstract ({a_path=[],"Null"},[t]) when can_follow_null ->
 		type_eq uctx a t
 	| TType (t1,tl1), TType (t2,tl2) when (t1 == t2 || (param = EqCoreType && t1.t_path = t2.t_path)) && List.length tl1 = List.length tl2 ->
 		type_eq_params uctx a b tl1 tl2
@@ -541,9 +556,10 @@ let rec type_eq uctx a b =
 		let i = ref 0 in
 		(try
 			type_eq uctx r1 r2;
-			List.iter2 (fun (n,o1,t1) (_,o2,t2) ->
+			List.iter2 (fun (n1,o1,t1) (n2,o2,t2) ->
 				incr i;
-				if o1 <> o2 then error [Not_matching_optional n];
+				if not uctx.allow_arg_name_mismatch && n1 <> n2 then error [Unify_custom (Printf.sprintf "Arg name mismatch: %s should be %s" n2 n1)];
+				if o1 <> o2 then error [Not_matching_optional n1];
 				type_eq uctx t1 t2
 			) l1 l2
 		with
@@ -565,19 +581,27 @@ let rec type_eq uctx a b =
 			| AbstractStatics a -> (match !(a1.a_status) with AbstractStatics a2 when a == a2 -> () | _ -> error [])
 			| _ -> ()
 			);
+			let fields = match !(a1.a_status) with
+				| ClassStatics c -> c.cl_statics
+				| _ -> a1.a_fields
+			in
 			PMap.iter (fun n f1 ->
 				try
 					let f2 = PMap.find n a2.a_fields in
-					if f1.cf_kind <> f2.cf_kind && (param = EqStrict || param = EqCoreType || not (unify_kind f1.cf_kind f2.cf_kind)) then error [invalid_kind n f1.cf_kind f2.cf_kind];
+					let kind_should_match = match param with
+						| EqStrict | EqCoreType | EqDoNotFollowNull | EqStricter -> true
+						| _ -> false
+					in
+					if f1.cf_kind <> f2.cf_kind && (kind_should_match || not (unify_kind ~strict:uctx.strict_field_kind f1.cf_kind f2.cf_kind)) then error [invalid_kind n f1.cf_kind f2.cf_kind];
 					let a = f1.cf_type and b = f2.cf_type in
 					(try type_eq uctx a b with Unify_error l -> error (invalid_field n :: l));
 					if (has_class_field_flag f1 CfPublic) != (has_class_field_flag f2 CfPublic) then error [invalid_visibility n];
 				with
 					Not_found ->
 						error [has_no_field b n];
-			) a1.a_fields;
+			) fields;
 			PMap.iter (fun n f2 ->
-				if not (PMap.mem n a1.a_fields) then begin
+				if not (PMap.mem n fields) then begin
 					error [has_no_field a n];
 				end;
 			) a2.a_fields;
@@ -606,7 +630,7 @@ let type_iseq uctx a b =
 
 let type_iseq_strict a b =
 	try
-		type_eq {default_unification_context with equality_kind = EqDoNotFollowNull} a b;
+		type_eq {default_unification_context with equality_kind = EqStricter} a b;
 		true
 	with Unify_error _ ->
 		false
@@ -636,11 +660,11 @@ let rec unify (uctx : unification_context) a b =
 	| _ , TLazy f -> unify uctx a (lazy_type f)
 	| TMono t , _ ->
 		(match t.tm_type with
-		| None -> if not (link t a b) then error [cannot_unify a b]
+		| None -> if uctx.equality_kind = EqStricter || not (link t a b) then error [cannot_unify a b]
 		| Some t -> unify uctx t b)
 	| _ , TMono t ->
 		(match t.tm_type with
-		| None -> if not (link t b a) then error [cannot_unify a b]
+		| None -> if uctx.equality_kind = EqStricter || not (link t b a) then error [cannot_unify a b]
 		| Some t -> unify uctx a t)
 	| TType (t,tl) , _ ->
 		rec_stack unify_stack (a,b)
@@ -745,7 +769,7 @@ let rec unify (uctx : unification_context) a b =
 				in
 				let _, ft, f1 = (try raw_class_field make_type c tl n with Not_found -> error [has_no_field a n]) in
 				let ft = apply_params c.cl_params tl ft in
-				if not (unify_kind f1.cf_kind f2.cf_kind) then error [invalid_kind n f1.cf_kind f2.cf_kind];
+				if not (unify_kind ~strict:uctx.strict_field_kind f1.cf_kind f2.cf_kind) then error [invalid_kind n f1.cf_kind f2.cf_kind];
 				if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then error [invalid_visibility n];
 
 				(match f2.cf_kind with
@@ -780,15 +804,14 @@ let rec unify (uctx : unification_context) a b =
 					then error [Missing_overload (f1, f2o.cf_type)]
 				) f2.cf_overloads;
 				(* we mark the field as :?used because it might be used through the structure *)
-				if not (Meta.has Meta.MaybeUsed f1.cf_meta) then begin
-					f1.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: f1.cf_meta;
+				if not (has_class_field_flag f1 CfMaybeUsed) then begin
+					add_class_field_flag f1 CfMaybeUsed;
 					match f2.cf_kind with
 					| Var vk ->
 						let check name =
 							try
 								let _,_,cf = raw_class_field make_type c tl name in
-								if not (Meta.has Meta.MaybeUsed cf.cf_meta) then
-									cf.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: cf.cf_meta
+								add_class_field_flag cf CfMaybeUsed
 							with Not_found ->
 								()
 						in
@@ -862,7 +885,7 @@ let rec unify (uctx : unification_context) a b =
 			error [cannot_unify a b]
 		end
 	| _ , TDynamic None ->
-		()
+		if uctx.equality_kind = EqStricter then error [cannot_unify a b]
 	| _ , TDynamic (Some t1) ->
 		begin match a with
 		| TAnon an ->
@@ -897,39 +920,57 @@ let rec unify (uctx : unification_context) a b =
 		error [cannot_unify a b]
 
 and unify_anons uctx a b a1 a2 =
-	(try
-		PMap.iter (fun n f2 ->
+	let unify_field a1_fields f2 =
+		let n = f2.cf_name in
+		let f1 = PMap.find n a1_fields in
+		if not (unify_kind ~strict:uctx.strict_field_kind f1.cf_kind f2.cf_kind) then
+			error [invalid_kind n f1.cf_kind f2.cf_kind];
+		if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then
+			error [invalid_visibility n];
 		try
-			let f1 = PMap.find n a1.a_fields in
-			if not (unify_kind f1.cf_kind f2.cf_kind) then
-				error [invalid_kind n f1.cf_kind f2.cf_kind];
-			if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then error [invalid_visibility n];
-			try
-				let f1_type =
-					if fast_eq f1.cf_type f2.cf_type then f1.cf_type
-					else field_type f1
-				in
-				unify_with_access uctx f1 f1_type f2;
-				(match !(a1.a_status) with
-				| ClassStatics c when not (Meta.has Meta.MaybeUsed f1.cf_meta) -> f1.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: f1.cf_meta
-				| _ -> ());
-			with
-				Unify_error l -> error (invalid_field n :: l)
-		with
-			Not_found ->
-				match !(a1.a_status) with
-				| Const when Meta.has Meta.Optional f2.cf_meta ->
-					a1.a_fields <- PMap.add f2.cf_name f2 a1.a_fields
-				| _ ->
-					error [has_no_field a n];
-		) a2.a_fields;
-		(match !(a2.a_status) with
-		| ClassStatics c -> (match !(a1.a_status) with ClassStatics c2 when c == c2 -> () | _ -> error [])
-		| EnumStatics e -> (match !(a1.a_status) with EnumStatics e2 when e == e2 -> () | _ -> error [])
-		| AbstractStatics a -> (match !(a1.a_status) with AbstractStatics a2 when a == a2 -> () | _ -> error [])
-		| Const | Extend _ | Closed -> ())
-	with
-		Unify_error l -> error (cannot_unify a b :: l))
+			let f1_type =
+				if fast_eq f1.cf_type f2.cf_type then f1.cf_type
+				else field_type f1
+			in
+			unify_with_access uctx f1 f1_type f2;
+			f1
+		with Unify_error l ->
+				error (invalid_field n :: l)
+	in
+	let unify_fields a1_fields f_good f_bad =
+		try
+			PMap.iter (fun _ f2 ->
+				try
+					f_good (unify_field a1_fields f2)
+				with Not_found ->
+					if not (f_bad f2) then
+						error [has_no_field a f2.cf_name]
+			) a2.a_fields
+		with Unify_error l ->
+			error (cannot_unify a b :: l)
+	in
+	begin match !(a1.a_status),!(a2.a_status) with
+		| ClassStatics c1,ClassStatics c2 when c1 == c2 ->
+			()
+		| EnumStatics en1,EnumStatics en2 when en1 == en2 ->
+			()
+		| AbstractStatics a1,AbstractStatics a2 when a1 == a2 ->
+			()
+		| Const,_ ->
+			unify_fields a1.a_fields (fun _ -> ()) (fun f2 ->
+				if Meta.has Meta.Optional f2.cf_meta then begin
+					a1.a_fields <- PMap.add f2.cf_name f2 a1.a_fields;
+					true
+				end else
+					false
+			)
+		| ClassStatics c1,_ ->
+			unify_fields c1.cl_statics (fun f1 ->
+				add_class_field_flag f1 CfMaybeUsed
+			) (fun _ -> false)
+		| _ ->
+			unify_fields a1.a_fields (fun _ -> ()) (fun _ -> false)
+	end
 
 and does_func_unify f =
 	try f(); true with Unify_error _ -> false

+ 2 - 2
src/core/texpr.ml

@@ -486,12 +486,12 @@ let foldmap f acc e =
 (* Collection of functions that return expressions *)
 module Builder = struct
 	let make_static_this c p =
-		mk (TTypeExpr (TClassDecl c)) (TType(TFunctions.class_module_type c,[])) p
+		mk (TTypeExpr (TClassDecl c)) c.cl_type p
 
 	let make_typeexpr mt pos =
 		let t =
 			match resolve_typedef mt with
-			| TClassDecl c -> TType(class_module_type c,[])
+			| TClassDecl c -> c.cl_type
 			| TEnumDecl e -> e.e_type
 			| TAbstractDecl a -> TType(abstract_module_type a [],[])
 			| _ -> die "" __LOC__

+ 1 - 1
src/core/timer.ml

@@ -212,4 +212,4 @@ class timer (id : string list) = object(self)
 
 	method nest (name : string) =
 		new timer (id @ [name])
-end
+end

+ 18 - 0
src/core/zip_output.ml

@@ -0,0 +1,18 @@
+class virtual any_output = object(self)
+	method virtual add_entry : string -> string -> unit
+	method virtual close : unit
+end
+
+class zip_output
+	(zip_path : string)
+	(compression_level : int)
+= object(self)
+	inherit any_output
+	val zip = Zip.open_out zip_path
+
+	method add_entry (content : string) (name : string) =
+		Zip.add_entry ~level:compression_level content zip name
+
+	method close =
+		Zip.close_out zip
+end

+ 1 - 1
src/dune

@@ -17,7 +17,7 @@
 (library
 	(name haxe)
 	(libraries
-		extc extproc extlib_leftovers mbedtls neko objsize pcre2 camlp-streams swflib ttflib ziplib
+		extc extproc extlib_leftovers mbedtls neko objsize pcre2 camlp-streams swflib ziplib
 		json
 		unix ipaddr str bigarray threads dynlink
 		xml-light extlib sha terminal_size

+ 1 - 1
src/filters/exceptions.ml

@@ -73,7 +73,7 @@ let std_is ctx e t p =
 		| TFun(_,t) -> t
 		| _ -> raise_typing_error ("Std.isOfType is not a function and cannot be called") p
 	in
-	let type_expr = { eexpr = TTypeExpr(module_type_of_type t); etype = t; epos = p } in
+	let type_expr = TyperBase.type_module_type ctx.typer (module_type_of_type t) p in
 	make_static_call ctx.typer std_cls isOfType_field (fun t -> t) [e; type_expr] return_type p
 
 (**

+ 2 - 3
src/filters/filters.ml

@@ -613,15 +613,14 @@ let save_class_state com t =
 		let csr = Option.map (mk_field_restore) c.cl_constructor in
 		let ofr = List.map (mk_field_restore) c.cl_ordered_fields in
 		let osr = List.map (mk_field_restore) c.cl_ordered_statics in
-		let init = c.cl_init in
-		Option.may save_vars init;
+		let init = Option.map mk_field_restore c.cl_init in
 		c.cl_restore <- (fun() ->
 			c.cl_super <- sup;
 			c.cl_implements <- impl;
 			c.cl_meta <- meta;
 			if ext then add_class_flag c CExtern else remove_class_flag c CExtern;
 			c.cl_path <- path;
-			c.cl_init <- init;
+			c.cl_init <- Option.map restore_field init;
 			c.cl_ordered_fields <- List.map restore_field ofr;
 			c.cl_ordered_statics <- List.map restore_field osr;
 			c.cl_fields <- mk_pmap c.cl_ordered_fields;

+ 2 - 2
src/filters/filtersCommon.ml

@@ -81,11 +81,11 @@ let run_expression_filters ?(ignore_processed_status=false) ctx detail_times fil
 		(match c.cl_constructor with
 		| None -> ()
 		| Some f -> process_field f);
-		(match c.cl_init with
+		(match TClass.get_cl_init c with
 		| None -> ()
 		| Some e ->
 			let identifier = Printf.sprintf "%s.__init__" (s_type_path c.cl_path) in
-			c.cl_init <- Some (run (Some identifier) e));
+			TClass.set_cl_init c (run (Some identifier) e))
 	| TEnumDecl _ -> ()
 	| TTypeDecl _ -> ()
 	| TAbstractDecl _ -> ()

+ 14 - 21
src/generators/gencpp.ml

@@ -1322,17 +1322,7 @@ exception PathFound of string;;
 
 let strip_file ctx file = (match Common.defined ctx Common.Define.AbsolutePath with
    | true -> file
-   | false -> let flen = String.length file in
-   (* Not quite right - should probably test is file exists *)
-   try
-      List.iter (fun path ->
-         let plen = String.length path in
-         if (flen>plen && path=(String.sub file 0 plen ))
-            then raise (PathFound (String.sub file plen (flen-plen)) ) )
-         (ctx.class_path @ ctx.std_path);
-      file;
-   with PathFound tail ->
-      tail)
+   | false -> ctx.class_paths#relative_path file)
 ;;
 
 let with_debug ctx metadata run =
@@ -5013,7 +5003,7 @@ let find_referenced_types_flags ctx obj field_name super_deps constructor_deps h
    (* Body of main function *)
    (match obj with
    | TClassDecl class_def -> visit_class class_def;
-      (match class_def.cl_init with Some expression -> visit_params expression | _ -> ())
+      (match TClass.get_cl_init class_def with Some expression -> visit_params expression | _ -> ())
    | TEnumDecl enum_def -> visit_enum enum_def
    | TTypeDecl _ | TAbstractDecl _ -> (* These are expanded *) ());
 
@@ -5465,7 +5455,7 @@ let rec find_next_super_iteration ctx class_def =
 ;;
 
 let has_init_field class_def =
-   match class_def.cl_init with
+   match TClass.get_cl_init class_def with
    | Some _ -> true
    | _ -> false;;
 
@@ -5543,7 +5533,7 @@ let has_compare_field class_def =
 
 
 let has_boot_field class_def =
-   match class_def.cl_init with
+   match TClass.get_cl_init class_def with
    | None -> List.exists has_field_init (List.filter should_implement_field class_def.cl_ordered_statics)
    | _ -> true
 ;;
@@ -6104,7 +6094,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta
       end;
    end;
 
-   (match class_def.cl_init with
+   (match TClass.get_cl_init class_def with
    | Some expression ->
       let ctx = file_context baseCtx cpp_file debug false in
       output_cpp ("void " ^ class_name^ "::__init__()");
@@ -8389,7 +8379,7 @@ let generate_script_class common_ctx script class_def =
    script#write ((string_of_int ( (List.length ordered_fields) +
                                  (List.length ordered_statics) +
                                  (match class_def.cl_constructor with Some _ -> 1 | _ -> 0 ) +
-                                 (match class_def.cl_init with Some _ -> 1 | _ -> 0 ) ) )
+                                 (match TClass.get_cl_init class_def with Some _ -> 1 | _ -> 0 ) ) )
                                  ^ "\n");
 
    let generate_field isStatic field =
@@ -8422,7 +8412,7 @@ let generate_script_class common_ctx script class_def =
    (match class_def.cl_constructor with
       | Some field  -> generate_field true field
       | _ -> () );
-   (match class_def.cl_init with
+   (match TClass.get_cl_init class_def with
       | Some expression  -> script#voidFunc true false "__init__" expression
       | _ -> () );
 
@@ -8488,7 +8478,7 @@ let generate_cppia ctx =
       );
    ) common_ctx.types;
 
-   (match common_ctx.main with
+   (match common_ctx.main.main_expr with
    | None -> script#writeOpLine IaNoMain;
    | Some e -> script#writeOpLine IaMain;
          script#gen_expression e
@@ -8600,7 +8590,7 @@ let generate_source ctx =
    List.iter (fun job -> job () ) !jobs;
 
 
-   (match common_ctx.main with
+   (match common_ctx.main.main_expr with
    | None -> generate_dummy_main common_ctx
    | Some e ->
       let main_field = { (mk_field "__main__" t_dynamic e.epos null_pos) with
@@ -8663,7 +8653,7 @@ let generate_source ctx =
      end;
    end;
 
-   let output_name = match  common_ctx.main_class with
+   let output_name = match  common_ctx.main.main_class with
    | Some path -> (snd path)
    | _ -> "output" in
 
@@ -8679,7 +8669,10 @@ let generate_source ctx =
          | "true" | "sys" | "dce" | "cpp" | "debug" -> ();
          | _ -> cmd := !cmd @ [Printf.sprintf "-D%s=\"%s\"" name (escape_command value)];
       ) common_ctx.defines.values;
-      List.iter (fun path -> cmd := !cmd @ [Printf.sprintf "-I%s" (escape_command path)]) common_ctx.class_path;
+      common_ctx.class_paths#iter (fun path ->
+		let path = path#path in
+		cmd := !cmd @ [Printf.sprintf "-I%s" (escape_command path)]
+	  );
       common_ctx.print ("haxelib " ^ (String.concat " " !cmd) ^ "\n");
       if common_ctx.run_command_args "haxelib" !cmd <> 0 then failwith "Build failed";
       Sys.chdir old_dir;

+ 6 - 5
src/generators/genhl.ml

@@ -329,11 +329,12 @@ let make_debug ctx arr =
 		| false -> try
 			(* lookup relative path *)
 			let len = String.length p.pfile in
-			let base = List.find (fun path ->
+			let base = ctx.com.class_paths#find (fun path ->
+				let path = path#path in
 				let l = String.length path in
 				len > l && String.sub p.pfile 0 l = path
-			) ctx.com.Common.class_path in
-			let l = String.length base in
+			) in
+			let l = String.length base#path in
 			String.sub p.pfile l (len - l)
 		with Not_found ->
 			p.pfile
@@ -3695,7 +3696,7 @@ let generate_static_init ctx types main =
 	(* init class statics *)
 	let init_exprs = ref [] in
 	List.iter (fun t ->
-		(match t with TClassDecl { cl_init = Some e } -> init_exprs := e :: !init_exprs | _ -> ());
+		(match t with TClassDecl { cl_init = Some {cf_expr = Some e} } -> init_exprs := e :: !init_exprs | _ -> ());
 		match t with
 		| TClassDecl c when not (has_class_flag c CExtern) ->
 			List.iter (fun f ->
@@ -4186,7 +4187,7 @@ let generate com =
 
 	let ctx = create_context com false dump in
 	add_types ctx com.types;
-	let code = build_code ctx com.types com.main in
+	let code = build_code ctx com.types com.main.main_expr in
 	Array.sort (fun (lib1,_,_,_) (lib2,_,_,_) -> lib1 - lib2) code.natives;
 	if dump then begin
 		(match ctx.dump_out with None -> () | Some ch -> IO.close_out ch);

+ 1 - 1
src/generators/genhxold.ml

@@ -144,7 +144,7 @@ let generate_type com t =
 	let print_meta ml =
 		List.iter (fun (m,pl,_) ->
 			match m with
-			| Meta.DefParam | Meta.CoreApi | Meta.Used | Meta.MaybeUsed | Meta.FlatEnum | Meta.Value | Meta.DirectlyUsed | Meta.Enum -> ()
+			| Meta.DefParam | Meta.CoreApi | Meta.Used | Meta.FlatEnum | Meta.Value | Meta.DirectlyUsed | Meta.Enum -> ()
 			| _ ->
 			match pl with
 			| [] -> p "@%s " (Meta.to_string m)

+ 2 - 2
src/generators/genjs.ml

@@ -1623,7 +1623,7 @@ let need_to_generate_interface ctx cl_iface =
 
 let generate_type ctx = function
 	| TClassDecl c ->
-		(match c.cl_init with
+		(match TClass.get_cl_init c with
 		| None -> ()
 		| Some e ->
 			ctx.inits <- e :: ctx.inits);
@@ -1970,7 +1970,7 @@ let generate com =
 	end;
 	List.iter (gen_block_element ~newline_after:true ~keep_blocks:(ctx.es_version >= 6) ctx) (List.rev ctx.inits);
 	List.iter (generate_static ctx) (List.rev ctx.statics);
-	(match com.main with
+	(match com.main.main_expr with
 	| None -> ()
 	| Some e -> gen_expr ctx e; newline ctx);
 	if ctx.js_modern then begin

+ 6 - 28
src/generators/genjvm.ml

@@ -50,16 +50,11 @@ let get_construction_mode c cf =
 	if Meta.has Meta.HxGen cf.cf_meta then ConstructInitPlusNew
 	else ConstructInit
 
-class virtual jvm_output = object(self)
-	method virtual add_entry : string -> string -> unit
-	method virtual close : unit
-end
-
 (* Haxe *)
 
 type generation_context = {
 	com : Common.context;
-	out : jvm_output;
+	out : Zip_output.any_output;
 	t_runtime_exception : Type.t;
 	entry_point : (tclass * texpr) option;
 	t_exception : Type.t;
@@ -109,24 +104,10 @@ let run_timed gctx detail name f =
 		sub#run_finally f (fun () -> gctx.timer <- old)
 	end
 
-class jar_output
-	(jar_path : string)
-	(compression_level : int)
-= object(self)
-	inherit jvm_output
-	val jar = Zip.open_out jar_path
-
-	method add_entry (content : string) (name : string) =
-		Zip.add_entry ~level:compression_level content jar name
-
-	method close =
-		Zip.close_out jar
-end
-
 class file_output
 	(base_path : string)
 	= object(self)
-	inherit jvm_output
+	inherit Zip_output.any_output
 
 	method add_entry (content : string) (name : string) =
 		let path = base_path ^ name in
@@ -2551,10 +2532,7 @@ class tclass_to_jvm gctx c = object(self)
 			let p = null_pos in
 			let efield = Texpr.Builder.make_static_field c cf p in
 			let eop = mk (TBinop(OpAssign,efield,e)) cf.cf_type p in
-			begin match c.cl_init with
-			| None -> c.cl_init <- Some eop
-			| Some e -> c.cl_init <- Some (concat e eop)
-			end
+			TClass.add_cl_init c eop
 		in
 		begin match cf.cf_expr with
 			| None ->
@@ -2637,7 +2615,7 @@ class tclass_to_jvm gctx c = object(self)
 			| Some cf,None -> field MConstructor cf
 			| None,_ -> ()
 		end;
-		begin match c.cl_init with
+		begin match TClass.get_cl_init c with
 			| None ->
 				()
 			| Some e ->
@@ -3031,7 +3009,7 @@ let generate jvm_flag com =
 	in
 	if compression_level < 0 || compression_level > 9 then failwith "Invalid value for -D jvm.compression-level: Must be >=0 and <= 9";
 	let create_jar path =
-		new jar_output path compression_level
+		new Zip_output.zip_output path compression_level
 	in
 	let out_dir,out = if jvm_flag then begin
 		match path.file_name with
@@ -3055,7 +3033,7 @@ let generate jvm_flag com =
 		let jar_path = Printf.sprintf "%s%s.jar" jar_dir jar_name in
 		jar_dir,create_jar jar_path
 	end in
-	let anon_identification = new tanon_identification haxe_dynamic_object_path in
+	let anon_identification = new tanon_identification in
 	let dynamic_level = try
 		int_of_string (Define.defined_value com.defines Define.JvmDynamicLevel)
 	with _ ->

+ 2 - 2
src/generators/genlua.ml

@@ -1840,7 +1840,7 @@ let generate_require ctx path meta =
 
 let generate_type ctx = function
     | TClassDecl c ->
-        (match c.cl_init with
+        (match TClass.get_cl_init c with
          | None -> ()
          | Some e ->
              ctx.inits <- e :: ctx.inits);
@@ -2200,7 +2200,7 @@ let generate com =
             gen_value ctx { e with eexpr = TFunction fn; etype = TFun ([],com.basic.tvoid) };
         println ctx ", _hx_handle_error)";
         println ctx "if not success then _G.error(err) end";
-    ) com.main;
+    ) com.main.main_expr;
 
     if anyExposed then
         println ctx "return _hx_exports";

+ 6 - 5
src/generators/genneko.ml

@@ -57,11 +57,12 @@ let pos ctx p =
 				| false -> try
 					(* lookup relative path *)
 					let len = String.length p.pfile in
-					let base = List.find (fun path ->
+					let base = ctx.com.class_paths#find (fun path ->
+						let path = path#path in
 						let l = String.length path in
 						len > l && String.sub p.pfile 0 l = path
-					) ctx.com.Common.class_path in
-					let l = String.length base in
+					) in
+					let l = String.length base#path in
 					String.sub p.pfile l (len - l)
 
 					with Not_found -> p.pfile
@@ -554,7 +555,7 @@ let gen_enum ctx e =
 let gen_type ctx t acc =
 	match t with
 	| TClassDecl c ->
-		(match c.cl_init with
+		(match TClass.get_cl_init c with
 		| None -> ()
 		| Some e -> ctx.inits <- (c,e) :: ctx.inits);
 		if (has_class_flag c CExtern) then
@@ -779,7 +780,7 @@ let generate com =
 		{ psource = "<header>"; pline = 1; }
 	) in
 	let el = build ctx com.types in
-	let emain = (match com.main with None -> [] | Some e -> [gen_expr ctx e]) in
+	let emain = (match com.main.main_expr with None -> [] | Some e -> [gen_expr ctx e]) in
 	let e = (EBlock ((header()) @ libs :: el @ emain), null_pos) in
 	let source = Common.defined com Define.NekoSource in
 	let use_nekoc = Common.defined com Define.UseNekoc in

+ 5 - 5
src/generators/genphp7.ml

@@ -959,7 +959,7 @@ class class_wrapper (cls) =
 			if (has_class_flag cls CInterface) then
 				false
 			else
-				match cls.cl_init with
+				match TClass.get_cl_init cls with
 					| Some _ -> true
 					| None ->
 						List.exists
@@ -978,7 +978,7 @@ class class_wrapper (cls) =
 			Returns expression of a user-defined static __init__ method
 			@see http://old.haxe.org/doc/advanced/magic#initialization-magic
 		*)
-		method! get_magic_init = cls.cl_init
+		method! get_magic_init = TClass.get_cl_init cls
 		(**
 			Returns hx source file name where this type was declared
 		*)
@@ -994,7 +994,7 @@ class class_wrapper (cls) =
 			if not (has_class_flag cls CExtern) then
 				None
 			else
-				match cls.cl_init with
+				match TClass.get_cl_init cls with
 					| None -> None
 					| Some body ->
 						let path =
@@ -1009,8 +1009,8 @@ class class_wrapper (cls) =
 								cl_ordered_fields  = [];
 								cl_ordered_statics  = [];
 								cl_constructor = None;
-								cl_init = Some body
 						} in
+						TClass.set_cl_init additional_cls body;
 						remove_class_flag additional_cls CExtern;
 						Some (TClassDecl additional_cls)
 	end
@@ -4038,7 +4038,7 @@ class generator (ctx:php_generator_context) =
 			Returns PHP code for entry point
 		*)
 		method private get_entry_point : (string * string) option =
-			match ctx.pgc_common.main with
+			match ctx.pgc_common.main.main_expr with
 				| None -> None
 				| Some expr ->
 					let writer = new code_writer ctx ([], "") "" in

+ 2 - 2
src/generators/genpy.ml

@@ -2001,7 +2001,7 @@ module Generator = struct
 		!has_static_methods || !has_empty_static_vars
 
 	let gen_class_init ctx c =
-		match c.cl_init with
+		match TClass.get_cl_init c with
 			| None ->
 				()
 			| Some e ->
@@ -2410,7 +2410,7 @@ module Generator = struct
 		List.iter (fun f -> f()) (List.rev ctx.class_inits)
 
 	let gen_main ctx =
-		match ctx.com.main with
+		match ctx.com.main.main_expr with
 			| None ->
 				()
 			| Some e ->

+ 1 - 1
src/generators/genshared.ml

@@ -301,7 +301,7 @@ class ['a] typedef_interfaces (infos : 'a info_context) (anon_identification : '
 			try
 				let path_inner,is_extern = try Hashtbl.find interface_rewrites pfm.pfm_path with Not_found -> path_inner,false in
 				if self#implements_recursively c path_inner then raise (Unify_error [Unify_custom "already implemented"]);
-				anon_identification#unify tc pfm;
+				anon_identification#unify ~strict:false tc pfm;
 				let ci = self#make_interface_class pfm path_inner is_extern in
 				c.cl_implements <- (ci,[]) :: c.cl_implements;
 				(* print_endline (Printf.sprintf "%s IMPLEMENTS %s" (s_type_path c.cl_path) (s_type_path path_inner)); *)

+ 1 - 56
src/generators/genswf.ml

@@ -142,7 +142,7 @@ let build_dependencies t =
 			add_field f;
 			if c.cl_path <> (["flash"],"Boot") then add_path (["flash"],"Boot") DKExpr;
 		);
-		(match c.cl_init with
+		(match TClass.get_cl_init c with
 		| None -> ()
 		| Some e -> add_expr e);
 		(match c.cl_super with
@@ -222,8 +222,6 @@ let detect_format data p =
 	| _ ->
 		abort "Unknown file format" p
 
-open TTFData
-
 let build_swf9 com file swc =
 	let boot_name = if swc <> None || Common.defined com Define.HaxeBoot then "haxe" else "boot_" ^ (String.sub (Digest.to_hex (Digest.string (Filename.basename file))) 0 4) in
 	let code = Genswf9.generate com boot_name in
@@ -269,59 +267,6 @@ let build_swf9 com file swc =
 		| TClassDecl c ->
 			let rec loop = function
 				| [] -> acc
-				| (Meta.Font,(EConst (String(file,_)),p) :: args,_) :: l ->
-					let file = try Common.find_file com file with Not_found -> file in
-					let ch = try open_in_bin file with _ -> abort "File not found" p in
-					let ttf = try TTFParser.parse ch with e -> abort ("Error while parsing font " ^ file ^ " : " ^ Printexc.to_string e) p in
-					close_in ch;
-					let get_string e = match fst e with
-						| EConst (String(s,_)) -> s
-						| _ -> raise Not_found
-					in
-					let ttf_config = {
-						ttfc_range_str = "";
-						ttfc_font_name = None;
-						ttfc_font_weight = TFWRegular;
-						ttfc_font_posture = TFPNormal;
-					} in
-					begin match args with
-						| (EConst (String(str,_)),_) :: _ -> ttf_config.ttfc_range_str <- str;
-						| _ -> ()
-					end;
-					begin match args with
-						| _ :: [e] ->
-							begin match fst e with
-								| EObjectDecl fl ->
-									(try ttf_config.ttfc_font_name <- Some(get_string (Expr.field_assoc "fontName" fl)) with Not_found -> ());
-									(try ttf_config.ttfc_font_weight <- (
-										match get_string (Expr.field_assoc "fontWeight" fl) with
-										| "regular" -> TFWRegular
-										| "bold" -> TFWBold
-										| _ -> abort "Invalid fontWeight value. Must be `regular` or `bold`." p
-									) with Not_found -> ());
-									(try ttf_config.ttfc_font_posture <- (
-										match get_string (Expr.field_assoc "fontStyle" fl) with
-										| "normal" -> TFPNormal
-										| "italic" -> TFPItalic
-										| _ -> abort "Invalid fontStyle value. Must be `normal` or `italic`." p
-									) with Not_found -> ());
-								| _ ->
-									()
-							end
-						| _ ->
-							()
-					end;
-					let ttf_swf = TTFSwfWriter.to_swf ttf ttf_config in
-					let ch = IO.output_string () in
-					let b = IO.output_bits ch in
-					TTFSwfWriter.write_font2 ch b ttf_swf;
-					let data = IO.close_out ch in
-					incr cid;
-					classes := { f9_cid = Some !cid; f9_classname = s_type_path c.cl_path } :: !classes;
-					tag (TFont3 {
-						cd_id = !cid;
-						cd_data = data;
-					}) :: loop l
 				| (Meta.Bitmap,[EConst (String(file,_)),p],_) :: l ->
 					let data = load_file_data file p in
 					incr cid;

+ 4 - 4
src/generators/genswf9.ml

@@ -1982,7 +1982,7 @@ let generate_extern_inits ctx =
 	List.iter (fun t ->
 		match t with
 		| TClassDecl c when (has_class_flag c CExtern) ->
-			(match c.cl_init with
+			(match TClass.get_cl_init c with
 			| None -> ()
 			| Some e -> gen_expr ctx false e);
 		| _ -> ()
@@ -2007,7 +2007,7 @@ let generate_inits ctx =
 			j()
 		| _ -> ()
 	) ctx.com.types;
-	(match ctx.com.main with
+	(match ctx.com.main.main_expr with
 	| None -> ()
 	| Some e -> gen_expr ctx false e);
 	write ctx HRetVoid;
@@ -2035,7 +2035,7 @@ let generate_class_init ctx c hc =
 	if not (has_class_flag c CInterface) then write ctx HPopScope;
 	write ctx (HInitProp (type_path ctx c.cl_path));
 	if ctx.swc && c.cl_path = ctx.boot then generate_extern_inits ctx;
-	(match c.cl_init with
+	(match TClass.get_cl_init c with
 	| None -> ()
 	| Some e ->
 		gen_expr ctx false e;
@@ -2888,7 +2888,7 @@ let generate com boot_name =
 		try_scope_reg = None;
 		for_call = false;
 	} in
-	let types = if ctx.swc && com.main_class = None then
+	let types = if ctx.swc && com.main.main_class = None then
 		(*
 			make sure that both Boot and RealBoot are the first two classes in the SWC
 			this way initializing RealBoot will also run externs __init__ blocks before

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

@@ -379,8 +379,7 @@ let setup get_api =
 	let api = get_api (fun() -> (get_ctx()).curapi.get_com()) (fun() -> (get_ctx()).curapi) in
 	List.iter (fun (n,v) ->
 		Hashtbl.replace GlobalState.macro_lib n v
-	) api;
-	Globals.macro_platform := Globals.Eval
+	) api
 
 let do_reuse ctx api =
 	ctx.curapi <- api;

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

@@ -211,7 +211,7 @@ let create_static_prototype ctx mt =
 			|  _ ->
 				()
 		) fields;
-		begin match c.cl_init with
+		begin match TClass.get_cl_init c with
 			| None -> ()
 			| Some e -> DynArray.add delays (false,(fun _ -> ignore(eval_expr ctx (EKMethod(key,key___init__)) e)))
 		end;

+ 0 - 0
src/macro/eval/EvalStackTrace.ml → src/macro/eval/evalStackTrace.ml


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

@@ -2569,7 +2569,7 @@ module StdSys = struct
 	open Common
 
 	let args = vfun0 (fun () ->
-		encode_array (List.map create_unknown ((get_ctx()).curapi.MacroApi.get_com()).sys_args)
+		encode_array (List.map create_unknown ((get_ctx()).curapi.MacroApi.get_com()).args)
 	)
 
 	let _command = vfun1 (fun cmd ->
@@ -2632,7 +2632,7 @@ module StdSys = struct
 	let programPath = vfun0 (fun () ->
 		let ctx = get_ctx() in
 		let com = ctx.curapi.get_com() in
-		match com.main_class with
+		match com.main.main_class with
 		| None -> vnull
 		| Some p ->
 			match ctx.curapi.get_type (s_type_path p) with

+ 12 - 15
src/macro/macroApi.ml

@@ -53,7 +53,6 @@ type 'value compiler_api = {
 	define_module : string -> 'value list -> ((string * Globals.pos) list * Ast.import_mode) list -> Ast.type_path list -> unit;
 	module_dependency : string -> string -> unit;
 	current_module : unit -> module_def;
-	use_cache : unit -> bool;
 	format_string : string -> Globals.pos -> Ast.expr;
 	cast_or_unify : Type.t -> texpr -> Globals.pos -> bool;
 	add_global_metadata : string -> string -> (bool * bool * bool) -> pos -> unit;
@@ -515,7 +514,6 @@ and encode_exceptions_config ec =
 and encode_package_rule pr =
 	let tag, pl = match pr with
 		| Forbidden -> 0, []
-		| Directory (path) -> 1, [encode_string path]
 		| Remap (path) -> 2, [encode_string path]
 	in
 	encode_enum ~pos:None IPackageRule tag pl
@@ -1170,7 +1168,7 @@ and encode_tclass c =
 		"fields", encode_ref c.cl_ordered_fields (encode_and_map_array encode_cfield) (fun() -> "class fields");
 		"statics", encode_ref c.cl_ordered_statics (encode_and_map_array encode_cfield) (fun() -> "class fields");
 		"constructor", (match c.cl_constructor with None -> vnull | Some cf -> encode_cfref cf);
-		"init", (match c.cl_init with None -> vnull | Some e -> encode_texpr e);
+		"init", (match TClass.get_cl_init c with None -> vnull | Some e -> encode_texpr e);
 		"overrides", (encode_array (List.map encode_cfref (List.filter (fun cf -> has_class_field_flag cf CfOverride) c.cl_ordered_fields)))
 	]
 
@@ -1846,7 +1844,7 @@ let macro_api ccom get_api =
 			vnull
 		);
 		"class_path", vfun0 (fun() ->
-			encode_array (List.map encode_string (ccom()).class_path);
+			encode_array (List.map encode_string (ccom()).class_paths#as_string_list);
 		);
 		"resolve_path", vfun1 (fun file ->
 			let file = decode_string file in
@@ -2022,7 +2020,7 @@ let macro_api ccom get_api =
 				let api = encode_obj [
 					"outputFile", encode_string com.file;
 					"types", encode_array (List.map (fun t -> encode_type (type_of_module_type t)) com.types);
-					"main", (match com.main with None -> vnull | Some e -> encode_texpr e);
+					"main", (match com.main.main_expr with None -> vnull | Some e -> encode_texpr e);
 					"generateValue", vfun1 (fun v ->
 						let e = decode_texpr v in
 						let str = Genjs.gen_single_expr js_ctx e false in
@@ -2069,8 +2067,7 @@ let macro_api ccom get_api =
 		);
 		"flush_disk_cache", vfun0 (fun () ->
 			let com = (get_api()).get_com() in
-			com.file_lookup_cache#clear;
-			com.readdir_cache#clear;
+			com.class_paths#clear_cache;
 			vnull
 		);
 		"get_pos_infos", vfun1 (fun p ->
@@ -2169,15 +2166,15 @@ let macro_api ccom get_api =
 		"add_class_path", vfun1 (fun cp ->
 			let com = ccom() in
 			let cp = decode_string cp in
-			let cp = Path.add_trailing_slash cp in
-			com.class_path <- cp :: com.class_path;
+			let path = Path.add_trailing_slash cp in
+			let cp = new ClassPath.directory_class_path path User in
+			com.class_paths#add cp;
 			(match com.get_macros() with
 			| Some(mcom) ->
-				mcom.class_path <- cp :: mcom.class_path;
+				mcom.class_paths#add cp#clone;
 			| None ->
 				());
-			com.file_lookup_cache#clear;
-			com.readdir_cache#clear;
+			com.class_paths#clear_cache;
 			vnull
 		);
 		"add_native_lib", vfun1 (fun file ->
@@ -2244,8 +2241,8 @@ let macro_api ccom get_api =
 				"foptimize", vbool com.foptimize;
 				"platform", encode_platform com.platform;
 				"platformConfig", encode_platform_config com.config;
-				"stdPath", encode_array (List.map encode_string com.std_path);
-				"mainClass", (match com.main_class with None -> vnull | Some path -> encode_path path);
+				"stdPath", encode_array (List.map (fun path -> encode_string path#path) com.class_paths#get_std_paths);
+				"mainClass", (match com.main.main_class with None -> vnull | Some path -> encode_path path);
 				"packageRules", encode_string_map encode_package_rule com.package_rules;
 			]
 		);
@@ -2254,7 +2251,7 @@ let macro_api ccom get_api =
 			vnull
 		);
 		"get_main_expr", vfun0 (fun() ->
-			match (ccom()).main with None -> vnull | Some e -> encode_texpr e
+			match (ccom()).main.main_expr with None -> vnull | Some e -> encode_texpr e
 		);
 		"get_module_types", vfun0 (fun() ->
 			encode_array (List.map encode_module_type (ccom()).types)

+ 2 - 2
src/optimization/analyzer.ml

@@ -1126,7 +1126,7 @@ module Run = struct
 			| None -> ()
 			| Some f -> process_field false f;
 		end;
-		begin match c.cl_init with
+		begin match TClass.get_cl_init c with
 			| None ->
 				()
 			| Some e ->
@@ -1138,7 +1138,7 @@ module Run = struct
 					| TFunction tf -> tf.tf_expr
 					| _ -> die "" __LOC__
 				in
-				c.cl_init <- Some e
+				TClass.set_cl_init c e
 		end
 
 	let run_on_type com config t =

+ 66 - 38
src/optimization/dce.ml

@@ -40,7 +40,7 @@ type dce = {
 	mutable marked_maybe_fields : tclass_field list;
 	mutable t_stack : t list;
 	mutable ts_stack : t list;
-	mutable features : (string, class_field_ref list) Hashtbl.t;
+	mutable features : (string, class_field_ref list ref) Hashtbl.t;
 }
 
 let push_class dce c =
@@ -121,7 +121,8 @@ let mk_keep_meta pos =
 *)
 let rec keep_field dce cf c kind =
 	let is_static = kind = CfrStatic in
-	Meta.has_one_of (Meta.Used :: keep_metas) cf.cf_meta
+	Meta.has_one_of keep_metas cf.cf_meta
+	|| has_class_field_flag cf CfUsed
 	|| cf.cf_name = "__init__"
 	|| has_class_field_flag cf CfExtern
 	|| (not is_static && overrides_extern_field cf c)
@@ -153,7 +154,7 @@ let rec check_feature dce s =
 		List.iter (fun cfr ->
 			let (c, cf) = resolve_class_field_ref dce.com cfr in
 			mark_field dce c cf cfr.cfr_kind
-		) l;
+		) !l;
 		Hashtbl.remove dce.features s;
 	with Not_found ->
 		()
@@ -166,8 +167,8 @@ and check_and_add_feature dce s =
 (* mark a field as kept *)
 and mark_field dce c cf kind =
 	let add c' cf =
-		if not (Meta.has Meta.Used cf.cf_meta) then begin
-			cf.cf_meta <- (mk_used_meta cf.cf_pos) :: cf.cf_meta;
+		if not (has_class_field_flag cf CfUsed) then begin
+			add_class_field_flag cf CfUsed;
 			dce.added_fields <- (c',cf,kind) :: 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);
@@ -185,6 +186,11 @@ and mark_field dce c cf kind =
 			| None -> ()
 		in
 		loop c
+	| CfrInit ->
+		begin match c.cl_init with
+			| Some cf -> add c cf
+			| None -> ()
+		end
 	| CfrStatic | CfrMember ->
 		let stat = kind = CfrStatic in
 		if not (PMap.mem cf.cf_name (if stat then c.cl_statics else c.cl_fields)) then begin
@@ -202,20 +208,20 @@ let rec update_marked_class_fields dce c =
 	let pop = push_class dce c in
 	(* mark all :?used fields as surely :used now *)
 	List.iter (fun cf ->
-		if Meta.has Meta.MaybeUsed cf.cf_meta then mark_field dce c cf CfrStatic
+		if has_class_field_flag cf CfMaybeUsed then mark_field dce c cf CfrStatic
 	) c.cl_ordered_statics;
 	List.iter (fun cf ->
-		if Meta.has Meta.MaybeUsed cf.cf_meta then mark_field dce c cf CfrMember
+		if has_class_field_flag cf CfMaybeUsed then mark_field dce c cf CfrMember
 	) c.cl_ordered_fields;
 	(* we always have to keep super classes and implemented interfaces *)
-	(match c.cl_init with None -> () | Some init -> dce.follow_expr dce init);
+	(match TClass.get_cl_init c with None -> () | Some init -> dce.follow_expr dce init);
 	List.iter (fun (c,_) -> mark_class dce c) c.cl_implements;
 	(match c.cl_super with None -> () | Some (csup,pl) -> mark_class dce csup);
 	pop()
 
 (* 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 <- (mk_used_meta c.cl_pos) :: c.cl_meta;
+and mark_class dce c = if not (has_class_flag c CUsed) then begin
+	add_class_flag c CUsed;
 	check_feature dce (Printf.sprintf "%s.*" (s_type_path c.cl_path));
 	update_marked_class_fields dce c;
 end
@@ -238,8 +244,8 @@ and mark_t dce p t =
 		dce.t_stack <- t :: dce.t_stack;
 		begin match follow t with
 		| TInst({cl_kind = KTypeParameter ttp} as c,pl) ->
-			if not (Meta.has Meta.Used c.cl_meta) then begin
-				c.cl_meta <- (mk_used_meta c.cl_pos) :: c.cl_meta;
+			if not (has_class_flag c CUsed) then begin
+				add_class_flag c CUsed;
 				List.iter (mark_t dce p) (get_constraints ttp);
 			end;
 			List.iter (mark_t dce p) pl
@@ -288,10 +294,10 @@ let mark_dependent_fields dce csup n kind =
 			let cf = PMap.find n (if stat then c.cl_statics else c.cl_fields) in
 			(* if it's clear that the class is kept, the field has to be kept as well. This is also true for
 				extern interfaces because we cannot remove fields from them *)
-			if Meta.has Meta.Used c.cl_meta || ((has_class_flag csup CInterface) && (has_class_flag csup CExtern)) then mark_field dce c cf kind
+			if has_class_flag c CUsed || ((has_class_flag csup CInterface) && (has_class_flag csup CExtern)) then mark_field dce c cf kind
 			(* otherwise it might be kept if the class is kept later, so mark it as :?used *)
-			else if not (Meta.has Meta.MaybeUsed cf.cf_meta) then begin
-				cf.cf_meta <- (Meta.MaybeUsed,[],cf.cf_pos) :: cf.cf_meta;
+			else if not (has_class_field_flag cf CfMaybeUsed) then begin
+				add_class_field_flag cf CfMaybeUsed;
 				dce.marked_maybe_fields <- cf :: dce.marked_maybe_fields;
 			end
 		with Not_found ->
@@ -685,7 +691,7 @@ and expr dce e =
 let fix_accessors com =
 	List.iter (fun mt -> match mt with
 		(* filter empty abstract implementation classes (issue #1885). *)
-		| TClassDecl({cl_kind = KAbstractImpl _} as c) when c.cl_ordered_statics = [] && c.cl_ordered_fields = [] && not (Meta.has Meta.Used c.cl_meta) ->
+		| TClassDecl({cl_kind = KAbstractImpl _} as c) when c.cl_ordered_statics = [] && c.cl_ordered_fields = [] && not (has_class_flag c CUsed) ->
 			add_class_flag c CExtern;
 		| TClassDecl({cl_kind = KAbstractImpl a} as c) when a.a_enum ->
 			let is_runtime_field cf =
@@ -716,16 +722,44 @@ let fix_accessors com =
 		| _ -> ()
 	) com.types
 
+let extract_if_feature meta =
+	let rec loop = function
+		| [] ->
+			[]
+		| (Meta.IfFeature,el,_) :: _ ->
+			List.map (fun (e,p) -> match e with
+				| EConst (String(s,_)) -> s
+				| _ -> Error.raise_typing_error "String expected" p
+			) el
+		| _ :: l ->
+			loop l
+	in
+	loop meta
+
 let collect_entry_points dce com =
+	let delayed = ref [] in
+	let check_feature cf_ref meta =
+		List.iter (fun s ->
+			try
+				let l = Hashtbl.find dce.features s in
+				l := cf_ref :: !l
+			with Not_found ->
+				Hashtbl.add dce.features s (ref [cf_ref])
+		) meta;
+	in
 	List.iter (fun t ->
-		let mt = t_infos t in
-		mt.mt_meta <- Meta.remove Meta.Used mt.mt_meta;
 		match t with
 		| TClassDecl c ->
+			remove_class_flag c CUsed;
+			let cl_if_feature = extract_if_feature c.cl_meta in
 			let keep_class = keep_whole_class dce c && (not (has_class_flag c CExtern) || (has_class_flag c CInterface)) in
 			let is_struct = dce.com.platform = Hl && Meta.has Meta.Struct c.cl_meta in
 			let loop kind cf =
-				if keep_class || is_struct || keep_field dce cf c kind then mark_field dce c cf kind
+				let cf_ref = mk_class_field_ref c cf kind com.is_macro_context in
+				let cf_if_feature = extract_if_feature cf.cf_meta in
+				check_feature cf_ref (cl_if_feature @ cf_if_feature);
+				(* Have to delay mark_field so that we see all @:ifFeature *)
+				if keep_class || is_struct || keep_field dce cf c kind then delayed := (fun () -> mark_field dce c cf kind) :: !delayed
 			in
 			List.iter (loop CfrStatic) c.cl_ordered_statics;
 			List.iter (loop CfrMember) c.cl_ordered_fields;
@@ -734,21 +768,22 @@ let collect_entry_points dce com =
 				| None -> ()
 			end;
 			begin match c.cl_init with
-				| Some e when keep_class || Meta.has Meta.KeepInit c.cl_meta ->
-					(* create a fake field to deal with our internal logic (issue #3286) *)
-					let cf = mk_field "__init__" e.etype e.epos null_pos in
-					cf.cf_expr <- Some e;
-					loop CfrStatic cf
+				| Some cf when keep_class || Meta.has Meta.KeepInit c.cl_meta ->
+					loop CfrInit cf
 				| _ ->
 					()
 			end;
 		| TEnumDecl en when keep_whole_enum dce en ->
-			let pop = push_class dce {null_class with cl_module = en.e_module} in
-			mark_enum dce en;
-			pop()
+			en.e_meta <- Meta.remove Meta.Used en.e_meta;
+			delayed := (fun () ->
+				let pop = push_class dce {null_class with cl_module = en.e_module} in
+				mark_enum dce en;
+				pop()
+			) :: !delayed;
 		| _ ->
 			()
 	) com.types;
+	List.iter (fun f -> f()) !delayed;
 	if dce.debug then begin
 		List.iter (fun (c,cf,_) -> match cf.cf_expr with
 			| None -> ()
@@ -840,8 +875,8 @@ let sweep dce com =
 			let inef cf = is_physical_field cf in
 			let has_non_extern_fields = List.exists inef c.cl_ordered_fields || List.exists inef c.cl_ordered_statics in
 			(* we keep a class if it was used or has a used field *)
-			if Meta.has Meta.Used c.cl_meta || has_non_extern_fields then loop (mt :: acc) l else begin
-				(match c.cl_init with
+			if has_class_flag c CUsed || has_non_extern_fields then loop (mt :: acc) l else begin
+				(match TClass.get_cl_init c with
 				| Some f when Meta.has Meta.KeepInit c.cl_meta ->
 					(* it means that we only need the __init__ block *)
 					add_class_flag c CExtern;
@@ -868,7 +903,7 @@ let run com main mode =
 		com = com;
 		full = full;
 		dependent_types = Hashtbl.create 0;
-		std_dirs = if full then [] else List.map Path.get_full_path com.std_path;
+		std_dirs = if full then [] else List.map (fun path -> Path.get_full_path path#path) com.class_paths#get_std_paths;
 		debug = Common.defined com Define.DceDebug;
 		added_fields = [];
 		follow_expr = expr;
@@ -879,12 +914,6 @@ let run com main mode =
 		features = Hashtbl.create 0;
 		curclass = null_class;
 	} in
-	List.iter (fun m ->
-		List.iter (fun (s,v) ->
-			if Hashtbl.mem dce.features s then Hashtbl.replace dce.features s (v :: Hashtbl.find dce.features s)
-			else Hashtbl.add dce.features s [v]
-		) m.m_extra.m_if_feature;
-	) com.modules;
 
 	(* first step: get all entry points, which is the main method and all class methods which are marked with @:keep *)
 	collect_entry_points dce com;
@@ -928,5 +957,4 @@ let run com main mode =
 	) com.types;
 
 	(* cleanup added fields metadata - compatibility with compilation server *)
-	List.iter (fun cf -> cf.cf_meta <- Meta.remove Meta.Used cf.cf_meta) dce.marked_fields;
-	List.iter (fun cf -> cf.cf_meta <- Meta.remove Meta.MaybeUsed cf.cf_meta) dce.marked_maybe_fields
+	List.iter (fun cf -> remove_class_field_flag cf CfUsed) dce.marked_fields

+ 0 - 2
src/typing/callUnification.ml

@@ -513,9 +513,7 @@ object(self)
 			let ep = err.err_pos in
 			(* display additional info in the case the error is not part of our original call *)
 			if ep.pfile <> p.pfile || ep.pmax < p.pmin || ep.pmin > p.pmax then begin
-				locate_macro_error := false;
 				old (if (ep = null_pos) then { err with err_pos = p } else err);
-				locate_macro_error := true;
 				(* TODO add as sub for above error *)
 				if ep <> null_pos then old (make_error ~depth:(err.err_depth+1) (Custom (compl_msg "Called from macro here")) p);
 			end else

+ 38 - 25
src/typing/fields.ml

@@ -109,7 +109,7 @@ let field_access ctx mode f fh e pfield =
 	let pfull = punion e.epos pfield in
 	let is_set = match mode with MSet _ -> true | _ -> false in
 	check_no_closure_meta ctx f fh mode pfield;
-	let bypass_accessor = if ctx.bypass_accessor > 0 then (ctx.bypass_accessor <- ctx.bypass_accessor - 1; true) else false in
+	let bypass_accessor () = if ctx.bypass_accessor > 0 then (ctx.bypass_accessor <- ctx.bypass_accessor - 1; true) else false in
 	let make_access inline = FieldAccess.create e f fh (inline && ctx.allow_inline) pfull in
 	match f.cf_kind with
 	| Method m ->
@@ -208,8 +208,6 @@ let field_access ctx mode f fh e pfield =
 		| AccCall ->
 			let m = (match mode with MSet _ -> "set_" | _ -> "get_") ^ f.cf_name in
 			let bypass_accessor =
-				bypass_accessor
-				||
 				(
 					m = ctx.curfield.cf_name
 					&&
@@ -218,7 +216,7 @@ let field_access ctx mode f fh e pfield =
 					| TLocal v -> Option.map_default (fun vthis -> v == vthis) false ctx.vthis
 					| TTypeExpr (TClassDecl c) when c == ctx.curclass -> true
 					| _ -> false
-				)
+				) || bypass_accessor ()
 			in
 			if bypass_accessor then (
 				(match e.eexpr with TLocal _ when Common.defined ctx.com Define.Haxe3Compat -> warning ctx WTemp "Field set has changed here in Haxe 4: call setter explicitly to keep Haxe 3.x behaviour" pfield | _ -> ());
@@ -272,7 +270,7 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 		| None -> raise Not_found
 	in
 	let type_field_by_et f e t =
-		f { e with etype = t } (follow_without_type t)
+		f e (follow_without_type t)
 	in
 	let type_field_by_e f e =
 		f e (follow_without_type e.etype)
@@ -293,7 +291,15 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 		type_field_by_forward f Meta.ForwardStatics a
 	in
 	let type_field_by_forward_member f e a tl =
-		let f () = type_field_by_et f e (Abstract.get_underlying_type ~return_first:true a tl) in
+		let f () =
+			let t = Abstract.get_underlying_type ~return_first:true a tl in
+			let e = if Meta.has Meta.ForwardAccessOnAbstract a.a_meta then
+				e
+			else
+				mk (TCast(e,None)) t e.epos
+			in
+			type_field_by_et f e t
+		in
 		type_field_by_forward f Meta.Forward a
 	in
 	let type_field_by_typedef f e td tl =
@@ -329,29 +335,33 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 				type_field_by_interfaces e c
 			)
 		| TAnon a ->
-			(try
-				let f = PMap.find i a.a_fields in
-				if has_class_field_flag f CfImpl && not (has_class_field_flag f CfEnum) then display_error ctx.com "Cannot access non-static abstract field statically" pfield;
-				match !(a.a_status) with
+			begin match !(a.a_status) with
+				| ClassStatics c ->
+					begin try
+						let cf = PMap.find i c.cl_statics in
+						if has_class_field_flag cf CfImpl && not (has_class_field_flag cf CfEnum) then display_error ctx.com "Cannot access non-static abstract field statically" pfield;
+						field_access cf (FHStatic c)
+					with Not_found ->
+						begin match c.cl_kind with
+						| KAbstractImpl a ->
+							type_field_by_forward_static (fun() ->
+								let mt = try module_type_of_type a.a_this with Exit -> raise Not_found in
+								let et = type_module_type ctx mt p in
+								type_field_by_e type_field_by_type et
+							) a
+						| _ ->
+							raise Not_found
+						end
+					end
 				| EnumStatics en ->
-					let c = try PMap.find f.cf_name en.e_constrs with Not_found -> die "" __LOC__ in
+					let c = PMap.find i en.e_constrs in
 					let fmode = FEnum (en,c) in
 					let t = enum_field_type ctx en c p in
 					AKExpr (mk (TField (e,fmode)) t p)
-				| ClassStatics c ->
-					field_access f (FHStatic c)
 				| _ ->
-					field_access f FHAnon
-			with Not_found ->
-				match !(a.a_status) with
-				| ClassStatics { cl_kind = KAbstractImpl a } ->
-					type_field_by_forward_static (fun() ->
-						let mt = try module_type_of_type a.a_this with Exit -> raise Not_found in
-						let et = type_module_type ctx mt p in
-						type_field_by_e type_field_by_type et
-					) a
-				| _ -> raise Not_found
-			)
+					let cf = PMap.find i a.a_fields in
+					field_access cf FHAnon
+			end;
 		| TMono r ->
 			let mk_field () = {
 				(mk_field i (mk_mono()) p null_pos) with
@@ -372,7 +382,10 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 					field_access f FHAnon
 				)
 			| CTypes tl ->
-				type_field_by_list (fun (t,_) -> type_field_by_et type_field_by_type e t) tl
+				type_field_by_list (fun (t,_) ->
+					let e = mk (TCast(e,None)) t e.epos in
+					type_field_by_et type_field_by_type e t
+				) tl
 			| CUnknown ->
 				if not (List.exists (fun (m,_) -> m == r) ctx.monomorphs.perfunction) && not (ctx.untyped && ctx.com.platform = Neko) then
 					ctx.monomorphs.perfunction <- (r,p) :: ctx.monomorphs.perfunction;

+ 2 - 2
src/typing/finalization.ml

@@ -9,7 +9,7 @@ open Typecore
 (* FINALIZATION *)
 
 let get_main ctx types =
-	match ctx.com.main_class with
+	match ctx.com.main.main_class with
 	| None -> None
 	| Some path ->
 		let p = null_pos in
@@ -179,7 +179,7 @@ let sort_types com (modules : module_lut) =
 	and walk_class p c =
 		(match c.cl_super with None -> () | Some (c,_) -> loop_class p c);
 		List.iter (fun (c,_) -> loop_class p c) c.cl_implements;
-		(match c.cl_init with
+		(match TClass.get_cl_init c with
 		| None -> ()
 		| Some e -> walk_expr p e);
 		PMap.iter (fun _ f ->

+ 34 - 11
src/typing/generic.ml

@@ -231,6 +231,10 @@ let build_instances ctx t p =
 	in
 	loop t
 
+let clone_type_parameter gctx mg path ttp =
+	let ttp = clone_type_parameter (generic_substitute_type gctx) path ttp in
+	ttp.ttp_class.cl_module <- mg;
+	ttp
 
 let build_generic_class ctx c p tl =
 	let pack = fst c.cl_path in
@@ -308,14 +312,7 @@ let build_generic_class ctx c p tl =
 		set_type_parameter_dependencies mg tl;
 		let build_field cf_old =
 			let params = List.map (fun ttp ->
-				let c = {ttp.ttp_class with cl_module = mg} in
-				let def = Option.map (generic_substitute_type gctx) ttp.ttp_default in
-				let constraints = match ttp.ttp_constraints with
-					| None -> None
-					| Some constraints -> Some (lazy (List.map (generic_substitute_type gctx) (Lazy.force constraints)))
-				in
-				let ttp' = mk_type_param c ttp.ttp_host def constraints in
-				c.cl_kind <- KTypeParameter ttp';
+				let ttp' = clone_type_parameter gctx mg ([cf_old.cf_name],ttp.ttp_name) ttp in
 				(ttp.ttp_type,ttp')
 			) cf_old.cf_params in
 			let param_subst = List.map (fun (t,ttp) -> t,(ttp.ttp_type,None)) params in
@@ -366,7 +363,7 @@ let build_generic_class ctx c p tl =
 			cf_new.cf_type <- TLazy r;
 			cf_new
 		in
-		if c.cl_init <> None then raise_typing_error "This class can't be generic" p;
+		if TClass.get_cl_init c <> None then raise_typing_error "This class can't be generic" p;
 		List.iter (fun cf -> match cf.cf_kind with
 			| Method MethMacro when not ctx.com.is_macro_context -> ()
 			| _ -> raise_typing_error "A generic class can't have static fields" cf.cf_pos
@@ -408,6 +405,17 @@ let build_generic_class ctx c p tl =
 		TInst (cg,[])
 	end
 
+let extract_type_parameters tl =
+	let params = DynArray.create () in
+	let rec loop t = match follow t with
+		| TInst({cl_kind = KTypeParameter ttp},[]) ->
+			DynArray.add params ttp;
+		| _ ->
+			TFunctions.iter loop t
+	in
+	List.iter loop tl;
+	DynArray.to_list params
+
 let type_generic_function ctx fa fcc with_type p =
 	let c,stat = match fa.fa_host with
 		| FHInstance(c,tl) -> c,false
@@ -431,8 +439,18 @@ let type_generic_function ctx fa fcc with_type p =
 	) monos;
 	let el = fcc.fc_args in
 	let gctx = make_generic ctx cf.cf_params monos (Meta.has (Meta.Custom ":debug.generic") cf.cf_meta) p in
-	let fc_type = build_instances ctx fcc.fc_type p in
 	let name = cf.cf_name ^ "_" ^ gctx.name in
+	let params = extract_type_parameters monos in
+	let clones = List.map (fun ttp ->
+		let name_path = if (fst ttp.ttp_class.cl_path) = [cf.cf_name] then ([name],ttp.ttp_name) else ttp.ttp_class.cl_path in
+		clone_type_parameter gctx c.cl_module name_path ttp
+	) params in
+	let param_subst = List.map2 (fun ttp ttp' ->
+		(ttp.ttp_type,ttp')
+	) params clones in
+	let param_subst = List.map (fun (t,ttp) -> t,(ttp.ttp_type,None)) param_subst in
+	let gctx = {gctx with subst = param_subst @ gctx.subst} in
+	let fc_type = build_instances ctx (generic_substitute_type gctx fcc.fc_type) p in
 	let unify_existing_field tcf pcf = try
 		unify_raise tcf fc_type p
 	with Error ({ err_message = Unify _; err_depth = depth } as err) ->
@@ -483,7 +501,12 @@ let type_generic_function ctx fa fcc with_type p =
 			);
 			cf2.cf_kind <- cf.cf_kind;
 			if not (has_class_field_flag cf CfPublic) then remove_class_field_flag cf2 CfPublic;
-			cf2.cf_meta <- (Meta.NoCompletion,[],p) :: (Meta.NoUsing,[],p) :: (Meta.GenericInstance,[],p) :: cf.cf_meta
+			let meta = List.filter (fun (meta,_,_) -> match meta with
+				| Meta.Generic -> false
+				| _ -> true
+			) cf.cf_meta in
+			cf2.cf_meta <- (Meta.NoCompletion,[],p) :: (Meta.NoUsing,[],p) :: (Meta.GenericInstance,[],p) :: meta;
+			cf2.cf_params <- clones
 		in
 		let mk_cf2 name =
 			mk_field ~static:stat name fc_type cf.cf_pos cf.cf_name_pos

+ 17 - 14
src/typing/macroContext.ml

@@ -34,7 +34,6 @@ module Interp = struct
 	include BuiltApi
 end
 
-let macro_enable_cache = ref false
 let macro_interp_cache = ref None
 
 let safe_decode com v expected t p f =
@@ -270,9 +269,6 @@ let make_macro_com_api com mcom p =
 		current_module = (fun() ->
 			null_module
 		);
-		use_cache = (fun() ->
-			!macro_enable_cache
-		);
 		format_string = (fun s p ->
 			FormatString.format_string com.defines s p (fun e p -> (e,p))
 		);
@@ -610,9 +606,7 @@ let init_macro_interp mctx mint =
 	ignore(TypeloadModule.load_module mctx (["haxe";"macro"],"Expr") p);
 	ignore(TypeloadModule.load_module mctx (["haxe";"macro"],"Type") p);
 	Interp.init mint;
-	if !macro_enable_cache && not (Common.defined mctx.com Define.NoMacroCache) then begin
-		macro_interp_cache := Some mint;
-	end
+	macro_interp_cache := Some mint
 
 and flush_macro_context mint mctx =
 	let t = macro_timer mctx.com ["flush"] in
@@ -664,7 +658,6 @@ and flush_macro_context mint mctx =
 		Exceptions.patch_constructors mctx;
 		(fun mt -> AddFieldInits.add_field_inits mctx.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt);
 		minimal_restore;
-		Naming.apply_native_paths
 	] in
 	let ready = fun t ->
 		FiltersCommon.apply_filters_once mctx expr_filters t;
@@ -709,16 +702,26 @@ let create_macro_context com =
 	let com2 = Common.clone com true in
 	com.get_macros <- (fun() -> Some com2);
 	com2.package_rules <- PMap.empty;
-	com2.main_class <- None;
 	(* Inherit most display settings, but require normal typing. *)
 	com2.display <- {com.display with dms_kind = DMNone; dms_full_typing = true; dms_force_macro_typing = true; dms_inline = true; };
-	com2.class_path <- List.filter (fun s -> not (ExtString.String.exists s "/_std/")) com2.class_path;
-	let name = platform_name !Globals.macro_platform in
-	com2.class_path <- List.map (fun p -> p ^ name ^ "/_std/") com2.std_path @ com2.class_path;
+	com2.class_paths#lock_context "macro" false;
+	let name = platform_name Eval in
+	let eval_std = ref None in
+	com2.class_paths#modify (fun cp -> match cp#scope with
+		| StdTarget ->
+			[]
+		| Std ->
+			eval_std := Some (new ClassPath.directory_class_path (cp#path ^ name ^ "/_std/") StdTarget);
+			[cp#clone]
+		| _ ->
+			[cp#clone]
+	) com.class_paths#as_list;
+	(* Eval _std must be in front so we don't look into hxnodejs or something. *)
+	com2.class_paths#add (Option.get !eval_std);
 	let defines = adapt_defines_to_macro_context com2.defines; in
 	com2.defines.values <- defines.values;
 	com2.defines.defines_signature <- None;
-	com2.platform <- !Globals.macro_platform;
+	com2.platform <- Eval;
 	Common.init_platform com2;
 	let mctx = !create_context_ref com2 None in
 	mctx.is_display_file <- false;
@@ -1066,7 +1069,7 @@ let interpret ctx =
 	let mctx = get_macro_context ctx in
 	let mctx = Interp.create ctx.com (make_macro_api ctx mctx null_pos) false in
 	Interp.add_types mctx ctx.com.types (fun t -> ());
-	match ctx.com.main with
+	match ctx.com.main.main_expr with
 		| None -> ()
 		| Some e -> ignore(Interp.eval_expr mctx e)
 

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