From 739db2c4444e28f09008b9b7423779c27293dd75 Mon Sep 17 00:00:00 2001 From: mappu Date: Sun, 12 Apr 2020 14:42:01 +1200 Subject: [PATCH] move MutatingWalker to new subpackage, exhaustively implement all cases --- main.go | 11 +- mutatingwalker.go | 54 -- normalisealts.go | 6 +- exhaustive.go => parseutil/Exhaustive.go | 6 +- parseutil/MutatingWalker.go | 1086 ++++++++++++++++++++++ 5 files changed, 1105 insertions(+), 58 deletions(-) delete mode 100644 mutatingwalker.go rename exhaustive.go => parseutil/Exhaustive.go (99%) create mode 100644 parseutil/MutatingWalker.go diff --git a/main.go b/main.go index f876288..809bedc 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,8 @@ import ( "github.com/z7zmey/php-parser/parser" "github.com/z7zmey/php-parser/visitor" + + "php2go/parseutil" ) func ConvertFile(filename string) (string, error) { @@ -48,7 +50,14 @@ func ConvertFile(filename string) (string, error) { } // Pass 1: Normalise Alt** Stmt types - walkMutate(&n, normaliseAltCb) + normaliser := parseutil.MutatingWalker{ + EnterNode: normaliseAltCb, + LeaveNode: parseutil.MutatingWalkerNoop, + } + err = normaliser.Walk(&n) + if err != nil { + return "", err + } // 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 { diff --git a/mutatingwalker.go b/mutatingwalker.go deleted file mode 100644 index 4af95e8..0000000 --- a/mutatingwalker.go +++ /dev/null @@ -1,54 +0,0 @@ -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)) - - } - -} diff --git a/normalisealts.go b/normalisealts.go index c7c7437..d31533c 100644 --- a/normalisealts.go +++ b/normalisealts.go @@ -9,7 +9,7 @@ import ( //"github.com/z7zmey/php-parser/walker" ) -func normaliseAltCb(n_ *node.Node) { +func normaliseAltCb(n_ *node.Node) error { switch n := (*n_).(type) { case *stmt.AltIf: @@ -36,6 +36,8 @@ func normaliseAltCb(n_ *node.Node) { *n_ = elifStmt default: - return // no change + // no change } + + return nil // always } diff --git a/exhaustive.go b/parseutil/Exhaustive.go similarity index 99% rename from exhaustive.go rename to parseutil/Exhaustive.go index 8410339..30fe3e6 100644 --- a/exhaustive.go +++ b/parseutil/Exhaustive.go @@ -1,4 +1,4 @@ -package main +package parseutil import ( "fmt" @@ -215,6 +215,10 @@ type Exhaustive interface { func switchExhaustive(e Exhaustive, n_ *node.Node) error { n := *n_ // no copy + if n == nil { + return nil // inner handlers expect a non-nil pointer + } + switch n := n.(type) { // node diff --git a/parseutil/MutatingWalker.go b/parseutil/MutatingWalker.go new file mode 100644 index 0000000..e57fb68 --- /dev/null +++ b/parseutil/MutatingWalker.go @@ -0,0 +1,1086 @@ +package parseutil + +import ( + "errors" + "fmt" + "reflect" + + "github.com/z7zmey/php-parser/node" + "github.com/z7zmey/php-parser/node/expr" + "github.com/z7zmey/php-parser/node/expr/assign" + "github.com/z7zmey/php-parser/node/expr/binary" + "github.com/z7zmey/php-parser/node/expr/cast" + "github.com/z7zmey/php-parser/node/name" + "github.com/z7zmey/php-parser/node/scalar" + "github.com/z7zmey/php-parser/node/stmt" +) + +func MutatingWalkerNoop(n *node.Node) error { return nil } + +var ( + ErrDoNotWalkDeeper = errors.New("ErrDoNotWalkDeeper") +) + +// MutatingWalker walks the AST by pointer to interface. +// This allows for modification of interior AST nodes while walking, unlike the +// upstream php-parser.Walker() interface that walks by value. +type MutatingWalker struct { + EnterNode func(n *node.Node) error + LeaveNode func(n *node.Node) error +} + +// + +func (mw MutatingWalker) walkEach(pNodes ...*node.Node) error { + for _, pNode := range pNodes { + err := mw.walkSingle(pNode) + if err != nil { + return err + } + } + return nil +} + +func (mw MutatingWalker) walkSlice(arr []node.Node) error { + for idx, _ := range arr { + err := mw.walkSingle(&arr[idx]) + if err != nil { + return err + } + } + return nil +} + +func (mw MutatingWalker) walkSingle(n *node.Node) error { + err := mw.EnterNode(n) + if err != nil { + if err == ErrDoNotWalkDeeper { + return nil + } + return err + } + + if *n == nil || reflect.ValueOf(*n).IsNil() { + // don't enter it + + } else { + err = switchExhaustive(mw, n) + if err != nil { + return err + } + } + + err = mw.LeaveNode(n) + if err != nil { + return err + } + + return nil +} + +// node + +func (mw MutatingWalker) handleNodeRoot(n *node.Root) error { + return mw.walkSlice(n.Stmts) +} + +func (mw MutatingWalker) handleNodeIdentifier(n *node.Identifier) error { + return nil +} + +func (mw MutatingWalker) handleNodeParameter(n *node.Parameter) error { + return mw.walkEach(&n.DefaultValue, &n.Variable, &n.VariableType) +} + +func (mw MutatingWalker) handleNodeNullable(n *node.Nullable) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleNodeArgument(n *node.Argument) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleNodeArgumentList(n *node.ArgumentList) error { + return mw.walkSlice(n.Arguments) +} + +// name + +func (mw MutatingWalker) handleNameNamePart(n *name.NamePart) error { + return nil +} + +func (mw MutatingWalker) handleNameName(n *name.Name) error { + return mw.walkSlice(n.Parts) +} + +func (mw MutatingWalker) handleNameFullyQualified(n *name.FullyQualified) error { + return mw.walkSlice(n.Parts) +} + +func (mw MutatingWalker) handleNameRelative(n *name.Relative) error { + return mw.walkSlice(n.Parts) +} + +// scalar + +func (mw MutatingWalker) handleScalarLnumber(n *scalar.Lnumber) error { + return nil +} + +func (mw MutatingWalker) handleScalarDnumber(n *scalar.Dnumber) error { + return nil +} + +func (mw MutatingWalker) handleScalarString(n *scalar.String) error { + return nil +} + +func (mw MutatingWalker) handleScalarEncapsedStringPart(n *scalar.EncapsedStringPart) error { + return nil +} + +func (mw MutatingWalker) handleScalarEncapsed(n *scalar.Encapsed) error { + return mw.walkSlice(n.Parts) +} + +func (mw MutatingWalker) handleScalarHeredoc(n *scalar.Heredoc) error { + return mw.walkSlice(n.Parts) +} + +func (mw MutatingWalker) handleScalarMagicConstant(n *scalar.MagicConstant) error { + return nil +} + +// assign + +func (mw MutatingWalker) handleAssign(n *assign.Assign) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignReference(n *assign.Reference) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignBitwiseAnd(n *assign.BitwiseAnd) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignBitwiseOr(n *assign.BitwiseOr) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignBitwiseXor(n *assign.BitwiseXor) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignCoalesce(n *assign.Coalesce) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignConcat(n *assign.Concat) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignDiv(n *assign.Div) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignMinus(n *assign.Minus) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignMod(n *assign.Mod) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignMul(n *assign.Mul) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignPlus(n *assign.Plus) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignPow(n *assign.Pow) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignShiftLeft(n *assign.ShiftLeft) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +func (mw MutatingWalker) handleAssignShiftRight(n *assign.ShiftRight) error { + return mw.walkEach(&n.Variable, &n.Expression) +} + +// binary + +func (mw MutatingWalker) handleBinaryBitwiseAnd(n *binary.BitwiseAnd) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryBitwiseOr(n *binary.BitwiseOr) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryBitwiseXor(n *binary.BitwiseXor) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryBooleanAnd(n *binary.BooleanAnd) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryBooleanOr(n *binary.BooleanOr) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryCoalesce(n *binary.Coalesce) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryConcat(n *binary.Concat) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryDiv(n *binary.Div) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryEqual(n *binary.Equal) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryGreaterOrEqual(n *binary.GreaterOrEqual) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryGreater(n *binary.Greater) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryIdentical(n *binary.Identical) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryLogicalAnd(n *binary.LogicalAnd) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryLogicalOr(n *binary.LogicalOr) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryLogicalXor(n *binary.LogicalXor) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryMinus(n *binary.Minus) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryMod(n *binary.Mod) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryMul(n *binary.Mul) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryNotEqual(n *binary.NotEqual) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryNotIdentical(n *binary.NotIdentical) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryPlus(n *binary.Plus) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryPow(n *binary.Pow) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryShiftLeft(n *binary.ShiftLeft) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinaryShiftRight(n *binary.ShiftRight) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinarySmallerOrEqual(n *binary.SmallerOrEqual) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinarySmaller(n *binary.Smaller) error { + return mw.walkEach(&n.Left, &n.Right) +} + +func (mw MutatingWalker) handleBinarySpaceship(n *binary.Spaceship) error { + return mw.walkEach(&n.Left, &n.Right) +} + +// cast + +func (mw MutatingWalker) handleCastArray(n *cast.Array) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleCastBool(n *cast.Bool) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleCastDouble(n *cast.Double) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleCastInt(n *cast.Int) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleCastObject(n *cast.Object) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleCastString(n *cast.String) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleCastUnset(n *cast.Unset) error { + return mw.walkSingle(&n.Expr) +} + +// expr + +func (mw MutatingWalker) handleExprArrayDimFetch(n *expr.ArrayDimFetch) error { + return mw.walkEach(&n.Dim, &n.Variable) +} + +func (mw MutatingWalker) handleExprArrayItem(n *expr.ArrayItem) error { + return mw.walkEach(&n.Key, &n.Val) +} + +func (mw MutatingWalker) handleExprArray(n *expr.Array) error { + return mw.walkSlice(n.Items) +} + +func (mw MutatingWalker) handleExprArrowFunction(n *expr.ArrowFunction) error { + err := mw.walkSlice(n.Params) + if err != nil { + return err + } + + return mw.walkEach(&n.Expr, &n.ReturnType) +} + +func (mw MutatingWalker) handleExprBitwiseNot(n *expr.BitwiseNot) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprBooleanNot(n *expr.BooleanNot) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprClassConstFetch(n *expr.ClassConstFetch) error { + return mw.walkEach(&n.Class, &n.ConstantName) +} + +func (mw MutatingWalker) handleExprClone(n *expr.Clone) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprClosureUse(n *expr.ClosureUse) error { + return mw.walkSlice(n.Uses) +} + +func (mw MutatingWalker) handleExprClosure(n *expr.Closure) error { + err := mw.walkSlice(n.Params) + if err != nil { + return err + } + err = mw.walkSlice(n.Stmts) + if err != nil { + return err + } + + // n.ClosureUse is not boxed as a node.Node + // Box it, and then reinstate it after we have handled all *node.Node types + + var boxedClosureUse node.Node = n.ClosureUse + err = mw.walkEach(&boxedClosureUse, &n.ReturnType) + if err != nil { + return err + } + + cu, ok := boxedClosureUse.(*expr.ClosureUse) + if !ok { + return fmt.Errorf("illegal modification from '*expr.ClosureUse' to incompatible type '%t'", boxedClosureUse) + } + n.ClosureUse = cu // reinstate + + // Done + return nil +} + +func (mw MutatingWalker) handleExprConstFetch(n *expr.ConstFetch) error { + return mw.walkSingle(&n.Constant) +} + +func (mw MutatingWalker) handleExprEmpty(n *expr.Empty) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprErrorSuppress(n *expr.ErrorSuppress) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprEval(n *expr.Eval) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprExit(n *expr.Exit) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprFunctionCall(n *expr.FunctionCall) error { + var boxedArgumentList node.Node = n.ArgumentList + + err := mw.walkEach(&boxedArgumentList, &n.Function) + if err != nil { + return err + } + + al, ok := boxedArgumentList.(*node.ArgumentList) + if !ok { + return fmt.Errorf("illegal modification from '*node.ArgumentList' to incompatible type '%t'", boxedArgumentList) + } + n.ArgumentList = al // reinstate + + return nil +} + +func (mw MutatingWalker) handleExprInclude(n *expr.Include) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprIncludeOnce(n *expr.IncludeOnce) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprInstanceOf(n *expr.InstanceOf) error { + return mw.walkEach(&n.Class, &n.Expr) +} + +func (mw MutatingWalker) handleExprIsset(n *expr.Isset) error { + return mw.walkSlice(n.Variables) +} + +func (mw MutatingWalker) handleExprList(n *expr.List) error { + return mw.walkSlice(n.Items) +} + +func (mw MutatingWalker) handleExprMethodCall(n *expr.MethodCall) error { + var boxedArgumentList node.Node = n.ArgumentList + + err := mw.walkEach(&boxedArgumentList, &n.Method, &n.Variable) + if err != nil { + return err + } + + al, ok := boxedArgumentList.(*node.ArgumentList) + if !ok { + return fmt.Errorf("illegal modification from '*node.ArgumentList' to incompatible type '%t'", boxedArgumentList) + } + n.ArgumentList = al // reinstate + + return nil +} + +func (mw MutatingWalker) handleExprNew(n *expr.New) error { + var boxedArgumentList node.Node = n.ArgumentList + + err := mw.walkEach(&boxedArgumentList, &n.Class) + if err != nil { + return err + } + + al, ok := boxedArgumentList.(*node.ArgumentList) + if !ok { + return fmt.Errorf("illegal modification from '*node.ArgumentList' to incompatible type '%t'", boxedArgumentList) + } + n.ArgumentList = al // reinstate + + return nil +} + +func (mw MutatingWalker) handleExprPostDec(n *expr.PostDec) error { + return mw.walkSingle(&n.Variable) +} + +func (mw MutatingWalker) handleExprPostInc(n *expr.PostInc) error { + return mw.walkSingle(&n.Variable) +} + +func (mw MutatingWalker) handleExprPreDec(n *expr.PreDec) error { + return mw.walkSingle(&n.Variable) +} + +func (mw MutatingWalker) handleExprPreInc(n *expr.PreInc) error { + return mw.walkSingle(&n.Variable) +} + +func (mw MutatingWalker) handleExprPrint(n *expr.Print) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprPropertyFetch(n *expr.PropertyFetch) error { + return mw.walkEach(&n.Property, &n.Variable) +} + +func (mw MutatingWalker) handleExprReference(n *expr.Reference) error { + return mw.walkSingle(&n.Variable) +} + +func (mw MutatingWalker) handleExprRequire(n *expr.Require) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprRequireOnce(n *expr.RequireOnce) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprShellExec(n *expr.ShellExec) error { + return mw.walkSlice(n.Parts) +} + +func (mw MutatingWalker) handleExprShortArray(n *expr.ShortArray) error { + return mw.walkSlice(n.Items) +} + +func (mw MutatingWalker) handleExprShortList(n *expr.ShortList) error { + return mw.walkSlice(n.Items) +} + +func (mw MutatingWalker) handleExprStaticCall(n *expr.StaticCall) error { + var boxedArgumentList node.Node = n.ArgumentList + + err := mw.walkEach(&boxedArgumentList, &n.Call, &n.Class) + if err != nil { + return err + } + + al, ok := boxedArgumentList.(*node.ArgumentList) + if !ok { + return fmt.Errorf("illegal modification from '*node.ArgumentList' to incompatible type '%t'", boxedArgumentList) + } + n.ArgumentList = al // reinstate + + return nil +} + +func (mw MutatingWalker) handleExprStaticPropertyFetch(n *expr.StaticPropertyFetch) error { + return mw.walkEach(&n.Class, &n.Property) +} + +func (mw MutatingWalker) handleExprTernary(n *expr.Ternary) error { + return mw.walkEach(&n.Condition, &n.IfTrue, &n.IfFalse) +} + +func (mw MutatingWalker) handleExprUnaryMinus(n *expr.UnaryMinus) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprUnaryPlus(n *expr.UnaryPlus) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprVariable(n *expr.Variable) error { + return mw.walkSingle(&n.VarName) +} + +func (mw MutatingWalker) handleExprYieldFrom(n *expr.YieldFrom) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleExprYield(n *expr.Yield) error { + return mw.walkEach(&n.Key, &n.Value) +} + +// stmt + +func (mw MutatingWalker) handleStmtAltElse(n *stmt.AltElse) error { + return mw.walkSingle(&n.Stmt) +} + +func (mw MutatingWalker) handleStmtAltElseIf(n *stmt.AltElseIf) error { + return mw.walkEach(&n.Cond, &n.Stmt) +} + +func (mw MutatingWalker) handleStmtAltFor(n *stmt.AltFor) error { + err := mw.walkSlice(n.Cond) + if err != nil { + return err + } + + err = mw.walkSlice(n.Init) + if err != nil { + return err + } + + err = mw.walkSlice(n.Loop) + if err != nil { + return err + } + + return mw.walkSingle(&n.Stmt) +} + +func (mw MutatingWalker) handleStmtAltForeach(n *stmt.AltForeach) error { + return mw.walkEach(&n.Expr, &n.Key, &n.Stmt, &n.Variable) +} + +func (mw MutatingWalker) handleStmtAltIf(n *stmt.AltIf) error { + err := mw.walkSlice(n.ElseIf) + if err != nil { + return err + } + + return mw.walkEach(&n.Cond, &n.Else, &n.Stmt) +} + +func (mw MutatingWalker) handleStmtAltSwitch(n *stmt.AltSwitch) error { + var boxedCaseList node.Node = n.CaseList + + err := mw.walkEach(&boxedCaseList, &n.Cond) + if err != nil { + return err + } + + cl, ok := boxedCaseList.(*stmt.CaseList) + if !ok { + return fmt.Errorf("illegal modification from '*stmt.CaseList' to incompatible type '%t'", boxedCaseList) + } + n.CaseList = cl // reinstate + + return nil +} + +func (mw MutatingWalker) handleStmtAltWhile(n *stmt.AltWhile) error { + return mw.walkEach(&n.Cond, &n.Stmt) +} + +func (mw MutatingWalker) handleStmtBreak(n *stmt.Break) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleStmtCase(n *stmt.Case) error { + err := mw.walkSlice(n.Stmts) + if err != nil { + return err + } + + return mw.walkSingle(&n.Cond) +} + +func (mw MutatingWalker) handleStmtCaseList(n *stmt.CaseList) error { + return mw.walkSlice(n.Cases) +} + +func (mw MutatingWalker) handleStmtCatch(n *stmt.Catch) error { + err := mw.walkSlice(n.Types) + if err != nil { + return err + } + + err = mw.walkSingle(&n.Variable) + if err != nil { + return err + } + + return mw.walkSlice(n.Stmts) +} + +func (mw MutatingWalker) handleStmtClass(n *stmt.Class) error { + var ( + boxedArgumentList node.Node = n.ArgumentList + boxedClassExtends node.Node = n.Extends + boxedClassImplements node.Node = n.Implements + ) + + err := mw.walkEach(&n.ClassName, &boxedArgumentList, &boxedClassExtends, &boxedClassImplements) + if err != nil { + return err + } + + al, ok := boxedArgumentList.(*node.ArgumentList) + if !ok { + return fmt.Errorf("illegal modification from '*node.ArgumentList' to incompatible type '%t'", boxedArgumentList) + } + n.ArgumentList = al // reinstate + + ce, ok := boxedClassExtends.(*stmt.ClassExtends) + if !ok { + return fmt.Errorf("illegal modification from '*stmt.ClassExtends' to incompatible type '%t'", boxedClassExtends) + } + n.Extends = ce // reinstate + + ci, ok := boxedClassImplements.(*stmt.ClassImplements) + if !ok { + return fmt.Errorf("illegal modification from '*stmt.ClassImplements' to incompatible type '%t'", boxedClassImplements) + } + n.Implements = ci // reinstate + + // + + err = mw.walkSlice(n.Modifiers) + if err != nil { + return err + } + + return mw.walkSlice(n.Stmts) +} + +func (mw MutatingWalker) handleStmtClassExtends(n *stmt.ClassExtends) error { + return mw.walkSingle(&n.ClassName) +} + +func (mw MutatingWalker) handleStmtClassImplements(n *stmt.ClassImplements) error { + return mw.walkSlice(n.InterfaceNames) +} + +func (mw MutatingWalker) handleStmtClassMethod(n *stmt.ClassMethod) error { + err := mw.walkEach(&n.MethodName, &n.ReturnType) + if err != nil { + return err + } + + err = mw.walkSlice(n.Modifiers) + if err != nil { + return err + } + + err = mw.walkSlice(n.Params) + if err != nil { + return err + } + + return mw.walkSingle(&n.Stmt) // we could have embedded it in the leading walkEach, but, try and keep the ordering a little bit +} + +func (mw MutatingWalker) handleStmtClassConstList(n *stmt.ClassConstList) error { + err := mw.walkSlice(n.Modifiers) + if err != nil { + return err + } + + return mw.walkSlice(n.Consts) +} + +func (mw MutatingWalker) handleStmtConstList(n *stmt.ConstList) error { + return mw.walkSlice(n.Consts) +} + +func (mw MutatingWalker) handleStmtConstant(n *stmt.Constant) error { + return mw.walkEach(&n.ConstantName, &n.Expr) +} + +func (mw MutatingWalker) handleStmtContinue(n *stmt.Continue) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleStmtDeclare(n *stmt.Declare) error { + err := mw.walkSlice(n.Consts) + if err != nil { + return err + } + + return mw.walkSingle(&n.Stmt) +} + +func (mw MutatingWalker) handleStmtDefault(n *stmt.Default) error { + return mw.walkSlice(n.Stmts) +} + +func (mw MutatingWalker) handleStmtDo(n *stmt.Do) error { + return mw.walkEach(&n.Stmt, &n.Cond) +} + +func (mw MutatingWalker) handleStmtEcho(n *stmt.Echo) error { + return mw.walkSlice(n.Exprs) +} + +func (mw MutatingWalker) handleStmtElseIf(n *stmt.ElseIf) error { + return mw.walkEach(&n.Cond, &n.Stmt) +} + +func (mw MutatingWalker) handleStmtElse(n *stmt.Else) error { + return mw.walkEach(&n.Stmt) +} + +func (mw MutatingWalker) handleStmtExpression(n *stmt.Expression) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleStmtFinally(n *stmt.Finally) error { + return mw.walkSlice(n.Stmts) +} + +func (mw MutatingWalker) handleStmtFor(n *stmt.For) error { + err := mw.walkSlice(n.Cond) + if err != nil { + return err + } + + err = mw.walkSlice(n.Init) + if err != nil { + return err + } + + err = mw.walkSlice(n.Loop) + if err != nil { + return err + } + + return mw.walkSingle(&n.Stmt) +} + +func (mw MutatingWalker) handleStmtForeach(n *stmt.Foreach) error { + return mw.walkEach(&n.Expr, &n.Key, &n.Stmt, &n.Variable) +} + +func (mw MutatingWalker) handleStmtFunction(n *stmt.Function) error { + err := mw.walkEach(&n.FunctionName, &n.ReturnType) + if err != nil { + return err + } + + err = mw.walkSlice(n.Params) + if err != nil { + return err + } + + return mw.walkSlice(n.Stmts) +} + +func (mw MutatingWalker) handleStmtGlobal(n *stmt.Global) error { + return mw.walkSlice(n.Vars) +} + +func (mw MutatingWalker) handleStmtGoto(n *stmt.Goto) error { + return mw.walkSingle(&n.Label) +} + +func (mw MutatingWalker) handleStmtGroupUse(n *stmt.GroupUse) error { + err := mw.walkEach(&n.Prefix, &n.UseType) + if err != nil { + return err + } + + return mw.walkSlice(n.UseList) +} + +func (mw MutatingWalker) handleStmtHaltCompiler(n *stmt.HaltCompiler) error { + return nil +} + +func (mw MutatingWalker) handleStmtIf(n *stmt.If) error { + err := mw.walkEach(&n.Cond, &n.Stmt) + if err != nil { + return err + } + + err = mw.walkSlice(n.ElseIf) + if err != nil { + return err + } + + return mw.walkSingle(&n.Else) +} + +func (mw MutatingWalker) handleStmtInlineHtml(n *stmt.InlineHtml) error { + return nil +} + +func (mw MutatingWalker) handleStmtInterface(n *stmt.Interface) error { + var boxedInterfaceExtends node.Node = n.Extends + + err := mw.walkEach(&n.InterfaceName, &boxedInterfaceExtends) + if err != nil { + return err + } + + ie, ok := boxedInterfaceExtends.(*stmt.InterfaceExtends) + if !ok { + return fmt.Errorf("illegal modification from '*stmt.InterfaceExtends' to incompatible type '%t'", boxedInterfaceExtends) + } + n.Extends = ie // reinstate + + // + + return mw.walkSlice(n.Stmts) +} + +func (mw MutatingWalker) handleStmtInterfaceExtends(n *stmt.InterfaceExtends) error { + return mw.walkSlice(n.InterfaceNames) +} + +func (mw MutatingWalker) handleStmtLabel(n *stmt.Label) error { + return mw.walkSingle(&n.LabelName) +} + +func (mw MutatingWalker) handleStmtNamespace(n *stmt.Namespace) error { + err := mw.walkSingle(&n.NamespaceName) + if err != nil { + return err + } + + return mw.walkSlice(n.Stmts) +} + +func (mw MutatingWalker) handleStmtNop(n *stmt.Nop) error { + return nil +} + +func (mw MutatingWalker) handleStmtPropertyList(n *stmt.PropertyList) error { + err := mw.walkSlice(n.Modifiers) + if err != nil { + return err + } + + err = mw.walkSingle(&n.Type) + if err != nil { + return err + } + + return mw.walkSlice(n.Properties) +} + +func (mw MutatingWalker) handleStmtProperty(n *stmt.Property) error { + return mw.walkEach(&n.Expr, &n.Variable) +} + +func (mw MutatingWalker) handleStmtReturn(n *stmt.Return) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleStmtStaticVar(n *stmt.StaticVar) error { + return mw.walkEach(&n.Variable, &n.Expr) +} + +func (mw MutatingWalker) handleStmtStatic(n *stmt.Static) error { + return mw.walkSlice(n.Vars) +} + +func (mw MutatingWalker) handleStmtStmtList(n *stmt.StmtList) error { + for i, _ := range n.Stmts { + mw.walkSingle(&n.Stmts[i]) + } + return nil +} + +func (mw MutatingWalker) handleStmtSwitch(n *stmt.Switch) error { + var boxedCaseList node.Node = n.CaseList + + err := mw.walkEach(&boxedCaseList, &n.Cond) + if err != nil { + return err + } + + cl, ok := boxedCaseList.(*stmt.CaseList) + if !ok { + return fmt.Errorf("illegal modification from '*stmt.CaseList' to incompatible type '%t'", boxedCaseList) + } + n.CaseList = cl // reinstate + + return nil +} + +func (mw MutatingWalker) handleStmtThrow(n *stmt.Throw) error { + return mw.walkSingle(&n.Expr) +} + +func (mw MutatingWalker) handleStmtTraitAdaptationList(n *stmt.TraitAdaptationList) error { + return mw.walkSlice(n.Adaptations) +} + +func (mw MutatingWalker) handleStmtTraitMethodRef(n *stmt.TraitMethodRef) error { + return mw.walkEach(&n.Method, &n.Trait) +} + +func (mw MutatingWalker) handleStmtTraitUseAlias(n *stmt.TraitUseAlias) error { + return mw.walkEach(&n.Alias, &n.Modifier, &n.Ref) +} + +func (mw MutatingWalker) handleStmtTraitUsePrecedence(n *stmt.TraitUsePrecedence) error { + err := mw.walkSlice(n.Insteadof) + if err != nil { + return err + } + + return mw.walkSingle(&n.Ref) +} + +func (mw MutatingWalker) handleStmtTraitUse(n *stmt.TraitUse) error { + err := mw.walkSingle(&n.TraitAdaptationList) + if err != nil { + return err + } + + return mw.walkSlice(n.Traits) +} + +func (mw MutatingWalker) handleStmtTrait(n *stmt.Trait) error { + err := mw.walkSingle(&n.TraitName) + if err != nil { + return err + } + + return mw.walkSlice(n.Stmts) +} + +func (mw MutatingWalker) handleStmtTry(n *stmt.Try) error { + err := mw.walkSlice(n.Stmts) + if err != nil { + return err + } + + err = mw.walkSlice(n.Catches) + if err != nil { + return err + } + + return mw.walkSingle(&n.Finally) +} + +func (mw MutatingWalker) handleStmtUnset(n *stmt.Unset) error { + return mw.walkSlice(n.Vars) +} + +func (mw MutatingWalker) handleStmtUseList(n *stmt.UseList) error { + err := mw.walkSlice(n.Uses) + if err != nil { + return err + } + + return mw.walkSingle(&n.UseType) +} + +func (mw MutatingWalker) handleStmtUse(n *stmt.Use) error { + return mw.walkEach(&n.Alias, &n.Use, &n.UseType) +} + +func (mw MutatingWalker) handleStmtWhile(n *stmt.While) error { + return mw.walkEach(&n.Cond, &n.Stmt) +} + +var _ Exhaustive = MutatingWalker{} // interface assertion + +// + +func (mw MutatingWalker) Walk(n *node.Node) error { + return mw.walkSingle(n) +}