package php7_test

import (
	"testing"

	"gotest.tools/assert"

	"php-parser/internal/php7"
	"php-parser/internal/scanner"
	"php-parser/pkg/ast"
	"php-parser/pkg/conf"
	"php-parser/pkg/errors"
	"php-parser/pkg/position"
	"php-parser/pkg/token"
	"php-parser/pkg/version"
)

func TestIdentifier(t *testing.T) {
	src := `<? $foo;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    8,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    8,
				},
				Expr: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    7,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$foo"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    7,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Value: []byte("$foo"),
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    8,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestPhp7ArgumentNode(t *testing.T) {
	src := `<?
		foo($a, ...$b);
		$foo($a, ...$b);
		$foo->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: 1,
												EndLine:   1,
												StartPos:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte("\n\t\t"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   2,
												StartPos:  2,
												EndPos:    5,
											},
										},
									},
								},
								Value: []byte("foo"),
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  8,
							EndPos:    9,
						},
					},
					Args: []ast.Vertex{
						&ast.Argument{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  9,
								EndPos:    11,
							},
							Expr: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  9,
									EndPos:    11,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  9,
										EndPos:    11,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$a"),
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  9,
											EndPos:    11,
										},
									},
									Value: []byte("$a"),
								},
							},
						},
						&ast.Argument{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  13,
								EndPos:    18,
							},
							VariadicTkn: &token.Token{
								ID:    token.T_ELLIPSIS,
								Value: []byte("..."),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  13,
									EndPos:    16,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  12,
											EndPos:    13,
										},
									},
								},
							},
							Expr: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  16,
									EndPos:    18,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  16,
										EndPos:    18,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$b"),
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  16,
											EndPos:    18,
										},
									},
									Value: []byte("$b"),
								},
							},
						},
					},
					SeparatorTkns: []*token.Token{
						{
							ID:    token.ID(44),
							Value: []byte(","),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  18,
							EndPos:    19,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  19,
						EndPos:    20,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 3,
					EndLine:   3,
					StartPos:  23,
					EndPos:    39,
				},
				Expr: &ast.ExprFunctionCall{
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  23,
						EndPos:    38,
					},
					Function: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  23,
							EndPos:    27,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  23,
								EndPos:    27,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$foo"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  23,
									EndPos:    27,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 2,
											EndLine:   3,
											StartPos:  20,
											EndPos:    23,
										},
									},
								},
							},
							Value: []byte("$foo"),
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  27,
							EndPos:    28,
						},
					},
					Args: []ast.Vertex{
						&ast.Argument{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  28,
								EndPos:    30,
							},
							Expr: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  28,
									EndPos:    30,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  28,
										EndPos:    30,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$a"),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  28,
											EndPos:    30,
										},
									},
									Value: []byte("$a"),
								},
							},
						},
						&ast.Argument{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  32,
								EndPos:    37,
							},
							VariadicTkn: &token.Token{
								ID:    token.T_ELLIPSIS,
								Value: []byte("..."),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  32,
									EndPos:    35,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  31,
											EndPos:    32,
										},
									},
								},
							},
							Expr: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  35,
									EndPos:    37,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  35,
										EndPos:    37,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$b"),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  35,
											EndPos:    37,
										},
									},
									Value: []byte("$b"),
								},
							},
						},
					},
					SeparatorTkns: []*token.Token{
						{
							ID:    token.ID(44),
							Value: []byte(","),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  30,
								EndPos:    31,
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  37,
							EndPos:    38,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  38,
						EndPos:    39,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 4,
					EndLine:   4,
					StartPos:  42,
					EndPos:    63,
				},
				Expr: &ast.ExprMethodCall{
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  42,
						EndPos:    62,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  42,
							EndPos:    46,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  42,
								EndPos:    46,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$foo"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  42,
									EndPos:    46,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   4,
											StartPos:  39,
											EndPos:    42,
										},
									},
								},
							},
							Value: []byte("$foo"),
						},
					},
					ObjectOperatorTkn: &token.Token{
						ID:    token.T_OBJECT_OPERATOR,
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestPhp7ParameterNode(t *testing.T) {
	src := `<?
		function foo(?bar $bar=null, baz &...$baz) {}
		class foo {public function foo(?bar $bar=null, baz &...$baz) {}}
		function(?bar $bar=null, baz &...$baz) {};
		static function(?bar $bar=null, baz &...$baz) {};
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   5,
			StartPos:  5,
			EndPos:    214,
		},
		Stmts: []ast.Vertex{
			&ast.StmtFunction{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   2,
					StartPos:  5,
					EndPos:    50,
				},
				FunctionTkn: &token.Token{
					ID:    token.T_FUNCTION,
					Value: []byte("function"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  5,
						EndPos:    13,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  14,
						EndPos:    17,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  14,
							EndPos:    17,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  13,
									EndPos:    14,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  17,
						EndPos:    18,
					},
				},
				Params: []ast.Vertex{
					&ast.Parameter{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  18,
							EndPos:    32,
						},
						Type: &ast.Nullable{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  18,
								EndPos:    22,
							},
							QuestionTkn: &token.Token{
								ID:    token.ID(63),
								Value: []byte("?"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  18,
									EndPos:    19,
								},
							},
							Expr: &ast.Name{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  19,
									EndPos:    22,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  19,
											EndPos:    22,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("bar"),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  19,
												EndPos:    22,
											},
										},
										Value: []byte("bar"),
									},
								},
							},
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  23,
								EndPos:    27,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  23,
									EndPos:    27,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$bar"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  23,
										EndPos:    27,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  22,
												EndPos:    23,
											},
										},
									},
								},
								Value: []byte("$bar"),
							},
						},
						EqualTkn: &token.Token{
							ID:    token.ID(61),
							Value: []byte("="),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  27,
								EndPos:    28,
							},
						},
						DefaultValue: &ast.ExprConstFetch{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  28,
								EndPos:    32,
							},
							Const: &ast.Name{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  28,
									EndPos:    32,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  28,
											EndPos:    32,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("null"),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  28,
												EndPos:    32,
											},
										},
										Value: []byte("null"),
									},
								},
							},
						},
					},
					&ast.Parameter{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  34,
							EndPos:    46,
						},
						Type: &ast.Name{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  34,
								EndPos:    37,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  34,
										EndPos:    37,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("baz"),
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  34,
											EndPos:    37,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 2,
													EndLine:   2,
													StartPos:  33,
													EndPos:    34,
												},
											},
										},
									},
									Value: []byte("baz"),
								},
							},
						},
						AmpersandTkn: &token.Token{
							ID:    token.ID(38),
							Value: []byte("&"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  38,
								EndPos:    39,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  37,
										EndPos:    38,
									},
								},
							},
						},
						VariadicTkn: &token.Token{
							ID:    token.T_ELLIPSIS,
							Value: []byte("..."),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  39,
								EndPos:    42,
							},
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  42,
								EndPos:    46,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  42,
									EndPos:    46,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$baz"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  42,
										EndPos:    46,
									},
								},
								Value: []byte("$baz"),
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  32,
							EndPos:    33,
						},
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  46,
						EndPos:    47,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  48,
						EndPos:    49,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  47,
								EndPos:    48,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  49,
						EndPos:    50,
					},
				},
			},
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 3,
					EndLine:   3,
					StartPos:  53,
					EndPos:    117,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  53,
						EndPos:    58,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   3,
								StartPos:  50,
								EndPos:    53,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  59,
						EndPos:    62,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  59,
							EndPos:    62,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  58,
									EndPos:    59,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  63,
						EndPos:    64,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  62,
								EndPos:    63,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtClassMethod{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  64,
							EndPos:    116,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  64,
									EndPos:    70,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_PUBLIC,
									Value: []byte("public"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  64,
										EndPos:    70,
									},
								},
								Value: []byte("public"),
							},
						},
						FunctionTkn: &token.Token{
							ID:    token.T_FUNCTION,
							Value: []byte("function"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  71,
								EndPos:    79,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  70,
										EndPos:    71,
									},
								},
							},
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  80,
								EndPos:    83,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("foo"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  80,
									EndPos:    83,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  79,
											EndPos:    80,
										},
									},
								},
							},
							Value: []byte("foo"),
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  83,
								EndPos:    84,
							},
						},
						Params: []ast.Vertex{
							&ast.Parameter{
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  84,
									EndPos:    98,
								},
								Type: &ast.Nullable{
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  84,
										EndPos:    88,
									},
									QuestionTkn: &token.Token{
										ID:    token.ID(63),
										Value: []byte("?"),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  84,
											EndPos:    85,
										},
									},
									Expr: &ast.Name{
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  85,
											EndPos:    88,
										},
										Parts: []ast.Vertex{
											&ast.NamePart{
												Position: &position.Position{
													StartLine: 3,
													EndLine:   3,
													StartPos:  85,
													EndPos:    88,
												},
												StringTkn: &token.Token{
													ID:    token.T_STRING,
													Value: []byte("bar"),
													Position: &position.Position{
														StartLine: 3,
														EndLine:   3,
														StartPos:  85,
														EndPos:    88,
													},
												},
												Value: []byte("bar"),
											},
										},
									},
								},
								Var: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  89,
										EndPos:    93,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  89,
											EndPos:    93,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$bar"),
											Position: &position.Position{
												StartLine: 3,
												EndLine:   3,
												StartPos:  89,
												EndPos:    93,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 3,
														EndLine:   3,
														StartPos:  88,
														EndPos:    89,
													},
												},
											},
										},
										Value: []byte("$bar"),
									},
								},
								EqualTkn: &token.Token{
									ID:    token.ID(61),
									Value: []byte("="),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  93,
										EndPos:    94,
									},
								},
								DefaultValue: &ast.ExprConstFetch{
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  94,
										EndPos:    98,
									},
									Const: &ast.Name{
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  94,
											EndPos:    98,
										},
										Parts: []ast.Vertex{
											&ast.NamePart{
												Position: &position.Position{
													StartLine: 3,
													EndLine:   3,
													StartPos:  94,
													EndPos:    98,
												},
												StringTkn: &token.Token{
													ID:    token.T_STRING,
													Value: []byte("null"),
													Position: &position.Position{
														StartLine: 3,
														EndLine:   3,
														StartPos:  94,
														EndPos:    98,
													},
												},
												Value: []byte("null"),
											},
										},
									},
								},
							},
							&ast.Parameter{
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  100,
									EndPos:    112,
								},
								Type: &ast.Name{
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  100,
										EndPos:    103,
									},
									Parts: []ast.Vertex{
										&ast.NamePart{
											Position: &position.Position{
												StartLine: 3,
												EndLine:   3,
												StartPos:  100,
												EndPos:    103,
											},
											StringTkn: &token.Token{
												ID:    token.T_STRING,
												Value: []byte("baz"),
												Position: &position.Position{
													StartLine: 3,
													EndLine:   3,
													StartPos:  100,
													EndPos:    103,
												},
												FreeFloating: []*token.Token{
													{
														ID:    token.T_WHITESPACE,
														Value: []byte(" "),
														Position: &position.Position{
															StartLine: 3,
															EndLine:   3,
															StartPos:  99,
															EndPos:    100,
														},
													},
												},
											},
											Value: []byte("baz"),
										},
									},
								},
								AmpersandTkn: &token.Token{
									ID:    token.ID(38),
									Value: []byte("&"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  104,
										EndPos:    105,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 3,
												EndLine:   3,
												StartPos:  103,
												EndPos:    104,
											},
										},
									},
								},
								VariadicTkn: &token.Token{
									ID:    token.T_ELLIPSIS,
									Value: []byte("..."),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  105,
										EndPos:    108,
									},
								},
								Var: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  108,
										EndPos:    112,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  108,
											EndPos:    112,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$baz"),
											Position: &position.Position{
												StartLine: 3,
												EndLine:   3,
												StartPos:  108,
												EndPos:    112,
											},
										},
										Value: []byte("$baz"),
									},
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  98,
									EndPos:    99,
								},
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  112,
								EndPos:    113,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  114,
								EndPos:    116,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.ID(123),
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  114,
									EndPos:    115,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  113,
											EndPos:    114,
										},
									},
								},
							},
							Stmts: []ast.Vertex{},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  115,
									EndPos:    116,
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  116,
						EndPos:    117,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 4,
					EndLine:   4,
					StartPos:  120,
					EndPos:    162,
				},
				Expr: &ast.ExprClosure{
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  120,
						EndPos:    161,
					},
					FunctionTkn: &token.Token{
						ID:    token.T_FUNCTION,
						Value: []byte("function"),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  120,
							EndPos:    128,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   4,
									StartPos:  117,
									EndPos:    120,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  128,
							EndPos:    129,
						},
					},
					Params: []ast.Vertex{
						&ast.Parameter{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  129,
								EndPos:    143,
							},
							Type: &ast.Nullable{
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  129,
									EndPos:    133,
								},
								QuestionTkn: &token.Token{
									ID:    token.ID(63),
									Value: []byte("?"),
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  129,
										EndPos:    130,
									},
								},
								Expr: &ast.Name{
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  130,
										EndPos:    133,
									},
									Parts: []ast.Vertex{
										&ast.NamePart{
											Position: &position.Position{
												StartLine: 4,
												EndLine:   4,
												StartPos:  130,
												EndPos:    133,
											},
											StringTkn: &token.Token{
												ID:    token.T_STRING,
												Value: []byte("bar"),
												Position: &position.Position{
													StartLine: 4,
													EndLine:   4,
													StartPos:  130,
													EndPos:    133,
												},
											},
											Value: []byte("bar"),
										},
									},
								},
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  134,
									EndPos:    138,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  134,
										EndPos:    138,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$bar"),
										Position: &position.Position{
											StartLine: 4,
											EndLine:   4,
											StartPos:  134,
											EndPos:    138,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 4,
													EndLine:   4,
													StartPos:  133,
													EndPos:    134,
												},
											},
										},
									},
									Value: []byte("$bar"),
								},
							},
							EqualTkn: &token.Token{
								ID:    token.ID(61),
								Value: []byte("="),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  138,
									EndPos:    139,
								},
							},
							DefaultValue: &ast.ExprConstFetch{
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  139,
									EndPos:    143,
								},
								Const: &ast.Name{
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  139,
										EndPos:    143,
									},
									Parts: []ast.Vertex{
										&ast.NamePart{
											Position: &position.Position{
												StartLine: 4,
												EndLine:   4,
												StartPos:  139,
												EndPos:    143,
											},
											StringTkn: &token.Token{
												ID:    token.T_STRING,
												Value: []byte("null"),
												Position: &position.Position{
													StartLine: 4,
													EndLine:   4,
													StartPos:  139,
													EndPos:    143,
												},
											},
											Value: []byte("null"),
										},
									},
								},
							},
						},
						&ast.Parameter{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  145,
								EndPos:    157,
							},
							Type: &ast.Name{
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  145,
									EndPos:    148,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 4,
											EndLine:   4,
											StartPos:  145,
											EndPos:    148,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("baz"),
											Position: &position.Position{
												StartLine: 4,
												EndLine:   4,
												StartPos:  145,
												EndPos:    148,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 4,
														EndLine:   4,
														StartPos:  144,
														EndPos:    145,
													},
												},
											},
										},
										Value: []byte("baz"),
									},
								},
							},
							AmpersandTkn: &token.Token{
								ID:    token.ID(38),
								Value: []byte("&"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  149,
									EndPos:    150,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 4,
											EndLine:   4,
											StartPos:  148,
											EndPos:    149,
										},
									},
								},
							},
							VariadicTkn: &token.Token{
								ID:    token.T_ELLIPSIS,
								Value: []byte("..."),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  150,
									EndPos:    153,
								},
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  153,
									EndPos:    157,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  153,
										EndPos:    157,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$baz"),
										Position: &position.Position{
											StartLine: 4,
											EndLine:   4,
											StartPos:  153,
											EndPos:    157,
										},
									},
									Value: []byte("$baz"),
								},
							},
						},
					},
					SeparatorTkns: []*token.Token{
						{
							ID:    token.ID(44),
							Value: []byte(","),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  143,
								EndPos:    144,
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  157,
							EndPos:    158,
						},
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  159,
							EndPos:    160,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  158,
									EndPos:    159,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  160,
							EndPos:    161,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  161,
						EndPos:    162,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 5,
					EndLine:   5,
					StartPos:  165,
					EndPos:    214,
				},
				Expr: &ast.ExprClosure{
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  165,
						EndPos:    213,
					},
					StaticTkn: &token.Token{
						ID:    token.T_STATIC,
						Value: []byte("static"),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  165,
							EndPos:    171,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   5,
									StartPos:  162,
									EndPos:    165,
								},
							},
						},
					},
					FunctionTkn: &token.Token{
						ID:    token.T_FUNCTION,
						Value: []byte("function"),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  172,
							EndPos:    180,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  171,
									EndPos:    172,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  180,
							EndPos:    181,
						},
					},
					Params: []ast.Vertex{
						&ast.Parameter{
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  181,
								EndPos:    195,
							},
							Type: &ast.Nullable{
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  181,
									EndPos:    185,
								},
								QuestionTkn: &token.Token{
									ID:    token.ID(63),
									Value: []byte("?"),
									Position: &position.Position{
										StartLine: 5,
										EndLine:   5,
										StartPos:  181,
										EndPos:    182,
									},
								},
								Expr: &ast.Name{
									Position: &position.Position{
										StartLine: 5,
										EndLine:   5,
										StartPos:  182,
										EndPos:    185,
									},
									Parts: []ast.Vertex{
										&ast.NamePart{
											Position: &position.Position{
												StartLine: 5,
												EndLine:   5,
												StartPos:  182,
												EndPos:    185,
											},
											StringTkn: &token.Token{
												ID:    token.T_STRING,
												Value: []byte("bar"),
												Position: &position.Position{
													StartLine: 5,
													EndLine:   5,
													StartPos:  182,
													EndPos:    185,
												},
											},
											Value: []byte("bar"),
										},
									},
								},
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  186,
									EndPos:    190,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 5,
										EndLine:   5,
										StartPos:  186,
										EndPos:    190,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$bar"),
										Position: &position.Position{
											StartLine: 5,
											EndLine:   5,
											StartPos:  186,
											EndPos:    190,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 5,
													EndLine:   5,
													StartPos:  185,
													EndPos:    186,
												},
											},
										},
									},
									Value: []byte("$bar"),
								},
							},
							EqualTkn: &token.Token{
								ID:    token.ID(61),
								Value: []byte("="),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  190,
									EndPos:    191,
								},
							},
							DefaultValue: &ast.ExprConstFetch{
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  191,
									EndPos:    195,
								},
								Const: &ast.Name{
									Position: &position.Position{
										StartLine: 5,
										EndLine:   5,
										StartPos:  191,
										EndPos:    195,
									},
									Parts: []ast.Vertex{
										&ast.NamePart{
											Position: &position.Position{
												StartLine: 5,
												EndLine:   5,
												StartPos:  191,
												EndPos:    195,
											},
											StringTkn: &token.Token{
												ID:    token.T_STRING,
												Value: []byte("null"),
												Position: &position.Position{
													StartLine: 5,
													EndLine:   5,
													StartPos:  191,
													EndPos:    195,
												},
											},
											Value: []byte("null"),
										},
									},
								},
							},
						},
						&ast.Parameter{
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  197,
								EndPos:    209,
							},
							Type: &ast.Name{
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  197,
									EndPos:    200,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 5,
											EndLine:   5,
											StartPos:  197,
											EndPos:    200,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("baz"),
											Position: &position.Position{
												StartLine: 5,
												EndLine:   5,
												StartPos:  197,
												EndPos:    200,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 5,
														EndLine:   5,
														StartPos:  196,
														EndPos:    197,
													},
												},
											},
										},
										Value: []byte("baz"),
									},
								},
							},
							AmpersandTkn: &token.Token{
								ID:    token.ID(38),
								Value: []byte("&"),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  201,
									EndPos:    202,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 5,
											EndLine:   5,
											StartPos:  200,
											EndPos:    201,
										},
									},
								},
							},
							VariadicTkn: &token.Token{
								ID:    token.T_ELLIPSIS,
								Value: []byte("..."),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  202,
									EndPos:    205,
								},
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  205,
									EndPos:    209,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 5,
										EndLine:   5,
										StartPos:  205,
										EndPos:    209,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$baz"),
										Position: &position.Position{
											StartLine: 5,
											EndLine:   5,
											StartPos:  205,
											EndPos:    209,
										},
									},
									Value: []byte("$baz"),
								},
							},
						},
					},
					SeparatorTkns: []*token.Token{
						{
							ID:    token.ID(44),
							Value: []byte(","),
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  195,
								EndPos:    196,
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  209,
							EndPos:    210,
						},
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  211,
							EndPos:    212,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  210,
									EndPos:    211,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  212,
							EndPos:    213,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  213,
						EndPos:    214,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   6,
						StartPos:  214,
						EndPos:    216,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestCommentEndFile(t *testing.T) {
	src := `<? //comment at the end)`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: -1,
			EndLine:   -1,
			StartPos:  -1,
			EndPos:    -1,
		},
		Stmts: []ast.Vertex{},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_OPEN_TAG,
					Value: []byte("<?"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  0,
						EndPos:    2,
					},
				},
				{
					ID:    token.T_WHITESPACE,
					Value: []byte(" "),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  2,
						EndPos:    3,
					},
				},
				{
					ID:    token.T_COMMENT,
					Value: []byte("//comment at the end)"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    24,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

// name

func TestName(t *testing.T) {
	src := `<? foo();`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    9,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    9,
				},
				Expr: &ast.ExprFunctionCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    8,
					},
					Function: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  3,
									EndPos:    6,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  3,
										EndPos:    6,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_OPEN_TAG,
											Value: []byte("<?"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  2,
												EndPos:    3,
											},
										},
									},
								},
								Value: []byte("foo"),
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  8,
						EndPos:    9,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestFullyQualified(t *testing.T) {
	src := `<? \foo();`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    10,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    10,
				},
				Expr: &ast.ExprFunctionCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    9,
					},
					Function: &ast.NameFullyQualified{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    7,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  4,
										EndPos:    7,
									},
								},
								Value: []byte("foo"),
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestRelative(t *testing.T) {
	src := `<? namespace\foo();`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    19,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    19,
				},
				Expr: &ast.ExprFunctionCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    18,
					},
					Function: &ast.NameRelative{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    16,
						},
						NsTkn: &token.Token{
							ID:    token.T_NAMESPACE,
							Value: []byte("namespace"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    12,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    16,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    16,
									},
								},
								Value: []byte("foo"),
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    17,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  17,
							EndPos:    18,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

// scalar

func TestScalarEncapsed_SimpleVar(t *testing.T) {
	src := `<? "test $var";`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    15,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    15,
				},
				Expr: &ast.ScalarEncapsed{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    14,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    9,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("test "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    9,
								},
							},
							Value: []byte("test "),
						},
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    13,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    13,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$var"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    13,
									},
								},
								Value: []byte("$var"),
							},
						},
					},
					CloseQuoteTkn: &token.Token{
						ID:    token.ID(34),
						Value: []byte("\""),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarEncapsed_SimpleVarOneChar(t *testing.T) {
	src := `<? "test $a";`

	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.ScalarEncapsed{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    9,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("test "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    9,
								},
							},
							Value: []byte("test "),
						},
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    11,
									},
								},
								Value: []byte("$a"),
							},
						},
					},
					CloseQuoteTkn: &token.Token{
						ID:    token.ID(34),
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarEncapsed_SimpleVarEndsEcapsed(t *testing.T) {
	src := `<? "test $var\"";`

	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.ScalarEncapsed{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    16,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    9,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("test "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    9,
								},
							},
							Value: []byte("test "),
						},
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    13,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    13,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$var"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    13,
									},
								},
								Value: []byte("$var"),
							},
						},
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    15,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("\\\""),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    15,
								},
							},
							Value: []byte("\\\""),
						},
					},
					CloseQuoteTkn: &token.Token{
						ID:    token.ID(34),
						Value: []byte("\""),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    16,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarEncapsed_StringVarCurveOpen(t *testing.T) {
	src := `<? "=$a{$b}";`

	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.ScalarEncapsed{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    5,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("="),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    5,
								},
							},
							Value: []byte("="),
						},
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  5,
								EndPos:    7,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    7,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  5,
										EndPos:    7,
									},
								},
								Value: []byte("$a"),
							},
						},
						&ast.ScalarEncapsedStringBrackets{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    11,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.T_CURLY_OPEN,
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  7,
									EndPos:    8,
								},
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    10,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    10,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$b"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    10,
										},
									},
									Value: []byte("$b"),
								},
							},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    11,
								},
							},
						},
					},
					CloseQuoteTkn: &token.Token{
						ID:    token.ID(34),
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarEncapsed_SimpleVarPropertyFetch(t *testing.T) {
	src := `<? "test $foo->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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    9,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("test "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    9,
								},
							},
							Value: []byte("test "),
						},
						&ast.ExprPropertyFetch{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    18,
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    13,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    13,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  9,
											EndPos:    13,
										},
									},
									Value: []byte("$foo"),
								},
							},
							ObjectOperatorTkn: &token.Token{
								ID:    token.T_OBJECT_OPERATOR,
								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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarEncapsed_DollarOpenCurlyBraces(t *testing.T) {
	src := `<? "test ${foo}";`

	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.ScalarEncapsed{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    16,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    9,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("test "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    9,
								},
							},
							Value: []byte("test "),
						},
						&ast.ScalarEncapsedStringVar{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    15,
							},
							DollarOpenCurlyBracketTkn: &token.Token{
								ID:    token.T_DOLLAR_OPEN_CURLY_BRACES,
								Value: []byte("${"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  11,
									EndPos:    14,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_STRING_VARNAME,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  11,
										EndPos:    14,
									},
								},
								Value: []byte("foo"),
							},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    15,
								},
							},
						},
					},
					CloseQuoteTkn: &token.Token{
						ID:    token.ID(34),
						Value: []byte("\""),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    16,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarEncapsed_DollarOpenCurlyBracesDimNumber(t *testing.T) {
	src := `<? "test ${foo[0]}";`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    20,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    20,
				},
				Expr: &ast.ScalarEncapsed{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    19,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    9,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("test "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    9,
								},
							},
							Value: []byte("test "),
						},
						&ast.ScalarEncapsedStringVar{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    15,
							},
							DollarOpenCurlyBracketTkn: &token.Token{
								ID:    token.T_DOLLAR_OPEN_CURLY_BRACES,
								Value: []byte("${"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  11,
									EndPos:    14,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_STRING_VARNAME,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  11,
										EndPos:    14,
									},
								},
								Value: []byte("foo"),
							},
							OpenSquareBracketTkn: &token.Token{
								ID:    token.ID(91),
								Value: []byte("["),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    15,
								},
							},
							Dim: &ast.ScalarLnumber{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  15,
									EndPos:    16,
								},
								NumberTkn: &token.Token{
									ID:    token.T_LNUMBER,
									Value: []byte("0"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  15,
										EndPos:    16,
									},
								},
								Value: []byte("0"),
							},
							CloseSquareBracketTkn: &token.Token{
								ID:    token.ID(93),
								Value: []byte("]"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  16,
									EndPos:    17,
								},
							},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    18,
								},
							},
						},
					},
					CloseQuoteTkn: &token.Token{
						ID:    token.ID(34),
						Value: []byte("\""),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    19,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  19,
						EndPos:    20,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarEncapsed_CurlyOpenMethodCall(t *testing.T) {
	src := `<? "test {$foo->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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    9,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("test "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    9,
								},
							},
							Value: []byte("test "),
						},
						&ast.ScalarEncapsedStringBrackets{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    22,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.T_CURLY_OPEN,
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    10,
								},
							},
							Var: &ast.ExprMethodCall{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    21,
								},
								Var: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  10,
										EndPos:    14,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  10,
											EndPos:    14,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$foo"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  10,
												EndPos:    14,
											},
										},
										Value: []byte("$foo"),
									},
								},
								ObjectOperatorTkn: &token.Token{
									ID:    token.T_OBJECT_OPERATOR,
									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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarHeredoc_HeredocSimpleLabel(t *testing.T) {
	src := `<? <<<LBL
test $var
LBL;
`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   3,
			StartPos:  3,
			EndPos:    24,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   3,
					StartPos:  3,
					EndPos:    24,
				},
				Expr: &ast.ScalarHeredoc{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   3,
						StartPos:  3,
						EndPos:    23,
					},
					OpenHeredocTkn: &token.Token{
						ID:    token.T_START_HEREDOC,
						Value: []byte("<<<LBL\n"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  10,
								EndPos:    15,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("test "),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  10,
									EndPos:    15,
								},
							},
							Value: []byte("test "),
						},
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  15,
								EndPos:    19,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  15,
									EndPos:    19,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$var"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  15,
										EndPos:    19,
									},
								},
								Value: []byte("$var"),
							},
						},
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  19,
								EndPos:    20,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("\n"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  19,
									EndPos:    20,
								},
							},
							Value: []byte("\n"),
						},
					},
					CloseHeredocTkn: &token.Token{
						ID:    token.T_END_HEREDOC,
						Value: []byte("LBL"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  20,
							EndPos:    23,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  23,
						EndPos:    24,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  24,
						EndPos:    25,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarHeredoc_SimpleHeredocLabel(t *testing.T) {
	src := `<? <<<"LBL"
test $var
LBL;
`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   3,
			StartPos:  3,
			EndPos:    26,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   3,
					StartPos:  3,
					EndPos:    26,
				},
				Expr: &ast.ScalarHeredoc{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   3,
						StartPos:  3,
						EndPos:    25,
					},
					OpenHeredocTkn: &token.Token{
						ID:    token.T_START_HEREDOC,
						Value: []byte("<<<\"LBL\"\n"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    17,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("test "),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  12,
									EndPos:    17,
								},
							},
							Value: []byte("test "),
						},
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  17,
								EndPos:    21,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  17,
									EndPos:    21,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$var"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  17,
										EndPos:    21,
									},
								},
								Value: []byte("$var"),
							},
						},
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  21,
								EndPos:    22,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("\n"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  21,
									EndPos:    22,
								},
							},
							Value: []byte("\n"),
						},
					},
					CloseHeredocTkn: &token.Token{
						ID:    token.T_END_HEREDOC,
						Value: []byte("LBL"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  22,
							EndPos:    25,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  25,
						EndPos:    26,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  26,
						EndPos:    27,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarHeredoc_SimpleNowdocLabel(t *testing.T) {
	src := `<? <<<'LBL'
test $var
LBL;
`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   3,
			StartPos:  3,
			EndPos:    26,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   3,
					StartPos:  3,
					EndPos:    26,
				},
				Expr: &ast.ScalarHeredoc{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   3,
						StartPos:  3,
						EndPos:    25,
					},
					OpenHeredocTkn: &token.Token{
						ID:    token.T_START_HEREDOC,
						Value: []byte("<<<'LBL'\n"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    22,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("test $var\n"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  12,
									EndPos:    22,
								},
							},
							Value: []byte("test $var\n"),
						},
					},
					CloseHeredocTkn: &token.Token{
						ID:    token.T_END_HEREDOC,
						Value: []byte("LBL"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  22,
							EndPos:    25,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  25,
						EndPos:    26,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  26,
						EndPos:    27,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarHeredoc_EmptyHeredoc(t *testing.T) {
	src := `<? <<<CAD
CAD;
`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   2,
			StartPos:  3,
			EndPos:    14,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   2,
					StartPos:  3,
					EndPos:    14,
				},
				Expr: &ast.ScalarHeredoc{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   2,
						StartPos:  3,
						EndPos:    13,
					},
					OpenHeredocTkn: &token.Token{
						ID:    token.T_START_HEREDOC,
						Value: []byte("<<<CAD\n"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					CloseHeredocTkn: &token.Token{
						ID:    token.T_END_HEREDOC,
						Value: []byte("AD"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  11,
							EndPos:    13,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  13,
						EndPos:    14,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarHeredoc_HeredocScalarString(t *testing.T) {
	src := `<? <<<CAD
	hello
CAD;
`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   3,
			StartPos:  3,
			EndPos:    21,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   3,
					StartPos:  3,
					EndPos:    21,
				},
				Expr: &ast.ScalarHeredoc{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   3,
						StartPos:  3,
						EndPos:    20,
					},
					OpenHeredocTkn: &token.Token{
						ID:    token.T_START_HEREDOC,
						Value: []byte("<<<CAD\n"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  10,
								EndPos:    17,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("\thello\n"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  10,
									EndPos:    17,
								},
							},
							Value: []byte("\thello\n"),
						},
					},
					CloseHeredocTkn: &token.Token{
						ID:    token.T_END_HEREDOC,
						Value: []byte("CAD"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  17,
							EndPos:    20,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  20,
						EndPos:    21,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  21,
						EndPos:    22,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarMagicConstant(t *testing.T) {
	// TODO: test all magic constants
	src := `<? __DIR__;`

	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.ScalarMagicConstant{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    10,
					},
					MagicConstTkn: &token.Token{
						ID:    token.T_DIR,
						Value: []byte("__DIR__"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("__DIR__"),
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarNumber_LNumber(t *testing.T) {
	src := `<? 1234567890123456789;`

	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.ScalarLnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    22,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1234567890123456789"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    22,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("1234567890123456789"),
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarNumber_DNumber(t *testing.T) {
	src := `<? 12345678901234567890;`

	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.ScalarDnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    23,
					},
					NumberTkn: &token.Token{
						ID:    token.T_DNUMBER,
						Value: []byte("12345678901234567890"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    23,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("12345678901234567890"),
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarNumber_Float(t *testing.T) {
	src := `<? 0.;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    6,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    6,
				},
				Expr: &ast.ScalarDnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    5,
					},
					NumberTkn: &token.Token{
						ID:    token.T_DNUMBER,
						Value: []byte("0."),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("0."),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  5,
						EndPos:    6,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarNumber_BinaryLNumber(t *testing.T) {
	src := `<? 0b0111111111111111111111111111111111111111111111111111111111111111;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    70,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    70,
				},
				Expr: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    69,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("0b0111111111111111111111111111111111111111111111111111111111111111"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    69,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("0b0111111111111111111111111111111111111111111111111111111111111111"),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  69,
						EndPos:    70,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarNumber_BinaryDNumber(t *testing.T) {
	src := `<? 0b1111111111111111111111111111111111111111111111111111111111111111;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    70,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    70,
				},
				Expr: &ast.ScalarDnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    69,
					},
					NumberTkn: &token.Token{
						ID:    token.T_DNUMBER,
						Value: []byte("0b1111111111111111111111111111111111111111111111111111111111111111"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    69,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("0b1111111111111111111111111111111111111111111111111111111111111111"),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  69,
						EndPos:    70,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarNumber_HLNumber(t *testing.T) {
	src := `<? 0x007111111111111111;`

	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.ScalarLnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    23,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("0x007111111111111111"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    23,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("0x007111111111111111"),
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarNumber_HDNumber(t *testing.T) {
	src := `<? 0x8111111111111111;`

	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.ScalarDnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    21,
					},
					NumberTkn: &token.Token{
						ID:    token.T_DNUMBER,
						Value: []byte("0x8111111111111111"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    21,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("0x8111111111111111"),
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarString_DoubleQuotedScalarString(t *testing.T) {
	src := `<? "test";`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    10,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    10,
				},
				Expr: &ast.ScalarString{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    9,
					},
					StringTkn: &token.Token{
						ID:    token.T_CONSTANT_ENCAPSED_STRING,
						Value: []byte("\"test\""),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    9,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("\"test\""),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarString_DoubleQuotedScalarStringWithEscapedVar(t *testing.T) {
	src := `<? "\$test";`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				Expr: &ast.ScalarString{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					StringTkn: &token.Token{
						ID:    token.T_CONSTANT_ENCAPSED_STRING,
						Value: []byte("\"\\$test\""),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    11,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("\"\\$test\""),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarString_MultilineDoubleQuotedScalarString(t *testing.T) {
	src := `<? "
	test
	";`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   3,
			StartPos:  3,
			EndPos:    14,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   3,
					StartPos:  3,
					EndPos:    14,
				},
				Expr: &ast.ScalarString{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   3,
						StartPos:  3,
						EndPos:    13,
					},
					StringTkn: &token.Token{
						ID:    token.T_CONSTANT_ENCAPSED_STRING,
						Value: []byte("\"\n\ttest\n\t\""),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   3,
							StartPos:  3,
							EndPos:    13,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("\"\n\ttest\n\t\""),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  13,
						EndPos:    14,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarString_SingleQuotedScalarString(t *testing.T) {
	src := `<? '$test';`

	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.ScalarString{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    10,
					},
					StringTkn: &token.Token{
						ID:    token.T_CONSTANT_ENCAPSED_STRING,
						Value: []byte("'$test'"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("'$test'"),
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestScalarString_MultilineSingleQuotedScalarString(t *testing.T) {
	src := `<? '
	$test
	';`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   3,
			StartPos:  3,
			EndPos:    15,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   3,
					StartPos:  3,
					EndPos:    15,
				},
				Expr: &ast.ScalarString{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   3,
						StartPos:  3,
						EndPos:    14,
					},
					StringTkn: &token.Token{
						ID:    token.T_CONSTANT_ENCAPSED_STRING,
						Value: []byte("'\n\t$test\n\t'"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   3,
							StartPos:  3,
							EndPos:    14,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("'\n\t$test\n\t'"),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

// stmt

func TestStmtAltIf_AltIf(t *testing.T) {
	src := `<?
		if ($a) :
		endif;
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   3,
			StartPos:  5,
			EndPos:    23,
		},
		Stmts: []ast.Vertex{
			&ast.StmtIf{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   3,
					StartPos:  5,
					EndPos:    23,
				},
				IfTkn: &token.Token{
					ID:    token.T_IF,
					Value: []byte("if"),
					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: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  8,
						EndPos:    9,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  7,
								EndPos:    8,
							},
						},
					},
				},
				Cond: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  9,
						EndPos:    11,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  9,
							EndPos:    11,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  9,
								EndPos:    11,
							},
						},
						Value: []byte("$a"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  11,
						EndPos:    12,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: -1,
						EndLine:   -1,
						StartPos:  -1,
						EndPos:    -1,
					},
					Stmts: []ast.Vertex{},
				},
				EndIfTkn: &token.Token{
					ID:    token.T_ENDIF,
					Value: []byte("endif"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  17,
						EndPos:    22,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   3,
								StartPos:  14,
								EndPos:    17,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  22,
						EndPos:    23,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   4,
						StartPos:  23,
						EndPos:    25,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtAltIf_AltElseIf(t *testing.T) {
	src := `<?
		if ($a) :
		elseif ($b):
		endif;
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   4,
			StartPos:  5,
			EndPos:    38,
		},
		Stmts: []ast.Vertex{
			&ast.StmtIf{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   4,
					StartPos:  5,
					EndPos:    38,
				},
				IfTkn: &token.Token{
					ID:    token.T_IF,
					Value: []byte("if"),
					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: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  8,
						EndPos:    9,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  7,
								EndPos:    8,
							},
						},
					},
				},
				Cond: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  9,
						EndPos:    11,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  9,
							EndPos:    11,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  9,
								EndPos:    11,
							},
						},
						Value: []byte("$a"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  11,
						EndPos:    12,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: -1,
						EndLine:   -1,
						StartPos:  -1,
						EndPos:    -1,
					},
					Stmts: []ast.Vertex{},
				},
				ElseIf: []ast.Vertex{
					&ast.StmtElseIf{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   -1,
							StartPos:  17,
							EndPos:    -1,
						},
						ElseIfTkn: &token.Token{
							ID:    token.T_ELSEIF,
							Value: []byte("elseif"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  17,
								EndPos:    23,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   3,
										StartPos:  14,
										EndPos:    17,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  24,
								EndPos:    25,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  23,
										EndPos:    24,
									},
								},
							},
						},
						Cond: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  25,
								EndPos:    27,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  25,
									EndPos:    27,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  25,
										EndPos:    27,
									},
								},
								Value: []byte("$b"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  27,
								EndPos:    28,
							},
						},
						ColonTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  28,
								EndPos:    29,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: -1,
								EndLine:   -1,
								StartPos:  -1,
								EndPos:    -1,
							},
							Stmts: []ast.Vertex{},
						},
					},
				},
				EndIfTkn: &token.Token{
					ID:    token.T_ENDIF,
					Value: []byte("endif"),
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  32,
						EndPos:    37,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   4,
								StartPos:  29,
								EndPos:    32,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  37,
						EndPos:    38,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 4,
						EndLine:   5,
						StartPos:  38,
						EndPos:    40,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtAltIf_AltElse(t *testing.T) {
	src := `<?
		if ($a) :
		else:
		endif;
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   4,
			StartPos:  5,
			EndPos:    31,
		},
		Stmts: []ast.Vertex{
			&ast.StmtIf{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   4,
					StartPos:  5,
					EndPos:    31,
				},
				IfTkn: &token.Token{
					ID:    token.T_IF,
					Value: []byte("if"),
					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: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  8,
						EndPos:    9,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  7,
								EndPos:    8,
							},
						},
					},
				},
				Cond: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  9,
						EndPos:    11,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  9,
							EndPos:    11,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  9,
								EndPos:    11,
							},
						},
						Value: []byte("$a"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  11,
						EndPos:    12,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: -1,
						EndLine:   -1,
						StartPos:  -1,
						EndPos:    -1,
					},
					Stmts: []ast.Vertex{},
				},
				Else: &ast.StmtElse{
					Position: &position.Position{
						StartLine: 3,
						EndLine:   -1,
						StartPos:  17,
						EndPos:    -1,
					},
					ElseTkn: &token.Token{
						ID:    token.T_ELSE,
						Value: []byte("else"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  17,
							EndPos:    21,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   3,
									StartPos:  14,
									EndPos:    17,
								},
							},
						},
					},
					ColonTkn: &token.Token{
						ID:    token.ID(58),
						Value: []byte(":"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  21,
							EndPos:    22,
						},
					},
					Stmt: &ast.StmtStmtList{
						Position: &position.Position{
							StartLine: -1,
							EndLine:   -1,
							StartPos:  -1,
							EndPos:    -1,
						},
						Stmts: []ast.Vertex{},
					},
				},
				EndIfTkn: &token.Token{
					ID:    token.T_ENDIF,
					Value: []byte("endif"),
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  25,
						EndPos:    30,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   4,
								StartPos:  22,
								EndPos:    25,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  30,
						EndPos:    31,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 4,
						EndLine:   5,
						StartPos:  31,
						EndPos:    33,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtAltIf_AltElseElseIf(t *testing.T) {
	src := `<?
		if ($a) :
		elseif ($b):
		elseif ($c):
		else:
		endif;
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   6,
			StartPos:  5,
			EndPos:    61,
		},
		Stmts: []ast.Vertex{
			&ast.StmtIf{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   6,
					StartPos:  5,
					EndPos:    61,
				},
				IfTkn: &token.Token{
					ID:    token.T_IF,
					Value: []byte("if"),
					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: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  8,
						EndPos:    9,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  7,
								EndPos:    8,
							},
						},
					},
				},
				Cond: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  9,
						EndPos:    11,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  9,
							EndPos:    11,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  9,
								EndPos:    11,
							},
						},
						Value: []byte("$a"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  11,
						EndPos:    12,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: -1,
						EndLine:   -1,
						StartPos:  -1,
						EndPos:    -1,
					},
					Stmts: []ast.Vertex{},
				},
				ElseIf: []ast.Vertex{
					&ast.StmtElseIf{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   -1,
							StartPos:  17,
							EndPos:    -1,
						},
						ElseIfTkn: &token.Token{
							ID:    token.T_ELSEIF,
							Value: []byte("elseif"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  17,
								EndPos:    23,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   3,
										StartPos:  14,
										EndPos:    17,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  24,
								EndPos:    25,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  23,
										EndPos:    24,
									},
								},
							},
						},
						Cond: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  25,
								EndPos:    27,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  25,
									EndPos:    27,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  25,
										EndPos:    27,
									},
								},
								Value: []byte("$b"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  27,
								EndPos:    28,
							},
						},
						ColonTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  28,
								EndPos:    29,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: -1,
								EndLine:   -1,
								StartPos:  -1,
								EndPos:    -1,
							},
							Stmts: []ast.Vertex{},
						},
					},
					&ast.StmtElseIf{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   -1,
							StartPos:  32,
							EndPos:    -1,
						},
						ElseIfTkn: &token.Token{
							ID:    token.T_ELSEIF,
							Value: []byte("elseif"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  32,
								EndPos:    38,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   4,
										StartPos:  29,
										EndPos:    32,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  39,
								EndPos:    40,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  38,
										EndPos:    39,
									},
								},
							},
						},
						Cond: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  40,
								EndPos:    42,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  40,
									EndPos:    42,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$c"),
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  40,
										EndPos:    42,
									},
								},
								Value: []byte("$c"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  42,
								EndPos:    43,
							},
						},
						ColonTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  43,
								EndPos:    44,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: -1,
								EndLine:   -1,
								StartPos:  -1,
								EndPos:    -1,
							},
							Stmts: []ast.Vertex{},
						},
					},
				},
				Else: &ast.StmtElse{
					Position: &position.Position{
						StartLine: 5,
						EndLine:   -1,
						StartPos:  47,
						EndPos:    -1,
					},
					ElseTkn: &token.Token{
						ID:    token.T_ELSE,
						Value: []byte("else"),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  47,
							EndPos:    51,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   5,
									StartPos:  44,
									EndPos:    47,
								},
							},
						},
					},
					ColonTkn: &token.Token{
						ID:    token.ID(58),
						Value: []byte(":"),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  51,
							EndPos:    52,
						},
					},
					Stmt: &ast.StmtStmtList{
						Position: &position.Position{
							StartLine: -1,
							EndLine:   -1,
							StartPos:  -1,
							EndPos:    -1,
						},
						Stmts: []ast.Vertex{},
					},
				},
				EndIfTkn: &token.Token{
					ID:    token.T_ENDIF,
					Value: []byte("endif"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  55,
						EndPos:    60,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 5,
								EndLine:   6,
								StartPos:  52,
								EndPos:    55,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  60,
						EndPos:    61,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   7,
						StartPos:  61,
						EndPos:    63,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClassConstList(t *testing.T) {
	src := `<? class foo{ public const FOO = 1, BAR = 2; }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    46,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    46,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    13,
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtClassConstList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    44,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    20,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_PUBLIC,
									Value: []byte("public"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    20,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  13,
												EndPos:    14,
											},
										},
									},
								},
								Value: []byte("public"),
							},
						},
						ConstTkn: &token.Token{
							ID:    token.T_CONST,
							Value: []byte("const"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  21,
								EndPos:    26,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  20,
										EndPos:    21,
									},
								},
							},
						},
						Consts: []ast.Vertex{
							&ast.StmtConstant{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  27,
									EndPos:    34,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  27,
										EndPos:    30,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("FOO"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  27,
											EndPos:    30,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  26,
													EndPos:    27,
												},
											},
										},
									},
									Value: []byte("FOO"),
								},
								EqualTkn: &token.Token{
									ID:    token.ID(61),
									Value: []byte("="),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  31,
										EndPos:    32,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  30,
												EndPos:    31,
											},
										},
									},
								},
								Expr: &ast.ScalarLnumber{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  33,
										EndPos:    34,
									},
									NumberTkn: &token.Token{
										ID:    token.T_LNUMBER,
										Value: []byte("1"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  33,
											EndPos:    34,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  32,
													EndPos:    33,
												},
											},
										},
									},
									Value: []byte("1"),
								},
							},
							&ast.StmtConstant{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  36,
									EndPos:    43,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  36,
										EndPos:    39,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("BAR"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  36,
											EndPos:    39,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  35,
													EndPos:    36,
												},
											},
										},
									},
									Value: []byte("BAR"),
								},
								EqualTkn: &token.Token{
									ID:    token.ID(61),
									Value: []byte("="),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  40,
										EndPos:    41,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  39,
												EndPos:    40,
											},
										},
									},
								},
								Expr: &ast.ScalarLnumber{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  42,
										EndPos:    43,
									},
									NumberTkn: &token.Token{
										ID:    token.T_LNUMBER,
										Value: []byte("2"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  42,
											EndPos:    43,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  41,
													EndPos:    42,
												},
											},
										},
									},
									Value: []byte("2"),
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  34,
									EndPos:    35,
								},
							},
						},
						SemiColonTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  43,
								EndPos:    44,
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  45,
						EndPos:    46,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  44,
								EndPos:    45,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClassConstList_WithoutModifiers(t *testing.T) {
	src := `<? class foo{ const FOO = 1, BAR = 2; }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    39,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    39,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    13,
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtClassConstList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    37,
						},
						ConstTkn: &token.Token{
							ID:    token.T_CONST,
							Value: []byte("const"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    19,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    14,
									},
								},
							},
						},
						Consts: []ast.Vertex{
							&ast.StmtConstant{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  20,
									EndPos:    27,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  20,
										EndPos:    23,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("FOO"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  20,
											EndPos:    23,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  19,
													EndPos:    20,
												},
											},
										},
									},
									Value: []byte("FOO"),
								},
								EqualTkn: &token.Token{
									ID:    token.ID(61),
									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,
											},
										},
									},
								},
								Expr: &ast.ScalarLnumber{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  26,
										EndPos:    27,
									},
									NumberTkn: &token.Token{
										ID:    token.T_LNUMBER,
										Value: []byte("1"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  26,
											EndPos:    27,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  25,
													EndPos:    26,
												},
											},
										},
									},
									Value: []byte("1"),
								},
							},
							&ast.StmtConstant{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  29,
									EndPos:    36,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  29,
										EndPos:    32,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("BAR"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  29,
											EndPos:    32,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  28,
													EndPos:    29,
												},
											},
										},
									},
									Value: []byte("BAR"),
								},
								EqualTkn: &token.Token{
									ID:    token.ID(61),
									Value: []byte("="),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  33,
										EndPos:    34,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  32,
												EndPos:    33,
											},
										},
									},
								},
								Expr: &ast.ScalarLnumber{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  35,
										EndPos:    36,
									},
									NumberTkn: &token.Token{
										ID:    token.T_LNUMBER,
										Value: []byte("2"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  35,
											EndPos:    36,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  34,
													EndPos:    35,
												},
											},
										},
									},
									Value: []byte("2"),
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  27,
									EndPos:    28,
								},
							},
						},
						SemiColonTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  36,
								EndPos:    37,
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  38,
						EndPos:    39,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  37,
								EndPos:    38,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClassMethod_SimpleClassMethod(t *testing.T) {
	src := `<? class foo{ function bar() {} }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    33,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    33,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    13,
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtClassMethod{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    31,
						},
						FunctionTkn: &token.Token{
							ID:    token.T_FUNCTION,
							Value: []byte("function"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    22,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    14,
									},
								},
							},
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  23,
								EndPos:    26,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  23,
									EndPos:    26,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  22,
											EndPos:    23,
										},
									},
								},
							},
							Value: []byte("bar"),
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  26,
								EndPos:    27,
							},
						},
						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,
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  32,
						EndPos:    33,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  31,
								EndPos:    32,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClassMethod_PrivateProtectedClassMethod(t *testing.T) {
	src := `<? class foo{ final private function bar() {} protected function baz() {} }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    75,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    75,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    13,
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtClassMethod{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    45,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    19,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_FINAL,
									Value: []byte("final"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    19,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  13,
												EndPos:    14,
											},
										},
									},
								},
								Value: []byte("final"),
							},
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  20,
									EndPos:    27,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_PRIVATE,
									Value: []byte("private"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  20,
										EndPos:    27,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  19,
												EndPos:    20,
											},
										},
									},
								},
								Value: []byte("private"),
							},
						},
						FunctionTkn: &token.Token{
							ID:    token.T_FUNCTION,
							Value: []byte("function"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  28,
								EndPos:    36,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  27,
										EndPos:    28,
									},
								},
							},
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  37,
								EndPos:    40,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  37,
									EndPos:    40,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  36,
											EndPos:    37,
										},
									},
								},
							},
							Value: []byte("bar"),
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  40,
								EndPos:    41,
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  41,
								EndPos:    42,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  43,
								EndPos:    45,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.ID(123),
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  43,
									EndPos:    44,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  42,
											EndPos:    43,
										},
									},
								},
							},
							Stmts: []ast.Vertex{},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  44,
									EndPos:    45,
								},
							},
						},
					},
					&ast.StmtClassMethod{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  46,
							EndPos:    73,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  46,
									EndPos:    55,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_PROTECTED,
									Value: []byte("protected"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  46,
										EndPos:    55,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  45,
												EndPos:    46,
											},
										},
									},
								},
								Value: []byte("protected"),
							},
						},
						FunctionTkn: &token.Token{
							ID:    token.T_FUNCTION,
							Value: []byte("function"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  56,
								EndPos:    64,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  55,
										EndPos:    56,
									},
								},
							},
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  65,
								EndPos:    68,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("baz"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  65,
									EndPos:    68,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  64,
											EndPos:    65,
										},
									},
								},
							},
							Value: []byte("baz"),
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  68,
								EndPos:    69,
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  69,
								EndPos:    70,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  71,
								EndPos:    73,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.ID(123),
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  71,
									EndPos:    72,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  70,
											EndPos:    71,
										},
									},
								},
							},
							Stmts: []ast.Vertex{},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  72,
									EndPos:    73,
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  74,
						EndPos:    75,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  73,
								EndPos:    74,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClassMethod_Php7ClassMethod(t *testing.T) {
	src := `<? class foo{ public static function &bar(): void {} }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    54,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    54,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    13,
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtClassMethod{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    52,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    20,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_PUBLIC,
									Value: []byte("public"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    20,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  13,
												EndPos:    14,
											},
										},
									},
								},
								Value: []byte("public"),
							},
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  21,
									EndPos:    27,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_STATIC,
									Value: []byte("static"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  21,
										EndPos:    27,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  20,
												EndPos:    21,
											},
										},
									},
								},
								Value: []byte("static"),
							},
						},
						FunctionTkn: &token.Token{
							ID:    token.T_FUNCTION,
							Value: []byte("function"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  28,
								EndPos:    36,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  27,
										EndPos:    28,
									},
								},
							},
						},
						AmpersandTkn: &token.Token{
							ID:    token.ID(38),
							Value: []byte("&"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  37,
								EndPos:    38,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  36,
										EndPos:    37,
									},
								},
							},
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  38,
								EndPos:    41,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  38,
									EndPos:    41,
								},
							},
							Value: []byte("bar"),
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  41,
								EndPos:    42,
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  42,
								EndPos:    43,
							},
						},
						ColonTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  43,
								EndPos:    44,
							},
						},
						ReturnType: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  45,
								EndPos:    49,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  45,
										EndPos:    49,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("void"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  45,
											EndPos:    49,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  44,
													EndPos:    45,
												},
											},
										},
									},
									Value: []byte("void"),
								},
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  50,
								EndPos:    52,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.ID(123),
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  50,
									EndPos:    51,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  49,
											EndPos:    50,
										},
									},
								},
							},
							Stmts: []ast.Vertex{},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  51,
									EndPos:    52,
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  53,
						EndPos:    54,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  52,
								EndPos:    53,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClassMethod_AbstractClassMethod(t *testing.T) {
	src := `<? abstract class Foo{ abstract public function bar(); }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    56,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    56,
				},
				Modifiers: []ast.Vertex{
					&ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    11,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_ABSTRACT,
							Value: []byte("abstract"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    11,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Value: []byte("abstract"),
					},
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    17,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    21,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    21,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    18,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  21,
						EndPos:    22,
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtClassMethod{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  23,
							EndPos:    54,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  23,
									EndPos:    31,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_ABSTRACT,
									Value: []byte("abstract"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  23,
										EndPos:    31,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  22,
												EndPos:    23,
											},
										},
									},
								},
								Value: []byte("abstract"),
							},
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  32,
									EndPos:    38,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_PUBLIC,
									Value: []byte("public"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  32,
										EndPos:    38,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  31,
												EndPos:    32,
											},
										},
									},
								},
								Value: []byte("public"),
							},
						},
						FunctionTkn: &token.Token{
							ID:    token.T_FUNCTION,
							Value: []byte("function"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  39,
								EndPos:    47,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  38,
										EndPos:    39,
									},
								},
							},
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  48,
								EndPos:    51,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  48,
									EndPos:    51,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  47,
											EndPos:    48,
										},
									},
								},
							},
							Value: []byte("bar"),
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  51,
								EndPos:    52,
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  52,
								EndPos:    53,
							},
						},
						Stmt: &ast.StmtNop{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  53,
								EndPos:    54,
							},
							SemiColonTkn: &token.Token{
								ID:    token.ID(59),
								Value: []byte(";"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  53,
									EndPos:    54,
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  55,
						EndPos:    56,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  54,
								EndPos:    55,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClassMethod_Php7AbstractClassMethod(t *testing.T) {
	src := `<? abstract class Foo{ public function bar(): void; }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    53,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    53,
				},
				Modifiers: []ast.Vertex{
					&ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    11,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_ABSTRACT,
							Value: []byte("abstract"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    11,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Value: []byte("abstract"),
					},
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    17,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    21,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    21,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    18,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  21,
						EndPos:    22,
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtClassMethod{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  23,
							EndPos:    51,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  23,
									EndPos:    29,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_PUBLIC,
									Value: []byte("public"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  23,
										EndPos:    29,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  22,
												EndPos:    23,
											},
										},
									},
								},
								Value: []byte("public"),
							},
						},
						FunctionTkn: &token.Token{
							ID:    token.T_FUNCTION,
							Value: []byte("function"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  30,
								EndPos:    38,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  29,
										EndPos:    30,
									},
								},
							},
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  39,
								EndPos:    42,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  39,
									EndPos:    42,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  38,
											EndPos:    39,
										},
									},
								},
							},
							Value: []byte("bar"),
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  42,
								EndPos:    43,
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  43,
								EndPos:    44,
							},
						},
						ColonTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  44,
								EndPos:    45,
							},
						},
						ReturnType: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  46,
								EndPos:    50,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  46,
										EndPos:    50,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("void"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  46,
											EndPos:    50,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  45,
													EndPos:    46,
												},
											},
										},
									},
									Value: []byte("void"),
								},
							},
						},
						Stmt: &ast.StmtNop{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  50,
								EndPos:    51,
							},
							SemiColonTkn: &token.Token{
								ID:    token.ID(59),
								Value: []byte(";"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  50,
									EndPos:    51,
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  52,
						EndPos:    53,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  51,
								EndPos:    52,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClass_SimpleClass(t *testing.T) {
	src := `<? class foo{ }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    15,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    15,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    13,
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    15,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClass_AbstractClass(t *testing.T) {
	src := `<? abstract class foo{ }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    24,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    24,
				},
				Modifiers: []ast.Vertex{
					&ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    11,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_ABSTRACT,
							Value: []byte("abstract"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    11,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Value: []byte("abstract"),
					},
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    17,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    21,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    21,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    18,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  21,
						EndPos:    22,
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  23,
						EndPos:    24,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClass_ClassExtends(t *testing.T) {
	src := `<? final class foo extends bar { }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    34,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    34,
				},
				Modifiers: []ast.Vertex{
					&ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    8,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_FINAL,
							Value: []byte("final"),
							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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Value: []byte("final"),
					},
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  15,
						EndPos:    18,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    18,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    15,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				ExtendsTkn: &token.Token{
					ID:    token.T_EXTENDS,
					Value: []byte("extends"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  19,
						EndPos:    26,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    19,
							},
						},
					},
				},
				Extends: &ast.Name{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  27,
						EndPos:    30,
					},
					Parts: []ast.Vertex{
						&ast.NamePart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  27,
								EndPos:    30,
							},
							StringTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  27,
									EndPos:    30,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  26,
											EndPos:    27,
										},
									},
								},
							},
							Value: []byte("bar"),
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  31,
						EndPos:    32,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  30,
								EndPos:    31,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  33,
						EndPos:    34,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  32,
								EndPos:    33,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClass_ClassImplement(t *testing.T) {
	src := `<? final class foo implements bar { }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    37,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    37,
				},
				Modifiers: []ast.Vertex{
					&ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    8,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_FINAL,
							Value: []byte("final"),
							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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Value: []byte("final"),
					},
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  15,
						EndPos:    18,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    18,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    15,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				ImplementsTkn: &token.Token{
					ID:    token.T_IMPLEMENTS,
					Value: []byte("implements"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  19,
						EndPos:    29,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    19,
							},
						},
					},
				},
				Implements: []ast.Vertex{
					&ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  30,
							EndPos:    33,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  30,
									EndPos:    33,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("bar"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  30,
										EndPos:    33,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  29,
												EndPos:    30,
											},
										},
									},
								},
								Value: []byte("bar"),
							},
						},
					},
				},
				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:  36,
						EndPos:    37,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClass_ClassImplements(t *testing.T) {
	src := `<? final class foo implements bar, baz { }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    42,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    42,
				},
				Modifiers: []ast.Vertex{
					&ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    8,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_FINAL,
							Value: []byte("final"),
							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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Value: []byte("final"),
					},
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  15,
						EndPos:    18,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    18,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    15,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				ImplementsTkn: &token.Token{
					ID:    token.T_IMPLEMENTS,
					Value: []byte("implements"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  19,
						EndPos:    29,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    19,
							},
						},
					},
				},
				Implements: []ast.Vertex{
					&ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  30,
							EndPos:    33,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  30,
									EndPos:    33,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("bar"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  30,
										EndPos:    33,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  29,
												EndPos:    30,
											},
										},
									},
								},
								Value: []byte("bar"),
							},
						},
					},
					&ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  35,
							EndPos:    38,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  35,
									EndPos:    38,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("baz"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  35,
										EndPos:    38,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  34,
												EndPos:    35,
											},
										},
									},
								},
								Value: []byte("baz"),
							},
						},
					},
				},
				ImplementsSeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  33,
							EndPos:    34,
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  39,
						EndPos:    40,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  38,
								EndPos:    39,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  41,
						EndPos:    42,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  40,
								EndPos:    41,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtClass_AnonimousClass(t *testing.T) {
	src := `<? new class() extends foo implements bar, baz { };`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    51,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    51,
				},
				Expr: &ast.ExprNew{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    50,
					},
					NewTkn: &token.Token{
						ID:    token.T_NEW,
						Value: []byte("new"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Class: &ast.StmtClass{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    50,
						},
						ClassTkn: &token.Token{
							ID:    token.T_CLASS,
							Value: []byte("class"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    12,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  6,
										EndPos:    7,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    14,
							},
						},
						ExtendsTkn: &token.Token{
							ID:    token.T_EXTENDS,
							Value: []byte("extends"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    22,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    15,
									},
								},
							},
						},
						Extends: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  23,
								EndPos:    26,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  23,
										EndPos:    26,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  23,
											EndPos:    26,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  22,
													EndPos:    23,
												},
											},
										},
									},
									Value: []byte("foo"),
								},
							},
						},
						ImplementsTkn: &token.Token{
							ID:    token.T_IMPLEMENTS,
							Value: []byte("implements"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  27,
								EndPos:    37,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  26,
										EndPos:    27,
									},
								},
							},
						},
						Implements: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  38,
									EndPos:    41,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  38,
											EndPos:    41,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("bar"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  38,
												EndPos:    41,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  37,
														EndPos:    38,
													},
												},
											},
										},
										Value: []byte("bar"),
									},
								},
							},
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  43,
									EndPos:    46,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  43,
											EndPos:    46,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("baz"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  43,
												EndPos:    46,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  42,
														EndPos:    43,
													},
												},
											},
										},
										Value: []byte("baz"),
									},
								},
							},
						},
						ImplementsSeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  41,
									EndPos:    42,
								},
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  47,
								EndPos:    48,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  46,
										EndPos:    47,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  49,
								EndPos:    50,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  48,
										EndPos:    49,
									},
								},
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  50,
						EndPos:    51,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtConstList(t *testing.T) {
	src := `<? const FOO = 1, BAR = 2;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    26,
		},
		Stmts: []ast.Vertex{
			&ast.StmtConstList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    26,
				},
				ConstTkn: &token.Token{
					ID:    token.T_CONST,
					Value: []byte("const"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Consts: []ast.Vertex{
					&ast.StmtConstant{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    16,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    12,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("FOO"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    12,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    9,
										},
									},
								},
							},
							Value: []byte("FOO"),
						},
						EqualTkn: &token.Token{
							ID:    token.ID(61),
							Value: []byte("="),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    14,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    13,
									},
								},
							},
						},
						Expr: &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"),
						},
					},
					&ast.StmtConstant{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    25,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    21,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("BAR"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  18,
									EndPos:    21,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  17,
											EndPos:    18,
										},
									},
								},
							},
							Value: []byte("BAR"),
						},
						EqualTkn: &token.Token{
							ID:    token.ID(61),
							Value: []byte("="),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  22,
								EndPos:    23,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  21,
										EndPos:    22,
									},
								},
							},
						},
						Expr: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  24,
								EndPos:    25,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("2"),
								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,
										},
									},
								},
							},
							Value: []byte("2"),
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    17,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  25,
						EndPos:    26,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtContinue_Empty(t *testing.T) {
	src := `<? while (1) { continue; }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    26,
		},
		Stmts: []ast.Vertex{
			&ast.StmtWhile{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    26,
				},
				WhileTkn: &token.Token{
					ID:    token.T_WHILE,
					Value: []byte("while"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Cond: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    26,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    13,
								},
							},
						},
					},
					Stmts: []ast.Vertex{
						&ast.StmtContinue{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    24,
							},
							ContinueTkn: &token.Token{
								ID:    token.T_CONTINUE,
								Value: []byte("continue"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  15,
									EndPos:    23,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										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:  23,
									EndPos:    24,
								},
							},
						},
					},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  25,
							EndPos:    26,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  24,
									EndPos:    25,
								},
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtContinue_Light(t *testing.T) {
	src := `<? while (1) { continue 2; }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    28,
		},
		Stmts: []ast.Vertex{
			&ast.StmtWhile{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    28,
				},
				WhileTkn: &token.Token{
					ID:    token.T_WHILE,
					Value: []byte("while"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Cond: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    28,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    13,
								},
							},
						},
					},
					Stmts: []ast.Vertex{
						&ast.StmtContinue{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    26,
							},
							ContinueTkn: &token.Token{
								ID:    token.T_CONTINUE,
								Value: []byte("continue"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  15,
									EndPos:    23,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  14,
											EndPos:    15,
										},
									},
								},
							},
							Expr: &ast.ScalarLnumber{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  24,
									EndPos:    25,
								},
								NumberTkn: &token.Token{
									ID:    token.T_LNUMBER,
									Value: []byte("2"),
									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,
											},
										},
									},
								},
								Value: []byte("2"),
							},
							SemiColonTkn: &token.Token{
								ID:    token.ID(59),
								Value: []byte(";"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  25,
									EndPos:    26,
								},
							},
						},
					},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  27,
							EndPos:    28,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  26,
									EndPos:    27,
								},
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtContinue(t *testing.T) {
	src := `<? while (1) { continue(3); }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    29,
		},
		Stmts: []ast.Vertex{
			&ast.StmtWhile{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    29,
				},
				WhileTkn: &token.Token{
					ID:    token.T_WHILE,
					Value: []byte("while"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Cond: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    29,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    13,
								},
							},
						},
					},
					Stmts: []ast.Vertex{
						&ast.StmtContinue{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    27,
							},
							ContinueTkn: &token.Token{
								ID:    token.T_CONTINUE,
								Value: []byte("continue"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  15,
									EndPos:    23,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  14,
											EndPos:    15,
										},
									},
								},
							},
							Expr: &ast.ExprBrackets{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  23,
									EndPos:    26,
								},
								OpenParenthesisTkn: &token.Token{
									ID:    token.ID(40),
									Value: []byte("("),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  23,
										EndPos:    24,
									},
								},
								Expr: &ast.ScalarLnumber{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  24,
										EndPos:    25,
									},
									NumberTkn: &token.Token{
										ID:    token.T_LNUMBER,
										Value: []byte("3"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  24,
											EndPos:    25,
										},
									},
									Value: []byte("3"),
								},
								CloseParenthesisTkn: &token.Token{
									ID:    token.ID(41),
									Value: []byte(")"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  25,
										EndPos:    26,
									},
								},
							},
							SemiColonTkn: &token.Token{
								ID:    token.ID(59),
								Value: []byte(";"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  26,
									EndPos:    27,
								},
							},
						},
					},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						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,
								},
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtDeclare(t *testing.T) {
	src := `<? declare(ticks=1);`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    20,
		},
		Stmts: []ast.Vertex{
			&ast.StmtDeclare{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    20,
				},
				DeclareTkn: &token.Token{
					ID:    token.T_DECLARE,
					Value: []byte("declare"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
				},
				Consts: []ast.Vertex{
					&ast.StmtConstant{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    18,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    16,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("ticks"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  11,
									EndPos:    16,
								},
							},
							Value: []byte("ticks"),
						},
						EqualTkn: &token.Token{
							ID:    token.ID(61),
							Value: []byte("="),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
						},
						Expr: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  17,
								EndPos:    18,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    18,
								},
							},
							Value: []byte("1"),
						},
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
				Stmt: &ast.StmtNop{
					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:  19,
							EndPos:    20,
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtDeclare_Stmts(t *testing.T) {
	src := `<? declare(ticks=1, strict_types=1) {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    38,
		},
		Stmts: []ast.Vertex{
			&ast.StmtDeclare{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    38,
				},
				DeclareTkn: &token.Token{
					ID:    token.T_DECLARE,
					Value: []byte("declare"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
				},
				Consts: []ast.Vertex{
					&ast.StmtConstant{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    18,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    16,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("ticks"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  11,
									EndPos:    16,
								},
							},
							Value: []byte("ticks"),
						},
						EqualTkn: &token.Token{
							ID:    token.ID(61),
							Value: []byte("="),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
						},
						Expr: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  17,
								EndPos:    18,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    18,
								},
							},
							Value: []byte("1"),
						},
					},
					&ast.StmtConstant{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  20,
							EndPos:    34,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  20,
								EndPos:    32,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("strict_types"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  20,
									EndPos:    32,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  19,
											EndPos:    20,
										},
									},
								},
							},
							Value: []byte("strict_types"),
						},
						EqualTkn: &token.Token{
							ID:    token.ID(61),
							Value: []byte("="),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  32,
								EndPos:    33,
							},
						},
						Expr: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  33,
								EndPos:    34,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  33,
									EndPos:    34,
								},
							},
							Value: []byte("1"),
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    19,
						},
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  34,
						EndPos:    35,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  36,
						EndPos:    38,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  36,
							EndPos:    37,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  35,
									EndPos:    36,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  37,
							EndPos:    38,
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtDeclare_Alt(t *testing.T) {
	src := `<? declare(ticks=1): enddeclare;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    32,
		},
		Stmts: []ast.Vertex{
			&ast.StmtDeclare{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    32,
				},
				DeclareTkn: &token.Token{
					ID:    token.T_DECLARE,
					Value: []byte("declare"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
				},
				Consts: []ast.Vertex{
					&ast.StmtConstant{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    18,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    16,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("ticks"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  11,
									EndPos:    16,
								},
							},
							Value: []byte("ticks"),
						},
						EqualTkn: &token.Token{
							ID:    token.ID(61),
							Value: []byte("="),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
						},
						Expr: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  17,
								EndPos:    18,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    18,
								},
							},
							Value: []byte("1"),
						},
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  19,
						EndPos:    20,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: -1,
						EndLine:   -1,
						StartPos:  -1,
						EndPos:    -1,
					},
					Stmts: []ast.Vertex{},
				},
				EndDeclareTkn: &token.Token{
					ID:    token.T_ENDDECLARE,
					Value: []byte("enddeclare"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  21,
						EndPos:    31,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							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:  31,
						EndPos:    32,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtDo(t *testing.T) {
	src := `<? do {} while(1);`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    18,
		},
		Stmts: []ast.Vertex{
			&ast.StmtDo{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    18,
				},
				DoTkn: &token.Token{
					ID:    token.T_DO,
					Value: []byte("do"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    8,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    6,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
				},
				WhileTkn: &token.Token{
					ID:    token.T_WHILE,
					Value: []byte("while"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    15,
					},
				},
				Cond: &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,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  16,
						EndPos:    17,
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtEcho(t *testing.T) {
	src := `<? echo $a, 1;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    14,
		},
		Stmts: []ast.Vertex{
			&ast.StmtEcho{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    14,
				},
				EchoTkn: &token.Token{
					ID:    token.T_ECHO,
					Value: []byte("echo"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    7,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Exprs: []ast.Vertex{
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    10,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    10,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								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,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					&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,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  11,
										EndPos:    12,
									},
								},
							},
						},
						Value: []byte("1"),
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtEcho_Parenthesis(t *testing.T) {
	src := `<? echo($a);`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtEcho{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				EchoTkn: &token.Token{
					ID:    token.T_ECHO,
					Value: []byte("echo"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    7,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Exprs: []ast.Vertex{
					&ast.ExprBrackets{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    11,
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
						},
						Expr: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    10,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    10,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    10,
									},
								},
								Value: []byte("$a"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    11,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtExpression(t *testing.T) {
	src := `<? 1;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    5,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    5,
				},
				Expr: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    4,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("1"),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  4,
						EndPos:    5,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtFor(t *testing.T) {
	src := `<? for($i = 0; $i < 10; $i++, $i++) {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    38,
		},
		Stmts: []ast.Vertex{
			&ast.StmtFor{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    38,
				},
				ForTkn: &token.Token{
					ID:    token.T_FOR,
					Value: []byte("for"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
				Init: []ast.Vertex{
					&ast.ExprAssign{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    13,
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    9,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  7,
									EndPos:    9,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$i"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  7,
										EndPos:    9,
									},
								},
								Value: []byte("$i"),
							},
						},
						EqualTkn: &token.Token{
							ID:    token.ID(61),
							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,
									},
								},
							},
						},
						Expr: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("0"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    13,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  11,
											EndPos:    12,
										},
									},
								},
							},
							Value: []byte("0"),
						},
					},
				},
				InitSemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
				},
				Cond: []ast.Vertex{
					&ast.ExprBinarySmaller{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    22,
						},
						Left: &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("$i"),
									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("$i"),
							},
						},
						OpTkn: &token.Token{
							ID:    token.ID(60),
							Value: []byte("<"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    19,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Right: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  20,
								EndPos:    22,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("10"),
								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("10"),
						},
					},
				},
				CondSemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  22,
						EndPos:    23,
					},
				},
				Loop: []ast.Vertex{
					&ast.ExprPostInc{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  24,
							EndPos:    28,
						},
						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("$i"),
									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("$i"),
							},
						},
						IncTkn: &token.Token{
							ID:    token.T_INC,
							Value: []byte("++"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  26,
								EndPos:    28,
							},
						},
					},
					&ast.ExprPostInc{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  30,
							EndPos:    34,
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  30,
								EndPos:    32,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  30,
									EndPos:    32,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$i"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  30,
										EndPos:    32,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  29,
												EndPos:    30,
											},
										},
									},
								},
								Value: []byte("$i"),
							},
						},
						IncTkn: &token.Token{
							ID:    token.T_INC,
							Value: []byte("++"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  32,
								EndPos:    34,
							},
						},
					},
				},
				LoopSeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						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:  34,
						EndPos:    35,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  36,
						EndPos:    38,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  36,
							EndPos:    37,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  35,
									EndPos:    36,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  37,
							EndPos:    38,
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtFor_Alt(t *testing.T) {
	src := `<? for(; $i < 10; $i++) : endfor;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    33,
		},
		Stmts: []ast.Vertex{
			&ast.StmtFor{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    33,
				},
				ForTkn: &token.Token{
					ID:    token.T_FOR,
					Value: []byte("for"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
				InitSemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    8,
					},
				},
				Cond: []ast.Vertex{
					&ast.ExprBinarySmaller{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    16,
						},
						Left: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$i"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    11,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  8,
												EndPos:    9,
											},
										},
									},
								},
								Value: []byte("$i"),
							},
						},
						OpTkn: &token.Token{
							ID:    token.ID(60),
							Value: []byte("<"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  11,
										EndPos:    12,
									},
								},
							},
						},
						Right: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    16,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("10"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    16,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  13,
											EndPos:    14,
										},
									},
								},
							},
							Value: []byte("10"),
						},
					},
				},
				CondSemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  16,
						EndPos:    17,
					},
				},
				Loop: []ast.Vertex{
					&ast.ExprPostInc{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    22,
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  18,
									EndPos:    20,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$i"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  18,
										EndPos:    20,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  17,
												EndPos:    18,
											},
										},
									},
								},
								Value: []byte("$i"),
							},
						},
						IncTkn: &token.Token{
							ID:    token.T_INC,
							Value: []byte("++"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  20,
								EndPos:    22,
							},
						},
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  22,
						EndPos:    23,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					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,
							},
						},
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: -1,
						EndLine:   -1,
						StartPos:  -1,
						EndPos:    -1,
					},
					Stmts: []ast.Vertex{},
				},
				EndForTkn: &token.Token{
					ID:    token.T_ENDFOR,
					Value: []byte("endfor"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  26,
						EndPos:    32,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  25,
								EndPos:    26,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  32,
						EndPos:    33,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtForeach(t *testing.T) {
	src := `<? foreach ($a as $v) {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    24,
		},
		Stmts: []ast.Vertex{
			&ast.StmtForeach{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    24,
				},
				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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    11,
							},
						},
					},
				},
				Expr: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    14,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    14,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    14,
							},
						},
						Value: []byte("$a"),
					},
				},
				AsTkn: &token.Token{
					ID:    token.T_AS,
					Value: []byte("as"),
					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,
							},
						},
					},
				},
				Var: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    20,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    20,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$v"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Value: []byte("$v"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  20,
						EndPos:    21,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  22,
						EndPos:    24,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  22,
							EndPos:    23,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  21,
									EndPos:    22,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtForeach_Expr(t *testing.T) {
	src := `<? foreach ([] as $v) {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    24,
		},
		Stmts: []ast.Vertex{
			&ast.StmtForeach{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    24,
				},
				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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    11,
							},
						},
					},
				},
				Expr: &ast.ExprArray{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    14,
					},
					OpenBracketTkn: &token.Token{
						ID:    token.ID(91),
						Value: []byte("["),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
					CloseBracketTkn: &token.Token{
						ID:    token.ID(93),
						Value: []byte("]"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
					},
				},
				AsTkn: &token.Token{
					ID:    token.T_AS,
					Value: []byte("as"),
					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,
							},
						},
					},
				},
				Var: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    20,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    20,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$v"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Value: []byte("$v"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  20,
						EndPos:    21,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  22,
						EndPos:    24,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  22,
							EndPos:    23,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  21,
									EndPos:    22,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtForeach_Alt(t *testing.T) {
	src := `<? foreach ($a as $v) : endforeach;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    35,
		},
		Stmts: []ast.Vertex{
			&ast.StmtForeach{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    35,
				},
				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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    11,
							},
						},
					},
				},
				Expr: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    14,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    14,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    14,
							},
						},
						Value: []byte("$a"),
					},
				},
				AsTkn: &token.Token{
					ID:    token.T_AS,
					Value: []byte("as"),
					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,
							},
						},
					},
				},
				Var: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    20,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    20,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$v"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Value: []byte("$v"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  20,
						EndPos:    21,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  22,
						EndPos:    23,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  21,
								EndPos:    22,
							},
						},
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: -1,
						EndLine:   -1,
						StartPos:  -1,
						EndPos:    -1,
					},
					Stmts: []ast.Vertex{},
				},
				EndForeachTkn: &token.Token{
					ID:    token.T_ENDFOREACH,
					Value: []byte("endforeach"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  24,
						EndPos:    34,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  23,
								EndPos:    24,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  34,
						EndPos:    35,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtForeach_WithKey(t *testing.T) {
	src := `<? foreach ($a as $k => $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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    11,
							},
						},
					},
				},
				Expr: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    14,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    14,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    14,
							},
						},
						Value: []byte("$a"),
					},
				},
				AsTkn: &token.Token{
					ID:    token.T_AS,
					Value: []byte("as"),
					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,
							},
						},
					},
				},
				Key: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    20,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    20,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$k"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Value: []byte("$k"),
					},
				},
				DoubleArrowTkn: &token.Token{
					ID:    token.T_DOUBLE_ARROW,
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtForeach_ExprWithKey(t *testing.T) {
	src := `<? foreach ([] as $k => $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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    11,
							},
						},
					},
				},
				Expr: &ast.ExprArray{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    14,
					},
					OpenBracketTkn: &token.Token{
						ID:    token.ID(91),
						Value: []byte("["),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
					CloseBracketTkn: &token.Token{
						ID:    token.ID(93),
						Value: []byte("]"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
					},
				},
				AsTkn: &token.Token{
					ID:    token.T_AS,
					Value: []byte("as"),
					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,
							},
						},
					},
				},
				Key: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    20,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    20,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$k"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Value: []byte("$k"),
					},
				},
				DoubleArrowTkn: &token.Token{
					ID:    token.T_DOUBLE_ARROW,
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtForeach_WithRef(t *testing.T) {
	src := `<? foreach ($a as $k => &$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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    11,
							},
						},
					},
				},
				Expr: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    14,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    14,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    14,
							},
						},
						Value: []byte("$a"),
					},
				},
				AsTkn: &token.Token{
					ID:    token.T_AS,
					Value: []byte("as"),
					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,
							},
						},
					},
				},
				Key: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    20,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    20,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$k"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Value: []byte("$k"),
					},
				},
				DoubleArrowTkn: &token.Token{
					ID:    token.T_DOUBLE_ARROW,
					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.ID(38),
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtForeach_WithList(t *testing.T) {
	src := `<? foreach ($a as $k => 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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    11,
							},
						},
					},
				},
				Expr: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    14,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    14,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    14,
							},
						},
						Value: []byte("$a"),
					},
				},
				AsTkn: &token.Token{
					ID:    token.T_AS,
					Value: []byte("as"),
					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,
							},
						},
					},
				},
				Key: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    20,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    20,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$k"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Value: []byte("$k"),
					},
				},
				DoubleArrowTkn: &token.Token{
					ID:    token.T_DOUBLE_ARROW,
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtFunction(t *testing.T) {
	src := `<? function foo() {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    20,
		},
		Stmts: []ast.Vertex{
			&ast.StmtFunction{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    20,
				},
				FunctionTkn: &token.Token{
					ID:    token.T_FUNCTION,
					Value: []byte("function"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    15,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  11,
									EndPos:    12,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  15,
						EndPos:    16,
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  16,
						EndPos:    17,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  17,
								EndPos:    18,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  19,
						EndPos:    20,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtFunction_Return(t *testing.T) {
	src := `<? function foo() {return;}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    27,
		},
		Stmts: []ast.Vertex{
			&ast.StmtFunction{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    27,
				},
				FunctionTkn: &token.Token{
					ID:    token.T_FUNCTION,
					Value: []byte("function"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    15,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  11,
									EndPos:    12,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  15,
						EndPos:    16,
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  16,
						EndPos:    17,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  17,
								EndPos:    18,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtReturn{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  19,
							EndPos:    26,
						},
						ReturnTkn: &token.Token{
							ID:    token.T_RETURN,
							Value: []byte("return"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  19,
								EndPos:    25,
							},
						},
						SemiColonTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  25,
								EndPos:    26,
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  26,
						EndPos:    27,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtFunction_ReturnVar(t *testing.T) {
	src := `<? function foo(array $a, callable $b) {return $a;}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    51,
		},
		Stmts: []ast.Vertex{
			&ast.StmtFunction{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    51,
				},
				FunctionTkn: &token.Token{
					ID:    token.T_FUNCTION,
					Value: []byte("function"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    15,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  11,
									EndPos:    12,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  15,
						EndPos:    16,
					},
				},
				Params: []ast.Vertex{
					&ast.Parameter{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    24,
						},
						Type: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    21,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_ARRAY,
								Value: []byte("array"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  16,
									EndPos:    21,
								},
							},
							Value: []byte("array"),
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  22,
								EndPos:    24,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  22,
									EndPos:    24,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  22,
										EndPos:    24,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  21,
												EndPos:    22,
											},
										},
									},
								},
								Value: []byte("$a"),
							},
						},
					},
					&ast.Parameter{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  26,
							EndPos:    37,
						},
						Type: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  26,
								EndPos:    34,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_CALLABLE,
								Value: []byte("callable"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  26,
									EndPos:    34,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  25,
											EndPos:    26,
										},
									},
								},
							},
							Value: []byte("callable"),
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  35,
								EndPos:    37,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  35,
									EndPos:    37,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  35,
										EndPos:    37,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  34,
												EndPos:    35,
											},
										},
									},
								},
								Value: []byte("$b"),
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  24,
							EndPos:    25,
						},
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  37,
						EndPos:    38,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  39,
						EndPos:    40,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  38,
								EndPos:    39,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtReturn{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  40,
							EndPos:    50,
						},
						ReturnTkn: &token.Token{
							ID:    token.T_RETURN,
							Value: []byte("return"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  40,
								EndPos:    46,
							},
						},
						Expr: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  47,
								EndPos:    49,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  47,
									EndPos:    49,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  47,
										EndPos:    49,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  46,
												EndPos:    47,
											},
										},
									},
								},
								Value: []byte("$a"),
							},
						},
						SemiColonTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  49,
								EndPos:    50,
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  50,
						EndPos:    51,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtFunction_Ref(t *testing.T) {
	src := `<? function &foo() {return 1;}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    30,
		},
		Stmts: []ast.Vertex{
			&ast.StmtFunction{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    30,
				},
				FunctionTkn: &token.Token{
					ID:    token.T_FUNCTION,
					Value: []byte("function"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				AmpersandTkn: &token.Token{
					ID:    token.ID(38),
					Value: []byte("&"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    13,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    16,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    16,
						},
					},
					Value: []byte("foo"),
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  16,
						EndPos:    17,
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  17,
						EndPos:    18,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  19,
						EndPos:    20,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    19,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtReturn{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  20,
							EndPos:    29,
						},
						ReturnTkn: &token.Token{
							ID:    token.T_RETURN,
							Value: []byte("return"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  20,
								EndPos:    26,
							},
						},
						Expr: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  27,
								EndPos:    28,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  27,
									EndPos:    28,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  26,
											EndPos:    27,
										},
									},
								},
							},
							Value: []byte("1"),
						},
						SemiColonTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  28,
								EndPos:    29,
							},
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtFunction_ReturnType(t *testing.T) {
	src := `<? function &foo(): void {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    27,
		},
		Stmts: []ast.Vertex{
			&ast.StmtFunction{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    27,
				},
				FunctionTkn: &token.Token{
					ID:    token.T_FUNCTION,
					Value: []byte("function"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				AmpersandTkn: &token.Token{
					ID:    token.ID(38),
					Value: []byte("&"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  12,
						EndPos:    13,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    16,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    16,
						},
					},
					Value: []byte("foo"),
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  16,
						EndPos:    17,
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  17,
						EndPos:    18,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
				ReturnType: &ast.Name{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  20,
						EndPos:    24,
					},
					Parts: []ast.Vertex{
						&ast.NamePart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  20,
								EndPos:    24,
							},
							StringTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("void"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  20,
									EndPos:    24,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  19,
											EndPos:    20,
										},
									},
								},
							},
							Value: []byte("void"),
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  25,
						EndPos:    26,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  24,
								EndPos:    25,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  26,
						EndPos:    27,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtGlobal(t *testing.T) {
	src := `<? global $a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    13,
		},
		Stmts: []ast.Vertex{
			&ast.StmtGlobal{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    13,
				},
				GlobalTkn: &token.Token{
					ID:    token.T_GLOBAL,
					Value: []byte("global"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    9,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Vars: []ast.Vertex{
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    12,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    12,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    12,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  9,
											EndPos:    10,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtGlobal_Vars(t *testing.T) {
	src := `<? global $a, $b, $$c, ${foo()};`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    32,
		},
		Stmts: []ast.Vertex{
			&ast.StmtGlobal{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    32,
				},
				GlobalTkn: &token.Token{
					ID:    token.T_GLOBAL,
					Value: []byte("global"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    9,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Vars: []ast.Vertex{
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    12,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    12,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    12,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  9,
											EndPos:    10,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    16,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    16,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    16,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  13,
											EndPos:    14,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    21,
						},
						DollarTkn: &token.Token{
							ID:    token.ID(36),
							Value: []byte("$"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    19,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Name: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  19,
								EndPos:    21,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    21,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$c"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  19,
										EndPos:    21,
									},
								},
								Value: []byte("$c"),
							},
						},
					},
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  23,
							EndPos:    31,
						},
						DollarTkn: &token.Token{
							ID:    token.ID(36),
							Value: []byte("$"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  23,
								EndPos:    24,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  22,
										EndPos:    23,
									},
								},
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  24,
								EndPos:    25,
							},
						},
						Name: &ast.ExprFunctionCall{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  25,
								EndPos:    30,
							},
							Function: &ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  25,
									EndPos:    28,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										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,
								},
							},
						},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  30,
								EndPos:    31,
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    17,
						},
					},
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  21,
							EndPos:    22,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  31,
						EndPos:    32,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtGotoLabel(t *testing.T) {
	src := `<? a: goto a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    13,
		},
		Stmts: []ast.Vertex{
			&ast.StmtLabel{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    5,
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    4,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("a"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Value: []byte("a"),
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  4,
						EndPos:    5,
					},
				},
			},
			&ast.StmtGoto{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  6,
					EndPos:    13,
				},
				GotoTkn: &token.Token{
					ID:    token.T_GOTO,
					Value: []byte("goto"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  5,
								EndPos:    6,
							},
						},
					},
				},
				Label: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("a"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
						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:  12,
						EndPos:    13,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtHaltCompiler(t *testing.T) {
	src := `<? __halt_compiler();`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    21,
		},
		Stmts: []ast.Vertex{
			&ast.StmtHaltCompiler{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    21,
				},
				HaltCompilerTkn: &token.Token{
					ID:    token.T_HALT_COMPILER,
					Value: []byte("__halt_compiler"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    18,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
				CloseParenthesisTkn: &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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtIf(t *testing.T) {
	src := `<? if ($a) {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    13,
		},
		Stmts: []ast.Vertex{
			&ast.StmtIf{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    13,
				},
				IfTkn: &token.Token{
					ID:    token.T_IF,
					Value: []byte("if"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  5,
								EndPos:    6,
							},
						},
					},
				},
				Cond: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    9,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    9,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    9,
							},
						},
						Value: []byte("$a"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    13,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    11,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtIf_ElseIf(t *testing.T) {
	src := `<? if ($a) {} elseif ($b) {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    28,
		},
		Stmts: []ast.Vertex{
			&ast.StmtIf{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    28,
				},
				IfTkn: &token.Token{
					ID:    token.T_IF,
					Value: []byte("if"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  5,
								EndPos:    6,
							},
						},
					},
				},
				Cond: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    9,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    9,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    9,
							},
						},
						Value: []byte("$a"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    13,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    11,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
				},
				ElseIf: []ast.Vertex{
					&ast.StmtElseIf{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    28,
						},
						ElseIfTkn: &token.Token{
							ID:    token.T_ELSEIF,
							Value: []byte("elseif"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    14,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  21,
								EndPos:    22,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  20,
										EndPos:    21,
									},
								},
							},
						},
						Cond: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  22,
								EndPos:    24,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  22,
									EndPos:    24,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  22,
										EndPos:    24,
									},
								},
								Value: []byte("$b"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  24,
								EndPos:    25,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  26,
								EndPos:    28,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.ID(123),
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  26,
									EndPos:    27,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  25,
											EndPos:    26,
										},
									},
								},
							},
							Stmts: []ast.Vertex{},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  27,
									EndPos:    28,
								},
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtIf_Else(t *testing.T) {
	src := `<? if ($a) {} else {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    21,
		},
		Stmts: []ast.Vertex{
			&ast.StmtIf{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    21,
				},
				IfTkn: &token.Token{
					ID:    token.T_IF,
					Value: []byte("if"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  5,
								EndPos:    6,
							},
						},
					},
				},
				Cond: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    9,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    9,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    9,
							},
						},
						Value: []byte("$a"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    13,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    11,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
				},
				Else: &ast.StmtElse{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    21,
					},
					ElseTkn: &token.Token{
						ID:    token.T_ELSE,
						Value: []byte("else"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    18,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    14,
								},
							},
						},
					},
					Stmt: &ast.StmtStmtList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  19,
							EndPos:    21,
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  19,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  18,
										EndPos:    19,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtIf_ElseElseIf(t *testing.T) {
	src := `<? if ($a) {} elseif ($b) {} elseif ($c) {} else {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    51,
		},
		Stmts: []ast.Vertex{
			&ast.StmtIf{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    51,
				},
				IfTkn: &token.Token{
					ID:    token.T_IF,
					Value: []byte("if"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  5,
								EndPos:    6,
							},
						},
					},
				},
				Cond: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    9,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    9,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    9,
							},
						},
						Value: []byte("$a"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    13,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    11,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
				},
				ElseIf: []ast.Vertex{
					&ast.StmtElseIf{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    28,
						},
						ElseIfTkn: &token.Token{
							ID:    token.T_ELSEIF,
							Value: []byte("elseif"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    14,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  21,
								EndPos:    22,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  20,
										EndPos:    21,
									},
								},
							},
						},
						Cond: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  22,
								EndPos:    24,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  22,
									EndPos:    24,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  22,
										EndPos:    24,
									},
								},
								Value: []byte("$b"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  24,
								EndPos:    25,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  26,
								EndPos:    28,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.ID(123),
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  26,
									EndPos:    27,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  25,
											EndPos:    26,
										},
									},
								},
							},
							Stmts: []ast.Vertex{},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  27,
									EndPos:    28,
								},
							},
						},
					},
					&ast.StmtElseIf{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  29,
							EndPos:    43,
						},
						ElseIfTkn: &token.Token{
							ID:    token.T_ELSEIF,
							Value: []byte("elseif"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  29,
								EndPos:    35,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  28,
										EndPos:    29,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  36,
								EndPos:    37,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  35,
										EndPos:    36,
									},
								},
							},
						},
						Cond: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  37,
								EndPos:    39,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  37,
									EndPos:    39,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$c"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  37,
										EndPos:    39,
									},
								},
								Value: []byte("$c"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  39,
								EndPos:    40,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  41,
								EndPos:    43,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.ID(123),
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  41,
									EndPos:    42,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  40,
											EndPos:    41,
										},
									},
								},
							},
							Stmts: []ast.Vertex{},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  42,
									EndPos:    43,
								},
							},
						},
					},
				},
				Else: &ast.StmtElse{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  44,
						EndPos:    51,
					},
					ElseTkn: &token.Token{
						ID:    token.T_ELSE,
						Value: []byte("else"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  44,
							EndPos:    48,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  43,
									EndPos:    44,
								},
							},
						},
					},
					Stmt: &ast.StmtStmtList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  49,
							EndPos:    51,
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  49,
								EndPos:    50,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  48,
										EndPos:    49,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  50,
								EndPos:    51,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtIf_ElseIfElseIfElse(t *testing.T) {
	src := `<? if ($a) {} elseif ($b) {} else if ($c) {} else {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    52,
		},
		Stmts: []ast.Vertex{
			&ast.StmtIf{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    52,
				},
				IfTkn: &token.Token{
					ID:    token.T_IF,
					Value: []byte("if"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  5,
								EndPos:    6,
							},
						},
					},
				},
				Cond: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    9,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    9,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$a"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    9,
							},
						},
						Value: []byte("$a"),
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    13,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    11,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
				},
				ElseIf: []ast.Vertex{
					&ast.StmtElseIf{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    28,
						},
						ElseIfTkn: &token.Token{
							ID:    token.T_ELSEIF,
							Value: []byte("elseif"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    20,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    14,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  21,
								EndPos:    22,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  20,
										EndPos:    21,
									},
								},
							},
						},
						Cond: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  22,
								EndPos:    24,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  22,
									EndPos:    24,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  22,
										EndPos:    24,
									},
								},
								Value: []byte("$b"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  24,
								EndPos:    25,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  26,
								EndPos:    28,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.ID(123),
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  26,
									EndPos:    27,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  25,
											EndPos:    26,
										},
									},
								},
							},
							Stmts: []ast.Vertex{},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  27,
									EndPos:    28,
								},
							},
						},
					},
				},
				Else: &ast.StmtElse{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  29,
						EndPos:    52,
					},
					ElseTkn: &token.Token{
						ID:    token.T_ELSE,
						Value: []byte("else"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  29,
							EndPos:    33,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  28,
									EndPos:    29,
								},
							},
						},
					},
					Stmt: &ast.StmtIf{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  34,
							EndPos:    52,
						},
						IfTkn: &token.Token{
							ID:    token.T_IF,
							Value: []byte("if"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  34,
								EndPos:    36,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  33,
										EndPos:    34,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  37,
								EndPos:    38,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  36,
										EndPos:    37,
									},
								},
							},
						},
						Cond: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  38,
								EndPos:    40,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  38,
									EndPos:    40,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$c"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  38,
										EndPos:    40,
									},
								},
								Value: []byte("$c"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  40,
								EndPos:    41,
							},
						},
						Stmt: &ast.StmtStmtList{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  42,
								EndPos:    44,
							},
							OpenCurlyBracketTkn: &token.Token{
								ID:    token.ID(123),
								Value: []byte("{"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  42,
									EndPos:    43,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  41,
											EndPos:    42,
										},
									},
								},
							},
							Stmts: []ast.Vertex{},
							CloseCurlyBracketTkn: &token.Token{
								ID:    token.ID(125),
								Value: []byte("}"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  43,
									EndPos:    44,
								},
							},
						},
						Else: &ast.StmtElse{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  45,
								EndPos:    52,
							},
							ElseTkn: &token.Token{
								ID:    token.T_ELSE,
								Value: []byte("else"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  45,
									EndPos:    49,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  44,
											EndPos:    45,
										},
									},
								},
							},
							Stmt: &ast.StmtStmtList{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  50,
									EndPos:    52,
								},
								OpenCurlyBracketTkn: &token.Token{
									ID:    token.ID(123),
									Value: []byte("{"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  50,
										EndPos:    51,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  49,
												EndPos:    50,
											},
										},
									},
								},
								Stmts: []ast.Vertex{},
								CloseCurlyBracketTkn: &token.Token{
									ID:    token.ID(125),
									Value: []byte("}"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  51,
										EndPos:    52,
									},
								},
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtInlineHtml(t *testing.T) {
	src := `<? ?> <div></div>`

	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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
			},
			&ast.StmtInlineHtml{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  5,
					EndPos:    17,
				},
				InlineHtmlTkn: &token.Token{
					ID:    token.T_INLINE_HTML,
					Value: []byte(" <div></div>"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  5,
						EndPos:    17,
					},
				},
				Value: []byte(" <div></div>"),
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtInterface(t *testing.T) {
	src := `<? interface Foo {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    19,
		},
		Stmts: []ast.Vertex{
			&ast.StmtInterface{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    19,
				},
				InterfaceTkn: &token.Token{
					ID:    token.T_INTERFACE,
					Value: []byte("interface"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    16,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    16,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    13,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  17,
						EndPos:    18,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtInterface_Extend(t *testing.T) {
	src := `<? interface Foo extends Bar {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    31,
		},
		Stmts: []ast.Vertex{
			&ast.StmtInterface{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    31,
				},
				InterfaceTkn: &token.Token{
					ID:    token.T_INTERFACE,
					Value: []byte("interface"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    16,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    16,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    13,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				ExtendsTkn: &token.Token{
					ID:    token.T_EXTENDS,
					Value: []byte("extends"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  17,
						EndPos:    24,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
						},
					},
				},
				Extends: []ast.Vertex{
					&ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  25,
							EndPos:    28,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  25,
									EndPos:    28,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Bar"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  25,
										EndPos:    28,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  24,
												EndPos:    25,
											},
										},
									},
								},
								Value: []byte("Bar"),
							},
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtInterface_Extends(t *testing.T) {
	src := `<? interface Foo extends Bar, Baz {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    36,
		},
		Stmts: []ast.Vertex{
			&ast.StmtInterface{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    36,
				},
				InterfaceTkn: &token.Token{
					ID:    token.T_INTERFACE,
					Value: []byte("interface"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    16,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    16,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    13,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				ExtendsTkn: &token.Token{
					ID:    token.T_EXTENDS,
					Value: []byte("extends"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  17,
						EndPos:    24,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
						},
					},
				},
				Extends: []ast.Vertex{
					&ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  25,
							EndPos:    28,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  25,
									EndPos:    28,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Bar"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  25,
										EndPos:    28,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  24,
												EndPos:    25,
											},
										},
									},
								},
								Value: []byte("Bar"),
							},
						},
					},
					&ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  30,
							EndPos:    33,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  30,
									EndPos:    33,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Baz"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  30,
										EndPos:    33,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  29,
												EndPos:    30,
											},
										},
									},
								},
								Value: []byte("Baz"),
							},
						},
					},
				},
				ExtendsSeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  28,
							EndPos:    29,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtNamespace(t *testing.T) {
	src := `<? namespace Foo;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    17,
		},
		Stmts: []ast.Vertex{
			&ast.StmtNamespace{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    17,
				},
				NsTkn: &token.Token{
					ID:    token.T_NAMESPACE,
					Value: []byte("namespace"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Name{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    16,
					},
					Parts: []ast.Vertex{
						&ast.NamePart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    16,
							},
							StringTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("Foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    16,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    13,
										},
									},
								},
							},
							Value: []byte("Foo"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtNamespace_Stmts(t *testing.T) {
	src := `<? namespace Foo {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    19,
		},
		Stmts: []ast.Vertex{
			&ast.StmtNamespace{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    19,
				},
				NsTkn: &token.Token{
					ID:    token.T_NAMESPACE,
					Value: []byte("namespace"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Name{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    16,
					},
					Parts: []ast.Vertex{
						&ast.NamePart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    16,
							},
							StringTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("Foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    16,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    13,
										},
									},
								},
							},
							Value: []byte("Foo"),
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  17,
						EndPos:    18,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtNamespace_Anonymous(t *testing.T) {
	src := `<? namespace {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    15,
		},
		Stmts: []ast.Vertex{
			&ast.StmtNamespace{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    15,
				},
				NsTkn: &token.Token{
					ID:    token.T_NAMESPACE,
					Value: []byte("namespace"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtProperty(t *testing.T) {
	src := `<? class foo {var $a;}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    22,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    22,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtPropertyList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    21,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    17,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VAR,
									Value: []byte("var"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    17,
									},
								},
								Value: []byte("var"),
							},
						},
						Props: []ast.Vertex{
							&ast.StmtProperty{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  18,
									EndPos:    20,
								},
								Var: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  18,
										EndPos:    20,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  18,
											EndPos:    20,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$a"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  18,
												EndPos:    20,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  17,
														EndPos:    18,
													},
												},
											},
										},
										Value: []byte("$a"),
									},
								},
							},
						},
						SemiColonTkn: &token.Token{
							ID:    token.ID(59),
							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,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtProperty_Properties(t *testing.T) {
	src := `<? class foo {public static $a, $b = 1;}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    40,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    40,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtPropertyList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    39,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    20,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_PUBLIC,
									Value: []byte("public"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    20,
									},
								},
								Value: []byte("public"),
							},
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  21,
									EndPos:    27,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_STATIC,
									Value: []byte("static"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  21,
										EndPos:    27,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  20,
												EndPos:    21,
											},
										},
									},
								},
								Value: []byte("static"),
							},
						},
						Props: []ast.Vertex{
							&ast.StmtProperty{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  28,
									EndPos:    30,
								},
								Var: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  28,
										EndPos:    30,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  28,
											EndPos:    30,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$a"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  28,
												EndPos:    30,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  27,
														EndPos:    28,
													},
												},
											},
										},
										Value: []byte("$a"),
									},
								},
							},
							&ast.StmtProperty{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  32,
									EndPos:    38,
								},
								Var: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  32,
										EndPos:    34,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  32,
											EndPos:    34,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$b"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  32,
												EndPos:    34,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  31,
														EndPos:    32,
													},
												},
											},
										},
										Value: []byte("$b"),
									},
								},
								EqualTkn: &token.Token{
									ID:    token.ID(61),
									Value: []byte("="),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  35,
										EndPos:    36,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  34,
												EndPos:    35,
											},
										},
									},
								},
								Expr: &ast.ScalarLnumber{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  37,
										EndPos:    38,
									},
									NumberTkn: &token.Token{
										ID:    token.T_LNUMBER,
										Value: []byte("1"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  37,
											EndPos:    38,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  36,
													EndPos:    37,
												},
											},
										},
									},
									Value: []byte("1"),
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  30,
									EndPos:    31,
								},
							},
						},
						SemiColonTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  38,
								EndPos:    39,
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  39,
						EndPos:    40,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtProperty_Properties2(t *testing.T) {
	src := `<? class foo {public static $a = 1, $b;}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    40,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    40,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtPropertyList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    39,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    20,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_PUBLIC,
									Value: []byte("public"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    20,
									},
								},
								Value: []byte("public"),
							},
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  21,
									EndPos:    27,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_STATIC,
									Value: []byte("static"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  21,
										EndPos:    27,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  20,
												EndPos:    21,
											},
										},
									},
								},
								Value: []byte("static"),
							},
						},
						Props: []ast.Vertex{
							&ast.StmtProperty{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  28,
									EndPos:    34,
								},
								Var: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  28,
										EndPos:    30,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  28,
											EndPos:    30,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$a"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  28,
												EndPos:    30,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  27,
														EndPos:    28,
													},
												},
											},
										},
										Value: []byte("$a"),
									},
								},
								EqualTkn: &token.Token{
									ID:    token.ID(61),
									Value: []byte("="),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  31,
										EndPos:    32,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  30,
												EndPos:    31,
											},
										},
									},
								},
								Expr: &ast.ScalarLnumber{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  33,
										EndPos:    34,
									},
									NumberTkn: &token.Token{
										ID:    token.T_LNUMBER,
										Value: []byte("1"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  33,
											EndPos:    34,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  32,
													EndPos:    33,
												},
											},
										},
									},
									Value: []byte("1"),
								},
							},
							&ast.StmtProperty{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  36,
									EndPos:    38,
								},
								Var: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  36,
										EndPos:    38,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  36,
											EndPos:    38,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$b"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  36,
												EndPos:    38,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  35,
														EndPos:    36,
													},
												},
											},
										},
										Value: []byte("$b"),
									},
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  34,
									EndPos:    35,
								},
							},
						},
						SemiColonTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  38,
								EndPos:    39,
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  39,
						EndPos:    40,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtProperty_PropertyType(t *testing.T) {
	src := `<? class foo {var bar $a;}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    26,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    26,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtPropertyList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    25,
						},
						Modifiers: []ast.Vertex{
							&ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    17,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VAR,
									Value: []byte("var"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    17,
									},
								},
								Value: []byte("var"),
							},
						},
						Type: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    21,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  18,
										EndPos:    21,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  18,
											EndPos:    21,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  17,
													EndPos:    18,
												},
											},
										},
									},
									Value: []byte("bar"),
								},
							},
						},
						Props: []ast.Vertex{
							&ast.StmtProperty{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  22,
									EndPos:    24,
								},
								Var: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  22,
										EndPos:    24,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  22,
											EndPos:    24,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$a"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  22,
												EndPos:    24,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  21,
														EndPos:    22,
													},
												},
											},
										},
										Value: []byte("$a"),
									},
								},
							},
						},
						SemiColonTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  24,
								EndPos:    25,
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  25,
						EndPos:    26,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtStaticVar(t *testing.T) {
	src := `<? static $a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    13,
		},
		Stmts: []ast.Vertex{
			&ast.StmtStatic{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    13,
				},
				StaticTkn: &token.Token{
					ID:    token.T_STATIC,
					Value: []byte("static"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    9,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Vars: []ast.Vertex{
					&ast.StmtStaticVar{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    12,
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    12,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    12,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  10,
										EndPos:    12,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  9,
												EndPos:    10,
											},
										},
									},
								},
								Value: []byte("$a"),
							},
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtStaticVar_Vars(t *testing.T) {
	src := `<? static $a, $b = 1;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    21,
		},
		Stmts: []ast.Vertex{
			&ast.StmtStatic{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    21,
				},
				StaticTkn: &token.Token{
					ID:    token.T_STATIC,
					Value: []byte("static"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    9,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Vars: []ast.Vertex{
					&ast.StmtStaticVar{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    12,
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    12,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    12,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  10,
										EndPos:    12,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  9,
												EndPos:    10,
											},
										},
									},
								},
								Value: []byte("$a"),
							},
						},
					},
					&ast.StmtStaticVar{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    20,
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    16,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    16,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    16,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  13,
												EndPos:    14,
											},
										},
									},
								},
								Value: []byte("$b"),
							},
						},
						EqualTkn: &token.Token{
							ID:    token.ID(61),
							Value: []byte("="),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  17,
								EndPos:    18,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  16,
										EndPos:    17,
									},
								},
							},
						},
						Expr: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  19,
								EndPos:    20,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    20,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  18,
											EndPos:    19,
										},
									},
								},
							},
							Value: []byte("1"),
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtStaticVar_Vars2(t *testing.T) {
	src := `<? static $a = 1, $b;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    21,
		},
		Stmts: []ast.Vertex{
			&ast.StmtStatic{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    21,
				},
				StaticTkn: &token.Token{
					ID:    token.T_STATIC,
					Value: []byte("static"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    9,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Vars: []ast.Vertex{
					&ast.StmtStaticVar{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    16,
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    12,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    12,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  10,
										EndPos:    12,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  9,
												EndPos:    10,
											},
										},
									},
								},
								Value: []byte("$a"),
							},
						},
						EqualTkn: &token.Token{
							ID:    token.ID(61),
							Value: []byte("="),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    14,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    13,
									},
								},
							},
						},
						Expr: &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"),
						},
					},
					&ast.StmtStaticVar{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    20,
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  18,
									EndPos:    20,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  18,
										EndPos:    20,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  17,
												EndPos:    18,
											},
										},
									},
								},
								Value: []byte("$b"),
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    17,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtSwitch(t *testing.T) {
	src := `<?
		switch (1) {
			case 1: break;
			case 2: break;
		}
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   5,
			StartPos:  5,
			EndPos:    57,
		},
		Stmts: []ast.Vertex{
			&ast.StmtSwitch{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   5,
					StartPos:  5,
					EndPos:    57,
				},
				SwitchTkn: &token.Token{
					ID:    token.T_SWITCH,
					Value: []byte("switch"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  5,
						EndPos:    11,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  12,
						EndPos:    13,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
				},
				Cond: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  13,
						EndPos:    14,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  13,
							EndPos:    14,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  14,
						EndPos:    15,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  16,
						EndPos:    17,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  15,
								EndPos:    16,
							},
						},
					},
				},
				Cases: []ast.Vertex{
					&ast.StmtCase{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  21,
							EndPos:    35,
						},
						CaseTkn: &token.Token{
							ID:    token.T_CASE,
							Value: []byte("case"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  21,
								EndPos:    25,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t\t"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   3,
										StartPos:  17,
										EndPos:    21,
									},
								},
							},
						},
						Cond: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  26,
								EndPos:    27,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  26,
									EndPos:    27,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  25,
											EndPos:    26,
										},
									},
								},
							},
							Value: []byte("1"),
						},
						CaseSeparatorTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  27,
								EndPos:    28,
							},
						},
						Stmts: []ast.Vertex{
							&ast.StmtBreak{
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  29,
									EndPos:    35,
								},
								BreakTkn: &token.Token{
									ID:    token.T_BREAK,
									Value: []byte("break"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  29,
										EndPos:    34,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 3,
												EndLine:   3,
												StartPos:  28,
												EndPos:    29,
											},
										},
									},
								},
								SemiColonTkn: &token.Token{
									ID:    token.ID(59),
									Value: []byte(";"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  34,
										EndPos:    35,
									},
								},
							},
						},
					},
					&ast.StmtCase{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  39,
							EndPos:    53,
						},
						CaseTkn: &token.Token{
							ID:    token.T_CASE,
							Value: []byte("case"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  39,
								EndPos:    43,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t\t"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   4,
										StartPos:  35,
										EndPos:    39,
									},
								},
							},
						},
						Cond: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  44,
								EndPos:    45,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("2"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  44,
									EndPos:    45,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 4,
											EndLine:   4,
											StartPos:  43,
											EndPos:    44,
										},
									},
								},
							},
							Value: []byte("2"),
						},
						CaseSeparatorTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  45,
								EndPos:    46,
							},
						},
						Stmts: []ast.Vertex{
							&ast.StmtBreak{
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  47,
									EndPos:    53,
								},
								BreakTkn: &token.Token{
									ID:    token.T_BREAK,
									Value: []byte("break"),
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  47,
										EndPos:    52,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 4,
												EndLine:   4,
												StartPos:  46,
												EndPos:    47,
											},
										},
									},
								},
								SemiColonTkn: &token.Token{
									ID:    token.ID(59),
									Value: []byte(";"),
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  52,
										EndPos:    53,
									},
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  56,
						EndPos:    57,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   5,
								StartPos:  53,
								EndPos:    56,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   6,
						StartPos:  57,
						EndPos:    59,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtSwitch_Semicolon(t *testing.T) {
	src := `<?
		switch (1) {;
			case 1; break;
			case 2; break;
		}
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   5,
			StartPos:  5,
			EndPos:    58,
		},
		Stmts: []ast.Vertex{
			&ast.StmtSwitch{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   5,
					StartPos:  5,
					EndPos:    58,
				},
				SwitchTkn: &token.Token{
					ID:    token.T_SWITCH,
					Value: []byte("switch"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  5,
						EndPos:    11,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  12,
						EndPos:    13,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
				},
				Cond: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  13,
						EndPos:    14,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  13,
							EndPos:    14,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  14,
						EndPos:    15,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  16,
						EndPos:    17,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  15,
								EndPos:    16,
							},
						},
					},
				},
				CaseSeparatorTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  17,
						EndPos:    18,
					},
				},
				Cases: []ast.Vertex{
					&ast.StmtCase{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  22,
							EndPos:    36,
						},
						CaseTkn: &token.Token{
							ID:    token.T_CASE,
							Value: []byte("case"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  22,
								EndPos:    26,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t\t"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   3,
										StartPos:  18,
										EndPos:    22,
									},
								},
							},
						},
						Cond: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  27,
								EndPos:    28,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  27,
									EndPos:    28,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  26,
											EndPos:    27,
										},
									},
								},
							},
							Value: []byte("1"),
						},
						CaseSeparatorTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  28,
								EndPos:    29,
							},
						},
						Stmts: []ast.Vertex{
							&ast.StmtBreak{
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  30,
									EndPos:    36,
								},
								BreakTkn: &token.Token{
									ID:    token.T_BREAK,
									Value: []byte("break"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  30,
										EndPos:    35,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 3,
												EndLine:   3,
												StartPos:  29,
												EndPos:    30,
											},
										},
									},
								},
								SemiColonTkn: &token.Token{
									ID:    token.ID(59),
									Value: []byte(";"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   3,
										StartPos:  35,
										EndPos:    36,
									},
								},
							},
						},
					},
					&ast.StmtCase{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  40,
							EndPos:    54,
						},
						CaseTkn: &token.Token{
							ID:    token.T_CASE,
							Value: []byte("case"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  40,
								EndPos:    44,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t\t"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   4,
										StartPos:  36,
										EndPos:    40,
									},
								},
							},
						},
						Cond: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  45,
								EndPos:    46,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("2"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  45,
									EndPos:    46,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 4,
											EndLine:   4,
											StartPos:  44,
											EndPos:    45,
										},
									},
								},
							},
							Value: []byte("2"),
						},
						CaseSeparatorTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  46,
								EndPos:    47,
							},
						},
						Stmts: []ast.Vertex{
							&ast.StmtBreak{
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  48,
									EndPos:    54,
								},
								BreakTkn: &token.Token{
									ID:    token.T_BREAK,
									Value: []byte("break"),
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  48,
										EndPos:    53,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 4,
												EndLine:   4,
												StartPos:  47,
												EndPos:    48,
											},
										},
									},
								},
								SemiColonTkn: &token.Token{
									ID:    token.ID(59),
									Value: []byte(";"),
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  53,
										EndPos:    54,
									},
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  57,
						EndPos:    58,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   5,
								StartPos:  54,
								EndPos:    57,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   6,
						StartPos:  58,
						EndPos:    60,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtSwitch_Alt(t *testing.T) {
	src := `<?
		switch (1) :
			case 1:
			default:
			case 2;
		endswitch;
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   6,
			StartPos:  5,
			EndPos:    64,
		},
		Stmts: []ast.Vertex{
			&ast.StmtSwitch{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   6,
					StartPos:  5,
					EndPos:    64,
				},
				SwitchTkn: &token.Token{
					ID:    token.T_SWITCH,
					Value: []byte("switch"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  5,
						EndPos:    11,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  12,
						EndPos:    13,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
				},
				Cond: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  13,
						EndPos:    14,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  13,
							EndPos:    14,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  14,
						EndPos:    15,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  16,
						EndPos:    17,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  15,
								EndPos:    16,
							},
						},
					},
				},
				Cases: []ast.Vertex{
					&ast.StmtCase{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   -1,
							StartPos:  21,
							EndPos:    -1,
						},
						CaseTkn: &token.Token{
							ID:    token.T_CASE,
							Value: []byte("case"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  21,
								EndPos:    25,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t\t"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   3,
										StartPos:  17,
										EndPos:    21,
									},
								},
							},
						},
						Cond: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  26,
								EndPos:    27,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  26,
									EndPos:    27,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  25,
											EndPos:    26,
										},
									},
								},
							},
							Value: []byte("1"),
						},
						CaseSeparatorTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  27,
								EndPos:    28,
							},
						},
						Stmts: []ast.Vertex{},
					},
					&ast.StmtDefault{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   -1,
							StartPos:  32,
							EndPos:    -1,
						},
						DefaultTkn: &token.Token{
							ID:    token.T_DEFAULT,
							Value: []byte("default"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  32,
								EndPos:    39,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t\t"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   4,
										StartPos:  28,
										EndPos:    32,
									},
								},
							},
						},
						CaseSeparatorTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  39,
								EndPos:    40,
							},
						},
						Stmts: []ast.Vertex{},
					},
					&ast.StmtCase{
						Position: &position.Position{
							StartLine: 5,
							EndLine:   -1,
							StartPos:  44,
							EndPos:    -1,
						},
						CaseTkn: &token.Token{
							ID:    token.T_CASE,
							Value: []byte("case"),
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  44,
								EndPos:    48,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t\t"),
									Position: &position.Position{
										StartLine: 4,
										EndLine:   5,
										StartPos:  40,
										EndPos:    44,
									},
								},
							},
						},
						Cond: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  49,
								EndPos:    50,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("2"),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  49,
									EndPos:    50,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 5,
											EndLine:   5,
											StartPos:  48,
											EndPos:    49,
										},
									},
								},
							},
							Value: []byte("2"),
						},
						CaseSeparatorTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  50,
								EndPos:    51,
							},
						},
						Stmts: []ast.Vertex{},
					},
				},
				EndSwitchTkn: &token.Token{
					ID:    token.T_ENDSWITCH,
					Value: []byte("endswitch"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  54,
						EndPos:    63,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 5,
								EndLine:   6,
								StartPos:  51,
								EndPos:    54,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  63,
						EndPos:    64,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   7,
						StartPos:  64,
						EndPos:    66,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtSwitch_AltSemicolon(t *testing.T) {
	src := `<?
		switch (1) :;
			case 1;
			case 2;
		endswitch;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   5,
			StartPos:  5,
			EndPos:    53,
		},
		Stmts: []ast.Vertex{
			&ast.StmtSwitch{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   5,
					StartPos:  5,
					EndPos:    53,
				},
				SwitchTkn: &token.Token{
					ID:    token.T_SWITCH,
					Value: []byte("switch"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  5,
						EndPos:    11,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  12,
						EndPos:    13,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
				},
				Cond: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  13,
						EndPos:    14,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  13,
							EndPos:    14,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  14,
						EndPos:    15,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  16,
						EndPos:    17,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  15,
								EndPos:    16,
							},
						},
					},
				},
				CaseSeparatorTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  17,
						EndPos:    18,
					},
				},
				Cases: []ast.Vertex{
					&ast.StmtCase{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   -1,
							StartPos:  22,
							EndPos:    -1,
						},
						CaseTkn: &token.Token{
							ID:    token.T_CASE,
							Value: []byte("case"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  22,
								EndPos:    26,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t\t"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   3,
										StartPos:  18,
										EndPos:    22,
									},
								},
							},
						},
						Cond: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  27,
								EndPos:    28,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  27,
									EndPos:    28,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  26,
											EndPos:    27,
										},
									},
								},
							},
							Value: []byte("1"),
						},
						CaseSeparatorTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  28,
								EndPos:    29,
							},
						},
						Stmts: []ast.Vertex{},
					},
					&ast.StmtCase{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   -1,
							StartPos:  33,
							EndPos:    -1,
						},
						CaseTkn: &token.Token{
							ID:    token.T_CASE,
							Value: []byte("case"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  33,
								EndPos:    37,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte("\n\t\t\t"),
									Position: &position.Position{
										StartLine: 3,
										EndLine:   4,
										StartPos:  29,
										EndPos:    33,
									},
								},
							},
						},
						Cond: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  38,
								EndPos:    39,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("2"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  38,
									EndPos:    39,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 4,
											EndLine:   4,
											StartPos:  37,
											EndPos:    38,
										},
									},
								},
							},
							Value: []byte("2"),
						},
						CaseSeparatorTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  39,
								EndPos:    40,
							},
						},
						Stmts: []ast.Vertex{},
					},
				},
				EndSwitchTkn: &token.Token{
					ID:    token.T_ENDSWITCH,
					Value: []byte("endswitch"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  43,
						EndPos:    52,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   5,
								StartPos:  40,
								EndPos:    43,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  52,
						EndPos:    53,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtThrow(t *testing.T) {
	src := `<? throw $e;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtThrow{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				ThrowTkn: &token.Token{
					ID:    token.T_THROW,
					Value: []byte("throw"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Expr: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    11,
					},
					Name: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    11,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_VARIABLE,
							Value: []byte("$e"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    9,
									},
								},
							},
						},
						Value: []byte("$e"),
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTrait(t *testing.T) {
	src := `<? trait Foo {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    15,
		},
		Stmts: []ast.Vertex{
			&ast.StmtTrait{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    15,
				},
				TraitTkn: &token.Token{
					ID:    token.T_TRAIT,
					Value: []byte("trait"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTraitUse(t *testing.T) {
	src := `<? class Foo { use Bar; }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    25,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    25,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtTraitUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    23,
						},
						UseTkn: &token.Token{
							ID:    token.T_USE,
							Value: []byte("use"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    18,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    15,
									},
								},
							},
						},
						Traits: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    22,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  19,
											EndPos:    22,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Bar"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  19,
												EndPos:    22,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  18,
														EndPos:    19,
													},
												},
											},
										},
										Value: []byte("Bar"),
									},
								},
							},
						},
						SemiColonTkn: &token.Token{
							ID:    token.ID(59),
							Value: []byte(";"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  22,
								EndPos:    23,
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					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,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTraitUse_Uses(t *testing.T) {
	src := `<? class Foo { use Bar, Baz; }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    30,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    30,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtTraitUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    28,
						},
						UseTkn: &token.Token{
							ID:    token.T_USE,
							Value: []byte("use"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    18,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    15,
									},
								},
							},
						},
						Traits: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    22,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  19,
											EndPos:    22,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Bar"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  19,
												EndPos:    22,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  18,
														EndPos:    19,
													},
												},
											},
										},
										Value: []byte("Bar"),
									},
								},
							},
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  24,
									EndPos:    27,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  24,
											EndPos:    27,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Baz"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  24,
												EndPos:    27,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  23,
														EndPos:    24,
													},
												},
											},
										},
										Value: []byte("Baz"),
									},
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								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:  27,
								EndPos:    28,
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					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,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTraitUse_EmptyAdaptations(t *testing.T) {
	src := `<? class Foo { use Bar, Baz {} }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    32,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    32,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtTraitUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    30,
						},
						UseTkn: &token.Token{
							ID:    token.T_USE,
							Value: []byte("use"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    18,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    15,
									},
								},
							},
						},
						Traits: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    22,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  19,
											EndPos:    22,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Bar"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  19,
												EndPos:    22,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  18,
														EndPos:    19,
													},
												},
											},
										},
										Value: []byte("Bar"),
									},
								},
							},
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  24,
									EndPos:    27,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  24,
											EndPos:    27,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Baz"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  24,
												EndPos:    27,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  23,
														EndPos:    24,
													},
												},
											},
										},
										Value: []byte("Baz"),
									},
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  22,
									EndPos:    23,
								},
							},
						},
						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,
									},
								},
							},
						},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							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:  31,
						EndPos:    32,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTraitUse_Modifier(t *testing.T) {
	src := `<? class Foo { use Bar, Baz { one as public; } }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    48,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    48,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtTraitUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    46,
						},
						UseTkn: &token.Token{
							ID:    token.T_USE,
							Value: []byte("use"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    18,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    15,
									},
								},
							},
						},
						Traits: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    22,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  19,
											EndPos:    22,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Bar"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  19,
												EndPos:    22,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  18,
														EndPos:    19,
													},
												},
											},
										},
										Value: []byte("Bar"),
									},
								},
							},
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  24,
									EndPos:    27,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  24,
											EndPos:    27,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Baz"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  24,
												EndPos:    27,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  23,
														EndPos:    24,
													},
												},
											},
										},
										Value: []byte("Baz"),
									},
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  22,
									EndPos:    23,
								},
							},
						},
						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,
									},
								},
							},
						},
						Adaptations: []ast.Vertex{
							&ast.StmtTraitUseAlias{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  30,
									EndPos:    43,
								},
								Method: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  30,
										EndPos:    33,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("one"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  30,
											EndPos:    33,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  29,
													EndPos:    30,
												},
											},
										},
									},
									Value: []byte("one"),
								},
								AsTkn: &token.Token{
									ID:    token.T_AS,
									Value: []byte("as"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  34,
										EndPos:    36,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  33,
												EndPos:    34,
											},
										},
									},
								},
								Modifier: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  37,
										EndPos:    43,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_PUBLIC,
										Value: []byte("public"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  37,
											EndPos:    43,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  36,
													EndPos:    37,
												},
											},
										},
									},
									Value: []byte("public"),
								},
								SemiColonTkn: &token.Token{
									ID:    token.ID(59),
									Value: []byte(";"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  43,
										EndPos:    44,
									},
								},
							},
						},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  45,
								EndPos:    46,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  44,
										EndPos:    45,
									},
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  47,
						EndPos:    48,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  46,
								EndPos:    47,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTraitUse_AliasModifier(t *testing.T) {
	src := `<? class Foo { use Bar, Baz { one as public two; } }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    52,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    52,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtTraitUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    50,
						},
						UseTkn: &token.Token{
							ID:    token.T_USE,
							Value: []byte("use"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    18,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    15,
									},
								},
							},
						},
						Traits: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    22,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  19,
											EndPos:    22,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Bar"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  19,
												EndPos:    22,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  18,
														EndPos:    19,
													},
												},
											},
										},
										Value: []byte("Bar"),
									},
								},
							},
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  24,
									EndPos:    27,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  24,
											EndPos:    27,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Baz"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  24,
												EndPos:    27,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  23,
														EndPos:    24,
													},
												},
											},
										},
										Value: []byte("Baz"),
									},
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  22,
									EndPos:    23,
								},
							},
						},
						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,
									},
								},
							},
						},
						Adaptations: []ast.Vertex{
							&ast.StmtTraitUseAlias{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  30,
									EndPos:    47,
								},
								Method: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  30,
										EndPos:    33,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("one"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  30,
											EndPos:    33,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  29,
													EndPos:    30,
												},
											},
										},
									},
									Value: []byte("one"),
								},
								AsTkn: &token.Token{
									ID:    token.T_AS,
									Value: []byte("as"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  34,
										EndPos:    36,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  33,
												EndPos:    34,
											},
										},
									},
								},
								Modifier: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  37,
										EndPos:    43,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_PUBLIC,
										Value: []byte("public"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  37,
											EndPos:    43,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  36,
													EndPos:    37,
												},
											},
										},
									},
									Value: []byte("public"),
								},
								Alias: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  44,
										EndPos:    47,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("two"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  44,
											EndPos:    47,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  43,
													EndPos:    44,
												},
											},
										},
									},
									Value: []byte("two"),
								},
								SemiColonTkn: &token.Token{
									ID:    token.ID(59),
									Value: []byte(";"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  47,
										EndPos:    48,
									},
								},
							},
						},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  49,
								EndPos:    50,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  48,
										EndPos:    49,
									},
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  51,
						EndPos:    52,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  50,
								EndPos:    51,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTraitUse_Adaptions(t *testing.T) {
	src := `<? class Foo { use Bar, Baz { Bar::one insteadof Baz, Quux; Baz::one as two; } }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    80,
		},
		Stmts: []ast.Vertex{
			&ast.StmtClass{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    80,
				},
				ClassTkn: &token.Token{
					ID:    token.T_CLASS,
					Value: []byte("class"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Name: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_STRING,
						Value: []byte("Foo"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
					},
					Value: []byte("Foo"),
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmts: []ast.Vertex{
					&ast.StmtTraitUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    78,
						},
						UseTkn: &token.Token{
							ID:    token.T_USE,
							Value: []byte("use"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    18,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    15,
									},
								},
							},
						},
						Traits: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    22,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  19,
											EndPos:    22,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Bar"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  19,
												EndPos:    22,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  18,
														EndPos:    19,
													},
												},
											},
										},
										Value: []byte("Bar"),
									},
								},
							},
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  24,
									EndPos:    27,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  24,
											EndPos:    27,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Baz"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  24,
												EndPos:    27,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  23,
														EndPos:    24,
													},
												},
											},
										},
										Value: []byte("Baz"),
									},
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  22,
									EndPos:    23,
								},
							},
						},
						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,
									},
								},
							},
						},
						Adaptations: []ast.Vertex{
							&ast.StmtTraitUsePrecedence{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  30,
									EndPos:    58,
								},
								Trait: &ast.Name{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  30,
										EndPos:    33,
									},
									Parts: []ast.Vertex{
										&ast.NamePart{
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  30,
												EndPos:    33,
											},
											StringTkn: &token.Token{
												ID:    token.T_STRING,
												Value: []byte("Bar"),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  30,
													EndPos:    33,
												},
												FreeFloating: []*token.Token{
													{
														ID:    token.T_WHITESPACE,
														Value: []byte(" "),
														Position: &position.Position{
															StartLine: 1,
															EndLine:   1,
															StartPos:  29,
															EndPos:    30,
														},
													},
												},
											},
											Value: []byte("Bar"),
										},
									},
								},
								DoubleColonTkn: &token.Token{
									ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
									Value: []byte("::"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  33,
										EndPos:    35,
									},
								},
								Method: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  35,
										EndPos:    38,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("one"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  35,
											EndPos:    38,
										},
									},
									Value: []byte("one"),
								},
								InsteadofTkn: &token.Token{
									ID:    token.T_INSTEADOF,
									Value: []byte("insteadof"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  39,
										EndPos:    48,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  38,
												EndPos:    39,
											},
										},
									},
								},
								Insteadof: []ast.Vertex{
									&ast.Name{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  49,
											EndPos:    52,
										},
										Parts: []ast.Vertex{
											&ast.NamePart{
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  49,
													EndPos:    52,
												},
												StringTkn: &token.Token{
													ID:    token.T_STRING,
													Value: []byte("Baz"),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  49,
														EndPos:    52,
													},
													FreeFloating: []*token.Token{
														{
															ID:    token.T_WHITESPACE,
															Value: []byte(" "),
															Position: &position.Position{
																StartLine: 1,
																EndLine:   1,
																StartPos:  48,
																EndPos:    49,
															},
														},
													},
												},
												Value: []byte("Baz"),
											},
										},
									},
									&ast.Name{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  54,
											EndPos:    58,
										},
										Parts: []ast.Vertex{
											&ast.NamePart{
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  54,
													EndPos:    58,
												},
												StringTkn: &token.Token{
													ID:    token.T_STRING,
													Value: []byte("Quux"),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  54,
														EndPos:    58,
													},
													FreeFloating: []*token.Token{
														{
															ID:    token.T_WHITESPACE,
															Value: []byte(" "),
															Position: &position.Position{
																StartLine: 1,
																EndLine:   1,
																StartPos:  53,
																EndPos:    54,
															},
														},
													},
												},
												Value: []byte("Quux"),
											},
										},
									},
								},
								SeparatorTkns: []*token.Token{
									{
										ID:    token.ID(44),
										Value: []byte(","),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  52,
											EndPos:    53,
										},
									},
								},
								SemiColonTkn: &token.Token{
									ID:    token.ID(59),
									Value: []byte(";"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  58,
										EndPos:    59,
									},
								},
							},
							&ast.StmtTraitUseAlias{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  60,
									EndPos:    75,
								},
								Trait: &ast.Name{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  60,
										EndPos:    63,
									},
									Parts: []ast.Vertex{
										&ast.NamePart{
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  60,
												EndPos:    63,
											},
											StringTkn: &token.Token{
												ID:    token.T_STRING,
												Value: []byte("Baz"),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  60,
													EndPos:    63,
												},
												FreeFloating: []*token.Token{
													{
														ID:    token.T_WHITESPACE,
														Value: []byte(" "),
														Position: &position.Position{
															StartLine: 1,
															EndLine:   1,
															StartPos:  59,
															EndPos:    60,
														},
													},
												},
											},
											Value: []byte("Baz"),
										},
									},
								},
								DoubleColonTkn: &token.Token{
									ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
									Value: []byte("::"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  63,
										EndPos:    65,
									},
								},
								Method: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  65,
										EndPos:    68,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("one"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  65,
											EndPos:    68,
										},
									},
									Value: []byte("one"),
								},
								AsTkn: &token.Token{
									ID:    token.T_AS,
									Value: []byte("as"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  69,
										EndPos:    71,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  68,
												EndPos:    69,
											},
										},
									},
								},
								Alias: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  72,
										EndPos:    75,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("two"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  72,
											EndPos:    75,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  71,
													EndPos:    72,
												},
											},
										},
									},
									Value: []byte("two"),
								},
								SemiColonTkn: &token.Token{
									ID:    token.ID(59),
									Value: []byte(";"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  75,
										EndPos:    76,
									},
								},
							},
						},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  77,
								EndPos:    78,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  76,
										EndPos:    77,
									},
								},
							},
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  79,
						EndPos:    80,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  78,
								EndPos:    79,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTry_Try(t *testing.T) {
	src := `<?
		try {}
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   -1,
			StartPos:  5,
			EndPos:    -1,
		},
		Stmts: []ast.Vertex{
			&ast.StmtTry{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   -1,
					StartPos:  5,
					EndPos:    -1,
				},
				TryTkn: &token.Token{
					ID:    token.T_TRY,
					Value: []byte("try"),
					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: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  10,
						EndPos:    11,
					},
				},
				Catches: []ast.Vertex{},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   3,
						StartPos:  11,
						EndPos:    13,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTry_TryCatch(t *testing.T) {
	src := `<?
		try {} catch (Exception $e) {}
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   2,
			StartPos:  5,
			EndPos:    35,
		},
		Stmts: []ast.Vertex{
			&ast.StmtTry{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   2,
					StartPos:  5,
					EndPos:    35,
				},
				TryTkn: &token.Token{
					ID:    token.T_TRY,
					Value: []byte("try"),
					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: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  10,
						EndPos:    11,
					},
				},
				Catches: []ast.Vertex{
					&ast.StmtCatch{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  12,
							EndPos:    35,
						},
						CatchTkn: &token.Token{
							ID:    token.T_CATCH,
							Value: []byte("catch"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    17,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  11,
										EndPos:    12,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  18,
								EndPos:    19,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Types: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  19,
									EndPos:    28,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  19,
											EndPos:    28,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Exception"),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  19,
												EndPos:    28,
											},
										},
										Value: []byte("Exception"),
									},
								},
							},
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  29,
								EndPos:    31,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  29,
									EndPos:    31,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$e"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  29,
										EndPos:    31,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  28,
												EndPos:    29,
											},
										},
									},
								},
								Value: []byte("$e"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  31,
								EndPos:    32,
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  33,
								EndPos:    34,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  32,
										EndPos:    33,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  34,
								EndPos:    35,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   3,
						StartPos:  35,
						EndPos:    37,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTry_Php7TryCatch(t *testing.T) {
	src := `<?
		try {} catch (Exception|RuntimeException $e) {}
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   2,
			StartPos:  5,
			EndPos:    52,
		},
		Stmts: []ast.Vertex{
			&ast.StmtTry{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   2,
					StartPos:  5,
					EndPos:    52,
				},
				TryTkn: &token.Token{
					ID:    token.T_TRY,
					Value: []byte("try"),
					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: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  10,
						EndPos:    11,
					},
				},
				Catches: []ast.Vertex{
					&ast.StmtCatch{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  12,
							EndPos:    52,
						},
						CatchTkn: &token.Token{
							ID:    token.T_CATCH,
							Value: []byte("catch"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    17,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  11,
										EndPos:    12,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  18,
								EndPos:    19,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Types: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  19,
									EndPos:    28,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  19,
											EndPos:    28,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Exception"),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  19,
												EndPos:    28,
											},
										},
										Value: []byte("Exception"),
									},
								},
							},
							&ast.Name{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  29,
									EndPos:    45,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  29,
											EndPos:    45,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("RuntimeException"),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  29,
												EndPos:    45,
											},
										},
										Value: []byte("RuntimeException"),
									},
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(124),
								Value: []byte("|"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  28,
									EndPos:    29,
								},
							},
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  46,
								EndPos:    48,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  46,
									EndPos:    48,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$e"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  46,
										EndPos:    48,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  45,
												EndPos:    46,
											},
										},
									},
								},
								Value: []byte("$e"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  48,
								EndPos:    49,
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  50,
								EndPos:    51,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  49,
										EndPos:    50,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  51,
								EndPos:    52,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   3,
						StartPos:  52,
						EndPos:    54,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTry_TryCatchCatch(t *testing.T) {
	src := `<?
		try {} catch (Exception $e) {} catch (RuntimeException $e) {}
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   2,
			StartPos:  5,
			EndPos:    66,
		},
		Stmts: []ast.Vertex{
			&ast.StmtTry{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   2,
					StartPos:  5,
					EndPos:    66,
				},
				TryTkn: &token.Token{
					ID:    token.T_TRY,
					Value: []byte("try"),
					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: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  10,
						EndPos:    11,
					},
				},
				Catches: []ast.Vertex{
					&ast.StmtCatch{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  12,
							EndPos:    35,
						},
						CatchTkn: &token.Token{
							ID:    token.T_CATCH,
							Value: []byte("catch"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    17,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  11,
										EndPos:    12,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  18,
								EndPos:    19,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Types: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  19,
									EndPos:    28,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  19,
											EndPos:    28,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Exception"),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  19,
												EndPos:    28,
											},
										},
										Value: []byte("Exception"),
									},
								},
							},
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  29,
								EndPos:    31,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  29,
									EndPos:    31,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$e"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  29,
										EndPos:    31,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  28,
												EndPos:    29,
											},
										},
									},
								},
								Value: []byte("$e"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  31,
								EndPos:    32,
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  33,
								EndPos:    34,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  32,
										EndPos:    33,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  34,
								EndPos:    35,
							},
						},
					},
					&ast.StmtCatch{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  36,
							EndPos:    66,
						},
						CatchTkn: &token.Token{
							ID:    token.T_CATCH,
							Value: []byte("catch"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  36,
								EndPos:    41,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  35,
										EndPos:    36,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  42,
								EndPos:    43,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  41,
										EndPos:    42,
									},
								},
							},
						},
						Types: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  43,
									EndPos:    59,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  43,
											EndPos:    59,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("RuntimeException"),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  43,
												EndPos:    59,
											},
										},
										Value: []byte("RuntimeException"),
									},
								},
							},
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  60,
								EndPos:    62,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  60,
									EndPos:    62,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$e"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  60,
										EndPos:    62,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  59,
												EndPos:    60,
											},
										},
									},
								},
								Value: []byte("$e"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  62,
								EndPos:    63,
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  64,
								EndPos:    65,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  63,
										EndPos:    64,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  65,
								EndPos:    66,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   3,
						StartPos:  66,
						EndPos:    68,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTry_TryCatchFinally(t *testing.T) {
	src := `<?
		try {} catch (Exception $e) {} finally {}
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   2,
			StartPos:  5,
			EndPos:    46,
		},
		Stmts: []ast.Vertex{
			&ast.StmtTry{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   2,
					StartPos:  5,
					EndPos:    46,
				},
				TryTkn: &token.Token{
					ID:    token.T_TRY,
					Value: []byte("try"),
					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: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte("\n\t\t"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   2,
								StartPos:  2,
								EndPos:    5,
							},
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  10,
						EndPos:    11,
					},
				},
				Catches: []ast.Vertex{
					&ast.StmtCatch{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  12,
							EndPos:    35,
						},
						CatchTkn: &token.Token{
							ID:    token.T_CATCH,
							Value: []byte("catch"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    17,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  11,
										EndPos:    12,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  18,
								EndPos:    19,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Types: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  19,
									EndPos:    28,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  19,
											EndPos:    28,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Exception"),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  19,
												EndPos:    28,
											},
										},
										Value: []byte("Exception"),
									},
								},
							},
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  29,
								EndPos:    31,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  29,
									EndPos:    31,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$e"),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  29,
										EndPos:    31,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 2,
												EndLine:   2,
												StartPos:  28,
												EndPos:    29,
											},
										},
									},
								},
								Value: []byte("$e"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  31,
								EndPos:    32,
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  33,
								EndPos:    34,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 2,
										EndLine:   2,
										StartPos:  32,
										EndPos:    33,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  34,
								EndPos:    35,
							},
						},
					},
				},
				Finally: &ast.StmtFinally{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  36,
						EndPos:    46,
					},
					FinallyTkn: &token.Token{
						ID:    token.T_FINALLY,
						Value: []byte("finally"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  36,
							EndPos:    43,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  35,
									EndPos:    36,
								},
							},
						},
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  44,
							EndPos:    45,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  43,
									EndPos:    44,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  45,
							EndPos:    46,
						},
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   3,
						StartPos:  46,
						EndPos:    48,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtTry_TryCatchCatchCatch(t *testing.T) {
	src := `<? try {} catch (Exception $e) {} catch (\RuntimeException $e) {} catch (namespace\AdditionException $e) {}`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    107,
		},
		Stmts: []ast.Vertex{
			&ast.StmtTry{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    107,
				},
				TryTkn: &token.Token{
					ID:    token.T_TRY,
					Value: []byte("try"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    8,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  6,
								EndPos:    7,
							},
						},
					},
				},
				Stmts: []ast.Vertex{},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  8,
						EndPos:    9,
					},
				},
				Catches: []ast.Vertex{
					&ast.StmtCatch{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    33,
						},
						CatchTkn: &token.Token{
							ID:    token.T_CATCH,
							Value: []byte("catch"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    15,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    10,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  15,
										EndPos:    16,
									},
								},
							},
						},
						Types: []ast.Vertex{
							&ast.Name{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    26,
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  17,
											EndPos:    26,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("Exception"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  17,
												EndPos:    26,
											},
										},
										Value: []byte("Exception"),
									},
								},
							},
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  27,
								EndPos:    29,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  27,
									EndPos:    29,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$e"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  27,
										EndPos:    29,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  26,
												EndPos:    27,
											},
										},
									},
								},
								Value: []byte("$e"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  29,
								EndPos:    30,
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  31,
								EndPos:    32,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  30,
										EndPos:    31,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  32,
								EndPos:    33,
							},
						},
					},
					&ast.StmtCatch{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  34,
							EndPos:    65,
						},
						CatchTkn: &token.Token{
							ID:    token.T_CATCH,
							Value: []byte("catch"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  34,
								EndPos:    39,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  33,
										EndPos:    34,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  40,
								EndPos:    41,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  39,
										EndPos:    40,
									},
								},
							},
						},
						Types: []ast.Vertex{
							&ast.NameFullyQualified{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  41,
									EndPos:    58,
								},
								NsSeparatorTkn: &token.Token{
									ID:    token.T_NS_SEPARATOR,
									Value: []byte("\\"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  41,
										EndPos:    42,
									},
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  42,
											EndPos:    58,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("RuntimeException"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  42,
												EndPos:    58,
											},
										},
										Value: []byte("RuntimeException"),
									},
								},
							},
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  59,
								EndPos:    61,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  59,
									EndPos:    61,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$e"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  59,
										EndPos:    61,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  58,
												EndPos:    59,
											},
										},
									},
								},
								Value: []byte("$e"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  61,
								EndPos:    62,
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  63,
								EndPos:    64,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  62,
										EndPos:    63,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  64,
								EndPos:    65,
							},
						},
					},
					&ast.StmtCatch{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  66,
							EndPos:    107,
						},
						CatchTkn: &token.Token{
							ID:    token.T_CATCH,
							Value: []byte("catch"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  66,
								EndPos:    71,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  65,
										EndPos:    66,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  72,
								EndPos:    73,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  71,
										EndPos:    72,
									},
								},
							},
						},
						Types: []ast.Vertex{
							&ast.NameRelative{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  73,
									EndPos:    100,
								},
								NsTkn: &token.Token{
									ID:    token.T_NAMESPACE,
									Value: []byte("namespace"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  73,
										EndPos:    82,
									},
								},
								NsSeparatorTkn: &token.Token{
									ID:    token.T_NS_SEPARATOR,
									Value: []byte("\\"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  82,
										EndPos:    83,
									},
								},
								Parts: []ast.Vertex{
									&ast.NamePart{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  83,
											EndPos:    100,
										},
										StringTkn: &token.Token{
											ID:    token.T_STRING,
											Value: []byte("AdditionException"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  83,
												EndPos:    100,
											},
										},
										Value: []byte("AdditionException"),
									},
								},
							},
						},
						Var: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  101,
								EndPos:    103,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  101,
									EndPos:    103,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$e"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  101,
										EndPos:    103,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  100,
												EndPos:    101,
											},
										},
									},
								},
								Value: []byte("$e"),
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  103,
								EndPos:    104,
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  105,
								EndPos:    106,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  104,
										EndPos:    105,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  106,
								EndPos:    107,
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUnset(t *testing.T) {
	src := `<? unset($a);`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    13,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUnset{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    13,
				},
				UnsetTkn: &token.Token{
					ID:    token.T_UNSET,
					Value: []byte("unset"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  8,
						EndPos:    9,
					},
				},
				Vars: []ast.Vertex{
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    11,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUnset_Vars(t *testing.T) {
	src := `<? unset($a, $b);`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    17,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUnset{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    17,
				},
				UnsetTkn: &token.Token{
					ID:    token.T_UNSET,
					Value: []byte("unset"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  8,
						EndPos:    9,
					},
				},
				Vars: []ast.Vertex{
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    11,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
							},
							Value: []byte("$a"),
						},
					},
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    15,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    15,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    15,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    13,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  15,
						EndPos:    16,
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUnset_TrailingComma(t *testing.T) {
	src := `<? unset($a, $b,);`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    18,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUnset{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    18,
				},
				UnsetTkn: &token.Token{
					ID:    token.T_UNSET,
					Value: []byte("unset"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  8,
						EndPos:    9,
					},
				},
				Vars: []ast.Vertex{
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    11,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
							},
							Value: []byte("$a"),
						},
					},
					&ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    15,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    15,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    15,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    13,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
					},
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    16,
						},
					},
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  16,
						EndPos:    17,
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse(t *testing.T) {
	src := `<? use Foo;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    11,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    11,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    10,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    10,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  7,
										EndPos:    10,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  7,
											EndPos:    10,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  6,
													EndPos:    7,
												},
											},
										},
									},
									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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_FullyQualified(t *testing.T) {
	src := `<? use \Foo;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    11,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  6,
										EndPos:    7,
									},
								},
							},
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    11,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    11,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    11,
										},
									},
									Value: []byte("Foo"),
								},
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_FullyQualifiedAlias(t *testing.T) {
	src := `<? use \Foo as Bar;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    19,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    19,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    18,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  6,
										EndPos:    7,
									},
								},
							},
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    11,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    11,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    11,
										},
									},
									Value: []byte("Foo"),
								},
							},
						},
						AsTkn: &token.Token{
							ID:    token.T_AS,
							Value: []byte("as"),
							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,
									},
								},
							},
						},
						Alias: &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,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  14,
											EndPos:    15,
										},
									},
								},
							},
							Value: []byte("Bar"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_List(t *testing.T) {
	src := `<? use Foo, Bar;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    16,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    16,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    10,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    10,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  7,
										EndPos:    10,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  7,
											EndPos:    10,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  6,
													EndPos:    7,
												},
											},
										},
									},
									Value: []byte("Foo"),
								},
							},
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    15,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    15,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    15,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    15,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  11,
													EndPos:    12,
												},
											},
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_ListAlias(t *testing.T) {
	src := `<? use Foo, Bar as Baz;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    23,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    23,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    10,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    10,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  7,
										EndPos:    10,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  7,
											EndPos:    10,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  6,
													EndPos:    7,
												},
											},
										},
									},
									Value: []byte("Foo"),
								},
							},
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    22,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    15,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    15,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    15,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  11,
													EndPos:    12,
												},
											},
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
						AsTkn: &token.Token{
							ID:    token.T_AS,
							Value: []byte("as"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    18,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  15,
										EndPos:    16,
									},
								},
							},
						},
						Alias: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  19,
								EndPos:    22,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("Baz"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    22,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  18,
											EndPos:    19,
										},
									},
								},
							},
							Value: []byte("Baz"),
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_ListFunctionType(t *testing.T) {
	src := `<? use function Foo, \Bar;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    26,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    26,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Type: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    15,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_FUNCTION,
						Value: []byte("function"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  6,
									EndPos:    7,
								},
							},
						},
					},
					Value: []byte("function"),
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    19,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    19,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  16,
										EndPos:    19,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  16,
											EndPos:    19,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  15,
													EndPos:    16,
												},
											},
										},
									},
									Value: []byte("Foo"),
								},
							},
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  21,
							EndPos:    25,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  21,
								EndPos:    22,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  20,
										EndPos:    21,
									},
								},
							},
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  22,
								EndPos:    25,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  22,
										EndPos:    25,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  22,
											EndPos:    25,
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						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:  25,
						EndPos:    26,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_ListFunctionTypeAliases(t *testing.T) {
	src := `<? use function Foo as foo, \Bar as bar;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    40,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    40,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Type: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    15,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_FUNCTION,
						Value: []byte("function"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  6,
									EndPos:    7,
								},
							},
						},
					},
					Value: []byte("function"),
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    26,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    19,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  16,
										EndPos:    19,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  16,
											EndPos:    19,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  15,
													EndPos:    16,
												},
											},
										},
									},
									Value: []byte("Foo"),
								},
							},
						},
						AsTkn: &token.Token{
							ID:    token.T_AS,
							Value: []byte("as"),
							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,
									},
								},
							},
						},
						Alias: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  23,
								EndPos:    26,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  23,
									EndPos:    26,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  22,
											EndPos:    23,
										},
									},
								},
							},
							Value: []byte("foo"),
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  28,
							EndPos:    39,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							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,
									},
								},
							},
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  29,
								EndPos:    32,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  29,
										EndPos:    32,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  29,
											EndPos:    32,
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
						AsTkn: &token.Token{
							ID:    token.T_AS,
							Value: []byte("as"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  33,
								EndPos:    35,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  32,
										EndPos:    33,
									},
								},
							},
						},
						Alias: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  36,
								EndPos:    39,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  36,
									EndPos:    39,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  35,
											EndPos:    36,
										},
									},
								},
							},
							Value: []byte("bar"),
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  26,
							EndPos:    27,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  39,
						EndPos:    40,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_ListConstType(t *testing.T) {
	src := `<? use const Foo, \Bar;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    23,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    23,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Type: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_CONST,
						Value: []byte("const"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  6,
									EndPos:    7,
								},
							},
						},
					},
					Value: []byte("const"),
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    16,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    16,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    16,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  13,
											EndPos:    16,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  12,
													EndPos:    13,
												},
											},
										},
									},
									Value: []byte("Foo"),
								},
							},
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    22,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    19,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    18,
									},
								},
							},
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  19,
								EndPos:    22,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  19,
										EndPos:    22,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  19,
											EndPos:    22,
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    17,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_ListConstTypeAliases(t *testing.T) {
	src := `<? use const Foo as foo, \Bar as bar;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    37,
		},
		Stmts: []ast.Vertex{
			&ast.StmtUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    37,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Type: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_CONST,
						Value: []byte("const"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  6,
									EndPos:    7,
								},
							},
						},
					},
					Value: []byte("const"),
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    23,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    16,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    16,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  13,
											EndPos:    16,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  12,
													EndPos:    13,
												},
											},
										},
									},
									Value: []byte("Foo"),
								},
							},
						},
						AsTkn: &token.Token{
							ID:    token.T_AS,
							Value: []byte("as"),
							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,
									},
								},
							},
						},
						Alias: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  20,
								EndPos:    23,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  20,
									EndPos:    23,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  19,
											EndPos:    20,
										},
									},
								},
							},
							Value: []byte("foo"),
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  25,
							EndPos:    36,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  25,
								EndPos:    26,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  24,
										EndPos:    25,
									},
								},
							},
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  26,
								EndPos:    29,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  26,
										EndPos:    29,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  26,
											EndPos:    29,
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
						AsTkn: &token.Token{
							ID:    token.T_AS,
							Value: []byte("as"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  30,
								EndPos:    32,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  29,
										EndPos:    30,
									},
								},
							},
						},
						Alias: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  33,
								EndPos:    36,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  33,
									EndPos:    36,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  32,
											EndPos:    33,
										},
									},
								},
							},
							Value: []byte("bar"),
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  23,
							EndPos:    24,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  36,
						EndPos:    37,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_GroupUse(t *testing.T) {
	src := `<? use Foo\{Bar, Baz};`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    22,
		},
		Stmts: []ast.Vertex{
			&ast.StmtGroupUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    22,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Prefix: &ast.Name{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    10,
					},
					Parts: []ast.Vertex{
						&ast.NamePart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    10,
							},
							StringTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("Foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  7,
									EndPos:    10,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  6,
											EndPos:    7,
										},
									},
								},
							},
							Value: []byte("Foo"),
						},
					},
				},
				NsSeparatorTkn: &token.Token{
					ID:    token.T_NS_SEPARATOR,
					Value: []byte("\\"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    15,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    15,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    15,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    15,
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  17,
							EndPos:    20,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  17,
								EndPos:    20,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    20,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Baz"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  17,
											EndPos:    20,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  16,
													EndPos:    17,
												},
											},
										},
									},
									Value: []byte("Baz"),
								},
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    16,
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_GroupUseAlias(t *testing.T) {
	src := `<? use Foo\{Bar, Baz as quux};`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    30,
		},
		Stmts: []ast.Vertex{
			&ast.StmtGroupUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    30,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Prefix: &ast.Name{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    10,
					},
					Parts: []ast.Vertex{
						&ast.NamePart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    10,
							},
							StringTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("Foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  7,
									EndPos:    10,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  6,
											EndPos:    7,
										},
									},
								},
							},
							Value: []byte("Foo"),
						},
					},
				},
				NsSeparatorTkn: &token.Token{
					ID:    token.T_NS_SEPARATOR,
					Value: []byte("\\"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    15,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    15,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    15,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    15,
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  17,
							EndPos:    28,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  17,
								EndPos:    20,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    20,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Baz"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  17,
											EndPos:    20,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  16,
													EndPos:    17,
												},
											},
										},
									},
									Value: []byte("Baz"),
								},
							},
						},
						AsTkn: &token.Token{
							ID:    token.T_AS,
							Value: []byte("as"),
							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,
									},
								},
							},
						},
						Alias: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  24,
								EndPos:    28,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("quux"),
								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,
										},
									},
								},
							},
							Value: []byte("quux"),
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    16,
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  28,
						EndPos:    29,
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_FunctionGroupUse(t *testing.T) {
	src := `<? use function Foo\{Bar, Baz};`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    31,
		},
		Stmts: []ast.Vertex{
			&ast.StmtGroupUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    31,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Type: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    15,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_FUNCTION,
						Value: []byte("function"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  6,
									EndPos:    7,
								},
							},
						},
					},
					Value: []byte("function"),
				},
				Prefix: &ast.Name{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  16,
						EndPos:    19,
					},
					Parts: []ast.Vertex{
						&ast.NamePart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    19,
							},
							StringTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("Foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  16,
									EndPos:    19,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  15,
											EndPos:    16,
										},
									},
								},
							},
							Value: []byte("Foo"),
						},
					},
				},
				NsSeparatorTkn: &token.Token{
					ID:    token.T_NS_SEPARATOR,
					Value: []byte("\\"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  19,
						EndPos:    20,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  20,
						EndPos:    21,
					},
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  21,
							EndPos:    24,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  21,
								EndPos:    24,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  21,
										EndPos:    24,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  21,
											EndPos:    24,
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  26,
							EndPos:    29,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  26,
								EndPos:    29,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  26,
										EndPos:    29,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Baz"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  26,
											EndPos:    29,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  25,
													EndPos:    26,
												},
											},
										},
									},
									Value: []byte("Baz"),
								},
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  24,
							EndPos:    25,
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  29,
						EndPos:    30,
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_ConstGroupUse(t *testing.T) {
	src := `<? use const Foo\{Bar, Baz};`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    28,
		},
		Stmts: []ast.Vertex{
			&ast.StmtGroupUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    28,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Type: &ast.Identifier{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    12,
					},
					IdentifierTkn: &token.Token{
						ID:    token.T_CONST,
						Value: []byte("const"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  6,
									EndPos:    7,
								},
							},
						},
					},
					Value: []byte("const"),
				},
				Prefix: &ast.Name{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    16,
					},
					Parts: []ast.Vertex{
						&ast.NamePart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    16,
							},
							StringTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("Foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    16,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    13,
										},
									},
								},
							},
							Value: []byte("Foo"),
						},
					},
				},
				NsSeparatorTkn: &token.Token{
					ID:    token.T_NS_SEPARATOR,
					Value: []byte("\\"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  16,
						EndPos:    17,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  17,
						EndPos:    18,
					},
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    21,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    21,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  18,
										EndPos:    21,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  18,
											EndPos:    21,
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  23,
							EndPos:    26,
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  23,
								EndPos:    26,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  23,
										EndPos:    26,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Baz"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  23,
											EndPos:    26,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  22,
													EndPos:    23,
												},
											},
										},
									},
									Value: []byte("Baz"),
								},
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  21,
							EndPos:    22,
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  26,
						EndPos:    27,
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  27,
						EndPos:    28,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtUse_MixedGroupUse(t *testing.T) {
	src := `<? use Foo\{const Bar, function Baz};`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    37,
		},
		Stmts: []ast.Vertex{
			&ast.StmtGroupUseList{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    37,
				},
				UseTkn: &token.Token{
					ID:    token.T_USE,
					Value: []byte("use"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_OPEN_TAG,
							Value: []byte("<?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				Prefix: &ast.Name{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    10,
					},
					Parts: []ast.Vertex{
						&ast.NamePart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    10,
							},
							StringTkn: &token.Token{
								ID:    token.T_STRING,
								Value: []byte("Foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  7,
									EndPos:    10,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  6,
											EndPos:    7,
										},
									},
								},
							},
							Value: []byte("Foo"),
						},
					},
				},
				NsSeparatorTkn: &token.Token{
					ID:    token.T_NS_SEPARATOR,
					Value: []byte("\\"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
				},
				OpenCurlyBracketTkn: &token.Token{
					ID:    token.ID(123),
					Value: []byte("{"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
				Uses: []ast.Vertex{
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    21,
						},
						Type: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    17,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_CONST,
								Value: []byte("const"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    17,
								},
							},
							Value: []byte("const"),
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    21,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  18,
										EndPos:    21,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Bar"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  18,
											EndPos:    21,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  17,
													EndPos:    18,
												},
											},
										},
									},
									Value: []byte("Bar"),
								},
							},
						},
					},
					&ast.StmtUse{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  23,
							EndPos:    35,
						},
						Type: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  23,
								EndPos:    31,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_FUNCTION,
								Value: []byte("function"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  23,
									EndPos:    31,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  22,
											EndPos:    23,
										},
									},
								},
							},
							Value: []byte("function"),
						},
						Use: &ast.Name{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  32,
								EndPos:    35,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  32,
										EndPos:    35,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Baz"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  32,
											EndPos:    35,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  31,
													EndPos:    32,
												},
											},
										},
									},
									Value: []byte("Baz"),
								},
							},
						},
					},
				},
				SeparatorTkns: []*token.Token{
					{
						ID:    token.ID(44),
						Value: []byte(","),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  21,
							EndPos:    22,
						},
					},
				},
				CloseCurlyBracketTkn: &token.Token{
					ID:    token.ID(125),
					Value: []byte("}"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  35,
						EndPos:    36,
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  36,
						EndPos:    37,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtBreak_Empty(t *testing.T) {
	src := `<? while (1) { break; }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    23,
		},
		Stmts: []ast.Vertex{
			&ast.StmtWhile{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    23,
				},
				WhileTkn: &token.Token{
					ID:    token.T_WHILE,
					Value: []byte("while"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Cond: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    23,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    13,
								},
							},
						},
					},
					Stmts: []ast.Vertex{
						&ast.StmtBreak{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    21,
							},
							BreakTkn: &token.Token{
								ID:    token.T_BREAK,
								Value: []byte("break"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  15,
									EndPos:    20,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										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:  20,
									EndPos:    21,
								},
							},
						},
					},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  22,
							EndPos:    23,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtBreak_Light(t *testing.T) {
	src := `<? while (1) { break 2; }`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    25,
		},
		Stmts: []ast.Vertex{
			&ast.StmtWhile{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    25,
				},
				WhileTkn: &token.Token{
					ID:    token.T_WHILE,
					Value: []byte("while"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Cond: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    25,
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    13,
								},
							},
						},
					},
					Stmts: []ast.Vertex{
						&ast.StmtBreak{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    23,
							},
							BreakTkn: &token.Token{
								ID:    token.T_BREAK,
								Value: []byte("break"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  15,
									EndPos:    20,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  14,
											EndPos:    15,
										},
									},
								},
							},
							Expr: &ast.ScalarLnumber{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  21,
									EndPos:    22,
								},
								NumberTkn: &token.Token{
									ID:    token.T_LNUMBER,
									Value: []byte("2"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  21,
										EndPos:    22,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  20,
												EndPos:    21,
											},
										},
									},
								},
								Value: []byte("2"),
							},
							SemiColonTkn: &token.Token{
								ID:    token.ID(59),
								Value: []byte(";"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  22,
									EndPos:    23,
								},
							},
						},
					},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						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,
								},
							},
						},
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStmtBreak(t *testing.T) {
	src := `<? while (1) : break(3); endwhile;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    34,
		},
		Stmts: []ast.Vertex{
			&ast.StmtWhile{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    34,
				},
				WhileTkn: &token.Token{
					ID:    token.T_WHILE,
					Value: []byte("while"),
					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:  0,
								EndPos:    2,
							},
						},
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  2,
								EndPos:    3,
							},
						},
					},
				},
				OpenParenthesisTkn: &token.Token{
					ID:    token.ID(40),
					Value: []byte("("),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
				},
				Cond: &ast.ScalarLnumber{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  10,
						EndPos:    11,
					},
					NumberTkn: &token.Token{
						ID:    token.T_LNUMBER,
						Value: []byte("1"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
					Value: []byte("1"),
				},
				CloseParenthesisTkn: &token.Token{
					ID:    token.ID(41),
					Value: []byte(")"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
				ColonTkn: &token.Token{
					ID:    token.ID(58),
					Value: []byte(":"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  13,
						EndPos:    14,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
				},
				Stmt: &ast.StmtStmtList{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  15,
						EndPos:    24,
					},
					Stmts: []ast.Vertex{
						&ast.StmtBreak{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  15,
								EndPos:    24,
							},
							BreakTkn: &token.Token{
								ID:    token.T_BREAK,
								Value: []byte("break"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  15,
									EndPos:    20,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  14,
											EndPos:    15,
										},
									},
								},
							},
							Expr: &ast.ExprBrackets{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  20,
									EndPos:    23,
								},
								OpenParenthesisTkn: &token.Token{
									ID:    token.ID(40),
									Value: []byte("("),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  20,
										EndPos:    21,
									},
								},
								Expr: &ast.ScalarLnumber{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  21,
										EndPos:    22,
									},
									NumberTkn: &token.Token{
										ID:    token.T_LNUMBER,
										Value: []byte("3"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  21,
											EndPos:    22,
										},
									},
									Value: []byte("3"),
								},
								CloseParenthesisTkn: &token.Token{
									ID:    token.ID(41),
									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,
								},
							},
						},
					},
				},
				EndWhileTkn: &token.Token{
					ID:    token.T_ENDWHILE,
					Value: []byte("endwhile"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  25,
						EndPos:    33,
					},
					FreeFloating: []*token.Token{
						{
							ID:    token.T_WHITESPACE,
							Value: []byte(" "),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  24,
								EndPos:    25,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  33,
						EndPos:    34,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

// expr

func TestExprArrayDimFetch(t *testing.T) {
	src := `<? $a[1];`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    9,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    9,
				},
				Expr: &ast.ExprArrayDimFetch{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    8,
					},
					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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpenBracketTkn: &token.Token{
						ID:    token.ID(91),
						Value: []byte("["),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  5,
							EndPos:    6,
						},
					},
					Dim: &ast.ScalarLnumber{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
						NumberTkn: &token.Token{
							ID:    token.T_LNUMBER,
							Value: []byte("1"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  6,
								EndPos:    7,
							},
						},
						Value: []byte("1"),
					},
					CloseBracketTkn: &token.Token{
						ID:    token.ID(93),
						Value: []byte("]"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  8,
						EndPos:    9,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprArrayDimFetch_Nested(t *testing.T) {
	src := `<? $a[1][2];`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				Expr: &ast.ExprArrayDimFetch{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					Var: &ast.ExprArrayDimFetch{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    8,
						},
						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:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  2,
												EndPos:    3,
											},
										},
									},
								},
								Value: []byte("$a"),
							},
						},
						OpenBracketTkn: &token.Token{
							ID:    token.ID(91),
							Value: []byte("["),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  5,
								EndPos:    6,
							},
						},
						Dim: &ast.ScalarLnumber{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  6,
								EndPos:    7,
							},
							NumberTkn: &token.Token{
								ID:    token.T_LNUMBER,
								Value: []byte("1"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  6,
									EndPos:    7,
								},
							},
							Value: []byte("1"),
						},
						CloseBracketTkn: &token.Token{
							ID:    token.ID(93),
							Value: []byte("]"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
						},
					},
					OpenBracketTkn: &token.Token{
						ID:    token.ID(91),
						Value: []byte("["),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
					},
					Dim: &ast.ScalarLnumber{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    10,
						},
						NumberTkn: &token.Token{
							ID:    token.T_LNUMBER,
							Value: []byte("2"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    10,
							},
						},
						Value: []byte("2"),
					},
					CloseBracketTkn: &token.Token{
						ID:    token.ID(93),
						Value: []byte("]"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprArray(t *testing.T) {
	src := `<? array();`

	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.ExprArray{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    10,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenBracketTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
					},
					CloseBracketTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    10,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprArray_Item(t *testing.T) {
	src := `<? array(1);`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				Expr: &ast.ExprArray{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenBracketTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
					},
					Items: []ast.Vertex{
						&ast.ExprArrayItem{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    10,
							},
							Val: &ast.ScalarLnumber{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    10,
								},
								NumberTkn: &token.Token{
									ID:    token.T_LNUMBER,
									Value: []byte("1"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    10,
									},
								},
								Value: []byte("1"),
							},
						},
					},
					CloseBracketTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprArray_Items(t *testing.T) {
	src := `<? array(1=>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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenBracketTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
					},
					Items: []ast.Vertex{
						&ast.ExprArrayItem{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    13,
							},
							Key: &ast.ScalarLnumber{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    10,
								},
								NumberTkn: &token.Token{
									ID:    token.T_LNUMBER,
									Value: []byte("1"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    10,
									},
								},
								Value: []byte("1"),
							},
							DoubleArrowTkn: &token.Token{
								ID:    token.T_DOUBLE_ARROW,
								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.ID(38),
								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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprArray_ItemUnpack(t *testing.T) {
	src := `<? array(...$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,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenBracketTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
					},
					Items: []ast.Vertex{
						&ast.ExprArrayItem{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    14,
							},
							EllipsisTkn: &token.Token{
								ID:    token.T_ELLIPSIS,
								Value: []byte("..."),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    12,
								},
							},
							Val: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    14,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    14,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$b"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    14,
										},
									},
									Value: []byte("$b"),
								},
							},
						},
					},
					CloseBracketTkn: &token.Token{
						ID:    token.ID(41),
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprArrowFunction(t *testing.T) {
	src := `<? fn() => $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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  5,
							EndPos:    6,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
					},
					DoubleArrowTkn: &token.Token{
						ID:    token.T_DOUBLE_ARROW,
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprArrowFunction_ReturnType(t *testing.T) {
	src := `<? fn & () : foo => $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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					AmpersandTkn: &token.Token{
						ID:    token.ID(38),
						Value: []byte("&"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    6,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  7,
									EndPos:    8,
								},
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    10,
						},
					},
					ColonTkn: &token.Token{
						ID:    token.ID(58),
						Value: []byte(":"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    11,
								},
							},
						},
					},
					ReturnType: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    16,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    16,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    16,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  12,
												EndPos:    13,
											},
										},
									},
								},
								Value: []byte("foo"),
							},
						},
					},
					DoubleArrowTkn: &token.Token{
						ID:    token.T_DOUBLE_ARROW,
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprBitwiseNot(t *testing.T) {
	src := `<? ~$a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    7,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    7,
				},
				Expr: &ast.ExprBitwiseNot{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					TildaTkn: &token.Token{
						ID:    token.ID(126),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  4,
							EndPos:    6,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    6,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    6,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprBooleanNot(t *testing.T) {
	src := `<? !$a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    7,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    7,
				},
				Expr: &ast.ExprBooleanNot{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					ExclamationTkn: &token.Token{
						ID:    token.ID(33),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  4,
							EndPos:    6,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    6,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    6,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprClassConstFetch(t *testing.T) {
	src := `<? Foo::Bar;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				Expr: &ast.ExprClassConstFetch{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					Class: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  3,
									EndPos:    6,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  3,
										EndPos:    6,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_OPEN_TAG,
											Value: []byte("<?"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  2,
												EndPos:    3,
											},
										},
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
					DoubleColonTkn: &token.Token{
						ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
						Value: []byte("::"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    8,
						},
					},
					Const: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    11,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_STRING,
							Value: []byte("Bar"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    11,
							},
						},
						Value: []byte("Bar"),
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprClassConstFetch_Static(t *testing.T) {
	src := `<? static::bar;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    15,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    15,
				},
				Expr: &ast.ExprClassConstFetch{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    14,
					},
					Class: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    9,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_STATIC,
							Value: []byte("static"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    9,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Value: []byte("static"),
					},
					DoubleColonTkn: &token.Token{
						ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
						Value: []byte("::"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    11,
						},
					},
					Const: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    14,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_STRING,
							Value: []byte("bar"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    14,
							},
						},
						Value: []byte("bar"),
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprClone_Brackets(t *testing.T) {
	src := `<? clone($a);`

	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.ExprClone{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					CloneTkn: &token.Token{
						ID:    token.T_CLONE,
						Value: []byte("clone"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &ast.ExprBrackets{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    12,
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
						Expr: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    11,
									},
								},
								Value: []byte("$a"),
							},
						},
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprClone(t *testing.T) {
	src := `<? clone $a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				Expr: &ast.ExprClone{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					CloneTkn: &token.Token{
						ID:    token.T_CLONE,
						Value: []byte("clone"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    11,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    9,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprClosure(t *testing.T) {
	src := `<? function(){};`

	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.ExprClosure{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    15,
					},
					FunctionTkn: &token.Token{
						ID:    token.T_FUNCTION,
						Value: []byte("function"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    11,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprClosure_Use(t *testing.T) {
	src := `<? function($a, $b) use ($c, &$d) {};`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    37,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    37,
				},
				Expr: &ast.ExprClosure{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    36,
					},
					FunctionTkn: &token.Token{
						ID:    token.T_FUNCTION,
						Value: []byte("function"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    11,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
					},
					Params: []ast.Vertex{
						&ast.Parameter{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    14,
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    14,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    14,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$a"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    14,
										},
									},
									Value: []byte("$a"),
								},
							},
						},
						&ast.Parameter{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    18,
							},
							Var: &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,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  15,
													EndPos:    16,
												},
											},
										},
									},
									Value: []byte("$b"),
								},
							},
						},
					},
					SeparatorTkns: []*token.Token{
						{
							ID:    token.ID(44),
							Value: []byte(","),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    15,
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    19,
						},
					},
					UseTkn: &token.Token{
						ID:    token.T_USE,
						Value: []byte("use"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  20,
							EndPos:    23,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    20,
								},
							},
						},
					},
					UseOpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						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,
								},
							},
						},
					},
					Uses: []ast.Vertex{
						&ast.ExprClosureUse{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  25,
								EndPos:    27,
							},
							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("$c"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  25,
											EndPos:    27,
										},
									},
									Value: []byte("$c"),
								},
							},
						},
						&ast.ExprClosureUse{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  29,
								EndPos:    32,
							},
							AmpersandTkn: &token.Token{
								ID:    token.ID(38),
								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,
										},
									},
								},
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  30,
									EndPos:    32,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  30,
										EndPos:    32,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$d"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  30,
											EndPos:    32,
										},
									},
									Value: []byte("$d"),
								},
							},
						},
					},
					UseSeparatorTkns: []*token.Token{
						{
							ID:    token.ID(44),
							Value: []byte(","),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  27,
								EndPos:    28,
							},
						},
					},
					UseCloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  32,
							EndPos:    33,
						},
					},
					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,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  36,
						EndPos:    37,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprClosure_Use2(t *testing.T) {
	src := `<? function($a, $b) use (&$c, $d) {};`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    37,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    37,
				},
				Expr: &ast.ExprClosure{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    36,
					},
					FunctionTkn: &token.Token{
						ID:    token.T_FUNCTION,
						Value: []byte("function"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    11,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
					},
					Params: []ast.Vertex{
						&ast.Parameter{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    14,
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    14,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    14,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$a"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    14,
										},
									},
									Value: []byte("$a"),
								},
							},
						},
						&ast.Parameter{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    18,
							},
							Var: &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,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  15,
													EndPos:    16,
												},
											},
										},
									},
									Value: []byte("$b"),
								},
							},
						},
					},
					SeparatorTkns: []*token.Token{
						{
							ID:    token.ID(44),
							Value: []byte(","),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    15,
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    19,
						},
					},
					UseTkn: &token.Token{
						ID:    token.T_USE,
						Value: []byte("use"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  20,
							EndPos:    23,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    20,
								},
							},
						},
					},
					UseOpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						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,
								},
							},
						},
					},
					Uses: []ast.Vertex{
						&ast.ExprClosureUse{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  25,
								EndPos:    28,
							},
							AmpersandTkn: &token.Token{
								ID:    token.ID(38),
								Value: []byte("&"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  25,
									EndPos:    26,
								},
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  26,
									EndPos:    28,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  26,
										EndPos:    28,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$c"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  26,
											EndPos:    28,
										},
									},
									Value: []byte("$c"),
								},
							},
						},
						&ast.ExprClosureUse{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  30,
								EndPos:    32,
							},
							Var: &ast.ExprVariable{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  30,
									EndPos:    32,
								},
								Name: &ast.Identifier{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  30,
										EndPos:    32,
									},
									IdentifierTkn: &token.Token{
										ID:    token.T_VARIABLE,
										Value: []byte("$d"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  30,
											EndPos:    32,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  29,
													EndPos:    30,
												},
											},
										},
									},
									Value: []byte("$d"),
								},
							},
						},
					},
					UseSeparatorTkns: []*token.Token{
						{
							ID:    token.ID(44),
							Value: []byte(","),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  28,
								EndPos:    29,
							},
						},
					},
					UseCloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  32,
							EndPos:    33,
						},
					},
					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,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  36,
						EndPos:    37,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprClosure_ReturnType(t *testing.T) {
	src := `<? function(): void {};`

	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.ExprClosure{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    22,
					},
					FunctionTkn: &token.Token{
						ID:    token.T_FUNCTION,
						Value: []byte("function"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    11,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
					ColonTkn: &token.Token{
						ID:    token.ID(58),
						Value: []byte(":"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
					},
					ReturnType: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    19,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  15,
									EndPos:    19,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("void"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  15,
										EndPos:    19,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  14,
												EndPos:    15,
											},
										},
									},
								},
								Value: []byte("void"),
							},
						},
					},
					OpenCurlyBracketTkn: &token.Token{
						ID:    token.ID(123),
						Value: []byte("{"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  20,
							EndPos:    21,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  19,
									EndPos:    20,
								},
							},
						},
					},
					Stmts: []ast.Vertex{},
					CloseCurlyBracketTkn: &token.Token{
						ID:    token.ID(125),
						Value: []byte("}"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  21,
							EndPos:    22,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprConstFetch(t *testing.T) {
	src := `<? foo;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    7,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    7,
				},
				Expr: &ast.ExprConstFetch{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					Const: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  3,
									EndPos:    6,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  3,
										EndPos:    6,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_OPEN_TAG,
											Value: []byte("<?"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  2,
												EndPos:    3,
											},
										},
									},
								},
								Value: []byte("foo"),
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprConstFetch_Relative(t *testing.T) {
	src := `<? namespace\foo;`

	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.ExprConstFetch{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    16,
					},
					Const: &ast.NameRelative{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    16,
						},
						NsTkn: &token.Token{
							ID:    token.T_NAMESPACE,
							Value: []byte("namespace"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    12,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    16,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    16,
									},
								},
								Value: []byte("foo"),
							},
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprConstFetch_FullyQualified(t *testing.T) {
	src := `<? \foo;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    8,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    8,
				},
				Expr: &ast.ExprConstFetch{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    7,
					},
					Const: &ast.NameFullyQualified{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    7,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  4,
										EndPos:    7,
									},
								},
								Value: []byte("foo"),
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    8,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprEmpty(t *testing.T) {
	src := `<? empty($a);`

	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.ExprEmpty{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					EmptyTkn: &token.Token{
						ID:    token.T_EMPTY,
						Value: []byte("empty"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    11,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
							},
							Value: []byte("$a"),
						},
					},
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprErrorSuppress(t *testing.T) {
	src := `<? @$a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    7,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    7,
				},
				Expr: &ast.ExprErrorSuppress{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					AtTkn: &token.Token{
						ID:    token.ID(64),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  4,
							EndPos:    6,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    6,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    6,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprEval(t *testing.T) {
	src := `<? eval($a);`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				Expr: &ast.ExprEval{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					EvalTkn: &token.Token{
						ID:    token.T_EVAL,
						Value: []byte("eval"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    10,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    10,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    10,
								},
							},
							Value: []byte("$a"),
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprExit(t *testing.T) {
	src := `<? exit;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    8,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    8,
				},
				Expr: &ast.ExprExit{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    7,
					},
					ExitTkn: &token.Token{
						ID:    token.T_EXIT,
						Value: []byte("exit"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    8,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprExit_Empty(t *testing.T) {
	src := `<? exit();`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    10,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    10,
				},
				Expr: &ast.ExprExit{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    9,
					},
					ExitTkn: &token.Token{
						ID:    token.T_EXIT,
						Value: []byte("exit"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  9,
						EndPos:    10,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprExit_Expr(t *testing.T) {
	src := `<? exit($a);`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				Expr: &ast.ExprExit{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					ExitTkn: &token.Token{
						ID:    token.T_EXIT,
						Value: []byte("exit"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    10,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    10,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    10,
								},
							},
							Value: []byte("$a"),
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprDie(t *testing.T) {
	src := `<? die;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    7,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    7,
				},
				Expr: &ast.ExprExit{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					ExitTkn: &token.Token{
						ID:    token.T_EXIT,
						Value: []byte("die"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprDie_Empty(t *testing.T) {
	src := `<? die();`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    9,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    9,
				},
				Expr: &ast.ExprExit{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    8,
					},
					ExitTkn: &token.Token{
						ID:    token.T_EXIT,
						Value: []byte("die"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  8,
						EndPos:    9,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprDie_Expr(t *testing.T) {
	src := `<? die($a);`

	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.ExprExit{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    10,
					},
					ExitTkn: &token.Token{
						ID:    token.T_EXIT,
						Value: []byte("die"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    9,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    9,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  7,
									EndPos:    9,
								},
							},
							Value: []byte("$a"),
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    10,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprFunctionCall(t *testing.T) {
	src := `<? foo();`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    9,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    9,
				},
				Expr: &ast.ExprFunctionCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    8,
					},
					Function: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  3,
									EndPos:    6,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  3,
										EndPos:    6,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_OPEN_TAG,
											Value: []byte("<?"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  2,
												EndPos:    3,
											},
										},
									},
								},
								Value: []byte("foo"),
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  8,
						EndPos:    9,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprFunctionCall_Relative(t *testing.T) {
	src := `<? namespace\foo();`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    19,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    19,
				},
				Expr: &ast.ExprFunctionCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    18,
					},
					Function: &ast.NameRelative{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    16,
						},
						NsTkn: &token.Token{
							ID:    token.T_NAMESPACE,
							Value: []byte("namespace"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    12,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    16,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    16,
									},
								},
								Value: []byte("foo"),
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    17,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  17,
							EndPos:    18,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprFunctionCall_FullyQualified(t *testing.T) {
	src := `<? \foo([]);`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				Expr: &ast.ExprFunctionCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					Function: &ast.NameFullyQualified{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    7,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  4,
										EndPos:    7,
									},
								},
								Value: []byte("foo"),
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
					Args: []ast.Vertex{
						&ast.Argument{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    10,
							},
							Expr: &ast.ExprArray{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    10,
								},
								OpenBracketTkn: &token.Token{
									ID:    token.ID(91),
									Value: []byte("["),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    9,
									},
								},
								CloseBracketTkn: &token.Token{
									ID:    token.ID(93),
									Value: []byte("]"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    10,
									},
								},
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprFunctionCall_Var(t *testing.T) {
	src := `<? $foo(yield $a);`

	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.ExprFunctionCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    17,
					},
					Function: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    7,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  3,
									EndPos:    7,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_OPEN_TAG,
										Value: []byte("<?"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$foo"),
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
					Args: []ast.Vertex{
						&ast.Argument{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    16,
							},
							Expr: &ast.ExprYield{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    16,
								},
								YieldTkn: &token.Token{
									ID:    token.T_YIELD,
									Value: []byte("yield"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    13,
									},
								},
								Val: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    16,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  14,
											EndPos:    16,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$a"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  14,
												EndPos:    16,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  13,
														EndPos:    14,
													},
												},
											},
										},
										Value: []byte("$a"),
									},
								},
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    17,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprFunctionCall_ExprArg(t *testing.T) {
	src := `<? ceil($foo/3);`

	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.ExprFunctionCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    15,
					},
					Function: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  3,
									EndPos:    7,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("ceil"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  3,
										EndPos:    7,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_OPEN_TAG,
											Value: []byte("<?"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  2,
												EndPos:    3,
											},
										},
									},
								},
								Value: []byte("ceil"),
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    8,
						},
					},
					Args: []ast.Vertex{
						&ast.Argument{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    14,
							},
							Expr: &ast.ExprBinaryDiv{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    14,
								},
								Left: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    12,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    12,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$foo"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  8,
												EndPos:    12,
											},
										},
										Value: []byte("$foo"),
									},
								},
								OpTkn: &token.Token{
									ID:    token.ID(47),
									Value: []byte("/"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    13,
									},
								},
								Right: &ast.ScalarLnumber{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    14,
									},
									NumberTkn: &token.Token{
										ID:    token.T_LNUMBER,
										Value: []byte("3"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  13,
											EndPos:    14,
										},
									},
									Value: []byte("3"),
								},
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprPostDec(t *testing.T) {
	src := `<? $a--;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    8,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    8,
				},
				Expr: &ast.ExprPostDec{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    7,
					},
					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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					DecTkn: &token.Token{
						ID:    token.T_DEC,
						Value: []byte("--"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  5,
							EndPos:    7,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    8,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprPostInc(t *testing.T) {
	src := `<? $a++;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    8,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    8,
				},
				Expr: &ast.ExprPostInc{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    7,
					},
					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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					IncTkn: &token.Token{
						ID:    token.T_INC,
						Value: []byte("++"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  5,
							EndPos:    7,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    8,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprPreDec(t *testing.T) {
	src := `<? --$a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    8,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    8,
				},
				Expr: &ast.ExprPreDec{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    7,
					},
					DecTkn: &token.Token{
						ID:    token.T_DEC,
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  5,
							EndPos:    7,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  5,
								EndPos:    7,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    7,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    8,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprPreInc(t *testing.T) {
	src := `<? ++$a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    8,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    8,
				},
				Expr: &ast.ExprPreInc{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    7,
					},
					IncTkn: &token.Token{
						ID:    token.T_INC,
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  5,
							EndPos:    7,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  5,
								EndPos:    7,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    7,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  7,
						EndPos:    8,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprInclude(t *testing.T) {
	src := `<? include $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.ExprInclude{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    13,
					},
					IncludeTkn: &token.Token{
						ID:    token.T_INCLUDE,
						Value: []byte("include"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprInclude_Once(t *testing.T) {
	src := `<? include_once $a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    19,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    19,
				},
				Expr: &ast.ExprIncludeOnce{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    18,
					},
					IncludeOnceTkn: &token.Token{
						ID:    token.T_INCLUDE_ONCE,
						Value: []byte("include_once"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &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("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  16,
									EndPos:    18,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  15,
											EndPos:    16,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprRequire(t *testing.T) {
	src := `<? require $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.ExprRequire{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    13,
					},
					RequireTkn: &token.Token{
						ID:    token.T_REQUIRE,
						Value: []byte("require"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprRequire_Once(t *testing.T) {
	src := `<? require_once $a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    19,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    19,
				},
				Expr: &ast.ExprRequireOnce{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    18,
					},
					RequireOnceTkn: &token.Token{
						ID:    token.T_REQUIRE_ONCE,
						Value: []byte("require_once"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &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("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  16,
									EndPos:    18,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  15,
											EndPos:    16,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprInstanceOf(t *testing.T) {
	src := `<? $a instanceof Foo;`

	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.ExprInstanceOf{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    20,
					},
					Expr: &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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					InstanceOfTkn: &token.Token{
						ID:    token.T_INSTANCEOF,
						Value: []byte("instanceof"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    16,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    6,
								},
							},
						},
					},
					Class: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  17,
							EndPos:    20,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    20,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    20,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  16,
												EndPos:    17,
											},
										},
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprInstanceOf_Relative(t *testing.T) {
	src := `<? $a instanceof namespace\Foo;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    31,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    31,
				},
				Expr: &ast.ExprInstanceOf{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    30,
					},
					Expr: &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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					InstanceOfTkn: &token.Token{
						ID:    token.T_INSTANCEOF,
						Value: []byte("instanceof"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    16,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    6,
								},
							},
						},
					},
					Class: &ast.NameRelative{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  17,
							EndPos:    30,
						},
						NsTkn: &token.Token{
							ID:    token.T_NAMESPACE,
							Value: []byte("namespace"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  17,
								EndPos:    26,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  16,
										EndPos:    17,
									},
								},
							},
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  26,
								EndPos:    27,
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  27,
									EndPos:    30,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  27,
										EndPos:    30,
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprInstanceOf_FullyQualified(t *testing.T) {
	src := `<? $a instanceof \Foo;`

	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.ExprInstanceOf{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    21,
					},
					Expr: &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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					InstanceOfTkn: &token.Token{
						ID:    token.T_INSTANCEOF,
						Value: []byte("instanceof"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    16,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    6,
								},
							},
						},
					},
					Class: &ast.NameFullyQualified{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  17,
							EndPos:    21,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  17,
								EndPos:    18,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  16,
										EndPos:    17,
									},
								},
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  18,
									EndPos:    21,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  18,
										EndPos:    21,
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprIsset(t *testing.T) {
	src := `<? isset($a);`

	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.ExprIsset{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					IssetTkn: &token.Token{
						ID:    token.T_ISSET,
						Value: []byte("isset"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
					},
					Vars: []ast.Vertex{
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    11,
									},
								},
								Value: []byte("$a"),
							},
						},
					},
					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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprIsset_Variables(t *testing.T) {
	src := `<? isset($a, $b);`

	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.ExprIsset{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    16,
					},
					IssetTkn: &token.Token{
						ID:    token.T_ISSET,
						Value: []byte("isset"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
					},
					Vars: []ast.Vertex{
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    11,
									},
								},
								Value: []byte("$a"),
							},
						},
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    15,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    15,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    15,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  12,
												EndPos:    13,
											},
										},
									},
								},
								Value: []byte("$b"),
							},
						},
					},
					SeparatorTkns: []*token.Token{
						{
							ID:    token.ID(44),
							Value: []byte(","),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    12,
							},
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  15,
							EndPos:    16,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprList_Empty(t *testing.T) {
	src := `<? list() = $b;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    15,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    15,
				},
				Expr: &ast.ExprAssign{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    14,
					},
					Var: &ast.ExprList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    9,
						},
						ListTkn: &token.Token{
							ID:    token.T_LIST,
							Value: []byte("list"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    7,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						OpenBracketTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
						},
						CloseBracketTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						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,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    14,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    14,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								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,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprList(t *testing.T) {
	src := `<? list($a) = $b;`

	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.ExprAssign{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    16,
					},
					Var: &ast.ExprList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    11,
						},
						ListTkn: &token.Token{
							ID:    token.T_LIST,
							Value: []byte("list"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    7,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						OpenBracketTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
						},
						Items: []ast.Vertex{
							&ast.ExprArrayItem{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    10,
								},
								Val: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    10,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    10,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$a"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  8,
												EndPos:    10,
											},
										},
										Value: []byte("$a"),
									},
								},
							},
						},
						CloseBracketTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    11,
							},
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  11,
									EndPos:    12,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    16,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    16,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    16,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  13,
											EndPos:    14,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprList_ArrayIndex(t *testing.T) {
	src := `<? list($a[]) = $b;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    19,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    19,
				},
				Expr: &ast.ExprAssign{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    18,
					},
					Var: &ast.ExprList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    13,
						},
						ListTkn: &token.Token{
							ID:    token.T_LIST,
							Value: []byte("list"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    7,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						OpenBracketTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
						},
						Items: []ast.Vertex{
							&ast.ExprArrayItem{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    12,
								},
								Val: &ast.ExprArrayDimFetch{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    12,
									},
									Var: &ast.ExprVariable{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    10,
										},
										Name: &ast.Identifier{
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  8,
												EndPos:    10,
											},
											IdentifierTkn: &token.Token{
												ID:    token.T_VARIABLE,
												Value: []byte("$a"),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  8,
													EndPos:    10,
												},
											},
											Value: []byte("$a"),
										},
									},
									OpenBracketTkn: &token.Token{
										ID:    token.ID(91),
										Value: []byte("["),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  10,
											EndPos:    11,
										},
									},
									CloseBracketTkn: &token.Token{
										ID:    token.ID(93),
										Value: []byte("]"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  11,
											EndPos:    12,
										},
									},
								},
							},
						},
						CloseBracketTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    14,
								},
							},
						},
					},
					Expr: &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,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  15,
											EndPos:    16,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprList_List(t *testing.T) {
	src := `<? list(list($a)) = $b;`

	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.ExprAssign{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    22,
					},
					Var: &ast.ExprList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    17,
						},
						ListTkn: &token.Token{
							ID:    token.T_LIST,
							Value: []byte("list"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    7,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						OpenBracketTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
						},
						Items: []ast.Vertex{
							&ast.ExprArrayItem{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    16,
								},
								Val: &ast.ExprList{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    16,
									},
									ListTkn: &token.Token{
										ID:    token.T_LIST,
										Value: []byte("list"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    12,
										},
									},
									OpenBracketTkn: &token.Token{
										ID:    token.ID(40),
										Value: []byte("("),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    13,
										},
									},
									Items: []ast.Vertex{
										&ast.ExprArrayItem{
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  13,
												EndPos:    15,
											},
											Val: &ast.ExprVariable{
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  13,
													EndPos:    15,
												},
												Name: &ast.Identifier{
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  13,
														EndPos:    15,
													},
													IdentifierTkn: &token.Token{
														ID:    token.T_VARIABLE,
														Value: []byte("$a"),
														Position: &position.Position{
															StartLine: 1,
															EndLine:   1,
															StartPos:  13,
															EndPos:    15,
														},
													},
													Value: []byte("$a"),
												},
											},
										},
									},
									CloseBracketTkn: &token.Token{
										ID:    token.ID(41),
										Value: []byte(")"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  15,
											EndPos:    16,
										},
									},
								},
							},
						},
						CloseBracketTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    19,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    18,
								},
							},
						},
					},
					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("$b"),
								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("$b"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprList_EmptyItem(t *testing.T) {
	src := `<? list(, $a) = $b;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    19,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    19,
				},
				Expr: &ast.ExprAssign{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    18,
					},
					Var: &ast.ExprList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    13,
						},
						ListTkn: &token.Token{
							ID:    token.T_LIST,
							Value: []byte("list"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    7,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						OpenBracketTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
						},
						Items: []ast.Vertex{
							&ast.ExprArrayItem{},
							&ast.ExprArrayItem{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    12,
								},
								Val: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  10,
										EndPos:    12,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  10,
											EndPos:    12,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$a"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  10,
												EndPos:    12,
											},
											FreeFloating: []*token.Token{
												{
													ID:    token.T_WHITESPACE,
													Value: []byte(" "),
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  9,
														EndPos:    10,
													},
												},
											},
										},
										Value: []byte("$a"),
									},
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    9,
								},
							},
						},
						CloseBracketTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    14,
								},
							},
						},
					},
					Expr: &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,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  15,
											EndPos:    16,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprList_EmptyItems(t *testing.T) {
	src := `<? list(, , $a, ) = $b;`

	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.ExprAssign{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    22,
					},
					Var: &ast.ExprList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    17,
						},
						ListTkn: &token.Token{
							ID:    token.T_LIST,
							Value: []byte("list"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    7,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						OpenBracketTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
						},
						Items: []ast.Vertex{
							&ast.ExprArrayItem{},
							&ast.ExprArrayItem{},
							&ast.ExprArrayItem{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  12,
									EndPos:    14,
								},
								Val: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    14,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    14,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$a"),
											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,
													},
												},
											},
										},
										Value: []byte("$a"),
									},
								},
							},
							&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:  10,
									EndPos:    11,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  9,
											EndPos:    10,
										},
									},
								},
							},
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    15,
								},
							},
						},
						CloseBracketTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  15,
										EndPos:    16,
									},
								},
							},
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    19,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    18,
								},
							},
						},
					},
					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("$b"),
								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("$b"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprMethodCall(t *testing.T) {
	src := `<? $a->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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					ObjectOperatorTkn: &token.Token{
						ID:    token.T_OBJECT_OPERATOR,
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprNew(t *testing.T) {
	src := `<? new 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.ExprNew{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    10,
					},
					NewTkn: &token.Token{
						ID:    token.T_NEW,
						Value: []byte("new"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Class: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    10,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  7,
									EndPos:    10,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  7,
										EndPos:    10,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  6,
												EndPos:    7,
											},
										},
									},
								},
								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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprNew_Relative(t *testing.T) {
	src := `<? new namespace\Foo();`

	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.ExprNew{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    22,
					},
					NewTkn: &token.Token{
						ID:    token.T_NEW,
						Value: []byte("new"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Class: &ast.NameRelative{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    20,
						},
						NsTkn: &token.Token{
							ID:    token.T_NAMESPACE,
							Value: []byte("namespace"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    16,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  6,
										EndPos:    7,
									},
								},
							},
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  17,
									EndPos:    20,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  17,
										EndPos:    20,
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  20,
							EndPos:    21,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  21,
							EndPos:    22,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprNew_FullyQualified(t *testing.T) {
	src := `<? new \Foo();`

	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.ExprNew{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    13,
					},
					NewTkn: &token.Token{
						ID:    token.T_NEW,
						Value: []byte("new"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Class: &ast.NameFullyQualified{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    11,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    8,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  6,
										EndPos:    7,
									},
								},
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    11,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    11,
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprNew_Anonymous(t *testing.T) {
	src := `<? new class ($a, ...$b) {};`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    28,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    28,
				},
				Expr: &ast.ExprNew{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    27,
					},
					NewTkn: &token.Token{
						ID:    token.T_NEW,
						Value: []byte("new"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Class: &ast.StmtClass{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    27,
						},
						ClassTkn: &token.Token{
							ID:    token.T_CLASS,
							Value: []byte("class"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  7,
								EndPos:    12,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  6,
										EndPos:    7,
									},
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    14,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  12,
										EndPos:    13,
									},
								},
							},
						},
						Args: []ast.Vertex{
							&ast.Argument{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    16,
								},
								Expr: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  14,
										EndPos:    16,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  14,
											EndPos:    16,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$a"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  14,
												EndPos:    16,
											},
										},
										Value: []byte("$a"),
									},
								},
							},
							&ast.Argument{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  18,
									EndPos:    23,
								},
								VariadicTkn: &token.Token{
									ID:    token.T_ELLIPSIS,
									Value: []byte("..."),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  18,
										EndPos:    21,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  17,
												EndPos:    18,
											},
										},
									},
								},
								Expr: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  21,
										EndPos:    23,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  21,
											EndPos:    23,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$b"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  21,
												EndPos:    23,
											},
										},
										Value: []byte("$b"),
									},
								},
							},
						},
						SeparatorTkns: []*token.Token{
							{
								ID:    token.ID(44),
								Value: []byte(","),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  16,
									EndPos:    17,
								},
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  23,
								EndPos:    24,
							},
						},
						OpenCurlyBracketTkn: &token.Token{
							ID:    token.ID(123),
							Value: []byte("{"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  25,
								EndPos:    26,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  24,
										EndPos:    25,
									},
								},
							},
						},
						Stmts: []ast.Vertex{},
						CloseCurlyBracketTkn: &token.Token{
							ID:    token.ID(125),
							Value: []byte("}"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  26,
								EndPos:    27,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  27,
						EndPos:    28,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprPrint(t *testing.T) {
	src := `<? print($a);`

	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.ExprPrint{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					PrintTkn: &token.Token{
						ID:    token.T_PRINT,
						Value: []byte("print"),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &ast.ExprBrackets{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    12,
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
						Expr: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  9,
										EndPos:    11,
									},
								},
								Value: []byte("$a"),
							},
						},
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprPropertyFetch(t *testing.T) {
	src := `<? $a->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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					ObjectOperatorTkn: &token.Token{
						ID:    token.T_OBJECT_OPERATOR,
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprShellExec(t *testing.T) {
	src := "<? `cmd $a`;"

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				Expr: &ast.ExprShellExec{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					OpenBacktickTkn: &token.Token{
						ID:    token.ID(96),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    8,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("cmd "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    8,
								},
							},
							Value: []byte("cmd "),
						},
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    10,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    10,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$a"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    10,
									},
								},
								Value: []byte("$a"),
							},
						},
					},
					CloseBacktickTkn: &token.Token{
						ID:    token.ID(96),
						Value: []byte("`"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    11,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprShortArray(t *testing.T) {
	src := `<? [];`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    6,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    6,
				},
				Expr: &ast.ExprArray{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    5,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					CloseBracketTkn: &token.Token{
						ID:    token.ID(93),
						Value: []byte("]"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  4,
							EndPos:    5,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  5,
						EndPos:    6,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprShortArray_Item(t *testing.T) {
	src := `<? [1];`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    7,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    7,
				},
				Expr: &ast.ExprArray{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Items: []ast.Vertex{
						&ast.ExprArrayItem{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    5,
							},
							Val: &ast.ScalarLnumber{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    5,
								},
								NumberTkn: &token.Token{
									ID:    token.T_LNUMBER,
									Value: []byte("1"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  4,
										EndPos:    5,
									},
								},
								Value: []byte("1"),
							},
						},
					},
					CloseBracketTkn: &token.Token{
						ID:    token.ID(93),
						Value: []byte("]"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  5,
							EndPos:    6,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprShortArray_Items(t *testing.T) {
	src := `<? [1=>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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Items: []ast.Vertex{
						&ast.ExprArrayItem{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    8,
							},
							Key: &ast.ScalarLnumber{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    5,
								},
								NumberTkn: &token.Token{
									ID:    token.T_LNUMBER,
									Value: []byte("1"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  4,
										EndPos:    5,
									},
								},
								Value: []byte("1"),
							},
							DoubleArrowTkn: &token.Token{
								ID:    token.T_DOUBLE_ARROW,
								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.ID(38),
								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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprShortList(t *testing.T) {
	src := `<? [$a] = $b;`

	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.ExprAssign{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					Var: &ast.ExprList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Items: []ast.Vertex{
							&ast.ExprArrayItem{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    6,
								},
								Val: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  4,
										EndPos:    6,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  4,
											EndPos:    6,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$a"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  4,
												EndPos:    6,
											},
										},
										Value: []byte("$a"),
									},
								},
							},
						},
						CloseBracketTkn: &token.Token{
							ID:    token.ID(93),
							Value: []byte("]"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  6,
								EndPos:    7,
							},
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
						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:  10,
							EndPos:    12,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    12,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    12,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  9,
											EndPos:    10,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprShortList_ArrayIndex(t *testing.T) {
	src := `<? [$a[]] = $b;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    15,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    15,
				},
				Expr: &ast.ExprAssign{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    14,
					},
					Var: &ast.ExprList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    9,
						},
						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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Items: []ast.Vertex{
							&ast.ExprArrayItem{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    8,
								},
								Val: &ast.ExprArrayDimFetch{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  4,
										EndPos:    8,
									},
									Var: &ast.ExprVariable{
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  4,
											EndPos:    6,
										},
										Name: &ast.Identifier{
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  4,
												EndPos:    6,
											},
											IdentifierTkn: &token.Token{
												ID:    token.T_VARIABLE,
												Value: []byte("$a"),
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  4,
													EndPos:    6,
												},
											},
											Value: []byte("$a"),
										},
									},
									OpenBracketTkn: &token.Token{
										ID:    token.ID(91),
										Value: []byte("["),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  6,
											EndPos:    7,
										},
									},
									CloseBracketTkn: &token.Token{
										ID:    token.ID(93),
										Value: []byte("]"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  7,
											EndPos:    8,
										},
									},
								},
							},
						},
						CloseBracketTkn: &token.Token{
							ID:    token.ID(93),
							Value: []byte("]"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    9,
							},
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						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,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    14,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    14,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								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,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprShortList_List(t *testing.T) {
	src := `<? [list($a)] = $b;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    19,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    19,
				},
				Expr: &ast.ExprAssign{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    18,
					},
					Var: &ast.ExprList{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    13,
						},
						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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Items: []ast.Vertex{
							&ast.ExprArrayItem{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    12,
								},
								Val: &ast.ExprList{
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  4,
										EndPos:    12,
									},
									ListTkn: &token.Token{
										ID:    token.T_LIST,
										Value: []byte("list"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  4,
											EndPos:    8,
										},
									},
									OpenBracketTkn: &token.Token{
										ID:    token.ID(40),
										Value: []byte("("),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    9,
										},
									},
									Items: []ast.Vertex{
										&ast.ExprArrayItem{
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  9,
												EndPos:    11,
											},
											Val: &ast.ExprVariable{
												Position: &position.Position{
													StartLine: 1,
													EndLine:   1,
													StartPos:  9,
													EndPos:    11,
												},
												Name: &ast.Identifier{
													Position: &position.Position{
														StartLine: 1,
														EndLine:   1,
														StartPos:  9,
														EndPos:    11,
													},
													IdentifierTkn: &token.Token{
														ID:    token.T_VARIABLE,
														Value: []byte("$a"),
														Position: &position.Position{
															StartLine: 1,
															EndLine:   1,
															StartPos:  9,
															EndPos:    11,
														},
													},
													Value: []byte("$a"),
												},
											},
										},
									},
									CloseBracketTkn: &token.Token{
										ID:    token.ID(41),
										Value: []byte(")"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  11,
											EndPos:    12,
										},
									},
								},
							},
						},
						CloseBracketTkn: &token.Token{
							ID:    token.ID(93),
							Value: []byte("]"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    15,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    14,
								},
							},
						},
					},
					Expr: &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,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  15,
											EndPos:    16,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  18,
						EndPos:    19,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprStaticCall(t *testing.T) {
	src := `<? Foo::bar();`

	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.ExprStaticCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    13,
					},
					Class: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  3,
									EndPos:    6,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  3,
										EndPos:    6,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_OPEN_TAG,
											Value: []byte("<?"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  2,
												EndPos:    3,
											},
										},
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
					DoubleColonTkn: &token.Token{
						ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
						Value: []byte("::"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    8,
						},
					},
					Call: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    11,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_STRING,
							Value: []byte("bar"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    11,
							},
						},
						Value: []byte("bar"),
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprStaticCall_Relative(t *testing.T) {
	src := `<? namespace\Foo::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.ExprStaticCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    23,
					},
					Class: &ast.NameRelative{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    16,
						},
						NsTkn: &token.Token{
							ID:    token.T_NAMESPACE,
							Value: []byte("namespace"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    12,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    16,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    16,
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
					DoubleColonTkn: &token.Token{
						ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
						Value: []byte("::"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    18,
						},
					},
					Call: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    21,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_STRING,
							Value: []byte("bar"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    21,
							},
						},
						Value: []byte("bar"),
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  21,
							EndPos:    22,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprStaticCall_FullyQualified(t *testing.T) {
	src := `<? \Foo::bar();`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    15,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    15,
				},
				Expr: &ast.ExprStaticCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    14,
					},
					Class: &ast.NameFullyQualified{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    7,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  4,
										EndPos:    7,
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
					DoubleColonTkn: &token.Token{
						ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
						Value: []byte("::"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    9,
						},
					},
					Call: &ast.Identifier{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    12,
						},
						IdentifierTkn: &token.Token{
							ID:    token.T_STRING,
							Value: []byte("bar"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    12,
							},
						},
						Value: []byte("bar"),
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprStaticCall_Var(t *testing.T) {
	src := `<? Foo::$bar();`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    15,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    15,
				},
				Expr: &ast.ExprStaticCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    14,
					},
					Class: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  3,
									EndPos:    6,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  3,
										EndPos:    6,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_OPEN_TAG,
											Value: []byte("<?"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  2,
												EndPos:    3,
											},
										},
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
					DoubleColonTkn: &token.Token{
						ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
						Value: []byte("::"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    8,
						},
					},
					Call: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    12,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    12,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    12,
								},
							},
							Value: []byte("$bar"),
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  12,
							EndPos:    13,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						Value: []byte(")"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprStaticCall_VarVar(t *testing.T) {
	src := `<? $foo::$bar();`

	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.ExprStaticCall{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    15,
					},
					Class: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    7,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$foo"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  3,
									EndPos:    7,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_OPEN_TAG,
										Value: []byte("<?"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$foo"),
						},
					},
					DoubleColonTkn: &token.Token{
						ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
						Value: []byte("::"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    9,
						},
					},
					Call: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    13,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    13,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    13,
								},
							},
							Value: []byte("$bar"),
						},
					},
					OpenParenthesisTkn: &token.Token{
						ID:    token.ID(40),
						Value: []byte("("),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    14,
						},
					},
					CloseParenthesisTkn: &token.Token{
						ID:    token.ID(41),
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprStaticPropertyFetch(t *testing.T) {
	src := `<? Foo::$bar;`

	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.ExprStaticPropertyFetch{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					Class: &ast.Name{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    6,
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  3,
									EndPos:    6,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  3,
										EndPos:    6,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_OPEN_TAG,
											Value: []byte("<?"),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  2,
												EndPos:    3,
											},
										},
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
					DoubleColonTkn: &token.Token{
						ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
						Value: []byte("::"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    8,
						},
					},
					Prop: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    12,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    12,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    12,
								},
							},
							Value: []byte("$bar"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprStaticPropertyFetch_Relative(t *testing.T) {
	src := `<? namespace\Foo::$bar;`

	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.ExprStaticPropertyFetch{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    22,
					},
					Class: &ast.NameRelative{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    16,
						},
						NsTkn: &token.Token{
							ID:    token.T_NAMESPACE,
							Value: []byte("namespace"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  3,
								EndPos:    12,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_OPEN_TAG,
									Value: []byte("<?"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							Value: []byte("\\"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  12,
								EndPos:    13,
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    16,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    16,
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
					DoubleColonTkn: &token.Token{
						ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
						Value: []byte("::"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    18,
						},
					},
					Prop: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    22,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    22,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  18,
									EndPos:    22,
								},
							},
							Value: []byte("$bar"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprStaticPropertyFetch_FullyQualified(t *testing.T) {
	src := `<? \Foo::$bar;`

	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.ExprStaticPropertyFetch{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    13,
					},
					Class: &ast.NameFullyQualified{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    7,
						},
						NsSeparatorTkn: &token.Token{
							ID:    token.T_NS_SEPARATOR,
							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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Parts: []ast.Vertex{
							&ast.NamePart{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    7,
								},
								StringTkn: &token.Token{
									ID:    token.T_STRING,
									Value: []byte("Foo"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  4,
										EndPos:    7,
									},
								},
								Value: []byte("Foo"),
							},
						},
					},
					DoubleColonTkn: &token.Token{
						ID:    token.T_PAAMAYIM_NEKUDOTAYIM,
						Value: []byte("::"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  7,
							EndPos:    9,
						},
					},
					Prop: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    13,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    13,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$bar"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    13,
								},
							},
							Value: []byte("$bar"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprTernary(t *testing.T) {
	src := `<? $a ? $b : $c;`

	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.ExprTernary{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    15,
					},
					Cond: &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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					QuestionTkn: &token.Token{
						ID:    token.ID(63),
						Value: []byte("?"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    6,
								},
							},
						},
					},
					IfTrue: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    10,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    10,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								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,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
					ColonTkn: &token.Token{
						ID:    token.ID(58),
						Value: []byte(":"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  11,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    11,
								},
							},
						},
					},
					IfFalse: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  13,
							EndPos:    15,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    15,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$c"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    15,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  12,
											EndPos:    13,
										},
									},
								},
							},
							Value: []byte("$c"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprTernary_Simple(t *testing.T) {
	src := `<? $a ? : $c;`

	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.ExprTernary{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    12,
					},
					Cond: &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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					QuestionTkn: &token.Token{
						ID:    token.ID(63),
						Value: []byte("?"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    6,
								},
							},
						},
					},
					ColonTkn: &token.Token{
						ID:    token.ID(58),
						Value: []byte(":"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    9,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  7,
									EndPos:    8,
								},
							},
						},
					},
					IfFalse: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  10,
							EndPos:    12,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  10,
								EndPos:    12,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$c"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  10,
									EndPos:    12,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  9,
											EndPos:    10,
										},
									},
								},
							},
							Value: []byte("$c"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprTernary_NestedTrue(t *testing.T) {
	src := `<? $a ? $b ? $c : $d : $e;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    26,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    26,
				},
				Expr: &ast.ExprTernary{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    25,
					},
					Cond: &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:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  2,
											EndPos:    3,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					QuestionTkn: &token.Token{
						ID:    token.ID(63),
						Value: []byte("?"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  6,
							EndPos:    7,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  5,
									EndPos:    6,
								},
							},
						},
					},
					IfTrue: &ast.ExprTernary{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  8,
							EndPos:    20,
						},
						Cond: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    10,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    10,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									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,
											},
										},
									},
								},
								Value: []byte("$b"),
							},
						},
						QuestionTkn: &token.Token{
							ID:    token.ID(63),
							Value: []byte("?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    12,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  10,
										EndPos:    11,
									},
								},
							},
						},
						IfTrue: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    15,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    15,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$c"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    15,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  12,
												EndPos:    13,
											},
										},
									},
								},
								Value: []byte("$c"),
							},
						},
						ColonTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  16,
								EndPos:    17,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  15,
										EndPos:    16,
									},
								},
							},
						},
						IfFalse: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  18,
									EndPos:    20,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$d"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  18,
										EndPos:    20,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  17,
												EndPos:    18,
											},
										},
									},
								},
								Value: []byte("$d"),
							},
						},
					},
					ColonTkn: &token.Token{
						ID:    token.ID(58),
						Value: []byte(":"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  21,
							EndPos:    22,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  20,
									EndPos:    21,
								},
							},
						},
					},
					IfFalse: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  23,
							EndPos:    25,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  23,
								EndPos:    25,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$e"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  23,
									EndPos:    25,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  22,
											EndPos:    23,
										},
									},
								},
							},
							Value: []byte("$e"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  25,
						EndPos:    26,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprTernary_NestedCond(t *testing.T) {
	src := `<? $a ? $b : $c ? $d : $e;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    26,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    26,
				},
				Expr: &ast.ExprTernary{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    25,
					},
					Cond: &ast.ExprTernary{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    15,
						},
						Cond: &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:  0,
												EndPos:    2,
											},
										},
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  2,
												EndPos:    3,
											},
										},
									},
								},
								Value: []byte("$a"),
							},
						},
						QuestionTkn: &token.Token{
							ID:    token.ID(63),
							Value: []byte("?"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  6,
								EndPos:    7,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  5,
										EndPos:    6,
									},
								},
							},
						},
						IfTrue: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  8,
								EndPos:    10,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  8,
									EndPos:    10,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$b"),
									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,
											},
										},
									},
								},
								Value: []byte("$b"),
							},
						},
						ColonTkn: &token.Token{
							ID:    token.ID(58),
							Value: []byte(":"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  11,
								EndPos:    12,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  10,
										EndPos:    11,
									},
								},
							},
						},
						IfFalse: &ast.ExprVariable{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  13,
								EndPos:    15,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  13,
									EndPos:    15,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$c"),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  13,
										EndPos:    15,
									},
									FreeFloating: []*token.Token{
										{
											ID:    token.T_WHITESPACE,
											Value: []byte(" "),
											Position: &position.Position{
												StartLine: 1,
												EndLine:   1,
												StartPos:  12,
												EndPos:    13,
											},
										},
									},
								},
								Value: []byte("$c"),
							},
						},
					},
					QuestionTkn: &token.Token{
						ID:    token.ID(63),
						Value: []byte("?"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  16,
							EndPos:    17,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  15,
									EndPos:    16,
								},
							},
						},
					},
					IfTrue: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  18,
							EndPos:    20,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  18,
								EndPos:    20,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$d"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  18,
									EndPos:    20,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  17,
											EndPos:    18,
										},
									},
								},
							},
							Value: []byte("$d"),
						},
					},
					ColonTkn: &token.Token{
						ID:    token.ID(58),
						Value: []byte(":"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  21,
							EndPos:    22,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  20,
									EndPos:    21,
								},
							},
						},
					},
					IfFalse: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  23,
							EndPos:    25,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  23,
								EndPos:    25,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$e"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  23,
									EndPos:    25,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  22,
											EndPos:    23,
										},
									},
								},
							},
							Value: []byte("$e"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  25,
						EndPos:    26,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprUnaryMinus(t *testing.T) {
	src := `<? -$a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    7,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    7,
				},
				Expr: &ast.ExprUnaryMinus{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					MinusTkn: &token.Token{
						ID:    token.ID(45),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  4,
							EndPos:    6,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    6,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    6,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprUnaryPlus(t *testing.T) {
	src := `<? +$a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    7,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    7,
				},
				Expr: &ast.ExprUnaryPlus{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					PlusTkn: &token.Token{
						ID:    token.ID(43),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  4,
							EndPos:    6,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    6,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    6,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprVariable(t *testing.T) {
	src := `<? $a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    6,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    6,
				},
				Expr: &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:  0,
										EndPos:    2,
									},
								},
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  2,
										EndPos:    3,
									},
								},
							},
						},
						Value: []byte("$a"),
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  5,
						EndPos:    6,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprVariable_Variable(t *testing.T) {
	src := `<? $$a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    7,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    7,
				},
				Expr: &ast.ExprVariable{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    6,
					},
					DollarTkn: &token.Token{
						ID:    token.ID(36),
						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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Name: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  4,
							EndPos:    6,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  4,
								EndPos:    6,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  4,
									EndPos:    6,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  6,
						EndPos:    7,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprYield(t *testing.T) {
	src := `<? yield;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    9,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    9,
				},
				Expr: &ast.ExprYield{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    8,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  8,
						EndPos:    9,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprYield_Val(t *testing.T) {
	src := `<? yield $a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 1,
			EndLine:   1,
			StartPos:  3,
			EndPos:    12,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 1,
					EndLine:   1,
					StartPos:  3,
					EndPos:    12,
				},
				Expr: &ast.ExprYield{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    11,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Val: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    11,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    9,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprYield_KeyVal(t *testing.T) {
	src := `<? yield $a => $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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Key: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    11,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    9,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					DoubleArrowTkn: &token.Token{
						ID:    token.T_DOUBLE_ARROW,
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprYield_Expr(t *testing.T) {
	src := `<? yield 1;`

	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.ExprYield{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    10,
					},
					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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Val: &ast.ScalarLnumber{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    10,
						},
						NumberTkn: &token.Token{
							ID:    token.T_LNUMBER,
							Value: []byte("1"),
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    10,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 1,
										EndLine:   1,
										StartPos:  8,
										EndPos:    9,
									},
								},
							},
						},
						Value: []byte("1"),
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprYield_KeyExpr(t *testing.T) {
	src := `<? yield $a => 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:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Key: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  9,
							EndPos:    11,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  9,
								EndPos:    11,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  9,
									EndPos:    11,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  8,
											EndPos:    9,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					DoubleArrowTkn: &token.Token{
						ID:    token.T_DOUBLE_ARROW,
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestExprYieldFrom(t *testing.T) {
	src := `<? yield from $a;`

	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.ExprYieldFrom{
					Position: &position.Position{
						StartLine: 1,
						EndLine:   1,
						StartPos:  3,
						EndPos:    16,
					},
					YieldFromTkn: &token.Token{
						ID:    token.T_YIELD_FROM,
						Value: []byte("yield from"),
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  3,
							EndPos:    13,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  2,
									EndPos:    3,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 1,
							EndLine:   1,
							StartPos:  14,
							EndPos:    16,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 1,
								EndLine:   1,
								StartPos:  14,
								EndPos:    16,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  14,
									EndPos:    16,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   1,
											StartPos:  13,
											EndPos:    14,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

// expr assign

func TestExprAssign_Assign(t *testing.T) {
	src := `<?
		$a = $b;
		$a =& $b;
		$a =& new Foo;
		$a =& new Foo($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;
		$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: 1,
											EndLine:   1,
											StartPos:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   2,
											StartPos:  2,
											EndPos:    5,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  8,
							EndPos:    9,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  7,
									EndPos:    8,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  10,
							EndPos:    12,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  10,
								EndPos:    12,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  10,
									EndPos:    12,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  9,
											EndPos:    10,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  12,
						EndPos:    13,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 3,
					EndLine:   3,
					StartPos:  16,
					EndPos:    25,
				},
				Expr: &ast.ExprAssignReference{
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  16,
						EndPos:    24,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  16,
							EndPos:    18,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  16,
								EndPos:    18,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  16,
									EndPos:    18,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 2,
											EndLine:   3,
											StartPos:  13,
											EndPos:    16,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  19,
							EndPos:    20,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  18,
									EndPos:    19,
								},
							},
						},
					},
					AmpersandTkn: &token.Token{
						ID:    token.ID(38),
						Value: []byte("&"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  20,
							EndPos:    21,
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  22,
							EndPos:    24,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  22,
								EndPos:    24,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  22,
									EndPos:    24,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  21,
											EndPos:    22,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  24,
						EndPos:    25,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 4,
					EndLine:   4,
					StartPos:  28,
					EndPos:    42,
				},
				Expr: &ast.ExprAssignReference{
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  28,
						EndPos:    41,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  28,
							EndPos:    30,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  28,
								EndPos:    30,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  28,
									EndPos:    30,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   4,
											StartPos:  25,
											EndPos:    28,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  31,
							EndPos:    32,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  30,
									EndPos:    31,
								},
							},
						},
					},
					AmpersandTkn: &token.Token{
						ID:    token.ID(38),
						Value: []byte("&"),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  32,
							EndPos:    33,
						},
					},
					Expr: &ast.ExprNew{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  34,
							EndPos:    41,
						},
						NewTkn: &token.Token{
							ID:    token.T_NEW,
							Value: []byte("new"),
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  34,
								EndPos:    37,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  33,
										EndPos:    34,
									},
								},
							},
						},
						Class: &ast.Name{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  38,
								EndPos:    41,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 4,
										EndLine:   4,
										StartPos:  38,
										EndPos:    41,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 4,
											EndLine:   4,
											StartPos:  38,
											EndPos:    41,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 4,
													EndLine:   4,
													StartPos:  37,
													EndPos:    38,
												},
											},
										},
									},
									Value: []byte("Foo"),
								},
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  41,
						EndPos:    42,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 5,
					EndLine:   5,
					StartPos:  45,
					EndPos:    63,
				},
				Expr: &ast.ExprAssignReference{
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  45,
						EndPos:    62,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  45,
							EndPos:    47,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  45,
								EndPos:    47,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  45,
									EndPos:    47,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 4,
											EndLine:   5,
											StartPos:  42,
											EndPos:    45,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.ID(61),
						Value: []byte("="),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  48,
							EndPos:    49,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  47,
									EndPos:    48,
								},
							},
						},
					},
					AmpersandTkn: &token.Token{
						ID:    token.ID(38),
						Value: []byte("&"),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  49,
							EndPos:    50,
						},
					},
					Expr: &ast.ExprNew{
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  51,
							EndPos:    62,
						},
						NewTkn: &token.Token{
							ID:    token.T_NEW,
							Value: []byte("new"),
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  51,
								EndPos:    54,
							},
							FreeFloating: []*token.Token{
								{
									ID:    token.T_WHITESPACE,
									Value: []byte(" "),
									Position: &position.Position{
										StartLine: 5,
										EndLine:   5,
										StartPos:  50,
										EndPos:    51,
									},
								},
							},
						},
						Class: &ast.Name{
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  55,
								EndPos:    58,
							},
							Parts: []ast.Vertex{
								&ast.NamePart{
									Position: &position.Position{
										StartLine: 5,
										EndLine:   5,
										StartPos:  55,
										EndPos:    58,
									},
									StringTkn: &token.Token{
										ID:    token.T_STRING,
										Value: []byte("Foo"),
										Position: &position.Position{
											StartLine: 5,
											EndLine:   5,
											StartPos:  55,
											EndPos:    58,
										},
										FreeFloating: []*token.Token{
											{
												ID:    token.T_WHITESPACE,
												Value: []byte(" "),
												Position: &position.Position{
													StartLine: 5,
													EndLine:   5,
													StartPos:  54,
													EndPos:    55,
												},
											},
										},
									},
									Value: []byte("Foo"),
								},
							},
						},
						OpenParenthesisTkn: &token.Token{
							ID:    token.ID(40),
							Value: []byte("("),
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  58,
								EndPos:    59,
							},
						},
						Args: []ast.Vertex{
							&ast.Argument{
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  59,
									EndPos:    61,
								},
								Expr: &ast.ExprVariable{
									Position: &position.Position{
										StartLine: 5,
										EndLine:   5,
										StartPos:  59,
										EndPos:    61,
									},
									Name: &ast.Identifier{
										Position: &position.Position{
											StartLine: 5,
											EndLine:   5,
											StartPos:  59,
											EndPos:    61,
										},
										IdentifierTkn: &token.Token{
											ID:    token.T_VARIABLE,
											Value: []byte("$b"),
											Position: &position.Position{
												StartLine: 5,
												EndLine:   5,
												StartPos:  59,
												EndPos:    61,
											},
										},
										Value: []byte("$b"),
									},
								},
							},
						},
						CloseParenthesisTkn: &token.Token{
							ID:    token.ID(41),
							Value: []byte(")"),
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  61,
								EndPos:    62,
							},
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  62,
						EndPos:    63,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 6,
					EndLine:   6,
					StartPos:  66,
					EndPos:    75,
				},
				Expr: &ast.ExprAssignBitwiseAnd{
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  66,
						EndPos:    74,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 6,
							EndLine:   6,
							StartPos:  66,
							EndPos:    68,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 6,
								EndLine:   6,
								StartPos:  66,
								EndPos:    68,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 6,
									EndLine:   6,
									StartPos:  66,
									EndPos:    68,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 5,
											EndLine:   6,
											StartPos:  63,
											EndPos:    66,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_AND_EQUAL,
						Value: []byte("&="),
						Position: &position.Position{
							StartLine: 6,
							EndLine:   6,
							StartPos:  69,
							EndPos:    71,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 6,
									EndLine:   6,
									StartPos:  68,
									EndPos:    69,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 6,
							EndLine:   6,
							StartPos:  72,
							EndPos:    74,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 6,
								EndLine:   6,
								StartPos:  72,
								EndPos:    74,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 6,
									EndLine:   6,
									StartPos:  72,
									EndPos:    74,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 6,
											EndLine:   6,
											StartPos:  71,
											EndPos:    72,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  74,
						EndPos:    75,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 7,
					EndLine:   7,
					StartPos:  78,
					EndPos:    87,
				},
				Expr: &ast.ExprAssignBitwiseOr{
					Position: &position.Position{
						StartLine: 7,
						EndLine:   7,
						StartPos:  78,
						EndPos:    86,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 7,
							EndLine:   7,
							StartPos:  78,
							EndPos:    80,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 7,
								EndLine:   7,
								StartPos:  78,
								EndPos:    80,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 7,
									EndLine:   7,
									StartPos:  78,
									EndPos:    80,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 6,
											EndLine:   7,
											StartPos:  75,
											EndPos:    78,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_OR_EQUAL,
						Value: []byte("|="),
						Position: &position.Position{
							StartLine: 7,
							EndLine:   7,
							StartPos:  81,
							EndPos:    83,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 7,
									EndLine:   7,
									StartPos:  80,
									EndPos:    81,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 7,
							EndLine:   7,
							StartPos:  84,
							EndPos:    86,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 7,
								EndLine:   7,
								StartPos:  84,
								EndPos:    86,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 7,
									EndLine:   7,
									StartPos:  84,
									EndPos:    86,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 7,
											EndLine:   7,
											StartPos:  83,
											EndPos:    84,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 7,
						EndLine:   7,
						StartPos:  86,
						EndPos:    87,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 8,
					EndLine:   8,
					StartPos:  90,
					EndPos:    99,
				},
				Expr: &ast.ExprAssignBitwiseXor{
					Position: &position.Position{
						StartLine: 8,
						EndLine:   8,
						StartPos:  90,
						EndPos:    98,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 8,
							EndLine:   8,
							StartPos:  90,
							EndPos:    92,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 8,
								EndLine:   8,
								StartPos:  90,
								EndPos:    92,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 8,
									EndLine:   8,
									StartPos:  90,
									EndPos:    92,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 7,
											EndLine:   8,
											StartPos:  87,
											EndPos:    90,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_XOR_EQUAL,
						Value: []byte("^="),
						Position: &position.Position{
							StartLine: 8,
							EndLine:   8,
							StartPos:  93,
							EndPos:    95,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 8,
									EndLine:   8,
									StartPos:  92,
									EndPos:    93,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 8,
							EndLine:   8,
							StartPos:  96,
							EndPos:    98,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 8,
								EndLine:   8,
								StartPos:  96,
								EndPos:    98,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 8,
									EndLine:   8,
									StartPos:  96,
									EndPos:    98,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 8,
											EndLine:   8,
											StartPos:  95,
											EndPos:    96,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 8,
						EndLine:   8,
						StartPos:  98,
						EndPos:    99,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 9,
					EndLine:   9,
					StartPos:  102,
					EndPos:    111,
				},
				Expr: &ast.ExprAssignConcat{
					Position: &position.Position{
						StartLine: 9,
						EndLine:   9,
						StartPos:  102,
						EndPos:    110,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 9,
							EndLine:   9,
							StartPos:  102,
							EndPos:    104,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 9,
								EndLine:   9,
								StartPos:  102,
								EndPos:    104,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 9,
									EndLine:   9,
									StartPos:  102,
									EndPos:    104,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 8,
											EndLine:   9,
											StartPos:  99,
											EndPos:    102,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_CONCAT_EQUAL,
						Value: []byte(".="),
						Position: &position.Position{
							StartLine: 9,
							EndLine:   9,
							StartPos:  105,
							EndPos:    107,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 9,
									EndLine:   9,
									StartPos:  104,
									EndPos:    105,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 9,
							EndLine:   9,
							StartPos:  108,
							EndPos:    110,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 9,
								EndLine:   9,
								StartPos:  108,
								EndPos:    110,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 9,
									EndLine:   9,
									StartPos:  108,
									EndPos:    110,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 9,
											EndLine:   9,
											StartPos:  107,
											EndPos:    108,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 9,
						EndLine:   9,
						StartPos:  110,
						EndPos:    111,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 10,
					EndLine:   10,
					StartPos:  114,
					EndPos:    123,
				},
				Expr: &ast.ExprAssignDiv{
					Position: &position.Position{
						StartLine: 10,
						EndLine:   10,
						StartPos:  114,
						EndPos:    122,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 10,
							EndLine:   10,
							StartPos:  114,
							EndPos:    116,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 10,
								EndLine:   10,
								StartPos:  114,
								EndPos:    116,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 10,
									EndLine:   10,
									StartPos:  114,
									EndPos:    116,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 9,
											EndLine:   10,
											StartPos:  111,
											EndPos:    114,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_DIV_EQUAL,
						Value: []byte("/="),
						Position: &position.Position{
							StartLine: 10,
							EndLine:   10,
							StartPos:  117,
							EndPos:    119,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 10,
									EndLine:   10,
									StartPos:  116,
									EndPos:    117,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 10,
							EndLine:   10,
							StartPos:  120,
							EndPos:    122,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 10,
								EndLine:   10,
								StartPos:  120,
								EndPos:    122,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 10,
									EndLine:   10,
									StartPos:  120,
									EndPos:    122,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 10,
											EndLine:   10,
											StartPos:  119,
											EndPos:    120,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 10,
						EndLine:   10,
						StartPos:  122,
						EndPos:    123,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 11,
					EndLine:   11,
					StartPos:  126,
					EndPos:    135,
				},
				Expr: &ast.ExprAssignMinus{
					Position: &position.Position{
						StartLine: 11,
						EndLine:   11,
						StartPos:  126,
						EndPos:    134,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 11,
							EndLine:   11,
							StartPos:  126,
							EndPos:    128,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 11,
								EndLine:   11,
								StartPos:  126,
								EndPos:    128,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 11,
									EndLine:   11,
									StartPos:  126,
									EndPos:    128,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 10,
											EndLine:   11,
											StartPos:  123,
											EndPos:    126,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_MINUS_EQUAL,
						Value: []byte("-="),
						Position: &position.Position{
							StartLine: 11,
							EndLine:   11,
							StartPos:  129,
							EndPos:    131,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 11,
									EndLine:   11,
									StartPos:  128,
									EndPos:    129,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 11,
							EndLine:   11,
							StartPos:  132,
							EndPos:    134,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 11,
								EndLine:   11,
								StartPos:  132,
								EndPos:    134,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 11,
									EndLine:   11,
									StartPos:  132,
									EndPos:    134,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 11,
											EndLine:   11,
											StartPos:  131,
											EndPos:    132,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 11,
						EndLine:   11,
						StartPos:  134,
						EndPos:    135,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 12,
					EndLine:   12,
					StartPos:  138,
					EndPos:    147,
				},
				Expr: &ast.ExprAssignMod{
					Position: &position.Position{
						StartLine: 12,
						EndLine:   12,
						StartPos:  138,
						EndPos:    146,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 12,
							EndLine:   12,
							StartPos:  138,
							EndPos:    140,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 12,
								EndLine:   12,
								StartPos:  138,
								EndPos:    140,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 12,
									EndLine:   12,
									StartPos:  138,
									EndPos:    140,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 11,
											EndLine:   12,
											StartPos:  135,
											EndPos:    138,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_MOD_EQUAL,
						Value: []byte("%="),
						Position: &position.Position{
							StartLine: 12,
							EndLine:   12,
							StartPos:  141,
							EndPos:    143,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 12,
									EndLine:   12,
									StartPos:  140,
									EndPos:    141,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 12,
							EndLine:   12,
							StartPos:  144,
							EndPos:    146,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 12,
								EndLine:   12,
								StartPos:  144,
								EndPos:    146,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 12,
									EndLine:   12,
									StartPos:  144,
									EndPos:    146,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 12,
											EndLine:   12,
											StartPos:  143,
											EndPos:    144,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 12,
						EndLine:   12,
						StartPos:  146,
						EndPos:    147,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 13,
					EndLine:   13,
					StartPos:  150,
					EndPos:    159,
				},
				Expr: &ast.ExprAssignMul{
					Position: &position.Position{
						StartLine: 13,
						EndLine:   13,
						StartPos:  150,
						EndPos:    158,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 13,
							EndLine:   13,
							StartPos:  150,
							EndPos:    152,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 13,
								EndLine:   13,
								StartPos:  150,
								EndPos:    152,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 13,
									EndLine:   13,
									StartPos:  150,
									EndPos:    152,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 12,
											EndLine:   13,
											StartPos:  147,
											EndPos:    150,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_MUL_EQUAL,
						Value: []byte("*="),
						Position: &position.Position{
							StartLine: 13,
							EndLine:   13,
							StartPos:  153,
							EndPos:    155,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 13,
									EndLine:   13,
									StartPos:  152,
									EndPos:    153,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 13,
							EndLine:   13,
							StartPos:  156,
							EndPos:    158,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 13,
								EndLine:   13,
								StartPos:  156,
								EndPos:    158,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 13,
									EndLine:   13,
									StartPos:  156,
									EndPos:    158,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 13,
											EndLine:   13,
											StartPos:  155,
											EndPos:    156,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 13,
						EndLine:   13,
						StartPos:  158,
						EndPos:    159,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 14,
					EndLine:   14,
					StartPos:  162,
					EndPos:    171,
				},
				Expr: &ast.ExprAssignPlus{
					Position: &position.Position{
						StartLine: 14,
						EndLine:   14,
						StartPos:  162,
						EndPos:    170,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 14,
							EndLine:   14,
							StartPos:  162,
							EndPos:    164,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 14,
								EndLine:   14,
								StartPos:  162,
								EndPos:    164,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 14,
									EndLine:   14,
									StartPos:  162,
									EndPos:    164,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 13,
											EndLine:   14,
											StartPos:  159,
											EndPos:    162,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_PLUS_EQUAL,
						Value: []byte("+="),
						Position: &position.Position{
							StartLine: 14,
							EndLine:   14,
							StartPos:  165,
							EndPos:    167,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 14,
									EndLine:   14,
									StartPos:  164,
									EndPos:    165,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 14,
							EndLine:   14,
							StartPos:  168,
							EndPos:    170,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 14,
								EndLine:   14,
								StartPos:  168,
								EndPos:    170,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 14,
									EndLine:   14,
									StartPos:  168,
									EndPos:    170,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 14,
											EndLine:   14,
											StartPos:  167,
											EndPos:    168,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 14,
						EndLine:   14,
						StartPos:  170,
						EndPos:    171,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 15,
					EndLine:   15,
					StartPos:  174,
					EndPos:    184,
				},
				Expr: &ast.ExprAssignPow{
					Position: &position.Position{
						StartLine: 15,
						EndLine:   15,
						StartPos:  174,
						EndPos:    183,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 15,
							EndLine:   15,
							StartPos:  174,
							EndPos:    176,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 15,
								EndLine:   15,
								StartPos:  174,
								EndPos:    176,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 15,
									EndLine:   15,
									StartPos:  174,
									EndPos:    176,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 14,
											EndLine:   15,
											StartPos:  171,
											EndPos:    174,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_POW_EQUAL,
						Value: []byte("**="),
						Position: &position.Position{
							StartLine: 15,
							EndLine:   15,
							StartPos:  177,
							EndPos:    180,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 15,
									EndLine:   15,
									StartPos:  176,
									EndPos:    177,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 15,
							EndLine:   15,
							StartPos:  181,
							EndPos:    183,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 15,
								EndLine:   15,
								StartPos:  181,
								EndPos:    183,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 15,
									EndLine:   15,
									StartPos:  181,
									EndPos:    183,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 15,
											EndLine:   15,
											StartPos:  180,
											EndPos:    181,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 15,
						EndLine:   15,
						StartPos:  183,
						EndPos:    184,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 16,
					EndLine:   16,
					StartPos:  187,
					EndPos:    197,
				},
				Expr: &ast.ExprAssignShiftLeft{
					Position: &position.Position{
						StartLine: 16,
						EndLine:   16,
						StartPos:  187,
						EndPos:    196,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 16,
							EndLine:   16,
							StartPos:  187,
							EndPos:    189,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 16,
								EndLine:   16,
								StartPos:  187,
								EndPos:    189,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 16,
									EndLine:   16,
									StartPos:  187,
									EndPos:    189,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 15,
											EndLine:   16,
											StartPos:  184,
											EndPos:    187,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_SL_EQUAL,
						Value: []byte("<<="),
						Position: &position.Position{
							StartLine: 16,
							EndLine:   16,
							StartPos:  190,
							EndPos:    193,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 16,
									EndLine:   16,
									StartPos:  189,
									EndPos:    190,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 16,
							EndLine:   16,
							StartPos:  194,
							EndPos:    196,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 16,
								EndLine:   16,
								StartPos:  194,
								EndPos:    196,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 16,
									EndLine:   16,
									StartPos:  194,
									EndPos:    196,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 16,
											EndLine:   16,
											StartPos:  193,
											EndPos:    194,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 16,
						EndLine:   16,
						StartPos:  196,
						EndPos:    197,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 17,
					EndLine:   17,
					StartPos:  200,
					EndPos:    210,
				},
				Expr: &ast.ExprAssignShiftRight{
					Position: &position.Position{
						StartLine: 17,
						EndLine:   17,
						StartPos:  200,
						EndPos:    209,
					},
					Var: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 17,
							EndLine:   17,
							StartPos:  200,
							EndPos:    202,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 17,
								EndLine:   17,
								StartPos:  200,
								EndPos:    202,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 17,
									EndLine:   17,
									StartPos:  200,
									EndPos:    202,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 16,
											EndLine:   17,
											StartPos:  197,
											EndPos:    200,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					EqualTkn: &token.Token{
						ID:    token.T_SR_EQUAL,
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

// expr binary

func TestExprBinary_BitwiseAnd(t *testing.T) {
	src := `<?
		$a & $b;
		$a | $b;
		$a ^ $b;
		$a && $b;
		$a || $b;
		$a ?? $b;
		$a . $b;
		$a / $b;
		$a == $b;
		$a >= $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: 1,
											EndLine:   1,
											StartPos:  0,
											EndPos:    2,
										},
									},
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 1,
											EndLine:   2,
											StartPos:  2,
											EndPos:    5,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpTkn: &token.Token{
						ID:    token.ID(38),
						Value: []byte("&"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  8,
							EndPos:    9,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  7,
									EndPos:    8,
								},
							},
						},
					},
					Right: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  10,
							EndPos:    12,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  10,
								EndPos:    12,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  10,
									EndPos:    12,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 2,
											EndLine:   2,
											StartPos:  9,
											EndPos:    10,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  12,
						EndPos:    13,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 3,
					EndLine:   3,
					StartPos:  16,
					EndPos:    24,
				},
				Expr: &ast.ExprBinaryBitwiseOr{
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  16,
						EndPos:    23,
					},
					Left: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  16,
							EndPos:    18,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  16,
								EndPos:    18,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  16,
									EndPos:    18,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 2,
											EndLine:   3,
											StartPos:  13,
											EndPos:    16,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpTkn: &token.Token{
						ID:    token.ID(124),
						Value: []byte("|"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  19,
							EndPos:    20,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  18,
									EndPos:    19,
								},
							},
						},
					},
					Right: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  21,
							EndPos:    23,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  21,
								EndPos:    23,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  21,
									EndPos:    23,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   3,
											StartPos:  20,
											EndPos:    21,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  23,
						EndPos:    24,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 4,
					EndLine:   4,
					StartPos:  27,
					EndPos:    35,
				},
				Expr: &ast.ExprBinaryBitwiseXor{
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  27,
						EndPos:    34,
					},
					Left: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  27,
							EndPos:    29,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  27,
								EndPos:    29,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  27,
									EndPos:    29,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 3,
											EndLine:   4,
											StartPos:  24,
											EndPos:    27,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpTkn: &token.Token{
						ID:    token.ID(94),
						Value: []byte("^"),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  30,
							EndPos:    31,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  29,
									EndPos:    30,
								},
							},
						},
					},
					Right: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  32,
							EndPos:    34,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  32,
								EndPos:    34,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  32,
									EndPos:    34,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 4,
											EndLine:   4,
											StartPos:  31,
											EndPos:    32,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  34,
						EndPos:    35,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 5,
					EndLine:   5,
					StartPos:  38,
					EndPos:    47,
				},
				Expr: &ast.ExprBinaryBooleanAnd{
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  38,
						EndPos:    46,
					},
					Left: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  38,
							EndPos:    40,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  38,
								EndPos:    40,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  38,
									EndPos:    40,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 4,
											EndLine:   5,
											StartPos:  35,
											EndPos:    38,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpTkn: &token.Token{
						ID:    token.T_BOOLEAN_AND,
						Value: []byte("&&"),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  41,
							EndPos:    43,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  40,
									EndPos:    41,
								},
							},
						},
					},
					Right: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  44,
							EndPos:    46,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  44,
								EndPos:    46,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  44,
									EndPos:    46,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 5,
											EndLine:   5,
											StartPos:  43,
											EndPos:    44,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  46,
						EndPos:    47,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 6,
					EndLine:   6,
					StartPos:  50,
					EndPos:    59,
				},
				Expr: &ast.ExprBinaryBooleanOr{
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  50,
						EndPos:    58,
					},
					Left: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 6,
							EndLine:   6,
							StartPos:  50,
							EndPos:    52,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 6,
								EndLine:   6,
								StartPos:  50,
								EndPos:    52,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 6,
									EndLine:   6,
									StartPos:  50,
									EndPos:    52,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 5,
											EndLine:   6,
											StartPos:  47,
											EndPos:    50,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpTkn: &token.Token{
						ID:    token.T_BOOLEAN_OR,
						Value: []byte("||"),
						Position: &position.Position{
							StartLine: 6,
							EndLine:   6,
							StartPos:  53,
							EndPos:    55,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 6,
									EndLine:   6,
									StartPos:  52,
									EndPos:    53,
								},
							},
						},
					},
					Right: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 6,
							EndLine:   6,
							StartPos:  56,
							EndPos:    58,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 6,
								EndLine:   6,
								StartPos:  56,
								EndPos:    58,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 6,
									EndLine:   6,
									StartPos:  56,
									EndPos:    58,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 6,
											EndLine:   6,
											StartPos:  55,
											EndPos:    56,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  58,
						EndPos:    59,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 7,
					EndLine:   7,
					StartPos:  62,
					EndPos:    71,
				},
				Expr: &ast.ExprBinaryCoalesce{
					Position: &position.Position{
						StartLine: 7,
						EndLine:   7,
						StartPos:  62,
						EndPos:    70,
					},
					Left: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 7,
							EndLine:   7,
							StartPos:  62,
							EndPos:    64,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 7,
								EndLine:   7,
								StartPos:  62,
								EndPos:    64,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 7,
									EndLine:   7,
									StartPos:  62,
									EndPos:    64,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 6,
											EndLine:   7,
											StartPos:  59,
											EndPos:    62,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpTkn: &token.Token{
						ID:    token.T_COALESCE,
						Value: []byte("??"),
						Position: &position.Position{
							StartLine: 7,
							EndLine:   7,
							StartPos:  65,
							EndPos:    67,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 7,
									EndLine:   7,
									StartPos:  64,
									EndPos:    65,
								},
							},
						},
					},
					Right: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 7,
							EndLine:   7,
							StartPos:  68,
							EndPos:    70,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 7,
								EndLine:   7,
								StartPos:  68,
								EndPos:    70,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 7,
									EndLine:   7,
									StartPos:  68,
									EndPos:    70,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 7,
											EndLine:   7,
											StartPos:  67,
											EndPos:    68,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 7,
						EndLine:   7,
						StartPos:  70,
						EndPos:    71,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 8,
					EndLine:   8,
					StartPos:  74,
					EndPos:    82,
				},
				Expr: &ast.ExprBinaryConcat{
					Position: &position.Position{
						StartLine: 8,
						EndLine:   8,
						StartPos:  74,
						EndPos:    81,
					},
					Left: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 8,
							EndLine:   8,
							StartPos:  74,
							EndPos:    76,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 8,
								EndLine:   8,
								StartPos:  74,
								EndPos:    76,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 8,
									EndLine:   8,
									StartPos:  74,
									EndPos:    76,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 7,
											EndLine:   8,
											StartPos:  71,
											EndPos:    74,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpTkn: &token.Token{
						ID:    token.ID(46),
						Value: []byte("."),
						Position: &position.Position{
							StartLine: 8,
							EndLine:   8,
							StartPos:  77,
							EndPos:    78,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 8,
									EndLine:   8,
									StartPos:  76,
									EndPos:    77,
								},
							},
						},
					},
					Right: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 8,
							EndLine:   8,
							StartPos:  79,
							EndPos:    81,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 8,
								EndLine:   8,
								StartPos:  79,
								EndPos:    81,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 8,
									EndLine:   8,
									StartPos:  79,
									EndPos:    81,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 8,
											EndLine:   8,
											StartPos:  78,
											EndPos:    79,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 8,
						EndLine:   8,
						StartPos:  81,
						EndPos:    82,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 9,
					EndLine:   9,
					StartPos:  85,
					EndPos:    93,
				},
				Expr: &ast.ExprBinaryDiv{
					Position: &position.Position{
						StartLine: 9,
						EndLine:   9,
						StartPos:  85,
						EndPos:    92,
					},
					Left: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 9,
							EndLine:   9,
							StartPos:  85,
							EndPos:    87,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 9,
								EndLine:   9,
								StartPos:  85,
								EndPos:    87,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 9,
									EndLine:   9,
									StartPos:  85,
									EndPos:    87,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 8,
											EndLine:   9,
											StartPos:  82,
											EndPos:    85,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpTkn: &token.Token{
						ID:    token.ID(47),
						Value: []byte("/"),
						Position: &position.Position{
							StartLine: 9,
							EndLine:   9,
							StartPos:  88,
							EndPos:    89,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 9,
									EndLine:   9,
									StartPos:  87,
									EndPos:    88,
								},
							},
						},
					},
					Right: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 9,
							EndLine:   9,
							StartPos:  90,
							EndPos:    92,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 9,
								EndLine:   9,
								StartPos:  90,
								EndPos:    92,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 9,
									EndLine:   9,
									StartPos:  90,
									EndPos:    92,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 9,
											EndLine:   9,
											StartPos:  89,
											EndPos:    90,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 9,
						EndLine:   9,
						StartPos:  92,
						EndPos:    93,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 10,
					EndLine:   10,
					StartPos:  96,
					EndPos:    105,
				},
				Expr: &ast.ExprBinaryEqual{
					Position: &position.Position{
						StartLine: 10,
						EndLine:   10,
						StartPos:  96,
						EndPos:    104,
					},
					Left: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 10,
							EndLine:   10,
							StartPos:  96,
							EndPos:    98,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 10,
								EndLine:   10,
								StartPos:  96,
								EndPos:    98,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 10,
									EndLine:   10,
									StartPos:  96,
									EndPos:    98,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 9,
											EndLine:   10,
											StartPos:  93,
											EndPos:    96,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpTkn: &token.Token{
						ID:    token.T_IS_EQUAL,
						Value: []byte("=="),
						Position: &position.Position{
							StartLine: 10,
							EndLine:   10,
							StartPos:  99,
							EndPos:    101,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte(" "),
								Position: &position.Position{
									StartLine: 10,
									EndLine:   10,
									StartPos:  98,
									EndPos:    99,
								},
							},
						},
					},
					Right: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 10,
							EndLine:   10,
							StartPos:  102,
							EndPos:    104,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 10,
								EndLine:   10,
								StartPos:  102,
								EndPos:    104,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$b"),
								Position: &position.Position{
									StartLine: 10,
									EndLine:   10,
									StartPos:  102,
									EndPos:    104,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte(" "),
										Position: &position.Position{
											StartLine: 10,
											EndLine:   10,
											StartPos:  101,
											EndPos:    102,
										},
									},
								},
							},
							Value: []byte("$b"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 10,
						EndLine:   10,
						StartPos:  104,
						EndPos:    105,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 11,
					EndLine:   11,
					StartPos:  108,
					EndPos:    117,
				},
				Expr: &ast.ExprBinaryGreaterOrEqual{
					Position: &position.Position{
						StartLine: 11,
						EndLine:   11,
						StartPos:  108,
						EndPos:    116,
					},
					Left: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 11,
							EndLine:   11,
							StartPos:  108,
							EndPos:    110,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 11,
								EndLine:   11,
								StartPos:  108,
								EndPos:    110,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 11,
									EndLine:   11,
									StartPos:  108,
									EndPos:    110,
								},
								FreeFloating: []*token.Token{
									{
										ID:    token.T_WHITESPACE,
										Value: []byte("\n\t\t"),
										Position: &position.Position{
											StartLine: 10,
											EndLine:   11,
											StartPos:  105,
											EndPos:    108,
										},
									},
								},
							},
							Value: []byte("$a"),
						},
					},
					OpTkn: &token.Token{
						ID:    token.T_IS_GREATER_OR_EQUAL,
						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 := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

// expr cast

func TestExprCast_Array(t *testing.T) {
	src := `<?
		(array)$a;
		(boolean)$a;
		(bool)$a;
		(double)$a;
		(float)$a;
		(integer)$a;
		(int)$a;
		(object)$a;
		(string)$a;
		(binary)$a;
		(unset)$a;`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   12,
			StartPos:  5,
			EndPos:    150,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   2,
					StartPos:  5,
					EndPos:    15,
				},
				Expr: &ast.ExprCastArray{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  5,
						EndPos:    14,
					},
					CastTkn: &token.Token{
						ID:    token.T_ARRAY_CAST,
						Value: []byte("(array)"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  5,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   2,
									StartPos:  2,
									EndPos:    5,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  12,
							EndPos:    14,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 2,
								EndLine:   2,
								StartPos:  12,
								EndPos:    14,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   2,
									StartPos:  12,
									EndPos:    14,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  14,
						EndPos:    15,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 3,
					EndLine:   3,
					StartPos:  18,
					EndPos:    30,
				},
				Expr: &ast.ExprCastBool{
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  18,
						EndPos:    29,
					},
					CastTkn: &token.Token{
						ID:    token.T_BOOL_CAST,
						Value: []byte("(boolean)"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  18,
							EndPos:    27,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   3,
									StartPos:  15,
									EndPos:    18,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  27,
							EndPos:    29,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 3,
								EndLine:   3,
								StartPos:  27,
								EndPos:    29,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   3,
									StartPos:  27,
									EndPos:    29,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  29,
						EndPos:    30,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 4,
					EndLine:   4,
					StartPos:  33,
					EndPos:    42,
				},
				Expr: &ast.ExprCastBool{
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  33,
						EndPos:    41,
					},
					CastTkn: &token.Token{
						ID:    token.T_BOOL_CAST,
						Value: []byte("(bool)"),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  33,
							EndPos:    39,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   4,
									StartPos:  30,
									EndPos:    33,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  39,
							EndPos:    41,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 4,
								EndLine:   4,
								StartPos:  39,
								EndPos:    41,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   4,
									StartPos:  39,
									EndPos:    41,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 4,
						EndLine:   4,
						StartPos:  41,
						EndPos:    42,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 5,
					EndLine:   5,
					StartPos:  45,
					EndPos:    56,
				},
				Expr: &ast.ExprCastDouble{
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  45,
						EndPos:    55,
					},
					CastTkn: &token.Token{
						ID:    token.T_DOUBLE_CAST,
						Value: []byte("(double)"),
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  45,
							EndPos:    53,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 4,
									EndLine:   5,
									StartPos:  42,
									EndPos:    45,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 5,
							EndLine:   5,
							StartPos:  53,
							EndPos:    55,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  53,
								EndPos:    55,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  53,
									EndPos:    55,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 5,
						EndLine:   5,
						StartPos:  55,
						EndPos:    56,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 6,
					EndLine:   6,
					StartPos:  59,
					EndPos:    69,
				},
				Expr: &ast.ExprCastDouble{
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  59,
						EndPos:    68,
					},
					CastTkn: &token.Token{
						ID:    token.T_DOUBLE_CAST,
						Value: []byte("(float)"),
						Position: &position.Position{
							StartLine: 6,
							EndLine:   6,
							StartPos:  59,
							EndPos:    66,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   6,
									StartPos:  56,
									EndPos:    59,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 6,
							EndLine:   6,
							StartPos:  66,
							EndPos:    68,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 6,
								EndLine:   6,
								StartPos:  66,
								EndPos:    68,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 6,
									EndLine:   6,
									StartPos:  66,
									EndPos:    68,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  68,
						EndPos:    69,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 7,
					EndLine:   7,
					StartPos:  72,
					EndPos:    84,
				},
				Expr: &ast.ExprCastInt{
					Position: &position.Position{
						StartLine: 7,
						EndLine:   7,
						StartPos:  72,
						EndPos:    83,
					},
					CastTkn: &token.Token{
						ID:    token.T_INT_CAST,
						Value: []byte("(integer)"),
						Position: &position.Position{
							StartLine: 7,
							EndLine:   7,
							StartPos:  72,
							EndPos:    81,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 6,
									EndLine:   7,
									StartPos:  69,
									EndPos:    72,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 7,
							EndLine:   7,
							StartPos:  81,
							EndPos:    83,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 7,
								EndLine:   7,
								StartPos:  81,
								EndPos:    83,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 7,
									EndLine:   7,
									StartPos:  81,
									EndPos:    83,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 7,
						EndLine:   7,
						StartPos:  83,
						EndPos:    84,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 8,
					EndLine:   8,
					StartPos:  87,
					EndPos:    95,
				},
				Expr: &ast.ExprCastInt{
					Position: &position.Position{
						StartLine: 8,
						EndLine:   8,
						StartPos:  87,
						EndPos:    94,
					},
					CastTkn: &token.Token{
						ID:    token.T_INT_CAST,
						Value: []byte("(int)"),
						Position: &position.Position{
							StartLine: 8,
							EndLine:   8,
							StartPos:  87,
							EndPos:    92,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 7,
									EndLine:   8,
									StartPos:  84,
									EndPos:    87,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 8,
							EndLine:   8,
							StartPos:  92,
							EndPos:    94,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 8,
								EndLine:   8,
								StartPos:  92,
								EndPos:    94,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 8,
									EndLine:   8,
									StartPos:  92,
									EndPos:    94,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 8,
						EndLine:   8,
						StartPos:  94,
						EndPos:    95,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 9,
					EndLine:   9,
					StartPos:  98,
					EndPos:    109,
				},
				Expr: &ast.ExprCastObject{
					Position: &position.Position{
						StartLine: 9,
						EndLine:   9,
						StartPos:  98,
						EndPos:    108,
					},
					CastTkn: &token.Token{
						ID:    token.T_OBJECT_CAST,
						Value: []byte("(object)"),
						Position: &position.Position{
							StartLine: 9,
							EndLine:   9,
							StartPos:  98,
							EndPos:    106,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 8,
									EndLine:   9,
									StartPos:  95,
									EndPos:    98,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 9,
							EndLine:   9,
							StartPos:  106,
							EndPos:    108,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 9,
								EndLine:   9,
								StartPos:  106,
								EndPos:    108,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 9,
									EndLine:   9,
									StartPos:  106,
									EndPos:    108,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 9,
						EndLine:   9,
						StartPos:  108,
						EndPos:    109,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 10,
					EndLine:   10,
					StartPos:  112,
					EndPos:    123,
				},
				Expr: &ast.ExprCastString{
					Position: &position.Position{
						StartLine: 10,
						EndLine:   10,
						StartPos:  112,
						EndPos:    122,
					},
					CastTkn: &token.Token{
						ID:    token.T_STRING_CAST,
						Value: []byte("(string)"),
						Position: &position.Position{
							StartLine: 10,
							EndLine:   10,
							StartPos:  112,
							EndPos:    120,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 9,
									EndLine:   10,
									StartPos:  109,
									EndPos:    112,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 10,
							EndLine:   10,
							StartPos:  120,
							EndPos:    122,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 10,
								EndLine:   10,
								StartPos:  120,
								EndPos:    122,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 10,
									EndLine:   10,
									StartPos:  120,
									EndPos:    122,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 10,
						EndLine:   10,
						StartPos:  122,
						EndPos:    123,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 11,
					EndLine:   11,
					StartPos:  126,
					EndPos:    137,
				},
				Expr: &ast.ExprCastString{
					Position: &position.Position{
						StartLine: 11,
						EndLine:   11,
						StartPos:  126,
						EndPos:    136,
					},
					CastTkn: &token.Token{
						ID:    token.T_STRING_CAST,
						Value: []byte("(binary)"),
						Position: &position.Position{
							StartLine: 11,
							EndLine:   11,
							StartPos:  126,
							EndPos:    134,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 10,
									EndLine:   11,
									StartPos:  123,
									EndPos:    126,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 11,
							EndLine:   11,
							StartPos:  134,
							EndPos:    136,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 11,
								EndLine:   11,
								StartPos:  134,
								EndPos:    136,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 11,
									EndLine:   11,
									StartPos:  134,
									EndPos:    136,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 11,
						EndLine:   11,
						StartPos:  136,
						EndPos:    137,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 12,
					EndLine:   12,
					StartPos:  140,
					EndPos:    150,
				},
				Expr: &ast.ExprCastUnset{
					Position: &position.Position{
						StartLine: 12,
						EndLine:   12,
						StartPos:  140,
						EndPos:    149,
					},
					CastTkn: &token.Token{
						ID:    token.T_UNSET_CAST,
						Value: []byte("(unset)"),
						Position: &position.Position{
							StartLine: 12,
							EndLine:   12,
							StartPos:  140,
							EndPos:    147,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 11,
									EndLine:   12,
									StartPos:  137,
									EndPos:    140,
								},
							},
						},
					},
					Expr: &ast.ExprVariable{
						Position: &position.Position{
							StartLine: 12,
							EndLine:   12,
							StartPos:  147,
							EndPos:    149,
						},
						Name: &ast.Identifier{
							Position: &position.Position{
								StartLine: 12,
								EndLine:   12,
								StartPos:  147,
								EndPos:    149,
							},
							IdentifierTkn: &token.Token{
								ID:    token.T_VARIABLE,
								Value: []byte("$a"),
								Position: &position.Position{
									StartLine: 12,
									EndLine:   12,
									StartPos:  147,
									EndPos:    149,
								},
							},
							Value: []byte("$a"),
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 12,
						EndLine:   12,
						StartPos:  149,
						EndPos:    150,
					},
				},
			},
		},
		EndTkn: &token.Token{},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestStrings(t *testing.T) {
	src := `<?
		"test";
		"\$test";
		"
			test
		";
		'$test';
		'
			$test
		';
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   10,
			StartPos:  5,
			EndPos:    70,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   2,
					StartPos:  5,
					EndPos:    12,
				},
				Expr: &ast.ScalarString{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  5,
						EndPos:    11,
					},
					StringTkn: &token.Token{
						ID:    token.T_CONSTANT_ENCAPSED_STRING,
						Value: []byte("\"test\""),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  5,
							EndPos:    11,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   2,
									StartPos:  2,
									EndPos:    5,
								},
							},
						},
					},
					Value: []byte("\"test\""),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 2,
						EndLine:   2,
						StartPos:  11,
						EndPos:    12,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 3,
					EndLine:   3,
					StartPos:  15,
					EndPos:    24,
				},
				Expr: &ast.ScalarString{
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  15,
						EndPos:    23,
					},
					StringTkn: &token.Token{
						ID:    token.T_CONSTANT_ENCAPSED_STRING,
						Value: []byte("\"\\$test\""),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  15,
							EndPos:    23,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 2,
									EndLine:   3,
									StartPos:  12,
									EndPos:    15,
								},
							},
						},
					},
					Value: []byte("\"\\$test\""),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  23,
						EndPos:    24,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 4,
					EndLine:   6,
					StartPos:  27,
					EndPos:    41,
				},
				Expr: &ast.ScalarString{
					Position: &position.Position{
						StartLine: 4,
						EndLine:   6,
						StartPos:  27,
						EndPos:    40,
					},
					StringTkn: &token.Token{
						ID:    token.T_CONSTANT_ENCAPSED_STRING,
						Value: []byte("\"\n\t\t\ttest\n\t\t\""),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   6,
							StartPos:  27,
							EndPos:    40,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   4,
									StartPos:  24,
									EndPos:    27,
								},
							},
						},
					},
					Value: []byte("\"\n\t\t\ttest\n\t\t\""),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  40,
						EndPos:    41,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 7,
					EndLine:   7,
					StartPos:  44,
					EndPos:    52,
				},
				Expr: &ast.ScalarString{
					Position: &position.Position{
						StartLine: 7,
						EndLine:   7,
						StartPos:  44,
						EndPos:    51,
					},
					StringTkn: &token.Token{
						ID:    token.T_CONSTANT_ENCAPSED_STRING,
						Value: []byte("'$test'"),
						Position: &position.Position{
							StartLine: 7,
							EndLine:   7,
							StartPos:  44,
							EndPos:    51,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 6,
									EndLine:   7,
									StartPos:  41,
									EndPos:    44,
								},
							},
						},
					},
					Value: []byte("'$test'"),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 7,
						EndLine:   7,
						StartPos:  51,
						EndPos:    52,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 8,
					EndLine:   10,
					StartPos:  55,
					EndPos:    70,
				},
				Expr: &ast.ScalarString{
					Position: &position.Position{
						StartLine: 8,
						EndLine:   10,
						StartPos:  55,
						EndPos:    69,
					},
					StringTkn: &token.Token{
						ID:    token.T_CONSTANT_ENCAPSED_STRING,
						Value: []byte("'\n\t\t\t$test\n\t\t'"),
						Position: &position.Position{
							StartLine: 8,
							EndLine:   10,
							StartPos:  55,
							EndPos:    69,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 7,
									EndLine:   8,
									StartPos:  52,
									EndPos:    55,
								},
							},
						},
					},
					Value: []byte("'\n\t\t\t$test\n\t\t'"),
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 10,
						EndLine:   10,
						StartPos:  69,
						EndPos:    70,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 10,
						EndLine:   11,
						StartPos:  70,
						EndPos:    72,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestHeredoc(t *testing.T) {
	src := `<?
		<<<CAD
CAD;
		<<<CAD
	hello
CAD;
		<<<"CAD"
	hello
CAD;
		<<<"CAD"
	hello $world
CAD;
		<<<'CAD'
	hello $world
CAD;
	`

	expected := &ast.Root{
		Position: &position.Position{
			StartLine: 2,
			EndLine:   15,
			StartPos:  5,
			EndPos:    120,
		},
		Stmts: []ast.Vertex{
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 2,
					EndLine:   3,
					StartPos:  5,
					EndPos:    16,
				},
				Expr: &ast.ScalarHeredoc{
					Position: &position.Position{
						StartLine: 2,
						EndLine:   3,
						StartPos:  5,
						EndPos:    15,
					},
					OpenHeredocTkn: &token.Token{
						ID:    token.T_START_HEREDOC,
						Value: []byte("<<<CAD\n"),
						Position: &position.Position{
							StartLine: 2,
							EndLine:   2,
							StartPos:  5,
							EndPos:    12,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_OPEN_TAG,
								Value: []byte("<?"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   1,
									StartPos:  0,
									EndPos:    2,
								},
							},
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 1,
									EndLine:   2,
									StartPos:  2,
									EndPos:    5,
								},
							},
						},
					},
					CloseHeredocTkn: &token.Token{
						ID:    token.T_END_HEREDOC,
						Value: []byte("AD"),
						Position: &position.Position{
							StartLine: 3,
							EndLine:   3,
							StartPos:  13,
							EndPos:    15,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 3,
						EndLine:   3,
						StartPos:  15,
						EndPos:    16,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 4,
					EndLine:   6,
					StartPos:  19,
					EndPos:    37,
				},
				Expr: &ast.ScalarHeredoc{
					Position: &position.Position{
						StartLine: 4,
						EndLine:   6,
						StartPos:  19,
						EndPos:    36,
					},
					OpenHeredocTkn: &token.Token{
						ID:    token.T_START_HEREDOC,
						Value: []byte("<<<CAD\n"),
						Position: &position.Position{
							StartLine: 4,
							EndLine:   4,
							StartPos:  19,
							EndPos:    26,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 3,
									EndLine:   4,
									StartPos:  16,
									EndPos:    19,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 5,
								EndLine:   5,
								StartPos:  26,
								EndPos:    33,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("\thello\n"),
								Position: &position.Position{
									StartLine: 5,
									EndLine:   5,
									StartPos:  26,
									EndPos:    33,
								},
							},
							Value: []byte("\thello\n"),
						},
					},
					CloseHeredocTkn: &token.Token{
						ID:    token.T_END_HEREDOC,
						Value: []byte("CAD"),
						Position: &position.Position{
							StartLine: 6,
							EndLine:   6,
							StartPos:  33,
							EndPos:    36,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 6,
						EndLine:   6,
						StartPos:  36,
						EndPos:    37,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 7,
					EndLine:   9,
					StartPos:  40,
					EndPos:    60,
				},
				Expr: &ast.ScalarHeredoc{
					Position: &position.Position{
						StartLine: 7,
						EndLine:   9,
						StartPos:  40,
						EndPos:    59,
					},
					OpenHeredocTkn: &token.Token{
						ID:    token.T_START_HEREDOC,
						Value: []byte("<<<\"CAD\"\n"),
						Position: &position.Position{
							StartLine: 7,
							EndLine:   7,
							StartPos:  40,
							EndPos:    49,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 6,
									EndLine:   7,
									StartPos:  37,
									EndPos:    40,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 8,
								EndLine:   8,
								StartPos:  49,
								EndPos:    56,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("\thello\n"),
								Position: &position.Position{
									StartLine: 8,
									EndLine:   8,
									StartPos:  49,
									EndPos:    56,
								},
							},
							Value: []byte("\thello\n"),
						},
					},
					CloseHeredocTkn: &token.Token{
						ID:    token.T_END_HEREDOC,
						Value: []byte("CAD"),
						Position: &position.Position{
							StartLine: 9,
							EndLine:   9,
							StartPos:  56,
							EndPos:    59,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 9,
						EndLine:   9,
						StartPos:  59,
						EndPos:    60,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 10,
					EndLine:   12,
					StartPos:  63,
					EndPos:    90,
				},
				Expr: &ast.ScalarHeredoc{
					Position: &position.Position{
						StartLine: 10,
						EndLine:   12,
						StartPos:  63,
						EndPos:    89,
					},
					OpenHeredocTkn: &token.Token{
						ID:    token.T_START_HEREDOC,
						Value: []byte("<<<\"CAD\"\n"),
						Position: &position.Position{
							StartLine: 10,
							EndLine:   10,
							StartPos:  63,
							EndPos:    72,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 9,
									EndLine:   10,
									StartPos:  60,
									EndPos:    63,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 11,
								EndLine:   11,
								StartPos:  72,
								EndPos:    79,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("\thello "),
								Position: &position.Position{
									StartLine: 11,
									EndLine:   11,
									StartPos:  72,
									EndPos:    79,
								},
							},
							Value: []byte("\thello "),
						},
						&ast.ExprVariable{
							Position: &position.Position{
								StartLine: 11,
								EndLine:   11,
								StartPos:  79,
								EndPos:    85,
							},
							Name: &ast.Identifier{
								Position: &position.Position{
									StartLine: 11,
									EndLine:   11,
									StartPos:  79,
									EndPos:    85,
								},
								IdentifierTkn: &token.Token{
									ID:    token.T_VARIABLE,
									Value: []byte("$world"),
									Position: &position.Position{
										StartLine: 11,
										EndLine:   11,
										StartPos:  79,
										EndPos:    85,
									},
								},
								Value: []byte("$world"),
							},
						},
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 11,
								EndLine:   11,
								StartPos:  85,
								EndPos:    86,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("\n"),
								Position: &position.Position{
									StartLine: 11,
									EndLine:   11,
									StartPos:  85,
									EndPos:    86,
								},
							},
							Value: []byte("\n"),
						},
					},
					CloseHeredocTkn: &token.Token{
						ID:    token.T_END_HEREDOC,
						Value: []byte("CAD"),
						Position: &position.Position{
							StartLine: 12,
							EndLine:   12,
							StartPos:  86,
							EndPos:    89,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 12,
						EndLine:   12,
						StartPos:  89,
						EndPos:    90,
					},
				},
			},
			&ast.StmtExpression{
				Position: &position.Position{
					StartLine: 13,
					EndLine:   15,
					StartPos:  93,
					EndPos:    120,
				},
				Expr: &ast.ScalarHeredoc{
					Position: &position.Position{
						StartLine: 13,
						EndLine:   15,
						StartPos:  93,
						EndPos:    119,
					},
					OpenHeredocTkn: &token.Token{
						ID:    token.T_START_HEREDOC,
						Value: []byte("<<<'CAD'\n"),
						Position: &position.Position{
							StartLine: 13,
							EndLine:   13,
							StartPos:  93,
							EndPos:    102,
						},
						FreeFloating: []*token.Token{
							{
								ID:    token.T_WHITESPACE,
								Value: []byte("\n\t\t"),
								Position: &position.Position{
									StartLine: 12,
									EndLine:   13,
									StartPos:  90,
									EndPos:    93,
								},
							},
						},
					},
					Parts: []ast.Vertex{
						&ast.ScalarEncapsedStringPart{
							Position: &position.Position{
								StartLine: 14,
								EndLine:   14,
								StartPos:  102,
								EndPos:    116,
							},
							EncapsedStrTkn: &token.Token{
								ID:    token.T_ENCAPSED_AND_WHITESPACE,
								Value: []byte("\thello $world\n"),
								Position: &position.Position{
									StartLine: 14,
									EndLine:   14,
									StartPos:  102,
									EndPos:    116,
								},
							},
							Value: []byte("\thello $world\n"),
						},
					},
					CloseHeredocTkn: &token.Token{
						ID:    token.T_END_HEREDOC,
						Value: []byte("CAD"),
						Position: &position.Position{
							StartLine: 15,
							EndLine:   15,
							StartPos:  116,
							EndPos:    119,
						},
					},
				},
				SemiColonTkn: &token.Token{
					ID:    token.ID(59),
					Value: []byte(";"),
					Position: &position.Position{
						StartLine: 15,
						EndLine:   15,
						StartPos:  119,
						EndPos:    120,
					},
				},
			},
		},
		EndTkn: &token.Token{
			FreeFloating: []*token.Token{
				{
					ID:    token.T_WHITESPACE,
					Value: []byte("\n\t"),
					Position: &position.Position{
						StartLine: 15,
						EndLine:   16,
						StartPos:  120,
						EndPos:    122,
					},
				},
			},
		},
	}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	actual := php7parser.GetRootNode()
	assert.DeepEqual(t, expected, actual)
}

func TestControlCharsErrors(t *testing.T) {
	src := "<?php \004 echo $b; \"$a[\005test]\";"

	expected := []*errors.Error{
		{
			Msg: "WARNING: Unexpected character in input: '\004' (ASCII=4)",
			Pos: &position.Position{StartLine: 1, EndLine: 1, StartPos: 6, EndPos: 7},
		},
		{
			Msg: "WARNING: Unexpected character in input: '\005' (ASCII=5)",
			Pos: &position.Position{StartLine: 1, EndLine: 1, StartPos: 21, EndPos: 22},
		},
	}

	parserErrors := []*errors.Error{}

	config := conf.Config{
		Version: &version.Version{
			Major: 7,
			Minor: 4,
		},
		ErrorHandlerFunc: func(e *errors.Error) {
			parserErrors = append(parserErrors, e)
		},
	}
	lexer := scanner.NewLexer([]byte(src), config)
	php7parser := php7.NewParser(lexer, config)
	php7parser.Parse()
	assert.DeepEqual(t, expected, parserErrors)
}
