go-translator/pkg/service/service.go

274 строки
5,3 КиБ
Go

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 <Arduino.h>\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"))
}