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) } }