From 388f339de8385aaf352e664456d1e04fb131fe65 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 14:58:49 +0000 Subject: [PATCH 1/2] Initial plan From 4c12a5e30f1e6be61461b0ad92eadaaabd6f7954 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 15:05:22 +0000 Subject: [PATCH 2/2] feat: add T_PERCENT to ArgumentLexeme for %4% style specifiers Agent-Logs-Url: https://github.com/donatj/printf-parser/sessions/e0bec571-8995-42d0-95e4-b614c587fb7f Co-authored-by: donatj <133747+donatj@users.noreply.github.com> --- src/ArgumentLexeme.php | 3 +++ test/Integration/ParserTest.php | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/ArgumentLexeme.php b/src/ArgumentLexeme.php index c945faf..cc5c88c 100644 --- a/src/ArgumentLexeme.php +++ b/src/ArgumentLexeme.php @@ -43,6 +43,8 @@ class ArgumentLexeme extends Lexeme { public const T_INT_HEX = 'x'; /** @var string the argument is treated as an integer and presented as a hexadecimal number (with uppercase letters). */ public const T_INT_HEX_CAP = 'X'; + /** @var string a percent-sign type specifier (e.g. `%4%`). Unlike `%%`, an argument must be supplied even though it is not used. */ + public const T_PERCENT = '%'; public const VALID_T_TYPES = [ self::T_INT_AS_BINARY, @@ -61,6 +63,7 @@ class ArgumentLexeme extends Lexeme { self::T_INT_UNSIGNED, self::T_INT_HEX, self::T_INT_HEX_CAP, + self::T_PERCENT, ]; public const ARG_TYPE_MISSING = ''; diff --git a/test/Integration/ParserTest.php b/test/Integration/ParserTest.php index 086d7bc..2d1b8b8 100644 --- a/test/Integration/ParserTest.php +++ b/test/Integration/ParserTest.php @@ -233,6 +233,24 @@ public static function parseStringProvider() : array { '[=ll:1|||pos:|||left:||l][!=s:3]', false, ], + + 'percent type with width' => [ + '%4%', + '[%=4%:1|||pos:||4|left:|]', + true, + ], + + 'percent type with long modifier' => [ + '%l%', + '[%=l%:1|||pos:|||left:||l]', + true, + ], + + 'percent type with flags and precision' => [ + '%+5.5%', + '[%=+5.5%:1|||pos:1||5|left:|5]', + true, + ], ]; } @@ -377,6 +395,27 @@ public static function printfWithTypeProvider() : array { [ 1 => ArgumentLexeme::ARG_TYPE_DOUBLE, ArgumentLexeme::ARG_TYPE_INT ], true, ], + + 'percent type with width consumes one argument' => [ + '%4%', + [ [ ArgumentLexeme::ARG_TYPE_MISSING ] ], + [ 1 => ArgumentLexeme::ARG_TYPE_MISSING ], + true, + ], + + 'percent type with long modifier consumes one argument' => [ + '%l%', + [ [ ArgumentLexeme::ARG_TYPE_MISSING ] ], + [ 1 => ArgumentLexeme::ARG_TYPE_MISSING ], + true, + ], + + 'percent type with flags and precision consumes one argument' => [ + '%+5.5%', + [ [ ArgumentLexeme::ARG_TYPE_MISSING ] ], + [ 1 => ArgumentLexeme::ARG_TYPE_MISSING ], + true, + ], ]; }