go-translator/transpile_python/service.go

602 строки
11 КиБ
Go

package transpile_python
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"io"
"strings"
"github.com/davecgh/go-spew/spew"
)
// 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
}
var ind int
// 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)
}
ind = 0
// Read tokens from file by using Go's parser.
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "source.go", s.in, parser.ParseComments)
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, "")
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.
go func() {
for i, decl := range file.Decls {
handleDecl(i, decl, dst[i], done)
}
}()
// Wait for all workers are done.
for i := 0; i < count; i++ {
select {
case <-done:
}
}
// s.out.Write([]byte("from skidl import *\n"))
// Print the ordered result.
for i := 0; i < count; i++ {
for content := range dst[i] {
s.out.Write([]byte(content))
}
}
s.out.Write([]byte("main()\n"))
// Print the AST.
// ast.Fprint(os.Stderr, fset, file, nil)
return nil
}
func increaseInd() {
ind++
}
func decreaseInd() {
ind--
}
func indSpaces() string {
res := ""
for i := 0; i < ind; i++ {
res += " "
}
return res
}
func handleAssignStmt(as *ast.AssignStmt) string {
code := handleAssignStmtExpr(as.Lhs)
switch as.Tok {
case token.DEFINE:
code += " = "
default:
code += " " + as.Tok.String() + " "
}
code += handleAssignStmtExpr(as.Rhs)
code += "\n"
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)
switch be.Op {
case token.EQL:
code += "="
default:
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)
case *ast.IndexExpr:
code += handleIndexExpr(e)
default:
spew.Dump(e)
code += "Unknown in handleExpr"
}
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)
case *ast.BinaryExpr:
code += handleBinaryExpr(x)
default:
spew.Dump(stmt.X)
code += "unknown in handleExprStmt"
}
code += "\n"
return code
}
func handleFuncDecl(decl ast.Decl) string {
fd := decl.(*ast.FuncDecl)
if shouldSkipFunction(fd.Type) {
return ""
}
code := ""
if fd.Doc != nil {
t := fd.Doc.Text()
switch t {
case "@package\n":
code += t
case "@subcircuit\n":
code += t
}
}
code += "def "
name := ""
name = handleFuncDeclName(fd.Name)
if name == "NewController" {
return ""
}
code += name
code += "("
code += handleFuncDeclParams(fd.Type)
code += "):\n"
increaseInd()
code += handleBlockStmt(fd.Body)
decreaseInd()
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, names.Name)
}
}
code += strings.Join(values, ",")
return code
}
func handleBlockStmt(body *ast.BlockStmt) string {
code := ""
if body == nil {
return code
}
if len(body.List) == 0 {
return indSpaces() + "None\n"
}
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 = ""
}
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 += ""
default:
code += ident.Name
}
return code
}
func handleIfStmt(stmt *ast.IfStmt) string {
cond := handleExpr(stmt.Cond)
increaseInd()
body := handleBlockStmt(stmt.Body)
decreaseInd()
code := fmt.Sprintf("if %s:\n%s", cond, body)
if stmt.Else != nil {
increaseInd()
tail := handleBlockStmt(stmt.Else.(*ast.BlockStmt))
decreaseInd()
code += indSpaces()
code += fmt.Sprintf("else:\n%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"
}
}
} else {
code = "from " + strings.Trim(s.Path.Value, "\"") + " import *\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 handleIndexExpr(expr *ast.IndexExpr) string {
code := ""
switch x := expr.X.(type) {
case *ast.Ident:
code += x.String()
// case *ast.CallExpr:
// code += x....
default:
spew.Dump(x)
code += "unknown handleIndexExpr"
}
code += "["
code += expr.Index.(*ast.BasicLit).Value
code += "]"
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)
}
}
code += "\n"
return code
}
func handleStmt(stmt ast.Stmt, standaloneAssignment bool) string {
code := indSpaces()
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)
case *ast.ForStmt:
code += handleForStmt(s)
case *ast.IfStmt:
code += handleIfStmt(s)
case *ast.SwitchStmt:
code += handleSwitchStmt(s)
case *ast.ReturnStmt:
code += handleReturnStmt(s)
default:
spew.Dump(stmt)
code += "unknown handleStmt"
}
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 += "\n"
return code
}
func handleValueSpec(spec ast.Spec) string {
s := spec.(*ast.ValueSpec)
code := ""
code += handleValueSpecNames(s.Names)
if s.Values != nil {
code += " = "
code += handleValueSpecValues(s.Values)
}
code += "\n"
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.BinaryExpr:
code += handleBinaryExpr(v)
case *ast.SelectorExpr:
code += handleSelectorExpr(value)
case *ast.CallExpr:
code += handleCallExpr(v)
}
}
return code
}