package service import ( "go/ast" ) type Class interface { Name() string String() string MethodsString() string AddMethod(*ast.FuncDecl) } var ( classDeclarations []Class isInMethod = false currentReceiverName = "" ) type class struct { name string baseInterface string Struct *ast.StructType methods []*ast.FuncDecl } func NewClass(name string) *class { return &class{name: name} } func (c *class) Name() string { return c.name } func (c *class) String() (code string) { c.checkForBaseInterface() code += c.classDefinitionToString() return } func (c *class) MethodsString() (code string) { code += c.methodImplementationsToString() return } func (c *class) classDefinitionToString() (code string) { code += "class " + c.name if len(c.baseInterface) > 0 { code += ": public " + c.baseInterface } code += " {\n" code += "public:\n" code += c.structToString() code += "\n" code += c.methodDeclarationsToString() code += "\n" code += "};\n" return } func (c *class) checkForBaseInterface() { if c.Struct.Fields.NumFields() == 0 { return } if len(c.Struct.Fields.List[0].Names) == 0 { return } n := c.Struct.Fields.List[0].Names[0] if n.Name != "_baseInterface" { return } i, ok := c.Struct.Fields.List[0].Type.(*ast.Ident) if !ok { return } c.baseInterface = i.Name return } func (c *class) structToString() (code string) { code += handleExpr(c.Struct) code += "\n" return } func (c *class) methodDeclarationsToString() (code string) { for _, m := range c.methods { code += c.methodDeclarationToString(m) } code += "\n" return } func (c *class) methodDeclarationToString(m *ast.FuncDecl) (code string) { code += " " code += handleFuncDeclType(m.Type) code += " " code += m.Name.String() + "(" code += handleFuncDeclParams(m.Type) code += ");" code += "\n" return } func (c *class) methodImplementationsToString() (code string) { for _, m := range c.methods { code += c.methodImplementationToString(m) } code += "\n" return } func (c *class) methodImplementationToString(m *ast.FuncDecl) (code string) { code += handleFuncDeclType(m.Type) code += " " code += c.name + "::" code += m.Name.String() + "(" code += handleFuncDeclParams(m.Type) code += ") {\n" if len(m.Recv.List) > 0 { n := m.Recv.List[0].Names if len(n) > 0 { isInMethod = true currentReceiverName = n[0].Name } } code += handleBlockStmt(m.Body) isInMethod = false code += "}\n" return } func (c *class) AddMethod(m *ast.FuncDecl) { c.methods = append(c.methods, m) } // Handlers func handleClass(name string, st *ast.StructType) string { addClassFromStructType(name, st) return "" } func addClassFromStructType(name string, s *ast.StructType) Class { c := createClass(name) c.Struct = s return c } func handleMethodDeclaration(fd *ast.FuncDecl) string { class := getOrCreateClassFromFuncDecl(fd) class.AddMethod(fd) return "" } func getOrCreateClassFromFuncDecl(fd *ast.FuncDecl) Class { n := getClassNameFromReceiver(fd.Recv) return getOrCreateClass(n) } func getClassNameFromReceiver(recv *ast.FieldList) string { for _, f := range recv.List { return getClassNameFromStarReceiver(f.Type) } return "" } func getClassNameFromStarReceiver(expr ast.Expr) string { switch e := expr.(type) { case *ast.StarExpr: return handleExpr(e.X) } return "" } func getOrCreateClass(className string) Class { for _, c := range classDeclarations { if c.Name() == className { return c } } return createClass(className) } func createClass(className string) *class { c := NewClass(className) addClassDeclaration(c) return c } func addClassDeclaration(c Class) { dlock.Lock() defer dlock.Unlock() classDeclarations = append(classDeclarations, c) }