c2go icon indicating copy to clipboard operation
c2go copied to clipboard

Support function pointers

Open elliotchance opened this issue 7 years ago • 10 comments

elliotchance avatar Jun 04 '17 19:06 elliotchance

C

int (*f)(int, int);

int add(int a, int b) {
        return a + b;
}

int mul(int a, int b) {
        return a * b;
}

int main() {
        f = add;
        int i = f(3,4);

        f = mul;
        int j = f(3,4);

        return i + j;
}

Suggested Go

type F interface {
  f(int, int) int
}

type Add struct {}
func (Add) f(a int, b int) int {
        return a + b
}

type Mul struct {}
func (Mul) f(a int, b int) int {
        return a * b
}

func main() {
        var f F = Add{}
        noarch.Printf([]byte("%d\n\x00"), f.f(3, 4))
        f = Mul{}
        noarch.Printf([]byte("%d\n\x00"), f.f(3, 4))
}

Now I need to find out how to get from C to Go. This may not cover all cases...

yulvil avatar Oct 21 '17 03:10 yulvil

You should not need to create an interface. You can just convert the function pointer directly to it's equivalent type, for example:

int (*f)(int, int) -> func (int, int) int
void (*f)(float) -> func (float32)

To fix this you will just need to teach resolve.go how to translate one to the other by replacing this code: https://github.com/elliotchance/c2go/blob/master/types/resolve.go#L219-L225

Within a single function pointer you can use the resolve to convert each data type (of the parameters and return).

elliotchance avatar Oct 23 '17 01:10 elliotchance

I have the C example above working by hard-coding "int (int, int)" in a few places, hard-coding the Go AST... I now need to make it work with other return types and parameters.

The changes are affecting:

  • transpiler/declarations: transpileVarDecl
  • types/resolve: ResolveType
  • util/goast: internalTypeToExpr

I will keep working on this.

Go output: (no c2go warnings)

package main

import "os"

type __int128_t int64
type __uint128_t uint64

var f func(a int, b int) int

func add(a int, b int) int {
        return a + b
}
func mul(a int, b int) int {
        return a * b
}
func main() {
        __init()
        f = add
        var i int = f(3, 4)
        f = mul
        var j int = f(3, 4)
        os.Exit(i + j)
}
func __init() {
}

yulvil avatar Oct 29 '17 07:10 yulvil

@yulvil The output looks perfect. Did you manually write that or was that the output of c2go?

elliotchance avatar Oct 29 '17 22:10 elliotchance

@elliotchance The Go file was generated by c2go. I only implemented the int (*) (int, int) function pointer. I need to make it work with other arg/return types.

Work in progress:

  • https://github.com/elliotchance/c2go/compare/master...yulvil:funcptr?expand=1

yulvil avatar Oct 30 '17 14:10 yulvil

I am hoping to finish implementing this over the weekend.

yulvil avatar Nov 03 '17 16:11 yulvil

@yulvil , Excuse, I found your message, but too later - I create PR. Excuse me again.

Konstantin8105 avatar Nov 04 '17 22:11 Konstantin8105

@elliotchance @Konstantin8105 I do no think that the functionality is complete. We should reopen this issue.

  • Remove the "function pointers are not supported" warnings

https://github.com/elliotchance/c2go/blob/master/types/resolve.go#L226,L231

  • Add tests where the function arg type is different than int.

TODO:

  • Add resolve test cases
	{"int (*)(int, float, double)", "func(int, float32, float64) int"},
	{"double (*)(double, double)", "func(float64, float64) float64"},
	{"void (*)()", "func()"},
	{"void (*)(void)", "func()"},
	{"void (*)(int)", "func(int)"},
	{"void (*)(void *)", "func(interface{})"},
	{"void (*)(char *)", "func([]byte)"},
	{"void (*)(char **)", "func([][]byte)"},
	{"void* (*)()", "func() interface{}"},

Example:

double (*f)(int, float, double);

double add (int a, float b, double c) {
    return c;
}

double mul (int a, float b, double c) {
    return c;
}

int main() {
  f = add;
  f(3, 4, 5);

  f = mul;
  return f(3, 4, 5);
}

Current go output (not compiling)

// Warning (BinaryOperator): {main.c 12 0 3 7 }: function pointers are not supported
// Warning (BinaryOperator): {main.c 12 0 3 7 }: function pointers are not supported
// Warning (CallExpr): {main.c 13 0 3 12 }: I couldn't find an appropriate Go type for the C type 'float32'.
// Warning (CallExpr): {main.c 13 0 3 12 }: I couldn't find an appropriate Go type for the C type 'float64'.
// Warning (BinaryOperator): {main.c 15 0 3 7 }: function pointers are not supported
// Warning (BinaryOperator): {main.c 15 0 3 7 }: function pointers are not supported
// Warning (CallExpr): {main.c 16 0 10 19 }: I couldn't find an appropriate Go type for the C type 'float32'.
// Warning (CallExpr): {main.c 16 0 10 19 }: I couldn't find an appropriate Go type for the C type 'float64'.
// Warning (ReturnStmt): {main.c 16 0 3 19 }: I couldn't find an appropriate Go type for the C type 'float64'.

package main

import "os"

type __int128_t int64
type __uint128_t uint64
type __builtin_ms_va_list []byte

var f func(int, float32, float64) float64

func add(a int, b float32, c float64) float64 {
	return c
}
func mul(a int, b float32, c float64) float64 {
	return c
}
func main() {
	__init()
	f = add
	f(3, nil, nil)
	f = mul
	os.Exit(nil)
}
func __init() {
}

go build main.go

# command-line-arguments
./main.go:30:4: cannot use nil as type float32 in argument to f
./main.go:30:4: cannot use nil as type float64 in argument to f
./main.go:32:9: cannot use nil as type int in argument to os.Exit

yulvil avatar Nov 07 '17 16:11 yulvil

Some of these larger tasks should really be multiple issues so that we can provide the functionality in useful stages. Especially when "done" isn't an absolute measurement. Also there will always be cases where some edge case is not covered.

Thanks for providing that information, I've reopened this issue. I'll be sure to pay attention to when issues should really be broken down to something more specific. That's my bad since I opened this issue originally.

elliotchance avatar Nov 07 '17 23:11 elliotchance

Present output:

/*
        Package main - transpiled by c2go version: v0.21.10 Zinc 2018-02-14

        If you have found any issues, please raise an issue at:
        https://github.com/elliotchance/c2go/
*/

package main

import "os"

var f func(int, float32, float64) float64

// add - transpiled function from  /home/konstantin/go/src/templorary/6.c:3
func add(a int, b float32, c float64) float64 {
        return c
}

// mul - transpiled function from  /home/konstantin/go/src/templorary/6.c:7
func mul(a int, b float32, c float64) float64 {
        return c
}

// main - transpiled function from  /home/konstantin/go/src/templorary/6.c:11
func main() {
        f = add
        f(3, float32(4), float64(5))
        f = mul
        os.Exit(int(f(3, float32(4), float64(5))))
}
func init() {
}

That issue can be closed.

Konstantin8105 avatar Feb 16 '18 12:02 Konstantin8105