Skip to content

Commit 68ce715

Browse files
committed
added precision for s and d, also parameter index option
1 parent 10db957 commit 68ce715

File tree

1 file changed

+45
-24
lines changed

1 file changed

+45
-24
lines changed

src/HLL/sprintf.nqp

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
my module sprintf {
22
my @handlers;
3+
my $assert_used_args;
34

45
grammar Syntax {
56
token TOP {
@@ -18,22 +19,26 @@ my module sprintf {
1819
}
1920

2021
proto token directive { <...> }
21-
token directive:sym<b> { '%' <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[bB]> }
22-
token directive:sym<c> { '%' <flags>* <size>? <sym> }
23-
token directive:sym<d> { '%' <flags>* <size>? $<sym>=<[di]> }
24-
token directive:sym<e> { '%' <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[eE]> }
25-
token directive:sym<f> { '%' <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[fF]> }
26-
token directive:sym<g> { '%' <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[gG]> }
27-
token directive:sym<o> { '%' <flags>* <size>? [ '.' <precision=.size> ]? <sym> }
28-
token directive:sym<s> { '%' <flags>* <size>? <sym> }
29-
token directive:sym<u> { '%' <flags>* <size>? <sym> }
30-
token directive:sym<x> { '%' <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[xX]> }
22+
token directive:sym<b> { '%' <idx>? <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[bB]> }
23+
token directive:sym<c> { '%' <idx>? <flags>* <size>? <sym> }
24+
token directive:sym<d> { '%' <idx>? <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[di]> }
25+
token directive:sym<e> { '%' <idx>? <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[eE]> }
26+
token directive:sym<f> { '%' <idx>? <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[fF]> }
27+
token directive:sym<g> { '%' <idx>? <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[gG]> }
28+
token directive:sym<o> { '%' <idx>? <flags>* <size>? [ '.' <precision=.size> ]? <sym> }
29+
token directive:sym<s> { '%' <idx>? <flags>* <size>? [ '.' <precision=.size> ]? <sym> }
30+
token directive:sym<u> { '%' <idx>? <flags>* <size>? <sym> }
31+
token directive:sym<x> { '%' <idx>? <flags>* <size>? [ '.' <precision=.size> ]? $<sym>=<[xX]> }
3132

3233
proto token escape { <...> }
3334
token escape:sym<%> { '%' <flags>* <size>? <sym> }
3435

3536
token literal { <-[%]>+ }
3637

38+
token idx {
39+
$<param_index>=[\d+] '$'
40+
}
41+
3742
token flags {
3843
| $<space> = ' '
3944
| $<plus> = '+'
@@ -52,7 +57,7 @@ my module sprintf {
5257
my @statements;
5358
@statements.push( $_.ast ) for $<statement>;
5459

55-
if $*ARGS_USED < +@*ARGS_HAVE {
60+
if $assert_used_args && $*ARGS_USED < +@*ARGS_HAVE {
5661
nqp::die("Too few directives: found $*ARGS_USED,"
5762
~ " fewer than the " ~ +@*ARGS_HAVE ~ " arguments after the format string")
5863
}
@@ -71,8 +76,14 @@ my module sprintf {
7176
nqp::join('', @strings);
7277
}
7378

74-
sub next_argument() {
75-
@*ARGS_HAVE[$*ARGS_USED++]
79+
sub next_argument($/) {
80+
if $<idx> {
81+
$assert_used_args := 0;
82+
@*ARGS_HAVE[$<idx>.ast]
83+
}
84+
else {
85+
@*ARGS_HAVE[$*ARGS_USED++]
86+
}
7687
}
7788

7889
sub intify($number_representation) {
@@ -132,7 +143,7 @@ my module sprintf {
132143
}
133144

134145
method directive:sym<b>($/) {
135-
my $int := intify(next_argument());
146+
my $int := intify(next_argument($/));
136147
$int := nqp::base_I($int, 2);
137148
my $pre := ($<sym> eq 'b' ?? '0b' !! '0B') if $int && has_flag($/, 'hash');
138149
if nqp::chars($<precision>) {
@@ -145,17 +156,18 @@ my module sprintf {
145156
make $int;
146157
}
147158
method directive:sym<c>($/) {
148-
make nqp::chr(next_argument())
159+
make nqp::chr(next_argument($/))
149160
}
150161

151162
method directive:sym<d>($/) {
152-
my $int := intify(next_argument());
163+
my $int := intify(next_argument($/));
153164
my $knowhow := nqp::knowhow().new_type(:repr("P6bigint"));
154165
my $pad := padding_char($/);
155166
my $sign := nqp::islt_I($int, nqp::box_i(0, $knowhow)) ?? '-'
156167
!! has_flag($/, 'plus')
157168
?? '+' !! '';
158169
$int := nqp::tostr_I(nqp::abs_I($int, $knowhow));
170+
$int := nqp::substr($int, 0, $<precision>.ast) if nqp::chars($<precision>);
159171
if $pad ne ' ' && $<size> {
160172
$int := $sign ~ infix_x($pad, $<size>.ast - nqp::chars($int) - 1) ~ $int;
161173
}
@@ -243,28 +255,28 @@ my module sprintf {
243255
}
244256

245257
method directive:sym<e>($/) {
246-
my $float := next_argument();
258+
my $float := next_argument($/);
247259
my $precision := $<precision> ?? $<precision>.ast !! 6;
248260
my $pad := padding_char($/);
249261
my $size := $<size> ?? $<size>.ast !! 0;
250262
make scientific($float, $<sym>, $precision, $size, $pad);
251263
}
252264
method directive:sym<f>($/) {
253-
my $int := next_argument();
265+
my $int := next_argument($/);
254266
my $precision := $<precision> ?? $<precision>.ast !! 6;
255267
my $pad := padding_char($/);
256268
my $size := $<size> ?? $<size>.ast !! 0;
257269
make fixed-point($int, $precision, $size, $pad);
258270
}
259271
method directive:sym<g>($/) {
260-
my $float := next_argument();
272+
my $float := next_argument($/);
261273
my $precision := $<precision> ?? $<precision>.ast !! 6;
262274
my $pad := padding_char($/);
263275
my $size := $<size> ?? $<size>.ast !! 0;
264276
make shortest($float, $<sym> eq 'G' ?? 'E' !! 'e', $precision, $size, $pad);
265277
}
266278
method directive:sym<o>($/) {
267-
my $int := intify(next_argument());
279+
my $int := intify(next_argument($/));
268280
$int := nqp::base_I($int, 8);
269281
my $pre := '0' if $int && has_flag($/, 'hash');
270282
if nqp::chars($<precision>) {
@@ -278,12 +290,14 @@ my module sprintf {
278290
}
279291

280292
method directive:sym<s>($/) {
281-
make next_argument()
293+
my $string := next_argument($/);
294+
$string := nqp::substr($string, 0, $<precision>.ast) if nqp::chars($<precision>);
295+
make $string
282296
}
283297
# XXX: Should we emulate an upper limit, like 2**64?
284298
# XXX: Should we emulate p5 behaviour for negative values passed to %u ?
285299
method directive:sym<u>($/) {
286-
my $int := intify(next_argument());
300+
my $int := intify(next_argument($/));
287301
if $int < 0 {
288302
my $err := nqp::getstderr();
289303
nqp::printfh($err, "negative value '"
@@ -298,7 +312,7 @@ my module sprintf {
298312
make nqp::tostr_I($int)
299313
}
300314
method directive:sym<x>($/) {
301-
my $int := intify(next_argument());
315+
my $int := intify(next_argument($/));
302316
$int := nqp::base_I($int, 16);
303317
my $pre := '0X' if $int && has_flag($/, 'hash');
304318
if nqp::chars($<precision>) {
@@ -319,15 +333,22 @@ my module sprintf {
319333
make ~$/
320334
}
321335

336+
method idx($/) {
337+
my $index := $<param_index> - 1;
338+
nqp::die("Parameter index starts to count at 1 but 0 was passed") if $index < 0;
339+
make $index
340+
}
341+
322342
method size($/) {
323-
make $<star> ?? next_argument() !! ~$/
343+
make $<star> ?? next_argument({}) !! ~$/
324344
}
325345
}
326346

327347
my $actions := Actions.new();
328348

329349
sub sprintf($format, @arguments) {
330350
my @*ARGS_HAVE := @arguments;
351+
$assert_used_args := 1;
331352
return Syntax.parse( $format, :actions($actions) ).ast;
332353
}
333354

0 commit comments

Comments
 (0)