Create a new logical xor operator, spelled ^^

Previously, the low-precedence `xor` operator did not have a
higher-precedence logical variant, as compared `or` vs `||` and
`and` vs `&&`. This PR adds such an operator syntax, completing the
set.
This commit is contained in:
Martijn Lievaart 2024-02-14 19:30:29 +01:00 committed by Paul Evans
parent d3f42b8d38
commit d6e802ac91
7 changed files with 34 additions and 9 deletions

4
perly.act generated
View File

@ -1554,7 +1554,7 @@ case 2:
case 199:
#line 1250 "perly.y"
{ (yyval.opval) = newLOGOP(OP_OR, 0, (ps[-2].val.opval), (ps[0].val.opval)); }
{ (yyval.opval) = newLOGOP((ps[-1].val.ival), 0, (ps[-2].val.opval), (ps[0].val.opval)); }
break;
@ -2354,6 +2354,6 @@ case 2:
/* Generated from:
* ae786f28e8bc303471bcc03fc82e93a348d603252cc8c164a96cc0c26af78217 perly.y
* d200edcf6b5ba783b2b4e34928c5787fcab506e14d318042f4e46dee90ba0898 perly.y
* acf1cbfd2545faeaaa58b1cf0cf9d7f98b5be0752eb7a54528ef904a9e2e1ca7 regen_perly.pl
* ex: set ro ft=c: */

2
perly.h generated
View File

@ -236,6 +236,6 @@ int yyparse (void);
/* Generated from:
* ae786f28e8bc303471bcc03fc82e93a348d603252cc8c164a96cc0c26af78217 perly.y
* d200edcf6b5ba783b2b4e34928c5787fcab506e14d318042f4e46dee90ba0898 perly.y
* acf1cbfd2545faeaaa58b1cf0cf9d7f98b5be0752eb7a54528ef904a9e2e1ca7 regen_perly.pl
* ex: set ro ft=c: */

2
perly.tab generated
View File

@ -1336,6 +1336,6 @@ static const toketypes yy_type_tab[] =
};
/* Generated from:
* ae786f28e8bc303471bcc03fc82e93a348d603252cc8c164a96cc0c26af78217 perly.y
* d200edcf6b5ba783b2b4e34928c5787fcab506e14d318042f4e46dee90ba0898 perly.y
* acf1cbfd2545faeaaa58b1cf0cf9d7f98b5be0752eb7a54528ef904a9e2e1ca7 regen_perly.pl
* ex: set ro ft=c: */

View File

@ -1247,7 +1247,7 @@ termbinop: term[lhs] PLUGIN_HIGH_OP[op] term[rhs]
| term[lhs] PLUGIN_LOGICAL_AND_OP[op] term[rhs]
{ $$ = build_infix_plugin($lhs, $rhs, $op); }
| term[lhs] OROR term[rhs] /* $x || $y */
{ $$ = newLOGOP(OP_OR, 0, $lhs, $rhs); }
{ $$ = newLOGOP($OROR, 0, $lhs, $rhs); }
| term[lhs] PLUGIN_LOGICAL_OR_OP[op] term[rhs]
{ $$ = build_infix_plugin($lhs, $rhs, $op); }
| term[lhs] DORDOR term[rhs] /* $x // $y */

View File

@ -140,7 +140,7 @@ values only, not array values.
left & &.
left | |. ^ ^.
left &&
left || //
left || ^^ //
nonassoc .. ...
right ?:
right = += -= *= etc. goto last next redo dump
@ -1019,6 +1019,13 @@ if the left operand is true, the right operand is not even evaluated.
Scalar or list context propagates down to the right operand if it
is evaluated.
=head2 C-style Logical Xor
X<^^> X<operator, logical, xor>
Binary C<"^^"> performs a logical XOR operation. Both operands are
evaluated and the result is true only if exactly one of the operands is true.
Scalar or list context propagates down to the right operand.
=head2 Logical Defined-Or
X<//> X<operator, logical, defined-or>

View File

@ -1,7 +1,7 @@
#!./perl
#
# test the logical operators '&&', '||', '!', 'and', 'or', , 'xor', 'not'
# test the logical operators '&&', '||', '^^', '!', 'and', 'or', , 'xor', 'not'
#
BEGIN {
@ -10,7 +10,7 @@ BEGIN {
set_up_inc('../lib');
}
plan tests => 33;
plan tests => 47;
for my $i (undef, 0 .. 2, "", "0 but true") {
my $true = 1;
@ -104,4 +104,11 @@ for my $test (
) {
my ($a,$b, $exp) = @$test;
is(($a xor $b), $exp, "($a xor $b) == '$exp'");
is(($a ^^ $b), $exp, "($a ^^ $b) == '$exp'");
}
# precedence
is((1 xor 1 and 0), 1, '(1 xor 1 and 0) == 1');
is((1 xor 0 or 1), 1, "(1 xor 0 or 1) == 1");
is((1 ^^ 1 && 0), 1, '(1 ^^ 1 && 0) == 1');
is((1 ^^ 0 || 1), 1, "(1 ^^ 0 || 1) == 1");

13
toke.c
View File

@ -482,7 +482,7 @@ static struct debug_tokens {
DEBUG_TOKEN (NONE, NOAMP),
DEBUG_TOKEN (NONE, NOTOP),
DEBUG_TOKEN (IVAL, OROP),
DEBUG_TOKEN (NONE, OROR),
DEBUG_TOKEN (IVAL, OROR),
DEBUG_TOKEN (IVAL, PERLY_AMPERSAND),
DEBUG_TOKEN (IVAL, PERLY_BRACE_CLOSE),
DEBUG_TOKEN (IVAL, PERLY_BRACE_OPEN),
@ -6099,6 +6099,16 @@ yyl_caret(pTHX_ char *s)
{
char *d = s;
const bool bof = cBOOL(FEATURE_BITWISE_IS_ENABLED);
if (s[1] == '^') {
s += 2;
if (!PL_lex_allbrackets && PL_lex_fakeeof >=
(*s == '=' ? LEX_FAKEEOF_ASSIGN : LEX_FAKEEOF_LOGIC)) {
s -= 2;
TOKEN(0);
}
pl_yylval.ival = OP_XOR;
OPERATOR(OROR);
}
if (bof && s[1] == '.')
s++;
if (!PL_lex_allbrackets && PL_lex_fakeeof >=
@ -6618,6 +6628,7 @@ yyl_verticalbar(pTHX_ char *s)
s -= 2;
TOKEN(0);
}
pl_yylval.ival = OP_OR;
AOPERATOR(OROR);
}