php8.1: added intersection types support (#29)
This commit is contained in:
		
							parent
							
								
									7f6cd25376
								
							
						
					
					
						commit
						e16671724e
					
				| @ -789,6 +789,24 @@ func (b *Builder) NewUnionType( | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (b *Builder) NewIntersectionType( | ||||
| 	Types ast.Vertex, | ||||
| ) *ast.Intersection { | ||||
| 	var types []ast.Vertex | ||||
| 	var sepTkns []*token.Token | ||||
| 	if Types != nil { | ||||
| 		cases := Types.(*ParserSeparatedList) | ||||
| 		types = cases.Items | ||||
| 		sepTkns = cases.SeparatorTkns | ||||
| 	} | ||||
| 
 | ||||
| 	return &ast.Intersection{ | ||||
| 		Position:      b.Pos.NewNodeListPosition(types), | ||||
| 		Types:         types, | ||||
| 		SeparatorTkns: sepTkns, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (b *Builder) NewReturnType( | ||||
| 	ColonTkn *token.Token, | ||||
| 	Type ast.Vertex, | ||||
|  | ||||
| @ -227,6 +227,21 @@ func (lex *Lexer) ungetCnt(n int) { | ||||
| 	lex.te = lex.te - n | ||||
| } | ||||
| 
 | ||||
| func (lex *Lexer) ungetWhile(s byte) { | ||||
| 	for i := 0; i < 100; i++ { | ||||
| 		v := lex.data[lex.te] | ||||
| 		if v == s { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		lex.te-- | ||||
| 		lex.p-- | ||||
| 	} | ||||
| 
 | ||||
| 	lex.te++ | ||||
| 	lex.p++ | ||||
| } | ||||
| 
 | ||||
| func (lex *Lexer) error(msg string) { | ||||
| 	if lex.errHandlerFunc == nil { | ||||
| 		return | ||||
|  | ||||
| @ -322,3 +322,114 @@ enum C: int implements Bar {} | ||||
| 
 | ||||
| 	suite.Run() | ||||
| } | ||||
| 
 | ||||
| func TestIntersectionTypes(t *testing.T) { | ||||
| 	suite := tester.NewParserDumpTestSuite(t) | ||||
| 	suite.UsePHP8() | ||||
| 	suite.Code = `<?php | ||||
| class Test { | ||||
|     public A&B $prop; | ||||
| } | ||||
| 
 | ||||
| function test(A&B $a): A&B {} | ||||
| ` | ||||
| 
 | ||||
| 	suite.Expected = `&ast.Root{ | ||||
| 	Stmts: []ast.Vertex{ | ||||
| 		&ast.StmtClass{ | ||||
| 			Name: &ast.Identifier{ | ||||
| 				Val: []byte("Test"), | ||||
| 			}, | ||||
| 			Stmts: []ast.Vertex{ | ||||
| 				&ast.StmtPropertyList{ | ||||
| 					Modifiers: []ast.Vertex{ | ||||
| 						&ast.Identifier{ | ||||
| 							Val: []byte("public"), | ||||
| 						}, | ||||
| 					}, | ||||
| 					Type: &ast.Intersection{ | ||||
| 						Types: []ast.Vertex{ | ||||
| 							&ast.Name{ | ||||
| 								Parts: []ast.Vertex{ | ||||
| 									&ast.NamePart{ | ||||
| 										Val: []byte("A"), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 							&ast.Name{ | ||||
| 								Parts: []ast.Vertex{ | ||||
| 									&ast.NamePart{ | ||||
| 										Val: []byte("B"), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Props: []ast.Vertex{ | ||||
| 						&ast.StmtProperty{ | ||||
| 							Var: &ast.ExprVariable{ | ||||
| 								Name: &ast.Identifier{ | ||||
| 									Val: []byte("$prop"), | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		&ast.StmtFunction{ | ||||
| 			Name: &ast.Identifier{ | ||||
| 				Val: []byte("test"), | ||||
| 			}, | ||||
| 			Params: []ast.Vertex{ | ||||
| 				&ast.Parameter{ | ||||
| 					Type: &ast.Intersection{ | ||||
| 						Types: []ast.Vertex{ | ||||
| 							&ast.Name{ | ||||
| 								Parts: []ast.Vertex{ | ||||
| 									&ast.NamePart{ | ||||
| 										Val: []byte("A"), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 							&ast.Name{ | ||||
| 								Parts: []ast.Vertex{ | ||||
| 									&ast.NamePart{ | ||||
| 										Val: []byte("B"), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Var: &ast.ExprVariable{ | ||||
| 						Name: &ast.Identifier{ | ||||
| 							Val: []byte("$a"), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			ReturnType: &ast.Intersection{ | ||||
| 				Types: []ast.Vertex{ | ||||
| 					&ast.Name{ | ||||
| 						Parts: []ast.Vertex{ | ||||
| 							&ast.NamePart{ | ||||
| 								Val: []byte("A"), | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					&ast.Name{ | ||||
| 						Parts: []ast.Vertex{ | ||||
| 							&ast.NamePart{ | ||||
| 								Val: []byte("B"), | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Stmts: []ast.Vertex{}, | ||||
| 		}, | ||||
| 	}, | ||||
| },` | ||||
| 
 | ||||
| 	suite.Run() | ||||
| } | ||||
|  | ||||
| @ -4177,7 +4177,7 @@ class Point { | ||||
| 								}, | ||||
| 							}, | ||||
| 							AmpersandTkn: &token.Token{ | ||||
| 								ID: token.ID(38), | ||||
| 								ID: token.ID(57492), | ||||
| 								Val: []byte("&"), | ||||
| 								FreeFloating: []*token.Token{ | ||||
| 									{ | ||||
| @ -4302,7 +4302,7 @@ class Point { | ||||
| 								}, | ||||
| 							}, | ||||
| 							AmpersandTkn: &token.Token{ | ||||
| 								ID: token.ID(38), | ||||
| 								ID: token.ID(57492), | ||||
| 								Val: []byte("&"), | ||||
| 								FreeFloating: []*token.Token{ | ||||
| 									{ | ||||
|  | ||||
| @ -1972,7 +1972,7 @@ func TestPhp8ParameterNode(t *testing.T) { | ||||
| 							}, | ||||
| 						}, | ||||
| 						AmpersandTkn: &token.Token{ | ||||
| 							ID:    token.ID(38), | ||||
| 							ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 							Value: []byte("&"), | ||||
| 							Position: &position.Position{ | ||||
| 								StartLine: 2, | ||||
| @ -2453,7 +2453,7 @@ func TestPhp8ParameterNode(t *testing.T) { | ||||
| 									}, | ||||
| 								}, | ||||
| 								AmpersandTkn: &token.Token{ | ||||
| 									ID:    token.ID(38), | ||||
| 									ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 									Value: []byte("&"), | ||||
| 									Position: &position.Position{ | ||||
| 										StartLine: 3, | ||||
| @ -2826,7 +2826,7 @@ func TestPhp8ParameterNode(t *testing.T) { | ||||
| 								}, | ||||
| 							}, | ||||
| 							AmpersandTkn: &token.Token{ | ||||
| 								ID:    token.ID(38), | ||||
| 								ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 								Value: []byte("&"), | ||||
| 								Position: &position.Position{ | ||||
| 									StartLine: 4, | ||||
| @ -3212,7 +3212,7 @@ func TestPhp8ParameterNode(t *testing.T) { | ||||
| 								}, | ||||
| 							}, | ||||
| 							AmpersandTkn: &token.Token{ | ||||
| 								ID:    token.ID(38), | ||||
| 								ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 								Value: []byte("&"), | ||||
| 								Position: &position.Position{ | ||||
| 									StartLine: 5, | ||||
| @ -10102,7 +10102,7 @@ func TestStmtClassMethod_Php8ClassMethod(t *testing.T) { | ||||
| 							}, | ||||
| 						}, | ||||
| 						AmpersandTkn: &token.Token{ | ||||
| 							ID:    token.ID(38), | ||||
| 							ID:    token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 							Value: []byte("&"), | ||||
| 							Position: &position.Position{ | ||||
| 								StartLine: 1, | ||||
| @ -16870,7 +16870,7 @@ func TestStmtForeach_WithRef(t *testing.T) { | ||||
| 					}, | ||||
| 				}, | ||||
| 				AmpersandTkn: &token.Token{ | ||||
| 					ID:    token.ID(38), | ||||
| 					ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 					Value: []byte("&"), | ||||
| 					Position: &position.Position{ | ||||
| 						StartLine: 1, | ||||
| @ -18087,7 +18087,7 @@ func TestStmtFunction_Ref(t *testing.T) { | ||||
| 					}, | ||||
| 				}, | ||||
| 				AmpersandTkn: &token.Token{ | ||||
| 					ID:    token.ID(38), | ||||
| 					ID:    token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 					Value: []byte("&"), | ||||
| 					Position: &position.Position{ | ||||
| 						StartLine: 1, | ||||
| @ -18309,7 +18309,7 @@ func TestStmtFunction_ReturnType(t *testing.T) { | ||||
| 					}, | ||||
| 				}, | ||||
| 				AmpersandTkn: &token.Token{ | ||||
| 					ID:    token.ID(38), | ||||
| 					ID:    token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 					Value: []byte("&"), | ||||
| 					Position: &position.Position{ | ||||
| 						StartLine: 1, | ||||
| @ -35439,7 +35439,7 @@ func TestExprArray_Items(t *testing.T) { | ||||
| 								EndPos:    18, | ||||
| 							}, | ||||
| 							AmpersandTkn: &token.Token{ | ||||
| 								ID:    token.ID(38), | ||||
| 								ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 								Value: []byte("&"), | ||||
| 								Position: &position.Position{ | ||||
| 									StartLine: 1, | ||||
| @ -35929,7 +35929,7 @@ func TestExprArrowFunction_ReturnType(t *testing.T) { | ||||
| 						}, | ||||
| 					}, | ||||
| 					AmpersandTkn: &token.Token{ | ||||
| 						ID:    token.ID(38), | ||||
| 						ID:    token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 						Value: []byte("&"), | ||||
| 						Position: &position.Position{ | ||||
| 							StartLine: 1, | ||||
| @ -37273,7 +37273,7 @@ func TestExprClosure_Use(t *testing.T) { | ||||
| 								EndPos:    32, | ||||
| 							}, | ||||
| 							AmpersandTkn: &token.Token{ | ||||
| 								ID:    token.ID(38), | ||||
| 								ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 								Value: []byte("&"), | ||||
| 								Position: &position.Position{ | ||||
| 									StartLine: 1, | ||||
| @ -37633,7 +37633,7 @@ func TestExprClosure_Use2(t *testing.T) { | ||||
| 								EndPos:    28, | ||||
| 							}, | ||||
| 							AmpersandTkn: &token.Token{ | ||||
| 								ID:    token.ID(38), | ||||
| 								ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 								Value: []byte("&"), | ||||
| 								Position: &position.Position{ | ||||
| 									StartLine: 1, | ||||
| @ -45056,7 +45056,7 @@ func TestExprShortArray_Items(t *testing.T) { | ||||
| 								EndPos:    13, | ||||
| 							}, | ||||
| 							AmpersandTkn: &token.Token{ | ||||
| 								ID:    token.ID(38), | ||||
| 								ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 								Value: []byte("&"), | ||||
| 								Position: &position.Position{ | ||||
| 									StartLine: 1, | ||||
| @ -49734,7 +49734,7 @@ func TestExprAssign_Assign(t *testing.T) { | ||||
| 						}, | ||||
| 					}, | ||||
| 					AmpersandTkn: &token.Token{ | ||||
| 						ID:    token.ID(38), | ||||
| 						ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 						Value: []byte("&"), | ||||
| 						Position: &position.Position{ | ||||
| 							StartLine: 3, | ||||
| @ -49870,7 +49870,7 @@ func TestExprAssign_Assign(t *testing.T) { | ||||
| 						}, | ||||
| 					}, | ||||
| 					AmpersandTkn: &token.Token{ | ||||
| 						ID:    token.ID(38), | ||||
| 						ID:    token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 						Value: []byte("&"), | ||||
| 						Position: &position.Position{ | ||||
| 							StartLine: 4, | ||||
| @ -50038,7 +50038,7 @@ func TestExprAssign_Assign(t *testing.T) { | ||||
| 						}, | ||||
| 					}, | ||||
| 					AmpersandTkn: &token.Token{ | ||||
| 						ID:    token.ID(38), | ||||
| 						ID:    token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 						Value: []byte("&"), | ||||
| 						Position: &position.Position{ | ||||
| 							StartLine: 5, | ||||
| @ -51946,7 +51946,7 @@ func TestExprBinary_BitwiseAnd(t *testing.T) { | ||||
| 						}, | ||||
| 					}, | ||||
| 					OpTkn: &token.Token{ | ||||
| 						ID:    token.ID(38), | ||||
| 						ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 						Value: []byte("&"), | ||||
| 						Position: &position.Position{ | ||||
| 							StartLine: 2, | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -162,6 +162,8 @@ import ( | ||||
| %token <token> T_NAME_FULLY_QUALIFIED | ||||
| %token <token> T_READONLY | ||||
| %token <token> T_ENUM | ||||
| %token <token> T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG | ||||
| %token <token> T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG | ||||
| %token <token> '"' | ||||
| %token <token> '`' | ||||
| %token <token> '{' | ||||
| @ -208,7 +210,7 @@ import ( | ||||
| %left T_BOOLEAN_AND | ||||
| %left '|' | ||||
| %left '^' | ||||
| %left '&' | ||||
| %left T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG | ||||
| %nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL T_SPACESHIP | ||||
| %nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL | ||||
| %left '.' | ||||
| @ -227,7 +229,7 @@ import ( | ||||
| %left T_ENDIF | ||||
| %right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC T_READONLY | ||||
| 
 | ||||
| %type <token> optional_arg_ref optional_ellipsis returns_ref | ||||
| %type <token> optional_ref optional_arg_ref optional_ellipsis | ||||
| 
 | ||||
| %type <token> reserved_non_modifiers | ||||
| %type <token> semi_reserved | ||||
| @ -236,6 +238,7 @@ import ( | ||||
| %type <token> optional_comma | ||||
| %type <token> case_separator | ||||
| %type <token> use_type | ||||
| %type <token> ampersand | ||||
| 
 | ||||
| %type <node> top_statement name statement function_declaration_statement | ||||
| %type <node> class_declaration_statement trait_declaration_statement | ||||
| @ -267,6 +270,7 @@ import ( | ||||
| 
 | ||||
| %type <node> type_expr type union_type optional_return_type | ||||
| %type <node> type_expr_without_static type_without_static union_type_without_static optional_type_without_static | ||||
| %type <node> intersection_type intersection_type_without_static | ||||
| 
 | ||||
| %type <node> class_modifier | ||||
| %type <node> argument_list ctor_arguments | ||||
| @ -336,6 +340,11 @@ semi_reserved: | ||||
|     |   T_PROTECTED {$$=$1} | T_PUBLIC {$$=$1} | T_READONLY {$$=$1} | ||||
| ; | ||||
| 
 | ||||
| ampersand: | ||||
|         T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG     { $$ = $1 } | ||||
|     |   T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG { $$ = $1 } | ||||
| ; | ||||
| 
 | ||||
| identifier: | ||||
|         T_STRING        { $$ = $1 } | ||||
| ; | ||||
| @ -839,16 +848,21 @@ unset_variable: | ||||
| ; | ||||
| 
 | ||||
| function_declaration_statement: | ||||
|         T_FUNCTION returns_ref identifier '(' parameter_list ')' optional_return_type '{' inner_statement_list '}' | ||||
|         T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type '{' inner_statement_list '}' | ||||
|             { $$ = yylex.(*Parser).builder.NewFunction(nil, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) } | ||||
|     |   attributes | ||||
|         T_FUNCTION returns_ref identifier '(' parameter_list ')' optional_return_type '{' inner_statement_list '}' | ||||
|         T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type '{' inner_statement_list '}' | ||||
|             { $$ = yylex.(*Parser).builder.NewFunction($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) } | ||||
| ; | ||||
| 
 | ||||
| optional_ref: | ||||
|         /* empty */                    { $$ = nil } | ||||
|     |   ampersand                      { $$ = $1 } | ||||
| ; | ||||
| 
 | ||||
| optional_arg_ref: | ||||
|         /* empty */                           { $$ = nil } | ||||
|     |   '&'                            { $$ = $1 } | ||||
|     |   T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG { $$ = $1 } | ||||
| ; | ||||
| 
 | ||||
| optional_ellipsis: | ||||
| @ -956,7 +970,7 @@ foreach_variable: | ||||
|             { | ||||
|                 $$ = $1 | ||||
|             } | ||||
|     |   '&' variable | ||||
|     |   ampersand variable | ||||
|             { | ||||
|                 $$ = &ast.StmtForeach{ | ||||
|                     Position: yylex.(*Parser).builder.Pos.NewTokenNodePosition($1, $2), | ||||
| @ -1299,6 +1313,7 @@ type_expr: | ||||
|         type                { $$ = $1 } | ||||
|     |   '?' type            { $$ = yylex.(*Parser).builder.NewNullableType($1, $2) } | ||||
|     |   union_type          { $$ = yylex.(*Parser).builder.NewUnionType($1) } | ||||
|     |   intersection_type   { $$ = yylex.(*Parser).builder.NewIntersectionType($1) } | ||||
| ; | ||||
| 
 | ||||
| type: | ||||
| @ -1324,10 +1339,25 @@ union_type_without_static: | ||||
|             { $$ = yylex.(*Parser).builder.AppendToSeparatedList($1, $2, $3) } | ||||
| ; | ||||
| 
 | ||||
| intersection_type: | ||||
|         type T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type | ||||
|             { $$ = yylex.(*Parser).builder.NewSeparatedListWithTwoElements($1, $2, $3) } | ||||
|     |   intersection_type T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type | ||||
|             { $$ = yylex.(*Parser).builder.AppendToSeparatedList($1, $2, $3) } | ||||
| ; | ||||
| 
 | ||||
| intersection_type_without_static: | ||||
|         type_expr_without_static T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_expr_without_static | ||||
|             { $$ = yylex.(*Parser).builder.NewSeparatedListWithTwoElements($1, $2, $3) } | ||||
|     |   intersection_type_without_static T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_expr_without_static | ||||
|             { $$ = yylex.(*Parser).builder.AppendToSeparatedList($1, $2, $3) } | ||||
| ; | ||||
| 
 | ||||
| type_expr_without_static: | ||||
|         type_without_static              { $$ = $1 } | ||||
|     |   '?' type_without_static          { $$ = yylex.(*Parser).builder.NewNullableType($1, $2) } | ||||
|     |   union_type_without_static        { $$ = yylex.(*Parser).builder.NewUnionType($1) } | ||||
|     |   intersection_type_without_static { $$ = yylex.(*Parser).builder.NewIntersectionType($1) } | ||||
| ; | ||||
| 
 | ||||
| optional_type_without_static: | ||||
| @ -1438,7 +1468,7 @@ class_statement: | ||||
|             { $$ = yylex.(*Parser).builder.NewPropertyList($1, $2, $3, $4, $5) } | ||||
|     |   optional_attributes method_modifiers T_CONST class_const_list ';' | ||||
|             { $$ = yylex.(*Parser).builder.NewClassConstList($1, $2, $3, $4, $5) } | ||||
|     |   optional_attributes method_modifiers T_FUNCTION returns_ref identifier_ex '(' parameter_list ')' optional_return_type method_body | ||||
|     |   optional_attributes method_modifiers T_FUNCTION optional_ref identifier_ex '(' parameter_list ')' optional_return_type method_body | ||||
|             { $$ = yylex.(*Parser).builder.NewClassMethod($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) } | ||||
|     |   T_USE name_list trait_adaptations | ||||
|             { | ||||
| @ -1889,7 +1919,7 @@ expr_without_variable: | ||||
|                     Expr:     $3, | ||||
|                 } | ||||
|             } | ||||
|     |   variable '=' '&' expr | ||||
|     |   variable '=' ampersand expr | ||||
|             { | ||||
|                 $$ = &ast.ExprAssignReference{ | ||||
|                     Position: yylex.(*Parser).builder.Pos.NewNodesPosition($1, $4), | ||||
| @ -2110,7 +2140,16 @@ expr_without_variable: | ||||
|                     Right: $3, | ||||
|                 } | ||||
|             } | ||||
|     |   expr '&' expr | ||||
|     |   expr T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG expr | ||||
|             { | ||||
|                 $$ = &ast.ExprBinaryBitwiseAnd{ | ||||
|                     Position: yylex.(*Parser).builder.Pos.NewNodesPosition($1, $3), | ||||
|                     Left:  $1, | ||||
|                     OpTkn: $2, | ||||
|                     Right: $3, | ||||
|                 } | ||||
|             } | ||||
|     |   expr T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG expr | ||||
| 	    { | ||||
| 	        $$ = &ast.ExprBinaryBitwiseAnd{ | ||||
| 	    	     Position: yylex.(*Parser).builder.Pos.NewNodesPosition($1, $3), | ||||
| @ -2558,7 +2597,7 @@ attributed_inline_function: | ||||
| ; | ||||
| 
 | ||||
| inline_function: | ||||
|         T_FUNCTION returns_ref backup_doc_comment '(' parameter_list ')' lexical_vars optional_return_type '{' inner_statement_list '}' | ||||
|         T_FUNCTION optional_ref backup_doc_comment '(' parameter_list ')' lexical_vars optional_return_type '{' inner_statement_list '}' | ||||
|             { | ||||
|                 closure := $7.(*ast.ExprClosure) | ||||
| 
 | ||||
| @ -2577,7 +2616,7 @@ inline_function: | ||||
| 
 | ||||
|                 $$ = closure | ||||
|             } | ||||
|     |   T_FN returns_ref '(' parameter_list ')' optional_return_type backup_doc_comment T_DOUBLE_ARROW expr %prec T_THROW | ||||
|     |   T_FN optional_ref '(' parameter_list ')' optional_return_type backup_doc_comment T_DOUBLE_ARROW expr %prec T_THROW | ||||
|             { | ||||
|                 $$ = &ast.ExprArrowFunction{ | ||||
|                     Position: yylex.(*Parser).builder.Pos.NewTokenNodePosition($1, $9), | ||||
| @ -2599,11 +2638,6 @@ backup_doc_comment: | ||||
|         /* empty */ | ||||
| ; | ||||
| 
 | ||||
| returns_ref: | ||||
|         /* empty */ { $$ = nil } | ||||
|     |   '&'         { $$ = $1 } | ||||
| ; | ||||
| 
 | ||||
| lexical_vars: | ||||
|         /* empty */ | ||||
|             { $$ = &ast.ExprClosure{} } | ||||
| @ -2643,7 +2677,7 @@ lexical_var: | ||||
|                     }, | ||||
|                 } | ||||
|             } | ||||
|     |   '&' plain_variable | ||||
|     |   ampersand plain_variable | ||||
|             { | ||||
|                 $$ = &ast.ExprClosureUse{ | ||||
|                     Position: yylex.(*Parser).builder.Pos.NewTokensPosition($1, $2), | ||||
| @ -3105,7 +3139,7 @@ array_pair: | ||||
|                     Val: $1, | ||||
|                 } | ||||
|             } | ||||
|     |   expr T_DOUBLE_ARROW '&' variable | ||||
|     |   expr T_DOUBLE_ARROW T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG variable | ||||
|             { | ||||
|                 $$ = &ast.ExprArrayItem{ | ||||
|                     Position:       yylex.(*Parser).builder.Pos.NewNodesPosition($1, $4), | ||||
| @ -3115,7 +3149,7 @@ array_pair: | ||||
|                     Val:            $4, | ||||
|                 } | ||||
|             } | ||||
|     |   '&' variable | ||||
|     |   T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG variable | ||||
|             { | ||||
|                 $$ = &ast.ExprArrayItem{ | ||||
|                     Position:     yylex.(*Parser).builder.Pos.NewTokenNodePosition($1, $2), | ||||
|  | ||||
							
								
								
									
										38727
									
								
								internal/php8/scanner.go
									
									
									
									
									
								
							
							
						
						
									
										38727
									
								
								internal/php8/scanner.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -67,7 +67,7 @@ func (lex *Lexer) Lex() *token.Token { | ||||
|         varname_second = varname_first | [0-9]; | ||||
|         varname       = varname_first (varname_second)*; | ||||
|         heredoc_label = varname >heredoc_lbl_start %heredoc_lbl_end; | ||||
|         operators     = ';'|':'|','|'.'|'['|']'|'('|')'|'|'|'/'|'^'|'&'|'+'|'-'|'*'|'='|'%'|'!'|'~'|'$'|'<'|'>'|'?'|'@'; | ||||
|         operators     = ';'|':'|','|'.'|'['|']'|'('|')'|'|'|'/'|'^'|'+'|'-'|'*'|'='|'%'|'!'|'~'|'$'|'<'|'>'|'?'|'@'; | ||||
| 
 | ||||
|         prepush { lex.growCallStack(); } | ||||
| 
 | ||||
| @ -295,7 +295,6 @@ func (lex *Lexer) Lex() *token.Token { | ||||
|             'or'i                             => {lex.setTokenPosition(tkn); tok = token.T_LOGICAL_OR; fbreak;}; | ||||
|             'xor'i                            => {lex.setTokenPosition(tkn); tok = token.T_LOGICAL_XOR; fbreak;}; | ||||
|             '#['                              => {lex.setTokenPosition(tkn); tok = token.T_ATTRIBUTE; fbreak;}; | ||||
|             '...'                             => {lex.setTokenPosition(tkn); tok = token.T_ELLIPSIS; fbreak;}; | ||||
|             '::'                              => {lex.setTokenPosition(tkn); tok = token.T_PAAMAYIM_NEKUDOTAYIM; fbreak;}; | ||||
|             '&&'                              => {lex.setTokenPosition(tkn); tok = token.T_BOOLEAN_AND; fbreak;}; | ||||
|             '||'                              => {lex.setTokenPosition(tkn); tok = token.T_BOOLEAN_OR; fbreak;}; | ||||
| @ -370,6 +369,12 @@ func (lex *Lexer) Lex() *token.Token { | ||||
|                 fbreak; | ||||
|             }; | ||||
| 
 | ||||
|             "&" whitespace_line* '$'    => { lex.ungetWhile('&'); lex.setTokenPosition(tkn); tok = token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG; fbreak; }; | ||||
|             "&" whitespace_line* '...'  => { lex.ungetWhile('&'); lex.setTokenPosition(tkn); tok = token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG; fbreak; }; | ||||
|             "&" whitespace_line* ^'$'   => { lex.ungetWhile('&'); lex.setTokenPosition(tkn); tok = token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG; fbreak; }; | ||||
|             "&" whitespace_line* ^'...' => { lex.ungetWhile('&'); lex.setTokenPosition(tkn); tok = token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG; fbreak; }; | ||||
| 
 | ||||
|             '...'        => { lex.setTokenPosition(tkn); tok = token.T_ELLIPSIS; fbreak; }; | ||||
|             "{"          => { lex.setTokenPosition(tkn); tok = token.ID(int('{')); lex.call(ftargs, fentry(php)); goto _out; }; | ||||
|             "}"          => { lex.setTokenPosition(tkn); tok = token.ID(int('}')); lex.ret(1); goto _out;}; | ||||
|             "$" varname  => { lex.setTokenPosition(tkn); tok = token.T_VARIABLE; fbreak; }; | ||||
|  | ||||
| @ -180,3 +180,192 @@ func TestEnumTokens(t *testing.T) { | ||||
| 	} | ||||
| 	suite.Run() | ||||
| } | ||||
| 
 | ||||
| func TestAmpersandFollowedByEllipsisTokens(t *testing.T) { | ||||
| 	suite := tester.NewLexerTokenStructTestSuite(t) | ||||
| 	suite.UsePHP8() | ||||
| 	suite.Code = "<?php &...;" | ||||
| 	suite.Expected = []*token.Token{ | ||||
| 		{ | ||||
| 			ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 			Value: []byte("&"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    token.T_ELLIPSIS, | ||||
| 			Value: []byte("..."), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    ';', | ||||
| 			Value: []byte(";"), | ||||
| 		}, | ||||
| 	} | ||||
| 	suite.Run() | ||||
| } | ||||
| 
 | ||||
| func TestAmpersandFollowedByEllipsisTokens2(t *testing.T) { | ||||
| 	suite := tester.NewLexerTokenStructTestSuite(t) | ||||
| 	suite.UsePHP8() | ||||
| 	suite.Code = "<?php & ...;" | ||||
| 	suite.Expected = []*token.Token{ | ||||
| 		{ | ||||
| 			ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 			Value: []byte("&"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    token.T_ELLIPSIS, | ||||
| 			Value: []byte("..."), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    ';', | ||||
| 			Value: []byte(";"), | ||||
| 		}, | ||||
| 	} | ||||
| 	suite.Run() | ||||
| } | ||||
| 
 | ||||
| func TestAmpersandFollowedByEllipsisTokens3(t *testing.T) { | ||||
| 	suite := tester.NewLexerTokenStructTestSuite(t) | ||||
| 	suite.UsePHP8() | ||||
| 	suite.Code = "<?php & \n\t     ...;" | ||||
| 	suite.Expected = []*token.Token{ | ||||
| 		{ | ||||
| 			ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 			Value: []byte("&"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    token.T_ELLIPSIS, | ||||
| 			Value: []byte("..."), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    ';', | ||||
| 			Value: []byte(";"), | ||||
| 		}, | ||||
| 	} | ||||
| 	suite.Run() | ||||
| } | ||||
| 
 | ||||
| func TestAmpersandFollowedByVarTokens(t *testing.T) { | ||||
| 	suite := tester.NewLexerTokenStructTestSuite(t) | ||||
| 	suite.UsePHP8() | ||||
| 	suite.Code = "<?php &$a;" | ||||
| 	suite.Expected = []*token.Token{ | ||||
| 		{ | ||||
| 			ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 			Value: []byte("&"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    token.T_VARIABLE, | ||||
| 			Value: []byte("$a"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    ';', | ||||
| 			Value: []byte(";"), | ||||
| 		}, | ||||
| 	} | ||||
| 	suite.Run() | ||||
| } | ||||
| 
 | ||||
| func TestAmpersandFollowedByVarTokens2(t *testing.T) { | ||||
| 	suite := tester.NewLexerTokenStructTestSuite(t) | ||||
| 	suite.UsePHP8() | ||||
| 	suite.Code = "<?php & $a;" | ||||
| 	suite.Expected = []*token.Token{ | ||||
| 		{ | ||||
| 			ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 			Value: []byte("&"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    token.T_VARIABLE, | ||||
| 			Value: []byte("$a"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    ';', | ||||
| 			Value: []byte(";"), | ||||
| 		}, | ||||
| 	} | ||||
| 	suite.Run() | ||||
| } | ||||
| 
 | ||||
| func TestAmpersandFollowedByVarTokens3(t *testing.T) { | ||||
| 	suite := tester.NewLexerTokenStructTestSuite(t) | ||||
| 	suite.UsePHP8() | ||||
| 	suite.Code = "<?php & \n\t     $a;" | ||||
| 	suite.Expected = []*token.Token{ | ||||
| 		{ | ||||
| 			ID:    token.T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 			Value: []byte("&"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    token.T_VARIABLE, | ||||
| 			Value: []byte("$a"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    ';', | ||||
| 			Value: []byte(";"), | ||||
| 		}, | ||||
| 	} | ||||
| 	suite.Run() | ||||
| } | ||||
| 
 | ||||
| func TestAmpersandNotFollowedByVarOrEllipsisTokens(t *testing.T) { | ||||
| 	suite := tester.NewLexerTokenStructTestSuite(t) | ||||
| 	suite.UsePHP8() | ||||
| 	suite.Code = "<?php &A;" | ||||
| 	suite.Expected = []*token.Token{ | ||||
| 		{ | ||||
| 			ID:    token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 			Value: []byte("&"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    token.T_STRING, | ||||
| 			Value: []byte("A"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    ';', | ||||
| 			Value: []byte(";"), | ||||
| 		}, | ||||
| 	} | ||||
| 	suite.Run() | ||||
| } | ||||
| 
 | ||||
| func TestAmpersandNotFollowedByVarOrEllipsisTokens2(t *testing.T) { | ||||
| 	suite := tester.NewLexerTokenStructTestSuite(t) | ||||
| 	suite.UsePHP8() | ||||
| 	suite.Code = "<?php & A;" | ||||
| 	suite.Expected = []*token.Token{ | ||||
| 		{ | ||||
| 			ID:    token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 			Value: []byte("&"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    token.T_STRING, | ||||
| 			Value: []byte("A"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    ';', | ||||
| 			Value: []byte(";"), | ||||
| 		}, | ||||
| 	} | ||||
| 	suite.Run() | ||||
| } | ||||
| 
 | ||||
| func TestAmpersandNotFollowedByVarOrEllipsisTokens3(t *testing.T) { | ||||
| 	suite := tester.NewLexerTokenStructTestSuite(t) | ||||
| 	suite.UsePHP8() | ||||
| 	suite.Code = "<?php & \n\t     A;" | ||||
| 	suite.Expected = []*token.Token{ | ||||
| 		{ | ||||
| 			ID:    token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, | ||||
| 			Value: []byte("&"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    token.T_STRING, | ||||
| 			Value: []byte("A"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			ID:    ';', | ||||
| 			Value: []byte(";"), | ||||
| 		}, | ||||
| 	} | ||||
| 	suite.Run() | ||||
| } | ||||
|  | ||||
| @ -317,7 +317,7 @@ func TestTokens(t *testing.T) { | ||||
| 		token.ID(int('|')).String(), | ||||
| 		token.ID(int('/')).String(), | ||||
| 		token.ID(int('^')).String(), | ||||
| 		token.ID(int('&')).String(), | ||||
| 		token.ID(T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG).String(), | ||||
| 		token.ID(int('+')).String(), | ||||
| 		token.ID(int('-')).String(), | ||||
| 		token.ID(int('*')).String(), | ||||
|  | ||||
| @ -15,6 +15,7 @@ type Visitor interface { | ||||
| 	Argument(n *Argument) | ||||
| 	MatchArm(n *MatchArm) | ||||
| 	Union(n *Union) | ||||
| 	Intersection(n *Intersection) | ||||
| 	Attribute(n *Attribute) | ||||
| 	AttributeGroup(n *AttributeGroup) | ||||
| 
 | ||||
|  | ||||
| @ -50,6 +50,21 @@ func (n *Union) GetPosition() *position.Position { | ||||
| 	return n.Position | ||||
| } | ||||
| 
 | ||||
| // Intersection node is Expr&Expr1&... | ||||
| type Intersection struct { | ||||
| 	Position      *position.Position | ||||
| 	Types         []Vertex | ||||
| 	SeparatorTkns []*token.Token | ||||
| } | ||||
| 
 | ||||
| func (n *Intersection) Accept(v Visitor) { | ||||
| 	v.Intersection(n) | ||||
| } | ||||
| 
 | ||||
| func (n *Intersection) GetPosition() *position.Position { | ||||
| 	return n.Position | ||||
| } | ||||
| 
 | ||||
| // Parameter node | ||||
| type Parameter struct { | ||||
| 	Position     *position.Position | ||||
|  | ||||
| @ -152,6 +152,8 @@ const ( | ||||
| 	T_NAME_FULLY_QUALIFIED | ||||
| 	T_READONLY | ||||
| 	T_ENUM | ||||
| 	T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG | ||||
| 	T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG | ||||
| ) | ||||
| 
 | ||||
| type Token struct { | ||||
|  | ||||
| @ -154,11 +154,13 @@ func _() { | ||||
| 	_ = x[T_NAME_FULLY_QUALIFIED-57489] | ||||
| 	_ = x[T_READONLY-57490] | ||||
| 	_ = x[T_ENUM-57491] | ||||
| 	_ = x[T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG-57492] | ||||
| 	_ = x[T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG-57493] | ||||
| } | ||||
| 
 | ||||
| const _ID_name = "T_INCLUDET_INCLUDE_ONCET_EXITT_IFT_LNUMBERT_DNUMBERT_STRINGT_STRING_VARNAMET_VARIABLET_NUM_STRINGT_INLINE_HTMLT_CHARACTERT_BAD_CHARACTERT_ENCAPSED_AND_WHITESPACET_CONSTANT_ENCAPSED_STRINGT_ECHOT_DOT_WHILET_ENDWHILET_FORT_ENDFORT_FOREACHT_ENDFOREACHT_DECLARET_ENDDECLARET_AST_SWITCHT_ENDSWITCHT_CASET_DEFAULTT_BREAKT_CONTINUET_GOTOT_FUNCTIONT_FNT_CONSTT_RETURNT_TRYT_CATCHT_FINALLYT_THROWT_USET_INSTEADOFT_GLOBALT_VART_UNSETT_ISSETT_EMPTYT_HALT_COMPILERT_CLASST_TRAITT_INTERFACET_EXTENDST_IMPLEMENTST_OBJECT_OPERATORT_DOUBLE_ARROWT_LISTT_ARRAYT_CALLABLET_CLASS_CT_TRAIT_CT_METHOD_CT_FUNC_CT_LINET_FILET_COMMENTT_DOC_COMMENTT_OPEN_TAGT_OPEN_TAG_WITH_ECHOT_CLOSE_TAGT_WHITESPACET_START_HEREDOCT_END_HEREDOCT_DOLLAR_OPEN_CURLY_BRACEST_CURLY_OPENT_PAAMAYIM_NEKUDOTAYIMT_NAMESPACET_NS_CT_DIRT_NS_SEPARATORT_ELLIPSIST_EVALT_REQUIRET_REQUIRE_ONCET_LOGICAL_ORT_LOGICAL_XORT_LOGICAL_ANDT_INSTANCEOFT_NEWT_CLONET_ELSEIFT_ELSET_ENDIFT_PRINTT_YIELDT_STATICT_ABSTRACTT_FINALT_PRIVATET_PROTECTEDT_PUBLICT_INCT_DECT_YIELD_FROMT_INT_CASTT_DOUBLE_CASTT_STRING_CASTT_ARRAY_CASTT_OBJECT_CASTT_BOOL_CASTT_UNSET_CASTT_COALESCET_SPACESHIPT_NOELSET_PLUS_EQUALT_MINUS_EQUALT_MUL_EQUALT_POW_EQUALT_DIV_EQUALT_CONCAT_EQUALT_MOD_EQUALT_AND_EQUALT_OR_EQUALT_XOR_EQUALT_SL_EQUALT_SR_EQUALT_COALESCE_EQUALT_BOOLEAN_ORT_BOOLEAN_ANDT_POWT_SLT_SRT_IS_IDENTICALT_IS_NOT_IDENTICALT_IS_EQUALT_IS_NOT_EQUALT_IS_SMALLER_OR_EQUALT_IS_GREATER_OR_EQUALT_NULLSAFE_OBJECT_OPERATORT_MATCHT_ATTRIBUTET_NAME_RELATIVET_NAME_QUALIFIEDT_NAME_FULLY_QUALIFIEDT_READONLYT_ENUM" | ||||
| const _ID_name = "T_INCLUDET_INCLUDE_ONCET_EXITT_IFT_LNUMBERT_DNUMBERT_STRINGT_STRING_VARNAMET_VARIABLET_NUM_STRINGT_INLINE_HTMLT_CHARACTERT_BAD_CHARACTERT_ENCAPSED_AND_WHITESPACET_CONSTANT_ENCAPSED_STRINGT_ECHOT_DOT_WHILET_ENDWHILET_FORT_ENDFORT_FOREACHT_ENDFOREACHT_DECLARET_ENDDECLARET_AST_SWITCHT_ENDSWITCHT_CASET_DEFAULTT_BREAKT_CONTINUET_GOTOT_FUNCTIONT_FNT_CONSTT_RETURNT_TRYT_CATCHT_FINALLYT_THROWT_USET_INSTEADOFT_GLOBALT_VART_UNSETT_ISSETT_EMPTYT_HALT_COMPILERT_CLASST_TRAITT_INTERFACET_EXTENDST_IMPLEMENTST_OBJECT_OPERATORT_DOUBLE_ARROWT_LISTT_ARRAYT_CALLABLET_CLASS_CT_TRAIT_CT_METHOD_CT_FUNC_CT_LINET_FILET_COMMENTT_DOC_COMMENTT_OPEN_TAGT_OPEN_TAG_WITH_ECHOT_CLOSE_TAGT_WHITESPACET_START_HEREDOCT_END_HEREDOCT_DOLLAR_OPEN_CURLY_BRACEST_CURLY_OPENT_PAAMAYIM_NEKUDOTAYIMT_NAMESPACET_NS_CT_DIRT_NS_SEPARATORT_ELLIPSIST_EVALT_REQUIRET_REQUIRE_ONCET_LOGICAL_ORT_LOGICAL_XORT_LOGICAL_ANDT_INSTANCEOFT_NEWT_CLONET_ELSEIFT_ELSET_ENDIFT_PRINTT_YIELDT_STATICT_ABSTRACTT_FINALT_PRIVATET_PROTECTEDT_PUBLICT_INCT_DECT_YIELD_FROMT_INT_CASTT_DOUBLE_CASTT_STRING_CASTT_ARRAY_CASTT_OBJECT_CASTT_BOOL_CASTT_UNSET_CASTT_COALESCET_SPACESHIPT_NOELSET_PLUS_EQUALT_MINUS_EQUALT_MUL_EQUALT_POW_EQUALT_DIV_EQUALT_CONCAT_EQUALT_MOD_EQUALT_AND_EQUALT_OR_EQUALT_XOR_EQUALT_SL_EQUALT_SR_EQUALT_COALESCE_EQUALT_BOOLEAN_ORT_BOOLEAN_ANDT_POWT_SLT_SRT_IS_IDENTICALT_IS_NOT_IDENTICALT_IS_EQUALT_IS_NOT_EQUALT_IS_SMALLER_OR_EQUALT_IS_GREATER_OR_EQUALT_NULLSAFE_OBJECT_OPERATORT_MATCHT_ATTRIBUTET_NAME_RELATIVET_NAME_QUALIFIEDT_NAME_FULLY_QUALIFIEDT_READONLYT_ENUMT_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARGT_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG" | ||||
| 
 | ||||
| var _ID_index = [...]uint16{0, 9, 23, 29, 33, 42, 51, 59, 75, 85, 97, 110, 121, 136, 161, 187, 193, 197, 204, 214, 219, 227, 236, 248, 257, 269, 273, 281, 292, 298, 307, 314, 324, 330, 340, 344, 351, 359, 364, 371, 380, 387, 392, 403, 411, 416, 423, 430, 437, 452, 459, 466, 477, 486, 498, 515, 529, 535, 542, 552, 561, 570, 580, 588, 594, 600, 609, 622, 632, 652, 663, 675, 690, 703, 729, 741, 763, 774, 780, 785, 799, 809, 815, 824, 838, 850, 863, 876, 888, 893, 900, 908, 914, 921, 928, 935, 943, 953, 960, 969, 980, 988, 993, 998, 1010, 1020, 1033, 1046, 1058, 1071, 1082, 1094, 1104, 1115, 1123, 1135, 1148, 1159, 1170, 1181, 1195, 1206, 1217, 1227, 1238, 1248, 1258, 1274, 1286, 1299, 1304, 1308, 1312, 1326, 1344, 1354, 1368, 1389, 1410, 1436, 1443, 1454, 1469, 1485, 1507, 1517, 1523} | ||||
| var _ID_index = [...]uint16{0, 9, 23, 29, 33, 42, 51, 59, 75, 85, 97, 110, 121, 136, 161, 187, 193, 197, 204, 214, 219, 227, 236, 248, 257, 269, 273, 281, 292, 298, 307, 314, 324, 330, 340, 344, 351, 359, 364, 371, 380, 387, 392, 403, 411, 416, 423, 430, 437, 452, 459, 466, 477, 486, 498, 515, 529, 535, 542, 552, 561, 570, 580, 588, 594, 600, 609, 622, 632, 652, 663, 675, 690, 703, 729, 741, 763, 774, 780, 785, 799, 809, 815, 824, 838, 850, 863, 876, 888, 893, 900, 908, 914, 921, 928, 935, 943, 953, 960, 969, 980, 988, 993, 998, 1010, 1020, 1033, 1046, 1058, 1071, 1082, 1094, 1104, 1115, 1123, 1135, 1148, 1159, 1170, 1181, 1195, 1206, 1217, 1227, 1238, 1248, 1258, 1274, 1286, 1299, 1304, 1308, 1312, 1326, 1344, 1354, 1368, 1389, 1410, 1436, 1443, 1454, 1469, 1485, 1507, 1517, 1523, 1560, 1601} | ||||
| 
 | ||||
| func (i ID) String() string { | ||||
| 	i -= 57346 | ||||
|  | ||||
| @ -261,6 +261,17 @@ func (v *Dumper) Union(n *ast.Union) { | ||||
| 	v.print(v.indent, "},\n") | ||||
| } | ||||
| 
 | ||||
| func (v *Dumper) Intersection(n *ast.Intersection) { | ||||
| 	v.print(0, "&ast.Intersection{\n") | ||||
| 	v.indent++ | ||||
| 
 | ||||
| 	v.dumpPosition(n.Position) | ||||
| 	v.dumpVertexList("Types", n.Types) | ||||
| 	v.dumpTokenList("SeparatorTkns", n.SeparatorTkns) | ||||
| 
 | ||||
| 	v.indent-- | ||||
| 	v.print(v.indent, "},\n") | ||||
| } | ||||
| func (v *Dumper) Attribute(n *ast.Attribute) { | ||||
| 	v.print(0, "&ast.Attribute{\n") | ||||
| 	v.indent++ | ||||
|  | ||||
| @ -237,6 +237,12 @@ func (f *formatter) Union(n *ast.Union) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (f *formatter) Intersection(n *ast.Intersection) { | ||||
| 	if len(n.Types) > 0 { | ||||
| 		n.SeparatorTkns = f.formatList(n.Types, '&') | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (f *formatter) Attribute(n *ast.Attribute) { | ||||
| 	n.Name.Accept(f) | ||||
| 	n.OpenParenthesisTkn = f.newToken('(', []byte("(")) | ||||
|  | ||||
| @ -50,6 +50,10 @@ func (v *Null) Union(_ *ast.Union) { | ||||
| 	// do nothing | ||||
| } | ||||
| 
 | ||||
| func (v *Null) Intersection(_ *ast.Intersection) { | ||||
| 	// do nothing | ||||
| } | ||||
| 
 | ||||
| func (v *Null) Attribute(_ *ast.Attribute) { | ||||
| 	// do nothing | ||||
| } | ||||
|  | ||||
| @ -180,6 +180,10 @@ func (p *printer) Union(n *ast.Union) { | ||||
| 	p.printSeparatedList(n.Types, n.SeparatorTkns, []byte("|")) | ||||
| } | ||||
| 
 | ||||
| func (p *printer) Intersection(n *ast.Intersection) { | ||||
| 	p.printSeparatedList(n.Types, n.SeparatorTkns, []byte("&")) | ||||
| } | ||||
| 
 | ||||
| func (p *printer) Attribute(n *ast.Attribute) { | ||||
| 	p.printNode(n.Name) | ||||
| 	p.printToken(n.OpenParenthesisTkn, p.ifNodeList(n.Args, []byte("("))) | ||||
|  | ||||
| @ -104,3 +104,13 @@ $foo = $closure->__invoke(...); | ||||
| // new Foo(...); // not working | ||||
| `) | ||||
| } | ||||
| 
 | ||||
| func TestIntersectionTypesSyntaxPHP81(t *testing.T) { | ||||
| 	tester.NewParserPrintTestSuite(t).UsePHP8().Run(`<?php | ||||
| class Test { | ||||
|     public A&B $prop; | ||||
| } | ||||
| 
 | ||||
| function test(A&B $a): A&B {} | ||||
| `) | ||||
| } | ||||
|  | ||||
| @ -78,6 +78,14 @@ func (t *Traverser) Union(n *ast.Union) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (t *Traverser) Intersection(n *ast.Intersection) { | ||||
| 	n.Accept(t.v) | ||||
| 
 | ||||
| 	for _, nn := range n.Types { | ||||
| 		nn.Accept(t) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (t *Traverser) Attribute(n *ast.Attribute) { | ||||
| 	n.Accept(t.v) | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user