722 строки
14 КиБ
Go
722 строки
14 КиБ
Go
package service_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
|
|
var main_func_declared bool
|
|
|
|
// 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)
|
|
}
|
|
main_func_declared = false
|
|
// 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 {
|
|
ind = 0
|
|
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))
|
|
}
|
|
}
|
|
|
|
if main_func_declared {
|
|
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 indSpacesPlus() string {
|
|
increaseInd()
|
|
defer decreaseInd()
|
|
return indSpaces()
|
|
}
|
|
|
|
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 handleCompositeLit(cl *ast.CompositeLit) string {
|
|
code := "("
|
|
switch len(cl.Elts) {
|
|
case 0:
|
|
return "[]"
|
|
default:
|
|
switch cl.Type.(type) {
|
|
case *ast.ArrayType:
|
|
args := make([]string, 0)
|
|
for _, arg := range cl.Elts {
|
|
args = append(args, handleExpr(arg))
|
|
}
|
|
code += strings.Join(args, ",")
|
|
}
|
|
}
|
|
code += ")"
|
|
|
|
return code
|
|
}
|
|
|
|
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 handleBinaryExpr_FromIfStmt(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 {
|
|
// spew.Dump(expr)
|
|
func_name := handleExpr(expr.Fun)
|
|
code := ""
|
|
switch func_name {
|
|
case "append":
|
|
code = handleExpr(expr.Args[0])
|
|
code += ".append("
|
|
args := make([]string, 0)
|
|
for _, arg := range expr.Args[1:] {
|
|
args = append(args, handleExpr(arg))
|
|
}
|
|
code += strings.Join(args, ",")
|
|
code += ")"
|
|
return code
|
|
default:
|
|
code = func_name
|
|
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 := ""
|
|
// spew.Dump(expr)
|
|
switch e := expr.(type) {
|
|
case *ast.BasicLit:
|
|
code += handleBasicLit(e)
|
|
case *ast.CompositeLit:
|
|
code += handleCompositeLit(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 handleExpr_FromIfStmt(expr ast.Expr) string {
|
|
code := ""
|
|
// spew.Dump(expr)
|
|
switch e := expr.(type) {
|
|
case *ast.BasicLit:
|
|
code += handleBasicLit(e)
|
|
case *ast.CompositeLit:
|
|
code += handleCompositeLit(e)
|
|
case *ast.UnaryExpr:
|
|
code += handleUnaryExpr(e)
|
|
case *ast.BinaryExpr:
|
|
code += handleBinaryExpr_FromIfStmt(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 == "main" {
|
|
main_func_declared = true
|
|
}
|
|
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 += ""
|
|
case "true":
|
|
code += "True"
|
|
case "false":
|
|
code += "False"
|
|
default:
|
|
code += ident.Name
|
|
}
|
|
return code
|
|
}
|
|
|
|
func handleIfStmt(stmt *ast.IfStmt) string {
|
|
cond := handleExpr_FromIfStmt(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 := ""
|
|
libName := strings.Trim(s.Path.Value, "\"")
|
|
switch {
|
|
case s.Name == nil:
|
|
code = "import " + libName + "\n"
|
|
case s.Name.Name == ".":
|
|
code = "from " + libName + " import *\n"
|
|
default:
|
|
code = "import " + libName + " as " + s.Name.Name + "\n"
|
|
}
|
|
return code
|
|
}
|
|
|
|
func handleSelectorExpr(expr ast.Expr) string {
|
|
s := expr.(*ast.SelectorExpr)
|
|
code := ""
|
|
switch x := s.X.(type) {
|
|
case *ast.SelectorExpr:
|
|
code += handleSelectorExpr(x)
|
|
case *ast.Ident:
|
|
code += handleIdent(x)
|
|
case *ast.CallExpr:
|
|
code += handleCallExpr(x)
|
|
default:
|
|
spew.Dump(s)
|
|
code += "unknown handleSelectorExpr"
|
|
}
|
|
code += ".\\\n"
|
|
code += indSpacesPlus()
|
|
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.RangeStmt:
|
|
code += handleRangeStmt(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 handleRangeStmt(stmt *ast.RangeStmt) string {
|
|
code := "for "
|
|
code += handleIdent(stmt.Key)
|
|
code += " in "
|
|
code += handleExpr(stmt.X)
|
|
code += ":\n"
|
|
increaseInd()
|
|
code += handleBlockStmt(stmt.Body)
|
|
decreaseInd()
|
|
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)
|
|
default:
|
|
spew.Dump(expr)
|
|
code += "unknown handleValueSpecType"
|
|
}
|
|
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.CompositeLit:
|
|
code += handleCompositeLit(v)
|
|
case *ast.BinaryExpr:
|
|
code += handleBinaryExpr(v)
|
|
case *ast.SelectorExpr:
|
|
code += handleSelectorExpr(value)
|
|
case *ast.CallExpr:
|
|
code += handleCallExpr(v)
|
|
case *ast.Ident:
|
|
code += handleIdent(v)
|
|
default:
|
|
spew.Dump(value)
|
|
code += "unknown handleValueSpecValues"
|
|
}
|
|
}
|
|
return code
|
|
}
|