如何将FUNCTION名称放宽为变量

I code a plugin generator in Go. The repo is open.

The project creates some Go code in some temporary file defining a function taken from command-line arguments, compiles that code into a plugin, loads that plugin, gets the function in it, and invokes that with parameters, then prints the results.

We want to be able to process several functions and several plugins. For example, a function SUM of body return x+y;, a function PROD of body return x*y; and so on.

I don't want the generated code to always use the constant name FUNCTION. Can't the generated .go file contain a function whose name is given at runtime, i.e. my funame in the code below? Is there some feature of the Go language forbidding that?

//TODO: Investigate how to relax the name FUNCTION into a variable
type Xinterface interface {
    FUNCTION(x int, y int) int
}

Complete code

package main

import (
    "fmt"
    "os"
    "os/exec"
    "path/filepath"
    "plugin"
    "reflect"
    "strconv"
    "strings"
)


//TODO: Investigate how to relax the name FUNCTION into a variable
type Xinterface interface {
    FUNCTION(x int, y int) int
}

func main() {
    //Declare good variable names and create the file for the code
    funame := os.Args[1]
    funamel := strings.ToLower(funame)
    funamet := strings.Title(funame)
    fubody := os.Args[2]
    x1, err := strconv.Atoi(os.Args[3])
    y1, err := strconv.Atoi(os.Args[4])
    filename := fmt.Sprintf("/tmp/%s.go", funame)
    f, err := os.Create(filename)
    if err != nil {
        fmt.Println(err)
        return
    }
    //Here comes the program
    strprg := fmt.Sprintf(`package main 
import (
    "fmt"
)
type %s string 
func(s %s) FUNCTION (x int, y int) int { fmt.Println("")
%s} 
var %s %s`, funamel, funamel, fubody, funamet, funamel)
    fmt.Printf("func(s %s) FUNCTION (x int, y int) int { 
", funamel)
    fmt.Printf("start of %s: x=%d, y=%d
", funamel, x1, y1)
    l, err := f.WriteString(strprg)
    if err != nil {
        fmt.Println(err)
        f.Close()
        return
    }
    fmt.Println(l, "bytes written successfully")
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }

    ex, err := os.Executable()
    if err != nil {
        panic(err)
    }
    exPath := filepath.Dir(ex)
    fmt.Println(exPath)
    fmt.Println("compiling plugin")
    cmd := exec.Command("go", "build", "-buildmode=plugin", "-o", fmt.Sprintf("%s%s%s", "/tmp/", funame, ".so"), fmt.Sprintf("%s%s%s", "/tmp/", funame, ".go"))

    out, err2 := cmd.Output()
    fmt.Println(out)

    if err2 != nil {
        fmt.Println(err2)
        return
    }
    fmt.Println("loading module")
    // load module
    // 1. open the so file to load the symbols
    plug, err := plugin.Open(fmt.Sprintf("%s%s%s", "/tmp/", funame, ".so"))
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    fmt.Println("looking up symbol")
    // 2. look up a symbol (an exported function or variable)
    // in this case, variable funame
    symX, err := plug.Lookup(funame)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    fmt.Println("checking module")
    // 3. Assert that loaded symbol is of a desired type
    // in this case interface type X (defined above)
    var myvar Xinterface
    myvar, ok := symX.(Xinterface)
    if !ok {
        fmt.Println(fmt.Sprintf("unexpected type from module symbol %s", reflect.TypeOf(symX.(Xinterface))))
        os.Exit(1)
    }

    // 4. use the module

    fmt.Println(myvar.FUNCTION(x1, y1))
    fmt.Println(fmt.Sprintf("Generated code: %s", fmt.Sprintf("/tmp/%s%s", funamet , ".go") ))
    fmt.Println(fmt.Sprintf("Generated object file: %s", fmt.Sprintf("/tmp/%s%s", funamet , ".so") ))

}

Example usage:

$ go run forbasile.go SUM 'return x+y' 3 5
func(s sum) FUNCTION (x int, y int) int { 
start of sum: x=3, y=5
131 bytes written successfully
/tmp/go-build104174513/b001/exe
compiling plugin
[]
loading module
looking up symbol
checking module

8
Generated code: /tmp/SUM.go
Generated object file: /tmp/SUM.so
$ go run forbasile.go SUMSQUARE 'return x*x + y*y' 3 4
func(s sumsquare) FUNCTION (x int, y int) int { 
start of sumsquare: x=3, y=4
161 bytes written successfully
/tmp/go-build555823501/b001/exe
compiling plugin
[]
loading module
looking up symbol
checking module

25
Generated code: /tmp/SUMSQUARE.go
Generated object file: /tmp/SUMSQUARE.so

godoc

A Symbol is a pointer to a variable or function.

For example, a plugin defined as

package main

import "fmt"

func F() { fmt.Printf("Hello, number %d
", V) }

may be loaded with the Open function and then the exported package symbols V and F can be accessed

p, err := plugin.Open("plugin_name.so")
if err != nil {
    panic(err)
}
f, err := p.Lookup("F")
if err != nil {
    panic(err)
}
f.(func())() // prints "Hello, number 7"

"F" is just a String, so you can change its value at runtime anyway.