diff --git a/internal/php5/php5.go b/internal/php5/php5.go index a2bd33c..4e5baf8 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 ba55690..a9d05ee 100644 --- a/internal/php5/php5.y +++ b/internal/php5/php5.y @@ -3688,7 +3688,7 @@ function_call: } | class_name T_PAAMAYIM_NEKUDOTAYIM variable_name function_call_parameter_list { - $$ = &ast.ExprStaticCall{ + staticCall := &ast.ExprStaticCall{ Position: yylex.(*Parser).builder.NewNodesPosition($1, $4), Class: $1, DoubleColonTkn: $2, @@ -3698,6 +3698,14 @@ function_call: SeparatorTkns: $4.(*ast.ArgumentList).SeparatorTkns, CloseParenthesisTkn: $4.(*ast.ArgumentList).CloseParenthesisTkn, } + + if brackets, ok := $3.(*ast.ParserBrackets); ok { + staticCall.OpenCurlyBracketTkn = brackets.OpenBracketTkn + staticCall.Call = brackets.Child + staticCall.CloseCurlyBracketTkn = brackets.CloseBracketTkn + } + + $$ = staticCall } | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects function_call_parameter_list { @@ -3714,7 +3722,7 @@ function_call: } | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_name function_call_parameter_list { - $$ = &ast.ExprStaticCall{ + staticCall := &ast.ExprStaticCall{ Position: yylex.(*Parser).builder.NewNodesPosition($1, $4), Class: $1, DoubleColonTkn: $2, @@ -3724,6 +3732,14 @@ function_call: SeparatorTkns: $4.(*ast.ArgumentList).SeparatorTkns, CloseParenthesisTkn: $4.(*ast.ArgumentList).CloseParenthesisTkn, } + + if brackets, ok := $3.(*ast.ParserBrackets); ok { + staticCall.OpenCurlyBracketTkn = brackets.OpenBracketTkn + staticCall.Call = brackets.Child + staticCall.CloseCurlyBracketTkn = brackets.CloseBracketTkn + } + + $$ = staticCall } | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects function_call_parameter_list { diff --git a/internal/php7/php7.go b/internal/php7/php7.go index bdd9dc6..72e8ddc 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 078c6eb..dbb58b7 100644 --- a/internal/php7/php7.y +++ b/internal/php7/php7.y @@ -3321,7 +3321,7 @@ function_call: } | class_name T_PAAMAYIM_NEKUDOTAYIM member_name argument_list { - $$ = &ast.ExprStaticCall{ + staticCall := &ast.ExprStaticCall{ Position: yylex.(*Parser).builder.NewNodesPosition($1, $4), Class: $1, DoubleColonTkn: $2, @@ -3331,10 +3331,18 @@ function_call: SeparatorTkns: $4.(*ast.ArgumentList).SeparatorTkns, CloseParenthesisTkn: $4.(*ast.ArgumentList).CloseParenthesisTkn, } + + if brackets, ok := $3.(*ast.ParserBrackets); ok { + staticCall.OpenCurlyBracketTkn = brackets.OpenBracketTkn + staticCall.Call = brackets.Child + staticCall.CloseCurlyBracketTkn = brackets.CloseBracketTkn + } + + $$ = staticCall } | variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name argument_list { - $$ = &ast.ExprStaticCall{ + staticCall := &ast.ExprStaticCall{ Position: yylex.(*Parser).builder.NewNodesPosition($1, $4), Class: $1, DoubleColonTkn: $2, @@ -3344,6 +3352,14 @@ function_call: SeparatorTkns: $4.(*ast.ArgumentList).SeparatorTkns, CloseParenthesisTkn: $4.(*ast.ArgumentList).CloseParenthesisTkn, } + + if brackets, ok := $3.(*ast.ParserBrackets); ok { + staticCall.OpenCurlyBracketTkn = brackets.OpenBracketTkn + staticCall.Call = brackets.Child + staticCall.CloseCurlyBracketTkn = brackets.CloseBracketTkn + } + + $$ = staticCall } | callable_expr argument_list { diff --git a/pkg/ast/node.go b/pkg/ast/node.go index 7a89a90..290a51a 100644 --- a/pkg/ast/node.go +++ b/pkg/ast/node.go @@ -1681,14 +1681,16 @@ func (n *ExprShellExec) GetPosition() *position.Position { // ExprStaticCall node type ExprStaticCall struct { - Position *position.Position - Class Vertex - DoubleColonTkn *token.Token - Call Vertex - OpenParenthesisTkn *token.Token - Arguments []Vertex - SeparatorTkns []*token.Token - CloseParenthesisTkn *token.Token + Position *position.Position + Class Vertex + DoubleColonTkn *token.Token + OpenCurlyBracketTkn *token.Token + Call Vertex + CloseCurlyBracketTkn *token.Token + OpenParenthesisTkn *token.Token + Arguments []Vertex + SeparatorTkns []*token.Token + CloseParenthesisTkn *token.Token } func (n *ExprStaticCall) Accept(v NodeVisitor) { diff --git a/pkg/ast/visitor/dumper.go b/pkg/ast/visitor/dumper.go index 11f3159..dde094a 100644 --- a/pkg/ast/visitor/dumper.go +++ b/pkg/ast/visitor/dumper.go @@ -1473,7 +1473,9 @@ func (v *Dumper) ExprStaticCall(n *ast.ExprStaticCall) { v.dumpPosition(n.Position) v.dumpVertex("Class", n.Class) v.dumpToken("DoubleColonTkn", n.DoubleColonTkn) + v.dumpToken("OpenCurlyBracketTkn", n.OpenCurlyBracketTkn) v.dumpVertex("Call", n.Call) + v.dumpToken("CloseCurlyBracketTkn", n.CloseCurlyBracketTkn) v.dumpToken("OpenParenthesisTkn", n.OpenParenthesisTkn) v.dumpVertexList("Arguments", n.Arguments) v.dumpTokenList("SeparatorTkns", n.SeparatorTkns) diff --git a/pkg/ast/visitor/formatter.go b/pkg/ast/visitor/formatter.go index 9dd5d00..c698359 100644 --- a/pkg/ast/visitor/formatter.go +++ b/pkg/ast/visitor/formatter.go @@ -1394,6 +1394,17 @@ func (f *formatter) ExprShellExec(n *ast.ExprShellExec) { func (f *formatter) ExprStaticCall(n *ast.ExprStaticCall) { n.Class.Accept(f) n.DoubleColonTkn = f.newToken(token.T_PAAMAYIM_NEKUDOTAYIM, []byte("::")) + + n.OpenCurlyBracketTkn = nil + n.CloseCurlyBracketTkn = nil + switch n.Call.(type) { + case *ast.Identifier: + case *ast.ExprVariable: + default: + n.OpenCurlyBracketTkn = f.newToken('{', []byte("{")) + n.CloseCurlyBracketTkn = f.newToken('}', []byte("}")) + } + n.Call.Accept(f) n.OpenParenthesisTkn = f.newToken('(', []byte("(")) diff --git a/pkg/ast/visitor/formatter_test.go b/pkg/ast/visitor/formatter_test.go index bc08e81..8180fdb 100644 --- a/pkg/ast/visitor/formatter_test.go +++ b/pkg/ast/visitor/formatter_test.go @@ -4692,6 +4692,36 @@ func TestFormatter_ExprStaticCall(t *testing.T) { } } +func TestFormatter_ExprStaticCall_Expr(t *testing.T) { + o := bytes.NewBufferString("") + + n := &ast.ExprStaticCall{ + Class: &ast.NameName{ + Parts: []ast.Vertex{ + &ast.NameNamePart{ + Value: []byte("foo"), + }, + }, + }, + Call: &ast.ScalarString{ + Value: []byte("'bar'"), + }, + } + + f := visitor.NewFormatter().WithState(visitor.FormatterStatePHP).WithIndent(1) + n.Accept(f) + + p := visitor.NewPrinter(o).WithState(visitor.PrinterStatePHP) + n.Accept(p) + + expected := `foo::{'bar'}()` + actual := o.String() + + if expected != actual { + t.Errorf("\nexpected: %s\ngot: %s\n", expected, actual) + } +} + func TestFormatter_ExprStaticCall_Arguments(t *testing.T) { o := bytes.NewBufferString("") diff --git a/pkg/ast/visitor/printer.go b/pkg/ast/visitor/printer.go index d4ac78a..23b23f1 100644 --- a/pkg/ast/visitor/printer.go +++ b/pkg/ast/visitor/printer.go @@ -840,7 +840,9 @@ func (p *printer) ExprShellExec(n *ast.ExprShellExec) { func (p *printer) ExprStaticCall(n *ast.ExprStaticCall) { p.printNode(n.Class) p.printToken(n.DoubleColonTkn, []byte("::")) + p.printToken(n.OpenCurlyBracketTkn, nil) p.printNode(n.Call) + p.printToken(n.CloseCurlyBracketTkn, nil) p.printToken(n.OpenParenthesisTkn, p.ifNodeList(n.Arguments, []byte("("))) p.printSeparatedList(n.Arguments, n.SeparatorTkns, []byte(",")) p.printToken(n.CloseParenthesisTkn, p.ifNodeList(n.Arguments, []byte(")")))