Commit 7d93731b authored by Hugo Moreau's avatar Hugo Moreau

InnerCall: Handling multiple CallExpr

 * tests/innercall.go,
   tests/expected,
   transform/innercall.go : Here.
parent 0371342c
Pipeline #26601 passed with stage
in 2 minutes and 19 seconds
......@@ -7,6 +7,7 @@
#facto.go,23,23
#fibonacci.go,43,43
#if.go,13,13
#innercall.go,48,48
#mywhile.go,255,255
#multiple.go,6,6
#multiplecallassign.go,21,21
......
......@@ -13,7 +13,8 @@ func bar(x, y int) int {
}
func main() {
a, b := foo(42), 2
bar(foo(42), 2)
fmt.Println(a + b)
a, b := bar(foo(4), foo(20)), foo(54)
fmt.Println(a, b)
fmt.Println(foo(2011920))
fmt.Println(bar(foo(42), foo(3)), foo(55), bar(400, 4))
}
package transform
import (
"fmt"
"go/ast"
"go/token"
"strconv"
)
/*
The InnerCall transformation create temporary variables for multiple
CallExpr, for now is handled :
- AssignStmt
- ExprStmt
Transform :
Before:
```
a, b := foo(), foo()
bar(foo(), 42)
```
After:
```
G2P_foo_1 = foo()
G2P_foo_2 = foo()
a, b := G2P_foo_1, G2P_foo_1
G2P_foo_3 := foo()
bar(G2P_foo_3, 42)
```
*/
type InnerCall struct {
count map[string]int
}
......@@ -20,10 +40,11 @@ func (t *InnerCall) Pre(meta *Meta, v *Visitor) bool {
for i := 0; i < len(node.Rhs); i++ {
switch rhs := node.Rhs[i].(type) {
case *ast.CallExpr:
// Must decompose if len(node.Rhs) > 1
fmt.Println("CallExpr in AssignStmt", rhs)
addStmt := []*ast.AssignStmt{}
if len(node.Rhs) > 1 {
aStmt, n := t.CallExprRec(rhs)
addStmt = append(addStmt, aStmt...)
node.Rhs[i], rhs = n, n
if len(node.Rhs) > 1 && !isSelectExpr(rhs) {
ident := t.CreateTmpVar(rhs)
addStmt = append(addStmt, &ast.AssignStmt{
Lhs: []ast.Expr{ident},
......@@ -32,7 +53,6 @@ func (t *InnerCall) Pre(meta *Meta, v *Visitor) bool {
})
node.Rhs[i] = ident
}
CallExprRec(rhs)
for _, val := range addStmt {
c.InsertBefore(val)
}
......@@ -41,8 +61,11 @@ func (t *InnerCall) Pre(meta *Meta, v *Visitor) bool {
case *ast.ExprStmt:
switch nodeX := node.X.(type) {
case *ast.CallExpr:
fmt.Println("CallExpr in ExprStmt", nodeX)
CallExprRec(nodeX)
addStmt, n := t.CallExprRec(nodeX)
for _, val := range addStmt {
c.InsertBefore(val)
}
node.X = n
}
}
return true
......@@ -53,16 +76,26 @@ func (t *InnerCall) Post(meta *Meta, v *Visitor) bool {
}
// Handle recursive CallExpr
func CallExprRec(curNode *ast.CallExpr) {
func (t *InnerCall) CallExprRec(curNode *ast.CallExpr) ([]*ast.AssignStmt, *ast.CallExpr) {
res := []*ast.AssignStmt{}
for i := 0; i < len(curNode.Args); i++ {
switch arg := curNode.Args[i].(type) {
case *ast.CallExpr:
// Must decompose if len(curNode.Args[i]) > 1
fmt.Println("par:", curNode, "arg:", arg)
// Must call again to check if there is more CallExpr as args
CallExprRec(arg)
newRes, node := t.CallExprRec(arg)
curNode.Args[i], arg = node, node
res = append(res, newRes...)
if len(curNode.Args) > 1 && !isSelectExpr(arg) {
ident := t.CreateTmpVar(arg)
res = append(res, &ast.AssignStmt{
Lhs: []ast.Expr{ident},
Tok: token.DEFINE,
Rhs: []ast.Expr{arg},
})
curNode.Args[i] = ident
}
}
}
return res, curNode
}
func (t *InnerCall) CreateTmpVar(callExpr *ast.CallExpr) *ast.Ident {
......@@ -70,12 +103,6 @@ func (t *InnerCall) CreateTmpVar(callExpr *ast.CallExpr) *ast.Ident {
switch fun := callExpr.Fun.(type) {
case *ast.Ident:
name = fun.Name
case *ast.SelectorExpr:
switch selecX := fun.X.(type) {
case *ast.Ident:
name = selecX.Name
}
name += fun.Sel.Name
}
if _, ok := t.count[name]; !ok {
t.count[name] = 1
......@@ -83,8 +110,16 @@ func (t *InnerCall) CreateTmpVar(callExpr *ast.CallExpr) *ast.Ident {
res := ast.NewIdent("G2P_" + name + "_" + strconv.Itoa(t.count[name]))
res.Obj = &ast.Object{
Kind: ast.Var,
Name: "G2P_" + name + "_" + strconv.Itoa(t.count[name]),
Name: res.Name,
}
t.count[name]++
return res
}
func isSelectExpr(callExpr *ast.CallExpr) bool {
switch callExpr.Fun.(type) {
case *ast.SelectorExpr:
return true
}
return false
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment