Repository navigation
v0.26.0
Error messages and recovery follow PHP more closely, spans are ordered and stay inside their parent, and the printer keeps invalid code invalid.
Added
PropertyDecl::empty_hook_listandParam::empty_hook_listfor an empty hook list{}(php-ast).FunctionDecl::missing_param_list,MethodDecl::missing_param_list,ClosureExpr::missing_param_listandArrowFunctionExpr::missing_param_listfor a parameter list missing its((php-ast).LexerErrorKind::UnexpectedCharacter(php-lexer) andForbiddenRule::UnexpectedCharacter(php-rs-parser) for a control character in code.PrinterConfig::php_version, the PHP version the output is for (php-printer).ForbiddenRule::CallResultWriteandForbiddenRule::ListAsForeachKey(php-rs-parser).ParseError::UnmatchedDelimiterfor a}that closes nothing (php-rs-parser).ForeachStmt::by_ref_span, the&of a by-reference value (php-ast).Modifiers::is_varfor a property declared withvar(php-ast).
Changed
- The messages for a positional or unpacked argument after a named one, an unparenthesized nested ternary and an unparenthesized arrow function after
|>match PHP's (php-rs-parser). - A write to a call result, as in
f() = 1,$a->f()++,unset(f())or[f()] = $a, reports PHP'sCan't use function return value in write contextorCan't use method return value in write context, and a list as aforeachkeyCannot use list as key element(php-rs-parser). - From PHP 8.4, a
voidorneverreturn error in a method, or in a closure or arrow function inside a class, says "method" as PHP does (A void method must not return a value), andreturn null;from avoidfunction adds PHP's(did you mean "return;" instead of "return null;"?)(php-rs-parser). breakorcontinueoutside a loop orswitchreports PHP's'break' not in the 'loop' or 'switch' contextinstead ofCannot 'break' 1 level(php-rs-parser).- A repeated member or promoted-parameter modifier reports PHP's message, such as
Multiple access type modifiers are not allowedforpublic publicorpublic private(set) protected(set)andMultiple static modifiers are not allowed(php-rs-parser). - A repeated class modifier, as in
readonly readonly classorabstract readonly abstract class, reports PHP'sMultiple readonly modifiers are not allowedinstead of a syntax error, andabstract final classPHP'sCannot use the final modifier on an abstract class(php-rs-parser). - A
}at the top level that closes nothing reportsunmatched '}', as PHP'sUnmatched '}', instead ofexpected expression, found '}'andNo code may exist outside of namespace {}(php-rs-parser). - A
trywhose body is missing its{or}no longer also reports a missingcatchorfinallyclause, and compile errors inside an unclosed parameter list, such asCannot declare promoted property outside a constructorforfunction f(int $x { }, are dropped, since PHP stops at the syntax error (php-rs-parser). - Fewer recovery cascades: a
<?phpor<?=inside PHP code is one error and the statement after it parses; amatcharm missing its comma reports only that; the rest of a brokenforheader, as infor (;;;), is skipped; and aclasswith neither a name nor a body, as inclass\Foo::x();before PHP 8.0, no longer reads the following statements as class members (php-rs-parser). - A dynamic property fetch spans its closing
}, as in$o->{'x'}; a groupuseitem's name spans the name as written,DinA\{B, D}, instead of the prefix and its siblings;"${a}"spans the whole${a}like"${a[0]}"; and a statement or enum member with attributes starts at its first attribute, like a class member (php-rs-parser). - Each constant or property of a grouped declaration, as in
const A = 1, B = 2;orpublic $a, $b;, spans its own item, the first one from the modifiers, instead of the whole declaration or every earlier item, and a later item keeps its own doc comment, as PHP does (php-rs-parser). - A namespaced name starting with a keyword where it is not expected, as in
class A implements\B {}, is reported over the whole name, as PHP lexes it (php-rs-parser). - An
if,whileorswitchmissing its(before the{, as inif { }, reports only the missing(instead of also reading the body as a curly-brace offset and an unclosed)opened at the{;forandforeachno longer report an unclosed)whose(was missing (php-rs-parser). - A repeated property hook reports PHP's message,
Cannot redeclare property hook "get", with the hook name as written, instead ofduplicate 'get' hook(php-rs-parser). PhpVersionlives inphp-ast;php-rs-parserre-exports it at the same paths (php-ast,php-rs-parser).- A
?>that is a statement of its own, as after;,},:or another tag, is aNopwith the span of the?>; a?>that ends the statement before it adds nothing, and?><?phpno longer adds aNop(php-rs-parser). - Empty statements are dropped, except where the target PHP version rejects them before a
declare, and so is a?>with nothing but its consumed newline before the next<?php(php-printer). - The
CloseTagtoken includes the one newline after?>(\n,\r\nor\r), as PHP'sT_CLOSE_TAGdoes, so theInlineHtmlafter it holds only the output and theNopfor?>spans the newline (php-lexer,php-rs-parser). <?= ?>and<?=at the end of the file are anEchoholding anError, like<?= ;(php-rs-parser).- A short echo's
Echospan starts at<?=(php-rs-parser). - An
elseifbranch spans fromelseif, and an alternative-syntax then,elseiforelseblock from its:instead of fromif(php-rs-parser). - An alternative-syntax
while,for,foreach,declareorswitchbody spans from its:to its last statement, without the closing keyword, like anifblock; acatchclause spans fromcatchinstead of((php-rs-parser). - An unclosed statement or declaration body reports
missing closing '}', and a body missing its{reports only that, not also its}(php-rs-parser). - A syntax error at the same token as the previous one is dropped as a recovery cascade, as in
<?php if }or a body missing at the end of the file (php-rs-parser). - The asymmetric-visibility version error spans the set-visibility modifier, such as
private(set)(php-rs-parser). - A nested
__halt_compiler()reports PHP's message,__HALT_COMPILER() can only be used from the outermost scope, and is a statement of its own: parsing goes on after it, as in PHP, so it no longer reportsmissing closing '}'and its node ends at its;(php-rs-parser). - The printer writes a newline after a
?>before HTML when the source has one there or when the HTML starts with a newline that?>would swallow (php-printer).
Fixed
- An empty hook list
{}prints as{}instead of;, so the printed code keeps PHP's error (php-printer). - A class property with a fully qualified type and no modifier, such as
\Foo $a;, is a syntax error instead of being accepted (php-rs-parser). - An enum property with a fully qualified type, such as
public \Foo\Bar $a;, reportsEnum E cannot include propertiesinstead of a syntax error (php-rs-parser). - An unclosed
exit(,die(orclone(call no longer panics (php-rs-parser). - A promoted parameter with only
readonly,finalor a set-visibility modifier, such asprivate(set) int $a, reports that promotion requires PHP 8.0 (php-rs-parser). - No span ends before it starts: the version errors for set-only visibility on a promoted parameter and for a non-capturing
catch, and the spans of error statements, bodies missing their{,useitems, parameters, attributes, short echo tags, static variables and alternative-syntaxelseifbranches after a missing token (php-rs-parser). - A node recovered from a missing or unexpected token, such as the name and parameter of
public function @return f() {}, is empty and placed right after the last consumed token, so it lies inside its parent's span and no longer covers a token it did not consume (php-rs-parser). - A missing operand before an operator, as in
* 2;, sits at the operator, so the expression and statement no longer start at the whitespace before it (php-rs-parser). - A missing item in a group
use, as inuse A\{B, , C};, has anErrorname instead of the prefix with a span coveringA\{B,(php-rs-parser). - A missing static variable after a trailing comma lies inside its statement's span (
php-rs-parser). __halt_compiler() ?>followed by\rleaves the\rout of the data, as PHP does (php-rs-parser).- A control character in code, including form feed, is an error from PHP 8.0 instead of being skipped (
php-lexer,php-rs-parser). <?phpor<?=inside PHP code lexes as<, so it is a syntax error instead of being ignored (php-lexer).- A
?>where a statement is expected, as inif ($a) ?>x<?php, is the empty body and the HTML after it runs unconditionally, as in PHP (php-rs-parser). - Printing keeps whether a
declare(encoding=...)ordeclare(strict_types=...)after an empty statement is valid, instead of making a?>that ends a statement before one an error (php-printer). - A method missing its
(has no parameters instead of an empty placeholder (php-rs-parser). - A function missing its
(, as infunction f {}, has no parameters, so its body is no longer read as a parameter's property hook list (php-rs-parser). - A closure missing its
(, as infunction {}, has no parameters, so its body is no longer read as a parameter's property hook list (php-rs-parser). - An arrow function missing its
(, as infn => 1, has no parameters instead of an empty placeholder (php-rs-parser). - A grouped constant or property is split into declarations that keep their own doc comments, instead of moving
/** q */inpublic $p, /** q */ $q;to the next member (php-printer). - A comment before a property hook, such as a doc comment on
set(int $value) {}or// cbeforeget, prints before the hook instead of between its parameter list or keyword and its body (php-printer). - A heredoc line whose escapes decode to the closing label, as
\x45OTin<<<EOT, prints with its first byte escaped instead of ending the heredoc early (php-printer). - A control character in a string, backtick or heredoc literal prints as
\xNNinstead of the raw byte, so"a\0b"prints as"a\x00b"instead of a single-quoted string holding a NUL, consistent with\e,\fand\v(php-printer). - An empty alternative-syntax body, as in
foreach ($a as &$v): endforeach;orif ($a): endif;, prints without a blank line (php-printer). - A blank line follows a function, class-like or namespace declaration as it precedes one, instead of only before it (
php-printer). - A property declared with
varprints asvarinstead ofpublic(php-printer). - With the source given, a nested ternary or an arrow function after
|>that the source writes without parentheses prints without them, so$a ? $b : $c ? $d : $eand1 |> fn($x) => $xkeep PHP's error instead of becoming valid; without the source, the printer still adds the parentheses (php-printer). - A function, method, closure or arrow function missing its
(prints without(), so the printed code keeps PHP's error instead of becoming valid (php-printer). - A syntax error at the closing
}of a{$...}interpolation, as in"{$a->}", reportsfound '}'at the}instead offound end of file(php-rs-parser). - Recovery from an invalid class or enum member skips over a
{ ... }block, so the block's}no longer ends the class, as inpublic function @return f() {}(php-rs-parser). - A spread in
list(), as inlist(...$x) = $a, or in aforeachdestructuring target reports PHP'sSpread operator is not supported in assignmentsinstead of a syntax error orAssignments can only happen to writable values; an element of a nested list is reported at the element (php-rs-parser).