diff --git a/pkg/service/class.go b/pkg/service/class.go index 00eb16a..50bbea3 100644 --- a/pkg/service/class.go +++ b/pkg/service/class.go @@ -4,30 +4,40 @@ import ( "go/ast" ) +type Class interface { + Name() string + String() string + AddMethod(*ast.FuncDecl) +} + var ( - classDeclarations []*Class + classDeclarations []Class isInMethod = false currentReceiverName = "" ) -type Class struct { - Name string +type class struct { + name string Struct *ast.StructType methods []*ast.FuncDecl } -func NewClass(className string) *Class { - return &Class{Name: className} +func NewClass(name string) *class { + return &class{name: name} } -func (c *Class) String() (code string) { +func (c *class) Name() string { + return c.name +} + +func (c *class) String() (code string) { code += c.classDefinitionToString() code += c.methodImplementationsToString() return } -func (c *Class) classDefinitionToString() (code string) { - code = "class " + c.Name + " {" +func (c *class) classDefinitionToString() (code string) { + code = "class " + c.name + " {" code += "public:\n" code += c.structToString() @@ -39,19 +49,19 @@ func (c *Class) classDefinitionToString() (code string) { code += "};\n" return } -func (c *Class) structToString() (code string) { +func (c *class) structToString() (code string) { code += handleExpr(c.Struct) code += "\n" return } -func (c *Class) methodDeclarationsToString() (code string) { +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) { +func (c *class) methodDeclarationToString(m *ast.FuncDecl) (code string) { code += " " code += handleFuncDeclType(m.Type) code += " " @@ -62,7 +72,7 @@ func (c *Class) methodDeclarationToString(m *ast.FuncDecl) (code string) { return } -func (c *Class) methodImplementationsToString() (code string) { +func (c *class) methodImplementationsToString() (code string) { for _, m := range c.methods { code += c.methodImplementationToString(m) } @@ -70,10 +80,10 @@ func (c *Class) methodImplementationsToString() (code string) { return } -func (c *Class) methodImplementationToString(m *ast.FuncDecl) (code string) { +func (c *class) methodImplementationToString(m *ast.FuncDecl) (code string) { code += handleFuncDeclType(m.Type) code += " " - code += c.Name + "::" + code += c.name + "::" code += m.Name.String() + "(" code += handleFuncDeclParams(m.Type) code += ") {" @@ -92,7 +102,7 @@ func (c *Class) methodImplementationToString(m *ast.FuncDecl) (code string) { return } -func (c *Class) AddMethod(m *ast.FuncDecl) { +func (c *class) AddMethod(m *ast.FuncDecl) { c.methods = append(c.methods, m) } @@ -101,9 +111,10 @@ func handleClass(name string, st *ast.StructType) string { addClassFromStructType(name, st) return "" } -func addClassFromStructType(name string, s *ast.StructType) { +func addClassFromStructType(name string, s *ast.StructType) Class { c := createClass(name) c.Struct = s + return c } func handleMethodDeclaration(fd *ast.FuncDecl) string { @@ -112,7 +123,7 @@ func handleMethodDeclaration(fd *ast.FuncDecl) string { return "" } -func getOrCreateClassFromFuncDecl(fd *ast.FuncDecl) *Class { +func getOrCreateClassFromFuncDecl(fd *ast.FuncDecl) Class { n := getClassNameFromReceiver(fd.Recv) return getOrCreateClass(n) } @@ -131,9 +142,9 @@ func getClassNameFromStarReceiver(expr ast.Expr) string { return "" } -func getOrCreateClass(className string) *Class { +func getOrCreateClass(className string) Class { for _, c := range classDeclarations { - if c.Name == className { + if c.Name() == className { return c } } @@ -141,13 +152,13 @@ func getOrCreateClass(className string) *Class { return createClass(className) } -func createClass(className string) *Class { +func createClass(className string) *class { c := NewClass(className) addClassDeclaration(c) return c } -func addClassDeclaration(c *Class) { +func addClassDeclaration(c Class) { dlock.Lock() defer dlock.Unlock() diff --git a/pkg/service/class_abstract.go b/pkg/service/class_abstract.go new file mode 100644 index 0000000..04c6a92 --- /dev/null +++ b/pkg/service/class_abstract.go @@ -0,0 +1,87 @@ +package service + +import ( + "go/ast" + "strings" +) + +type abstractClass struct { + name string + Interface *ast.InterfaceType +} + +func NewAbstractClass(name string) *abstractClass { + return &abstractClass{name: name} +} + +func (c *abstractClass) Name() string { + return c.name +} + +func (c *abstractClass) String() (code string) { + code += c.abstractClassDefinitionToString() + return +} +func (c *abstractClass) abstractClassDefinitionToString() (code string) { + code = "class " + c.name + " {" + code += "public:\n" + + code += c.methodDeclarationsToString() + code += "\n" + + code += "};\n" + return +} +func (c *abstractClass) methodDeclarationsToString() (code string) { + for _, f := range c.Interface.Methods.List { + code += c.fieldDeclarationToString(f) + } + code += "\n" + return +} +func (c *abstractClass) fieldDeclarationToString(f *ast.Field) (code string) { + code += " virtual " + switch s := f.Type.(type) { + case *ast.FuncType: + code += handleFuncDeclType(s) + code += " " + code += handleIdentExpr(f.Names[0]) + code += "(" + code += handleAbstractFuncDeclParams(s) + code += ") = 0;" + } + + return +} +func handleAbstractFuncDeclParams(t *ast.FuncType) (code string) { + if t.Params == nil || t.Params.List == nil { + return + } + values := make([]string, 0) + for _, field := range t.Params.List { + switch ft := field.Type.(type) { + case *ast.Ident: + t := handleIdentExpr(ft) + values = append(values, t) + } + } + code += strings.Join(values, ",") + return +} + +func (c *abstractClass) AddMethod(m *ast.FuncDecl) {} + +func handleClassAbstract(name string, it *ast.InterfaceType) string { + addAbstractClassFromStructType(name, it) + return "" +} +func addAbstractClassFromStructType(name string, it *ast.InterfaceType) Class { + c := createAbstractClass(name) + c.Interface = it + return c +} +func createAbstractClass(className string) *abstractClass { + c := NewAbstractClass(className) + addClassDeclaration(c) + return c +} diff --git a/pkg/service/expr.go b/pkg/service/expr.go index 6db9db7..193a8a8 100644 --- a/pkg/service/expr.go +++ b/pkg/service/expr.go @@ -25,6 +25,8 @@ func handleExpr(expr ast.Expr) string { code += handleSelectorExpr(e) case *ast.StructType: code += handleStructType(e) + case *ast.InterfaceType: + code += handleInterfaceType(e) case *ast.ArrayType: code += handleArray(e) } @@ -54,7 +56,7 @@ func handleUnaryExpr(expr *ast.UnaryExpr) (code string) { cl, ok := expr.X.(*ast.CompositeLit) if ok { code += "new " - code += handleIdentExpr(cl.Type) + code += handleIdentExpr(cl.Type.(*ast.Ident)) code += "()" } else { code += expr.Op.String() @@ -71,8 +73,8 @@ func handleBinaryExpr(expr ast.Expr) string { return code } -func handleCallExpr(expr *ast.CallExpr) string { - code := handleExpr(expr.Fun) +func handleCallExpr(expr *ast.CallExpr) (code string) { + code = handleExpr(expr.Fun) code += "(" args := make([]string, 0) for _, arg := range expr.Args { @@ -80,11 +82,10 @@ func handleCallExpr(expr *ast.CallExpr) string { } code += strings.Join(args, ",") code += ")" - return code + return } -func handleIdentExpr(expr ast.Expr) string { - ident := expr.(*ast.Ident) +func handleIdentExpr(ident *ast.Ident) string { code := "" switch ident.Name { case "nil": diff --git a/pkg/service/features/app.feature b/pkg/service/features/app.feature index c70f7df..82d1f53 100644 --- a/pkg/service/features/app.feature +++ b/pkg/service/features/app.feature @@ -25,6 +25,29 @@ type device struct {} class device { public: }; +``` + + Сценарий: Интерфейс - это класс с виртуальными методами + * Исходник: +``` +package test + +type Device interface { + Name() string + String() string + Add(int) + Add2(int,float64) +} +``` + * Результат: +``` +class Device { +public: + virtual std::string Name() = 0; + virtual std::string String() = 0; + virtual void Add(int) = 0; + virtual void Add2(int,double) = 0; +}; ``` Сценарий: Структура с полем diff --git a/pkg/service/type.go b/pkg/service/type.go index 6abb243..7b5d697 100644 --- a/pkg/service/type.go +++ b/pkg/service/type.go @@ -9,9 +9,11 @@ var ( ) func handleTypeSpec(s *ast.TypeSpec) (code string) { - st, ok := s.Type.(*ast.StructType) - if ok { - return handleClass(s.Name.String(), st) + switch t := s.Type.(type) { + case *ast.StructType: + return handleClass(s.Name.String(), t) + case *ast.InterfaceType: + return handleClassAbstract(s.Name.String(), t) } return handleType(s) @@ -48,6 +50,10 @@ func handleStructType(s *ast.StructType) (code string) { return handleFieldList(s.Fields) } +func handleInterfaceType(s *ast.InterfaceType) (code string) { + return handleFieldList(s.Methods) +} + func handleFieldList(l *ast.FieldList) string { code := "" for _, f := range l.List { @@ -56,10 +62,16 @@ func handleFieldList(l *ast.FieldList) string { return code } -func handleField(f *ast.Field) string { - code := "" +func handleField(f *ast.Field) (code string) { code += " " - code += handleIdentExpr(f.Type) + + switch t := f.Type.(type) { + case *ast.Ident: + code += handleIdentExpr(t) + case *ast.FuncType: + code += handleFuncDeclType(t) + } + code += " " nado_zapyatuyu := false for _, n := range f.Names { @@ -70,5 +82,5 @@ func handleField(f *ast.Field) string { nado_zapyatuyu = true } code += ";\n" - return code + return }