Добавлена поддержка множества исходников
Этот коммит содержится в:
родитель
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
Обычный файл
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)
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче