diff --git a/internal/php5/parser_test.go b/internal/php5/parser_test.go index 0eb1d67..a2b90ea 100644 --- a/internal/php5/parser_test.go +++ b/internal/php5/parser_test.go @@ -17236,6 +17236,8 @@ func TestExprPrint(t *testing.T) { assert.DeepEqual(t, expected, actual) } +// TODO add test for `echo $a->b["c"]()->d["e"]();` + func TestExprPropertyFetch(t *testing.T) { src := `foo;` diff --git a/internal/php5/php5.go b/internal/php5/php5.go index 8501768..040152d 100644 Binary files a/internal/php5/php5.go and b/internal/php5/php5.go differ diff --git a/internal/php5/php5.y b/internal/php5/php5.y index 07db4b4..1502664 100644 --- a/internal/php5/php5.y +++ b/internal/php5/php5.y @@ -3744,24 +3744,26 @@ expr_without_variable: for _, n := range($4) { switch nn := n.(type) { + case *ast.ExprFunctionCall: + nn.Function = $$ + nn.Node.Position = position.NewNodesPosition($$, nn) + $$ = nn + case *ast.ExprArrayDimFetch: nn.Var = $$ + nn.Node.Position = position.NewNodesPosition($$, nn) $$ = nn - yylex.(*Parser).MoveFreeFloating(nn.Var, $$) case *ast.ExprPropertyFetch: nn.Var = $$ + nn.Node.Position = position.NewNodesPosition($$, nn) $$ = nn - yylex.(*Parser).MoveFreeFloating(nn.Var, $$) case *ast.ExprMethodCall: nn.Var = $$ + nn.Node.Position = position.NewNodesPosition($$, nn) $$ = nn - yylex.(*Parser).MoveFreeFloating(nn.Var, $$) } - - // save position - $$.GetNode().Position = position.NewNodesPosition($$, n) } } | expr '?' expr ':' expr @@ -5448,55 +5450,75 @@ variable: { $$ = $1 - if $4 != nil { - $4[0].(*ast.ExprMethodCall).Method = $3[len($3)-1].(*ast.ExprPropertyFetch).Property - $3 = append($3[:len($3)-1], $4...) - } + $3[0].(*ast.ExprPropertyFetch).ObjectOperatorTkn = $2 - // save comments - yylex.(*Parser).setFreeFloating($3[0], token.Var, $2.SkippedTokens) + if $4 != nil { + last := $3[len($3)-1] + switch l := last.(type) { + case *ast.ExprArrayDimFetch: + mc := $4[0].(*ast.ExprMethodCall) + $3 = append($3, &ast.ExprFunctionCall{ + Node: ast.Node{ + Position: position.NewNodePosition(mc), + }, + OpenParenthesisTkn: mc.OpenParenthesisTkn, + Arguments: mc.Arguments, + CloseParenthesisTkn: mc.OpenParenthesisTkn, + }, + ) + $3 = append($3, $4[1:len($4)]...) + case *ast.ExprPropertyFetch: + $4[0].(*ast.ExprMethodCall).Method = l.Property + $4[0].(*ast.ExprMethodCall).ObjectOperatorTkn = l.ObjectOperatorTkn + $3 = append($3[:len($3)-1], $4...) + } + } for _, n := range($3) { switch nn := n.(type) { + case *ast.ExprFunctionCall: + nn.Function = $$ + nn.Node.Position = position.NewNodesPosition($$, nn) + $$ = nn + case *ast.ExprArrayDimFetch: nn.Var = $$ - nn.GetNode().Position = position.NewNodesPosition($$, nn) + nn.Node.Position = position.NewNodesPosition($$, nn) $$ = nn - yylex.(*Parser).MoveFreeFloating(nn.Var, $$) case *ast.ExprPropertyFetch: nn.Var = $$ - nn.GetNode().Position = position.NewNodesPosition($$, nn) + nn.Node.Position = position.NewNodesPosition($$, nn) $$ = nn - yylex.(*Parser).MoveFreeFloating(nn.Var, $$) case *ast.ExprMethodCall: nn.Var = $$ - nn.GetNode().Position = position.NewNodesPosition($$, nn) + nn.Node.Position = position.NewNodesPosition($$, nn) $$ = nn - yylex.(*Parser).MoveFreeFloating(nn.Var, $$) } } for _, n := range($5) { switch nn := n.(type) { + case *ast.ExprFunctionCall: + nn.Function = $$ + nn.Node.Position = position.NewNodesPosition($$, nn) + $$ = nn + case *ast.ExprArrayDimFetch: nn.Var = $$ - nn.GetNode().Position = position.NewNodesPosition($$, nn) + nn.Node.Position = position.NewNodesPosition($$, nn) $$ = nn - yylex.(*Parser).MoveFreeFloating(nn.Var, $$) case *ast.ExprPropertyFetch: nn.Var = $$ - nn.GetNode().Position = position.NewNodesPosition($$, nn) + nn.Node.Position = position.NewNodesPosition($$, nn) $$ = nn - yylex.(*Parser).MoveFreeFloating(nn.Var, $$) case *ast.ExprMethodCall: nn.Var = $$ - nn.GetNode().Position = position.NewNodesPosition($$, nn) + nn.Node.Position = position.NewNodesPosition($$, nn) $$ = nn - yylex.(*Parser).MoveFreeFloating(nn.Var, $$) } } } @@ -5520,16 +5542,32 @@ variable_properties: variable_property: T_OBJECT_OPERATOR object_property method_or_not - { + {println("FOOFOOFOOFOOFOOFOOFOOFOOFOO") + $2[0].(*ast.ExprPropertyFetch).ObjectOperatorTkn = $1 + if $3 != nil { - $3[0].(*ast.ExprMethodCall).Method = $2[len($2)-1].(*ast.ExprPropertyFetch).Property - $2 = append($2[:len($2)-1], $3...) + last := $2[len($2)-1] + switch l := last.(type) { + case *ast.ExprArrayDimFetch: + mc := $3[0].(*ast.ExprMethodCall) + $2 = append($2, &ast.ExprFunctionCall{ + Node: ast.Node{ + Position: position.NewNodePosition(mc), + }, + OpenParenthesisTkn: mc.OpenParenthesisTkn, + Arguments: mc.Arguments, + CloseParenthesisTkn: mc.OpenParenthesisTkn, + }, + ) + $2 = append($2, $3[1:len($3)]...) + case *ast.ExprPropertyFetch: + $3[0].(*ast.ExprMethodCall).Method = l.Property + $3[0].(*ast.ExprMethodCall).ObjectOperatorTkn = l.ObjectOperatorTkn + $2 = append($2[:len($2)-1], $3...) + } } $$ = $2 - - // save comments - yylex.(*Parser).setFreeFloating($2[0], token.Var, $1.SkippedTokens) } ; @@ -5567,10 +5605,14 @@ array_method_dereference: method: function_call_parameter_list { - $$ = &ast.ExprMethodCall{ast.Node{}, nil, nil, $1.(*ast.ArgumentList)} - - // save position - $$.GetNode().Position = position.NewNodePosition($1) + $$ = &ast.ExprMethodCall{ + Node: ast.Node{ + Position: position.NewNodePosition($1), + }, + OpenParenthesisTkn: $1.(*ast.ArgumentList).OpenParenthesisTkn, + Arguments: $1.(*ast.ArgumentList).Arguments, + CloseParenthesisTkn: $1.(*ast.ArgumentList).CloseParenthesisTkn, + } } ; @@ -5785,11 +5827,14 @@ object_property: } | variable_without_objects { - fetch := &ast.ExprPropertyFetch{ast.Node{}, nil, $1} - $$ = []ast.Vertex{fetch} - - // save position - fetch.GetNode().Position = position.NewNodePosition($1) + $$ = []ast.Vertex{ + &ast.ExprPropertyFetch{ + Node: ast.Node{ + Position: position.NewNodePosition($1), + }, + Property: $1, + }, + } } ; @@ -5824,11 +5869,14 @@ object_dim_list: } | variable_name { - fetch := &ast.ExprPropertyFetch{ast.Node{}, nil, $1} - $$ = []ast.Vertex{fetch} - - // save position - fetch.GetNode().Position = position.NewNodePosition($1) + $$ = []ast.Vertex{ + &ast.ExprPropertyFetch{ + Node: ast.Node{ + Position: position.NewNodePosition($1), + }, + Property: $1, + }, + } } ; @@ -6179,29 +6227,31 @@ encaps_var: } | T_VARIABLE T_OBJECT_OPERATOR T_STRING { - identifier := &ast.Identifier{ + $$ = &ast.ExprPropertyFetch{ Node: ast.Node{ - Position: position.NewTokenPosition($1), + Position: position.NewTokensPosition($1, $3), }, - IdentifierTkn: $1, - Value: $1.Value, - } - variable := &ast.ExprVariable{ast.Node{}, identifier} - fetch := &ast.Identifier{ - Node: ast.Node{ - Position: position.NewTokenPosition($3), + Var: &ast.ExprVariable{ + Node: ast.Node{ + Position: position.NewTokenPosition($1), + }, + VarName: &ast.Identifier{ + Node: ast.Node{ + Position: position.NewTokenPosition($1), + }, + IdentifierTkn: $1, + Value: $1.Value, + }, + }, + ObjectOperatorTkn: $2, + Property: &ast.Identifier{ + Node: ast.Node{ + Position: position.NewTokenPosition($3), + }, + IdentifierTkn: $3, + Value: $3.Value, }, - IdentifierTkn: $3, - Value: $3.Value, } - $$ = &ast.ExprPropertyFetch{ast.Node{}, variable, fetch} - - // save position - variable.GetNode().Position = position.NewTokenPosition($1) - $$.GetNode().Position = position.NewTokensPosition($1, $3) - - // save comments - yylex.(*Parser).setFreeFloating($$, token.Var, $2.SkippedTokens) } | T_DOLLAR_OPEN_CURLY_BRACES expr '}' { diff --git a/internal/php7/php7.go b/internal/php7/php7.go index 9fde4cd..3979201 100644 Binary files a/internal/php7/php7.go and b/internal/php7/php7.go differ diff --git a/internal/php7/php7.y b/internal/php7/php7.y index 2e1cdb4..ca0a1c2 100644 --- a/internal/php7/php7.y +++ b/internal/php7/php7.y @@ -4274,14 +4274,17 @@ callable_variable: } | dereferencable T_OBJECT_OPERATOR property_name argument_list { - $$ = &ast.ExprMethodCall{ast.Node{}, $1, $3, $4.(*ast.ArgumentList)} - - // save position - $$.GetNode().Position = position.NewNodesPosition($1, $4) - - // save comments - yylex.(*Parser).MoveFreeFloating($1, $$) - yylex.(*Parser).setFreeFloating($$, token.Var, $2.SkippedTokens) + $$ = &ast.ExprMethodCall{ + Node: ast.Node{ + Position: position.NewNodesPosition($1, $4), + }, + Var: $1, + ObjectOperatorTkn: $2, + Method: $3, + OpenParenthesisTkn: $4.(*ast.ArgumentList).OpenParenthesisTkn, + Arguments: $4.(*ast.ArgumentList).Arguments, + CloseParenthesisTkn: $4.(*ast.ArgumentList).CloseParenthesisTkn, + } } | function_call { @@ -4300,14 +4303,14 @@ variable: } | dereferencable T_OBJECT_OPERATOR property_name { - $$ = &ast.ExprPropertyFetch{ast.Node{}, $1, $3} - - // save position - $$.GetNode().Position = position.NewNodesPosition($1, $3) - - // save comments - yylex.(*Parser).MoveFreeFloating($1, $$) - yylex.(*Parser).setFreeFloating($$, token.Var, $2.SkippedTokens) + $$ = &ast.ExprPropertyFetch{ + Node: ast.Node{ + Position: position.NewNodesPosition($1, $3), + }, + Var: $1, + ObjectOperatorTkn: $2, + Property: $3, + } } ; @@ -4409,14 +4412,14 @@ new_variable: } | new_variable T_OBJECT_OPERATOR property_name { - $$ = &ast.ExprPropertyFetch{ast.Node{}, $1, $3} - - // save position - $$.GetNode().Position = position.NewNodesPosition($1, $3) - - // save comments - yylex.(*Parser).MoveFreeFloating($1, $$) - yylex.(*Parser).setFreeFloating($$, token.Var, $2.SkippedTokens) + $$ = &ast.ExprPropertyFetch{ + Node: ast.Node{ + Position: position.NewNodesPosition($1, $3), + }, + Var: $1, + ObjectOperatorTkn: $2, + Property: $3, + } } | class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { @@ -4714,29 +4717,31 @@ encaps_var: } | T_VARIABLE T_OBJECT_OPERATOR T_STRING { - identifier := &ast.Identifier{ + $$ = &ast.ExprPropertyFetch{ Node: ast.Node{ - Position: position.NewTokenPosition($1), + Position: position.NewTokensPosition($1, $3), }, - IdentifierTkn: $1, - Value: $1.Value, - } - variable := &ast.ExprVariable{ast.Node{}, identifier} - fetch := &ast.Identifier{ - Node: ast.Node{ - Position: position.NewTokenPosition($3), + Var: &ast.ExprVariable{ + Node: ast.Node{ + Position: position.NewTokenPosition($1), + }, + VarName: &ast.Identifier{ + Node: ast.Node{ + Position: position.NewTokenPosition($1), + }, + IdentifierTkn: $1, + Value: $1.Value, + }, + }, + ObjectOperatorTkn: $2, + Property: &ast.Identifier{ + Node: ast.Node{ + Position: position.NewTokenPosition($3), + }, + IdentifierTkn: $3, + Value: $3.Value, }, - IdentifierTkn: $3, - Value: $3.Value, } - $$ = &ast.ExprPropertyFetch{ast.Node{}, variable, fetch} - - // save position - variable.GetNode().Position = position.NewTokenPosition($1) - $$.GetNode().Position = position.NewTokensPosition($1, $3) - - // save comments - yylex.(*Parser).setFreeFloating($$, token.Var, $2.SkippedTokens) } | T_DOLLAR_OPEN_CURLY_BRACES expr '}' { diff --git a/pkg/ast/node.go b/pkg/ast/node.go index 54ae3de..9f90db7 100644 --- a/pkg/ast/node.go +++ b/pkg/ast/node.go @@ -1215,9 +1215,12 @@ func (n *ExprList) Accept(v NodeVisitor) { // ExprMethodCall node type ExprMethodCall struct { Node - Var Vertex - Method Vertex - ArgumentList *ArgumentList + Var Vertex + ObjectOperatorTkn *token.Token + Method Vertex + OpenParenthesisTkn *token.Token + Arguments []Vertex + CloseParenthesisTkn *token.Token } func (n *ExprMethodCall) Accept(v NodeVisitor) { @@ -1288,8 +1291,9 @@ func (n *ExprPrint) Accept(v NodeVisitor) { // ExprPropertyFetch node type ExprPropertyFetch struct { Node - Var Vertex - Property Vertex + Var Vertex + ObjectOperatorTkn *token.Token + Property Vertex } func (n *ExprPropertyFetch) Accept(v NodeVisitor) { diff --git a/pkg/ast/traverser/dfs.go b/pkg/ast/traverser/dfs.go index 95f2d4a..fecf672 100644 --- a/pkg/ast/traverser/dfs.go +++ b/pkg/ast/traverser/dfs.go @@ -1396,10 +1396,12 @@ func (t *DFS) Traverse(n ast.Vertex) { t.Traverse(nn.Method) t.visitor.Leave("Method", true) } - if nn.ArgumentList != nil { - t.visitor.Enter("ArgumentList", true) - t.Traverse(nn.ArgumentList) - t.visitor.Leave("ArgumentList", true) + if nn.Arguments != nil { + t.visitor.Enter("Arguments", false) + for _, c := range nn.Arguments { + t.Traverse(c) + } + t.visitor.Leave("Arguments", false) } case *ast.ExprNew: if nn == nil { diff --git a/pkg/printer/pretty_printer.go b/pkg/printer/pretty_printer.go index 79782fe..ef01e44 100644 --- a/pkg/printer/pretty_printer.go +++ b/pkg/printer/pretty_printer.go @@ -1133,7 +1133,7 @@ func (p *PrettyPrinter) printExprMethodCall(n ast.Vertex) { io.WriteString(p.w, "->") p.Print(nn.Method) io.WriteString(p.w, "(") - p.joinPrint(", ", nn.ArgumentList.Arguments) + p.joinPrint(", ", nn.Arguments) io.WriteString(p.w, ")") } diff --git a/pkg/printer/printer.go b/pkg/printer/printer.go index dfbe5f1..8791841 100644 --- a/pkg/printer/printer.go +++ b/pkg/printer/printer.go @@ -1695,9 +1695,9 @@ func (p *Printer) printExprMethodCall(n ast.Vertex) { p.write([]byte("->")) p.Print(nn.Method) - p.printFreeFloatingOrDefault(nn.ArgumentList, token.Start, "(") - p.joinPrint(",", nn.ArgumentList.Arguments) - p.printFreeFloatingOrDefault(nn.ArgumentList, token.End, ")") + p.printToken(nn.OpenParenthesisTkn, "(") + p.joinPrint(",", nn.Arguments) + p.printToken(nn.CloseParenthesisTkn, ")") p.printFreeFloating(nn, token.End) }