Improve alternative operator names support

Handle alternative operator names in C++ preprocessor expressions.
Handle full set of alternative operator names in C++ expressions
(previously only "and", "or" and "not" were understood).

Fixes #2914
This commit is contained in:
Olly Betts 2024-05-30 11:38:32 +12:00
parent 99df7a085d
commit 0ce05c33e9
7 changed files with 83 additions and 24 deletions

View File

@ -7,6 +7,12 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.3.0 (in progress)
===========================
2024-05-30: olly
#2914 Handle alternative operator names in C++ preprocessor
expressions. Handle full set of alternative operator names in
C++ expressions (previously only "and", "or" and "not" were
understood).
2024-05-15: olly
#2868 Support C++17 fold expressions.

View File

@ -74,6 +74,9 @@
// so this would end up wrapped as int.
decltype(!0) should_be_bool;
// Test alternative operator names work in this context.
decltype(((compl 42) and (not 1)) or (2 xor 4)) should_be_bool2;
decltype(E1) should_be_enum;
auto get_number_sum(decltype(i+j) a) -> decltype(i+j) {

View File

@ -9,5 +9,9 @@ struct A
// Regression test for preprocessor bug with handling a slash immediately
// followed by a single quote, fixed in 4.2.0. (#2630)
int f(int i = 64/' ') { return i; }
// Regression test for alternative operator names - this failed to parse in
// SWIG 4.2.0 and earlier.
int g(bool b = (compl 1 or not 2) xor (3 and 4) xor (3 bitand 6) xor (3 bitor 5) xor (2 + 2 not_eq 5)) { return (int)b; }
};
%}

View File

@ -52,6 +52,7 @@ check::equal(gettype($b->should_be_int9), "integer");
check::equal(gettype($b->should_be_int10), "integer");
check::equal(gettype($b->should_be_bool), "boolean");
check::equal(gettype($b->should_be_bool2), "boolean");
check::equal(gettype($b::should_be_char), "string");
check::equal($b::should_be_char, "\0");

View File

@ -1,7 +1,7 @@
%module preproc_cpp
// booleans start
// Test boolean literals (https://github.com/swig/swig/pull/2394):
#if false
# error "boolean preproc check fail false"
#else
@ -31,7 +31,43 @@
#else
# error "boolean preproc check fail (0 || true)"
#endif
// booleans end
// Test alternative operator names (https://github.com/swig/swig/issues/2914):
#if true or 0
#else
# error "boolean preproc check fail true or 0"
#endif
#if true and 1
#else
# error "boolean preproc check fail true and 1"
#endif
#if true xor false
#else
# error "boolean preproc check fail true xor false"
#endif
#if 1 bitor 2
#else
# error "boolean preproc check fail 1 bitor 2"
#endif
#if not(1 bitand 2)
#else
# error "boolean preproc check fail not(1 bitand 2)"
#endif
#if compl 0
#else
# error "boolean preproc check fail compl 0"
#endif
#if (1 bitor 2) not_eq 1
#else
# error "boolean preproc check fail (1 bitor 2) not_eq 1"
#endif
// Regression tests for bugs handling a comma in a comment in a macro:

View File

@ -719,12 +719,6 @@ num_common:
/* C++ keywords */
if (cparse_cplusplus) {
if (strcmp(yytext, "and") == 0)
return (LAND);
if (strcmp(yytext, "or") == 0)
return (LOR);
if (strcmp(yytext, "not") == 0)
return (LNOT);
if (strcmp(yytext, "class") == 0)
return (CLASS);
if (strcmp(yytext, "private") == 0)
@ -802,9 +796,12 @@ num_common:
yylval.str = s;
return OPERATOR;
} else if (nexttok == SWIG_TOKEN_ID) {
/* We have an identifier. This could be any number of things. It could be a named version of
an operator (e.g., 'and_eq') or it could be a conversion operator. To deal with this, we're
going to read tokens until we encounter a ( or ;. Some care is needed for formatting. */
/* We have an identifier. It could be "new" or "delete",
* potentially followed by "[]", or it could be a conversion
* operator (it can't be "and_eq" or similar as those are returned
* as SWIG_TOKEN_ANDEQUAL, etc by Scanner_token()). To deal with
* this we read tokens until we encounter a suitable terminating
* token. Some care is needed for formatting. */
int needspace = 1;
int termtoken = 0;
const char *termvalue = 0;
@ -856,17 +853,6 @@ num_common:
|| (strcmp(t, "delete") == 0)
|| (strcmp(t, "new[]") == 0)
|| (strcmp(t, "delete[]") == 0)
|| (strcmp(t, "and") == 0)
|| (strcmp(t, "and_eq") == 0)
|| (strcmp(t, "bitand") == 0)
|| (strcmp(t, "bitor") == 0)
|| (strcmp(t, "compl") == 0)
|| (strcmp(t, "not") == 0)
|| (strcmp(t, "not_eq") == 0)
|| (strcmp(t, "or") == 0)
|| (strcmp(t, "or_eq") == 0)
|| (strcmp(t, "xor") == 0)
|| (strcmp(t, "xor_eq") == 0)
)) {
/* retract(strlen(t)); */

View File

@ -1025,12 +1025,35 @@ static int look(Scanner *s) {
}
break;
case 76: /* Identifier or true/false */
case 76: /* Identifier, true/false or alternative token */
if (cparse_cplusplus) {
if (Strcmp(s->text, "true") == 0)
return SWIG_TOKEN_BOOL;
else if (Strcmp(s->text, "false") == 0)
if (Strcmp(s->text, "false") == 0)
return SWIG_TOKEN_BOOL;
if (Strcmp(s->text, "and") == 0)
return SWIG_TOKEN_LAND;
if (Strcmp(s->text, "and_eq") == 0)
return SWIG_TOKEN_ANDEQUAL;
if (Strcmp(s->text, "bitand") == 0)
return SWIG_TOKEN_AND;
if (Strcmp(s->text, "bitor") == 0)
return SWIG_TOKEN_OR;
if (Strcmp(s->text, "compl") == 0)
return SWIG_TOKEN_NOT;
if (Strcmp(s->text, "not") == 0)
return SWIG_TOKEN_LNOT;
if (Strcmp(s->text, "not_eq") == 0)
return SWIG_TOKEN_NOTEQUAL;
if (Strcmp(s->text, "or") == 0)
return SWIG_TOKEN_LOR;
if (Strcmp(s->text, "or_eq") == 0)
return SWIG_TOKEN_OREQUAL;
if (Strcmp(s->text, "xor") == 0)
return SWIG_TOKEN_XOR;
if (Strcmp(s->text, "xor_eq") == 0)
return SWIG_TOKEN_XOREQUAL;
}
return SWIG_TOKEN_ID;