From: Alan T. DeKok Date: Thu, 1 Dec 2022 19:31:55 +0000 (-0500) Subject: add === and !== X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ba48384a53b8ec5ea87c43cd0da47c7132c55af4;p=thirdparty%2Ffreeradius-server.git add === and !== After other languages which have the same thing. This is less useful for FreeRADIUS, as all "variables" are strongly typed. But it could be used for non-quoted xlats, and it could be used in the future for "void" types --- diff --git a/doc/antora/modules/reference/pages/unlang/condition/cmp.adoc b/doc/antora/modules/reference/pages/unlang/condition/cmp.adoc index bbefd0d4cd6..9762aeef406 100644 --- a/doc/antora/modules/reference/pages/unlang/condition/cmp.adoc +++ b/doc/antora/modules/reference/pages/unlang/condition/cmp.adoc @@ -21,8 +21,10 @@ The comparison operators are given below. | Operator | Description | < | less than | \<= | less than or equals -| == | equals -| != | not equals +| == | equals, with automatic type casting +| != | not equals, with automatic type casting +| === | equals, but both operands have to be of the same type +| !== | not equals, or they are not of the same type | >= | greater than or equals | > | greater than | xref:condition/regex.adoc[=~] | regular expression matches diff --git a/src/lib/unlang/xlat_expr.c b/src/lib/unlang/xlat_expr.c index 94010f0e0fe..f5cb1609338 100644 --- a/src/lib/unlang/xlat_expr.c +++ b/src/lib/unlang/xlat_expr.c @@ -495,6 +495,8 @@ XLAT_CMP_FUNC(cmp_lt, T_OP_LT) XLAT_CMP_FUNC(cmp_le, T_OP_LE) XLAT_CMP_FUNC(cmp_gt, T_OP_GT) XLAT_CMP_FUNC(cmp_ge, T_OP_GE) +XLAT_CMP_FUNC(cmp_eq_type, T_OP_CMP_EQ_TYPE) +XLAT_CMP_FUNC(cmp_ne_type, T_OP_CMP_NE_TYPE) typedef struct { fr_token_t op; @@ -1696,6 +1698,8 @@ int xlat_register_expressions(void) XLAT_REGISTER_BINARY_CMP(T_OP_LE, le); XLAT_REGISTER_BINARY_CMP(T_OP_GT, gt); XLAT_REGISTER_BINARY_CMP(T_OP_GE, ge); + XLAT_REGISTER_BINARY_CMP(T_OP_CMP_EQ_TYPE, eq_type); + XLAT_REGISTER_BINARY_CMP(T_OP_CMP_NE_TYPE, ne_type); XLAT_REGISTER_REGEX_OP(T_OP_REG_EQ, reg_eq); XLAT_REGISTER_REGEX_OP(T_OP_REG_NE, reg_ne); @@ -1758,6 +1762,9 @@ static const fr_sbuff_term_elem_t binary_ops[T_TOKEN_LAST] = { [ T_OP_GT ] = L("cmp_gt"), [ T_OP_GE ] = L("cmp_ge"), + [ T_OP_CMP_EQ_TYPE ] = L("cmp_eq_type"), + [ T_OP_CMP_NE_TYPE ] = L("cmp_ne_type"), + [ T_OP_REG_EQ ] = L("reg_eq"), [ T_OP_REG_NE ] = L("reg_ne"), }; @@ -1811,6 +1818,9 @@ static const int precedence[T_TOKEN_LAST] = { [T_OP_CMP_EQ] = P(4,1), [T_OP_NE] = P(4,1), + [T_OP_CMP_EQ_TYPE] = P(4,1), + [T_OP_CMP_NE_TYPE] = P(4,1), + [T_OP_LT] = P(5,0), [T_OP_LE] = P(5,0), [T_OP_GT] = P(5,0), @@ -2399,6 +2409,7 @@ done: */ static fr_table_num_ordered_t const expr_assignment_op_table[] = { { L("!="), T_OP_NE }, + { L("!=="), T_OP_CMP_NE_TYPE }, { L("&"), T_AND }, { L("&&"), T_LAND }, @@ -2418,6 +2429,7 @@ static fr_table_num_ordered_t const expr_assignment_op_table[] = { { L("="), T_OP_EQ }, { L("=="), T_OP_CMP_EQ }, + { L("==="), T_OP_CMP_EQ_TYPE }, { L("=~"), T_OP_REG_EQ }, { L("!~"), T_OP_REG_NE }, diff --git a/src/lib/util/calc.c b/src/lib/util/calc.c index f9ea4322086..63badf72533 100644 --- a/src/lib/util/calc.c +++ b/src/lib/util/calc.c @@ -1777,6 +1777,32 @@ int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint if (!fr_type_is_leaf(a->type)) return invalid_type(a->type); if (!fr_type_is_leaf(b->type)) return invalid_type(b->type); + /* + * === and !== also check types. If the types are + * different, it's a failure. Otherwise they revert to == and !=. + */ + switch (op) { + case T_OP_CMP_EQ_TYPE: + if (a->type != b->type) { + mismatch_type: + fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); /* @todo - enum */ + dst->vb_bool = false; + return 0; + } + op = T_OP_CMP_EQ; + break; + + case T_OP_CMP_NE_TYPE: + if (a->type != b->type) goto mismatch_type; + + op = T_OP_NE; + break; + + default: + break; + } + + fr_value_box_init_null(&one); fr_value_box_init_null(&two); diff --git a/src/lib/util/token.c b/src/lib/util/token.c index d194becf5e3..c447c303a40 100644 --- a/src/lib/util/token.c +++ b/src/lib/util/token.c @@ -45,11 +45,13 @@ fr_table_num_ordered_t const fr_tokens_table[] = { { L("=*"), T_OP_CMP_TRUE }, { L("!*"), T_OP_CMP_FALSE }, { L("=="), T_OP_CMP_EQ }, + { L("==="), T_OP_CMP_EQ_TYPE }, { L("^="), T_OP_PREPEND }, { L("|="), T_OP_OR_EQ }, { L("&="), T_OP_AND_EQ }, { L("="), T_OP_EQ }, { L("!="), T_OP_NE }, + { L("!=="), T_OP_CMP_NE_TYPE }, { L(">="), T_OP_GE }, { L(">"), T_OP_GT }, { L("<="), T_OP_LE }, @@ -124,6 +126,9 @@ char const *fr_tokens[T_TOKEN_LAST] = { [T_OP_CMP_EQ] = "==", + [T_OP_CMP_EQ_TYPE] = "===", + [T_OP_CMP_NE_TYPE] = "!==", + [T_OP_PREPEND] = "^=", [T_HASH] = "#", @@ -199,6 +204,8 @@ const bool fr_equality_op[T_TOKEN_LAST] = { T(CMP_TRUE), T(CMP_FALSE), T(CMP_EQ), + T(CMP_EQ_TYPE), + T(CMP_NE_TYPE), }; #undef T diff --git a/src/lib/util/token.h b/src/lib/util/token.h index 79c01df894f..3507613f1ba 100644 --- a/src/lib/util/token.h +++ b/src/lib/util/token.h @@ -104,6 +104,8 @@ typedef enum fr_token { T_OP_CMP_TRUE, /* =* */ T_OP_CMP_FALSE, /* !* */ T_OP_CMP_EQ, /* == */ + T_OP_CMP_EQ_TYPE, /* === */ + T_OP_CMP_NE_TYPE, /* !== */ /* * Only used by LDAP ??? diff --git a/src/tests/unit/xlat/cond_base.txt b/src/tests/unit/xlat/cond_base.txt index 83c3a9b8b5d..78d4397885a 100644 --- a/src/tests/unit/xlat/cond_base.txt +++ b/src/tests/unit/xlat/cond_base.txt @@ -762,6 +762,38 @@ match ERROR offset 1: Unexpected text - attribute names must prefixed with '&' xlat_purify handled match %{rcode:'handled'} +# +# Automatic casting +# +xlat_purify (192.168.0.1 == "192.168.0.1") +match true + +xlat_purify (192.168.0.1 != "192.168.0.1") +match false + +xlat_purify (192.168.0.1 != "192.168.0.2") +match true + +# +# Types are different, so they don't match. +# +xlat_purify (192.168.0.1 === "192.168.0.1") +match false + +xlat_purify (192.168.0.1 !== "192.168.0.1") +match false + +xlat_purify (192.168.0.1 !== "192.168.0.2") +match false + +xlat_purify (192.168.0.1 === 192.168.0.1) +match true + +xlat_purify (192.168.0.1 !== 192.168.0.1) +match false + +xlat_purify (192.168.0.1 !== 192.168.0.2) +match true count -match 316 +match 334