Добавлена поддержка множества исходников

Этот коммит содержится в:
Softonik 2024-02-20 17:25:27 +03:00 коммит произвёл Nobody
родитель cd85400019
коммит ebd8a28d56
5 изменённых файлов: 131 добавлений и 67 удалений

Просмотреть файл

@ -3,6 +3,7 @@ package main
import (
"flag"
"fmt"
"io"
"my/go-translator/pkg/service"
"my/go-translator/pkg/service_python"
"os"
@ -14,30 +15,30 @@ const (
)
func main() {
mode, source, target, header_file, addArduinoH := getFlags()
checkFlagsAreValid(source)
safeTranspile(mode, source, target, header_file, addArduinoH)
mode, target, header_file, addArduinoH, sources := getFlags()
checkFlagsAreValid(sources)
safeTranspile(mode, sources, target, header_file, addArduinoH)
}
func getFlags() (int, string, string, string, bool) {
func getFlags() (int, string, string, bool, []string) {
pmode := flag.Bool("p", false, "Mode: C++ or Python")
target := flag.String("o", "", "Write to file instead of stdout")
header_file := flag.String("h", "", "Write headers to file also")
addArduinoH := flag.Bool("a", false, "Add Arduino.h")
flag.Parse()
source := flag.Arg(0)
target := flag.Arg(1)
sources := flag.Args()
mode := CPP_MODE
if *pmode {
mode = PYTHON_MODE
}
return mode, source, target, *header_file, *addArduinoH
return mode, *target, *header_file, *addArduinoH, sources
}
func checkFlagsAreValid(source string) {
if source == "" {
func checkFlagsAreValid(sources []string) {
if len(sources) == 0 {
printUsage()
os.Exit(1)
}
@ -49,21 +50,25 @@ func printUsage() {
flag.PrintDefaults()
fmt.Print("\n")
fmt.Print("Example:\n")
fmt.Printf("\tgo-tr [-a] [-h header.h] [-p] controller.go [output.cpp]\n\n")
fmt.Printf("\tgo-tr [-a] [-h header.h] [-o output.cpp] [-p] <input.go|input2.go|...>\n\n")
}
func safeTranspile(mode int, source, target, header_file string, addArduinoH bool) {
// Read the Golang source file.
in, err := os.Open(source)
if err != nil {
fmt.Fprintf(os.Stderr, "Go source file [%s] could not be opened! %v", source, err)
os.Exit(1)
func safeTranspile(mode int, sources []string, target, header_file string, addArduinoH bool) {
files := []io.Reader{}
var err error
for _, src := range sources {
in, err := os.Open(src)
if err != nil {
fmt.Fprintf(os.Stderr, "Go source file [%s] could not be opened! %v", src, err)
os.Exit(1)
}
defer in.Close()
files = append(files, in)
}
defer in.Close()
out := os.Stdout
if target != "" {
// Create the Arduino sketch file.
os.Remove(target)
out, err = os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_SYNC, 0644)
if err != nil {
@ -83,8 +88,7 @@ func safeTranspile(mode int, source, target, header_file string, addArduinoH boo
}
switch mode {
case CPP_MODE:
// Transpiles the Golang source into Arduino sketch.
service := service.NewService(in, out)
service := service.NewService(files, out)
service.SetHeaderWriter(header_f)
service.AddIncludeArduinoH(addArduinoH)
if err := service.Start(); err != nil {
@ -92,7 +96,7 @@ func safeTranspile(mode int, source, target, header_file string, addArduinoH boo
os.Exit(1)
}
case PYTHON_MODE:
service := service_python.NewService(in, out)
service := service_python.NewService(files[0], out)
if err := service.Start(); err != nil {
fmt.Fprintf(os.Stderr, "%v", err)
os.Exit(1)

24
pkg/service/features/multi_sources.feature Обычный файл
Просмотреть файл

@ -0,0 +1,24 @@
# Во имя Бога Милостивого, Милосердного!!!
# language: ru
Функциональность: Преобразование в C++: множество исходников
Сценарий: Два исходника
* Исходник:
```
package test
import "fmt"
func main() {}
```
* Исходник:
```
package test
import "fmt"
func other() {}
```
* Результат:
```
void main();
void other();
void main() {}
void other() {}
```

Просмотреть файл

@ -24,10 +24,7 @@ func InitializeScenario(ctx *godog.ScenarioContext) {
return ctx, nil
})
ctx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) {
if err == nil {
afterScenario()
}
afterScenario(err)
return ctx, nil
})
InitializeGomegaForGodog(ctx)

Просмотреть файл

@ -2,13 +2,13 @@ package service
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"io"
"sync"
)
// Service specifies the api logic of transforming a source code format into another target format.
type Service interface {
Start() error
SetHeaderWriter(io.Writer) error
@ -16,9 +16,7 @@ type Service interface {
}
const (
// ErrorWorkerReaderIsNil ...
ErrorWorkerReaderIsNil = "Reader should not be nil"
// ErrorWorkerWriterIsNil ...
ErrorWorkerWriterIsNil = "Writer should not be nil"
FunctionGoHelperPrefix = "__GoHelper_"
@ -30,20 +28,23 @@ var (
dlock sync.Mutex
)
// defaultService specifies the api logic of transforming a source code format into another target format.
type defaultService struct {
in io.Reader
in []io.Reader
out io.Writer
header io.Writer
decls []ast.Decl
addIncludeArduinoH bool
}
// NewService creates a a new transpile and returns its address.
func NewService(in io.Reader, out io.Writer) Service {
return &defaultService{
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 {
@ -59,7 +60,6 @@ func (s *defaultService) AddIncludeArduinoH(add bool) {
s.addIncludeArduinoH = add
}
// Start ...
func (s *defaultService) Start() error {
if s.in == nil {
return fmt.Errorf("Error: %s", ErrorWorkerReaderIsNil)
@ -67,25 +67,31 @@ func (s *defaultService) Start() error {
if s.out == nil {
return fmt.Errorf("Error: %s", ErrorWorkerWriterIsNil)
}
// Read tokens from file by using Go's parser.
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "source.go", s.in, 0)
err := s.parseFiles()
if err != nil {
return fmt.Errorf("ParseFile failed! %v", err)
}
// If source has no declarations then main it to an empty for loop.
if file.Decls == nil {
fmt.Fprint(s.out, "void loop() {}void setup() {}")
return nil
}
// Use Goroutines to work concurrently.
count := len(file.Decls)
done := make(chan bool, count)
dst := make([]chan string, count)
for i := 0; i < count; i++ {
dst[i] = make(chan string, 1)
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
@ -93,20 +99,49 @@ func (s *defaultService) Start() error {
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)
}
// Start a transpile with an individual channel for each declaration in the source file.
go func() {
for i, decl := range file.Decls {
for i, decl := range s.decls {
handleDecl(i, decl, dst[i], done)
}
}()
// Wait for all workers are 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()
@ -117,17 +152,14 @@ func (s *defaultService) Start() error {
s.printMethodImplementations()
s.printGoHelperDeclarations()
// Print the ordered result.
for i := 0; i < count; i++ {
for content := range dst[i] {
for i := 0; i < len(s.decls); i++ {
for content := range buf[i] {
s.out.Write([]byte(content))
}
}
s.out.Write([]byte("\n"))
// Print the AST.
// ast.Fprint(os.Stderr, fset, file, nil)
return nil
}

Просмотреть файл

@ -2,6 +2,7 @@ package service
import (
"bytes"
"io"
"strings"
. "my/go-translator/pkg/testgodoglib"
@ -11,7 +12,7 @@ import (
)
type testData struct {
src string
src []string
}
var (
@ -31,22 +32,28 @@ func afterSuite() {
func beforeScenario() {
resetTestData()
}
func afterScenario() {
func afterScenario(result error) {
}
// -----------------------
func исходник(src *godog.DocString) {
t.src = src.Content
t.src = append(t.src, src.Content)
}
func результат(out *godog.DocString) {
Compare_new(t.src, out.Content)
}
func Compare_new(source, expected string) {
var in, out bytes.Buffer
in.WriteString(source)
service := NewService(&in, &out)
func Compare_new(source []string, expected string) {
var in []io.Reader
var out bytes.Buffer
for _, s := range source {
b := &bytes.Buffer{}
b.WriteString(s)
in = append(in, b)
}
service := NewService(in, &out)
err := service.Start()
got := out.String()
tgot, texpected := trim_new(got), trim_new(expected)
@ -64,7 +71,7 @@ func trim_new(s string) string {
func Compare(source, expected string) {
var in, out bytes.Buffer
in.WriteString(source)
service := NewService(&in, &out)
service := NewService([]io.Reader{&in}, &out)
err := service.Start()
got := out.String()
tgot, texpected := Trim(got), Trim(expected)