Skip to content

Commit 29cc805

Browse files
committed
Implement assigning xor (^^=) operator
When I added '^^' I forgot to implement or test the assigning version of it. Also it seems `pp_xor` had the left and right arguments round the wrong way; but until the asymmetry introduced by this change nobody had noticed before. This is now fixed. Also adds `B::Deparse` support for the new assigning xor operator
1 parent 0f0d601 commit 29cc805

File tree

8 files changed

+48
-12
lines changed

8 files changed

+48
-12
lines changed

lib/B/Deparse.pm

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# This is based on the module of the same name by Malcolm Beattie,
88
# but essentially none of his code remains.
99

10-
package B::Deparse 1.84;
10+
package B::Deparse 1.85;
1111
use strict;
1212
use Carp;
1313
use B qw(class main_root main_start main_cv svref_2object opnumber perlstring
@@ -3318,9 +3318,16 @@ sub pp_and { logop(@_, "and", 3, "&&", 11, "if") }
33183318
sub pp_or { logop(@_, "or", 2, "||", 10, "unless") }
33193319
sub pp_dor { logop(@_, "//", 10) }
33203320

3321-
# xor is syntactically a logop, but it's really a binop (contrary to
3322-
# old versions of opcode.pl). Syntax is what matters here.
3323-
sub pp_xor { logop(@_, "xor", 2, "^^", 10, "") }
3321+
sub pp_xor {
3322+
my $self = shift;
3323+
my ($op, $cx) = @_;
3324+
if ($cx > 2 or $op->flags & OPf_STACKED) {
3325+
binop($self, @_, "^^", 10, ASSIGN);
3326+
}
3327+
else {
3328+
binop($self, @_, "xor", 2);
3329+
}
3330+
}
33243331

33253332
sub logassignop {
33263333
my $self = shift;

lib/B/Deparse.t

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3450,3 +3450,8 @@ $_ = (!$p) isa 'Some::Class';
34503450
$_ = (!$p) =~ tr/1//;
34513451
$_ = (!$p) =~ /1/;
34523452
$_ = (!$p) =~ s/1//r;
3453+
####
3454+
# xor operator
3455+
my($x, $y, $z);
3456+
$z = 1 + ($x ^^ $y);
3457+
$z = ($x ^^= $y);

op.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3230,6 +3230,7 @@ Perl_op_lvalue_flags(pTHX_ OP *o, I32 type, U32 flags)
32303230
case OP_I_MODULO:
32313231
case OP_I_ADD:
32323232
case OP_I_SUBTRACT:
3233+
case OP_XOR:
32333234
if (!(o->op_flags & OPf_STACKED))
32343235
goto nomod;
32353236
PL_modcount++;

pod/perldelta.pod

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ here, but most should go in the L</Performance Enhancements> section.
2727

2828
[ List each enhancement as a =head2 entry ]
2929

30+
=head2 Assigning logical xor C<^^=> operator
31+
32+
Perl 5.40.0 introduced the logical medium-precedence exclusive-or operator
33+
C<^^>. It was not noticed at the time that the assigning variant C<^^=> was
34+
also missing. This is now added.
35+
3036
=head1 Security
3137

3238
XXX Any security-related notices go here. In particular, any security

pod/perlop.pod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,7 +1341,7 @@ That should probably be written more simply as:
13411341
=head2 Assignment Operators
13421342
X<assignment> X<operator, assignment> X<=> X<**=> X<+=> X<*=> X<&=>
13431343
X<<< <<= >>> X<&&=> X<-=> X</=> X<|=> X<<< >>= >>> X<||=> X<//=> X<.=>
1344-
X<%=> X<^=> X<x=> X<&.=> X<|.=> X<^.=>
1344+
X<%=> X<^=> X<x=> X<&.=> X<|.=> X<^.=> X<^^=>
13451345

13461346
C<"="> is the ordinary assignment operator.
13471347

@@ -1360,7 +1360,7 @@ The following are recognized:
13601360
**= += *= &= &.= <<= &&=
13611361
-= /= |= |.= >>= ||=
13621362
.= %= ^= ^.= //=
1363-
x=
1363+
x= ^^=
13641364

13651365
Although these are grouped by family, they all have the precedence
13661366
of assignment. These combined assignment operators can only operate on

pp_ctl.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2172,11 +2172,16 @@ Perl_die_unwind(pTHX_ SV *msv)
21722172

21732173
PP(pp_xor)
21742174
{
2175-
SV *left = PL_stack_sp[0];
2176-
SV *right = PL_stack_sp[-1];
2177-
rpp_replace_2_IMM_NN(SvTRUE_NN(left) != SvTRUE_NN(right)
2178-
? &PL_sv_yes
2179-
: &PL_sv_no);
2175+
SV *left = PL_stack_sp[-1];
2176+
SV *right = PL_stack_sp[0];
2177+
bool ret = SvTRUE_NN(left) != SvTRUE_NN(right);
2178+
if (PL_op->op_flags & OPf_STACKED) {
2179+
sv_setbool(left, ret);
2180+
rpp_replace_2_1(left);
2181+
}
2182+
else {
2183+
rpp_replace_2_IMM_NN(boolSV(ret));
2184+
}
21802185
return NORMAL;
21812186
}
21822187

t/op/lop.t

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ BEGIN {
1010
set_up_inc('../lib');
1111
}
1212

13-
plan tests => 47;
13+
plan tests => 58;
1414

1515
for my $i (undef, 0 .. 2, "", "0 but true") {
1616
my $true = 1;
@@ -105,8 +105,16 @@ for my $test (
105105
my ($a,$b, $exp) = @$test;
106106
is(($a xor $b), $exp, "($a xor $b) == '$exp'");
107107
is(($a ^^ $b), $exp, "($a ^^ $b) == '$exp'");
108+
109+
my ($lhs, $rhs) = @$test;
110+
$lhs ^^= $rhs;
111+
is($lhs, $exp, "$a ^^= $b gives '$exp'");
108112
}
109113

114+
my $var = 123;
115+
($var ^^= 456) ^^= 456;
116+
is($var, 1, '^^= yields mutable lvalue');
117+
110118
# precedence
111119
is((1 xor 1 and 0), 1, '(1 xor 1 and 0) == 1');
112120
is((1 xor 0 or 1), 1, "(1 xor 0 or 1) == 1");

toke.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6097,6 +6097,10 @@ yyl_caret(pTHX_ char *s)
60976097
TOKEN(0);
60986098
}
60996099
pl_yylval.ival = OP_XOR;
6100+
if (*s == '=') {
6101+
s++;
6102+
OPERATOR(ASSIGNOP);
6103+
}
61006104
OPERATOR(OROR);
61016105
}
61026106
if (bof && s[1] == '.')

0 commit comments

Comments
 (0)