Files
squeezelite-esp32/components/spotify/cspot/cpp-reflection/cpp_generator.go
Philippe G 898998efb0 big merge
2021-12-18 21:04:23 -08:00

166 lines
4.0 KiB
Go

package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"os"
"path"
"strings"
"unicode"
)
type CppGenerator struct {
includes []string
files map[string]*CppGenerator
Body *bytes.Buffer
BodyBeforeLocalIncludes *bytes.Buffer
Filename string
IsHeader bool
}
// NewCppGenerator docsy bo ci wywali sie blad xd
func NewCppGenerator(filename string) *CppGenerator {
isHeader := true
if strings.HasSuffix(filename, ".cpp") {
isHeader = false
}
return &CppGenerator{
includes: []string{},
Body: &bytes.Buffer{},
BodyBeforeLocalIncludes: &bytes.Buffer{},
files: make(map[string]*CppGenerator),
Filename: filename,
IsHeader: isHeader,
}
}
func (cg *CppGenerator) SubFile(filename string, isHeader bool) *CppGenerator {
if gen, ok := cg.files[filename]; ok {
return gen
}
gen := NewCppGenerator(filename)
gen.IsHeader = isHeader
gen.files = cg.files
cg.files[filename] = gen
return gen
}
// AddLibraryInclude yes
func (cg *CppGenerator) AddLibraryInclude(name string) *CppGenerator {
resultingLine := fmt.Sprintf("#include <%s>", name)
for _, a := range cg.includes {
if a == resultingLine {
return cg
}
}
cg.includes = append(cg.includes, resultingLine)
return cg
}
func (cg *CppGenerator) AddLocalInclude(name string) *CppGenerator {
resultingLine := fmt.Sprintf("#include \"%s\"", name)
for _, a := range cg.includes {
if a == resultingLine {
return cg
}
}
cg.includes = append(cg.includes, resultingLine)
return cg
}
// OutputClassField yes
func (cg *CppGenerator) OutputClassField(theType string, name string) {
fmt.Fprintf(cg.Body, "%v %v;\n", theType, name)
}
// OutputClassTypeID yes
func (cg *CppGenerator) OutputClassTypeID(theID string) {
fmt.Fprintf(cg.Body, "static constexpr ReflectTypeID _TYPE_ID = ReflectTypeID::%v;\n", theID)
}
// OutputClass yes
func (cg *CppGenerator) OutputClass(name string, cb func()) {
fmt.Fprintf(cg.Body, "class %v {\npublic:\n", name)
cb()
fmt.Fprintf(cg.Body, "};\n\n")
}
// OutputEnumClass
func (cg *CppGenerator) OutputEnumClass(name string, cb func()) {
fmt.Fprintf(cg.Body, "enum class %v {\n", name)
cb()
fmt.Fprintf(cg.Body, "};\n\n")
}
func (cg *CppGenerator) OutputArrayVariable(t string, name string, length int, cb func()) {
fmt.Fprintf(cg.Body, "%v %v[%d] = {\n", t, name, length)
cb()
fmt.Fprintf(cg.Body, "};\n\n")
}
func (cg *CppGenerator) OutputArrayVariableExtern(t string, name string, length int) {
fmt.Fprintf(cg.Body, "extern %v %v[%d];", t, name, length)
}
func (cg *CppGenerator) OutputEnumClassField(name string, value string) {
fmt.Fprintf(cg.Body, "%v", name)
if value != "" {
fmt.Fprintf(cg.Body, " = %v", value)
}
fmt.Fprintf(cg.Body, ",\n")
}
func (cg *CppGenerator) EscapeCppString(str string) string {
d, _ := json.Marshal(str)
return string(d)
}
func (cg *CppGenerator) WriteToWriter(w io.Writer) {
fmt.Fprintf(w, "// THIS CORNFILE IS GENERATED. DO NOT EDIT! 🌽\n")
guardString := "_"
for _, c := range []rune(cg.Filename) {
if unicode.IsUpper(c) {
guardString += "_"
}
if unicode.IsLetter(c) {
guardString += strings.ToUpper(string([]rune{c}))
}
}
if cg.IsHeader {
fmt.Fprintf(w, "#ifndef %v\n", guardString)
fmt.Fprintf(w, "#define %v\n", guardString)
}
for _, a := range cg.includes {
if strings.Contains(a, "<") {
fmt.Fprintf(w, "%v\n", a)
}
}
io.Copy(w, cg.BodyBeforeLocalIncludes)
for _, a := range cg.includes {
if !strings.Contains(a, "<") && a != fmt.Sprintf("#include \"%v\"", cg.Filename) {
fmt.Fprintf(w, "%v\n", a)
}
}
io.Copy(w, cg.Body)
if cg.IsHeader {
fmt.Fprintf(w, "#endif\n")
}
}
func (cg *CppGenerator) OutputToDirectory(dirPath string) {
f, _ := os.Create(path.Join(dirPath, cg.Filename))
defer f.Close()
cg.WriteToWriter(f)
for _, fileToOutput := range cg.files {
f, _ := os.Create(path.Join(dirPath, fileToOutput.Filename))
defer f.Close()
fileToOutput.WriteToWriter(f)
}
}