Commit 56fc2025 authored by Hugo Moreau's avatar Hugo Moreau
Browse files

Dependencies: Refactoring the transform

Inner BlockStmt was not handled, it is currently done and refactored.

 * main.go : Modified.
   transform/dependencies_rework/go : Created.
parent dbe006f7
Pipeline #28372 passed with stage
in 2 minutes and 34 seconds
......@@ -103,7 +103,8 @@ func compileTo(filepath string, src []byte, file *os.File,
localvariable := &transform.LocalVariableAssignments{Global: true}
res := transform.ApplyAll(f, meta, []transform.Transform{
&transform.Dependencies{},
// &transform.Dependencies{},
&transform.DependenciesRework{},
// &transform.Debug{}, // only for debuging a special transformation
&transform.Alive{},
&transform.Channel{
......
package transform
import (
"fmt"
"go/ast"
"strconv"
)
type DependenciesRework struct {
GlobalVar []*ast.Object
Func map[*ast.Object]*FuncInfosBis
}
type VarInfos struct {
ReadStmt map[*[]StmtNumber]bool
WriteStmt map[*[]StmtNumber]bool
VarDep map[*ast.Object]bool
}
type FuncInfosBis struct {
Parameters []*ast.Field
Variables map[*ast.Object]*VarInfos
}
type StmtNumber struct {
Number int
If_or_else bool
}
func (t *DependenciesRework) init(file *ast.File) {
t.Func = make(map[*ast.Object]*FuncInfosBis)
for _, val := range file.Scope.Objects {
if val.Kind == ast.Var {
t.GlobalVar = append(t.GlobalVar, val)
}
}
}
func (t *DependenciesRework) handleFuncDecl(funcDecl *ast.FuncDecl) {
// Store the funcDecl and then our wanted informations.
// Analyze Function Body.
// Think on a recursive way in order to handle Stmt that contains a body too.
// DFS will be the way.
currentFunc := &FuncInfosBis{
Parameters: funcDecl.Type.Params.List,
Variables: make(map[*ast.Object]*VarInfos),
}
for key, value := range funcDecl.Body.List {
currentFunc.handleStmt([]StmtNumber{StmtNumber{key, false}}, false, value)
}
t.Func[funcDecl.Name.Obj] = currentFunc
return
}
func (infos *FuncInfosBis) addReadAndWrite(number []StmtNumber, read, write []*ast.Object) {
for _, value := range read {
if _, ok := infos.Variables[value]; !ok {
infos.Variables[value] = &VarInfos{
ReadStmt: make(map[*[]StmtNumber]bool),
WriteStmt: make(map[*[]StmtNumber]bool),
VarDep: make(map[*ast.Object]bool),
}
}
infos.Variables[value].ReadStmt[&number] = true
for _, dep := range read {
if dep != value {
infos.Variables[value].VarDep[dep] = true
}
}
for _, dep := range write {
if dep != value {
infos.Variables[value].VarDep[dep] = true
}
}
}
for _, value := range write {
if _, ok := infos.Variables[value]; !ok {
infos.Variables[value] = &VarInfos{
ReadStmt: make(map[*[]StmtNumber]bool),
WriteStmt: make(map[*[]StmtNumber]bool),
VarDep: make(map[*ast.Object]bool),
}
}
infos.Variables[value].WriteStmt[&number] = true
for _, dep := range read {
if dep != value {
infos.Variables[value].VarDep[dep] = true
}
}
for _, dep := range write {
if dep != value {
infos.Variables[value].VarDep[dep] = true
}
}
}
}
func (infos *FuncInfosBis) handleStmt(number []StmtNumber, if_or_else bool, stmt ast.Node) {
if stmt == nil {
return
}
switch stmt := stmt.(type) {
case *ast.AssignStmt:
// Handle LHS and RHS
// LHS is write
lhsVar := []*ast.Object{}
for _, lhs := range stmt.Lhs {
lhsVar = append(lhsVar, detectVar(lhs)...)
}
// RHS is read
rhsVar := []*ast.Object{}
for _, rhs := range stmt.Rhs {
rhsVar = append(rhsVar, detectVar(rhs)...)
}
// fmt.Println(number, stmt, "AssignStmt", "lhs", lhsVar, "rhs", rhsVar)
infos.addReadAndWrite(number, rhsVar, lhsVar)
return
case *ast.BlockStmt:
// fmt.Println(number, "BlockStmt")
for key, value := range stmt.List {
infos.handleStmt(append(number, StmtNumber{key, if_or_else}), false, value)
}
return
case *ast.ForStmt:
// Handle the fact that there is a BlockStmt
// fmt.Println(number, "ForStmt")
// Consider Init, Cond and Post as Part of the stmt since it is in the declaration
infos.handleStmt(number, false, stmt.Init)
infos.handleStmt(number, false, stmt.Cond)
infos.handleStmt(number, false, stmt.Post)
// Consider the Body as a new BlockStmt, so a new step is taken
infos.handleStmt(number, false, stmt.Body)
return
case *ast.IfStmt:
// Handle the fact that there is a BlockStmt
// and maybe a second one if there is an else
// Handle that Init is an Expr and can be an AssignStmt
// fmt.Println(number, "IfStmt")
// Consider Init and Cond as part of the Stmt
infos.handleStmt(number, false, stmt.Init)
infos.handleStmt(number, false, stmt.Cond)
// Consider Body and Else as two new step
// The question is how to represent this since there is two new BlockStmt if Else is declared
infos.handleStmt(number, false, stmt.Body)
infos.handleStmt(number, true, stmt.Else)
return
case *ast.IncDecStmt:
variables := detectVar(stmt.X)
// fmt.Println(number, stmt, "IncDecStmt", variables)
infos.addReadAndWrite(number, nil, variables)
return
case *ast.RangeStmt:
case *ast.SelectStmt:
case *ast.SwitchStmt:
case *ast.TypeSwitchStmt:
// Not Handle yet
return
default:
variables := detectVar(stmt)
// fmt.Println(number, stmt, "default", variables)
infos.addReadAndWrite(number, variables, nil)
}
}
func detectVar(stmt ast.Node) []*ast.Object {
variables := []*ast.Object{}
ast.Inspect(stmt, func(n ast.Node) bool {
decl, ok := n.(*ast.Ident)
if !ok {
return true
}
if decl.Obj != nil && decl.Obj.Kind == ast.Var {
variables = append(variables, decl.Obj)
}
return true
})
return variables
}
// Pre traversal applies the transformation.
func (t *DependenciesRework) Pre(meta *Meta, v *Visitor) bool {
c := v.Cursor()
switch node := c.Node().(type) {
case *ast.File:
t.init(node)
case *ast.FuncDecl:
t.handleFuncDecl(node)
}
return true
}
// Post traversal applies the transformation.
func (t *DependenciesRework) Post(meta *Meta, v *Visitor) bool {
c := v.Cursor()
switch c.Node().(type) {
case *ast.File:
for _, v := range t.GlobalVar {
fmt.Println(v)
}
for key, value := range t.Func {
fmt.Println(key)
for k, val := range value.Variables {
fmt.Println("\t", k)
fmt.Println("\t READ STMTS")
for statements, _ := range val.ReadStmt {
fmt.Println("\t\t", StmtNumberString(statements))
}
fmt.Println("\t WRITE STMTS")
for statements, _ := range val.WriteStmt {
fmt.Println("\t\t", StmtNumberString(statements))
}
fmt.Println("\t VARIABLES DEPENDENCIES")
for variables, _ := range val.VarDep {
fmt.Println("\t\t", variables)
}
println()
}
}
}
return true
}
func StmtNumberString(stmtsNmb *[]StmtNumber) string {
res := ""
for _, val := range *stmtsNmb {
if val.If_or_else {
res += "else "
}
res += strconv.Itoa(val.Number) + " "
}
return res
}
Supports Markdown
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