diff --git a/pkg/service/const.go b/pkg/service/const.go index 7c90939..5b48f47 100644 --- a/pkg/service/const.go +++ b/pkg/service/const.go @@ -21,8 +21,7 @@ func (c *Const) String() (code string) { func (c *Const) generate() (code string) { code += "const " - code += handleValueSpec(c.s) - code += ";" + code += handleLocalVariable(c.s) return } diff --git a/pkg/service/features/app.feature b/pkg/service/features/app.feature index e947668..33fa2dd 100644 --- a/pkg/service/features/app.feature +++ b/pkg/service/features/app.feature @@ -302,10 +302,10 @@ func main() { ``` * Результат: ``` +void main(); class device { public: }; -void main(); device *dev1,*dev2; void main() { dev1=new device(); @@ -333,11 +333,11 @@ func main() { ``` * Результат: ``` +Device* NewDevice(); +void main(); class Device { public: }; -Device* NewDevice(); -void main(); Device *dev1,*dev2; Device* NewDevice() { return new Device(); @@ -347,11 +347,21 @@ dev1=NewDevice(); } ``` - Сценарий: Последовательность блоков: константы, типы, абстрактные классы, классы, переменные, функции + Сценарий: Последовательность блоков: инклюды, константы, типы, абстрактные классы, классы, переменные, определения функций, функции * Исходник: ``` package test +import wifi "some/wifi" + +func someFunc() {} + +var a = 1 +var b = 1 + +type device struct {} +func (d *device) doSomething() {} + type Device interface { Name() string } @@ -362,10 +372,61 @@ const c1 = 4 ``` * Результат: ``` +#include + const int c1 = 4; + typedef int Mera; + +void someFunc(); + class Device { public: virtual std::string Name() = 0; }; + +class device { +public: + void doSomething(); +}; +void device::doSomething() { +} + +int a = 1; +int b = 1; + +void someFunc() { +} +``` + + Сценарий: Конвертация "while" в "for" + * Исходник: +``` +package test +import wifi "github.com/andygeiss/esp32/api/controller/wifi" +func Setup() { + serial.Begin(serial.BaudRate115200) + wifi.BeginEncrypted("SSID", "PASS") + for wifi.Status() != wifi.StatusConnected { + serial.Println("Connecting ...") + } + serial.Println("Connected!") +} +func Loop() {} +``` + * Результат: +``` +#include +void setup(); +void loop(); + +void setup() { +Serial.begin(115200); +WiFi.begin("SSID","PASS"); +while(WiFi.status()!=WL_CONNECTED) { +Serial.println("Connecting ..."); +} +Serial.println("Connected!"); +} +void loop() {} ``` diff --git a/pkg/service/features/includes.feature b/pkg/service/features/includes.feature new file mode 100644 index 0000000..ee21e13 --- /dev/null +++ b/pkg/service/features/includes.feature @@ -0,0 +1,40 @@ +# Во имя Бога Милостивого, Милосердного!!! +# language: ru +Функциональность: Преобразование в C++: инклюды + + Сценарий: Инклюд + * Исходник: +``` +package test +import wifi "github.com/andygeiss/esp32/api/controller/wifi" +var client wifi.Client +func Setup() {} +func Loop() { + serial.Print("Connecting to ") + serial.Println(host) + serial.Print(" ...") + if (client.Connect(host, 443) == true) { + serial.Println(" Connected!") + } else { + serial.Println(" Failed!") + } +} +``` + * Результат: +``` +#include +void setup(); +void loop(); +WiFiClient client; +void setup() {} +void loop() { +Serial.print("Connecting to "); +Serial.println(host); +Serial.print(" ..."); +if (client.connect(host,443)==true) { + Serial.println(" Connected!"); + } else { + Serial.println(" Failed!"); + } +} +``` diff --git a/pkg/service/features/variables.feature b/pkg/service/features/variables.feature index afd844c..98fd5e4 100644 --- a/pkg/service/features/variables.feature +++ b/pkg/service/features/variables.feature @@ -71,4 +71,20 @@ type GPIOS [GPIO_count]bool ``` typedef int Mera; typedef bool GPIOS[GPIO_count]; +``` + + Сценарий: Переменные в функциях + * Исходник: +``` +package test +func foo() { + var foo string = "bar" +} +``` + * Результат: +``` +void foo(); +void foo() { +std::string foo = "bar"; +} ``` diff --git a/pkg/service/func.go b/pkg/service/func.go index fc00abd..5884a07 100644 --- a/pkg/service/func.go +++ b/pkg/service/func.go @@ -1,11 +1,32 @@ package service import ( + "fmt" "go/ast" "strings" ) +var ( + inFunctionDepth = 0 +) + +func incInFunctionDepth() { + inFunctionDepth++ +} +func decInFunctionDepth() { + inFunctionDepth-- + if inFunctionDepth < 0 { + panic(fmt.Sprintf("inFunctionDepth: %v", inFunctionDepth)) + } +} +func IsInFunction() bool { + return inFunctionDepth > 0 +} + func handleFuncDecl(decl ast.Decl) string { + incInFunctionDepth() + defer decInFunctionDepth() + fd := decl.(*ast.FuncDecl) if fd.Recv != nil { return handleMethodDeclaration(fd) diff --git a/pkg/service/includes.go b/pkg/service/includes.go new file mode 100644 index 0000000..3cc7284 --- /dev/null +++ b/pkg/service/includes.go @@ -0,0 +1,46 @@ +package service + +import ( + "go/ast" +) + +var ( + includeDeclarations []*Include +) + +type Include struct { + i *ast.ImportSpec +} + +func NewInclude(i *ast.ImportSpec) *Include { + return &Include{i: i} +} + +func (i *Include) String() (code string) { + code += i.genString(i.i) + return +} + +func (i *Include) genString(s *ast.ImportSpec) (code string) { + if s.Name != nil { + name := handleIdentExpr(s.Name) + if val, ok := mapping[name]; ok { + name = val + } + if name != "" { + if name != "controller" { + code = "#include <" + name + ".h>\n" + } + } + } + return +} + +func handleImportSpec(s *ast.ImportSpec) (code string) { + addInclude(s) + return +} +func addInclude(s *ast.ImportSpec) { + c := NewInclude(s) + includeDeclarations = append(includeDeclarations, c) +} diff --git a/pkg/service/service.go b/pkg/service/service.go index ccbd72b..b42103f 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -86,10 +86,12 @@ func (s *defaultService) Start() error { dst[i] = make(chan string, 1) } + includeDeclarations = nil constDeclarations = nil typeDeclarations = nil abstractClassDeclarations = nil classDeclarations = nil + variableDeclarations = nil funcDeclarations = nil helpersForDeclarations = nil @@ -106,12 +108,14 @@ func (s *defaultService) Start() error { } } - s.printIncludeHeaders() + s.printIncludeAdruinoHeader() + s.printIncludes() s.printConstDeclarations() s.printTypeDeclarations() + s.printFunctionDeclarations() s.printAbstractClassDeclarations() s.printClassDeclarations() - s.printFunctionDeclarations() + s.printVariableDeclarations() s.printGoHelperDeclarations() // Print the ordered result. @@ -128,7 +132,7 @@ func (s *defaultService) Start() error { return nil } -func (s *defaultService) printIncludeHeaders() { +func (s *defaultService) printIncludeAdruinoHeader() { if !s.addIncludeArduinoH { return } @@ -136,6 +140,19 @@ func (s *defaultService) printIncludeHeaders() { h := "#include \n\n" s.out.Write([]byte(h)) } +func (s *defaultService) printIncludes() { + dlock.Lock() + defer dlock.Unlock() + + for _, c := range includeDeclarations { + 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) printConstDeclarations() { dlock.Lock() defer dlock.Unlock() @@ -162,6 +179,18 @@ func (s *defaultService) printTypeDeclarations() { } s.out.Write([]byte("\n")) } +func (s *defaultService) printFunctionDeclarations() { + dlock.Lock() + defer dlock.Unlock() + + for _, f := range funcDeclarations { + s.out.Write([]byte(f + "\n")) + if s.header != nil { + s.header.Write([]byte(f + "\n")) + } + } + s.out.Write([]byte("\n")) +} func (s *defaultService) printAbstractClassDeclarations() { dlock.Lock() defer dlock.Unlock() @@ -188,14 +217,15 @@ func (s *defaultService) printClassDeclarations() { } s.out.Write([]byte("\n")) } -func (s *defaultService) printFunctionDeclarations() { +func (s *defaultService) printVariableDeclarations() { dlock.Lock() defer dlock.Unlock() - for _, f := range funcDeclarations { - s.out.Write([]byte(f + "\n")) + for _, c := range variableDeclarations { + d := c.String() + s.out.Write([]byte(d + "\n")) if s.header != nil { - s.header.Write([]byte(f + "\n")) + s.header.Write([]byte(d + "\n")) } } s.out.Write([]byte("\n")) diff --git a/pkg/service/service_ginkgo_test.go b/pkg/service/service_ginkgo_test.go index 2319f9f..64ff353 100644 --- a/pkg/service/service_ginkgo_test.go +++ b/pkg/service/service_ginkgo_test.go @@ -90,22 +90,6 @@ var _ = Describe("Go Translator", func() { Compare(source, expected) }) - It("Function_With_Var_String_Declaration", func() { - source := `package test - func foo() { - var foo string = "bar" - } - ` - expected := ` - void foo(); - - void foo() { - std::string foo = "bar"; - } - ` - Compare(source, expected) - }) - It("Function_With_Function_Call", func() { source := `package test func foo() { @@ -497,73 +481,6 @@ var _ = Describe("Go Translator", func() { ` Compare(source, expected) }) - - It("ForLoop_WithoutInit_And_Post_Transpiles_To_While", func() { - source := `package test - import wifi "github.com/andygeiss/esp32/api/controller/wifi" - func Setup() { - serial.Begin(serial.BaudRate115200) - wifi.BeginEncrypted("SSID", "PASS") - for wifi.Status() != wifi.StatusConnected { - serial.Println("Connecting ...") - } - serial.Println("Connected!") - } - func Loop() {} - ` - expected := ` - void setup(); - void loop(); - - #include - void setup() { - Serial.begin(115200); - WiFi.begin("SSID","PASS"); - while(WiFi.status()!=WL_CONNECTED){ - Serial.println("Connecting..."); - } - Serial.println("Connected!"); - } - void loop() {} - ` - Compare(source, expected) - }) - - It("WiFiWebClient", func() { - source := `package test - import wifi "github.com/andygeiss/esp32/api/controller/wifi" - var client wifi.Client - func Setup() {} - func Loop() { - serial.Print("Connecting to ") - serial.Println(host) - serial.Print(" ...") - if (client.Connect(host, 443) == true) { - serial.Println(" Connected!") - } else { - serial.Println(" Failed!") - } - } - ` - expected := ` - void setup(); - void loop(); - - #include - WiFiClient client; - voidsetup(){} - voidloop(){ - Serial.print("Connecting to"); - Serial.println(host); - Serial.print(" ..."); - if(client.connect(host, 443) == true){ - Serial.println(" Connected!"); - } else { - Serial.println(" Failed!"); - } - }` - Compare(source, expected) - }) }) Describe("Arduino", func() { diff --git a/pkg/service/spec.go b/pkg/service/spec.go index a008276..171d5f7 100644 --- a/pkg/service/spec.go +++ b/pkg/service/spec.go @@ -32,9 +32,9 @@ func handleSpecsVariables(specs []ast.Spec) (code string) { for _, spec := range specs { switch s := spec.(type) { case *ast.ImportSpec: - code += handleImportSpec(spec) + code += handleImportSpec(s) case *ast.ValueSpec: - code += handleValueSpec(s) + ";" + code += handleGlobalOrLocalVariable(s) case *ast.TypeSpec: code += handleTypeSpec(s) } @@ -42,19 +42,10 @@ func handleSpecsVariables(specs []ast.Spec) (code string) { return } -func handleImportSpec(spec ast.Spec) string { - s := spec.(*ast.ImportSpec) - code := "" - if s.Name != nil { - name := handleIdentExpr(s.Name) - if val, ok := mapping[name]; ok { - name = val - } - if name != "" { - if name != "controller" { - code = "#include <" + name + ".h>\n" - } - } +func handleGlobalOrLocalVariable(s *ast.ValueSpec) (code string) { + if IsInFunction() { + return handleLocalVariable(s) } - return code + + return handleGlobalVariable(s) } diff --git a/pkg/service/value.go b/pkg/service/value.go index 84a7b12..8b5b146 100644 --- a/pkg/service/value.go +++ b/pkg/service/value.go @@ -4,37 +4,6 @@ import ( "go/ast" ) -func handleValueSpec(s *ast.ValueSpec) (code string) { - if s.Type == nil { - code += addTypeByValue(s) - } - - code += handleValueSpecType(s.Type) - code += " " - - _, ok := s.Type.(*ast.StarExpr) - if ok { - isPointerType = true - } - code += handleValueSpecNames(s.Names) - isPointerType = false - - if s.Values != nil { - code += " = " - code += handleValueSpecValues(s.Values) - } - - l, ok := s.Type.(*ast.ArrayType) - if ok { - code += "[" - if l.Len != nil { - code += handleExpr(l.Len) - } - code += "]" - } - return code -} - func addTypeByValue(s *ast.ValueSpec) (code string) { if len(s.Values) == 0 { return diff --git a/pkg/service/variables.go b/pkg/service/variables.go new file mode 100644 index 0000000..7a4c3ee --- /dev/null +++ b/pkg/service/variables.go @@ -0,0 +1,93 @@ +package service + +import "go/ast" + +var ( + variableDeclarations []*Variable +) + +type Variable struct { + s *ast.ValueSpec +} + +func NewVariable(s *ast.ValueSpec) *Variable { + return &Variable{s: s} +} + +func (c *Variable) String() (code string) { + code += c.genString(c.s) + return +} + +func (c *Variable) genString(s *ast.ValueSpec) (code string) { + if s.Type == nil { + code += addTypeByValue(s) + } + + code += handleValueSpecType(s.Type) + code += " " + + _, ok := s.Type.(*ast.StarExpr) + if ok { + isPointerType = true + } + code += handleValueSpecNames(s.Names) + isPointerType = false + + if s.Values != nil { + code += " = " + code += handleValueSpecValues(s.Values) + } + + l, ok := s.Type.(*ast.ArrayType) + if ok { + code += "[" + if l.Len != nil { + code += handleExpr(l.Len) + } + code += "]" + } + code += ";" + return +} + +func handleLocalVariable(s *ast.ValueSpec) (code string) { + if s.Type == nil { + code += addTypeByValue(s) + } + + code += handleValueSpecType(s.Type) + code += " " + + _, ok := s.Type.(*ast.StarExpr) + if ok { + isPointerType = true + } + code += handleValueSpecNames(s.Names) + isPointerType = false + + if s.Values != nil { + code += " = " + code += handleValueSpecValues(s.Values) + } + + l, ok := s.Type.(*ast.ArrayType) + if ok { + code += "[" + if l.Len != nil { + code += handleExpr(l.Len) + } + code += "]" + } + code += ";" + return code +} + +func handleGlobalVariable(s *ast.ValueSpec) (code string) { + addVariable(s) + return +} +func addVariable(s *ast.ValueSpec) { + c := NewVariable(s) + variableDeclarations = append(variableDeclarations, c) +}