package php8_test import ( "testing" "github.com/VKCOM/php-parser/internal/php8" "gotest.tools/assert" "github.com/VKCOM/php-parser/pkg/ast" "github.com/VKCOM/php-parser/pkg/conf" "github.com/VKCOM/php-parser/pkg/errors" "github.com/VKCOM/php-parser/pkg/position" "github.com/VKCOM/php-parser/pkg/token" "github.com/VKCOM/php-parser/pkg/version" ) func TestMain(m *testing.M) { // Ignore StartCol and EndCol in equality checks, these tests were written before they were added. position.CheckColEquality = false } func TestIdentifier(t *testing.T) { src := `bar($a, ...$b); foo::bar($a, ...$b); $foo::bar($a, ...$b); new foo($a, ...$b); /** anonymous class */ new class ($a, ...$b) {};` expected := &ast.Root{ Position: &position.Position{ StartLine: 2, EndLine: 9, StartPos: 5, EndPos: 185, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 20, }, Expr: &ast.ExprFunctionCall{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 19, }, Function: &ast.Name{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 8, }, Parts: []ast.Vertex{ &ast.NamePart{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 8, }, StringTkn: &token.Token{ ID: token.T_STRING, Value: []byte("foo"), Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 8, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 46, EndPos: 48, }, }, Method: &ast.Identifier{ Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 48, EndPos: 51, }, IdentifierTkn: &token.Token{ ID: token.T_STRING, Value: []byte("bar"), Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 48, EndPos: 51, }, }, Value: []byte("bar"), }, OpenParenthesisTkn: &token.Token{ ID: token.ID(40), Value: []byte("("), Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 51, EndPos: 52, }, }, Args: []ast.Vertex{ &ast.Argument{ Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 52, EndPos: 54, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 52, EndPos: 54, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 52, EndPos: 54, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 52, EndPos: 54, }, }, Value: []byte("$a"), }, }, }, &ast.Argument{ Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 56, EndPos: 61, }, VariadicTkn: &token.Token{ ID: token.T_ELLIPSIS, Value: []byte("..."), Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 56, EndPos: 59, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 55, EndPos: 56, }, }, }, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 59, EndPos: 61, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 59, EndPos: 61, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 59, EndPos: 61, }, }, Value: []byte("$b"), }, }, }, }, SeparatorTkns: []*token.Token{ { ID: token.ID(44), Value: []byte(","), Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 54, EndPos: 55, }, }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 61, EndPos: 62, }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 4, EndLine: 4, StartPos: 62, EndPos: 63, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 66, EndPos: 86, }, Expr: &ast.ExprStaticCall{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 66, EndPos: 85, }, Class: &ast.Name{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 66, EndPos: 69, }, Parts: []ast.Vertex{ &ast.NamePart{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 66, EndPos: 69, }, StringTkn: &token.Token{ ID: token.T_STRING, Value: []byte("foo"), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 66, EndPos: 69, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 4, EndLine: 5, StartPos: 63, EndPos: 66, }, }, }, }, Value: []byte("foo"), }, }, }, DoubleColonTkn: &token.Token{ ID: token.T_PAAMAYIM_NEKUDOTAYIM, Value: []byte("::"), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 69, EndPos: 71, }, }, Call: &ast.Identifier{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 71, EndPos: 74, }, IdentifierTkn: &token.Token{ ID: token.T_STRING, Value: []byte("bar"), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 71, EndPos: 74, }, }, Value: []byte("bar"), }, OpenParenthesisTkn: &token.Token{ ID: token.ID(40), Value: []byte("("), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 74, EndPos: 75, }, }, Args: []ast.Vertex{ &ast.Argument{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 75, EndPos: 77, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 75, EndPos: 77, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 75, EndPos: 77, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 75, EndPos: 77, }, }, Value: []byte("$a"), }, }, }, &ast.Argument{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 79, EndPos: 84, }, VariadicTkn: &token.Token{ ID: token.T_ELLIPSIS, Value: []byte("..."), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 79, EndPos: 82, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 78, EndPos: 79, }, }, }, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 82, EndPos: 84, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 82, EndPos: 84, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 82, EndPos: 84, }, }, Value: []byte("$b"), }, }, }, }, SeparatorTkns: []*token.Token{ { ID: token.ID(44), Value: []byte(","), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 77, EndPos: 78, }, }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 84, EndPos: 85, }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 5, EndLine: 5, StartPos: 85, EndPos: 86, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 89, EndPos: 110, }, Expr: &ast.ExprStaticCall{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 89, EndPos: 109, }, Class: &ast.ExprVariable{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 89, EndPos: 93, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 89, EndPos: 93, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$foo"), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 89, EndPos: 93, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 5, EndLine: 6, StartPos: 86, EndPos: 89, }, }, }, }, Value: []byte("$foo"), }, }, DoubleColonTkn: &token.Token{ ID: token.T_PAAMAYIM_NEKUDOTAYIM, Value: []byte("::"), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 93, EndPos: 95, }, }, Call: &ast.Identifier{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 95, EndPos: 98, }, IdentifierTkn: &token.Token{ ID: token.T_STRING, Value: []byte("bar"), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 95, EndPos: 98, }, }, Value: []byte("bar"), }, OpenParenthesisTkn: &token.Token{ ID: token.ID(40), Value: []byte("("), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 98, EndPos: 99, }, }, Args: []ast.Vertex{ &ast.Argument{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 99, EndPos: 101, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 99, EndPos: 101, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 99, EndPos: 101, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 99, EndPos: 101, }, }, Value: []byte("$a"), }, }, }, &ast.Argument{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 103, EndPos: 108, }, VariadicTkn: &token.Token{ ID: token.T_ELLIPSIS, Value: []byte("..."), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 103, EndPos: 106, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 102, EndPos: 103, }, }, }, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 106, EndPos: 108, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 106, EndPos: 108, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 106, EndPos: 108, }, }, Value: []byte("$b"), }, }, }, }, SeparatorTkns: []*token.Token{ { ID: token.ID(44), Value: []byte(","), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 101, EndPos: 102, }, }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 108, EndPos: 109, }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 6, EndLine: 6, StartPos: 109, EndPos: 110, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 113, EndPos: 132, }, Expr: &ast.ExprNew{ Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 113, EndPos: 131, }, NewTkn: &token.Token{ ID: token.T_NEW, Value: []byte("new"), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 113, EndPos: 116, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 6, EndLine: 7, StartPos: 110, EndPos: 113, }, }, }, }, Class: &ast.Name{ Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 117, EndPos: 120, }, Parts: []ast.Vertex{ &ast.NamePart{ Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 117, EndPos: 120, }, StringTkn: &token.Token{ ID: token.T_STRING, Value: []byte("foo"), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 117, EndPos: 120, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 116, EndPos: 117, }, }, }, }, Value: []byte("foo"), }, }, }, OpenParenthesisTkn: &token.Token{ ID: token.ID(40), Value: []byte("("), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 120, EndPos: 121, }, }, Args: []ast.Vertex{ &ast.Argument{ Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 121, EndPos: 123, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 121, EndPos: 123, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 121, EndPos: 123, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 121, EndPos: 123, }, }, Value: []byte("$a"), }, }, }, &ast.Argument{ Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 125, EndPos: 130, }, VariadicTkn: &token.Token{ ID: token.T_ELLIPSIS, Value: []byte("..."), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 125, EndPos: 128, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 124, EndPos: 125, }, }, }, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 128, EndPos: 130, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 128, EndPos: 130, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 128, EndPos: 130, }, }, Value: []byte("$b"), }, }, }, }, SeparatorTkns: []*token.Token{ { ID: token.ID(44), Value: []byte(","), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 123, EndPos: 124, }, }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 130, EndPos: 131, }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 7, EndLine: 7, StartPos: 131, EndPos: 132, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 160, EndPos: 185, }, Expr: &ast.ExprNew{ Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 160, EndPos: 184, }, NewTkn: &token.Token{ ID: token.T_NEW, Value: []byte("new"), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 160, EndPos: 163, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 7, EndLine: 8, StartPos: 132, EndPos: 135, }, }, { ID: token.T_DOC_COMMENT, Value: []byte("/** anonymous class */"), Position: &position.Position{ StartLine: 8, EndLine: 8, StartPos: 135, EndPos: 157, }, }, { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 8, EndLine: 9, StartPos: 157, EndPos: 160, }, }, }, }, Class: &ast.StmtClass{ Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 164, EndPos: 184, }, ClassTkn: &token.Token{ ID: token.T_CLASS, Value: []byte("class"), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 164, EndPos: 169, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 163, EndPos: 164, }, }, }, }, OpenParenthesisTkn: &token.Token{ ID: token.ID(40), Value: []byte("("), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 170, EndPos: 171, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 169, EndPos: 170, }, }, }, }, Args: []ast.Vertex{ &ast.Argument{ Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 171, EndPos: 173, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 171, EndPos: 173, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 171, EndPos: 173, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 171, EndPos: 173, }, }, Value: []byte("$a"), }, }, }, &ast.Argument{ Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 175, EndPos: 180, }, VariadicTkn: &token.Token{ ID: token.T_ELLIPSIS, Value: []byte("..."), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 175, EndPos: 178, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 174, EndPos: 175, }, }, }, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 178, EndPos: 180, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 178, EndPos: 180, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 178, EndPos: 180, }, }, Value: []byte("$b"), }, }, }, }, SeparatorTkns: []*token.Token{ { ID: token.ID(44), Value: []byte(","), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 173, EndPos: 174, }, }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 180, EndPos: 181, }, }, OpenCurlyBracketTkn: &token.Token{ ID: token.ID(123), Value: []byte("{"), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 182, EndPos: 183, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 181, EndPos: 182, }, }, }, }, Stmts: []ast.Vertex{}, CloseCurlyBracketTkn: &token.Token{ ID: token.ID(125), Value: []byte("}"), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 183, EndPos: 184, }, }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 9, EndLine: 9, StartPos: 184, EndPos: 185, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestPhp8ParameterNode(t *testing.T) { src := `bar()";` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 22, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 22, }, Expr: &ast.ScalarEncapsed{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 21, }, OpenQuoteTkn: &token.Token{ ID: token.ID(34), Value: []byte("\""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 4, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 13, EndPos: 15, }, }, Prop: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 15, EndPos: 18, }, IdentifierTkn: &token.Token{ ID: token.T_STRING, Value: []byte("bar"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 15, EndPos: 18, }, }, Value: []byte("bar"), }, }, &ast.ScalarEncapsedStringPart{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 18, EndPos: 20, }, EncapsedStrTkn: &token.Token{ ID: token.T_ENCAPSED_AND_WHITESPACE, Value: []byte("()"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 18, EndPos: 20, }, }, Value: []byte("()"), }, }, CloseQuoteTkn: &token.Token{ ID: token.ID(34), Value: []byte("\""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 20, EndPos: 21, }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 21, EndPos: 22, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestScalarEncapsed_DollarOpenCurlyBraces(t *testing.T) { src := `bar()}";` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 24, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 24, }, Expr: &ast.ScalarEncapsed{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 23, }, OpenQuoteTkn: &token.Token{ ID: token.ID(34), Value: []byte("\""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 4, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 14, EndPos: 16, }, }, Method: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 16, EndPos: 19, }, IdentifierTkn: &token.Token{ ID: token.T_STRING, Value: []byte("bar"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 16, EndPos: 19, }, }, Value: []byte("bar"), }, OpenParenthesisTkn: &token.Token{ ID: token.ID(40), Value: []byte("("), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 19, EndPos: 20, }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 20, EndPos: 21, }, }, }, CloseCurlyBracketTkn: &token.Token{ ID: token.ID(125), Value: []byte("}"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 21, EndPos: 22, }, }, }, }, CloseQuoteTkn: &token.Token{ ID: token.ID(34), Value: []byte("\""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 22, EndPos: 23, }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 23, EndPos: 24, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestScalarHeredoc_HeredocSimpleLabel(t *testing.T) { src := ` $v) {}` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 30, }, Stmts: []ast.Vertex{ &ast.StmtForeach{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 30, }, ForeachTkn: &token.Token{ ID: token.T_FOREACH, Value: []byte("foreach"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 10, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 21, EndPos: 23, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 20, EndPos: 21, }, }, }, }, Var: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, EndPos: 26, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, EndPos: 26, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$v"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, EndPos: 26, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 23, EndPos: 24, }, }, }, }, Value: []byte("$v"), }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 26, EndPos: 27, }, }, Stmt: &ast.StmtStmtList{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 28, EndPos: 30, }, OpenCurlyBracketTkn: &token.Token{ ID: token.ID(123), Value: []byte("{"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 28, EndPos: 29, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 27, EndPos: 28, }, }, }, }, Stmts: []ast.Vertex{}, CloseCurlyBracketTkn: &token.Token{ ID: token.ID(125), Value: []byte("}"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 29, EndPos: 30, }, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestStmtForeach_ExprWithKey(t *testing.T) { src := ` $v) {}` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 30, }, Stmts: []ast.Vertex{ &ast.StmtForeach{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 30, }, ForeachTkn: &token.Token{ ID: token.T_FOREACH, Value: []byte("foreach"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 10, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 21, EndPos: 23, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 20, EndPos: 21, }, }, }, }, Var: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, EndPos: 26, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, EndPos: 26, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$v"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, EndPos: 26, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 23, EndPos: 24, }, }, }, }, Value: []byte("$v"), }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 26, EndPos: 27, }, }, Stmt: &ast.StmtStmtList{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 28, EndPos: 30, }, OpenCurlyBracketTkn: &token.Token{ ID: token.ID(123), Value: []byte("{"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 28, EndPos: 29, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 27, EndPos: 28, }, }, }, }, Stmts: []ast.Vertex{}, CloseCurlyBracketTkn: &token.Token{ ID: token.ID(125), Value: []byte("}"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 29, EndPos: 30, }, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestStmtForeach_WithRef(t *testing.T) { src := ` &$v) {}` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 31, }, Stmts: []ast.Vertex{ &ast.StmtForeach{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 31, }, ForeachTkn: &token.Token{ ID: token.T_FOREACH, Value: []byte("foreach"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 10, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 21, EndPos: 23, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 20, EndPos: 21, }, }, }, }, AmpersandTkn: &token.Token{ ID: token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, Value: []byte("&"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, EndPos: 25, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 23, EndPos: 24, }, }, }, }, Var: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 25, EndPos: 27, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 25, EndPos: 27, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$v"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 25, EndPos: 27, }, }, Value: []byte("$v"), }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 27, EndPos: 28, }, }, Stmt: &ast.StmtStmtList{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 29, EndPos: 31, }, OpenCurlyBracketTkn: &token.Token{ ID: token.ID(123), Value: []byte("{"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 29, EndPos: 30, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 28, EndPos: 29, }, }, }, }, Stmts: []ast.Vertex{}, CloseCurlyBracketTkn: &token.Token{ ID: token.ID(125), Value: []byte("}"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 30, EndPos: 31, }, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestStmtForeach_WithList(t *testing.T) { src := ` list($v)) {}` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 36, }, Stmts: []ast.Vertex{ &ast.StmtForeach{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 36, }, ForeachTkn: &token.Token{ ID: token.T_FOREACH, Value: []byte("foreach"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 10, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 21, EndPos: 23, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 20, EndPos: 21, }, }, }, }, Var: &ast.ExprList{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, EndPos: 32, }, ListTkn: &token.Token{ ID: token.T_LIST, Value: []byte("list"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, EndPos: 28, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 23, EndPos: 24, }, }, }, }, OpenBracketTkn: &token.Token{ ID: token.ID(40), Value: []byte("("), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 28, EndPos: 29, }, }, Items: []ast.Vertex{ &ast.ExprArrayItem{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 29, EndPos: 31, }, Val: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 29, EndPos: 31, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 29, EndPos: 31, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$v"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 29, EndPos: 31, }, }, Value: []byte("$v"), }, }, }, }, CloseBracketTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 31, EndPos: 32, }, }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 32, EndPos: 33, }, }, Stmt: &ast.StmtStmtList{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 34, EndPos: 36, }, OpenCurlyBracketTkn: &token.Token{ ID: token.ID(123), Value: []byte("{"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 34, EndPos: 35, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 33, EndPos: 34, }, }, }, }, Stmts: []ast.Vertex{}, CloseCurlyBracketTkn: &token.Token{ ID: token.ID(125), Value: []byte("}"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 35, EndPos: 36, }, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestStmtFunction(t *testing.T) { src := `
` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 17, }, Stmts: []ast.Vertex{ &ast.StmtNop{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 5, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte("?>"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 5, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 5, EndPos: 17, }, }, Value: []byte("
"), }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestStmtInterface(t *testing.T) { src := `1, &$b,);` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 21, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 21, }, Expr: &ast.ExprArray{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 20, }, ArrayTkn: &token.Token{ ID: token.T_ARRAY, Value: []byte("array"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 8, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 10, EndPos: 12, }, }, Val: &ast.ScalarLnumber{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 12, EndPos: 13, }, NumberTkn: &token.Token{ ID: token.T_LNUMBER, Value: []byte("1"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 12, EndPos: 13, }, }, Value: []byte("1"), }, }, &ast.ExprArrayItem{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 15, EndPos: 18, }, AmpersandTkn: &token.Token{ ID: token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, Value: []byte("&"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 15, EndPos: 16, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 14, EndPos: 15, }, }, }, }, Val: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 16, EndPos: 18, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 16, EndPos: 18, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 16, EndPos: 18, }, }, Value: []byte("$b"), }, }, }, &ast.ExprArrayItem{}, }, SeparatorTkns: []*token.Token{ { ID: token.ID(44), Value: []byte(","), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 13, EndPos: 14, }, }, { ID: token.ID(44), Value: []byte(","), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 18, EndPos: 19, }, }, }, CloseBracketTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 19, EndPos: 20, }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 20, EndPos: 21, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestExprArray_ItemUnpack(t *testing.T) { src := ` $a;` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 14, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 14, }, Expr: &ast.ExprArrowFunction{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 13, }, FnTkn: &token.Token{ ID: token.T_FN, Value: []byte("fn"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 5, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 8, EndPos: 10, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 7, EndPos: 8, }, }, }, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 11, EndPos: 13, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 11, EndPos: 13, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 11, EndPos: 13, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 10, EndPos: 11, }, }, }, }, Value: []byte("$a"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 13, EndPos: 14, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestExprArrowFunction_ReturnType(t *testing.T) { src := ` $a;` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 23, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 23, }, Expr: &ast.ExprArrowFunction{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 22, }, FnTkn: &token.Token{ ID: token.T_FN, Value: []byte("fn"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 5, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 17, EndPos: 19, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 16, EndPos: 17, }, }, }, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 20, EndPos: 22, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 20, EndPos: 22, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 20, EndPos: 22, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 19, EndPos: 20, }, }, }, }, Value: []byte("$a"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 22, EndPos: 23, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestExprBitwiseNot(t *testing.T) { src := `foo();` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 13, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 13, }, Expr: &ast.ExprMethodCall{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 12, }, Var: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 5, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 5, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 5, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 5, EndPos: 7, }, }, Method: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 7, EndPos: 10, }, IdentifierTkn: &token.Token{ ID: token.T_STRING, Value: []byte("foo"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 7, EndPos: 10, }, }, Value: []byte("foo"), }, OpenParenthesisTkn: &token.Token{ ID: token.ID(40), Value: []byte("("), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 10, EndPos: 11, }, }, CloseParenthesisTkn: &token.Token{ ID: token.ID(41), Value: []byte(")"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 11, EndPos: 12, }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 12, EndPos: 13, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestExprNew(t *testing.T) { src := `foo;` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 11, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 11, }, Expr: &ast.ExprPropertyFetch{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 10, }, Var: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 5, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 5, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 5, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 5, EndPos: 7, }, }, Prop: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 7, EndPos: 10, }, IdentifierTkn: &token.Token{ ID: token.T_STRING, Value: []byte("foo"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 7, EndPos: 10, }, }, Value: []byte("foo"), }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 10, EndPos: 11, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestExprShellExec(t *testing.T) { src := "1, &$b,];` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 16, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 16, }, Expr: &ast.ExprArray{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 15, }, OpenBracketTkn: &token.Token{ ID: token.ID(91), Value: []byte("["), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 4, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 5, EndPos: 7, }, }, Val: &ast.ScalarLnumber{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 7, EndPos: 8, }, NumberTkn: &token.Token{ ID: token.T_LNUMBER, Value: []byte("1"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 7, EndPos: 8, }, }, Value: []byte("1"), }, }, &ast.ExprArrayItem{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 10, EndPos: 13, }, AmpersandTkn: &token.Token{ ID: token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, Value: []byte("&"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 10, EndPos: 11, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 9, EndPos: 10, }, }, }, }, Val: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 11, EndPos: 13, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 11, EndPos: 13, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 11, EndPos: 13, }, }, Value: []byte("$b"), }, }, }, &ast.ExprArrayItem{}, }, SeparatorTkns: []*token.Token{ { ID: token.ID(44), Value: []byte(","), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 8, EndPos: 9, }, }, { ID: token.ID(44), Value: []byte(","), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 13, EndPos: 14, }, }, }, CloseBracketTkn: &token.Token{ ID: token.ID(93), Value: []byte("]"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 14, EndPos: 15, }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 15, EndPos: 16, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestExprShortList(t *testing.T) { src := ` $b;` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 18, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 18, }, Expr: &ast.ExprYield{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 17, }, YieldTkn: &token.Token{ ID: token.T_YIELD, Value: []byte("yield"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 8, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 12, EndPos: 14, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 11, EndPos: 12, }, }, }, }, Val: &ast.ExprVariable{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 15, EndPos: 17, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 15, EndPos: 17, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 15, EndPos: 17, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 14, EndPos: 15, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 17, EndPos: 18, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestExprYield_Expr(t *testing.T) { src := ` 1;` expected := &ast.Root{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 17, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 17, }, Expr: &ast.ExprYield{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 16, }, YieldTkn: &token.Token{ ID: token.T_YIELD, Value: []byte("yield"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 3, EndPos: 8, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(""), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 12, EndPos: 14, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 11, EndPos: 12, }, }, }, }, Val: &ast.ScalarLnumber{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 15, EndPos: 16, }, NumberTkn: &token.Token{ ID: token.T_LNUMBER, Value: []byte("1"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 15, EndPos: 16, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 14, EndPos: 15, }, }, }, }, Value: []byte("1"), }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 16, EndPos: 17, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } func TestExprYieldFrom(t *testing.T) { src := `>= $b; $a ??= $b;` expected := &ast.Root{ Position: &position.Position{ StartLine: 2, EndLine: 18, StartPos: 5, EndPos: 223, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 13, }, Expr: &ast.ExprAssign{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 12, }, Var: &ast.ExprVariable{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 7, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 7, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 7, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(">="), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 203, EndPos: 206, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 202, EndPos: 203, }, }, }, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 207, EndPos: 209, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 207, EndPos: 209, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 207, EndPos: 209, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 206, EndPos: 207, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 209, EndPos: 210, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 213, EndPos: 223, }, Expr: &ast.ExprAssignCoalesce{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 213, EndPos: 222, }, Var: &ast.ExprVariable{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 213, EndPos: 215, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 213, EndPos: 215, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 213, EndPos: 215, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 17, EndLine: 18, StartPos: 210, EndPos: 213, }, }, }, }, Value: []byte("$a"), }, }, EqualTkn: &token.Token{ ID: token.T_COALESCE_EQUAL, Value: []byte("??="), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 216, EndPos: 219, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 215, EndPos: 216, }, }, }, }, Expr: &ast.ExprVariable{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 220, EndPos: 222, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 220, EndPos: 222, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 220, EndPos: 222, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 219, EndPos: 220, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 222, EndPos: 223, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } // expr binary func TestExprBinary_BitwiseAnd(t *testing.T) { src := `= $b; $a > $b; $a === $b; $a and $b; $a or $b; $a xor $b; $a - $b; $a % $b; $a * $b; $a != $b; $a !== $b; $a + $b; $a ** $b; $a << $b; $a >> $b; $a <= $b; $a < $b; $a <=> $b;` expected := &ast.Root{ Position: &position.Position{ StartLine: 2, EndLine: 28, StartPos: 5, EndPos: 320, }, Stmts: []ast.Vertex{ &ast.StmtExpression{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 13, }, Expr: &ast.ExprBinaryBitwiseAnd{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 12, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 7, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 7, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 2, EndLine: 2, StartPos: 5, EndPos: 7, }, FreeFloating: []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte("="), Position: &position.Position{ StartLine: 11, EndLine: 11, StartPos: 111, EndPos: 113, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 11, EndLine: 11, StartPos: 110, EndPos: 111, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 11, EndLine: 11, StartPos: 114, EndPos: 116, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 11, EndLine: 11, StartPos: 114, EndPos: 116, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 11, EndLine: 11, StartPos: 114, EndPos: 116, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 11, EndLine: 11, StartPos: 113, EndPos: 114, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 11, EndLine: 11, StartPos: 116, EndPos: 117, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 120, EndPos: 128, }, Expr: &ast.ExprBinaryGreater{ Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 120, EndPos: 127, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 120, EndPos: 122, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 120, EndPos: 122, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 120, EndPos: 122, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 11, EndLine: 12, StartPos: 117, EndPos: 120, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.ID(62), Value: []byte(">"), Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 123, EndPos: 124, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 122, EndPos: 123, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 125, EndPos: 127, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 125, EndPos: 127, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 125, EndPos: 127, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 124, EndPos: 125, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 12, EndLine: 12, StartPos: 127, EndPos: 128, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 131, EndPos: 141, }, Expr: &ast.ExprBinaryIdentical{ Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 131, EndPos: 140, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 131, EndPos: 133, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 131, EndPos: 133, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 131, EndPos: 133, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 12, EndLine: 13, StartPos: 128, EndPos: 131, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_IS_IDENTICAL, Value: []byte("==="), Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 134, EndPos: 137, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 133, EndPos: 134, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 138, EndPos: 140, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 138, EndPos: 140, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 138, EndPos: 140, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 137, EndPos: 138, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 13, EndLine: 13, StartPos: 140, EndPos: 141, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 144, EndPos: 154, }, Expr: &ast.ExprBinaryLogicalAnd{ Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 144, EndPos: 153, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 144, EndPos: 146, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 144, EndPos: 146, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 144, EndPos: 146, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 13, EndLine: 14, StartPos: 141, EndPos: 144, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_LOGICAL_AND, Value: []byte("and"), Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 147, EndPos: 150, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 146, EndPos: 147, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 151, EndPos: 153, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 151, EndPos: 153, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 151, EndPos: 153, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 150, EndPos: 151, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 14, EndLine: 14, StartPos: 153, EndPos: 154, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 157, EndPos: 166, }, Expr: &ast.ExprBinaryLogicalOr{ Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 157, EndPos: 165, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 157, EndPos: 159, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 157, EndPos: 159, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 157, EndPos: 159, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 14, EndLine: 15, StartPos: 154, EndPos: 157, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_LOGICAL_OR, Value: []byte("or"), Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 160, EndPos: 162, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 159, EndPos: 160, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 163, EndPos: 165, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 163, EndPos: 165, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 163, EndPos: 165, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 162, EndPos: 163, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 15, EndLine: 15, StartPos: 165, EndPos: 166, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 169, EndPos: 179, }, Expr: &ast.ExprBinaryLogicalXor{ Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 169, EndPos: 178, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 169, EndPos: 171, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 169, EndPos: 171, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 169, EndPos: 171, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 15, EndLine: 16, StartPos: 166, EndPos: 169, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_LOGICAL_XOR, Value: []byte("xor"), Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 172, EndPos: 175, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 171, EndPos: 172, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 176, EndPos: 178, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 176, EndPos: 178, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 176, EndPos: 178, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 175, EndPos: 176, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 16, EndLine: 16, StartPos: 178, EndPos: 179, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 182, EndPos: 190, }, Expr: &ast.ExprBinaryMinus{ Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 182, EndPos: 189, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 182, EndPos: 184, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 182, EndPos: 184, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 182, EndPos: 184, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 16, EndLine: 17, StartPos: 179, EndPos: 182, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.ID(45), Value: []byte("-"), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 185, EndPos: 186, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 184, EndPos: 185, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 187, EndPos: 189, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 187, EndPos: 189, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 187, EndPos: 189, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 186, EndPos: 187, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 17, EndLine: 17, StartPos: 189, EndPos: 190, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 193, EndPos: 201, }, Expr: &ast.ExprBinaryMod{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 193, EndPos: 200, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 193, EndPos: 195, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 193, EndPos: 195, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 193, EndPos: 195, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 17, EndLine: 18, StartPos: 190, EndPos: 193, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.ID(37), Value: []byte("%"), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 196, EndPos: 197, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 195, EndPos: 196, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 198, EndPos: 200, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 198, EndPos: 200, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 198, EndPos: 200, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 197, EndPos: 198, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 18, EndLine: 18, StartPos: 200, EndPos: 201, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 204, EndPos: 212, }, Expr: &ast.ExprBinaryMul{ Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 204, EndPos: 211, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 204, EndPos: 206, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 204, EndPos: 206, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 204, EndPos: 206, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 18, EndLine: 19, StartPos: 201, EndPos: 204, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.ID(42), Value: []byte("*"), Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 207, EndPos: 208, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 206, EndPos: 207, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 209, EndPos: 211, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 209, EndPos: 211, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 209, EndPos: 211, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 208, EndPos: 209, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 19, EndLine: 19, StartPos: 211, EndPos: 212, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 215, EndPos: 224, }, Expr: &ast.ExprBinaryNotEqual{ Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 215, EndPos: 223, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 215, EndPos: 217, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 215, EndPos: 217, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 215, EndPos: 217, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 19, EndLine: 20, StartPos: 212, EndPos: 215, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_IS_NOT_EQUAL, Value: []byte("!="), Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 218, EndPos: 220, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 217, EndPos: 218, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 221, EndPos: 223, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 221, EndPos: 223, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 221, EndPos: 223, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 220, EndPos: 221, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 20, EndLine: 20, StartPos: 223, EndPos: 224, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 227, EndPos: 237, }, Expr: &ast.ExprBinaryNotIdentical{ Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 227, EndPos: 236, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 227, EndPos: 229, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 227, EndPos: 229, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 227, EndPos: 229, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 20, EndLine: 21, StartPos: 224, EndPos: 227, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_IS_NOT_IDENTICAL, Value: []byte("!=="), Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 230, EndPos: 233, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 229, EndPos: 230, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 234, EndPos: 236, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 234, EndPos: 236, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 234, EndPos: 236, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 233, EndPos: 234, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 21, EndLine: 21, StartPos: 236, EndPos: 237, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 240, EndPos: 248, }, Expr: &ast.ExprBinaryPlus{ Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 240, EndPos: 247, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 240, EndPos: 242, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 240, EndPos: 242, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 240, EndPos: 242, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 21, EndLine: 22, StartPos: 237, EndPos: 240, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.ID(43), Value: []byte("+"), Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 243, EndPos: 244, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 242, EndPos: 243, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 245, EndPos: 247, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 245, EndPos: 247, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 245, EndPos: 247, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 244, EndPos: 245, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 22, EndLine: 22, StartPos: 247, EndPos: 248, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 251, EndPos: 260, }, Expr: &ast.ExprBinaryPow{ Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 251, EndPos: 259, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 251, EndPos: 253, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 251, EndPos: 253, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 251, EndPos: 253, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 22, EndLine: 23, StartPos: 248, EndPos: 251, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_POW, Value: []byte("**"), Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 254, EndPos: 256, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 253, EndPos: 254, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 257, EndPos: 259, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 257, EndPos: 259, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 257, EndPos: 259, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 256, EndPos: 257, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 23, EndLine: 23, StartPos: 259, EndPos: 260, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 263, EndPos: 272, }, Expr: &ast.ExprBinaryShiftLeft{ Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 263, EndPos: 271, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 263, EndPos: 265, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 263, EndPos: 265, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 263, EndPos: 265, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 23, EndLine: 24, StartPos: 260, EndPos: 263, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_SL, Value: []byte("<<"), Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 266, EndPos: 268, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 265, EndPos: 266, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 269, EndPos: 271, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 269, EndPos: 271, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 269, EndPos: 271, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 268, EndPos: 269, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 24, EndLine: 24, StartPos: 271, EndPos: 272, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 275, EndPos: 284, }, Expr: &ast.ExprBinaryShiftRight{ Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 275, EndPos: 283, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 275, EndPos: 277, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 275, EndPos: 277, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 275, EndPos: 277, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 24, EndLine: 25, StartPos: 272, EndPos: 275, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_SR, Value: []byte(">>"), Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 278, EndPos: 280, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 277, EndPos: 278, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 281, EndPos: 283, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 281, EndPos: 283, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 281, EndPos: 283, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 280, EndPos: 281, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 25, EndLine: 25, StartPos: 283, EndPos: 284, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 287, EndPos: 296, }, Expr: &ast.ExprBinarySmallerOrEqual{ Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 287, EndPos: 295, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 287, EndPos: 289, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 287, EndPos: 289, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 287, EndPos: 289, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 25, EndLine: 26, StartPos: 284, EndPos: 287, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_IS_SMALLER_OR_EQUAL, Value: []byte("<="), Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 290, EndPos: 292, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 289, EndPos: 290, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 293, EndPos: 295, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 293, EndPos: 295, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 293, EndPos: 295, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 292, EndPos: 293, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 26, EndLine: 26, StartPos: 295, EndPos: 296, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 299, EndPos: 307, }, Expr: &ast.ExprBinarySmaller{ Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 299, EndPos: 306, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 299, EndPos: 301, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 299, EndPos: 301, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 299, EndPos: 301, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 26, EndLine: 27, StartPos: 296, EndPos: 299, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.ID(60), Value: []byte("<"), Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 302, EndPos: 303, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 301, EndPos: 302, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 304, EndPos: 306, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 304, EndPos: 306, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 304, EndPos: 306, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 303, EndPos: 304, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 27, EndLine: 27, StartPos: 306, EndPos: 307, }, }, }, &ast.StmtExpression{ Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 310, EndPos: 320, }, Expr: &ast.ExprBinarySpaceship{ Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 310, EndPos: 319, }, Left: &ast.ExprVariable{ Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 310, EndPos: 312, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 310, EndPos: 312, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$a"), Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 310, EndPos: 312, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte("\n\t\t"), Position: &position.Position{ StartLine: 27, EndLine: 28, StartPos: 307, EndPos: 310, }, }, }, }, Value: []byte("$a"), }, }, OpTkn: &token.Token{ ID: token.T_SPACESHIP, Value: []byte("<=>"), Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 313, EndPos: 316, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 312, EndPos: 313, }, }, }, }, Right: &ast.ExprVariable{ Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 317, EndPos: 319, }, Name: &ast.Identifier{ Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 317, EndPos: 319, }, IdentifierTkn: &token.Token{ ID: token.T_VARIABLE, Value: []byte("$b"), Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 317, EndPos: 319, }, FreeFloating: []*token.Token{ { ID: token.T_WHITESPACE, Value: []byte(" "), Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 316, EndPos: 317, }, }, }, }, Value: []byte("$b"), }, }, }, SemiColonTkn: &token.Token{ ID: token.ID(59), Value: []byte(";"), Position: &position.Position{ StartLine: 28, EndLine: 28, StartPos: 319, EndPos: 320, }, }, }, }, EndTkn: &token.Token{}, } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := php8.NewLexer([]byte(src), config) php8parser := php8.NewParser(lexer, config) php8parser.Parse() actual := php8parser.GetRootNode() assert.DeepEqual(t, expected, actual) } // expr cast func TestStrings(t *testing.T) { src := `