diff --git a/internal/php5/parser_test.go b/internal/php5/parser_test.go index f4b35d8..889fb3c 100644 --- a/internal/php5/parser_test.go +++ b/internal/php5/parser_test.go @@ -16726,90 +16726,82 @@ func TestStmtGlobal_Vars(t *testing.T) { }, }, }, - VarName: &ast.ParserBrackets{ + OpenCurlyBracketTkn: &token.Token{ + ID: token.ID(123), + Value: []byte("{"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, - EndPos: 31, + EndPos: 25, }, - OpenBracketTkn: &token.Token{ - ID: token.ID(123), - Value: []byte("{"), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 24, - EndPos: 25, - }, + }, + VarName: &ast.ExprFunctionCall{ + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 25, + EndPos: 30, }, - Child: &ast.ExprFunctionCall{ + Function: &ast.NameName{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 25, - EndPos: 30, + EndPos: 28, }, - Function: &ast.NameName{ - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 25, - EndPos: 28, - }, - Parts: []ast.Vertex{ - &ast.NameNamePart{ + Parts: []ast.Vertex{ + &ast.NameNamePart{ + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 25, + EndPos: 28, + }, + StringTkn: &token.Token{ + ID: token.T_STRING, + Value: []byte("foo"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 25, EndPos: 28, }, - StringTkn: &token.Token{ - ID: token.T_STRING, - Value: []byte("foo"), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 25, - EndPos: 28, - }, - }, - Value: []byte("foo"), }, - }, - }, - OpenParenthesisTkn: &token.Token{ - ID: token.ID(40), - Value: []byte("("), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 28, - EndPos: 29, - }, - }, - CloseParenthesisTkn: &token.Token{ - ID: token.ID(41), - Value: []byte(")"), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 29, - EndPos: 30, + Value: []byte("foo"), }, }, }, - CloseBracketTkn: &token.Token{ - ID: token.ID(125), - Value: []byte("}"), + OpenParenthesisTkn: &token.Token{ + ID: token.ID(40), + Value: []byte("("), Position: &position.Position{ StartLine: 1, EndLine: 1, - StartPos: 30, - EndPos: 31, + StartPos: 28, + EndPos: 29, }, }, + CloseParenthesisTkn: &token.Token{ + ID: token.ID(41), + Value: []byte(")"), + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 29, + EndPos: 30, + }, + }, + }, + CloseCurlyBracketTkn: &token.Token{ + ID: token.ID(125), + Value: []byte("}"), + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 30, + EndPos: 31, + }, }, }, }, diff --git a/internal/php5/php5.go b/internal/php5/php5.go index 09a1930..9cc409a 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 f08fbff..ac247f2 100644 --- a/internal/php5/php5.y +++ b/internal/php5/php5.y @@ -2022,14 +2022,11 @@ global_var: | '$' '{' expr '}' { $$ = &ast.ExprVariable{ - Position: yylex.(*Parser).builder.NewTokensPosition($1, $4), - DollarTkn: $1, - VarName: &ast.ParserBrackets{ - Position: yylex.(*Parser).builder.NewTokensPosition($2, $4), - OpenBracketTkn: $2, - Child: $3, - CloseBracketTkn: $4, - }, + Position: yylex.(*Parser).builder.NewTokensPosition($1, $4), + DollarTkn: $1, + OpenCurlyBracketTkn: $2, + VarName: $3, + CloseCurlyBracketTkn: $4, } } ; @@ -5017,14 +5014,11 @@ compound_variable: | '$' '{' expr '}' { $$ = &ast.ExprVariable{ - Position: yylex.(*Parser).builder.NewTokensPosition($1, $4), - DollarTkn: $1, - VarName: &ast.ParserBrackets{ - Position: yylex.(*Parser).builder.NewTokensPosition($2, $4), - OpenBracketTkn: $2, - Child: $3, - CloseBracketTkn: $4, - }, + Position: yylex.(*Parser).builder.NewTokensPosition($1, $4), + DollarTkn: $1, + OpenCurlyBracketTkn: $2, + VarName: $3, + CloseCurlyBracketTkn: $4, } } ; diff --git a/internal/php7/parser_test.go b/internal/php7/parser_test.go index 2854d9a..b2bf948 100644 --- a/internal/php7/parser_test.go +++ b/internal/php7/parser_test.go @@ -18412,90 +18412,82 @@ func TestStmtGlobal_Vars(t *testing.T) { }, }, }, - VarName: &ast.ParserBrackets{ + OpenCurlyBracketTkn: &token.Token{ + ID: token.ID(123), + Value: []byte("{"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, - EndPos: 31, + EndPos: 25, }, - OpenBracketTkn: &token.Token{ - ID: token.ID(123), - Value: []byte("{"), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 24, - EndPos: 25, - }, + }, + VarName: &ast.ExprFunctionCall{ + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 25, + EndPos: 30, }, - Child: &ast.ExprFunctionCall{ + Function: &ast.NameName{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 25, - EndPos: 30, + EndPos: 28, }, - Function: &ast.NameName{ - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 25, - EndPos: 28, - }, - Parts: []ast.Vertex{ - &ast.NameNamePart{ + Parts: []ast.Vertex{ + &ast.NameNamePart{ + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 25, + EndPos: 28, + }, + StringTkn: &token.Token{ + ID: token.T_STRING, + Value: []byte("foo"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 25, EndPos: 28, }, - StringTkn: &token.Token{ - ID: token.T_STRING, - Value: []byte("foo"), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 25, - EndPos: 28, - }, - }, - Value: []byte("foo"), }, - }, - }, - OpenParenthesisTkn: &token.Token{ - ID: token.ID(40), - Value: []byte("("), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 28, - EndPos: 29, - }, - }, - CloseParenthesisTkn: &token.Token{ - ID: token.ID(41), - Value: []byte(")"), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 29, - EndPos: 30, + Value: []byte("foo"), }, }, }, - CloseBracketTkn: &token.Token{ - ID: token.ID(125), - Value: []byte("}"), + OpenParenthesisTkn: &token.Token{ + ID: token.ID(40), + Value: []byte("("), Position: &position.Position{ StartLine: 1, EndLine: 1, - StartPos: 30, - EndPos: 31, + StartPos: 28, + EndPos: 29, }, }, + CloseParenthesisTkn: &token.Token{ + ID: token.ID(41), + Value: []byte(")"), + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 29, + EndPos: 30, + }, + }, + }, + CloseCurlyBracketTkn: &token.Token{ + ID: token.ID(125), + Value: []byte("}"), + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 30, + EndPos: 31, + }, }, }, }, diff --git a/internal/php7/php7.go b/internal/php7/php7.go index 2c5e9d0..da378e5 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 4e44911..ae5f176 100644 --- a/internal/php7/php7.y +++ b/internal/php7/php7.y @@ -3790,14 +3790,11 @@ simple_variable: | '$' '{' expr '}' { $$ = &ast.ExprVariable{ - Position: yylex.(*Parser).builder.NewTokensPosition($1, $4), - DollarTkn: $1, - VarName: &ast.ParserBrackets{ - Position: yylex.(*Parser).builder.NewTokensPosition($2, $4), - OpenBracketTkn: $2, - Child: $3, - CloseBracketTkn: $4, - }, + Position: yylex.(*Parser).builder.NewTokensPosition($1, $4), + DollarTkn: $1, + OpenCurlyBracketTkn: $2, + VarName: $3, + CloseCurlyBracketTkn: $4, } } | '$' simple_variable diff --git a/pkg/ast/node.go b/pkg/ast/node.go index e85fde6..400537f 100644 --- a/pkg/ast/node.go +++ b/pkg/ast/node.go @@ -1761,9 +1761,11 @@ func (n *ExprUnaryPlus) GetPosition() *position.Position { // ExprVariable node type ExprVariable struct { - Position *position.Position - DollarTkn *token.Token - VarName Vertex + Position *position.Position + DollarTkn *token.Token + OpenCurlyBracketTkn *token.Token + VarName Vertex + CloseCurlyBracketTkn *token.Token } func (n *ExprVariable) Accept(v NodeVisitor) { diff --git a/pkg/ast/visitor/dumper.go b/pkg/ast/visitor/dumper.go index dc5536d..9778215 100644 --- a/pkg/ast/visitor/dumper.go +++ b/pkg/ast/visitor/dumper.go @@ -1537,7 +1537,9 @@ func (v *Dumper) ExprVariable(n *ast.ExprVariable) { v.dumpPosition(n.Position) v.dumpToken("DollarTkn", n.DollarTkn) + v.dumpToken("OpenCurlyBracketTkn", n.OpenCurlyBracketTkn) v.dumpVertex("VarName", n.VarName) + v.dumpToken("CloseCurlyBracketTkn", n.CloseCurlyBracketTkn) v.indent-- v.print(v.indent, "},\n") diff --git a/pkg/ast/visitor/formatter.go b/pkg/ast/visitor/formatter.go index f66c766..7fde3cb 100644 --- a/pkg/ast/visitor/formatter.go +++ b/pkg/ast/visitor/formatter.go @@ -1417,6 +1417,16 @@ func (f *formatter) ExprVariable(n *ast.ExprVariable) { n.DollarTkn = f.newToken('$', []byte("$")) } + n.OpenCurlyBracketTkn = nil + n.CloseCurlyBracketTkn = nil + switch n.VarName.(type) { + case *ast.Identifier: + case *ast.ExprVariable: + default: + n.OpenCurlyBracketTkn = f.newToken('{', []byte("{")) + n.CloseCurlyBracketTkn = f.newToken('}', []byte("}")) + } + n.VarName.Accept(f) } diff --git a/pkg/ast/visitor/formatter_test.go b/pkg/ast/visitor/formatter_test.go index 6a72c6b..62580e7 100644 --- a/pkg/ast/visitor/formatter_test.go +++ b/pkg/ast/visitor/formatter_test.go @@ -4877,6 +4877,29 @@ func TestFormatter_ExprVariable_Variable(t *testing.T) { } } +func TestFormatter_ExprVariable_Expression(t *testing.T) { + o := bytes.NewBufferString("") + + n := &ast.ExprVariable{ + VarName: &ast.ScalarString{ + Value: []byte("'foo'"), + }, + } + + f := visitor.NewFormatter().WithState(visitor.FormatterStatePHP).WithIndent(1) + n.Accept(f) + + p := visitor.NewPrinter(o).WithState(visitor.PrinterStatePHP) + n.Accept(p) + + expected := `${'foo'}` + actual := o.String() + + if expected != actual { + t.Errorf("\nexpected: %s\ngot: %s\n", expected, actual) + } +} + func TestFormatter_ExprYield(t *testing.T) { o := bytes.NewBufferString("") diff --git a/pkg/ast/visitor/printer.go b/pkg/ast/visitor/printer.go index 7fba6a1..99db93a 100644 --- a/pkg/ast/visitor/printer.go +++ b/pkg/ast/visitor/printer.go @@ -868,7 +868,9 @@ func (p *printer) ExprUnaryPlus(n *ast.ExprUnaryPlus) { func (p *printer) ExprVariable(n *ast.ExprVariable) { p.printToken(n.DollarTkn, nil) + p.printToken(n.OpenCurlyBracketTkn, nil) p.printNode(n.VarName) + p.printToken(n.CloseCurlyBracketTkn, nil) } func (p *printer) ExprYield(n *ast.ExprYield) { diff --git a/pkg/ast/visitor/printer_test.go b/pkg/ast/visitor/printer_test.go index 3f75246..621ea27 100644 --- a/pkg/ast/visitor/printer_test.go +++ b/pkg/ast/visitor/printer_test.go @@ -2609,13 +2609,19 @@ func TestPrinterPrintVariable(t *testing.T) { DollarTkn: &token.Token{ Value: []byte("$"), }, + OpenCurlyBracketTkn: &token.Token{ + Value: []byte("{"), + }, VarName: &ast.ExprVariable{ VarName: &ast.Identifier{Value: []byte("$var")}, }, + CloseCurlyBracketTkn: &token.Token{ + Value: []byte("}"), + }, } n.Accept(p) - expected := `$$var` + expected := `${$var}` actual := o.String() if expected != actual {