cleanup & refactoring
Этот коммит содержится в:
родитель
78ad829f70
коммит
24159ea339
14 изменённых файлов: 112 добавлений и 222 удалений
|
@ -1,6 +0,0 @@
|
|||
package transpiler
|
||||
|
||||
// Transpiler specifies the behaviour of taking Go source code and transforming it into another language.
|
||||
type Transpiler interface {
|
||||
Transpile() error
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package worker
|
||||
|
||||
// Mapping specifies the api logic to apply transformation to a specific identifier.
|
||||
type Mapping interface {
|
||||
Apply(ident string) string
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package worker
|
||||
|
||||
// Source stores the code which will be transformed into another format.
|
||||
type Source interface {
|
||||
String() string
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package worker
|
||||
|
||||
// Target stores the result of the transformation process.
|
||||
type Target interface {
|
||||
String() string
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package worker
|
||||
|
||||
// Worker specifies the api logic of transforming a source code format into another target format.
|
||||
type Worker interface {
|
||||
Start() error
|
||||
}
|
4
go.mod
4
go.mod
|
@ -1,5 +1,3 @@
|
|||
module github.com/andygeiss/esp32-transpiler
|
||||
|
||||
go 1.12
|
||||
|
||||
require github.com/andygeiss/assert v0.0.6
|
||||
go 1.14
|
||||
|
|
2
go.sum
2
go.sum
|
@ -1,2 +0,0 @@
|
|||
github.com/andygeiss/assert v0.0.6 h1:FyiAIudVwnxp55GIcNOaZ2ABr8n2RI9SXmaXG7+Y53o=
|
||||
github.com/andygeiss/assert v0.0.6/go.mod h1:ztUvWrfUo43X0zMA1XfX8esn5Uavk6ANSKTT0w2qvAI=
|
|
@ -1,30 +0,0 @@
|
|||
package transpile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/andygeiss/esp32-transpiler/api/transpiler"
|
||||
"github.com/andygeiss/esp32-transpiler/api/worker"
|
||||
)
|
||||
|
||||
// Transpiler uses a given worker to main source code.
|
||||
type Transpiler struct {
|
||||
w worker.Worker
|
||||
}
|
||||
|
||||
const (
|
||||
// ErrorTranspilerWorkerIsNil ...
|
||||
ErrorTranspilerWorkerIsNil = "Worker should not be nil"
|
||||
)
|
||||
|
||||
// NewTranspiler creates a new transpiler and returns its address.
|
||||
func NewTranspiler(w worker.Worker) transpiler.Transpiler {
|
||||
return &Transpiler{w}
|
||||
}
|
||||
|
||||
// Transpile invokes the workers
|
||||
func (c *Transpiler) Transpile() error {
|
||||
if c.w == nil {
|
||||
return fmt.Errorf("Error: %v", ErrorTranspilerWorkerIsNil)
|
||||
}
|
||||
return c.w.Start()
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package transpile_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/andygeiss/assert"
|
||||
"github.com/andygeiss/esp32-transpiler/api/worker"
|
||||
"github.com/andygeiss/esp32-transpiler/impl/transpile"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type mockupWorker struct {
|
||||
in io.Reader
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func (w *mockupWorker) Prepare(source []worker.Source) (chan worker.Source, error) {
|
||||
out := make(chan worker.Source)
|
||||
return out, nil
|
||||
}
|
||||
func (w *mockupWorker) Start() error {
|
||||
return nil
|
||||
}
|
||||
func (w *mockupWorker) Transform(source chan worker.Source) (chan worker.Target, error) {
|
||||
out := make(chan worker.Target)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func TestTranspileErrorShouldBeNil(t *testing.T) {
|
||||
var in, out bytes.Buffer
|
||||
worker := &mockupWorker{&in, &out}
|
||||
trans := transpile.NewTranspiler(worker)
|
||||
err := trans.Transpile()
|
||||
assert.That(t, err, nil)
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"github.com/andygeiss/esp32-transpiler/api/worker"
|
||||
)
|
||||
|
||||
var (
|
||||
rules = map[string]string{
|
||||
"digital.Low": "LOW",
|
||||
"digital.High": "HIGH",
|
||||
"digital.ModeInput": "INPUT",
|
||||
"digital.ModeOutput": "OUTPUT",
|
||||
"digital.PinMode": "pinMode",
|
||||
"digital.Write": "digitalWrite",
|
||||
"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": "void loop",
|
||||
"Setup": "void setup",
|
||||
}
|
||||
)
|
||||
|
||||
// Mapping specifies the api logic to apply transformation to a specific Golang identifier by reading simple JSON map.
|
||||
type Mapping struct{}
|
||||
|
||||
// NewMapping creates a new mapping and returns its address.
|
||||
func NewMapping() worker.Mapping {
|
||||
return &Mapping{}
|
||||
}
|
||||
|
||||
// Apply checks the Golang identifier and transforms it to a specific representation.
|
||||
func (*Mapping) Apply(ident string) string {
|
||||
for wanted := range rules {
|
||||
if ident == wanted {
|
||||
ident = rules[ident]
|
||||
}
|
||||
}
|
||||
return ident
|
||||
}
|
10
main.go
10
main.go
|
@ -1,10 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"esp32-transpiler/transpile"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/andygeiss/esp32-transpiler/impl/transpile"
|
||||
"github.com/andygeiss/esp32-transpiler/impl/worker"
|
||||
"os"
|
||||
)
|
||||
|
||||
|
@ -34,7 +33,7 @@ func printUsage() {
|
|||
flag.PrintDefaults()
|
||||
fmt.Print("\n")
|
||||
fmt.Print("Example:\n")
|
||||
fmt.Printf("\tesp32 -source impl/blink/controller.go -target impl/blink/controller.worker\n\n")
|
||||
fmt.Printf("\tesp32 -source impl/blink/controller.go -target impl/blink/controller.transpile\n\n")
|
||||
}
|
||||
|
||||
func safeTranspile(source, target string) {
|
||||
|
@ -53,9 +52,8 @@ func safeTranspile(source, target string) {
|
|||
os.Exit(1)
|
||||
}
|
||||
// Transpiles the Golang source into Arduino sketch.
|
||||
wrk := worker.NewWorker(in, out, worker.NewMapping())
|
||||
trans := transpile.NewTranspiler(wrk)
|
||||
if err := trans.Transpile(); err != nil {
|
||||
service := transpile.NewService(in, out)
|
||||
if err := service.Start(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
|
60
transpile/mapping.go
Обычный файл
60
transpile/mapping.go
Обычный файл
|
@ -0,0 +1,60 @@
|
|||
package transpile
|
||||
|
||||
var mapping = map[string]string{
|
||||
"digital.Low": "LOW",
|
||||
"digital.High": "HIGH",
|
||||
"digital.ModeInput": "INPUT",
|
||||
"digital.ModeOutput": "OUTPUT",
|
||||
"digital.PinMode": "pinMode",
|
||||
"digital.Write": "digitalWrite",
|
||||
"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": "void loop",
|
||||
"Setup": "void setup",
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
package worker
|
||||
package transpile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/andygeiss/esp32-transpiler/api/worker"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
|
@ -10,6 +9,11 @@ import (
|
|||
"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"
|
||||
|
@ -17,37 +21,37 @@ const (
|
|||
ErrorWorkerWriterIsNil = "Writer should not be nil"
|
||||
)
|
||||
|
||||
var mapping worker.Mapping
|
||||
|
||||
// Worker specifies the api logic of transforming a source code format into another target format.
|
||||
type Worker struct {
|
||||
// defaultService specifies the api logic of transforming a source code format into another target format.
|
||||
type defaultService struct {
|
||||
in io.Reader
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
// NewWorker creates a a new worker and returns its address.
|
||||
func NewWorker(in io.Reader, out io.Writer, m worker.Mapping) worker.Worker {
|
||||
mapping = m
|
||||
return &Worker{in, out}
|
||||
// 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 (w *Worker) Start() error {
|
||||
if w.in == nil {
|
||||
func (s *defaultService) Start() error {
|
||||
if s.in == nil {
|
||||
return fmt.Errorf("Error: %s", ErrorWorkerReaderIsNil)
|
||||
}
|
||||
if w.out == nil {
|
||||
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", w.in, 0)
|
||||
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(w.out, "void loop() {} void setup() {}")
|
||||
fmt.Fprint(s.out, "void loop() {} void setup() {}")
|
||||
return nil
|
||||
}
|
||||
// Use Goroutines to work concurrently.
|
||||
|
@ -57,7 +61,7 @@ func (w *Worker) Start() error {
|
|||
for i := 0; i < count; i++ {
|
||||
dst[i] = make(chan string, 1)
|
||||
}
|
||||
// Start a worker with an individual channel for each declaration in the source file.
|
||||
// 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)
|
||||
}
|
||||
|
@ -70,7 +74,7 @@ func (w *Worker) Start() error {
|
|||
// Print the ordered result.
|
||||
for i := 0; i < count; i++ {
|
||||
for content := range dst[i] {
|
||||
w.out.Write([]byte(content))
|
||||
s.out.Write([]byte(content))
|
||||
}
|
||||
}
|
||||
// Print the AST.
|
||||
|
@ -160,7 +164,7 @@ func handleExpr(expr ast.Expr) string {
|
|||
return code
|
||||
}
|
||||
|
||||
func handleParenExpr (stmt *ast.ParenExpr) string {
|
||||
func handleParenExpr(stmt *ast.ParenExpr) string {
|
||||
code := ""
|
||||
code += handleExpr(stmt.X)
|
||||
return code
|
||||
|
@ -249,7 +253,9 @@ func handleFuncDeclName(ident *ast.Ident) string {
|
|||
return code
|
||||
}
|
||||
code += ident.Name
|
||||
code = mapping.Apply(code)
|
||||
if val, ok := mapping[code]; ok {
|
||||
code = val
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
|
@ -302,7 +308,9 @@ func handleImportSpec(spec ast.Spec) string {
|
|||
code := ""
|
||||
if s.Name != nil {
|
||||
name := handleIdent(s.Name)
|
||||
name = mapping.Apply(name)
|
||||
if val, ok := mapping[name]; ok {
|
||||
name = val
|
||||
}
|
||||
if name != "" {
|
||||
if name != "controller" {
|
||||
code = "#include <" + name + ".h>\n"
|
||||
|
@ -321,7 +329,9 @@ func handleSelectorExpr(expr ast.Expr) string {
|
|||
}
|
||||
code += "."
|
||||
code += handleIdent(s.Sel)
|
||||
code = mapping.Apply(code)
|
||||
if val, ok := mapping[code]; ok {
|
||||
code = val
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
|
@ -370,9 +380,9 @@ func handleForStmt(stmt *ast.ForStmt) string {
|
|||
} else {
|
||||
code += "for"
|
||||
}
|
||||
code += "(" // stmt.Init
|
||||
code += "(" // stmt.Init
|
||||
code += handleBinaryExpr(stmt.Cond) // stmt.Cond
|
||||
code += "" // stmt.Post
|
||||
code += "" // stmt.Post
|
||||
code += ") {"
|
||||
code += handleBlockStmt(stmt.Body) // stmt.Body
|
||||
code += "}"
|
|
@ -1,9 +1,9 @@
|
|||
package worker_test
|
||||
package transpile_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/andygeiss/assert"
|
||||
"github.com/andygeiss/esp32-transpiler/impl/worker"
|
||||
"esp32-transpiler/transpile"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
@ -18,15 +18,20 @@ func Trim(s string) string {
|
|||
}
|
||||
|
||||
// Validate the content of a given source with an expected outcome by using a string compare.
|
||||
// The Worker will be started and used to transform the source into an Arduino sketch format.
|
||||
// The defaultService will be started and used to transform the source into an Arduino sketch format.
|
||||
func Validate(source, expected string, t *testing.T) {
|
||||
var in, out bytes.Buffer
|
||||
in.WriteString(source)
|
||||
wrk := worker.NewWorker(&in, &out, worker.NewMapping())
|
||||
assert.That(t, wrk.Start(), nil)
|
||||
code := out.String()
|
||||
tcode, texpected := Trim(code), Trim(expected)
|
||||
assert.That(t, tcode, texpected)
|
||||
service := transpile.NewService(&in, &out)
|
||||
err := service.Start()
|
||||
got := out.String()
|
||||
tgot, texpected := Trim(got), Trim(expected)
|
||||
if !reflect.DeepEqual(err, nil) {
|
||||
t.Fatalf("got %v, but expected %v", err, nil)
|
||||
}
|
||||
if !reflect.DeepEqual(err, nil) {
|
||||
t.Fatalf("got %v, but expected %v", tgot, texpected)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Empty_Package(t *testing.T) {
|
Загрузка…
Создание таблицы
Сослаться в новой задаче