// Package gdnative is responsible for parsing and generating binding code for // Go. package gdnative import ( "encoding/json" "errors" "io/ioutil" "log" "os" "text/template" ) // View is a structure that holds the api struct, so it can be used inside // our template. type View struct { API API StructType string } // NotLastElement is a function we use inside the template to test whether or // not the given element is the last in the slice or not. This is so we can // correctly insert commas for argument lists. func (v View) NotLastElement(n int, slice [][]string) bool { return n != (len(slice) - 1) } // NotVoid checks to see if the return string is void or not. This is used inside // our template so we can determine if we need to use the `return` keyword in // the function body. func (v View) NotVoid(ret string) bool { return ret != "void" } // HasArgs is a function we use inside the template to test whether or not the // function has arguments. This is so we can determine if we need to place a // comma. func (v View) HasArgs(args [][]string) bool { return len(args) != 0 } // Generate generates the bindings from the JSON definition func Generate() { // Get the API Path so we can locate the godot api JSON. apiPath := os.Getenv("API_PATH") if apiPath == "" { panic("$API_PATH is not defined.") } packagePath := apiPath // Create a structure for our template view. This will contain all of // the data we need to construct our binding methods. var view View // Unmarshal the JSON into our struct. apis := Parse(packagePath) // Add the core API to our view first view.API = apis.Core view.StructType = "core" // Generate the C bindings log.Println("Generating", view.StructType, "C headers...") WriteTemplate( packagePath+"/cmd/generate/templates/gdnative.h.tmpl", packagePath+"/gdnative/gdnative.gen.h", view, ) log.Println("Generating", view.StructType, "C bindings...") WriteTemplate( packagePath+"/cmd/generate/templates/gdnative.c.tmpl", packagePath+"/gdnative/gdnative.gen.c", view, ) // Loop through all of our extensions and generate the bindings for those. for _, api := range apis.Extensions { view.API = api view.StructType = "ext_" + api.Name log.Println("Generating", view.StructType, "C headers...") WriteTemplate( packagePath+"/cmd/generate/templates/gdnative.h.tmpl", packagePath+"/gdnative/"+api.Name+".gen.h", view, ) log.Println("Generating", view.StructType, "C bindings...") WriteTemplate( packagePath+"/cmd/generate/templates/gdnative.c.tmpl", packagePath+"/gdnative/"+api.Name+".gen.c", view, ) } } // Parse parses the given package path and returns go APIs wrapping Godot C gdnative API func Parse(packagePath string) APIs { // Open the gdnative_api.json file that defines the GDNative API. body, err := ioutil.ReadFile(packagePath + "/godot_headers/gdnative_api.json") if err != nil { panic(err) } // Unmarshal the JSON into our struct. var apis APIs if err := json.Unmarshal(body, &apis); err != nil { panic(errors.New("could not unmarshal Godot JSON API")) } return apis } // WriteTemplate writes the parsed template on the disk func WriteTemplate(templatePath, outputPath string, view View) { // Create a template from our template file. t, err := template.ParseFiles(templatePath) if err != nil { log.Fatal("Error parsing template:", err) } // Open the output file for writing f, err := os.Create(outputPath) if err != nil { panic(err) } defer f.Close() // Write the template with the given view. err = t.Execute(f, view) if err != nil { panic(err) } }