mirror of
https://github.com/nikic/PHP-Parser.git
synced 2025-01-17 07:08:14 +01:00
Introduce Stmt\Block
Stmt\Block will be created for { $a; } style blocks, unless these occur directly inside some structure that is usually combined with a block. For example if ($a) { $b; } will continue to use the old representation (plain array in in If_::$stmts), but a free-standing { $b; } will become a Stmt\Block. Fixes #590.
This commit is contained in:
parent
f5adbb5e3f
commit
a1ccf57727
@ -366,21 +366,13 @@ inner_statement:
|
||||
;
|
||||
|
||||
non_empty_statement:
|
||||
'{' inner_statement_list '}'
|
||||
{
|
||||
if ($2) {
|
||||
$$ = $2; prependLeadingComments($$);
|
||||
} else {
|
||||
makeNop($$);
|
||||
if (null === $$) { $$ = array(); }
|
||||
}
|
||||
}
|
||||
| T_IF '(' expr ')' statement elseif_list else_single
|
||||
{ $$ = Stmt\If_[$3, ['stmts' => toArray($5), 'elseifs' => $6, 'else' => $7]]; }
|
||||
'{' inner_statement_list '}' { $$ = Stmt\Block[$2]; }
|
||||
| T_IF '(' expr ')' blocklike_statement elseif_list else_single
|
||||
{ $$ = Stmt\If_[$3, ['stmts' => $5, 'elseifs' => $6, 'else' => $7]]; }
|
||||
| T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';'
|
||||
{ $$ = Stmt\If_[$3, ['stmts' => $6, 'elseifs' => $7, 'else' => $8]]; }
|
||||
| T_WHILE '(' expr ')' while_statement { $$ = Stmt\While_[$3, $5]; }
|
||||
| T_DO statement T_WHILE '(' expr ')' ';' { $$ = Stmt\Do_ [$5, toArray($2)]; }
|
||||
| T_DO blocklike_statement T_WHILE '(' expr ')' ';' { $$ = Stmt\Do_ [$5, $2]; }
|
||||
| T_FOR '(' for_expr ';' for_expr ';' for_expr ')' for_statement
|
||||
{ $$ = Stmt\For_[['init' => $3, 'cond' => $5, 'loop' => $7, 'stmts' => $9]]; }
|
||||
| T_SWITCH '(' expr ')' switch_case_list { $$ = Stmt\Switch_[$3, $5]; }
|
||||
@ -416,14 +408,16 @@ non_empty_statement:
|
||||
{ $$ = Stmt\TryCatch[$3, $5, $6]; $this->checkTryCatch($$); }
|
||||
| T_GOTO identifier_not_reserved semi { $$ = Stmt\Goto_[$2]; }
|
||||
| identifier_not_reserved ':' { $$ = Stmt\Label[$1]; }
|
||||
| error { $$ = array(); /* means: no statement */ }
|
||||
| error { $$ = null; /* means: no statement */ }
|
||||
;
|
||||
|
||||
statement:
|
||||
non_empty_statement
|
||||
| ';'
|
||||
{ makeNop($$);
|
||||
if ($$ === null) $$ = array(); /* means: no statement */ }
|
||||
| ';' { makeNop($$); }
|
||||
;
|
||||
|
||||
blocklike_statement:
|
||||
statement { toBlock($1); }
|
||||
;
|
||||
|
||||
catches:
|
||||
@ -554,17 +548,17 @@ non_empty_class_name_list:
|
||||
;
|
||||
|
||||
for_statement:
|
||||
statement { $$ = toArray($1); }
|
||||
blocklike_statement
|
||||
| ':' inner_statement_list T_ENDFOR ';' { $$ = $2; }
|
||||
;
|
||||
|
||||
foreach_statement:
|
||||
statement { $$ = toArray($1); }
|
||||
blocklike_statement
|
||||
| ':' inner_statement_list T_ENDFOREACH ';' { $$ = $2; }
|
||||
;
|
||||
|
||||
declare_statement:
|
||||
non_empty_statement { $$ = toArray($1); }
|
||||
non_empty_statement { toBlock($1); }
|
||||
| ';' { $$ = null; }
|
||||
| ':' inner_statement_list T_ENDDECLARE ';' { $$ = $2; }
|
||||
;
|
||||
@ -624,7 +618,7 @@ match_arm:
|
||||
;
|
||||
|
||||
while_statement:
|
||||
statement { $$ = toArray($1); }
|
||||
blocklike_statement { $$ = $1; }
|
||||
| ':' inner_statement_list T_ENDWHILE ';' { $$ = $2; }
|
||||
;
|
||||
|
||||
@ -634,7 +628,7 @@ elseif_list:
|
||||
;
|
||||
|
||||
elseif:
|
||||
T_ELSEIF '(' expr ')' statement { $$ = Stmt\ElseIf_[$3, toArray($5)]; }
|
||||
T_ELSEIF '(' expr ')' blocklike_statement { $$ = Stmt\ElseIf_[$3, $5]; }
|
||||
;
|
||||
|
||||
new_elseif_list:
|
||||
@ -649,7 +643,7 @@ new_elseif:
|
||||
|
||||
else_single:
|
||||
/* empty */ { $$ = null; }
|
||||
| T_ELSE statement { $$ = Stmt\Else_[toArray($2)]; }
|
||||
| T_ELSE blocklike_statement { $$ = Stmt\Else_[$2]; }
|
||||
;
|
||||
|
||||
new_else_single:
|
||||
|
@ -87,14 +87,15 @@ function resolveMacros($code) {
|
||||
if ('pushNormalizing' === $name) {
|
||||
assertArgs(2, $args, $name);
|
||||
|
||||
return 'if (is_array(' . $args[1] . ')) { $$ = array_merge(' . $args[0] . ', ' . $args[1] . '); }'
|
||||
. ' else { ' . $args[0] . '[] = ' . $args[1] . '; $$ = ' . $args[0] . '; }';
|
||||
return 'if (' . $args[1] . ' !== null) { ' . $args[0] . '[] = ' . $args[1] . '; } $$ = ' . $args[0] . ';';
|
||||
}
|
||||
|
||||
if ('toArray' == $name) {
|
||||
if ('toBlock' == $name) {
|
||||
assertArgs(1, $args, $name);
|
||||
|
||||
return 'is_array(' . $args[0] . ') ? ' . $args[0] . ' : array(' . $args[0] . ')';
|
||||
return 'if (' . $args[0] . ' instanceof Stmt\Block) { $$ = ' . $args[0] . '->stmts; } '
|
||||
. 'else if (' . $args[0] . ' === null) { $$ = []; } '
|
||||
. 'else { $$ = [' . $args[0] . ']; }';
|
||||
}
|
||||
|
||||
if ('parseVar' === $name) {
|
||||
@ -122,15 +123,6 @@ function resolveMacros($code) {
|
||||
return $args[0] . ' = $this->maybeCreateZeroLengthNop($this->tokenPos);';
|
||||
}
|
||||
|
||||
if ('prependLeadingComments' === $name) {
|
||||
assertArgs(1, $args, $name);
|
||||
|
||||
return '$comments = $this->getCommentsBeforeToken($this->tokenStartStack[#1]); $stmts = ' . $args[0] . '; '
|
||||
. 'if (!empty($comments)) {'
|
||||
. '$stmts[0]->setAttribute(\'comments\', '
|
||||
. 'array_merge($comments, $stmts[0]->getAttribute(\'comments\', []))); }';
|
||||
}
|
||||
|
||||
return $matches[0];
|
||||
},
|
||||
$code
|
||||
|
@ -195,12 +195,6 @@ class TokenStream {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function haveBracesInRange(int $startPos, int $endPos): bool {
|
||||
return $this->haveTokenInRange($startPos, $endPos, '{')
|
||||
|| $this->haveTokenInRange($startPos, $endPos, T_CURLY_OPEN)
|
||||
|| $this->haveTokenInRange($startPos, $endPos, '}');
|
||||
}
|
||||
|
||||
public function haveTagInRange(int $startPos, int $endPos): bool {
|
||||
return $this->haveTokenInRange($startPos, $endPos, \T_OPEN_TAG)
|
||||
|| $this->haveTokenInRange($startPos, $endPos, \T_CLOSE_TAG);
|
||||
|
29
lib/PhpParser/Node/Stmt/Block.php
Normal file
29
lib/PhpParser/Node/Stmt/Block.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Stmt;
|
||||
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
class Block extends Stmt {
|
||||
/** @var Stmt[] Statements */
|
||||
public array $stmts;
|
||||
|
||||
/**
|
||||
* A block of statements.
|
||||
*
|
||||
* @param Stmt[] $stmts Statements
|
||||
* @param array<string, mixed> $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $stmts, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->stmts = $stmts;
|
||||
}
|
||||
|
||||
public function getType(): string {
|
||||
return 'Stmt_Block';
|
||||
}
|
||||
|
||||
public function getSubNodeNames(): array {
|
||||
return ['stmts'];
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1012,6 +1012,10 @@ class Standard extends PrettyPrinterAbstract {
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function pStmt_Block(Stmt\Block $node): string {
|
||||
return '{' . $this->pStmts($node->stmts) . $this->nl . '}';
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
protected function pClassCommon(Stmt\Class_ $node, string $afterClassToken): string {
|
||||
|
@ -826,9 +826,8 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
}
|
||||
|
||||
if ($skipRemovedNode) {
|
||||
if ($isStmtList && ($this->origTokens->haveBracesInRange($pos, $itemStartPos) ||
|
||||
$this->origTokens->haveTagInRange($pos, $itemStartPos))) {
|
||||
// We'd remove the brace of a code block.
|
||||
if ($isStmtList && $this->origTokens->haveTagInRange($pos, $itemStartPos)) {
|
||||
// We'd remove an opening/closing PHP tag.
|
||||
// TODO: Preserve formatting.
|
||||
$this->setIndentLevel($origIndentLevel);
|
||||
return null;
|
||||
@ -937,9 +936,8 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
$pos, $itemStartPos, $indentAdjustment);
|
||||
$skipRemovedNode = true;
|
||||
} else {
|
||||
if ($isStmtList && ($this->origTokens->haveBracesInRange($pos, $itemStartPos) ||
|
||||
$this->origTokens->haveTagInRange($pos, $itemStartPos))) {
|
||||
// We'd remove the brace of a code block.
|
||||
if ($isStmtList && $this->origTokens->haveTagInRange($pos, $itemStartPos)) {
|
||||
// We'd remove an opening/closing PHP tag.
|
||||
// TODO: Preserve formatting.
|
||||
return null;
|
||||
}
|
||||
@ -1540,6 +1538,7 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
Stmt\Function_::class . '->stmts' => "\n",
|
||||
Stmt\If_::class . '->stmts' => "\n",
|
||||
Stmt\Namespace_::class . '->stmts' => "\n",
|
||||
Stmt\Block::class . '->stmts' => "\n",
|
||||
|
||||
// Attribute groups
|
||||
Stmt\Class_::class . '->attrGroups' => "\n",
|
||||
|
@ -153,8 +153,9 @@ $stmts[1] = $tmp;
|
||||
* fallback. */
|
||||
-----
|
||||
<?php
|
||||
|
||||
{
|
||||
$x;
|
||||
}
|
||||
function foo() {
|
||||
foo();
|
||||
/*
|
||||
|
@ -354,3 +354,16 @@ array_splice($stmts[0]->expr->var->items, 1, 0, [null]);
|
||||
-----
|
||||
<?php
|
||||
list($x, , $y) = $z;
|
||||
-----
|
||||
<?php
|
||||
{
|
||||
$a; $b;
|
||||
}
|
||||
-----
|
||||
$stmts[0]->stmts[] = new Stmt\Expression(new Expr\Variable('c'));
|
||||
-----
|
||||
<?php
|
||||
{
|
||||
$a; $b;
|
||||
$c;
|
||||
}
|
||||
|
@ -70,7 +70,6 @@ $y;
|
||||
array_splice($stmts, 0, 1, []);
|
||||
-----
|
||||
<?php
|
||||
|
||||
$y;
|
||||
-----
|
||||
<?php
|
||||
@ -80,8 +79,7 @@ $x;
|
||||
array_splice($stmts, 0, 1, []);
|
||||
-----
|
||||
<?php
|
||||
|
||||
$y;
|
||||
{ $y; }
|
||||
-----
|
||||
<?php
|
||||
$x;
|
||||
@ -90,7 +88,6 @@ $x;
|
||||
array_pop($stmts);
|
||||
-----
|
||||
<?php
|
||||
|
||||
$x;
|
||||
-----
|
||||
<?php
|
||||
@ -100,8 +97,7 @@ $y;
|
||||
array_pop($stmts);
|
||||
-----
|
||||
<?php
|
||||
|
||||
$x;
|
||||
{ $x; }
|
||||
-----
|
||||
<?php
|
||||
// Foo
|
||||
|
@ -15,6 +15,10 @@ Comments on blocks
|
||||
{}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_Variable(
|
||||
name: a
|
||||
@ -22,13 +26,23 @@ array(
|
||||
0: // baz
|
||||
)
|
||||
)
|
||||
comments: array(
|
||||
0: // baz
|
||||
)
|
||||
)
|
||||
)
|
||||
comments: array(
|
||||
0: // bar
|
||||
)
|
||||
)
|
||||
)
|
||||
comments: array(
|
||||
0: // foo
|
||||
1: // bar
|
||||
2: // baz
|
||||
)
|
||||
)
|
||||
1: Stmt_Nop(
|
||||
1: Stmt_Block(
|
||||
stmts: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // empty
|
||||
)
|
||||
|
@ -223,7 +223,9 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
1: Stmt_Expression(
|
||||
1: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_Assign(
|
||||
var: Expr_Variable(
|
||||
name: j
|
||||
@ -233,6 +235,8 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
2: Stmt_Expression(
|
||||
expr: Expr_Assign(
|
||||
var: Expr_Variable(
|
||||
|
@ -19,9 +19,13 @@ array(
|
||||
-----
|
||||
!!positions
|
||||
array(
|
||||
0: Stmt_Block[2:1 - 4:1](
|
||||
stmts: array(
|
||||
0: Stmt_Nop[3:0 - 3:17](
|
||||
comments: array(
|
||||
0: /* comment */
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -42,6 +42,10 @@ array(
|
||||
-----
|
||||
Syntax error, unexpected T_STATIC, expecting T_STRING from 1:13 to 1:18
|
||||
array(
|
||||
0: Stmt_Block(
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php class A extends self {}
|
||||
@ -211,6 +215,10 @@ array(
|
||||
-----
|
||||
Syntax error, unexpected T_STATIC, expecting T_STRING from 1:17 to 1:22
|
||||
array(
|
||||
0: Stmt_Block(
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php interface A extends self {}
|
||||
|
@ -5,6 +5,10 @@ class ReadOnly {}
|
||||
-----
|
||||
Syntax error, unexpected T_READONLY, expecting T_STRING from 2:7 to 2:14
|
||||
array(
|
||||
0: Stmt_Block(
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php
|
||||
|
@ -4,7 +4,9 @@ Declare
|
||||
|
||||
declare (X='Y');
|
||||
|
||||
declare (A='B', C='D') {}
|
||||
declare (A='B', C='D') {
|
||||
echo "foo";
|
||||
}
|
||||
|
||||
declare (A='B', C='D'):
|
||||
enddeclare;
|
||||
@ -43,6 +45,13 @@ array(
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Echo(
|
||||
exprs: array(
|
||||
0: Scalar_String(
|
||||
value: foo
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
2: Stmt_Declare(
|
||||
|
@ -63,14 +63,16 @@ array(
|
||||
0: // Missing NS separator
|
||||
)
|
||||
)
|
||||
1: Stmt_Expression(
|
||||
1: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_ConstFetch(
|
||||
name: Name(
|
||||
name: Bar
|
||||
)
|
||||
)
|
||||
)
|
||||
2: Stmt_Expression(
|
||||
1: Stmt_Expression(
|
||||
expr: Expr_ConstFetch(
|
||||
name: Name(
|
||||
name: Baz
|
||||
@ -78,6 +80,8 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php
|
||||
// Extra NS separator
|
||||
|
28
test/code/prettyPrinter/stmt/block.test
Normal file
28
test/code/prettyPrinter/stmt/block.test
Normal file
@ -0,0 +1,28 @@
|
||||
Block statements
|
||||
-----
|
||||
<?php
|
||||
echo "a";
|
||||
{
|
||||
}
|
||||
{
|
||||
echo "b";
|
||||
}
|
||||
if ($c) {
|
||||
echo "c";
|
||||
{
|
||||
echo "d";
|
||||
}
|
||||
}
|
||||
-----
|
||||
echo "a";
|
||||
{
|
||||
}
|
||||
{
|
||||
echo "b";
|
||||
}
|
||||
if ($c) {
|
||||
echo "c";
|
||||
{
|
||||
echo "d";
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user