package service import ( "fmt" "go/ast" "go/parser" "go/token" "io" "sync" ) type Service interface { Start() error SetHeaderWriter(io.Writer) error AddIncludeArduinoH(bool) } const ( ErrorWorkerReaderIsNil = "Reader should not be nil" ErrorWorkerWriterIsNil = "Writer should not be nil" FunctionGoHelperPrefix = "__GoHelper_" ) var ( funcDeclarations []string helpersForDeclarations []string dlock sync.Mutex ) type defaultService struct { in []io.Reader out io.Writer header io.Writer decls []ast.Decl addIncludeArduinoH bool } func NewService(in []io.Reader, out io.Writer) Service { s := &defaultService{ in: in, out: out, } s.initResults() return s } func (s *defaultService) SetHeaderWriter(w io.Writer) error { if w == nil { return fmt.Errorf("Empty") } s.header = w return nil } func (s *defaultService) AddIncludeArduinoH(add bool) { s.addIncludeArduinoH = add } func (s *defaultService) Start() error { if s.in == nil { return fmt.Errorf("Error: %s", ErrorWorkerReaderIsNil) } if s.out == nil { return fmt.Errorf("Error: %s", ErrorWorkerWriterIsNil) } err := s.parseFiles() if err != nil { return err } return s.generate() } func (s *defaultService) generate() error { dst := s.generateStructs() return s.printResult(dst) } func (s *defaultService) parseFiles() error { for _, in := range s.in { err := s.parseFile(in) if err != nil { return err } } return nil } func (*defaultService) initResults() { includeDeclarations = nil constDeclarations = nil typeDeclarations = nil classDeclarations = nil variableDeclarations = nil funcDeclarations = nil helpersForDeclarations = nil } func (s *defaultService) parseFile(in io.Reader) error { fset := token.NewFileSet() file, err := parser.ParseFile(fset, "virt_input.go", in, 0) if err != nil { return nil } // Debug the AST // ast.Fprint(os.Stderr, fset, file, nil) if file.Decls == nil { fmt.Fprint(s.out, "void loop() {}void setup() {}") return nil } s.decls = append(s.decls, file.Decls...) return nil } func (s *defaultService) generateStructs() []chan string { count := len(s.decls) done := make(chan bool, count) dst := make([]chan string, count) for i := 0; i < count; i++ { dst[i] = make(chan string, 1) } go func() { for i, decl := range s.decls { handleDecl(i, decl, dst[i], done) } }() for i := 0; i < count; i++ { select { case <-done: } } return dst } func (s *defaultService) printResult(buf []chan string) error { s.printIncludeAdruinoHeader() s.printIncludes() s.printConstDeclarations() s.printTypeDeclarations() s.printClassDeclarations() s.printFunctionDeclarations() s.printVariableDeclarations() s.printMethodImplementations() s.printGoHelperDeclarations() for i := 0; i < len(s.decls); i++ { for content := range buf[i] { s.out.Write([]byte(content)) } } s.out.Write([]byte("\n")) return nil } func (s *defaultService) printIncludeAdruinoHeader() { if !s.addIncludeArduinoH { return } 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() for _, c := range constDeclarations { 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) printTypeDeclarations() { dlock.Lock() defer dlock.Unlock() for _, c := range typeDeclarations { 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) 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() 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) printVariableDeclarations() { dlock.Lock() defer dlock.Unlock() for _, c := range variableDeclarations { 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) printMethodImplementations() { dlock.Lock() defer dlock.Unlock() for _, c := range classDeclarations { d := c.MethodsString() s.out.Write([]byte(d + "\n")) if s.header != nil { s.header.Write([]byte(d + "\n")) } } s.out.Write([]byte("\n")) } func (s *defaultService) printGoHelperDeclarations() { dlock.Lock() defer dlock.Unlock() for _, f := range helpersForDeclarations { helper := fmt.Sprintf(`void %v%v(void*) { %v(); vTaskDelete(NULL); }`, FunctionGoHelperPrefix, f, f) s.out.Write([]byte(helper + "\n")) } s.out.Write([]byte("\n")) }