Giter VIP home page Giter VIP logo

go2hx's Introduction

go2hx

Warning

experimental version, not able to compile most Go code correctly.

If you want to use working Golang libraries easily, try out the new: go2hxlibs

Compile Go to Haxe.

What is supported?

  • A few std libs (compatibility).
  • No support for Cgo and Go assembly
  • 95% of the normal language features

Installation

haxelib git go2hx https://github.com/go2hx/go2hx

Run compiler on a file:

haxelib run go2hx ./main.go

Run compiler on a library:

Caution

Almost all libs will not work yet, because of missing stdlib support.

haxelib run go2hx golang.org/x/example/stringutil

Commendation

A spiritual successor to Tardisgo written by Elliott Stoneham, A maintainer, mentor, and code contribuitor of this project. Elliott's wise counsel, solid engineering design, and effective programming is the core of this project and go2hx would not exist without him.

Tip

Commands in this documentation such as: haxe and haxelib may have npx as a prefix, that's because in those cases the command is using the local npm package lix to run Haxe, this is optional and if you would like to use non lix commands that's supported as well.

Setup from source

git clone https://github.com/go2hx/go2hx
npm i lix
npx lix download
cd go2hx
haxelib dev go2hx .

Now you can run the compiler, for example:

npx haxelib run go2hx ./main.go 

Note

Look at Run.hx to see how the building occurs.

Using the compiler development environment

After you have setup from source and ran the compiler at least once you should be able to use the dev tools, here is the list and how they work.

  • npx haxe rnd.hxml : rnd stands for research and development, it's a quirky name for a test bed that runs ./rnd/main.go use it for rapid testing of go snippets and comparison with go output.

  • npx haxe stdgo.hxml : (requires nodejs) go's standard library generator, all std pkgs compiled are added into ./stdgo/* for generating specific std go libs use the -D libs flag. For example to compile unicode/utf8 and strings run: npx haxe stdgo.hxml -D libs=unicode/utf8,strings

  • npx tests.hxml && hl tests.hl [suite] : (requires hashlink) A multi suite test runner with a built in regression tracker, used primarily by github actions to test for progression and regression of every commit to the project. [suite] can be any of the following added as an argument: unit, stdgo, yaegi, gobyexample, go . For example npx tests.hxml && hl tests.hl stdgo . Note && separates out 2 arguments for unix for windows you may need to use ||

  • npx haxe stdgo/[std].hxml --[target] : A series of hxml files created by running the stdgo test suite. Every stdlib listed in ./tests.json has an hxml file created at ./stdgo root folder. For example to run unicode/utf16 with the interp target : npx haxe stdgo/unicode_utf16.hxml --interp

go2hx's People

Contributors

elliott5 avatar jayvdb avatar pull[bot] avatar pxshadow avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go2hx's Issues

Language features revisted

There are some language features that I have overlooked and need to get correct in order to finish the language spec.

  • Equality == , past implementation used a macro based system to check equality, current idea for the rework is having Go.equals simple turn the 2 exprs into AnyInterfaces and have them use the operator overload equals, cleaning up where implementation occurs and indirectly having all Map key types be AnyInterfaces in order use the equality.

  • Reflect deep equals, past implementation did not adhere at all to the spec and was completely custom using Haxe's reflect and nothing from the actual Reflect package, current idea for new system is deepequal.go being compiled into Haxe code and tweaked to properly work with go2hx's internals.

  • address system, past implementation is rather scattered and not well designed, future implementation should cover all types with a function that acquires the uintptr address.

  • Fallthrough and goto have the least time invested out of any of the language features and need tests to cover them and get them working.

  • Edge cases for composite literals that are not supported such as field names + field indexes.

  • Go.set a macro based approach to not knowing the composite literal getting created in for instance a slice, is legacy and can be replaced by using Go type info in the future, no need at the moment but is a good idea to remove another implementation that needs separate maintenance.

  • Turning string into a slice of bytes is most likely not implemented correctly.

  • UInt64 is not supported for a number greater then Int64's abs range

Major rewrite of the typer from Go to Haxe

A rewrite of the typer from Go to Haxe.

What things it will solve.

  • Go's type inference being diffrent then Haxe (example: division for ints)
  • Infered interfaces
  • Hard setting all infrence so the inference is not diffrent then Haxe's
  • Easier to debug the process of typing and conversion
  • Keep the Go part completly stable and not needed to rebuild.
  • No longer need to use gorename witch is quite slow through a large project.
  • better debugging for Errors with Haxe's exception system.
  • closer coupling with the macro system.

Go Tests

Overview:

  • If a test runs beyond the timeout threshold (currently 10 seconds) a single line error is attempted to be shown, with the ending (timed out)

  • The tests are chosen from the go repo if they have the meta data at the top equaling: run or runoutput.

  • This current test suite is focused on the language specification and is good quality assurance for it, however it does not attempt to test the coverage of the go standard library. A seperate test suite will need to be created for that purpose in the future (will use the testing std package).

  • To run this yourself run haxe tests.hxml have hashlink setup, and run hl tests.hl it will give an output in terminal and during running it will append content into a file tests.txt that is the output for the Results section.

Results:

  • Alias1
  • Align
  • Append
  • Armimm
  • Atomicload
  • Bigalg - Int64Helper.hx:53: characters 5-10 : Uncaught exception NumberFormatError
  • Bigmap - GoArray.hx:36: characters 4-9 : Uncaught exception array out of bounds, index: 0 length: 0
  • Blank - Blank.hx:117: characters 9-11 : Type name should start with an uppercase letter
  • Bom
  • Char_lit
  • Clearfat - Clearfat.hx:69: characters 15-39 : Module stdgo.bytes.Bytes does not define type Buffer
  • Closure - Closure.hx:207: characters 31-67 : stdgo.runtime.MemStats does not have a constructor
  • Closure1
  • Closure2 - Closure2.hx:196: characters 19-21 : command_line_arguments.Y_main_4 has no field _v
  • Closure4
  • Complit - Complit.hx:226: characters 68-71 : stdgo.GoArray<stdgo.GoInt> has no field cap
  • Compos
  • Const - Const.hx:39: characters 22-28 : Float should be Int
  • Const3 - Const3.hx:57: characters 14-65 : stdgo.GoUInt64 should be stdgo.GoFloat64
  • Const4 - Const4.hx:20: characters 87-89 : String should be stdgo.GoArray<stdgo.GoInt>
  • Convert - Convert.hx:14: characters 41-49 : () -> stdgo.GoInt cannot be constructed
  • ConvT2X - ConvT2X.hx:113: characters 9-40 : Unknown<0> should be stdgo.GoString -> Unknown<0>
  • Copy - Copy.hx:248: characters 21-24 : Unknown identifier : my8
  • Crlf
  • Ddd - Ddd.hx:124: characters 37-41 : haxe.Rest<stdgo.GoInt> should be stdgo.Slice<stdgo.GoInt>
  • Decl
  • Defer - Defer.hx:99: characters 9-14 : Uncaught exception defer
  • Deferfin
  • Defernil
  • Deferprint - Deferprint.hx:28: characters 45-47 : String should be stdgo.GoInt
  • Divide - Divide.hx:23: characters 13-18 : Uncaught exception divide
  • Divmod - Go.hx:622: characters 16-33 : Unknown identifier : recover_exception
  • Env
  • Escape - Escape.hx:445: characters 17-18 : Unknown identifier : _
  • Escape3
  • Finprofiled - Go.hx:55: characters 20-28 : stdgo.runtime.MemProfileRecord does not have a constructor
  • Floatcmp
  • Float_lit (timed out)
  • Float_lit2 - Float_lit2.hx:157: characters 8-34 : Float should be stdgo.IntegerType
  • For_
  • Func - Func.hx:30: characters 38-49 : stdgo.GoFloat32 should be stdgo.GoInt
  • Func5 - Func5.hx:101: characters 9-14 : Uncaught exception fail
  • Func6
  • Func7
  • Func8
  • Gc
  • Gc1
  • Gcstring - Gcstring.hx:81: characters 59-79 : Not enough arguments, expected obj:stdgo.PointerData<stdgo.GoInt>
  • Heapsampling - Heapsampling.hx:327: characters 81-85 : Object requires fields: value, key
  • Helloworld
  • If_
  • Indirect - Indirect.hx:13: characters 70-72 : String should be stdgo.GoInt
  • Init1 - Init1.hx:60: characters 31-67 : stdgo.runtime.MemStats does not have a constructor
  • Initcomma - Initcomma.hx:98: characters 9-14 : Uncaught exception fail
  • Initempty - Initempty.hx:63: characters 18-23 : Duplicate module field declaration : command_line_arguments.Initempty._init
  • Inline_literal - Inline_literal.hx:44: characters 12-33 : Module stdgo.reflect.Reflect does not define type Reflect
  • Intcvt (timed out)
  • Int_lit
  • Iota - Iota.hx:121: characters 20-73 : stdgo.IntegerType should be stdgo.GoString
  • Literal - Literal.hx:374: character 25 : Invalid escape sequence \3. Values greater than \177 are not allowed. Use \u00ff instead.
  • Literal2 - Literal2.hx:102: characters 43-47 : Expected , or )
  • Makeslice - Makeslice.hx:143: characters 44-55 : stdgo.GoUInt64 should be stdgo.GoInt
  • Map_ (timed out)
  • Mapclear
  • Method3 - Method3.hx:46: characters 15-22 : command_line_arguments.I does not have a constructor
  • Nilptr - Nilptr.hx:124: characters 11-30 : Module stdgo.unsafe.Unsafe does not define type Unsafe
  • Peano (timed out)
  • Print
  • Printbig
  • Range - Range.hx:117: characters 9-10 : Unknown identifier : _
  • Recover1 - Go.hx:622: characters 16-33 : Unknown identifier : recover_exception
  • Reflectmethod1 - Uncaught exception Cannot call null
  • Reflectmethod2 - Reflectmethod2.hx:2: characters 8-29 : Module stdgo.reflect.Reflect does not define type Reflect
  • Reflectmethod3 - Reflectmethod3.hx:24: characters 40-68 : Module stdgo.reflect.Reflect does not define type Method
  • Reflectmethod4 - Reflectmethod4.hx:32: characters 7-28 : Module stdgo.reflect.Reflect does not define type Reflect
  • Reflectmethod5 - Reflectmethod5.hx:34: characters 17-38 : Module stdgo.reflect.Reflect does not define type Reflect
  • Reflectmethod6 - Reflectmethod6.hx:34: characters 17-38 : Module stdgo.reflect.Reflect does not define type Reflect
  • Rename - Rename.hx:50: characters 15-20 : Unexpected false
  • Reorder - Go.hx:606: characters 11-23 : stdgo.IntegerType has no field is_pointer
  • Reorder2 - Reorder2.hx:67: characters 9-17 : command_line_arguments.T1 should be command_line_arguments.I
  • Simassign - Simassign.hx:171: characters 28-38 : { v : stdgo.GoInt, u : stdgo.GoInt } should be stdgo.GoInt
  • Sizeof - Sizeof.hx:306: characters 52-53 : command_line_arguments.T2 has no field c
  • Slice3 - Slice3.hx:2: characters 8-19 : Type not found : bufio.Bufio
  • Slicecap - Go.hx:606: characters 11-23 : stdgo.GoUIntptr has no field is_pointer
  • Stack
  • Stackobj2 - Stackobj2.hx:162: characters 36-46 : { _n : stdgo.GoInt64 } should be Null<stdgo.GoInt64>
  • Stackobj3 - Stackobj3.hx:131: characters 9-14 : Uncaught exception bad liveness
  • Strcopy - Strcopy.hx:26: characters 247-281 : Module stdgo.reflect.Reflect does not define type StringHeader
  • Strength - Strength.hx:57: characters 39-42 : Expected ) or , or :
  • Stringrange - Stringrange.hx:67: character 28 : Invalid escape sequence \x. Values greater than \x7f are not allowed. Use \u00ca instead.
  • String_lit - String_lit.hx:20: character 27 : Invalid escape sequence \x. Values greater than \x7f are not allowed. Use \u00FF instead.
  • Struct0 - Go.hx:622: characters 16-33 : Unknown identifier : recover_exception
  • Switch_ - Switch_.hx:711: character 9 : Invalid character '#'
  • Tinyfin
  • Turing
  • Typeswitch - Typeswitch.hx:204: characters 38-39 : Unknown identifier : x
  • Typeswitch1 - Typeswitch1.hx:63: characters 67-69 : Unknown identifier : xx
  • Uintptrescapes3 - Uintptrescapes3.hx:48: characters 31-58 : Module stdgo.unsafe.Unsafe does not define type Pointer
  • Utf - Utf.hx:2: characters 8-31 : Type not found : stdgo.unicode.utf8.Utf8
  • Varinit
  • Winbatch - Winbatch.hx:85: characters 5-67 : Unexpected null

PASSING: 33/101

Transpile Fmt stdlib into Haxe sucessfully and passing the tests

The fmt formatter for Go is pretty sophiscated, currently go2hx was using a modified Haxe library that simulated the formatter for c, however Go has alot of extra features and requirements on top of C's fmt, I think it would be a good idea to eventually get Fmt to transpile properly into Haxe code for use in stdgo

Lix install errors

Lix install errors after commit PXshadow@4ad9ecd

$ lix install https://github.com/pxshadow/go2hx --global
downloading gh://github.com/pxshadow/go2hx#4ad9ecd422f619d6eb98e677fcb235d715a977b2
-> Done!
-> mounted as go2hx#0.0.1
Running post download hook:
> lix download && go build && haxe build.hxml
stdgo/Io.hx:3: characters 8-20 : Type not found : stdgo.Errors
stdgo/internal/ErrorReturn.hx:2: characters 8-20 : Type not found : stdgo.Errors
stdgo/internal/ErrorReturn.hx:5: characters 43-48 : Type not found : Error
stdgo/Fmt.hx:10: characters 8-20 : Type not found : stdgo.Errors
stdgo/Io.hx:9: characters 53-58 : Type not found : Error
stdgo/Fmt.hx:15: characters 9-21 : Type not found : stdgo.Errors
stdgo/Fmt.hx:31: characters 4-9 : stdgo.Writer has no field write
stdgo/Fmt.hx:34: characters 4-9 : stdgo.Writer has no field write
stdgo/Io.hx:3: characters 8-20 : Type not found : stdgo.Errors
stdgo/internal/ErrorReturn.hx:2: characters 8-20 : Type not found : stdgo.Errors
stdgo/internal/ErrorReturn.hx:5: characters 43-48 : Type not found : Error
stdgo/Fmt.hx:10: characters 8-20 : Type not found : stdgo.Errors
stdgo/Io.hx:9: characters 53-58 : Type not found : Error
stdgo/Fmt.hx:15: characters 9-21 : Type not found : stdgo.Errors
stdgo/Fmt.hx:31: characters 4-9 : stdgo.Writer has no field write
stdgo/Fmt.hx:34: characters 4-9 : stdgo.Writer has no field write
Failed to invoke `lix download && go build && haxe build.hxml` because Error: Command failed: lix download && go build && haxe build.hxml

BTree library working

Repo: https://github.com/tidwall/btree
Issue refrence: #1

  • double pointers.
  • goto statements and labels properly functioning.
  • no field name conflicts. (last conflict, being lower casing function names, how to set the displaced name without knowing the type, Could use a macro to sort out a potential function name conflicts)
  • private access allowed within a file module.
  • Go division.
  • pass through mutex.
  • defer stack system.
  • constants as Haxe finals
  • reciever proper initialization and usage with this, and copy system if not pointer.

tooling executable

Make Go's tooling much easier to use across all targets.

  • export.bson included where the tool is ran and removed once used.
  • bundle go's executable within haxe and add to where the command is called, delete after generation/testing is complete.
  • produce the build tools in github action and add to releases, each minor version update.
  • let the tool be used by haxelib git, lix, and npm
  • npm install && npm buil should be able to produce an executable tool with the only prerequisites (git,npm/node)

Runtime error after array has incorrect length of 0

Error Output

44
stdgo/GoArray.hx:46: [] index: 0 length: 0
Main.hx:77: characters 19-23 : Uncaught exception array out of length bounds

go2hx

package command_line_arguments;
import stdgo.Fmt;
import stdgo.StdTypes;
import stdgo.Go;
import stdgo.Builtin;
import stdgo.Pointer.PointerWrapper;
import stdgo.Slice;
import stdgo.GoArray;
import stdgo.GoArray.GoArrayPointer;
import stdgo.Pointer;
/**
    foo struct{ bar int }
**/
@:access(Foo) @:structInit @:allow(command_line_arguments) final class Foo {
    public var _bar : Int = 0;
    public function new(?_bar) stdgo.internal.Macro.initLocals();
    public function toString() {
        return '{${Std.string(_bar)}}';
    }
    public function __copy__() {
        return new Foo(_bar);
    }
}
/**
    func doubleInc(p *int) { *p += 2 }
**/
private function doubleInc(p:Pointer<Int>):Void {
    p._value_ += 2;
}
/**
    func barInc2(p *foo) { (*p).bar += 2 }
**/
private function barInc2(p:PointerWrapper<Foo>):Void {
    (p._value_)._bar += 2;
}
/**
    func barInc2star(p **foo) { (**p).bar += 2 }
**/
private function barInc2star(p:Pointer<PointerWrapper<Foo>>):Void {
    (p._value_._value_)._bar += 2;
}
/**
    func main() {
    	i := 42
    	doubleInc(&i)
    	fmt.Println(i)
    
    	a := []int{0, 1, 2, 3, 4, 5}
    	var p [6]*int
    	for j := range p {
    		p[j] = &a[j]
    	}
    	for i := range a {
    		doubleInc(p[i])
    	}
    	fmt.Println(a)
    
    	o := foo{42}
    	po := &o
    	barInc2(po)
    	fmt.Println(po, o) // should be 44
    	ppo := &po
    	barInc2star(ppo)
    	fmt.Println(ppo, po, o) // should be 46
    }
**/
private function main():Void {
    var i:Int = 42;
    doubleInc(Go.pointer(i));
    stdgo.Fmt.println(i);
    var a = new Slice<Int>(0, 1, 2, 3, 4, 5);
    var p:GoArray<Pointer<Int>> = make(((_ : GoArray<Pointer<Int>>)), [0]);
    for (j in 0 ... p.length) {
        p[j] = Go.pointer(a[j]);
    };
    for (i in 0 ... a.length) {
        doubleInc(p[i]);
    };
    stdgo.Fmt.println(a);
    var o = new Foo(42);
    var po = Go.pointer(o);
    barInc2(po);
    stdgo.Fmt.println(po, o);
    var ppo = Go.pointer(po);
    barInc2star(ppo);
    stdgo.Fmt.println(ppo, po, o);
}

In good news, if I change the array make line length from [0] to [6] the code executes correctly!

Exported code as a library

Currently the exported code is an isolated project with its own build hxml and pulling of haxe libraries.

  • make go2hx a haxelib and lix library with other library dependencies.
  • Only add a build.hxml and .haxerc if the exported code is a main file.
  • change bin name to the projects name somehow, either by the file name/ go module etc
  • don't add the std in the export folder, use go2hx's standard library of go.
  • remove import.hx and have the list of imports included in the generated code if they are acessed.

Pointer comparison is wrong

package main

import "fmt"

func main() {
	a1 := "the same value"
	p1 := &a1
	a2 := "the same value"
	p2 := &a2
	fmt.Println(p1 == p2) // false in Go, true in go2hx
}

Preface generated class and interface declarations with @:rtti

I'm planning to fork this repo and write the prototype reflect module in the correct location.

It would be really helpful to my testing @PXshadow if you could preface generated class and interface code with @:rtti.

There will be more code generation tweaks required, if the prototype approach works.

type expr unknown: *ast.BinaryExpr

try to test some base lib at go

go version go1.13.8 linux/amd64

./go2hx github.com/buger/jsonparser

type expr unknown: *ast.BinaryExpr type expr unknown: *ast.BinaryExpr type expr unknown: *ast.BinaryExpr type expr unknown: *ast.CallExpr type expr unknown: *ast.CallExpr src/Parser.hx:28: pkgs amount: 1 Failed to format github_com/buger/Jsonparser.hx: failed to create parser context: failed to make tokens { msg : UnknownEscapeSequence(\b), pos : { file : code snippet, min : 559, max : 560 } }

test suite

  • github actions, use node github action and run npm install and npm build.
  • use executable to run a tailored test suite from go2hxTest's repo
  • improve go2hx's error logging system, use log instead most likely.
  • If go2hx has a problem generating/building/running it will produce a error.txt and the sys output will be to please report an issue here like the prompt haxe has. in the file there will be OS, Haxe version, Go version. Go2hx version etc.

Seperate info into global and local data

Currently a type info is passed around pretty much to every function in typer, however its both global and local data of the scope so it has lead to data types that are much to large with alot of if checks to find the correct local data from the layer at. So instead local could be passed around and down the scope get more and more added witch would also allow the compiler to be multithreaded per function, also speeding up compile times, and creating trimming down on complexity at the same time.

--help complains about cwd and export.json

I've just run lix install https://github.com/go2hx/go2hx --global to install c6831cb

Then running lix run go2hx --help in my py2many root directory complains about issues that are likely not relevant to running --help:

go get: /Users/john.vandenberg/python/py2many is not within module rooted at /Users/john.vandenberg/haxe/haxe_libraries/go2hx/0.0.1/github/c6831cbb3f472519df9224734df76f728ee81c22
> parser:
Usage of ./go4hx:
  -ident
    	ident json
  -test
    	testing the go library in haxe
src/Main.hx:87: error: export.json not found

GopherJS handling of goto

I see from the part-generated code for goto in go2hx that you are thinking of using functions, that was my first thought too.

As a cross-check, I thought it would be helpful to see how GopherJS did it...

I took the example of a Go goto program from https://www.tutorialspoint.com/go/go_goto_statement.htm

Set up GopherJS on a virtual machine (it now requires an old version of Go), and inspected what was generated.

GopherJS uses a case statement to implement goto (but also for) ... so the Go code:

func main() {
	var a int = 10
LOOP:
	for a < 20 {
		if a == 15 {
			a = a + 1
			goto LOOP
		}
		println("value of a:",a)
		a++
	}
}

...generates this JS:

	main = function() {
		var a, $s;
		/* */ $s = 0; s: while (true) { switch ($s) { case 0:
		a = 10;
		/* LOOP: */ case 1:
		/* while (true) { */ case 2:
			/* if (!(a < 20)) { break; } */ if(!(a < 20)) { $s = 3; continue; }
			/* */ if (a === 15) { $s = 4; continue; }
			/* */ $s = 5; continue;
			/* if (a === 15) { */ case 4:
				a = a + 1 >> 0;
				/* goto LOOP */ $s = 1; continue;
			/* } */ case 5:
			console.log("value of a:", a);
			a = a + (1) >> 0;
		/* } */ $s = 2; continue; case 3:
		$s = -1; return;
		/* */ } return; }
	};

I hope that helps your thinking @PXshadow , let me know if you want to see other GopherJS examples.

Slice negative indexes

Go does bounds checking on arrays and slices.

Some (all?) of the Haxe implementations do bounds checks on haxe.ds.Vector which is used for Go arrays.

For slices though, which may start after the 0th element of the underlying array, a check for a negative index is also required in SliceData boundsCheck().

Pointers into a slice need to point to the underlying array

Changing the slice location changes previous pointers made into that slice.

package main

import "fmt"

func main() {
	sl := make([]int, 5)
	for i := 0; i < 5; i++ {
		sl[i] = i
	}

	sl2 := sl[1:3]

	ptr := &sl2[0]
	fmt.Println("*ptr should be 1=", *ptr, " sl2=", sl2) // correct 

	sl2 = sl[3:5]
	fmt.Println("*ptr should still be 1=", *ptr, " sl2=", sl2) // actually prints 3
}

Expected output

$ go run main.go
*ptr should be 1= 1  sl2= [1 2]
*ptr should still be 1= 1  sl2= [3 4]

Actual output

$ ./main.sh
> parser:
ident: false test: false
> typer: 2
> generator: 1
generating 1 file...
*ptr should be 1= 1  sl2= [1,2]
*ptr should still be 1= 3  sl2= [3,4]

Problem with Go->Haxe->C++

I want to use this tool to convert Go to Haxe firstly, and then use haxe --main Main --cpp ./ to convert Haxe to C++. But I got some problems.
A simple Go program:

    package main
    func main() {
        var a int=1
        var b int=2
        var c int=3
        c=a+b+c
    }

Firstly use go2hx to convert it to a Haxe program:

    package main;
    import stdgo.StdGoTypes;
    import stdgo.Go;
    /**
        func main() {
            var a int=1
            var b int=2
            var c int=3
            c=a+b+c
        }
    **/
    private function main():Void {
        var a:GoInt = (1 : IntegerType);
        var b:GoInt = (2 : IntegerType);
        var c:GoInt = (3 : IntegerType);
        c = a + b + c;
    }

But when I want to use haxe --main Main --cpp ./ to convert it ti a C++ program, I got stuck. Because --main need to specify class Main, but the Haxe program don't have this feature. Could I get some help?

Public Go API names in hx2go need to be standard, so that existing Go documentation can be used

Altering Go naming really should be a last resort, both because:

  • the Go API documentation is superb and hx2go programmers should be able to use it directly; and because
  • the Go code already has unique names, so changing those names stands the chance of names clashing (as in #28).

For example, look at a .Next() method in the Go documentation for accessing .tar files:
https://golang.org/pkg/archive/tar/#Reader.Next

Now notice that in the implementation of the .Next() public API, uses a private API called .next().
https://golang.org/src/archive/tar/reader.go?s=1315:1356#L37

This is a very common Go design pattern, behind the public API .Abc() is a private API .abc().

_is_pointer_ meaning for reflect

Consider this Go code:

	vert := Vertex{37.42202, -122.08408}
	var vertP *Vertex
	fmt.Println("---------> after init: vert=", vert, "vertP=", vertP)
	showInternals(vert, vertP)
	// output:
	// ---------> after init: vert= {37.42202 -122.08408} vertP= null
	// stdgo/reflect/Reflect.hx:1241: vert._address_=,25,vertP._address_=,null
	// stdgo/reflect/Reflect.hx:1242: vert._is_pointer_,false,vertP._is_pointer_,null

	vertP = &vert
	fmt.Println("---------> after vertp=&vert: vert=", vert, "vertP=", vertP)
	showInternals(vert, vertP)
	// output:
	// ---------> after vertp=&vert: vert= {37.42202 -122.08408} vertP= {37.42202 -122.08408}
	// stdgo/reflect/Reflect.hx:1241: vert._address_=,25,vertP._address_=,25
	// stdgo/reflect/Reflect.hx:1242: vert._is_pointer_,true,vertP._is_pointer_,true

	vertP = nil
	fmt.Println("---------> after vertP=nil: vert=", vert, "vertP=", vertP)
	showInternals(vert, vertP)
	// output:
	// ---------> after vertP=nil: vert= {37.42202 -122.08408} vertP= null
	// stdgo/reflect/Reflect.hx:1241: vert._address_=,25,vertP._address_=,null
	// stdgo/reflect/Reflect.hx:1242: vert._is_pointer_,true,vertP._is_pointer_,null
  1. After the initialisation phase, vert._is_pointer_==false and vertP==nil. LGTM.

  2. After vertP=&vert, both vert and vertP seem to be the same object (same _address_), with _is_pointer_==true. How can reflect know which is the pointer and which the target of that pointer?

  3. After vertP=nil, vert._is_pointer_==true which suggests vert is still a pointer, which clearly it is not.

Am I missing something about how _is_pointer_ works?

Go TypeSwitch

Currently can not use Abstracts as values for the "is" operator, blocked by needed compiler changes. HaxeFoundation/haxe#2976

 x = Go.assert(((1 : Byte)));
if ((x is UInt8)) { } else {
    panic("byte != uint8");
};
x = Go.assert(((2 : UInt8)));
if ((x is Byte)) { } else {
    panic("uint8 != byte");
};
var rune32 = false;
x = Go.assert(((3 : Rune)));
if ((x is Int)) { } else if ((x is Int32)) {
    rune32 = true;
} else {
    panic("rune != int and rune != int32");
};

iota and methods on non-struct named types - example reflect.Kind

package main

import "fmt"

const (
	Invalid Kind = iota
	Bool
	Int
	Int8
	Int16
	Int32
	Int64
	Uint
	Uint8
	Uint16
	Uint32
	Uint64
	Uintptr
	Float32
	Float64
	Complex64
	Complex128
	String
	UnsafePointer
	Chan
	Interface
	Ptr
	Slice
	Array
	Func
	Map
	Struct
)

type Kind int

func (k Kind) String() string {
	switch k {
	case Bool:
		return "bool"
	case Int:
		return "int"
	case Int8:
		return "int8"
	case Int16:
		return "int16"
	case Int32:
		return "int32"
	case Int64:
		return "int64"
	case Uint:
		return "uint"
	case Uint8:
		return "uint8"
	case Uint16:
		return "uint16"
	case Uint32:
		return "uint32"
	case Uint64:
		return "uint64"
	case Uintptr:
		return "uintptr"
	case Float32:
		return "float32"
	case Float64:
		return "float64"
	case Complex64:
		return "complex64"
	case Complex128:
		return "complex128"
	case String:
		return "string"
	case UnsafePointer:
		return "unsafe.Pointer"
	case Chan:
		return "chan"
	case Interface:
		return "interface"
	case Ptr:
		return "ptr"
	case Slice:
		return "slice"
	case Array:
		return "array"
	case Func:
		return "func"
	case Map:
		return "map"
	case Struct:
		return "struct"
	default:
		return "invalid"
	}
}

func main() {
	fmt.Println("Kind test harness")
	for i := 0; i < 30; i++ {
		k := Kind(i)
		fmt.Println(i, k.String())
	}
}

Does not compile on go2hx.
Both because iota is not implemented; and
because Go methods on non-struct named types are not implemented properly (no link between code and type).

Access to native Haxe from go2hx Go

In GopherJS they have a specific js pseudo-Go module, see https://pkg.go.dev/github.com/gopherjs/gopherjs/js

TardisGo also had a similar hx pseudo-Go module, see https://github.com/tardisgo/tardisgo/blob/e0dd9a7e46b597cdc4d310c8a677c2da7444008e/haxe/hx/hx.go

So go2hx needs a similar pseudo-Go module. This will allow much of the reflect (and maybe other low-level) modules to be written in Go, and therefore able to reuse existing Go code from elsewhere.

Originally posted by @elliott5 in https://github.com/PXshadow/go2hx/issues/8#issuecomment-796662137

KeyValueExpr and BasicLiterals can be intermixed in a CompositeLit

Currently KeyValueExprs are supported using the @:structInit system and BasicLiterals are supported by using the new constructor and adding into it by order, however there is no system in place to be able to intermix the two (as I had no idea it was possible) and as such a new system needs to be built to allow intermixing. Best option seems to be a macro, since this case is rare almost all composite literals should have very nice syntax for constructing.

Go divide by zero behaviour

In Go, all integers panic when divided by zero. This is a different behaviour from Haxe.

For floats & complexes, NaN should be returned. This means the code for complex number division in TardisGo was wrong (and so is wrong now in go2hx).

Go has a specific test for divide-by-zero behaviour at https://golang.org/test/zerodivide.go

Known reflect prototype issues

As regards my first pull request #41:

Only the Type side of reflect has been started, no work yet on the Value side.

The Type system only works fully for simple types with a textual name in the interface and for named types based on a struct, where a Haxe class is created which has had @:rtti metadata created.

Named types not based on a struct that generate code using the @:using(haxe.path.To._MyType__extension) are still to be worked up.

Anonymous structs work, but with native concrete Haxe types rather than Go type information based on abstract Haxe types.

Other types (array, slice ...) have not been looked at so far.

Representation of Go pointers in go2hx

All Haxe objects are of course pointers to the start of the contents of the object.

But how to represent pointers to elements within an object, or elements within elements?

I think a Go pointer type rendered in Haxe might contain two values:

  1. (a pointer to) the base object
  2. an array of indexes(into arrays) or field-names(for structures)

So a pointer to Go element dingbat[4].foo.bar[26] would be{dingbat,[4,"foo","bar",26]} in Haxe (inside a Class of course).

I fear Haxe reflection may be required to achieve this.

I see @PXshadow may be ahead of me on this, due to his work on https://github.com/andyli/ptr.

abstract GoUInt64 does not contain operation overloads for "==" and "!="

I looked into why armimm 64 ints are not working and concluded the problem was with this code:
https://github.com/PXshadow/go2hx/blob/18de82f8b38a879ac7f8c0daed993a04aa5c7fd0/stdgo/StdGoTypes.hx#L1669

Because there are not @:op(a == b) and @:op(a != b) in the abstract, on the hl and neko platforms the generated code is comparing two haxe.Int64 classes together rather than calling haxe.Int64.eq()/neq().

I suspect code like that below is required for == and !=:

	@:op(A != B) private static function neq(a:GoUInt64, b:GoUInt64):Bool
		return a.toBasic() != b.toBasic();

Simple pointer example not working

Go2hx generated code:

package command_line_arguments;
import stdgo.Fmt;
import stdgo.StdTypes;
import stdgo.Go;
import stdgo.Builtin;
import stdgo.Pointer.PointerWrapper;
/**
    func doubleInc(p *int) { *p += 2 }
**/
private function doubleInc(p:PointerWrapper<Int>):Void {
    p.value += 2;
}
/**
    func main() {
    	foo := 42
    	doubleInc(&foo)
    	fmt.Println(foo) // should be 44
    }
**/
private function main():Void {
    var foo:Int = 42;
    doubleInc(Go.pointer(foo));
    stdgo.Fmt.println(foo);
}

Gives Haxe compiler errors:

Invalid commandline class : Main should be command_line_arguments.Main
Main.hx:11: characters 7-12 : stdgo.PointerWrapper<Int> has no field value
/Users/elliott/haxe/haxe_libraries/go2hx/0.0.1/github/e1c308ca60544ea05204d467ab58d6f383df9ea7/stdgo/Go.hx:260: characters 20-26 : Type not found : Pointer

Refractor ExprDef system

Alot of the code currently uses ExprDef enum defines, it is not needed as ComplexTypes can be macro unified with the really nice macro keyword, so go through the codebase and remove all unneeded exprdefs, except complicated things like switch and function.

NaN integer conversion

func main() {
	var nan float32 = 0
	nan /= 0
	println(nan, int32(nan), int64(nan))
}

return: NaN -2147483648 -9223372036854775808

Not sure how to produce this without hard setting the conversions. Or should it even be reproduced? Currently one of Tinygo's tests relys on this.

Error type assertion gives 2 options as optional

I'm not quite sure how this works it seems to be equivlant to value,ok := map[get] where there is the value and then an optional, bool.

Here is the code example:

type argError struct {
    arg  int
    prob string
}
func f2(arg int) (int, error) {
	if arg == 42 {

		// In this case we use `&argError` syntax to build
		// a new struct, supplying values for the two
		// fields `arg` and `prob`.
		return -1, &argError{arg, "can't work with it"}
	}
	return arg + 3, nil
}


func (e *argError) Error() string {    
 return fmt.Sprintf("%d - %s", e.arg, e.prob)
}


func main() {
    _, e := f2(42)
    if ae, ok := e.(*argError); ok {
        fmt.Println(ae.arg)
        fmt.Println(ae.prob)
    }
}

Need to figure out some method to handle this as there is only the option for one variable or multiple variables but they all must be captured with a destruct.

Unsafe Pointer

pointer <-> unsafe pointer
uintptr <-> unsafe pointer

uintptr conversion not sure if it is possible in Haxe as it requires the element to have no reference for the garbage collector. Currently left with 2 ideas.

  1. Static analysis should be able to work with simple conversions from uintptr to unsafe Pointer, however the more complicated the harder the problem, such as field offsets, wild pointer arithmetic etc.

  2. Serializing, if during serialization to serialization the value changes the address would no longer be correct however, now that I write this it would be possible to have a Pointer update the global map of its address if it exists and reserialize it, could potentially be very slow but it would work! I'll work on that method for now.

The unsafe Pointer work is to get the TinyGo test reflection passing, it is currently running, some basic unsafe pointer logic is needed however in order to complete it.

Stdgo types need to be known by the compiler when typing.

Go code is currently processed in a certain typing order import/types first, variables next and finally functions. This allows the compiler to know for instanceType(10) being a type assertion rather then a function call. The issue comes from stdgo which is written in Haxe and passes no information to the compiler at present.

Example :

x := time.Duration(10)

The compiler doesn't know that Duration is a typedef of GoInt64, and keeps in a non existent function call. So there needs to be a system that passes in this case a list of interfaces of a package. Question is how should this data be stored, and should it be generated by macros, manually or something else?

pointer, indexing from another pointer, not working correctly

package main

import "fmt"

var a = []string{"", "the same value", "the same value"}

func main() {
	p1 := &a[1]
	p3 := &a[2]
	fmt.Println(p1 == P2(&a), P2(&a) == p3) // Go=false,true go2hx=false,false
}

func P2(b *[]string) *string {
	return &(*b)[2]
}

Get the reflect tests working first, using Go's own reflect code

@PXshadow wrote in an e-mail to @elliott5:
"...from what I understand now, I think it would be better to get the reflect tests working first and instead of handwriting the go's std reflect or go2hx needing it's own modified go repo, go2hx can transpile the package and then inject in the functions that use //:go:noescape for instance in tardisgo's modified go, you do this here. This idea may also be applicable to speed up, finishing the go standard library as before my thought was that if any package used syscall or internal it would need to be hand written in Haxe however this could make it only necessary to write the functions in the package that use syscall or internal."

This seems a good idea, but in addition to rewriting the syscall and internal functions, would also require hx2go to create all of the data-structures around Go type information (routinely created by the Go compiler) that the reflect code expects. "These data structures are known to the compiler..."

Further investigation is required, looking both at how GopherJS and TinyGo handle this issue, and also at how TardisGo did.

New stdgo hybrid system

The system currently relies on two datasets. excludes.json and stdgo.json

Whether a module exists or does not exist in either of these lists creates 4 possibilities that map to an intended behavior of the generation.

  • Excludes prevents a go package from being parsed and exported as data to then be compiled.
  • Stdgo list sets whether or not a root package (example: time, os, math) will have it's exported reference as stdgo.Time.Duration instead of just time.Duration
  1. No stdgo Go code or Haxe.
    example: flag (should require no modifications or changes from stdgo, and as such will be handled as normal compiled Go code to Haxe)
    excluded = false, stdgo = false
  2. Haxe code only
    example: os, runtime, unsafe (requires modification but only on the Haxe side and is not worth generating the Go side as it's close to a rewrite)
    excluded = true, stdgo = true
  3. Go and Haxe code
    example: time, errors (requires modification of some functionality of the module in Haxe replacing some Go functions, but alot of the module does not need to be rewritten. For module level fields that name conflict with std's Go name field, stdgo's Go field will replace them, following the same system as gopherjs's compiler native uses)
    excluded = false, stdgo = true

note : exclude = true, and stdgo = false, can not work because excluded generated Go's std module code and then also not having a reference for the Haxe code means the module path would throw as the path would point no where.

With this system in place, it would allow different generation cases to match with the standard libraries module characteristics.

Switch to Classes for typesystem

- [ ] multiple extension macro (not actually a feature of Golang)

  • new constructor
  • typer implement infered interfaces
  • toString() for printing
  • add functions into type
  • copy function

lix: no @run directive found for library go2hx

When I follow the instructions in the readme on macos, I get this error

lix install https://github.com/go2hx/go2hx --global
already downloaded: gh://github.com/go2hx/go2hx#ef2a555ad8e908c003cd27fd57b14da7852dc183
-> mounted as go2hx#0.0.1
> lix run go2hx github.com/tidwall/btree
no @run directive found for library go2hx

Same occurs if I specify local file ./print.go

lix use haxe nightly is successful.

I am very new to haxe and lix, so that is probably part of the problem.

Versions:

  • lix - v15.10.1
  • haxe - 4.2.0-rc.1+b37e43d

Also, I think it would be helpful if there was a section in the readme how to build from a git clone, which describes the various components (e.g. is run.n the workhorse behind go2hx?, what is go4hx? https://golangexample.com/the-go-to-haxe-transpiler/ explains them a bit) and how to run the tests and examples, for people without haxe/neko/etc experience.

I am assuming I have built the bits correctly, but without steps to follow, and CI verifying those steps work, I cant be confident.

Anyways, this is the errors I am getting atm with a local build.

hl tests.hl
> parser:
ident: false test: false
/path/to/go2hx/tests/go/test/alias1.go:12:6: main redeclared in this block
unknown parse type id: Chan
... (repeats many times) ...
unknown parse type id: Chan
> typer: 3
src/Typer.hx:2091: {}
Uncaught exception: type id is null: {}
Called from _Typer.$Typer_Fields_.parseType(Typer.hx:2092)
Called from _Typer.$Typer_Fields_.typeof(Typer.hx:1934)
Called from _Typer.$Typer_Fields_.typeAssignStmt(Typer.hx:1264)
Called from _Typer.$Typer_Fields_.typeStmt(Typer.hx:676)
Called from _Typer.$Typer_Fields_.typeStmtList(Typer.hx:755)
Called from _Typer.$Typer_Fields_.typeBlockStmt(Typer.hx:741)
Called from _Typer.$Typer_Fields_.typeFunction(Typer.hx:2627)
Called from _Typer.$Typer_Fields_.main(Typer.hx:262)
Called from _Main.$Main_Fields_.init(Main.hx:59)
Called from _Run.$Run_Fields_.compile(Run.hx:66)
Called from _Run.$Run_Fields_.gen(Run.hx:60)
Called from _Run.$Run_Fields_.main(Run.hx:16)
Called from fun$1194(?:1)
hl examples.hl
> parser:
ident: true test: false
> typer: 1
> generator: 0
examples/Examples.hx:34: run libraries
> parser:
ident: true test: false
> typer: 2
src/Typer.hx:2091: {}
Uncaught exception: type id is null: {}
Called from _Typer.$Typer_Fields_.parseType(Typer.hx:2092)
Called from _Typer.$Typer_Fields_.parseType(Typer.hx:2079)
Called from _Typer.$Typer_Fields_.parseType(Typer.hx:2087)
Called from _Typer.$Typer_Fields_.parseType(Typer.hx:2085)
Called from _Typer.$Typer_Fields_.typeCompositeLit(Typer.hx:2338)
Called from _Typer.$Typer_Fields_.typeExpr(Typer.hx:1591)
Called from _Typer.$Typer_Fields_.typeUnaryExpr(Typer.hx:2171)
Called from _Typer.$Typer_Fields_.typeExpr(Typer.hx:1587)
Called from _Typer.$Typer_Fields_.typeAssignStmt(Typer.hx:1251)
Called from _Typer.$Typer_Fields_.typeStmt(Typer.hx:676)
Called from _Typer.$Typer_Fields_.typeStmtList(Typer.hx:755)
Called from _Typer.$Typer_Fields_.typeBlockStmt(Typer.hx:741)
Called from _Typer.$Typer_Fields_.typeFunction(Typer.hx:2627)
Called from _Typer.$Typer_Fields_.main(Typer.hx:262)
Called from _Main.$Main_Fields_.init(Main.hx:59)
Called from _Examples.$Examples_Fields_.gen(Examples.hx:36)
Called from _Examples.$Examples_Fields_.main(Examples.hx:10)
Called from fun$1146(?:1)

After running haxe build.hxml, and a bit of guess work, it looks like I can get go2hx running without lix

neko ./run.n /path/to/print.go
> parser:
ident: false test: false
> typer: 2
src/Typer.hx:2091: {}
Called from ? line 1
Called from Main.hx line 17
Called from Main.hx line 59
Called from Typer.hx line 262
Called from Typer.hx line 2627
Called from Typer.hx line 741
Called from Typer.hx line 755
Called from Typer.hx line 675
Called from Typer.hx line 1284
Called from Typer.hx line 1585
Called from Typer.hx line 1850
Called from Typer.hx line 2061
Called from Typer.hx line 2092
Uncaught exception - type id is null: {}

fwiw, print.go is https://github.com/adsharma/py2many/blob/main/tests/expected/print.go

Comments in Go source mess up Go source comment in Haxe

Example from https://www.tutorialspoint.com/go/go_continue_statement.htm

package main

import "fmt"

func main() {
	/* local variable definition */
	var a int = 10

	/* do loop execution */
	for a < 20 {
		if a == 15 {
			/* skip the iteration */
			a = a + 1
			continue
		}
		fmt.Printf("value of a: %d\n", a)
		a++
	}
}

Is transpiled by go2hx into incorrectly commented Haxe, causing compilation failure.

package command_line_arguments;
import stdgo.fmt.Fmt;
import stdgo.StdGoTypes;
import stdgo.Go;
import stdgo.Builtin;
import stdgo.GoString;
/**
    func main() {
    	/* local variable definition */
    	var a int = 10
    
    	/* do loop execution */
    	for a < 20 {
    		if a == 15 {
    			/* skip the iteration */
    			a = a + 1
    			continue
    		}
    		fmt.Printf("value of a: %d\n", a)
    		a++
    	}
    }
**/
private function main():Void {
    var a:GoInt = (10 : IntegerType);
    while (a < (20 : IntegerType)) {
        if (a == (15 : IntegerType)) {
            a = a + (1 : IntegerType);
            continue;
        };
        stdgo.fmt.Fmt.printf((("value of a: %d\n" : GoString)), a);
        a++;
    };
}

Create Wiki

Topics to cover

  • Haxe versions.
  • Reserved keywords/ renaming system
  • Target generation, -cpp, -js, -interp etc
  • Externs (Go code refrencing Haxe functions)
  • Go library testing
  • Distribution (setting output, global libraries, etc)

Plug and Play

go2hx should make it extremly easy to use go libraries from haxe. The default options should cover 95% of cases, and the plugging should be intelligent on how it structures things for the end user.

  • callback on the go side if the path of the library was not found.
  • don't fail instantly rather check a few cases, for instance attempting to go get the path and re running.
  • remove potential human error such as including http://, https://, www.
  • try to rerun a path with ./ in front if it's not already included

Typedefs vs Classes

A discussion wich typesystem should be used for now (of course in the future it'd be possible to have both options and use the non default one with a flag).

Here are the features and drawbacks for the two diffrent types

Typedef

  • Closer to the Go style
  • Function declerations are required to be outside of the datatype, keeping the same style as Go
  • Structual sub-typing allows the same implicit relationship between types that Go has for interfaces.
  • No impact on performance for dynamic targets, static targets slower, with optimization on JVM/HL for common cases, worst case however requiring dynamic lookup - https://haxe.org/manual/types-structure-performance.html
  • multiple extensions allowed
  • No private fields, have to use @:noCompletion meta data to hide private fields from ide auto compleition.

Class

  • No implicit type relationship, needs to be figured out during the typing phase.
  • No multiple extensions allowed, need to reduce to one and consolidate types together.
  • No performance issues.
  • Go style is not kept, requires a new constructor, at least.
  • Function declerations can be both within the data type and outside of it.
  • Can implement interfaces.
  • Allows private fields and potentially less macro usage, with the draw back of more AST typing, and figuring out implicit type relations.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.