Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add builtin::numify #21982

Draft
wants to merge 2 commits into
base: blead
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ XS(XS_builtin_func1_scalar)
Perl_pp_stringify(aTHX);
break;

case OP_NUMIFY:
Perl_pp_numify(aTHX);
break;

default:
Perl_die(aTHX_ "panic: unhandled opcode %" IVdf
" for xs_builtin_func1_scalar()", (IV) ix);
Expand Down Expand Up @@ -532,6 +536,7 @@ static const struct BuiltinFuncDescriptor builtins[] = {
{ "is_tainted", SHORTVER(5,39), &XS_builtin_func1_scalar, &ck_builtin_func1, OP_IS_TAINTED, false },
{ "trim", SHORTVER(5,39), &XS_builtin_trim, &ck_builtin_func1, 0, false },
{ "stringify", NO_BUNDLE, &XS_builtin_func1_scalar, &ck_builtin_func1, OP_STRINGIFY, true },
{ "numify", NO_BUNDLE, &XS_builtin_func1_scalar, &ck_builtin_func1, OP_NUMIFY, true },

{ "created_as_string", NO_BUNDLE, &XS_builtin_created_as_string, &ck_builtin_func1, 0, true },
{ "created_as_number", NO_BUNDLE, &XS_builtin_created_as_number, &ck_builtin_func1, 0, true },
Expand Down
3 changes: 2 additions & 1 deletion ext/Opcode/Opcode.pm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package Opcode 1.65;
package Opcode 1.66;

use strict;

Expand Down Expand Up @@ -313,6 +313,7 @@ invert_opset function.
preinc i_preinc predec i_predec postinc i_postinc
postdec i_postdec int hex oct abs pow multiply i_multiply
divide i_divide modulo i_modulo add i_add subtract i_subtract
numify

left_shift right_shift bit_and bit_xor bit_or nbit_and
nbit_xor nbit_or sbit_and sbit_xor sbit_or negate i_negate not
Expand Down
5 changes: 3 additions & 2 deletions lib/B/Op_private.pm

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 24 additions & 3 deletions lib/builtin.pm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package builtin 0.012;
package builtin 0.013;

use strict;
use warnings;
Expand All @@ -21,7 +21,7 @@ builtin - Perl pragma to import built-in utility functions
weaken unweaken is_weak
blessed refaddr reftype
created_as_string created_as_number
stringify
stringify numify
ceil floor
indexed
trim
Expand Down Expand Up @@ -253,7 +253,8 @@ When given a value that is already a string, a copy of this value is returned
unchanged. False booleans are treated like the empty string.

Numbers are turned into a decimal representation. True booleans are treated
like the number 1.
like the number 1. C<undef> is treated as the empty string, provoking a
warning in the usual way.

References to objects in classes that have L<overload> and define the C<"">
overload entry will use the delegated method to provide a value here.
Expand All @@ -263,6 +264,26 @@ overload will return a string that names the underlying container type of
the reference, its memory address, and possibly its class name if it is an
object.

=head2 numify

$num = numify($val);

Returns a new plain perl number that represents the given argument.

When given a value that is already a number, a copy of this value is returned
unchanged. False booleans are treated like the number zero.

Strings are turned into a number by attempting to interpret a decimal
representation, possibly provoking a warning in the usual way. C<undef> is
treated as the number zero, again with a warning in the usual way.

References to objects in class that have L<overload> and define the C<0+>
overload entry will use the delegated method to provide a value here.

Non-object references, or references to objects in classes without a C<0+>
overload will return a number that represents the memory address of the
referred item.

=head2 ceil

$num = ceil($num);
Expand Down
27 changes: 27 additions & 0 deletions lib/builtin.t
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,33 @@ package FetchStoreCounter {
is(stringify(bless [], "WithOverloadedStringify"), "STRING", 'stringify invokes "" overload');
}

# numify
{
use builtin qw( numify );

is(numify(123), 123, 'numify an integral number');
is(numify(1.23), 1.23, 'numify a floating point number');
is(numify("456"), 456, 'numify a string');

my $aref = [];
is(numify($aref), $aref+0, 'numify an array ref');

use builtin qw( created_as_number );
ok(!ref numify($aref), 'numified arrayref is not a ref');
ok(created_as_number(numify($aref)), 'numified arrayref is created as num');

{
no warnings 'uninitialized';
is(numify(undef), 0, 'numified undef is zero');
}

package WithOverloadedNumify {
use overload '0+' => sub { return 987 };
}

is(numify(bless [], "WithOverloadedNumify"), 987, 'numify invokes 0+ overload');
}

# ceil, floor
{
use builtin qw( ceil floor );
Expand Down
9 changes: 8 additions & 1 deletion opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion opnames.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions pp.c
Original file line number Diff line number Diff line change
Expand Up @@ -7989,6 +7989,21 @@ PP(pp_is_tainted)
return NORMAL;
}

PP(pp_numify)
{
dTARGET;
SV *ssv = *PL_stack_sp;
if(SvNOK(ssv))
Comment on lines +7995 to +7996
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to SvGETMAGIC() before checking the flags:

$ ./perl ../21982.pl 
Built-in function 'builtin::numify' is experimental at ../21982.pl line 9.
Use of uninitialized value $magic in number conversion at ../21982.pl line 9.
0
123
$ cat ../21982.pl
#!perl
use v5.36.0;

my $val;

tie my $magic, "Foo";

$val = "123";
say builtin::numify($magic);
say $magic;

package Foo {
  sub TIESCALAR { bless {}, shift; }


  sub FETCH { $val }
}

Similarly:

$ ./perl -Ilib -E '$! = 0; open my $fh, "<", "unknown"; say builtin::numify($!); say $!+0'
Built-in function 'builtin::numify' is experimental at -e line 1.
0
2

sv_setnv(TARG, SvNV_nomg(ssv));
else if(SvIOK(ssv) && SvIsUV(ssv))
sv_setuv(TARG, SvUV_nomg(ssv));
else
sv_setiv(TARG, SvIV_nomg(ssv));
Comment on lines +8000 to +8001
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overloaded 0+ that returns a non-integer:

$ ./perl -Ilib ../21982b.pl 
Built-in function 'builtin::numify' is experimental at ../21982b.pl line 11.
3.14159265
3
$ cat ../21982b.pl
#!perl
use v5.36.0;
package Foo {
  use overload
    '0+' => sub { 3.14159265 },
    fallback => 1;
}
my $x = bless {}, "Foo";

say 0+$x;
say builtin::numify($x);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one I'm not so sure about:

$ ./perl -Ilib ../21982c.pl 
Built-in function 'builtin::numify' is experimental at ../21982c.pl line 7.
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
3
$ cat ../21982c.pl
#!perl
use v5.36.0;
use bigfloat;
my $x = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;

say 0+$x;
say builtin::numify($x);

SvSETMAGIC(TARG);
rpp_replace_1_1_NN(TARG);
return NORMAL;
}

/*
* ex: set ts=8 sts=4 sw=4 et:
*/
1 change: 1 addition & 0 deletions pp_proto.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions regen/opcodes
Original file line number Diff line number Diff line change
Expand Up @@ -605,3 +605,5 @@ methstart method start ck_null +
initfield initialise field ck_null +

classname class name ck_classname 0t

numify number conversion ck_fun fsT1 S
18 changes: 18 additions & 0 deletions t/lib/warnings/builtin
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,24 @@ Built-in function 'builtin::is_bool' is experimental at - line 6.
Built-in function 'builtin::is_bool' is experimental at - line 9.
Built-in function 'builtin::is_bool' is experimental at - line 12.
########
# builtin.c - stringify
use warnings qw(all -experimental::builtin);
use builtin qw(stringify);
my $x;
$x = stringify(undef);
EXPECT
Use of uninitialized value in string at - line 5.
########
# builtin.c - numify
use warnings qw(all -experimental::builtin);
use builtin qw(numify);
my $x;
$x = numify(undef);
$x = numify("hello");
EXPECT
Use of uninitialized value in number conversion at - line 5.
Argument "hello" isn't numeric in number conversion at - line 6.
########
# builtin.c - weakrefs
use strict;
use warnings qw(all -void);
Expand Down