gml/internal/build/generate.go
2019-01-11 02:25:31 +01:00

296 lines
6.6 KiB
Go

/*
* GML - Go QML
* Copyright (c) 2019 Roland Singer [roland.singer@deserbit.com]
* Copyright (c) 2019 Sebastian Borchers [sebastian@deserbit.com]
*/
package build
import (
"os"
"path/filepath"
"strings"
)
const (
genGoFilename = "gml_gen.go"
)
// TODO: make concurrent with multiple goroutines.
func generate(ctx *Context) (err error) {
gt, err := parseDirRecursive(ctx.SourceDir)
if err != nil {
return
}
err = generateCIncludeAllHeaderFile(gt, ctx.CGenIncludeDir)
if err != nil {
return
}
for _, gp := range gt.Packages {
err = generateGoFile(gp)
if err != nil {
return
}
err = generateCHeaderFile(gp, ctx.CGenDir)
if err != nil {
return
}
err = generateCPPHeaderFile(gp, ctx.CPPGenDir)
if err != nil {
return
}
err = generateCPPSourceFile(gp, ctx.CPPGenDir)
if err != nil {
return
}
}
return
}
// This shoult be in a separate directory, so no unnecessary files are in the global include dir.
func generateCIncludeAllHeaderFile(gt *genTargets, genDir string) (err error) {
filename := filepath.Join(genDir, "gml_gen.h")
// Create the file.
f, err := os.Create(filename)
if err != nil {
return
}
defer func() {
derr := f.Close()
if derr != nil && err == nil {
err = derr
}
}()
f.WriteString("// This file is auto-generated by gml.\n")
f.WriteString("#ifndef GML_GEN_C_INCLUDE_H\n")
f.WriteString("#define GML_GEN_C_INCLUDE_H\n\n")
for _, gp := range gt.Packages {
f.WriteString("#include \"../" + gp.Name + ".h\"\n")
}
f.WriteString("\n#endif\n")
return
}
func generateGoFile(gp *genPackage) (err error) {
filename := filepath.Join(gp.Dir, genGoFilename)
// Create the file.
f, err := os.Create(filename)
if err != nil {
return
}
defer func() {
derr := f.Close()
if derr != nil && err == nil {
err = derr
}
}()
// Write the header.
f.WriteString("// This file is auto-generated by gml.\n")
f.WriteString("package " + gp.Name + "\n\n")
f.WriteString("// #include <gml_gen.h>\n")
f.WriteString("import \"C\"\n\n")
for _, st := range gp.Structs {
// Add all signals.
for _, s := range st.Signals {
f.WriteString("func (_v *" + st.Name + ") " + s.Name + "(")
// Add the parameters.
for i, p := range s.Params {
if i != 0 {
f.WriteString(", ")
}
f.WriteString(p.Name + " " + p.Type)
}
f.WriteString(") {\n")
// TODO:
f.WriteString("}\n\n")
}
}
return
}
// TODO: add package prefix!
func generateCHeaderFile(gp *genPackage, genDir string) (err error) {
filename := filepath.Join(genDir, gp.Name+".h")
// Create the file.
f, err := os.Create(filename)
if err != nil {
return
}
defer func() {
derr := f.Close()
if derr != nil && err == nil {
err = derr
}
}()
// Write the header.
f.WriteString("// This file is auto-generated by gml.\n")
f.WriteString("#ifndef GML_GEN_C_" + strings.ToUpper(gp.Name) + "_H\n")
f.WriteString("#define GML_GEN_C_" + strings.ToUpper(gp.Name) + "_H\n\n")
f.WriteString("#ifdef __cplusplus\n")
f.WriteString("extern \"C\" {\n")
f.WriteString("#endif\n\n")
for _, st := range gp.Structs {
f.WriteString("//###\n")
f.WriteString("//### " + st.Name + "\n")
f.WriteString("//###\n\n")
base := "gml_gen_" + st.Name
f.WriteString("typedef void* " + base + ";\n\n")
// Constructor & destructor.
f.WriteString(base + " " + base + "_new();\n")
f.WriteString("void " + base + "_free(" + base + ");\n\n")
// Add all signals.
if len(st.Signals) > 0 {
for _, s := range st.Signals {
f.WriteString("void " + base + "_" + s.Name + "(") // TODO: return value.
for i, p := range s.Params {
if i != 0 {
f.WriteString(", ")
}
f.WriteString(p.Type + " " + p.Name) // TODO: to C types.
}
f.WriteString(");\n")
}
}
f.WriteString("\n")
}
f.WriteString("#ifdef __cplusplus\n")
f.WriteString("}\n")
f.WriteString("#endif\n\n")
f.WriteString("#endif\n")
return
}
func generateCPPSourceFile(gp *genPackage, genDir string) (err error) {
filename := filepath.Join(genDir, gp.Name+".cpp")
// Create the file.
f, err := os.Create(filename)
if err != nil {
return
}
defer func() {
derr := f.Close()
if derr != nil && err == nil {
err = derr
}
}()
// Write the header.
f.WriteString("// This file is auto-generated by gml.\n")
f.WriteString("#include \"" + gp.Name + ".h\"\n\n")
for _, st := range gp.Structs {
f.WriteString("//###\n")
f.WriteString("//### " + st.Name + "\n")
f.WriteString("//###\n\n")
base := "gml_gen_" + st.Name
cppbase := "GMLGen" + st.Name
// Constructor. TODO: try catch
f.WriteString(base + " " + base + "_new() {\n")
f.WriteString(" auto _vv = new " + cppbase + "();\n")
f.WriteString(" return (void*)_vv;\n")
f.WriteString("}\n\n")
// Destructor. TODO: try catch
f.WriteString("void " + base + "_free(" + base + " _v) {\n")
f.WriteString(" auto _vv = (" + cppbase + "*)_v;\n")
f.WriteString(" delete _vv;\n")
f.WriteString("}\n\n")
// Add all signals.
if len(st.Signals) > 0 {
for _, s := range st.Signals {
f.WriteString("void " + base + "_" + s.Name + "(") // TODO: return value.
for i, p := range s.Params {
if i != 0 {
f.WriteString(", ")
}
f.WriteString(p.Type + " " + p.Name) // TODO: to C types.
}
f.WriteString(") {\n")
f.WriteString("}\n")
}
}
f.WriteString("\n")
}
return
}
func generateCPPHeaderFile(gp *genPackage, genDir string) (err error) {
filename := filepath.Join(genDir, gp.Name+".h")
// Create the file.
f, err := os.Create(filename)
if err != nil {
return
}
defer func() {
derr := f.Close()
if derr != nil && err == nil {
err = derr
}
}()
// Write the header.
f.WriteString("// This file is auto-generated by gml.\n")
f.WriteString("#ifndef GML_GEN_CPP_" + strings.ToUpper(gp.Name) + "_H\n")
f.WriteString("#define GML_GEN_CPP_" + strings.ToUpper(gp.Name) + "_H\n\n")
f.WriteString("#include \"../gen_c/" + gp.Name + ".h\"\n")
f.WriteString("#include <QObject>\n\n")
for _, st := range gp.Structs {
f.WriteString("//###\n")
f.WriteString("//### " + st.Name + "\n")
f.WriteString("//###\n\n")
f.WriteString("class GMLGen" + st.Name + " : public QObject\n")
f.WriteString("{\n")
f.WriteString(" Q_OBJECT\n")
// Add all signals.
if len(st.Signals) > 0 {
f.WriteString("signals:\n")
for _, s := range st.Signals {
f.WriteString(" void " + s.Name + "(") // TODO: return value.
for i, p := range s.Params {
if i != 0 {
f.WriteString(", ")
}
f.WriteString(p.Type + " " + p.Name) // TODO: to C++ types.
}
f.WriteString(");\n")
}
}
f.WriteString("};\n\n")
}
f.WriteString("#endif\n")
return
}