diff --git a/Makefile b/Makefile index ecf1a18..21556ef 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,14 @@ PHPFILE=example.php all: compile run -build: +build: gofmt -l -s -w **/*.go go build run: build ./php-parser $(PHPFILE) -test: build +test: go test ./... --cover compile: ./php5/php5.go ./php7/php7.go ./scanner/scanner.go diff --git a/node/stmt/n_alt_if.go b/node/stmt/n_alt_if.go index 86ab871..6d6a656 100644 --- a/node/stmt/n_alt_if.go +++ b/node/stmt/n_alt_if.go @@ -71,7 +71,7 @@ func (n *AltIf) Walk(v walker.Visitor) { } if n.Else != nil { - vv := v.GetChildrenVisitor("else") + vv := v.GetChildrenVisitor("Else") n.Else.Walk(vv) } diff --git a/node/stmt/n_do.go b/node/stmt/n_do.go index a5ca6f6..2cc42f9 100644 --- a/node/stmt/n_do.go +++ b/node/stmt/n_do.go @@ -31,15 +31,15 @@ func (n *Do) Walk(v walker.Visitor) { return } - if n.Cond != nil { - vv := v.GetChildrenVisitor("Cond") - n.Cond.Walk(vv) - } - if n.Stmt != nil { vv := v.GetChildrenVisitor("Stmt") n.Stmt.Walk(vv) } + if n.Cond != nil { + vv := v.GetChildrenVisitor("Cond") + n.Cond.Walk(vv) + } + v.LeaveNode(n) } diff --git a/node/stmt/n_group_use.go b/node/stmt/n_group_use.go index ca986b1..169a471 100644 --- a/node/stmt/n_group_use.go +++ b/node/stmt/n_group_use.go @@ -8,15 +8,15 @@ import ( // GroupUse node type GroupUse struct { UseType node.Node - pRefix node.Node + Prefix node.Node UseList []node.Node } // NewGroupUse node constuctor -func NewGroupUse(UseType node.Node, pRefix node.Node, UseList []node.Node) *GroupUse { +func NewGroupUse(UseType node.Node, Prefix node.Node, UseList []node.Node) *GroupUse { return &GroupUse{ UseType, - pRefix, + Prefix, UseList, } } @@ -43,9 +43,9 @@ func (n *GroupUse) Walk(v walker.Visitor) { n.UseType.Walk(vv) } - if n.pRefix != nil { - vv := v.GetChildrenVisitor("pRefix") - n.pRefix.Walk(vv) + if n.Prefix != nil { + vv := v.GetChildrenVisitor("Prefix") + n.Prefix.Walk(vv) } if n.UseList != nil { diff --git a/node/stmt/n_if.go b/node/stmt/n_if.go index c0f3ca3..4a45a0c 100644 --- a/node/stmt/n_if.go +++ b/node/stmt/n_if.go @@ -71,7 +71,7 @@ func (n *If) Walk(v walker.Visitor) { } if n.Else != nil { - vv := v.GetChildrenVisitor("else") + vv := v.GetChildrenVisitor("Else") n.Else.Walk(vv) } diff --git a/node/stmt/n_switch.go b/node/stmt/n_switch.go index 2363fc6..440845c 100644 --- a/node/stmt/n_switch.go +++ b/node/stmt/n_switch.go @@ -2,23 +2,20 @@ package stmt import ( "github.com/z7zmey/php-parser/node" - "github.com/z7zmey/php-parser/token" "github.com/z7zmey/php-parser/walker" ) // Switch node type Switch struct { - token token.Token Cond node.Node - cases []node.Node + Cases []node.Node } // NewSwitch node constuctor -func NewSwitch(token token.Token, Cond node.Node, cases []node.Node) *Switch { +func NewSwitch(Cond node.Node, Cases []node.Node) *Switch { return &Switch{ - token, Cond, - cases, + Cases, } } @@ -39,9 +36,9 @@ func (n *Switch) Walk(v walker.Visitor) { n.Cond.Walk(vv) } - if n.cases != nil { - vv := v.GetChildrenVisitor("cases") - for _, nn := range n.cases { + if n.Cases != nil { + vv := v.GetChildrenVisitor("Cases") + for _, nn := range n.Cases { if nn != nil { nn.Walk(vv) } diff --git a/node/stmt/n_while.go b/node/stmt/n_while.go index 9fc6a48..dca92e6 100644 --- a/node/stmt/n_while.go +++ b/node/stmt/n_while.go @@ -2,21 +2,18 @@ package stmt import ( "github.com/z7zmey/php-parser/node" - "github.com/z7zmey/php-parser/token" "github.com/z7zmey/php-parser/walker" ) // While node type While struct { - Token token.Token Cond node.Node Stmt node.Node } // NewWhile node constuctor -func NewWhile(Token token.Token, Cond node.Node, Stmt node.Node) *While { +func NewWhile(Cond node.Node, Stmt node.Node) *While { return &While{ - Token, Cond, Stmt, } diff --git a/node/stmt/t_visitor_test.go b/node/stmt/t_visitor_test.go new file mode 100644 index 0000000..b8d2d5a --- /dev/null +++ b/node/stmt/t_visitor_test.go @@ -0,0 +1,493 @@ +package stmt_test + +import ( + "github.com/z7zmey/php-parser/node/expr" + "github.com/z7zmey/php-parser/node/stmt" + "reflect" + "testing" + + "github.com/z7zmey/php-parser/node" + "github.com/z7zmey/php-parser/walker" + "github.com/kylelemons/godebug/pretty" +) + +var nodesToTest = []struct { + node node.Node // node + expectedVisitedKeys []string // visited keys + expectedAttributes map[string]interface{} +}{ + { + &stmt.AltIf{ + Cond: &stmt.Expression{}, + Stmt: &stmt.StmtList{}, + ElseIf: []node.Node{&stmt.ElseIf{}}, + Else: &stmt.Else{}, + }, + []string{"Cond", "Stmt", "ElseIf", "Else"}, + map[string]interface{}{}, + }, + { + &stmt.AltElse{ + Stmt: &stmt.StmtList{}, + }, + []string{"Stmt"}, + map[string]interface{}{}, + }, + { + &stmt.AltElseIf{ + Cond: &stmt.Expression{}, + Stmt: &stmt.StmtList{}, + }, + []string{"Cond", "Stmt"}, + map[string]interface{}{}, + }, + { + &stmt.Break{ + Expr: &stmt.Expression{}, + }, + []string{"Expr"}, + map[string]interface{}{}, + }, + { + &stmt.Case{ + Cond: &stmt.Expression{}, + Stmts: []node.Node{}, + }, + []string{"Cond", "Stmts"}, + map[string]interface{}{}, + }, + { + &stmt.Catch{ + Types: []node.Node{}, + Variable: &expr.Variable{}, + Stmts: []node.Node{}, + }, + []string{"Types", "Variable", "Stmts"}, + map[string]interface{}{}, + }, + { + &stmt.ClassConstList{ + Modifiers: []node.Node{}, + Consts: []node.Node{}, + }, + []string{"Modifiers", "Consts"}, + map[string]interface{}{}, + }, + { + &stmt.ClassMethod{ + ReturnsRef: true, + PhpDocComment: "/** */", + MethodName: &node.Identifier{}, + Modifiers: []node.Node{}, + Params: []node.Node{}, + ReturnType: &node.Identifier{}, + Stmts: []node.Node{}, + }, + []string{"MethodName", "Modifiers", "Params", "ReturnType", "Stmts"}, + map[string]interface{}{"ReturnsRef": true, "PhpDocComment": "/** */"}, + }, + { + &stmt.Class{ + PhpDocComment: "/** */", + ClassName: &node.Identifier{}, + Modifiers: []node.Node{}, + Args: []node.Node{}, + Extends: &node.Identifier{}, + Implements: []node.Node{}, + Stmts: []node.Node{}, + }, + []string{"ClassName", "Modifiers", "Args", "Extends", "Implements", "Stmts"}, + map[string]interface{}{"PhpDocComment": "/** */"}, + }, + { + &stmt.ConstList{ + Consts: []node.Node{}, + }, + []string{"Consts"}, + map[string]interface{}{}, + }, + { + &stmt.Constant{ + PhpDocComment: "/** */", + ConstantName: &node.Identifier{}, + Expr: &stmt.Expression{}, + }, + []string{"ConstantName", "Expr"}, + map[string]interface{}{"PhpDocComment": "/** */"}, + }, + { + &stmt.Continue{ + Expr: &stmt.Expression{}, + }, + []string{"Expr"}, + map[string]interface{}{}, + }, + { + &stmt.Declare{ + Consts: []node.Node{}, + Stmt: &stmt.StmtList{}, + }, + []string{"Consts", "Stmt"}, + map[string]interface{}{}, + }, + { + &stmt.Default{ + Stmts: []node.Node{}, + }, + []string{"Stmts"}, + map[string]interface{}{}, + }, + { + &stmt.Do{ + Stmt: &stmt.StmtList{}, + Cond: &expr.Variable{}, + }, + []string{"Stmt", "Cond"}, + map[string]interface{}{}, + }, + { + &stmt.Do{ + Stmt: &stmt.StmtList{}, + Cond: &expr.Variable{}, + }, + []string{"Stmt", "Cond"}, + map[string]interface{}{}, + }, + { + &stmt.Echo{ + Exprs: []node.Node{}, + }, + []string{"Exprs"}, + map[string]interface{}{}, + }, + { + &stmt.If{ + Cond: &stmt.Expression{}, + Stmt: &stmt.StmtList{}, + ElseIf: []node.Node{&stmt.ElseIf{}}, + Else: &stmt.Else{}, + }, + []string{"Cond", "Stmt", "ElseIf", "Else"}, + map[string]interface{}{}, + }, + { + &stmt.Else{ + Stmt: &stmt.StmtList{}, + }, + []string{"Stmt"}, + map[string]interface{}{}, + }, + { + &stmt.ElseIf{ + Cond: &stmt.Expression{}, + Stmt: &stmt.StmtList{}, + }, + []string{"Cond", "Stmt"}, + map[string]interface{}{}, + }, + { + &stmt.Expression{ + Expr: &stmt.Expression{}, + }, + []string{"Expr"}, + map[string]interface{}{}, + }, + { + &stmt.Finally{ + Stmts: []node.Node{}, + }, + []string{"Stmts"}, + map[string]interface{}{}, + }, + { + &stmt.For{ + Init: []node.Node{}, + Cond: []node.Node{}, + Loop: []node.Node{}, + Stmt: &stmt.StmtList{}, + }, + []string{"Init", "Cond", "Loop", "Stmt"}, + map[string]interface{}{}, + }, + { + &stmt.Foreach{ + ByRef: true, + Expr: &stmt.Expression{}, + Key: &expr.Variable{}, + Variable: &expr.Variable{}, + Stmt: &stmt.StmtList{}, + }, + []string{"Expr", "Key", "Variable", "Stmt"}, + map[string]interface{}{"ByRef": true}, + }, + { + &stmt.Function{ + ReturnsRef: true, + PhpDocComment: "/** */", + FunctionName: &node.Identifier{}, + Params: []node.Node{}, + ReturnType: &node.Identifier{}, + Stmts: []node.Node{}, + }, + []string{"FunctionName", "Params", "ReturnType", "Stmts"}, + map[string]interface{}{"ReturnsRef": true, "PhpDocComment": "/** */"}, + }, + { + &stmt.Global{ + Vars: []node.Node{}, + }, + []string{"Vars"}, + map[string]interface{}{}, + }, + { + &stmt.Goto{ + Label: &node.Identifier{}, + }, + []string{"Label"}, + map[string]interface{}{}, + }, + { + &stmt.GroupUse{ + UseType: &node.Identifier{}, + Prefix: &node.Identifier{}, + UseList: []node.Node{}, + }, + []string{"UseType", "Prefix", "UseList"}, + map[string]interface{}{}, + }, + { + &stmt.HaltCompiler{}, + []string{}, + map[string]interface{}{}, + }, + { + &stmt.InlineHtml{ + Value: "hello", + }, + []string{}, + map[string]interface{}{"Value": "hello"}, + }, + { + &stmt.Interface{ + PhpDocComment: "/** */", + InterfaceName: &node.Identifier{}, + Extends: []node.Node{}, + Stmts: []node.Node{}, + }, + []string{"InterfaceName", "Extends", "Stmts"}, + map[string]interface{}{"PhpDocComment": "/** */"}, + }, + { + &stmt.Label{ + LabelName: &node.Identifier{}, + }, + []string{"LabelName"}, + map[string]interface{}{}, + }, + { + &stmt.Namespace{ + NamespaceName: &node.Identifier{}, + Stmts: []node.Node{}, + }, + []string{"NamespaceName", "Stmts"}, + map[string]interface{}{}, + }, + { + &stmt.Nop{}, + []string{}, + map[string]interface{}{}, + }, + { + &stmt.PropertyList{ + Modifiers: []node.Node{}, + Properties: []node.Node{}, + }, + []string{"Modifiers", "Properties"}, + map[string]interface{}{}, + }, + { + &stmt.Property{ + PhpDocComment: "/** */", + Variable: &expr.Variable{}, + Expr: &stmt.Expression{}, + }, + []string{"Variable", "Expr"}, + map[string]interface{}{"PhpDocComment": "/** */"}, + }, + { + &stmt.Return{ + Expr: &stmt.Expression{}, + }, + []string{"Expr"}, + map[string]interface{}{}, + }, + { + &stmt.StaticVar{ + Variable: &expr.Variable{}, + Expr: &stmt.Expression{}, + }, + []string{"Variable", "Expr"}, + map[string]interface{}{}, + }, + { + &stmt.Static{ + Vars: []node.Node{}, + }, + []string{"Vars"}, + map[string]interface{}{}, + }, + { + &stmt.Switch{ + Cond: &expr.Variable{}, + Cases: []node.Node{}, + }, + []string{"Cond", "Cases"}, + map[string]interface{}{}, + }, + { + &stmt.Throw{ + Expr: &stmt.Expression{}, + }, + []string{"Expr"}, + map[string]interface{}{}, + }, + { + &stmt.TraitMethodRef{ + Trait: &node.Identifier{}, + Method: &node.Identifier{}, + }, + []string{"Trait", "Method"}, + map[string]interface{}{}, + }, + { + &stmt.TraitUseAlias{ + Ref: &node.Identifier{}, + Modifier: &node.Identifier{}, + Alias: &node.Identifier{}, + }, + []string{"Ref", "Modifier", "Alias"}, + map[string]interface{}{}, + }, + { + &stmt.TraitUsePrecedence{ + Ref: &node.Identifier{}, + Insteadof: &node.Identifier{}, + }, + []string{"Ref", "Insteadof"}, + map[string]interface{}{}, + }, + { + &stmt.TraitUse{ + Traits: []node.Node{}, + Adaptations: []node.Node{}, + }, + []string{"Traits", "Adaptations"}, + map[string]interface{}{}, + }, + { + &stmt.Trait{ + PhpDocComment: "/** */", + TraitName: &node.Identifier{}, + Stmts: []node.Node{}, + }, + []string{"TraitName", "Stmts"}, + map[string]interface{}{"PhpDocComment": "/** */"}, + }, + { + &stmt.Try{ + Stmts: []node.Node{}, + Catches: []node.Node{}, + Finally: &stmt.Finally{}, + }, + []string{"Stmts", "Catches", "Finally"}, + map[string]interface{}{}, + }, + { + &stmt.Unset{ + Vars: []node.Node{}, + }, + []string{"Vars"}, + map[string]interface{}{}, + }, + { + &stmt.UseList{ + UseType: &node.Identifier{}, + Uses: []node.Node{}, + }, + []string{"UseType", "Uses"}, + map[string]interface{}{}, + }, + { + &stmt.Use{ + UseType: &node.Identifier{}, + Use: &node.Identifier{}, + Alias: &node.Identifier{}, + }, + []string{"UseType", "Use", "Alias"}, + map[string]interface{}{}, + }, + { + &stmt.While{ + Cond: &expr.Variable{}, + Stmt: &stmt.StmtList{}, + }, + []string{"Cond", "Stmt"}, + map[string]interface{}{}, + }, +} + +type visitorMock struct { + visitChildren bool + visitedKeys []string +} + +func (v *visitorMock) EnterNode(n walker.Walker) bool { return v.visitChildren } +func (v *visitorMock) GetChildrenVisitor(key string) walker.Visitor { + v.visitedKeys = append(v.visitedKeys, key) + return &visitorMock{v.visitChildren, nil} +} +func (v *visitorMock) LeaveNode(n walker.Walker) {} + +func TestVisitorDisableChildren(t *testing.T) { + for _, tt := range nodesToTest { + v := &visitorMock{false, nil} + tt.node.Walk(v) + + expected := []string{} + actual := v.visitedKeys + + diff := pretty.Compare(expected, actual) + if diff != "" { + t.Errorf("%s diff: (-expected +actual)\n%s", reflect.TypeOf(tt.node), diff) + } + } +} + +func TestVisitor(t *testing.T) { + for _, tt := range nodesToTest { + v := &visitorMock{true, nil} + tt.node.Walk(v) + + expected := tt.expectedVisitedKeys + actual := v.visitedKeys + + diff := pretty.Compare(expected, actual) + if diff != "" { + t.Errorf("%s diff: (-expected +actual)\n%s", reflect.TypeOf(tt.node), diff) + } + } +} + +// test Attributes() + +func TestNameAttributes(t *testing.T) { + for _, tt := range nodesToTest { + expected := tt.expectedAttributes + actual := tt.node.Attributes() + + diff := pretty.Compare(expected, actual) + if diff != "" { + t.Errorf("%s diff: (-expected +actual)\n%s", reflect.TypeOf(tt.node), diff) + } + } +} diff --git a/php5/php5.go b/php5/php5.go index d500eb4..fa73f32 100644 --- a/php5/php5.go +++ b/php5/php5.go @@ -2692,7 +2692,7 @@ yydefault: yyDollar = yyS[yypt-3 : yypt+1] //line php5/php5.y:605 { - yyVAL.node = stmt.NewWhile(yyDollar[1].token, yyDollar[2].node, yyDollar[3].node) + yyVAL.node = stmt.NewWhile(yyDollar[2].node, yyDollar[3].node) positions.AddPosition(yyVAL.node, positionBuilder.NewTokenNodePosition(yyDollar[1].token, yyDollar[3].node)) comments.AddComments(yyVAL.node, yyDollar[1].token.Comments()) } @@ -2716,7 +2716,7 @@ yydefault: yyDollar = yyS[yypt-3 : yypt+1] //line php5/php5.y:623 { - yyVAL.node = stmt.NewSwitch(yyDollar[1].token, yyDollar[2].node, yyDollar[3].nodesWithEndToken.nodes) + yyVAL.node = stmt.NewSwitch(yyDollar[2].node, yyDollar[3].nodesWithEndToken.nodes) positions.AddPosition(yyVAL.node, positionBuilder.NewTokensPosition(yyDollar[1].token, yyDollar[3].nodesWithEndToken.endToken)) comments.AddComments(yyVAL.node, yyDollar[1].token.Comments()) } diff --git a/php5/php5.y b/php5/php5.y index 746a2fa..9b61847 100644 --- a/php5/php5.y +++ b/php5/php5.y @@ -603,7 +603,7 @@ unticked_statement: } | T_WHILE parenthesis_expr while_statement { - $$ = stmt.NewWhile($1, $2, $3) + $$ = stmt.NewWhile($2, $3) positions.AddPosition($$, positionBuilder.NewTokenNodePosition($1, $3)) comments.AddComments($$, $1.Comments()) } @@ -621,7 +621,7 @@ unticked_statement: } | T_SWITCH parenthesis_expr switch_case_list { - $$ = stmt.NewSwitch($1, $2, $3.nodes) + $$ = stmt.NewSwitch($2, $3.nodes) positions.AddPosition($$, positionBuilder.NewTokensPosition($1, $3.endToken)) comments.AddComments($$, $1.Comments()) } diff --git a/php7/php7.go b/php7/php7.go index a825022..dae48e1 100644 --- a/php7/php7.go +++ b/php7/php7.go @@ -2880,7 +2880,7 @@ yydefault: yyDollar = yyS[yypt-5 : yypt+1] //line php7/php7.y:525 { - yyVAL.node = stmt.NewWhile(yyDollar[1].token, yyDollar[3].node, yyDollar[5].node) + yyVAL.node = stmt.NewWhile(yyDollar[3].node, yyDollar[5].node) positions.AddPosition(yyVAL.node, positionBuilder.NewTokenNodePosition(yyDollar[1].token, yyDollar[5].node)) comments.AddComments(yyVAL.node, yyDollar[1].token.Comments()) } @@ -2904,7 +2904,7 @@ yydefault: yyDollar = yyS[yypt-5 : yypt+1] //line php7/php7.y:543 { - yyVAL.node = stmt.NewSwitch(yyDollar[1].token, yyDollar[3].node, yyDollar[5].nodesWithEndToken.nodes) + yyVAL.node = stmt.NewSwitch(yyDollar[3].node, yyDollar[5].nodesWithEndToken.nodes) positions.AddPosition(yyVAL.node, positionBuilder.NewTokensPosition(yyDollar[1].token, yyDollar[5].nodesWithEndToken.endToken)) comments.AddComments(yyVAL.node, yyDollar[1].token.Comments()) } diff --git a/php7/php7.y b/php7/php7.y index 280cbe2..9d81a13 100644 --- a/php7/php7.y +++ b/php7/php7.y @@ -523,7 +523,7 @@ statement: | alt_if_stmt { $$ = $1; } | T_WHILE '(' expr ')' while_statement { - $$ = stmt.NewWhile($1, $3, $5) + $$ = stmt.NewWhile($3, $5) positions.AddPosition($$, positionBuilder.NewTokenNodePosition($1, $5)) comments.AddComments($$, $1.Comments()) } @@ -541,7 +541,7 @@ statement: } | T_SWITCH '(' expr ')' switch_case_list { - $$ = stmt.NewSwitch($1, $3, $5.nodes) + $$ = stmt.NewSwitch($3, $5.nodes) positions.AddPosition($$, positionBuilder.NewTokensPosition($1, $5.endToken)) comments.AddComments($$, $1.Comments()) }