510 lines
17 KiB
Go
510 lines
17 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
func main() {
|
|
|
|
var experiments string
|
|
flag.StringVar(&experiments, "experiments", "", "experiments to enable")
|
|
flag.Parse()
|
|
loadedExperiments := make(map[string]bool)
|
|
for _, exp := range strings.Split(experiments, ",") {
|
|
loadedExperiments[exp] = true
|
|
}
|
|
|
|
generatedBindingsPrefix := ``
|
|
generatedBindings := ``
|
|
experimentRegistry := ``
|
|
experimentUpdateSettings := ``
|
|
|
|
file, err := os.Open("spec")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer file.Close()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
// optionally, resize scanner's capacity for lines over 64K, see next example
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if strings.HasPrefix(line, "#") || len(line) == 0 {
|
|
// ignore
|
|
continue
|
|
}
|
|
|
|
parts := strings.Split(line, " ")
|
|
if len(parts) < 2 {
|
|
fmt.Printf("all spec lines must start with a type prefix and a function name: %v\n", parts)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fType := parts[0]
|
|
fName := parts[1]
|
|
args := parts[2:]
|
|
|
|
experiment := ""
|
|
if strings.HasPrefix(fType, "!") {
|
|
experiment = strings.ReplaceAll(fType, "!", "")
|
|
if _, gen := loadedExperiments[experiment]; gen {
|
|
fType = parts[1]
|
|
fName = parts[2]
|
|
args = parts[3:]
|
|
} else {
|
|
continue // skip experiment
|
|
}
|
|
}
|
|
|
|
if strings.HasPrefix(fType, "import") {
|
|
generatedBindingsPrefix += fName + "\n"
|
|
continue
|
|
}
|
|
|
|
if strings.HasPrefix(fType, "global") {
|
|
generatedBindings += fmt.Sprintf("var %s %s\n", parts[2], parts[3])
|
|
|
|
experimentRegistry += fmt.Sprintf(`
|
|
%s = %s.Init(&globalACN, appDir)
|
|
eventHandler.AddModule(%s)
|
|
%s.Enable(application, &globalACN)
|
|
`, parts[2], parts[4], parts[2], parts[2])
|
|
|
|
experimentUpdateSettings += fmt.Sprintf(`
|
|
%s.UpdateSettings(application, &globalACN)
|
|
`, parts[2])
|
|
|
|
continue
|
|
}
|
|
|
|
fmt.Printf("generating %v function for %v\n", fType, fName)
|
|
|
|
switch fType {
|
|
|
|
case "app":
|
|
generatedBindings = generateAppFunction(generatedBindings, fName, args)
|
|
case "exp":
|
|
generatedBindings = generateExpFunction(generatedBindings, fName, experiment, args)
|
|
case "(json)app":
|
|
generatedBindings = generateJsonAppFunction(generatedBindings, fName, args)
|
|
case "profile":
|
|
generatedBindings = generateProfileFunction(generatedBindings, fName, args)
|
|
case "(json)profile":
|
|
generatedBindings = generateJsonProfileFunction(generatedBindings, fName, args, false)
|
|
case "(json-err)profile":
|
|
generatedBindings = generateJsonProfileFunction(generatedBindings, fName, args, true)
|
|
case "@profile-experiment":
|
|
experiment := args[0]
|
|
generatedBindings = generateExperimentalProfileFunction(generatedBindings, experiment, fName, args[1:])
|
|
case "@(json)profile-experiment":
|
|
experiment := args[0]
|
|
generatedBindings = generateExperimentalJsonProfileFunction(generatedBindings, experiment, fName, args[1:])
|
|
default:
|
|
|
|
fmt.Printf("unknown function type %v\n", parts)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("%v\n", generatedBindings)
|
|
// NOTE: You can see individual generations by uncommenting the below lines..
|
|
// os.WriteFile("templates/bindings.go", []byte(generatedBindings), 0644)
|
|
// os.WriteFile("templates/imports.go", []byte(generatedBindingsPrefix), 0644)
|
|
|
|
template, _ := os.ReadFile("templates/lib_template.go")
|
|
templateString := string(template)
|
|
templateString = strings.ReplaceAll(templateString, "{{BINDINGS}}", generatedBindings)
|
|
templateString = strings.ReplaceAll(templateString, "{{EXPERIMENT_REGISTER}}", experimentRegistry)
|
|
templateString = strings.ReplaceAll(templateString, "{{EXPERIMENT_UPDATESETTINGS}}", experimentUpdateSettings)
|
|
templateString = strings.ReplaceAll(templateString, "{{IMPORTS}}", generatedBindingsPrefix)
|
|
os.WriteFile("lib.go", []byte(templateString), 0644)
|
|
}
|
|
|
|
var uniqueVarCounter = 0
|
|
|
|
func profileHandleArgPrototype() (string, string, string, string) {
|
|
return `onion_ptr *C.char, onion_len C.int`, `C.GoStringN(onion_ptr, onion_len)`, `profile string`, "profile"
|
|
}
|
|
|
|
func nameArgPrototype() (string, string, string, string) {
|
|
return `name_ptr *C.char, name_len C.int`, `C.GoStringN(name_ptr, name_len)`, `name string`, "name"
|
|
}
|
|
|
|
func passwordArgPrototype() (string, string, string, string) {
|
|
return `password_ptr *C.char, password_len C.int`, `C.GoStringN(password_ptr, password_len)`, `password string`, "password"
|
|
}
|
|
|
|
func intArgPrototype(varName string) (string, string, string, string) {
|
|
return fmt.Sprintf(`%s C.int`, ToSnakeCase(varName)), fmt.Sprintf(`int(%v)`, ToSnakeCase(varName)), fmt.Sprintf(`%v int`, varName), varName
|
|
}
|
|
|
|
func uintArgPrototype(varName string) (string, string, string, string) {
|
|
return fmt.Sprintf(`%s C.uint`, ToSnakeCase(varName)), fmt.Sprintf(`int(%v)`, ToSnakeCase(varName)), fmt.Sprintf(`%v int`, varName), varName
|
|
}
|
|
|
|
func conversationArgPrototype(varName string) (string, string, string, string) {
|
|
return intArgPrototype(varName)
|
|
}
|
|
|
|
func channelArgPrototype() (string, string, string, string) {
|
|
return intArgPrototype("channel_id")
|
|
}
|
|
|
|
func messageArgPrototype() (string, string, string, string) {
|
|
return intArgPrototype("message_id")
|
|
}
|
|
|
|
func boolArgPrototype(name string) (string, string, string, string) {
|
|
uniqueVarCounter += 1
|
|
varName := fmt.Sprintf("%s%d", name, uniqueVarCounter)
|
|
return fmt.Sprintf(`%s C.char`, ToSnakeCase(varName)), fmt.Sprintf(`%v == 1`, ToSnakeCase(varName)), fmt.Sprintf(`%v bool`, varName), varName
|
|
}
|
|
|
|
func stringArgPrototype(name string) (string, string, string, string) {
|
|
uniqueVarCounter += 1
|
|
varName := fmt.Sprintf("%s%d", name, uniqueVarCounter)
|
|
return fmt.Sprintf(`%s_ptr *C.char, %s_len C.int`, varName, varName), fmt.Sprintf(`C.GoStringN(%s_ptr, %s_len)`, varName, varName), fmt.Sprintf(`%v string`, varName), varName
|
|
}
|
|
|
|
func mapArgs(argsTypes []string) (string, string, string, string) {
|
|
var cArgs []string
|
|
var c2GoArgs []string
|
|
var goSpec []string
|
|
var gUse []string
|
|
for _, argSpec := range argsTypes {
|
|
argTypeParts := strings.Split(argSpec, ":")
|
|
argType := argTypeParts[0]
|
|
switch argType {
|
|
case "application":
|
|
gUse = append(gUse, "application")
|
|
case "acn":
|
|
gUse = append(gUse, "&globalACN")
|
|
case "profile":
|
|
c1, c2, c3, c4 := profileHandleArgPrototype()
|
|
cArgs = append(cArgs, c1)
|
|
c2GoArgs = append(c2GoArgs, c2)
|
|
goSpec = append(goSpec, c3)
|
|
gUse = append(gUse, c4)
|
|
case "name":
|
|
c1, c2, c3, c4 := nameArgPrototype()
|
|
cArgs = append(cArgs, c1)
|
|
c2GoArgs = append(c2GoArgs, c2)
|
|
goSpec = append(goSpec, c3)
|
|
gUse = append(gUse, c4)
|
|
case "password":
|
|
c1, c2, c3, c4 := passwordArgPrototype()
|
|
cArgs = append(cArgs, c1)
|
|
c2GoArgs = append(c2GoArgs, c2)
|
|
goSpec = append(goSpec, c3)
|
|
gUse = append(gUse, c4)
|
|
case "conversation":
|
|
name := "conversation"
|
|
if len(argTypeParts) == 2 {
|
|
name = argTypeParts[1]
|
|
}
|
|
c1, c2, c3, c4 := conversationArgPrototype(name)
|
|
cArgs = append(cArgs, c1)
|
|
c2GoArgs = append(c2GoArgs, c2)
|
|
goSpec = append(goSpec, c3)
|
|
gUse = append(gUse, c4)
|
|
case "channel":
|
|
c1, c2, c3, c4 := channelArgPrototype()
|
|
cArgs = append(cArgs, c1)
|
|
c2GoArgs = append(c2GoArgs, c2)
|
|
goSpec = append(goSpec, c3)
|
|
gUse = append(gUse, c4)
|
|
case "message":
|
|
c1, c2, c3, c4 := messageArgPrototype()
|
|
cArgs = append(cArgs, c1)
|
|
c2GoArgs = append(c2GoArgs, c2)
|
|
goSpec = append(goSpec, c3)
|
|
gUse = append(gUse, c4)
|
|
case "bool":
|
|
if len(argTypeParts) != 2 {
|
|
fmt.Printf("generic bool arg must have have e.g. bool:<name>\n")
|
|
os.Exit(1)
|
|
}
|
|
c1, c2, c3, c4 := boolArgPrototype(argTypeParts[1])
|
|
cArgs = append(cArgs, c1)
|
|
c2GoArgs = append(c2GoArgs, c2)
|
|
goSpec = append(goSpec, c3)
|
|
gUse = append(gUse, c4)
|
|
case "int":
|
|
if len(argTypeParts) != 2 {
|
|
fmt.Printf("generic int arg must have have e.g. int:<name>\n")
|
|
os.Exit(1)
|
|
}
|
|
c1, c2, c3, c4 := intArgPrototype(argTypeParts[1])
|
|
cArgs = append(cArgs, c1)
|
|
c2GoArgs = append(c2GoArgs, c2)
|
|
goSpec = append(goSpec, c3)
|
|
gUse = append(gUse, c4)
|
|
case "uint":
|
|
if len(argTypeParts) != 2 {
|
|
fmt.Printf("generic uint arg must have have e.g. uint:<name>\n")
|
|
os.Exit(1)
|
|
}
|
|
c1, c2, c3, c4 := uintArgPrototype(argTypeParts[1])
|
|
cArgs = append(cArgs, c1)
|
|
c2GoArgs = append(c2GoArgs, c2)
|
|
goSpec = append(goSpec, c3)
|
|
// because of java/kotlin/android/gomobile inability to recognize unsigned integers
|
|
// we need to pretent this is a signed interface...so do the final cast here...
|
|
// this will cause bad behavior if a negative number is passed through the java
|
|
// interface...so...don't do that...
|
|
gUse = append(gUse, fmt.Sprintf("uint(%s)", c4))
|
|
case "string":
|
|
if len(argTypeParts) != 2 {
|
|
fmt.Printf("generic string arg must have have e.g. string:<name>\n")
|
|
os.Exit(1)
|
|
}
|
|
c1, c2, c3, c4 := stringArgPrototype(argTypeParts[1])
|
|
cArgs = append(cArgs, c1)
|
|
c2GoArgs = append(c2GoArgs, c2)
|
|
goSpec = append(goSpec, c3)
|
|
gUse = append(gUse, c4)
|
|
default:
|
|
fmt.Printf("unknown arg type [%v]\n", argType)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
return strings.Join(cArgs, ","), strings.Join(c2GoArgs, ","), strings.Join(goSpec, ","), strings.Join(gUse, ",")
|
|
}
|
|
|
|
func generateAppFunction(bindings string, name string, argsTypes []string) string {
|
|
appPrototype := `
|
|
//export c_{{FNAME}}
|
|
func c_{{FNAME}}({{C_ARGS}}) {
|
|
{{FNAME}}({{C2GO_ARGS}})
|
|
}
|
|
|
|
func {{FNAME}}({{GO_ARGS_SPEC}}) {
|
|
application.{{LIBNAME}}({{GO_ARG}})
|
|
}
|
|
`
|
|
|
|
cArgs, c2GoArgs, goSpec, gUse := mapArgs(argsTypes)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{FNAME}}", strings.TrimPrefix(name, "Enhanced"))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{LIBNAME}}", name)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C_ARGS}}", cArgs)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C2GO_ARGS}}", c2GoArgs)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARGS_SPEC}}", goSpec)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARG}}", gUse)
|
|
|
|
bindings += appPrototype
|
|
return bindings
|
|
}
|
|
|
|
func generateExpFunction(bindings string, name string, exp string, argsTypes []string) string {
|
|
appPrototype := `
|
|
//export c_{{FNAME}}
|
|
func c_{{FNAME}}({{C_ARGS}}) {
|
|
{{FNAME}}({{C2GO_ARGS}})
|
|
}
|
|
|
|
func {{FNAME}}({{GO_ARGS_SPEC}}) {
|
|
{{EXPERIMENT}}.{{LIBNAME}}({{GO_ARG}})
|
|
}
|
|
`
|
|
|
|
cArgs, c2GoArgs, goSpec, gUse := mapArgs(argsTypes)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{FNAME}}", strings.TrimPrefix(name, "Enhanced"))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{EXPERIMENT}}", exp)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{LIBNAME}}", name)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C_ARGS}}", cArgs)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C2GO_ARGS}}", c2GoArgs)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARGS_SPEC}}", goSpec)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARG}}", gUse)
|
|
|
|
bindings += appPrototype
|
|
return bindings
|
|
}
|
|
|
|
func generateJsonAppFunction(bindings string, name string, argsTypes []string) string {
|
|
appPrototype := `
|
|
//export c_{{FNAME}}
|
|
func c_{{FNAME}}({{C_ARGS}}) *C.char {
|
|
return C.CString({{FNAME}}({{C2GO_ARGS}}))
|
|
}
|
|
|
|
func {{FNAME}}({{GO_ARGS_SPEC}}) string {
|
|
return application.{{LIBNAME}}({{GO_ARG}})
|
|
}
|
|
`
|
|
|
|
cArgs, c2GoArgs, goSpec, gUse := mapArgs(argsTypes)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{FNAME}}", strings.TrimPrefix(name, "Enhanced"))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{LIBNAME}}", name)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C_ARGS}}", cArgs)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C2GO_ARGS}}", c2GoArgs)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARGS_SPEC}}", goSpec)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARG}}", gUse)
|
|
|
|
bindings += appPrototype
|
|
return bindings
|
|
}
|
|
|
|
func generateProfileFunction(bindings string, name string, argsTypes []string) string {
|
|
appPrototype := `
|
|
//export c_{{FNAME}}
|
|
func c_{{FNAME}}({{C_ARGS}}) {
|
|
{{FNAME}}({{C2GO_ARGS}})
|
|
}
|
|
|
|
func {{FNAME}}({{GO_ARGS_SPEC}}) {
|
|
cwtchProfile := application.GetPeer(profile)
|
|
if cwtchProfile != nil {
|
|
cwtchProfile.{{LIBNAME}}({{GO_ARG}})
|
|
}
|
|
}
|
|
`
|
|
|
|
cArgs, c2GoArgs, goSpec, gUse := mapArgs(argsTypes)
|
|
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{FNAME}}", strings.TrimPrefix(name, "Enhanced"))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{LIBNAME}}", name)
|
|
// We need to prepend a set of profile handle arguments...
|
|
pArgs, c2GoPArg, goSpecP, _ := profileHandleArgPrototype()
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C_ARGS}}", strings.Join(append([]string{pArgs}, cArgs), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C2GO_ARGS}}", strings.Join(append([]string{c2GoPArg}, c2GoArgs), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARGS_SPEC}}", strings.Join(append([]string{goSpecP}, goSpec), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARG}}", gUse)
|
|
|
|
bindings += appPrototype
|
|
return bindings
|
|
}
|
|
|
|
func generateJsonProfileFunction(bindings string, name string, argsTypes []string, handleErr bool) string {
|
|
appPrototype := `
|
|
//export c_{{FNAME}}
|
|
func c_{{FNAME}}({{C_ARGS}}) *C.char {
|
|
return C.CString({{FNAME}}({{C2GO_ARGS}}))
|
|
}
|
|
|
|
func {{FNAME}}({{GO_ARGS_SPEC}}) string {
|
|
cwtchProfile := application.GetPeer(profile)
|
|
if cwtchProfile != nil {
|
|
{{HANDLE_FUNC}}
|
|
}
|
|
return ""
|
|
}
|
|
`
|
|
|
|
noErrorPrototype := `return cwtchProfile.{{LIBNAME}}({{GO_ARG}})`
|
|
withErrorPrototype := `res,err := cwtchProfile.{{LIBNAME}}({{GO_ARG}})
|
|
if err != nil {
|
|
log.Errorf("could not {{FNAME}} %v", err)
|
|
}
|
|
return res`
|
|
functionPrototype := noErrorPrototype
|
|
if handleErr {
|
|
functionPrototype = withErrorPrototype
|
|
}
|
|
|
|
cArgs, c2GoArgs, goSpec, gUse := mapArgs(argsTypes)
|
|
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{HANDLE_FUNC}}", functionPrototype)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{FNAME}}", strings.TrimPrefix(name, "Enhanced"))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{LIBNAME}}", name)
|
|
// We need to prepend a set of profile handle arguments...
|
|
pArgs, c2GoPArg, goSpecP, _ := profileHandleArgPrototype()
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C_ARGS}}", strings.Join(append([]string{pArgs}, cArgs), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C2GO_ARGS}}", strings.Join(append([]string{c2GoPArg}, c2GoArgs), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARGS_SPEC}}", strings.Join(append([]string{goSpecP}, goSpec), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARG}}", gUse)
|
|
|
|
bindings += appPrototype
|
|
return bindings
|
|
}
|
|
|
|
func generateExperimentalProfileFunction(bindings string, experiment string, name string, argsTypes []string) string {
|
|
appPrototype := `
|
|
//export c_{{FNAME}}
|
|
func c_{{FNAME}}({{C_ARGS}}) {
|
|
{{FNAME}}({{C2GO_ARGS}})
|
|
}
|
|
|
|
func {{FNAME}}({{GO_ARGS_SPEC}}) {
|
|
cwtchProfile := application.GetPeer(profile)
|
|
if cwtchProfile != nil {
|
|
functionality := {{EXPERIMENT}}.FunctionalityGate()
|
|
if functionality != nil {
|
|
err := functionality.{{LIBNAME}}(cwtchProfile, {{GO_ARG}})
|
|
if err != nil {
|
|
log.Errorf("error calling experimental feature {{FNAME}}: %v", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`
|
|
|
|
cArgs, c2GoArgs, goSpec, gUse := mapArgs(argsTypes)
|
|
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{FNAME}}", strings.TrimPrefix(name, "Enhanced"))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{LIBNAME}}", name)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{EXPERIMENT}}", experiment)
|
|
// We need to prepend a set of profile handle arguments...
|
|
pArgs, c2GoPArg, goSpecP, _ := profileHandleArgPrototype()
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C_ARGS}}", strings.Join(append([]string{pArgs}, cArgs), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C2GO_ARGS}}", strings.Join(append([]string{c2GoPArg}, c2GoArgs), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARGS_SPEC}}", strings.Join(append([]string{goSpecP}, goSpec), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARG}}", gUse)
|
|
|
|
bindings += appPrototype
|
|
return bindings
|
|
}
|
|
|
|
func generateExperimentalJsonProfileFunction(bindings string, experiment string, name string, argsTypes []string) string {
|
|
appPrototype := `
|
|
//export c_{{FNAME}}
|
|
func c_{{FNAME}}({{C_ARGS}}) *C.char {
|
|
return C.CString({{FNAME}}({{C2GO_ARGS}}))
|
|
}
|
|
|
|
func {{FNAME}}({{GO_ARGS_SPEC}}) string {
|
|
cwtchProfile := application.GetPeer(profile)
|
|
if cwtchProfile != nil {
|
|
functionality := {{EXPERIMENT}}.FunctionalityGate()
|
|
if functionality != nil {
|
|
return functionality.{{LIBNAME}}(cwtchProfile, {{GO_ARG}})
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
`
|
|
|
|
cArgs, c2GoArgs, goSpec, gUse := mapArgs(argsTypes)
|
|
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{FNAME}}", strings.TrimPrefix(name, "Enhanced"))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{LIBNAME}}", name)
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{EXPERIMENT}}", experiment)
|
|
// We need to prepend a set of profile handle arguments...
|
|
pArgs, c2GoPArg, goSpecP, _ := profileHandleArgPrototype()
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C_ARGS}}", strings.Join(append([]string{pArgs}, cArgs), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{C2GO_ARGS}}", strings.Join(append([]string{c2GoPArg}, c2GoArgs), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARGS_SPEC}}", strings.Join(append([]string{goSpecP}, goSpec), ","))
|
|
appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARG}}", gUse)
|
|
|
|
bindings += appPrototype
|
|
return bindings
|
|
}
|
|
|
|
var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)")
|
|
var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])")
|
|
|
|
func ToSnakeCase(str string) string {
|
|
snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}")
|
|
snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}")
|
|
return strings.ToLower(snake)
|
|
}
|