Добавлена поддержка множества исходников
Этот коммит содержится в:
родитель
cd85400019
коммит
ebd8a28d56
5 изменённых файлов: 131 добавлений и 67 удалений
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"my/go-translator/pkg/service"
|
"my/go-translator/pkg/service"
|
||||||
"my/go-translator/pkg/service_python"
|
"my/go-translator/pkg/service_python"
|
||||||
"os"
|
"os"
|
||||||
|
@ -14,30 +15,30 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
mode, source, target, header_file, addArduinoH := getFlags()
|
mode, target, header_file, addArduinoH, sources := getFlags()
|
||||||
checkFlagsAreValid(source)
|
checkFlagsAreValid(sources)
|
||||||
safeTranspile(mode, source, target, header_file, addArduinoH)
|
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")
|
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")
|
header_file := flag.String("h", "", "Write headers to file also")
|
||||||
addArduinoH := flag.Bool("a", false, "Add Arduino.h")
|
addArduinoH := flag.Bool("a", false, "Add Arduino.h")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
source := flag.Arg(0)
|
sources := flag.Args()
|
||||||
target := flag.Arg(1)
|
|
||||||
|
|
||||||
mode := CPP_MODE
|
mode := CPP_MODE
|
||||||
if *pmode {
|
if *pmode {
|
||||||
mode = PYTHON_MODE
|
mode = PYTHON_MODE
|
||||||
}
|
}
|
||||||
|
|
||||||
return mode, source, target, *header_file, *addArduinoH
|
return mode, *target, *header_file, *addArduinoH, sources
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkFlagsAreValid(source string) {
|
func checkFlagsAreValid(sources []string) {
|
||||||
if source == "" {
|
if len(sources) == 0 {
|
||||||
printUsage()
|
printUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
@ -49,21 +50,25 @@ func printUsage() {
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
fmt.Print("\n")
|
fmt.Print("\n")
|
||||||
fmt.Print("Example:\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) {
|
func safeTranspile(mode int, sources []string, target, header_file string, addArduinoH bool) {
|
||||||
// Read the Golang source file.
|
files := []io.Reader{}
|
||||||
in, err := os.Open(source)
|
var err error
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Go source file [%s] could not be opened! %v", source, err)
|
for _, src := range sources {
|
||||||
os.Exit(1)
|
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
|
out := os.Stdout
|
||||||
if target != "" {
|
if target != "" {
|
||||||
// Create the Arduino sketch file.
|
|
||||||
os.Remove(target)
|
os.Remove(target)
|
||||||
out, err = os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_SYNC, 0644)
|
out, err = os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_SYNC, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -83,8 +88,7 @@ func safeTranspile(mode int, source, target, header_file string, addArduinoH boo
|
||||||
}
|
}
|
||||||
switch mode {
|
switch mode {
|
||||||
case CPP_MODE:
|
case CPP_MODE:
|
||||||
// Transpiles the Golang source into Arduino sketch.
|
service := service.NewService(files, out)
|
||||||
service := service.NewService(in, out)
|
|
||||||
service.SetHeaderWriter(header_f)
|
service.SetHeaderWriter(header_f)
|
||||||
service.AddIncludeArduinoH(addArduinoH)
|
service.AddIncludeArduinoH(addArduinoH)
|
||||||
if err := service.Start(); err != nil {
|
if err := service.Start(); err != nil {
|
||||||
|
@ -92,7 +96,7 @@ func safeTranspile(mode int, source, target, header_file string, addArduinoH boo
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
case PYTHON_MODE:
|
case PYTHON_MODE:
|
||||||
service := service_python.NewService(in, out)
|
service := service_python.NewService(files[0], out)
|
||||||
if err := service.Start(); err != nil {
|
if err := service.Start(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%v", err)
|
fmt.Fprintf(os.Stderr, "%v", err)
|
||||||
os.Exit(1)
|
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
|
return ctx, nil
|
||||||
})
|
})
|
||||||
ctx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) {
|
ctx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) {
|
||||||
if err == nil {
|
afterScenario(err)
|
||||||
afterScenario()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx, nil
|
return ctx, nil
|
||||||
})
|
})
|
||||||
InitializeGomegaForGodog(ctx)
|
InitializeGomegaForGodog(ctx)
|
||||||
|
|
|
@ -2,13 +2,13 @@ package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Service specifies the api logic of transforming a source code format into another target format.
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
Start() error
|
Start() error
|
||||||
SetHeaderWriter(io.Writer) error
|
SetHeaderWriter(io.Writer) error
|
||||||
|
@ -16,9 +16,7 @@ type Service interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ErrorWorkerReaderIsNil ...
|
|
||||||
ErrorWorkerReaderIsNil = "Reader should not be nil"
|
ErrorWorkerReaderIsNil = "Reader should not be nil"
|
||||||
// ErrorWorkerWriterIsNil ...
|
|
||||||
ErrorWorkerWriterIsNil = "Writer should not be nil"
|
ErrorWorkerWriterIsNil = "Writer should not be nil"
|
||||||
|
|
||||||
FunctionGoHelperPrefix = "__GoHelper_"
|
FunctionGoHelperPrefix = "__GoHelper_"
|
||||||
|
@ -30,20 +28,23 @@ var (
|
||||||
dlock sync.Mutex
|
dlock sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
// defaultService specifies the api logic of transforming a source code format into another target format.
|
|
||||||
type defaultService struct {
|
type defaultService struct {
|
||||||
in io.Reader
|
in []io.Reader
|
||||||
out io.Writer
|
out io.Writer
|
||||||
header io.Writer
|
header io.Writer
|
||||||
|
decls []ast.Decl
|
||||||
addIncludeArduinoH bool
|
addIncludeArduinoH bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewService creates a a new transpile and returns its address.
|
func NewService(in []io.Reader, out io.Writer) Service {
|
||||||
func NewService(in io.Reader, out io.Writer) Service {
|
s := &defaultService{
|
||||||
return &defaultService{
|
|
||||||
in: in,
|
in: in,
|
||||||
out: out,
|
out: out,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.initResults()
|
||||||
|
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *defaultService) SetHeaderWriter(w io.Writer) error {
|
func (s *defaultService) SetHeaderWriter(w io.Writer) error {
|
||||||
|
@ -59,7 +60,6 @@ func (s *defaultService) AddIncludeArduinoH(add bool) {
|
||||||
s.addIncludeArduinoH = add
|
s.addIncludeArduinoH = add
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start ...
|
|
||||||
func (s *defaultService) Start() error {
|
func (s *defaultService) Start() error {
|
||||||
if s.in == nil {
|
if s.in == nil {
|
||||||
return fmt.Errorf("Error: %s", ErrorWorkerReaderIsNil)
|
return fmt.Errorf("Error: %s", ErrorWorkerReaderIsNil)
|
||||||
|
@ -67,25 +67,31 @@ func (s *defaultService) Start() error {
|
||||||
if s.out == nil {
|
if s.out == nil {
|
||||||
return fmt.Errorf("Error: %s", ErrorWorkerWriterIsNil)
|
return fmt.Errorf("Error: %s", ErrorWorkerWriterIsNil)
|
||||||
}
|
}
|
||||||
// Read tokens from file by using Go's parser.
|
|
||||||
fset := token.NewFileSet()
|
err := s.parseFiles()
|
||||||
file, err := parser.ParseFile(fset, "source.go", s.in, 0)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("ParseFile failed! %v", err)
|
return 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 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
|
includeDeclarations = nil
|
||||||
constDeclarations = nil
|
constDeclarations = nil
|
||||||
typeDeclarations = nil
|
typeDeclarations = nil
|
||||||
|
@ -93,20 +99,49 @@ func (s *defaultService) Start() error {
|
||||||
variableDeclarations = nil
|
variableDeclarations = nil
|
||||||
funcDeclarations = nil
|
funcDeclarations = nil
|
||||||
helpersForDeclarations = 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() {
|
go func() {
|
||||||
for i, decl := range file.Decls {
|
for i, decl := range s.decls {
|
||||||
handleDecl(i, decl, dst[i], done)
|
handleDecl(i, decl, dst[i], done)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
// Wait for all workers are done.
|
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
func (s *defaultService) printResult(buf []chan string) error {
|
||||||
s.printIncludeAdruinoHeader()
|
s.printIncludeAdruinoHeader()
|
||||||
s.printIncludes()
|
s.printIncludes()
|
||||||
s.printConstDeclarations()
|
s.printConstDeclarations()
|
||||||
|
@ -117,17 +152,14 @@ func (s *defaultService) Start() error {
|
||||||
s.printMethodImplementations()
|
s.printMethodImplementations()
|
||||||
s.printGoHelperDeclarations()
|
s.printGoHelperDeclarations()
|
||||||
|
|
||||||
// Print the ordered result.
|
for i := 0; i < len(s.decls); i++ {
|
||||||
for i := 0; i < count; i++ {
|
for content := range buf[i] {
|
||||||
for content := range dst[i] {
|
|
||||||
s.out.Write([]byte(content))
|
s.out.Write([]byte(content))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.out.Write([]byte("\n"))
|
s.out.Write([]byte("\n"))
|
||||||
|
|
||||||
// Print the AST.
|
|
||||||
// ast.Fprint(os.Stderr, fset, file, nil)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
. "my/go-translator/pkg/testgodoglib"
|
. "my/go-translator/pkg/testgodoglib"
|
||||||
|
@ -11,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type testData struct {
|
type testData struct {
|
||||||
src string
|
src []string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -31,22 +32,28 @@ func afterSuite() {
|
||||||
func beforeScenario() {
|
func beforeScenario() {
|
||||||
resetTestData()
|
resetTestData()
|
||||||
}
|
}
|
||||||
func afterScenario() {
|
func afterScenario(result error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------
|
// -----------------------
|
||||||
|
|
||||||
func исходник(src *godog.DocString) {
|
func исходник(src *godog.DocString) {
|
||||||
t.src = src.Content
|
t.src = append(t.src, src.Content)
|
||||||
}
|
}
|
||||||
func результат(out *godog.DocString) {
|
func результат(out *godog.DocString) {
|
||||||
Compare_new(t.src, out.Content)
|
Compare_new(t.src, out.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Compare_new(source, expected string) {
|
func Compare_new(source []string, expected string) {
|
||||||
var in, out bytes.Buffer
|
var in []io.Reader
|
||||||
in.WriteString(source)
|
var out bytes.Buffer
|
||||||
service := NewService(&in, &out)
|
|
||||||
|
for _, s := range source {
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
b.WriteString(s)
|
||||||
|
in = append(in, b)
|
||||||
|
}
|
||||||
|
service := NewService(in, &out)
|
||||||
err := service.Start()
|
err := service.Start()
|
||||||
got := out.String()
|
got := out.String()
|
||||||
tgot, texpected := trim_new(got), trim_new(expected)
|
tgot, texpected := trim_new(got), trim_new(expected)
|
||||||
|
@ -64,7 +71,7 @@ func trim_new(s string) string {
|
||||||
func Compare(source, expected string) {
|
func Compare(source, expected string) {
|
||||||
var in, out bytes.Buffer
|
var in, out bytes.Buffer
|
||||||
in.WriteString(source)
|
in.WriteString(source)
|
||||||
service := NewService(&in, &out)
|
service := NewService([]io.Reader{&in}, &out)
|
||||||
err := service.Start()
|
err := service.Start()
|
||||||
got := out.String()
|
got := out.String()
|
||||||
tgot, texpected := Trim(got), Trim(expected)
|
tgot, texpected := Trim(got), Trim(expected)
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче