Port and oracle
Each OCaml module in upstream's haxe/src was translated to a Haxe module at the same path, keeping function order, branch order and data layout. The reference compiler built from the pinned upstream commit is the oracle: for the same arguments, the port must write the same HXB modules, byte for byte. A first attempt that reimplemented parts of the compiler by hand was abandoned in favor of this direct translation.
OCaml semantics in the output
Most early mismatches came from OCaml behavior that reaches the output: Hashtbl iteration order (reproduced bucket by bucket), sorted PMap iteration, right-to-left evaluation of arguments with side effects, physical equality, 63-bit integers and float printing. These are emulated in src/core/ds.
Macros
Macros needed a port of the Eval interpreter and the macro API. After that, the 66 macro conformance cases, --interp, the compilation server, display services and haxelib support followed, each tested against the reference.
Performance and the C backend
Built for existing Haxe targets (HashLink, HL/C, JVM, C++, JS), the port was 1.3× to several times slower than the OCaml compiler, and the WebAssembly route through HL/C was large and slow to start. A dedicated backend was written instead: hxc lowers the typed program to C, with a runtime that has a precise generational GC, OS threads, TLS and libuv. Built with clang, it compiles its own sources to HXB with about 13% less CPU time and 15% less memory than the OCaml compiler (sequential passes, one machine; see the benchmarks). The same C, built with Emscripten, runs the playground; built with Cosmopolitan, it gives one binary for several systems.
Upstream's tests
Upstream's target-independent CI job (unit, misc, threads, display, server and two third-party projects) runs against the native build and passes. Running it found bugs that the conformance cases did not.
Target generators
The generators for JS, Lua, Python, PHP, Neko, HashLink, JVM, C++ and SWF were translated last, together with the OCaml libraries they use (Neko bytecode, SWF and ABC writers, zlib deflate). A differential fuzzer that generates random well-typed programs compares their output with the reference's for each target.
Keeping up with upstream
The pinned commit is moved forward by porting each upstream commit in between and rerunning the full test matrix against the rebuilt reference.