package service import ( "fmt" "go/ast" "go/token" "strings" "github.com/davecgh/go-spew/spew" ) func handleBlockStmt(body *ast.BlockStmt) string { code := "" if body == nil { return code } for _, stmt := range body.List { code += handleStmt(stmt, false) code += "\n" } return code } func handleStmt(stmt ast.Stmt, standaloneAssignment bool) string { // println() // spew.Dump(stmt) code := "" switch s := stmt.(type) { case *ast.AssignStmt: code += handleAssignStmt(s) if !standaloneAssignment { code += ";" } case *ast.IncDecStmt: code += handleIncDecStmt(s) if !standaloneAssignment { code += ";" } case *ast.BranchStmt: code += handleBranchStmt(s) case *ast.CaseClause: code += handleCaseClause(s) case *ast.DeclStmt: code += handleDeclStmt(s) case *ast.GoStmt: code += handleGoStmt(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) default: spew.Dump(stmt) panic("handleStmt: unknown type") } return code } func handleAssignStmt(a *ast.AssignStmt) (code string) { // println() // spew.Dump(a) tkn, new := handleToken(a.Tok) if new { t := "auto" if isExpr0String(a.Rhs) { t = "std::string" } code += t + " " } code += handleAssignStmtExpr(a.Lhs) code += tkn code += handleAssignStmtExpr(a.Rhs) return } func isExpr0String(ee []ast.Expr) bool { if len(ee) == 0 { return false } e0 := ee[0] switch e := e0.(type) { case *ast.BasicLit: return e.Kind == token.STRING } return false } func handleAssignStmtExpr(e []ast.Expr) (code string) { // println() // spew.Dump(e) ops := make([]string, 0) for _, op := range e { ops = append(ops, handleExpr(op)) } code += strings.Join(ops, ",") return } func handleToken(t token.Token) (code string, new bool) { st := t.String() switch st { case ":=": return "=", true } return st, false } func handleIncDecStmt(as *ast.IncDecStmt) string { code := handleExpr(as.X) code += as.Tok.String() return code } func handleBranchStmt(stmt *ast.BranchStmt) string { return stmt.Tok.String() + ";" } 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 handleDeclStmt(stmt *ast.DeclStmt) string { code := "" switch decl := stmt.Decl.(type) { case *ast.GenDecl: code += handleGenDecl(decl) } return code } func handleGoStmt(stmt *ast.GoStmt) string { code := "" switch f := stmt.Call.Fun.(type) { case *ast.Ident: go_helper := FunctionGoHelperPrefix + f.Name addGoHelperDeclaration(f.Name) code += `xTaskCreate(` + go_helper + `,"",1024,NULL,1,NULL);` + "\n" } return code } func addGoHelperDeclaration(f string) { dlock.Lock() defer dlock.Unlock() helpersForDeclarations = append(helpersForDeclarations, f) } func handleExprStmt(stmt *ast.ExprStmt) (code string) { // println() // spew.Dump(stmt) switch x := stmt.X.(type) { case *ast.CallExpr: code += handleCallExpr(x) } return } func handleForStmt(stmt *ast.ForStmt) (code string) { 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 += ";" } if stmt.Cond != nil { code += handleBinaryExpr(stmt.Cond) } else { code += "1" } if !is_while { code += ";" code += handleStmt(stmt.Post, true) } code += ") {\n" code += handleBlockStmt(stmt.Body) code += "}" return } func handleIfStmt(stmt *ast.IfStmt) string { // println() // spew.Dump(stmt) cond := handleExpr(stmt.Cond) body := handleBlockStmt(stmt.Body) code := fmt.Sprintf("if (%s) {\n %s }\n", cond, body) if stmt.Else != nil { tail := handleBlockStmt(stmt.Else.(*ast.BlockStmt)) code += fmt.Sprintf(" else {\n %s }\n", tail) } 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 }