Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support function pointers #157

Open
elliotchance opened this issue Jun 4, 2017 · 10 comments
Open

Support function pointers #157

elliotchance opened this issue Jun 4, 2017 · 10 comments

Comments

@elliotchance
Copy link
Owner

No description provided.

@yulvil
Copy link
Contributor

yulvil commented Oct 21, 2017

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...

@elliotchance
Copy link
Owner Author

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).

@yulvil
Copy link
Contributor

yulvil commented Oct 29, 2017

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() {
}

@elliotchance
Copy link
Owner Author

elliotchance commented Oct 29, 2017

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

@yulvil
Copy link
Contributor

yulvil commented Oct 30, 2017

@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:

@yulvil
Copy link
Contributor

yulvil commented Nov 3, 2017

I am hoping to finish implementing this over the weekend.

@Konstantin8105
Copy link
Contributor

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

@yulvil
Copy link
Contributor

yulvil commented Nov 7, 2017

@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

@elliotchance elliotchance reopened this Nov 7, 2017
@elliotchance
Copy link
Owner Author

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.

@Konstantin8105
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants