Skip to content

Commit

Permalink
fix: correct branch control flow graph for parenthesis expressions (#583
Browse files Browse the repository at this point in the history
)
  • Loading branch information
mvertes committed Apr 17, 2020
1 parent c580dfd commit 56925e6
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 25 deletions.
16 changes: 16 additions & 0 deletions _test/not0.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

func main() {
a := 0
b := true
c := false
if (b && c) {
a = 1
} else {
a = -1
}
println(a)
}

// Output:
// -1
15 changes: 15 additions & 0 deletions _test/not1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

func main() {
a := 0
b := true
if (!b) {
a = 1
} else {
a = -1
}
println(a)
}

// Output:
// -1
2 changes: 2 additions & 0 deletions interp/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ const (
aAndNot
aAndNotAssign
aBitNot
aBranch
aCall
aCase
aCompositeLit
Expand Down Expand Up @@ -253,6 +254,7 @@ var actions = [...]string{
aAndNot: "&^",
aAndNotAssign: "&^=",
aBitNot: "^",
aBranch: "branch",
aCall: "call",
aCase: "case",
aCompositeLit: "compositeLit",
Expand Down
52 changes: 27 additions & 25 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
cond.tnext = body.start
body.tnext = cond.start
}
cond.fnext = n
setFNext(cond, n)
sc = sc.pop()

case forStmt2: // for init; cond; {}
Expand All @@ -903,7 +903,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
body.tnext = cond.start
}
cond.tnext = body.start
cond.fnext = n
setFNext(cond, n)
sc = sc.pop()

case forStmt3: // for ; cond; post {}
Expand All @@ -922,7 +922,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
post.tnext = cond.start
}
cond.tnext = body.start
cond.fnext = n
setFNext(cond, n)
body.tnext = post.start
sc = sc.pop()

Expand Down Expand Up @@ -953,13 +953,13 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
post.tnext = cond.start
}
cond.tnext = body.start
cond.fnext = n
setFNext(cond, n)
body.tnext = post.start
sc = sc.pop()

case forRangeStmt:
n.start = n.child[0].start
n.child[0].fnext = n
setFNext(n.child[0], n)
sc = sc.pop()

case funcDecl:
Expand Down Expand Up @@ -1010,9 +1010,6 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
err = n.cfgErrorf("use of builtin %s not in function call", n.ident)
}
}
if sym.kind == varSym && sym.typ != nil && sym.typ.TypeOf().Kind() == reflect.Bool {
fixBranch(n)
}
}
if n.sym != nil {
n.recv = n.sym.recv
Expand All @@ -1035,7 +1032,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
n.start = cond.start
cond.tnext = tbody.start
}
cond.fnext = n
setFNext(cond, n)
tbody.tnext = n
sc = sc.pop()

Expand All @@ -1054,7 +1051,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
} else {
n.start = cond.start
cond.tnext = tbody.start
cond.fnext = fbody.start
setFNext(cond, fbody.start)
}
tbody.tnext = n
fbody.tnext = n
Expand All @@ -1078,7 +1075,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
cond.tnext = tbody.start
}
tbody.tnext = n
cond.fnext = n
setFNext(cond, n)
sc = sc.pop()

case ifStmt3: // if init; cond {} else {}
Expand All @@ -1097,7 +1094,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
} else {
init.tnext = cond.start
cond.tnext = tbody.start
cond.fnext = fbody.start
setFNext(cond, fbody.start)
}
tbody.tnext = n
fbody.tnext = n
Expand All @@ -1109,7 +1106,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
case landExpr:
n.start = n.child[0].start
n.child[0].tnext = n.child[1].start
n.child[0].fnext = n
setFNext(n.child[0], n)
n.child[1].tnext = n
n.typ = n.child[0].typ
n.findex = sc.add(n.typ)
Expand All @@ -1120,7 +1117,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
case lorExpr:
n.start = n.child[0].start
n.child[0].tnext = n
n.child[0].fnext = n.child[1].start
setFNext(n.child[0], n.child[1].start)
n.child[1].tnext = n
n.typ = n.child[0].typ
n.findex = sc.add(n.typ)
Expand Down Expand Up @@ -1423,7 +1420,8 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
}
// Chain case clauses.
for i, c := range clauses[:l-1] {
c.fnext = clauses[i+1] // Chain to next clause.
// Chain to next clause.
setFNext(c, clauses[i+1])
if len(c.child) == 0 {
c.tnext = n // Clause body is empty, exit.
} else {
Expand Down Expand Up @@ -1472,9 +1470,9 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
cond := c.child[0]
cond.tnext = body.start
if i == l-1 {
cond.fnext = n
setFNext(cond, n)
} else {
cond.fnext = clauses[i+1].start
setFNext(cond, clauses[i+1].start)
}
c.start = cond.start
} else {
Expand Down Expand Up @@ -1703,15 +1701,19 @@ func genRun(nod *node) error {
return err
}

// FixBranch sets the branch action to the identExpr node if it is a bool
// used in a conditional expression.
func fixBranch(n *node) {
switch n.anc.kind {
case ifStmt0, ifStmt1, ifStmt2, ifStmt3, forStmt1, forStmt2, forStmt3, forStmt4:
n.gen = branch
case parenExpr:
fixBranch(n.anc)
// setFnext sets the cond fnext field to next, propagates it for parenthesis blocks
// and sets the action to branch.
func setFNext(cond, next *node) {
if cond.action == aNop {
cond.action = aBranch
cond.gen = branch
cond.fnext = next
}
if cond.kind == parenExpr {
setFNext(cond.lastChild(), next)
return
}
cond.fnext = next
}

// GetDefault return the index of default case clause in a switch statement, or -1.
Expand Down

0 comments on commit 56925e6

Please sign in to comment.