Добавлен режим питона
Этот коммит содержится в:
родитель
c88b95cb99
коммит
085459f69f
4 изменённых файлов: 1320 добавлений и 13 удалений
|
@ -4,13 +4,19 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"my/go-translator/transpile"
|
||||
"my/go-translator/transpile_python"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
CPP_MODE = iota
|
||||
PYTHON_MODE
|
||||
)
|
||||
|
||||
func main() {
|
||||
source, target := getFlags()
|
||||
mode, source, target := getFlags()
|
||||
checkFlagsAreValid(source, target)
|
||||
safeTranspile(source, target)
|
||||
safeTranspile(mode, source, target)
|
||||
}
|
||||
|
||||
func checkFlagsAreValid(source, target string) {
|
||||
|
@ -20,25 +26,33 @@ func checkFlagsAreValid(source, target string) {
|
|||
}
|
||||
}
|
||||
|
||||
func getFlags() (string, string) {
|
||||
func getFlags() (int, string, string) {
|
||||
// source := flag.String("source", "", "Golang source file")
|
||||
// target := flag.String("target", "", "Arduino sketch file")
|
||||
flag.Parse()
|
||||
mode := CPP_MODE
|
||||
source := flag.Arg(0)
|
||||
target := flag.Arg(1)
|
||||
return source, target
|
||||
|
||||
if source == "-p" {
|
||||
mode = PYTHON_MODE
|
||||
source = flag.Arg(1)
|
||||
target = flag.Arg(2)
|
||||
}
|
||||
|
||||
return mode, source, target
|
||||
}
|
||||
|
||||
func printUsage() {
|
||||
fmt.Print("This program transpiles Golang source into corresponding C code.\n\n")
|
||||
fmt.Print("Options:\n")
|
||||
fmt.Print("This program transpiles Golang source into corresponding C++/python code.\n\n")
|
||||
fmt.Printf("Options:\n by default C++ mode\n -p - python mode\n")
|
||||
flag.PrintDefaults()
|
||||
fmt.Print("\n")
|
||||
fmt.Print("Example:\n")
|
||||
fmt.Printf("\tgo-tr controller.go controller.ino\n\n")
|
||||
fmt.Printf("\tgo-tr [-p] controller.go controller.ino\n\n")
|
||||
}
|
||||
|
||||
func safeTranspile(source, target string) {
|
||||
func safeTranspile(mode int, source, target string) {
|
||||
// Read the Golang source file.
|
||||
in, err := os.Open(source)
|
||||
if err != nil {
|
||||
|
@ -53,10 +67,19 @@ func safeTranspile(source, target string) {
|
|||
fmt.Fprintf(os.Stderr, "Arduino sketch file [%s] could not be opened! %v", target, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
// Transpiles the Golang source into Arduino sketch.
|
||||
service := transpile.NewService(in, out)
|
||||
if err := service.Start(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v", err)
|
||||
os.Exit(1)
|
||||
switch mode {
|
||||
case CPP_MODE:
|
||||
// Transpiles the Golang source into Arduino sketch.
|
||||
service := transpile.NewService(in, out)
|
||||
if err := service.Start(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
case PYTHON_MODE:
|
||||
service := transpile_python.NewService(in, out)
|
||||
if err := service.Start(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
97
transpile_python/mapping.go
Обычный файл
97
transpile_python/mapping.go
Обычный файл
|
@ -0,0 +1,97 @@
|
|||
package transpile_python
|
||||
|
||||
var mapping = map[string]string{
|
||||
"digital.Low": "LOW",
|
||||
"digital.High": "HIGH",
|
||||
"digital.ModeInput": "INPUT",
|
||||
"digital.ModeOutput": "OUTPUT",
|
||||
"digital.PinMode": "pinMode",
|
||||
"digital.Read": "digitalRead",
|
||||
"digital.Write": "digitalWrite",
|
||||
"analog.Read": "analogRead",
|
||||
"analog.Write": "analogWrite",
|
||||
"random.Num": "random",
|
||||
"random.NumBetween": "random",
|
||||
"random.Seed": "randomSeed",
|
||||
"serial.Available": "Serial.available",
|
||||
"serial.BaudRate300": "300",
|
||||
"serial.BaudRate600": "600",
|
||||
"serial.BaudRate1200": "1200",
|
||||
"serial.BaudRate2400": "2400",
|
||||
"serial.BaudRate4800": "4800",
|
||||
"serial.BaudRate9600": "9600",
|
||||
"serial.BaudRate14400": "14400",
|
||||
"serial.BaudRate28800": "28800",
|
||||
"serial.BaudRate38400": "38400",
|
||||
"serial.BaudRate57600": "57600",
|
||||
"serial.BaudRate115200": "115200",
|
||||
"serial.Begin": "Serial.begin",
|
||||
"serial.Print": "Serial.print",
|
||||
"serial.Println": "Serial.println",
|
||||
"timer.Delay": "delay",
|
||||
"wifi": "WiFi",
|
||||
"wifi.Client": "WiFiClient",
|
||||
"client.Connect": "client.connect",
|
||||
"client.Println": "client.println",
|
||||
"client.Write": "client.write",
|
||||
"wifi.Begin": "WiFi.begin",
|
||||
"wifi.BeginEncrypted": "WiFi.begin",
|
||||
"wifi.BSSID": "WiFi.BSSID",
|
||||
"wifi.Disconnect": "WiFi.disconnect",
|
||||
"wifi.EncryptionType": "WiFi.encryptionType",
|
||||
"wifi.EncryptionTypeAuto": "8",
|
||||
"wifi.EncryptionTypeCCMP": "4",
|
||||
"wifi.EncryptionTypeNone": "7",
|
||||
"wifi.EncryptionTypeTKIP": "2",
|
||||
"wifi.EncryptionTypeWEP": "5",
|
||||
"wifi.LocalIP": "WiFi.localIP",
|
||||
"wifi.RSSI": "WiFi.RSSI",
|
||||
"wifi.ScanNetworks": "WiFi.scanNetworks",
|
||||
"wifi.SetDNS": "WiFi.setDNS",
|
||||
"wifi.SSID": "WiFi.SSID",
|
||||
"wifi.Status": "WiFi.status",
|
||||
"wifi.StatusConnected": "WL_CONNECTED",
|
||||
"wifi.StatusConnectionLost": "WL_CONNECTION_LOST",
|
||||
"wifi.StatusConnectFailed": "WL_CONNECT_FAILED",
|
||||
"wifi.StatusDisconnected": "WL_DISCONNECTED",
|
||||
"wifi.StatusIdle": "WL_IDLE_STATUS",
|
||||
"wifi.StatusNoShield": "WL_NO_SHIELD",
|
||||
"wifi.StatusNoSSIDAvailable": "WL_NO_SSID_AVAIL",
|
||||
"wifi.StatusScanCompleted": "WL_SCAN_COMPLETED",
|
||||
"Loop": "loop",
|
||||
"Setup": "setup",
|
||||
"arduino.A0": "A0",
|
||||
"arduino.A1": "A1",
|
||||
"arduino.A2": "A2",
|
||||
"arduino.A3": "A3",
|
||||
"arduino.A4": "A4",
|
||||
"arduino.A5": "A5",
|
||||
"arduino.A6": "A6",
|
||||
"arduino.A7": "A7",
|
||||
"arduino.D0": "0",
|
||||
"arduino.D1": "1",
|
||||
"arduino.D2": "2",
|
||||
"arduino.D3": "3",
|
||||
"arduino.D4": "4",
|
||||
"arduino.D5": "5",
|
||||
"arduino.D6": "6",
|
||||
"arduino.D7": "7",
|
||||
"arduino.D8": "8",
|
||||
"arduino.D9": "9",
|
||||
"arduino.D10": "10",
|
||||
"arduino.D11": "11",
|
||||
"arduino.D12": "12",
|
||||
"arduino.D13": "13",
|
||||
"arduino.D14": "14",
|
||||
"arduino.CIPO": "14",
|
||||
"arduino.MISO": "14",
|
||||
"arduino.D15": "15",
|
||||
"arduino.SCK": "15",
|
||||
"arduino.D16": "16",
|
||||
"arduino.COPI": "16",
|
||||
"arduino.MOSI": "16",
|
||||
"arduino.D17": "17",
|
||||
"arduino.RXLED": "17",
|
||||
"arduino.D30": "30",
|
||||
"arduino.TXLED": "30",
|
||||
}
|
513
transpile_python/service.go
Обычный файл
513
transpile_python/service.go
Обычный файл
|
@ -0,0 +1,513 @@
|
|||
package transpile_python
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Service specifies the api logic of transforming a source code format into another target format.
|
||||
type Service interface {
|
||||
Start() error
|
||||
}
|
||||
|
||||
const (
|
||||
// ErrorWorkerReaderIsNil ...
|
||||
ErrorWorkerReaderIsNil = "Reader should not be nil"
|
||||
// ErrorWorkerWriterIsNil ...
|
||||
ErrorWorkerWriterIsNil = "Writer should not be nil"
|
||||
)
|
||||
|
||||
// defaultService specifies the api logic of transforming a source code format into another target format.
|
||||
type defaultService struct {
|
||||
in io.Reader
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
// NewService creates a a new transpile and returns its address.
|
||||
func NewService(in io.Reader, out io.Writer) Service {
|
||||
return &defaultService{
|
||||
in: in,
|
||||
out: out,
|
||||
}
|
||||
}
|
||||
|
||||
// Start ...
|
||||
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)
|
||||
}
|
||||
// Read tokens from file by using Go's parser.
|
||||
fset := token.NewFileSet()
|
||||
file, err := parser.ParseFile(fset, "source.go", s.in, 0)
|
||||
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)
|
||||
}
|
||||
// Start a transpile with an individual channel for each declaration in the source file.
|
||||
for i, decl := range file.Decls {
|
||||
go handleDecl(i, decl, dst[i], done)
|
||||
}
|
||||
// Wait for all workers are done.
|
||||
for i := 0; i < count; i++ {
|
||||
select {
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
// Print the ordered result.
|
||||
for i := 0; i < count; i++ {
|
||||
for content := range dst[i] {
|
||||
s.out.Write([]byte(content))
|
||||
}
|
||||
}
|
||||
|
||||
s.out.Write([]byte("\n"))
|
||||
|
||||
// Print the AST.
|
||||
// ast.Fprint(os.Stderr, fset, file, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleAssignStmt(as *ast.AssignStmt) string {
|
||||
code := handleAssignStmtExpr(as.Lhs)
|
||||
code += as.Tok.String()
|
||||
code += handleAssignStmtExpr(as.Rhs)
|
||||
return code
|
||||
}
|
||||
|
||||
func handleAssignStmtExpr(e []ast.Expr) string {
|
||||
ops := make([]string, 0)
|
||||
code := ""
|
||||
for _, op := range e {
|
||||
ops = append(ops, handleExpr(op))
|
||||
}
|
||||
code += strings.Join(ops, ",")
|
||||
return code
|
||||
}
|
||||
|
||||
func handleBasicLit(bl *ast.BasicLit) string {
|
||||
return bl.Value
|
||||
}
|
||||
|
||||
func handleUnaryExpr(expr *ast.UnaryExpr) string {
|
||||
code := expr.Op.String()
|
||||
code += handleExpr(expr.X)
|
||||
return code
|
||||
}
|
||||
|
||||
func handleBinaryExpr(expr ast.Expr) string {
|
||||
be := expr.(*ast.BinaryExpr)
|
||||
code := handleExpr(be.X)
|
||||
code += be.Op.String()
|
||||
code += handleExpr(be.Y)
|
||||
return code
|
||||
}
|
||||
|
||||
func handleCallExpr(expr *ast.CallExpr) string {
|
||||
code := handleExpr(expr.Fun)
|
||||
code += "("
|
||||
args := make([]string, 0)
|
||||
for _, arg := range expr.Args {
|
||||
args = append(args, handleExpr(arg))
|
||||
}
|
||||
code += strings.Join(args, ",")
|
||||
code += ")"
|
||||
return code
|
||||
}
|
||||
|
||||
func handleDecl(id int, decl ast.Decl, dst chan<- string, done chan<- bool) {
|
||||
code := ""
|
||||
switch d := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
code += handleFuncDecl(d)
|
||||
case *ast.GenDecl:
|
||||
code += handleGenDecl(d)
|
||||
}
|
||||
dst <- code
|
||||
close(dst)
|
||||
done <- true
|
||||
}
|
||||
|
||||
func handleDeclStmt(stmt *ast.DeclStmt) string {
|
||||
code := ""
|
||||
switch decl := stmt.Decl.(type) {
|
||||
case *ast.GenDecl:
|
||||
code += handleGenDecl(decl)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleExpr(expr ast.Expr) string {
|
||||
code := ""
|
||||
switch e := expr.(type) {
|
||||
case *ast.BasicLit:
|
||||
code += handleBasicLit(e)
|
||||
case *ast.UnaryExpr:
|
||||
code += handleUnaryExpr(e)
|
||||
case *ast.BinaryExpr:
|
||||
code += handleBinaryExpr(e)
|
||||
case *ast.CallExpr:
|
||||
code += handleCallExpr(e)
|
||||
case *ast.Ident:
|
||||
code += handleIdent(e)
|
||||
case *ast.ParenExpr:
|
||||
code += handleParenExpr(e)
|
||||
case *ast.SelectorExpr:
|
||||
code += handleSelectorExpr(e)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleParenExpr(stmt *ast.ParenExpr) string {
|
||||
code := ""
|
||||
code += handleExpr(stmt.X)
|
||||
return code
|
||||
}
|
||||
|
||||
func handleExprStmt(stmt *ast.ExprStmt) string {
|
||||
code := ""
|
||||
switch x := stmt.X.(type) {
|
||||
case *ast.CallExpr:
|
||||
code += handleCallExpr(x)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleFuncDecl(decl ast.Decl) string {
|
||||
fd := decl.(*ast.FuncDecl)
|
||||
if shouldSkipFunction(fd.Type) {
|
||||
return ""
|
||||
}
|
||||
code := ""
|
||||
name := ""
|
||||
code += handleFuncDeclType(fd.Type)
|
||||
code += " "
|
||||
name = handleFuncDeclName(fd.Name)
|
||||
if name == "NewController" {
|
||||
return ""
|
||||
}
|
||||
code += name
|
||||
code += "("
|
||||
code += handleFuncDeclParams(fd.Type)
|
||||
code += ") {"
|
||||
code += handleBlockStmt(fd.Body)
|
||||
code += "}"
|
||||
return code
|
||||
}
|
||||
func shouldSkipFunction(t *ast.FuncType) (res bool) {
|
||||
r := t.Results
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
l := r.List
|
||||
if len(l) != 1 {
|
||||
return
|
||||
}
|
||||
|
||||
p := l[0]
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
|
||||
pt := p.Type
|
||||
if pt == nil {
|
||||
return
|
||||
}
|
||||
|
||||
i, ok := pt.(*ast.Ident)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if i.Name == "ShouldBeSkipped" {
|
||||
return true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func handleFuncDeclParams(t *ast.FuncType) string {
|
||||
code := ""
|
||||
if t.Params == nil || t.Params.List == nil {
|
||||
return code
|
||||
}
|
||||
values := make([]string, 0)
|
||||
for _, field := range t.Params.List {
|
||||
ftype := ""
|
||||
switch ft := field.Type.(type) {
|
||||
case *ast.Ident:
|
||||
ftype = handleIdent(ft)
|
||||
}
|
||||
for _, names := range field.Names {
|
||||
values = append(values, ftype+" "+names.Name)
|
||||
}
|
||||
}
|
||||
code += strings.Join(values, ",")
|
||||
return code
|
||||
}
|
||||
|
||||
func handleBlockStmt(body *ast.BlockStmt) string {
|
||||
code := ""
|
||||
if body == nil {
|
||||
return code
|
||||
}
|
||||
for _, stmt := range body.List {
|
||||
code += handleStmt(stmt, false)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleBranchStmt(stmt *ast.BranchStmt) string {
|
||||
return "break;"
|
||||
}
|
||||
|
||||
func handleCaseClause(cc *ast.CaseClause) string {
|
||||
code := "case "
|
||||
clauses := make([]string, 0)
|
||||
for _, clause := range cc.List {
|
||||
clauses = append(clauses, handleExpr(clause))
|
||||
}
|
||||
code += strings.Join(clauses, ",")
|
||||
code += ":"
|
||||
for _, body := range cc.Body {
|
||||
code += handleStmt(body, false)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleFuncDeclName(ident *ast.Ident) string {
|
||||
code := ""
|
||||
if ident == nil {
|
||||
return code
|
||||
}
|
||||
code += ident.Name
|
||||
if val, ok := mapping[code]; ok {
|
||||
code = val
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleFuncDeclType(t *ast.FuncType) string {
|
||||
code := ""
|
||||
if t.Results == nil {
|
||||
code = "void"
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleGenDecl(decl ast.Decl) string {
|
||||
gd := decl.(*ast.GenDecl)
|
||||
code := ""
|
||||
switch gd.Tok {
|
||||
case token.CONST:
|
||||
code += "const "
|
||||
case token.VAR:
|
||||
code += ""
|
||||
}
|
||||
code += handleSpecs(gd.Specs)
|
||||
return code
|
||||
}
|
||||
|
||||
func handleIdent(expr ast.Expr) string {
|
||||
ident := expr.(*ast.Ident)
|
||||
code := ""
|
||||
switch ident.Name {
|
||||
case "string":
|
||||
code += "char*"
|
||||
default:
|
||||
code += ident.Name
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleIfStmt(stmt *ast.IfStmt) string {
|
||||
cond := handleExpr(stmt.Cond)
|
||||
body := handleBlockStmt(stmt.Body)
|
||||
code := fmt.Sprintf(`if (%s) { %s }`, cond, body)
|
||||
if stmt.Else != nil {
|
||||
tail := handleBlockStmt(stmt.Else.(*ast.BlockStmt))
|
||||
code += fmt.Sprintf(" else { %s }", tail)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleImportSpec(spec ast.Spec) string {
|
||||
s := spec.(*ast.ImportSpec)
|
||||
code := ""
|
||||
if s.Name != nil {
|
||||
name := handleIdent(s.Name)
|
||||
if val, ok := mapping[name]; ok {
|
||||
name = val
|
||||
}
|
||||
if name != "" {
|
||||
if name != "controller" {
|
||||
code = "#include <" + name + ".h>\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleSelectorExpr(expr ast.Expr) string {
|
||||
s := expr.(*ast.SelectorExpr)
|
||||
code := ""
|
||||
switch x := s.X.(type) {
|
||||
case *ast.Ident:
|
||||
code += handleIdent(x)
|
||||
}
|
||||
code += "."
|
||||
code += handleIdent(s.Sel)
|
||||
if val, ok := mapping[code]; ok {
|
||||
code = val
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleSpecs(specs []ast.Spec) string {
|
||||
code := ""
|
||||
for _, spec := range specs {
|
||||
switch spec.(type) {
|
||||
case *ast.ImportSpec:
|
||||
code += handleImportSpec(spec)
|
||||
case *ast.ValueSpec:
|
||||
code += handleValueSpec(spec) + ";"
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleStmt(stmt ast.Stmt, standaloneAssignment bool) string {
|
||||
code := ""
|
||||
switch s := stmt.(type) {
|
||||
case *ast.AssignStmt:
|
||||
code += handleAssignStmt(s)
|
||||
if !standaloneAssignment {
|
||||
code += ";"
|
||||
}
|
||||
case *ast.BranchStmt:
|
||||
code += handleBranchStmt(s)
|
||||
case *ast.CaseClause:
|
||||
code += handleCaseClause(s)
|
||||
case *ast.DeclStmt:
|
||||
code += handleDeclStmt(s)
|
||||
case *ast.ExprStmt:
|
||||
code += handleExprStmt(s)
|
||||
code += ";"
|
||||
case *ast.ForStmt:
|
||||
code += handleForStmt(s)
|
||||
case *ast.IfStmt:
|
||||
code += handleIfStmt(s)
|
||||
case *ast.SwitchStmt:
|
||||
code += handleSwitchStmt(s)
|
||||
case *ast.ReturnStmt:
|
||||
code += handleReturnStmt(s)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleForStmt(stmt *ast.ForStmt) string {
|
||||
code := ""
|
||||
is_while := false
|
||||
if stmt.Init == nil && stmt.Post == nil {
|
||||
is_while = true
|
||||
code += "while"
|
||||
} else {
|
||||
code += "for"
|
||||
}
|
||||
code += "("
|
||||
if !is_while {
|
||||
code += handleStmt(stmt.Init, true)
|
||||
code += ";"
|
||||
}
|
||||
code += handleBinaryExpr(stmt.Cond) // stmt.Cond
|
||||
if !is_while {
|
||||
code += ";"
|
||||
code += handleStmt(stmt.Post, true)
|
||||
}
|
||||
code += ") {"
|
||||
code += handleBlockStmt(stmt.Body) // stmt.Body
|
||||
code += "}"
|
||||
return code
|
||||
}
|
||||
|
||||
func handleSwitchStmt(stmt *ast.SwitchStmt) string {
|
||||
code := "switch ("
|
||||
code += handleExpr(stmt.Tag)
|
||||
code += "){"
|
||||
code += handleBlockStmt(stmt.Body)
|
||||
code += "}"
|
||||
return code
|
||||
}
|
||||
|
||||
func handleReturnStmt(stmt *ast.ReturnStmt) string {
|
||||
code := "return "
|
||||
if len(stmt.Results) > 0 {
|
||||
code += handleExpr(stmt.Results[0])
|
||||
}
|
||||
code += ";"
|
||||
return code
|
||||
}
|
||||
|
||||
func handleValueSpec(spec ast.Spec) string {
|
||||
s := spec.(*ast.ValueSpec)
|
||||
code := ""
|
||||
code += handleValueSpecType(s.Type)
|
||||
code += " "
|
||||
code += handleValueSpecNames(s.Names)
|
||||
if s.Values != nil {
|
||||
code += " = "
|
||||
code += handleValueSpecValues(s.Values)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleValueSpecNames(names []*ast.Ident) string {
|
||||
code := ""
|
||||
for _, name := range names {
|
||||
code += handleIdent(name)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleValueSpecType(expr ast.Expr) string {
|
||||
code := ""
|
||||
switch t := expr.(type) {
|
||||
case *ast.SelectorExpr:
|
||||
code += handleSelectorExpr(t)
|
||||
case *ast.Ident:
|
||||
code += handleIdent(t)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func handleValueSpecValues(values []ast.Expr) string {
|
||||
code := ""
|
||||
for _, value := range values {
|
||||
switch v := value.(type) {
|
||||
case *ast.BasicLit:
|
||||
code += handleBasicLit(v)
|
||||
case *ast.SelectorExpr:
|
||||
code += handleSelectorExpr(value)
|
||||
case *ast.CallExpr:
|
||||
code += handleCallExpr(v)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
674
transpile_python/service_test.go
Обычный файл
674
transpile_python/service_test.go
Обычный файл
|
@ -0,0 +1,674 @@
|
|||
package transpile_python
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestUtils(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Go Translator")
|
||||
}
|
||||
|
||||
var _ = Describe("Go Translator", func() {
|
||||
Describe("All", func() {
|
||||
It("Empty_Package", func() {
|
||||
source := `package test`
|
||||
expected := `void loop(){}
|
||||
void setup(){}`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_Declaration", func() {
|
||||
source := `package test
|
||||
func foo() {}
|
||||
func bar() {}
|
||||
`
|
||||
expected := `void foo(){}
|
||||
void bar() {}`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_Declaration_With_Args", func() {
|
||||
source := `package test
|
||||
func foo(x int) {}
|
||||
func bar(y int) {}
|
||||
`
|
||||
expected := `void foo(int x){}
|
||||
void bar(int y) {}`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Const_String_Declaration", func() {
|
||||
source := `package test
|
||||
const foo string = "bar"
|
||||
`
|
||||
expected := `
|
||||
const char* foo = "bar";
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Var_String_Declaration", func() {
|
||||
source := `package test
|
||||
var client wifi.Client
|
||||
`
|
||||
expected := `
|
||||
WiFiClient client;
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_With_Const_String_Declaration", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
const foo string = "bar"
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
const char* foo = "bar";
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_With_Var_String_Declaration", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
var foo string = "bar"
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
char* foo = "bar";
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_With_Function_Call", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
bar()
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
bar();
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_With_Function_Call_With_Args", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
bar(1,2,3)
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
bar(1,2,3);
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_With_Function_Call_With_String", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
bar("foo")
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
bar("foo");
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_With_Package_Function_Call", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
foo.Bar(1,"2")
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
foo.Bar(1,"2");
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_With_Assignments", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
x = 1
|
||||
y = 2
|
||||
z = x + y
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
x = 1;
|
||||
y = 2;
|
||||
z = x + y;
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_With_Package_Selector_Assignments", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
x = bar()
|
||||
y = pkg.Bar()
|
||||
z = x + y
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
x = bar();
|
||||
y = pkg.Bar();
|
||||
z = x + y;
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_Ident_Mapping", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
serial.Begin()
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
Serial.begin();
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_With_Ident_Param", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
foo.Bar(1,"2",digital.Low)
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
foo.Bar(1,"2",LOW);
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_With_Function_Param", func() {
|
||||
source := `package test
|
||||
func foo() {
|
||||
serial.Println(wifi.LocalIP())
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void foo() {
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Function_Should_Be_Skipped", func() {
|
||||
source := `package test
|
||||
func foo() (s ShouldBeSkipped) {
|
||||
return;
|
||||
}
|
||||
`
|
||||
expected := ``
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Package_Import", func() {
|
||||
source := `package test
|
||||
import "github.com/andygeiss/esp32-mqtt/api/controller"
|
||||
import "github.com/andygeiss/esp32-mqtt/api/controller/serial"
|
||||
import "github.com/andygeiss/esp32/api/controller/timer"
|
||||
import wifi "github.com/andygeiss/esp32/api/controller/wifi"
|
||||
`
|
||||
expected := `
|
||||
#include <WiFi.h>
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("Package_Import_But_Ignore_Controller", func() {
|
||||
source := `package test
|
||||
import controller "my/go-controller"
|
||||
import "github.com/andygeiss/esp32-mqtt/api/controller/serial"
|
||||
import "github.com/andygeiss/esp32/api/controller/timer"
|
||||
import wifi "github.com/andygeiss/esp32/api/controller/wifi"
|
||||
`
|
||||
expected := `
|
||||
#include <WiFi.h>
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("IfStmt_With_Condition_BasicLit_And_BasicLit", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
if 1 == 1 {
|
||||
serial.Println("1")
|
||||
}
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
if (1 == 1) {
|
||||
Serial.println("1");
|
||||
}
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("IfStmt_With_Condition_Ident_And_BasicLit", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
if x == 1 {
|
||||
serial.Println("1")
|
||||
}
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
if (x == 1) {
|
||||
Serial.println("1");
|
||||
}
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("IfStmt_With_Condition_CallExpr_And_BasicLit", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
if x() == 1 {
|
||||
serial.Println("1")
|
||||
}
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
if (x() == 1) {
|
||||
Serial.println("1");
|
||||
}
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("IfStmt_With_Condition_Const_And_BasicLit", func() {
|
||||
source := `package test
|
||||
const maxX = 1
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
if x == maxX {
|
||||
serial.Println("1")
|
||||
}
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
const maxX = 1;
|
||||
void setup() {}
|
||||
void loop() {
|
||||
if (x == maxX) {
|
||||
Serial.println("1");
|
||||
}
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("IfStmt_With_Else", func() {
|
||||
source := `package test
|
||||
const maxX = 1
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
if x == maxX {
|
||||
serial.Println("1")
|
||||
} else {
|
||||
serial.Println("2")
|
||||
}
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
const maxX = 1;
|
||||
void setup() {}
|
||||
void loop() {
|
||||
if (x == maxX) {
|
||||
Serial.println("1");
|
||||
} else {
|
||||
Serial.println("2");
|
||||
}
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("SwitchStmt_With_Ident_And_BasicLit", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
switch x {
|
||||
case 1:
|
||||
serial.Println("1")
|
||||
}
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
switch (x) {
|
||||
case 1:
|
||||
Serial.println("1");
|
||||
}
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("SwitchStmt_With_Break", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
switch x {
|
||||
case 1:
|
||||
serial.Println("1")
|
||||
break
|
||||
case 2:
|
||||
serial.Println("1")
|
||||
}
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
switch (x) {
|
||||
case 1:
|
||||
Serial.println("1");
|
||||
break;
|
||||
case 2:
|
||||
Serial.println("1");
|
||||
}
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("ForLoop_WithoutInit_And_Post_Transpiles_To_While", func() {
|
||||
source := `package test
|
||||
import wifi "github.com/andygeiss/esp32/api/controller/wifi"
|
||||
func Setup() {
|
||||
serial.Begin(serial.BaudRate115200)
|
||||
wifi.BeginEncrypted("SSID", "PASS")
|
||||
for wifi.Status() != wifi.StatusConnected {
|
||||
serial.Println("Connecting ...")
|
||||
}
|
||||
serial.Println("Connected!")
|
||||
}
|
||||
func Loop() {}
|
||||
`
|
||||
expected := `
|
||||
#include <WiFi.h>
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
WiFi.begin("SSID","PASS");
|
||||
while(WiFi.status()!=WL_CONNECTED){
|
||||
Serial.println("Connecting...");
|
||||
}
|
||||
Serial.println("Connected!");
|
||||
}
|
||||
void loop() {}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
|
||||
It("WiFiWebClient", func() {
|
||||
source := `package test
|
||||
import wifi "github.com/andygeiss/esp32/api/controller/wifi"
|
||||
var client wifi.Client
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
serial.Print("Connecting to ")
|
||||
serial.Println(host)
|
||||
serial.Print(" ...")
|
||||
if (client.Connect(host, 443) == true) {
|
||||
serial.Println(" Connected!")
|
||||
} else {
|
||||
serial.Println(" Failed!")
|
||||
}
|
||||
}
|
||||
`
|
||||
expected := `#include <WiFi.h>
|
||||
WiFiClient client;
|
||||
voidsetup(){}
|
||||
voidloop(){
|
||||
Serial.print("Connecting to");
|
||||
Serial.println(host);
|
||||
Serial.print(" ...");
|
||||
if(client.connect(host, 443) == true){
|
||||
Serial.println(" Connected!");
|
||||
} else {
|
||||
Serial.println(" Failed!");
|
||||
}
|
||||
}`
|
||||
Compare(source, expected)
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Arduino", func() {
|
||||
It("Maps constants", func() {
|
||||
source := `package test
|
||||
var analogInPin int = arduino.A0
|
||||
func Setup() {}
|
||||
func Loop() {}
|
||||
`
|
||||
expected := `
|
||||
int analogInPin = A0;
|
||||
void setup() {}
|
||||
void loop() {}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Функции", func() {
|
||||
It("Объявление void функции", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
}
|
||||
|
||||
func MyFunction() {
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
}
|
||||
void MyFunction() {
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
It("Объявление void функции с return", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
}
|
||||
|
||||
func MyFunction() {
|
||||
return
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
}
|
||||
void MyFunction() {
|
||||
return;
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
It("Объявление int функции", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
}
|
||||
|
||||
func MyFunction() int {
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
}
|
||||
MyFunction() {
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
It("Объявление int функции с return 0", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
}
|
||||
|
||||
func MyFunction() int {
|
||||
return 0
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
}
|
||||
MyFunction() {
|
||||
return 0;
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
It("Объявление int функции с return -1", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
}
|
||||
|
||||
func MyFunction() int {
|
||||
return -1
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
}
|
||||
MyFunction() {
|
||||
return -1;
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
It("Объявляет и вызывает функцию", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
var x int = MyFunction()
|
||||
}
|
||||
|
||||
func MyFunction() int {
|
||||
return 0
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
int x = MyFunction();
|
||||
}
|
||||
MyFunction() {
|
||||
return 0;
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Циклы", func() {
|
||||
It("for i=0; i<10; i+=1", func() {
|
||||
source := `package test
|
||||
func Setup() {}
|
||||
func Loop() {
|
||||
var i int
|
||||
for i=0; i<10; i+=1 {
|
||||
i = i
|
||||
}
|
||||
}
|
||||
`
|
||||
expected := `
|
||||
void setup() {}
|
||||
void loop() {
|
||||
int i;
|
||||
for (i=0; i<10; i+=1) {
|
||||
i = i;
|
||||
}
|
||||
}
|
||||
`
|
||||
Compare(source, expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func Compare(source, expected string) {
|
||||
var in, out bytes.Buffer
|
||||
in.WriteString(source)
|
||||
service := NewService(&in, &out)
|
||||
err := service.Start()
|
||||
got := out.String()
|
||||
tgot, texpected := Trim(got), Trim(expected)
|
||||
// spew.Dump(tgot)
|
||||
ExpectWithOffset(1, err).NotTo(HaveOccurred())
|
||||
ExpectWithOffset(1, tgot).To(Be(texpected))
|
||||
}
|
||||
|
||||
func Trim(s string) string {
|
||||
s = strings.Replace(s, " ", "", -1)
|
||||
s = strings.Replace(s, "\n", "", -1)
|
||||
s = strings.Replace(s, "\r", "", -1)
|
||||
s = strings.Replace(s, "\t", "", -1)
|
||||
return s
|
||||
}
|
||||
|
||||
func NDescribe(s string, i func()) int { return 0 }
|
||||
func NIt(s string, i func()) int { return 0 }
|
||||
|
||||
var Be = Equal
|
||||
|
||||
func NoErr(err error) {
|
||||
ExpectWithOffset(1, err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
var Ok = NoErr
|
Загрузка…
Создание таблицы
Сослаться в новой задаче