implement walkMutate(*node); completely transform AltIf->If

This commit is contained in:
mappu 2020-04-10 17:37:59 +12:00
parent 6d9aa8b022
commit df2fc21324
4 changed files with 74 additions and 73 deletions

View File

@ -28,3 +28,11 @@ endif;
// Unbraced
if (true) echo "100";
// Colon style within deeper scope
{{{{
if (1 == 1):
echo "asdf";
endif;
}}}}

View File

@ -48,8 +48,7 @@ func ConvertFile(filename string) (string, error) {
}
// Pass 1: Normalise Alt** Stmt types
normPass := normaliseAltsPass{}
n.Walk(&normPass) // can't modify root node, but that's fine
walkMutate(&n, normaliseAltCb)
// Debug pass: Walk and print JSON...
if fh, err := os.OpenFile(filename+`.parse2.json`, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644); err == nil {

54
mutatingwalker.go Normal file
View File

@ -0,0 +1,54 @@
package main
import (
// "fmt"
//"io/ioutil"
"github.com/z7zmey/php-parser/node"
"github.com/z7zmey/php-parser/node/stmt"
//"github.com/z7zmey/php-parser/walker"
)
func walkMutate(n_ *node.Node, cb func(*node.Node)) {
// Mutate in-place, non recursive...
cb(n_)
// Walk on the mutated version
// We must reimplement .Walk() in order to get pointer behaviour
switch n := (*n_).(type) {
case *stmt.StmtList:
for i, _ := range n.Stmts {
walkMutate(&n.Stmts[i], cb)
}
case *node.Root:
for i, _ := range n.Stmts {
walkMutate(&n.Stmts[i], cb)
}
case *stmt.If:
walkMutate(&n.Cond, cb)
walkMutate(&n.Else, cb)
for i, _ := range n.ElseIf {
walkMutate(&n.ElseIf[i], cb)
}
walkMutate(&n.Stmt, cb)
case *stmt.Else:
walkMutate(&n.Stmt, cb)
case *stmt.ElseIf:
walkMutate(&n.Cond, cb)
walkMutate(&n.Stmt, cb)
default:
// FIXME need to implement Walk() for all node types, to ensure that
// we can perform mutation transforms in nested contexts
// bail
//panic(fmt.Sprintf("walkMutate: unimplemented type '%t'", n))
}
}

View File

@ -1,101 +1,41 @@
package main
import (
"fmt"
//"fmt"
//"io/ioutil"
"github.com/z7zmey/php-parser/node"
"github.com/z7zmey/php-parser/node/stmt"
"github.com/z7zmey/php-parser/walker"
//"github.com/z7zmey/php-parser/walker"
)
type normaliseAltsPass struct {
}
func normaliseAltCb(n_ *node.Node) {
func (np *normaliseAltsPass) transformNonRecursive(n node.Node) (node.Node, bool) {
switch n := n.(type) {
switch n := (*n_).(type) {
case *stmt.AltIf:
// Build replacement node
ifStmt := stmt.NewIf(n.Cond, n.Stmt, n.ElseIf, n.Else)
ifStmt.FreeFloating = n.FreeFloating
ifStmt.Position = n.Position
// ifStmt has no .Attributes prop
return ifStmt, true
*n_ = ifStmt
case *stmt.AltElse:
elseStmt := stmt.NewElse(n.Stmt)
elseStmt.FreeFloating = n.FreeFloating
elseStmt.Position = n.Position
return elseStmt, true
*n_ = elseStmt
case *stmt.AltElseIf:
elifStmt := stmt.NewElseIf(n.Cond, n.Stmt)
elifStmt.FreeFloating = n.FreeFloating
elifStmt.Position = n.Position
return elifStmt, true
*n_ = elifStmt
default:
return n, false // no change
return // no change
}
}
func (np *normaliseAltsPass) walkMutateArray(stmts []node.Node) {
for i, _ := range stmts {
np.walkMutate(&stmts[i])
}
}
func (np *normaliseAltsPass) walkMutate(child *node.Node) {
v2, didChange := np.transformNonRecursive(*child)
if didChange {
v2.Walk(np)
*child = v2
} else {
(*child).Walk(np)
}
}
func (np *normaliseAltsPass) EnterNode(w walker.Walkable) bool {
n, ok := w.(node.Node)
if !ok {
panic(fmt.Errorf("Tried to walk non-node '%t'", w))
}
// We need to override the .Walk() behaviour for all possible *parents*
// of affected nodes. This is because the .Walk() interface does not give
// us any opportunity to override single elements by the time we get there
// Our custom Walk() implementation is not firing all EnterChildList/LeaveNode
// visitors - but - that's fine since they're all noops anyway
switch n := n.(type) {
case *stmt.StmtList:
np.walkMutateArray(n.Stmts) // mutate slice in place
return false // Signal not to use upstream .Walk() implementation
case *node.Root:
np.walkMutateArray(n.Stmts) // mutate slice in place
return false // Signal not to use upstream .Walk() implementation
case *stmt.AltIf:
panic("altif")
np.walkMutate(&n.Cond)
np.walkMutateArray(n.ElseIf)
np.walkMutate(&n.Else)
return false
default:
// No normalisation needed for this node type
// Recurse deeper
return true
}
}
func (np *normaliseAltsPass) LeaveNode(w walker.Walkable) {}
func (np *normaliseAltsPass) EnterChildNode(key string, w walker.Walkable) {}
func (np *normaliseAltsPass) LeaveChildNode(key string, w walker.Walkable) {}
func (np *normaliseAltsPass) EnterChildList(key string, w walker.Walkable) {}
func (np *normaliseAltsPass) LeaveChildList(key string, w walker.Walkable) {}
var _ walker.Visitor = &normaliseAltsPass{} // interface assertion