From 5e7dec08df820bac82fefb8d84cd5402218661b9 Mon Sep 17 00:00:00 2001 From: Softonik Date: Mon, 22 Jan 2024 15:29:31 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D1=86=D0=B5=D0=BD=D0=B0=D1=80=D0=B8?= =?UTF-8?q?=D0=B9:=20=D0=A1=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80?= =?UTF-8?q?=D0=B0=20=D1=81=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/service/class.go | 144 +++++++++++++++++++++++++++++++ pkg/service/features/app.feature | 23 +++++ pkg/service/func.go | 6 ++ pkg/service/init_test.go | 2 + pkg/service/service.go | 15 ++++ pkg/service/type.go | 27 ++---- 6 files changed, 195 insertions(+), 22 deletions(-) create mode 100644 pkg/service/class.go diff --git a/pkg/service/class.go b/pkg/service/class.go new file mode 100644 index 0000000..c8d7a1a --- /dev/null +++ b/pkg/service/class.go @@ -0,0 +1,144 @@ +package service + +import ( + "go/ast" +) + +var ( + classDeclarations []*Class +) + +type Class struct { + Name string + Struct *ast.StructType + methods []*ast.FuncDecl +} + +func NewClass(className string) *Class { + return &Class{Name: className} +} + +func (c *Class) String() (code string) { + code += c.classDefinitionToString() + code += c.methodImplementationsToString() + return +} +func (c *Class) classDefinitionToString() (code string) { + code = "class " + c.Name + " {" + code += "public:\n" + + code += c.structToString() + code += "\n" + + code += c.methodDeclarationsToString() + code += "\n" + + code += "};\n" + 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 += "void " + m.Name.String() + "();" + 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 += "void " + code += c.Name + "::" + code += m.Name.String() + "(" + + code += ") {" + code += handleBlockStmt(m.Body) + code += "}" + + code += "\n" + return +} + +func (c *Class) AddMethod(m *ast.FuncDecl) { + c.methods = append(c.methods, m) +} + +// Handlers +func handleClass(t *ast.TypeSpec) string { + st, ok := t.Type.(*ast.StructType) + if !ok { + return "" + } + + addClassFromStructType(t.Name.String(), st) + + return "" +} +func addClassFromStructType(name string, s *ast.StructType) { + c := createClass(name) + c.Struct = s +} + +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) +} diff --git a/pkg/service/features/app.feature b/pkg/service/features/app.feature index 2c0b18d..6fd0dec 100644 --- a/pkg/service/features/app.feature +++ b/pkg/service/features/app.feature @@ -79,3 +79,26 @@ public: std::string c,d,e; }; ``` +@f + Сценарий: Структура с методом + * Исходник: +``` +package test + +type device struct { + a int +} + +func (d *device) doSomething() { +} +``` + * Результат: +``` +class device { +public: + int a; + void doSomething(); +}; +void device::doSomething() { +} +``` diff --git a/pkg/service/func.go b/pkg/service/func.go index def4724..4bfd40a 100644 --- a/pkg/service/func.go +++ b/pkg/service/func.go @@ -7,6 +7,12 @@ import ( func handleFuncDecl(decl ast.Decl) string { fd := decl.(*ast.FuncDecl) + if fd.Recv != nil { + return handleMethodDeclaration(fd) + } + return handleFunctionDeclaration(fd) +} +func handleFunctionDeclaration(fd *ast.FuncDecl) string { if shouldSkipFunction(fd.Type) { return "" } diff --git a/pkg/service/init_test.go b/pkg/service/init_test.go index f57fc8b..43b9720 100644 --- a/pkg/service/init_test.go +++ b/pkg/service/init_test.go @@ -11,6 +11,7 @@ import ( "github.com/cucumber/godog/colors" . "github.com/onsi/gomega" + gomega_format "github.com/onsi/gomega/format" ) func InitializeScenario(ctx *godog.ScenarioContext) { @@ -47,6 +48,7 @@ func TestMain(t *testing.T) { StopOnFailure: true, TestingT: t, } + gomega_format.CharactersAroundMismatchToInclude = 100 godog.BindCommandLineFlags("godog.", &opts) godog.TestSuite{ diff --git a/pkg/service/service.go b/pkg/service/service.go index 5f2afe1..b32606d 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -86,6 +86,7 @@ func (s *defaultService) Start() error { dst[i] = make(chan string, 1) } + classDeclarations = nil funcDeclarations = nil helpersForDeclarations = nil @@ -103,6 +104,7 @@ func (s *defaultService) Start() error { } s.printIncludeHeaders() + s.printClassDeclarations() s.printFunctionDeclarations() s.printGoHelperDeclarations() @@ -128,6 +130,19 @@ func (s *defaultService) printIncludeHeaders() { h := "#include \n\n" s.out.Write([]byte(h)) } +func (s *defaultService) printClassDeclarations() { + dlock.Lock() + defer dlock.Unlock() + + for _, c := range classDeclarations { + d := c.String() + s.out.Write([]byte(d + "\n")) + if s.header != nil { + s.header.Write([]byte(d + "\n")) + } + } + s.out.Write([]byte("\n")) +} func (s *defaultService) printFunctionDeclarations() { dlock.Lock() defer dlock.Unlock() diff --git a/pkg/service/type.go b/pkg/service/type.go index 06f9964..7cb0b17 100644 --- a/pkg/service/type.go +++ b/pkg/service/type.go @@ -4,31 +4,14 @@ import ( "go/ast" ) -func handleTypeSpec(spec ast.Spec) string { +func handleTypeSpec(spec ast.Spec) (code string) { s := spec.(*ast.TypeSpec) - code := "class" - code += " " - code += s.Name.String() - code += " " - code += "{\n" - code += handleClass(s.Type) - // spew.Dump(s.TypeParams) - code += "};\n" - return code + handleClass(s) + return } -func handleClass(e ast.Expr) string { - code := "" - code += "public:\n" - code += handleExpr(e) - // spew.Dump(e) - return code -} - -func handleStructType(s *ast.StructType) string { - code := "" - code += handleFieldList(s.Fields) - return code +func handleStructType(s *ast.StructType) (code string) { + return handleFieldList(s.Fields) } func handleFieldList(l *ast.FieldList) string {