-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: lwsanty <[email protected]>
- Loading branch information
Showing
26 changed files
with
1,199 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
language: go | ||
|
||
go: | ||
- '1.13.x' | ||
|
||
go_import_path: github.com/lwsanty/gofactor | ||
|
||
script: | ||
- go test -v ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Oleksandr Chabaiev <[email protected]> (@lwsanty) | ||
Denys Smirnov <[email protected]> (@dennwc) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,154 @@ | ||
# gofactor | ||
Advanced utility for golang refactor based on DSL transformations | ||
Advanced utility for golang refactor based on DSL transformations provided by [bblfsh/sdk](https://github.com/bblfsh/sdk) | ||
|
||
## Usage example | ||
Imagine you have a piece of code | ||
```go | ||
package main | ||
|
||
import "fmt" | ||
|
||
func main() { | ||
var ( | ||
i int | ||
X int | ||
j int | ||
) | ||
|
||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
|
||
fmt.Println(i) | ||
|
||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if j%2 == 0 { | ||
j = 5 | ||
} | ||
} | ||
|
||
func a(i, X int) { | ||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
|
||
fmt.Println(i) | ||
|
||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
} | ||
``` | ||
And you want to replace all code patterns like | ||
```go | ||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
|
||
``` | ||
to | ||
```go | ||
if i%2 == 1 { | ||
i = 1 | ||
} else { | ||
X = 1 | ||
} | ||
``` | ||
Here's where refactor library comes for help. | ||
1) Init refactor object | ||
```go | ||
refactor, err := gofactor.NewRefactor(beforeSnippet, afterSnippet) | ||
if err != nil { | ||
log.Error(err) | ||
os.Exit(1) | ||
} | ||
``` | ||
2) call `Prepare` function to generate transformations mappings | ||
```go | ||
if err := refactor.Prepare(); err != nil { | ||
log.Error(err) | ||
os.Exit(1) | ||
} | ||
``` | ||
3) Apply generated transformations to the desired code | ||
```go | ||
code, err := refactor.Apply(desiredCode) | ||
if err != nil { | ||
log.Error(err) | ||
os.Exit(1) | ||
} | ||
``` | ||
**Result** | ||
```go | ||
package main | ||
|
||
import "fmt" | ||
|
||
func main() { | ||
var ( | ||
i int | ||
X int | ||
j int | ||
) | ||
if i%2 == 1 { | ||
i = 1 | ||
} else { | ||
X = 1 | ||
} | ||
fmt.Println(i) | ||
if i%2 == 1 { | ||
i = 1 | ||
} else { | ||
j = 1 | ||
} | ||
} | ||
func a(i, X int) { | ||
if i%2 == 1 { | ||
i = 1 | ||
} else { | ||
X = 1 | ||
} | ||
fmt.Println(i) | ||
if i%2 == 1 { | ||
i = 1 | ||
} else { | ||
X = 1 | ||
} | ||
} | ||
``` | ||
|
||
## Supported cases | ||
See `fixtures` | ||
|
||
## Under the hood | ||
1) both input and output patterns are converted to go `AST` nodes | ||
2) both input and output nodes converted to `bblfsh` `uast.Node`s | ||
3) define mapping of transformation operations from input to output node | ||
4) apply transformation mapping to the desired code: traverse over the `uast.Node`s tree and transform matching nodes | ||
5) convert transformed tree back to golang `AST` | ||
6) convert golang `AST` to string | ||
|
||
## Roadmap | ||
- currently library cannot be build because of `bblfsh/go-driver` dependency issue, fix this part | ||
- support functions refactor | ||
- handle cases with cascade `if`s, `switch`es and tail recursions | ||
- during the transformations we are forced to drop nodes positions, need to investigate the possibilities of preserving/reconstructing them(probably using DST nodes could help, related issue https://github.com/dave/dst/issues/38) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
|
||
"github.com/lwsanty/gofactor" | ||
"github.com/opentracing/opentracing-go/log" | ||
) | ||
|
||
const ( | ||
dir = "../fixtures/multiple-match2/" | ||
beforeDefault = dir + "before" | ||
afterDefault = dir + "after" | ||
testDefault = dir + "example.go" | ||
) | ||
|
||
func main() { | ||
var ( | ||
before string | ||
after string | ||
test string | ||
) | ||
flag.StringVar(&before, "before", beforeDefault, "a string var") | ||
flag.StringVar(&after, "after", afterDefault, "a string var") | ||
flag.StringVar(&test, "test", testDefault, "a string var") | ||
|
||
flag.Parse() | ||
|
||
handleErr := func(err error) { | ||
if err != nil { | ||
log.Error(err) | ||
os.Exit(1) | ||
} | ||
} | ||
readFile := func(filePath string) []byte { | ||
data, err := ioutil.ReadFile(filePath) | ||
handleErr(err) | ||
return data | ||
} | ||
|
||
beforeData := readFile(before) | ||
afterData := readFile(after) | ||
testData := readFile(test) | ||
|
||
refactor, err := gofactor.NewRefactor(string(beforeData), string(afterData)) | ||
handleErr(err) | ||
|
||
handleErr(refactor.Prepare()) | ||
|
||
code, err := refactor.Apply(string(testData)) | ||
handleErr(err) | ||
|
||
fmt.Println(code) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
if i%2 == 1 { | ||
i = 1 | ||
} else { | ||
X = 1 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package main | ||
|
||
import "fmt" | ||
|
||
func main() { | ||
var ( | ||
i int | ||
X int | ||
j int | ||
) | ||
|
||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
|
||
fmt.Println(i) | ||
|
||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if j%2 == 0 { | ||
X = 5 | ||
} | ||
} | ||
|
||
func a(i, X int) { | ||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
|
||
fmt.Println(i) | ||
|
||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package main | ||
|
||
import "fmt" | ||
|
||
func main() { | ||
var ( | ||
i int | ||
X int | ||
j int | ||
) | ||
if i%2 == 1 { | ||
i = 1 | ||
} else { | ||
X = 1 | ||
} | ||
fmt.Println(i) | ||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
if j%2 == 0 { | ||
X = 5 | ||
} | ||
} | ||
func a(i, X int) { | ||
if i%2 == 1 { | ||
i = 1 | ||
} else { | ||
X = 1 | ||
} | ||
fmt.Println(i) | ||
if i%2 == 1 { | ||
i = 1 | ||
} else { | ||
X = 1 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
if i%2 == 1 { | ||
i = 1 | ||
} else { | ||
X = 1 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package main | ||
|
||
import "fmt" | ||
|
||
func main() { | ||
var ( | ||
i int | ||
X int | ||
j int | ||
) | ||
|
||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
|
||
fmt.Println(i) | ||
|
||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if j%2 == 0 { | ||
j = 5 | ||
} | ||
} | ||
|
||
func a(i, X int) { | ||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
|
||
fmt.Println(i) | ||
|
||
if i%2 == 0 { | ||
i = 5 | ||
} | ||
|
||
if X%2 == 0 { | ||
X = 5 | ||
} | ||
} |
Oops, something went wrong.