From 8bf1fa822dd9bb3d91ead43ec08e506285f8168b Mon Sep 17 00:00:00 2001 From: Vadym Slizov Date: Sat, 26 Dec 2020 19:38:45 +0200 Subject: [PATCH] refactoring: update ast structure of "Foreach" node --- internal/php5/parser_test.go | 461 ++---------- internal/php5/php5.go | 1125 +++++++++++++++-------------- internal/php5/php5.y | 81 ++- internal/php7/parser_test.go | 461 ++---------- internal/php7/php7.go | 742 +++++++++---------- internal/php7/php7.y | 50 +- pkg/ast/node.go | 1 + pkg/ast/visitor/dumper.go | 1 + pkg/ast/visitor/formatter.go | 3 + pkg/ast/visitor/formatter_test.go | 38 + pkg/ast/visitor/printer.go | 1 + pkg/ast/visitor/printer_test.go | 33 + 12 files changed, 1263 insertions(+), 1734 deletions(-) diff --git a/internal/php5/parser_test.go b/internal/php5/parser_test.go index 6ff6707..10e9084 100644 --- a/internal/php5/parser_test.go +++ b/internal/php5/parser_test.go @@ -15045,61 +15045,53 @@ func TestStmtForeach_WithRef(t *testing.T) { }, }, }, - Var: &ast.ExprReference{ + AmpersandTkn: &token.Token{ + ID: token.ID(38), + Value: []byte("&"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, - EndPos: 27, + EndPos: 25, }, - 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, - }, + FreeFloating: []*token.Token{ + { + ID: token.T_WHITESPACE, + Value: []byte(" "), + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 23, + EndPos: 24, }, }, }, - Var: &ast.ExprVariable{ + }, + Var: &ast.ExprVariable{ + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 25, + EndPos: 27, + }, + VarName: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 25, EndPos: 27, }, - VarName: &ast.Identifier{ + IdentifierTkn: &token.Token{ + ID: token.T_VARIABLE, + Value: []byte("$v"), 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"), }, + Value: []byte("$v"), }, }, CloseParenthesisTkn: &token.Token{ @@ -31770,7 +31762,7 @@ func TestExprClosure_Use(t *testing.T) { EndPos: 36, }, FunctionTkn: &token.Token{ - ID: token.T_FUNCTION, + ID: token.T_FUNCTION, Value: []byte("function"), Position: &position.Position{ StartLine: 1, @@ -31780,7 +31772,7 @@ func TestExprClosure_Use(t *testing.T) { }, FreeFloating: []*token.Token{ { - ID: token.T_OPEN_TAG, + ID: token.T_OPEN_TAG, Value: []byte(" &$v) {}` - - expected := &ast.Root{ - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 3, - EndPos: 31, - }, - Stmts: []ast.Vertex{ - &ast.StmtForeach{ - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 3, - EndPos: 31, - }, - ForeachTkn: &token.Token{ - ID: token.T_FOREACH, - Value: []byte("foreach"), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 3, - EndPos: 10, - }, - FreeFloating: []*token.Token{ - { - ID: token.T_OPEN_TAG, - Value: []byte(""), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 21, - EndPos: 23, - }, - FreeFloating: []*token.Token{ - { - ID: token.T_WHITESPACE, - Value: []byte(" "), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 20, - EndPos: 21, - }, - }, - }, - }, - Var: &ast.ExprReference{ - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 24, - EndPos: 27, - }, - 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, - }, - VarName: &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{}, - } - - lexer := scanner.NewLexer([]byte(src), "5.6", nil) - php5parser := php5.NewParser(lexer, nil) - php5parser.Parse() - actual := php5parser.GetRootNode() - assert.DeepEqual(t, expected, actual) -} - func TestExprShellExec(t *testing.T) { src := "= 0; i-- { yyDollar[1].list[i].(*ast.ExprVariable).VarName = yyDollar[2].node @@ -7403,7 +7428,7 @@ yydefault: } case 449: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:4866 + // line internal/php5/php5.y:4891 { yyVAL.node = &ast.ExprStaticPropertyFetch{ Position: yylex.(*Parser).builder.NewNodesPosition(yyDollar[1].node, yyDollar[3].node), @@ -7414,7 +7439,7 @@ yydefault: } case 450: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:4875 + // line internal/php5/php5.y:4900 { yyVAL.node = &ast.ExprStaticPropertyFetch{ Position: yylex.(*Parser).builder.NewNodesPosition(yyDollar[1].node, yyDollar[3].node), @@ -7425,13 +7450,13 @@ yydefault: } case 451: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:4887 + // line internal/php5/php5.y:4912 { yyVAL.node = yyDollar[1].node } case 452: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:4894 + // line internal/php5/php5.y:4919 { yyVAL.node = &ast.ExprArrayDimFetch{ Position: yylex.(*Parser).builder.NewNodeTokenPosition(yyDollar[1].node, yyDollar[4].token), @@ -7443,7 +7468,7 @@ yydefault: } case 453: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:4904 + // line internal/php5/php5.y:4929 { yyVAL.node = &ast.ExprArrayDimFetch{ Position: yylex.(*Parser).builder.NewNodeTokenPosition(yyDollar[1].node, yyDollar[4].token), @@ -7455,31 +7480,31 @@ yydefault: } case 454: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:4917 + // line internal/php5/php5.y:4942 { yyVAL.node = yyDollar[1].node } case 455: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:4921 + // line internal/php5/php5.y:4946 { yyVAL.node = yyDollar[1].node } case 456: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:4925 + // line internal/php5/php5.y:4950 { yyVAL.node = yyDollar[1].node } case 457: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:4933 + // line internal/php5/php5.y:4958 { yyVAL.node = yyDollar[1].node } case 458: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:4937 + // line internal/php5/php5.y:4962 { for i := len(yyDollar[1].list) - 1; i >= 0; i-- { yyDollar[1].list[i].(*ast.ExprVariable).VarName = yyDollar[2].node @@ -7491,13 +7516,13 @@ yydefault: } case 459: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:4947 + // line internal/php5/php5.y:4972 { yyVAL.node = yyDollar[1].node } case 460: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:4954 + // line internal/php5/php5.y:4979 { yyVAL.node = &ast.ExprArrayDimFetch{ Position: yylex.(*Parser).builder.NewNodeTokenPosition(yyDollar[1].node, yyDollar[4].token), @@ -7509,7 +7534,7 @@ yydefault: } case 461: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:4964 + // line internal/php5/php5.y:4989 { yyVAL.node = &ast.ExprArrayDimFetch{ Position: yylex.(*Parser).builder.NewNodeTokenPosition(yyDollar[1].node, yyDollar[4].token), @@ -7521,13 +7546,13 @@ yydefault: } case 462: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:4974 + // line internal/php5/php5.y:4999 { yyVAL.node = yyDollar[1].node } case 463: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:4982 + // line internal/php5/php5.y:5007 { yyVAL.node = &ast.ExprVariable{ Position: yylex.(*Parser).builder.NewTokenPosition(yyDollar[1].token), @@ -7540,7 +7565,7 @@ yydefault: } case 464: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:4993 + // line internal/php5/php5.y:5018 { yyVAL.node = &ast.ExprVariable{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[4].token), @@ -7555,25 +7580,25 @@ yydefault: } case 465: yyDollar = yyS[yypt-0 : yypt+1] - // line internal/php5/php5.y:5009 + // line internal/php5/php5.y:5034 { yyVAL.node = nil } case 466: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5013 + // line internal/php5/php5.y:5038 { yyVAL.node = yyDollar[1].node } case 467: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5021 + // line internal/php5/php5.y:5046 { yyVAL.list = yyDollar[1].list } case 468: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5025 + // line internal/php5/php5.y:5050 { yyVAL.list = []ast.Vertex{ &ast.ExprPropertyFetch{ @@ -7584,7 +7609,7 @@ yydefault: } case 469: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:5037 + // line internal/php5/php5.y:5062 { fetch := &ast.ExprArrayDimFetch{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[2].token, yyDollar[4].token), @@ -7598,7 +7623,7 @@ yydefault: } case 470: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:5049 + // line internal/php5/php5.y:5074 { fetch := &ast.ExprArrayDimFetch{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[2].token, yyDollar[4].token), @@ -7612,7 +7637,7 @@ yydefault: } case 471: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5061 + // line internal/php5/php5.y:5086 { yyVAL.list = []ast.Vertex{ &ast.ExprPropertyFetch{ @@ -7623,7 +7648,7 @@ yydefault: } case 472: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5073 + // line internal/php5/php5.y:5098 { yyVAL.node = &ast.Identifier{ Position: yylex.(*Parser).builder.NewTokenPosition(yyDollar[1].token), @@ -7633,7 +7658,7 @@ yydefault: } case 473: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5081 + // line internal/php5/php5.y:5106 { yyVAL.node = &ast.ParserBrackets{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[3].token), @@ -7644,7 +7669,7 @@ yydefault: } case 474: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5093 + // line internal/php5/php5.y:5118 { yyVAL.list = []ast.Vertex{ &ast.ExprVariable{ @@ -7655,7 +7680,7 @@ yydefault: } case 475: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:5102 + // line internal/php5/php5.y:5127 { yyVAL.list = append(yyDollar[1].list, &ast.ExprVariable{ Position: yylex.(*Parser).builder.NewTokenPosition(yyDollar[2].token), @@ -7664,7 +7689,7 @@ yydefault: } case 476: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5112 + // line internal/php5/php5.y:5137 { yyDollar[1].node.(*ast.ParserSeparatedList).SeparatorTkns = append(yyDollar[1].node.(*ast.ParserSeparatedList).SeparatorTkns, yyDollar[2].token) yyDollar[1].node.(*ast.ParserSeparatedList).Items = append(yyDollar[1].node.(*ast.ParserSeparatedList).Items, yyDollar[3].node) @@ -7673,7 +7698,7 @@ yydefault: } case 477: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5119 + // line internal/php5/php5.y:5144 { yyVAL.node = &ast.ParserSeparatedList{ Items: []ast.Vertex{yyDollar[1].node}, @@ -7681,7 +7706,7 @@ yydefault: } case 478: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5129 + // line internal/php5/php5.y:5154 { yyVAL.node = &ast.ExprArrayItem{ Position: yylex.(*Parser).builder.NewNodePosition(yyDollar[1].node), @@ -7690,7 +7715,7 @@ yydefault: } case 479: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:5136 + // line internal/php5/php5.y:5161 { pairList := yyDollar[3].node.(*ast.ParserSeparatedList) fistPair := pairList.Items[0].(*ast.ExprArrayItem) @@ -7713,19 +7738,19 @@ yydefault: } case 480: yyDollar = yyS[yypt-0 : yypt+1] - // line internal/php5/php5.y:5157 + // line internal/php5/php5.y:5182 { yyVAL.node = &ast.ExprArrayItem{} } case 481: yyDollar = yyS[yypt-0 : yypt+1] - // line internal/php5/php5.y:5165 + // line internal/php5/php5.y:5190 { yyVAL.node = &ast.ParserSeparatedList{} } case 482: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:5169 + // line internal/php5/php5.y:5194 { if yyDollar[2].token != nil { yyDollar[1].node.(*ast.ParserSeparatedList).SeparatorTkns = append(yyDollar[1].node.(*ast.ParserSeparatedList).SeparatorTkns, yyDollar[2].token) @@ -7736,7 +7761,7 @@ yydefault: } case 483: yyDollar = yyS[yypt-5 : yypt+1] - // line internal/php5/php5.y:5181 + // line internal/php5/php5.y:5206 { arrayItem := &ast.ExprArrayItem{ Position: yylex.(*Parser).builder.NewNodesPosition(yyDollar[3].node, yyDollar[5].node), @@ -7752,7 +7777,7 @@ yydefault: } case 484: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5195 + // line internal/php5/php5.y:5220 { arrayItem := &ast.ExprArrayItem{ Position: yylex.(*Parser).builder.NewNodePosition(yyDollar[3].node), @@ -7766,7 +7791,7 @@ yydefault: } case 485: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5207 + // line internal/php5/php5.y:5232 { yyVAL.node = &ast.ParserSeparatedList{ Items: []ast.Vertex{ @@ -7781,7 +7806,7 @@ yydefault: } case 486: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5220 + // line internal/php5/php5.y:5245 { yyVAL.node = &ast.ParserSeparatedList{ Items: []ast.Vertex{ @@ -7794,7 +7819,7 @@ yydefault: } case 487: yyDollar = yyS[yypt-6 : yypt+1] - // line internal/php5/php5.y:5231 + // line internal/php5/php5.y:5256 { arrayItem := &ast.ExprArrayItem{ Position: yylex.(*Parser).builder.NewNodesPosition(yyDollar[3].node, yyDollar[6].node), @@ -7814,7 +7839,7 @@ yydefault: } case 488: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:5249 + // line internal/php5/php5.y:5274 { arrayItem := &ast.ExprArrayItem{ Position: yylex.(*Parser).builder.NewTokenNodePosition(yyDollar[3].token, yyDollar[4].node), @@ -7832,7 +7857,7 @@ yydefault: } case 489: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:5265 + // line internal/php5/php5.y:5290 { yyVAL.node = &ast.ParserSeparatedList{ Items: []ast.Vertex{ @@ -7851,7 +7876,7 @@ yydefault: } case 490: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:5282 + // line internal/php5/php5.y:5307 { yyVAL.node = &ast.ParserSeparatedList{ Items: []ast.Vertex{ @@ -7868,13 +7893,13 @@ yydefault: } case 491: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:5300 + // line internal/php5/php5.y:5325 { yyVAL.list = append(yyDollar[1].list, yyDollar[2].node) } case 492: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:5304 + // line internal/php5/php5.y:5329 { yyVAL.list = append( yyDollar[1].list, @@ -7887,13 +7912,13 @@ yydefault: } case 493: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5315 + // line internal/php5/php5.y:5340 { yyVAL.list = []ast.Vertex{yyDollar[1].node} } case 494: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:5319 + // line internal/php5/php5.y:5344 { yyVAL.list = []ast.Vertex{ &ast.ScalarEncapsedStringPart{ @@ -7906,7 +7931,7 @@ yydefault: } case 495: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5333 + // line internal/php5/php5.y:5358 { yyVAL.node = &ast.ExprVariable{ Position: yylex.(*Parser).builder.NewTokenPosition(yyDollar[1].token), @@ -7919,7 +7944,7 @@ yydefault: } case 496: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:5344 + // line internal/php5/php5.y:5369 { yyVAL.node = &ast.ExprArrayDimFetch{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[4].token), @@ -7938,7 +7963,7 @@ yydefault: } case 497: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5361 + // line internal/php5/php5.y:5386 { yyVAL.node = &ast.ExprPropertyFetch{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[3].token), @@ -7960,7 +7985,7 @@ yydefault: } case 498: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5381 + // line internal/php5/php5.y:5406 { yyVAL.node = &ast.ParserBrackets{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[3].token), @@ -7974,7 +7999,7 @@ yydefault: } case 499: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5393 + // line internal/php5/php5.y:5418 { yyVAL.node = &ast.ParserBrackets{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[3].token), @@ -7992,7 +8017,7 @@ yydefault: } case 500: yyDollar = yyS[yypt-6 : yypt+1] - // line internal/php5/php5.y:5409 + // line internal/php5/php5.y:5434 { yyVAL.node = &ast.ParserBrackets{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[6].token), @@ -8016,7 +8041,7 @@ yydefault: } case 501: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5431 + // line internal/php5/php5.y:5456 { yyVAL.node = &ast.ParserBrackets{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[3].token), @@ -8027,7 +8052,7 @@ yydefault: } case 502: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5443 + // line internal/php5/php5.y:5468 { yyVAL.node = &ast.ScalarString{ Position: yylex.(*Parser).builder.NewTokenPosition(yyDollar[1].token), @@ -8037,7 +8062,7 @@ yydefault: } case 503: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5451 + // line internal/php5/php5.y:5476 { // TODO: add option to handle 64 bit integer if _, err := strconv.Atoi(string(yyDollar[1].token.Value)); err == nil { @@ -8056,7 +8081,7 @@ yydefault: } case 504: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5468 + // line internal/php5/php5.y:5493 { yyVAL.node = &ast.ExprVariable{ Position: yylex.(*Parser).builder.NewTokenPosition(yyDollar[1].token), @@ -8069,7 +8094,7 @@ yydefault: } case 505: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:5482 + // line internal/php5/php5.y:5507 { yyVAL.node = &ast.ExprIsset{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[4].token), @@ -8082,7 +8107,7 @@ yydefault: } case 506: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:5493 + // line internal/php5/php5.y:5518 { yyVAL.node = &ast.ExprEmpty{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[4].token), @@ -8094,7 +8119,7 @@ yydefault: } case 507: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:5503 + // line internal/php5/php5.y:5528 { yyVAL.node = &ast.ExprEmpty{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[4].token), @@ -8106,7 +8131,7 @@ yydefault: } case 508: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:5513 + // line internal/php5/php5.y:5538 { yyVAL.node = &ast.ExprInclude{ Position: yylex.(*Parser).builder.NewTokenNodePosition(yyDollar[1].token, yyDollar[2].node), @@ -8116,7 +8141,7 @@ yydefault: } case 509: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:5521 + // line internal/php5/php5.y:5546 { yyVAL.node = &ast.ExprIncludeOnce{ Position: yylex.(*Parser).builder.NewTokenNodePosition(yyDollar[1].token, yyDollar[2].node), @@ -8126,7 +8151,7 @@ yydefault: } case 510: yyDollar = yyS[yypt-4 : yypt+1] - // line internal/php5/php5.y:5529 + // line internal/php5/php5.y:5554 { yyVAL.node = &ast.ExprEval{ Position: yylex.(*Parser).builder.NewTokensPosition(yyDollar[1].token, yyDollar[4].token), @@ -8138,7 +8163,7 @@ yydefault: } case 511: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:5539 + // line internal/php5/php5.y:5564 { yyVAL.node = &ast.ExprRequire{ Position: yylex.(*Parser).builder.NewTokenNodePosition(yyDollar[1].token, yyDollar[2].node), @@ -8148,7 +8173,7 @@ yydefault: } case 512: yyDollar = yyS[yypt-2 : yypt+1] - // line internal/php5/php5.y:5547 + // line internal/php5/php5.y:5572 { yyVAL.node = &ast.ExprRequireOnce{ Position: yylex.(*Parser).builder.NewTokenNodePosition(yyDollar[1].token, yyDollar[2].node), @@ -8158,7 +8183,7 @@ yydefault: } case 513: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5558 + // line internal/php5/php5.y:5583 { yyVAL.node = &ast.ParserSeparatedList{ Items: []ast.Vertex{yyDollar[1].node}, @@ -8166,7 +8191,7 @@ yydefault: } case 514: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5564 + // line internal/php5/php5.y:5589 { yyDollar[1].node.(*ast.ParserSeparatedList).SeparatorTkns = append(yyDollar[1].node.(*ast.ParserSeparatedList).SeparatorTkns, yyDollar[2].token) yyDollar[1].node.(*ast.ParserSeparatedList).Items = append(yyDollar[1].node.(*ast.ParserSeparatedList).Items, yyDollar[3].node) @@ -8175,19 +8200,19 @@ yydefault: } case 515: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5574 + // line internal/php5/php5.y:5599 { yyVAL.node = yyDollar[1].node } case 516: yyDollar = yyS[yypt-1 : yypt+1] - // line internal/php5/php5.y:5578 + // line internal/php5/php5.y:5603 { yyVAL.node = yyDollar[1].node } case 517: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5585 + // line internal/php5/php5.y:5610 { yyVAL.node = &ast.ExprClassConstFetch{ Position: yylex.(*Parser).builder.NewNodeTokenPosition(yyDollar[1].node, yyDollar[3].token), @@ -8202,7 +8227,7 @@ yydefault: } case 518: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5598 + // line internal/php5/php5.y:5623 { yyVAL.node = &ast.ExprClassConstFetch{ Position: yylex.(*Parser).builder.NewNodeTokenPosition(yyDollar[1].node, yyDollar[3].token), @@ -8217,7 +8242,7 @@ yydefault: } case 519: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5614 + // line internal/php5/php5.y:5639 { yyVAL.node = &ast.ExprClassConstFetch{ Position: yylex.(*Parser).builder.NewNodeTokenPosition(yyDollar[1].node, yyDollar[3].token), @@ -8232,7 +8257,7 @@ yydefault: } case 520: yyDollar = yyS[yypt-3 : yypt+1] - // line internal/php5/php5.y:5630 + // line internal/php5/php5.y:5655 { yyVAL.node = &ast.ExprClassConstFetch{ Position: yylex.(*Parser).builder.NewNodeTokenPosition(yyDollar[1].node, yyDollar[3].token), diff --git a/internal/php5/php5.y b/internal/php5/php5.y index 50edcc3..6b33687 100644 --- a/internal/php5/php5.y +++ b/internal/php5/php5.y @@ -5,6 +5,7 @@ import ( "strconv" "github.com/z7zmey/php-parser/pkg/ast" + "github.com/z7zmey/php-parser/pkg/errors" "github.com/z7zmey/php-parser/pkg/token" ) @@ -983,39 +984,63 @@ unticked_statement: } | T_FOREACH '(' variable T_AS foreach_variable foreach_optional_arg ')' foreach_statement { - $8.(*ast.StmtForeach).ForeachTkn = $1 - $8.(*ast.StmtForeach).OpenParenthesisTkn = $2 - $8.(*ast.StmtForeach).Expr = $3 - $8.(*ast.StmtForeach).AsTkn = $4 - if $6 == nil { - $8.(*ast.StmtForeach).Var = $5 - } else { - $8.(*ast.StmtForeach).Key = $5 - $8.(*ast.StmtForeach).DoubleArrowTkn = $6.(*ast.StmtForeach).DoubleArrowTkn - $8.(*ast.StmtForeach).Var = $6.(*ast.StmtForeach).Var - } - $8.(*ast.StmtForeach).CloseParenthesisTkn = $7 - $8.(*ast.StmtForeach).Position = yylex.(*Parser).builder.NewTokenNodePosition($1, $8) + foreach := $8.(*ast.StmtForeach) - $$ = $8 + foreach.Position = yylex.(*Parser).builder.NewTokenNodePosition($1, $8) + foreach.ForeachTkn = $1 + foreach.OpenParenthesisTkn = $2 + foreach.Expr = $3 + foreach.AsTkn = $4 + foreach.Var = $5 + foreach.CloseParenthesisTkn = $7 + + if $6 != nil { + foreach.Key = foreach.Var + foreach.DoubleArrowTkn = $6.(*ast.StmtForeach).DoubleArrowTkn + foreach.Var = $6.(*ast.StmtForeach).Var + } + + if val, ok := foreach.Key.(*ast.ExprReference); ok { + yylex.(*Parser).errHandlerFunc(errors.NewError("Key element cannot be a reference", val.AmpersandTkn.Position)) + foreach.Key = val.Var + } + + if val, ok := foreach.Var.(*ast.ExprReference); ok { + foreach.AmpersandTkn = val.AmpersandTkn + foreach.Var = val.Var + } + + $$ = foreach } | T_FOREACH '(' expr_without_variable T_AS foreach_variable foreach_optional_arg ')' foreach_statement { - $8.(*ast.StmtForeach).ForeachTkn = $1 - $8.(*ast.StmtForeach).OpenParenthesisTkn = $2 - $8.(*ast.StmtForeach).Expr = $3 - $8.(*ast.StmtForeach).AsTkn = $4 - if $6 == nil { - $8.(*ast.StmtForeach).Var = $5 - } else { - $8.(*ast.StmtForeach).Key = $5 - $8.(*ast.StmtForeach).DoubleArrowTkn = $6.(*ast.StmtForeach).DoubleArrowTkn - $8.(*ast.StmtForeach).Var = $6.(*ast.StmtForeach).Var - } - $8.(*ast.StmtForeach).CloseParenthesisTkn = $7 - $8.(*ast.StmtForeach).Position = yylex.(*Parser).builder.NewTokenNodePosition($1, $8) + foreach := $8.(*ast.StmtForeach) - $$ = $8 + foreach.Position = yylex.(*Parser).builder.NewTokenNodePosition($1, $8) + foreach.ForeachTkn = $1 + foreach.OpenParenthesisTkn = $2 + foreach.Expr = $3 + foreach.AsTkn = $4 + foreach.Var = $5 + foreach.CloseParenthesisTkn = $7 + + if $6 != nil { + foreach.Key = foreach.Var + foreach.DoubleArrowTkn = $6.(*ast.StmtForeach).DoubleArrowTkn + foreach.Var = $6.(*ast.StmtForeach).Var + } + + if val, ok := foreach.Key.(*ast.ExprReference); ok { + yylex.(*Parser).errHandlerFunc(errors.NewError("Key element cannot be a reference", val.AmpersandTkn.Position)) + foreach.Key = val.Var + } + + if val, ok := foreach.Var.(*ast.ExprReference); ok { + foreach.AmpersandTkn = val.AmpersandTkn + foreach.Var = val.Var + } + + $$ = foreach } | T_DECLARE '(' declare_list ')' declare_statement { diff --git a/internal/php7/parser_test.go b/internal/php7/parser_test.go index c33bafd..eb10949 100644 --- a/internal/php7/parser_test.go +++ b/internal/php7/parser_test.go @@ -16524,61 +16524,53 @@ func TestStmtForeach_WithRef(t *testing.T) { }, }, }, - Var: &ast.ExprReference{ + AmpersandTkn: &token.Token{ + ID: token.ID(38), + Value: []byte("&"), Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 24, - EndPos: 27, + EndPos: 25, }, - 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, - }, + FreeFloating: []*token.Token{ + { + ID: token.T_WHITESPACE, + Value: []byte(" "), + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 23, + EndPos: 24, }, }, }, - Var: &ast.ExprVariable{ + }, + Var: &ast.ExprVariable{ + Position: &position.Position{ + StartLine: 1, + EndLine: 1, + StartPos: 25, + EndPos: 27, + }, + VarName: &ast.Identifier{ Position: &position.Position{ StartLine: 1, EndLine: 1, StartPos: 25, EndPos: 27, }, - VarName: &ast.Identifier{ + IdentifierTkn: &token.Token{ + ID: token.T_VARIABLE, + Value: []byte("$v"), 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"), }, + Value: []byte("$v"), }, }, CloseParenthesisTkn: &token.Token{ @@ -36268,7 +36260,7 @@ func TestExprClosure_Use(t *testing.T) { EndPos: 36, }, FunctionTkn: &token.Token{ - ID: token.T_FUNCTION, + ID: token.T_FUNCTION, Value: []byte("function"), Position: &position.Position{ StartLine: 1, @@ -36278,7 +36270,7 @@ func TestExprClosure_Use(t *testing.T) { }, FreeFloating: []*token.Token{ { - ID: token.T_OPEN_TAG, + ID: token.T_OPEN_TAG, Value: []byte(" &$v) {}` - - expected := &ast.Root{ - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 3, - EndPos: 31, - }, - Stmts: []ast.Vertex{ - &ast.StmtForeach{ - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 3, - EndPos: 31, - }, - ForeachTkn: &token.Token{ - ID: token.T_FOREACH, - Value: []byte("foreach"), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 3, - EndPos: 10, - }, - FreeFloating: []*token.Token{ - { - ID: token.T_OPEN_TAG, - Value: []byte(""), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 21, - EndPos: 23, - }, - FreeFloating: []*token.Token{ - { - ID: token.T_WHITESPACE, - Value: []byte(" "), - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 20, - EndPos: 21, - }, - }, - }, - }, - Var: &ast.ExprReference{ - Position: &position.Position{ - StartLine: 1, - EndLine: 1, - StartPos: 24, - EndPos: 27, - }, - 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, - }, - VarName: &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{}, - } - - lexer := scanner.NewLexer([]byte(src), "7.4", nil) - php7parser := php7.NewParser(lexer, nil) - php7parser.Parse() - actual := php7parser.GetRootNode() - assert.DeepEqual(t, expected, actual) -} - func TestExprShellExec(t *testing.T) { src := ""))) + p.printToken(n.AmpersandTkn, nil) p.printNode(n.Var) p.printToken(n.CloseParenthesisTkn, []byte(")")) p.printToken(n.ColonTkn, nil) diff --git a/pkg/ast/visitor/printer_test.go b/pkg/ast/visitor/printer_test.go index 571f51e..8671134 100644 --- a/pkg/ast/visitor/printer_test.go +++ b/pkg/ast/visitor/printer_test.go @@ -3799,6 +3799,39 @@ func TestPrinterPrintStmtForeach(t *testing.T) { } } +func TestPrinterPrintStmtForeach_Reference(t *testing.T) { + o := bytes.NewBufferString("") + + p := visitor.NewPrinter(o).WithState(visitor.PrinterStatePHP) + n := &ast.StmtForeach{ + Expr: &ast.ExprVariable{ + VarName: &ast.Identifier{Value: []byte("$a")}, + }, + Key: &ast.ExprVariable{ + VarName: &ast.Identifier{Value: []byte("$k")}, + }, + AmpersandTkn: &token.Token{ + Value: []byte("&"), + }, + Var: &ast.ExprVariable{ + VarName: &ast.Identifier{Value: []byte("$v")}, + }, + Stmt: &ast.StmtStmtList{ + Stmts: []ast.Vertex{ + &ast.StmtNop{}, + }, + }, + } + n.Accept(p) + + expected := `foreach($a as$k=>&$v){;}` + actual := o.String() + + if expected != actual { + t.Errorf("\nexpected: %s\ngot: %s\n", expected, actual) + } +} + func TestPrinterPrintStmtFunction(t *testing.T) { o := bytes.NewBufferString("")