A Go target for Haxe
Write Haxe and get Go source output you
can build with the standard go toolchain.
- Go interop - automatic extern generation, and interop between Haxe and Go types.
- Self compiled - the compiler runs on the Go target itself.
- Custom target - integrates through Haxe's
--custom-targetdefine; no forked compiler required. - Written in Haxe - entire compiler + stdlib code is written in Haxe.
- Concurrency - use goroutines, channels, and
select(go.Syntax.select).
⚠️ Experimental. hx2go is under active development. Expect rough edges and breaking changes.
- Haxe nightly
5.0.0-preview.1+957b2c7or newer
- Go
1.26or newer
Install the library via haxelib:
haxelib git hx2go https://github.com/go2hx/hx2goAdd the target flags to your .hxml:
-L hx2go
--custom-target go=output
# Build and run the generated module
--cmd go -C output/main run .Given a Main.hx:
function main() {
trace("Hello from Haxe, running on Go!");
}Compiling with the flags above generates a Go module under output/main and runs it.
Change go run to go build:
--cmd go build ./output/mainIt will create an executable located at ./output/main/main (on Windows OS with the extension .exe).
For example, to launch an HTTP file server, alter Main.hx to:
import go.net.Http;
import go.net.http.Dir;
function main() {
var port = ":8082";
trace('http file server: http://localhost$port');
var dir:Dir = ".";
var err = Http.listenAndServe(port, Http.fileServer(dir));
trace(err);
}For example, to print the ASCII graph below:
Main.hx:6:
10.00 ┤ ╭╮
9.00 ┤ ╭╮ ││
8.00 ┤ ││ ╭╮││
7.00 ┤ ││ ││││╭╮
6.00 ┤ │╰╮ ││││││ ╭
5.00 ┤ │ │ ╭╯╰╯│││╭╯
4.00 ┤╭╯ │╭╯ ││││
3.00 ┼╯ ││ ││││
2.00 ┤ ╰╯ ╰╯╰╯
Add the go library flag to your .hxml:
-D go-lib=github.com/guptarohit/asciigraphRun the Haxe compiler using the altered .hxml once before trying to access the externs to allow the compiler to generate them.
Alter Main.hx to:
import go.github_com.guptarohit.Asciigraph;
function main() {
var data:Array<Float> = [3, 4, 9, 6, 2, 4, 5, 8, 5, 10, 2, 7, 2, 5, 6];
var graph:String = Asciigraph.plot(data);
trace("\n" + graph);
}In some libraries like ebiten or bubbletea a class must be compatible with a given interface.
This is not the case by default, as such, you must use @:go.Export.
By using this meta you create some aliases where go-compatible names are used and types like
go.Tuple<T> are brought back to actual tuples. Try the following:
Add the go library flag to your .hxml:
-D go-lib=github.com/hajimehoshi/ebiten/v2
-D go-lib=github.com/hajimehoshi/ebiten/v2/ebitenutilRun the Haxe compiler using the altered .hxml once before trying to access the externs to allow the compiler to generate them.
Alter Main.hx to:
import go.github_com.hajimehoshi.ebiten.v2.Ebitenutil;
import go.github_com.hajimehoshi.ebiten.v2.Ebiten;
import go.github_com.hajimehoshi.ebiten.v2.Image;
import go.Pointer;
import go.GoInt;
import go.Error;
import go.Tuple;
class Game {
public function new() {
return;
}
@:go.Export
public function draw(screen: Pointer<Image>): Void {
Ebitenutil.debugPrint(screen, "Hello, World!");
}
@:go.Export
public function update(): Error {
return null;
}
@:go.Export
@:go.Tuple("screenWidth", "screenHeight")
public function layout(outsideWidth: GoInt, outsideHeight: GoInt): Tuple<{ screenWidth: GoInt, screenHeight: GoInt }> {
return { screenWidth: 640, screenHeight: 480 };
}
}
function main() {
Ebiten.setWindowSize(640, 480);
Ebiten.setWindowTitle("Hello, World!");
Ebiten.runGame(new Game()).sure();
}Note how Ebiten.runGame has the following signature in go:
func RunGame(game Game) errorWhere Game is:
type Game interface {
Update() error
Draw(screen *Image)
Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int)
}Due to the usage of @:go.Export on these 3 functions, the Haxe class can be used as the implementation for this Go interface.
Goroutines / Channels
import go.Chan;
import go.Syntax;
function sum(c: Chan<Int>, values: Array<Int>): Void {
var sum = 0;
for (value in values) {
sum += value;
}
c.send(sum);
}
function main() {
var arr: Array<Int> = [7, 2, 8, -9, 4, 0];
var ch: Chan<Int> = new Chan();
Syntax.go(sum.bind(ch, arr.slice(0, 3)));
Syntax.go(sum.bind(ch, arr.slice(3, 6)));
var x = ch.receive();
var y = ch.receive();
trace(x, y, x + y);
}Select
import go.Syntax;
import go.Chan;
function fib(c: Chan<Int>, quit: Chan<Int>) {
var x = 0;
var y = 1;
var f = true;
while (f) {
Syntax.select(
Select.send(c, x, () -> {
var v = x;
x = y;
y = v + y;
}),
Select.receive(quit, _ -> {
trace("quit");
f = false;
})
);
}
}
function main() {
var chan: Chan<Int> = new Chan();
var quit: Chan<Int> = new Chan();
Syntax.go(() -> {
for (i in 0...10) {
trace(chan.receive());
}
quit.send(0);
});
fib(chan, quit);
}Defer
import go.Syntax;
function main() {
Syntax.defer(() -> trace("Second!"));
trace("First!");
}Fixed-size Arrays
import go.crypto.Sha256_;
import go.GoArray;
import go.Byte;
import go.Slice;
function main() {
var fixed: GoArray<Byte, 32> = Sha256_.sum256("Hello, World!");
for (value in fixed) {
trace(value);
}
trace(fixed[0]);
fixed[3] = 42; // works like normal
var slice: Slice<Byte> = fixed; // [N]T -> []T can be implicit
trace(slice);
slice[0] = 123;
trace(fixed[0], slice[0]); // not copied
var array: Array<Byte> = slice;
array[0] = 111;
trace(fixed[0], slice[0], array[0]); // Array<T>, Slice<T> and GoArray<T, N> all hold the same identity
array.push(0); // at this point Array<T> has grown, and doesn't share the identity with GoArray<T, N> and Slice<T> anymore
array[0] = 222;
trace(fixed[0], slice[0], array[0]);
// please be careful with casts to array as they *may* share identity, but they *may* not.
// consider using copy() when casting Slice<T> to Array<T>
// GoArray<T, N> = [N]T
// Slice<T> = []T
// Array<T> = *[]T
}Raw syntax
import go.Syntax;
function main() {
var result = Syntax.code("{0} + 5", 10); // beware: types are *not* checked
trace(result);
}ℹ️ The above graph updates in real-time as new changes are merged upstream.
Contributions are welcome. Please open an issue to discuss substantial changes before sending a pull request.
git clone https://github.com/go2hx/hx2go --recursive
cd hx2go
haxelib dev hx2go .the tests require the utest library
Runs the tests found at ./tests
haxe Tests.hxmlRuns the Haxe compiler's unit tests
haxe scripts/haxeunit.hxml
hx2go is open-source software licensed under the MIT license.
Creators: Mikaib, Elliott Stoneham, PXshadow.
