node: bail out upon assignment inside if-expression

This commit is contained in:
mappu 2020-04-07 18:52:30 +12:00
parent 49241e7a8c
commit 315174c79a
3 changed files with 67 additions and 0 deletions

View File

@ -37,6 +37,8 @@ The goal is to produce idiomatic, maintainable Go code as part of a one-off conv
[ ] Assignment expressions
- Go doesn't support assignment in rvalues, only as a statement
- When walking below stmt level, need to first fully walk and check for any function calls + assignments that may need hoisting (and we can probably only do that correctly if there is no short-circuiting)
- [X] Add subtree walk + catch error for this case
- [ ] Add hoisting pass
[ ] Closures
- [ ] Handle value/reference captures
[ ] Sort callbacks

42
miniwalker.go Normal file
View File

@ -0,0 +1,42 @@
package main
import (
"fmt"
"github.com/z7zmey/php-parser/node"
"github.com/z7zmey/php-parser/walker"
)
type miniWalker struct {
cb func(node.Node) error
lastErr error
}
func (mw *miniWalker) EnterNode(w walker.Walkable) bool {
n, ok := w.(node.Node)
if !ok {
mw.lastErr = fmt.Errorf("Tried to walk non-node '%t'", w)
return false
}
err := mw.cb(n)
if err != nil {
mw.lastErr = err
return false
}
return true
}
func (mw *miniWalker) LeaveNode(w walker.Walkable) {}
func (mw *miniWalker) EnterChildNode(key string, w walker.Walkable) {}
func (mw *miniWalker) LeaveChildNode(key string, w walker.Walkable) {}
func (mw *miniWalker) EnterChildList(key string, w walker.Walkable) {}
func (mw *miniWalker) LeaveChildList(key string, w walker.Walkable) {}
func walk(n node.Node, cb func(node.Node) error) error {
mw := miniWalker{cb: cb}
n.Walk(&mw)
return mw.lastErr
}

23
node.go
View File

@ -511,6 +511,15 @@ func (this *conversionState) convertNoFreeFloating(n_ node.Node) (string, error)
return "fmt.Print(" + quoted + ")\n", nil // newline - standalone statement
case *stmt.If:
hasCondAssign, err := hasInteriorAssignment(n.Cond)
if err != nil {
return "", parseErr{n, err}
}
if hasCondAssign {
return "", parseErr{n.Cond, fmt.Errorf("please remove assignment from if-expression")}
}
cond, err := this.convert(n.Cond)
if err != nil {
return "", parseErr{n, err}
@ -1158,3 +1167,17 @@ func (this *conversionState) convertFunctionCommon(params []node.Node, returnTyp
// No extra trailing newline in case this is part of a large expression
return ret, nil
}
// hasInteriorAssignment recursively walks a node, to determine if it contains
// any assignment expressions
func hasInteriorAssignment(n node.Node) (hasAnyAssign bool, err error) {
err = walk(n, func(n node.Node) error {
if _, ok := n.(*assign.Assign); ok {
hasAnyAssign = true
}
return nil
})
return // named return
}