commit c97d629: [Project] Support multiply, minus and divide operators in expressions
Vsevolod Stakhov
vsevolod at highsecure.ru
Wed Jun 17 13:35:06 UTC 2020
Author: Vsevolod Stakhov
Date: 2020-06-16 15:35:48 +0100
URL: https://github.com/rspamd/rspamd/commit/c97d6296c3d07df135c65e598543b51c94dfbc5b
[Project] Support multiply, minus and divide operators in expressions
---
src/libutil/expression.c | 81 ++++++++++++++++++++++++++++++++++++++++++++----
src/libutil/expression.h | 6 ++--
2 files changed, 79 insertions(+), 8 deletions(-)
diff --git a/src/libutil/expression.c b/src/libutil/expression.c
index 6099a308f..9b166ee25 100644
--- a/src/libutil/expression.c
+++ b/src/libutil/expression.c
@@ -89,6 +89,12 @@ rspamd_expr_op_to_str (enum rspamd_expression_op op)
case OP_PLUS:
op_str = "+";
break;
+ case OP_MINUS:
+ op_str = "-";
+ break;
+ case OP_DIVIDE:
+ op_str = "/";
+ break;
case OP_NOT:
op_str = "!";
break;
@@ -180,9 +186,14 @@ rspamd_expr_logic_priority (enum rspamd_expression_op op)
switch (op) {
case OP_NOT:
+ ret = 7;
+ break;
+ case OP_MULT:
+ case OP_DIVIDE:
ret = 6;
break;
case OP_PLUS:
+ case OP_MINUS:
ret = 5;
break;
case OP_GE:
@@ -191,7 +202,6 @@ rspamd_expr_logic_priority (enum rspamd_expression_op op)
case OP_LT:
ret = 4;
break;
- case OP_MULT:
case OP_AND:
ret = 3;
break;
@@ -227,6 +237,8 @@ rspamd_expr_is_operation_symbol (gchar a)
case '<':
case '+':
case '*':
+ case '-':
+ case '/':
return TRUE;
}
@@ -278,6 +290,12 @@ rspamd_expr_str_to_op (const gchar *a, const gchar *end, const gchar **next)
case '+':
op = OP_PLUS;
break;
+ case '/':
+ op = OP_DIVIDE;
+ break;
+ case '-':
+ op = OP_MINUS;
+ break;
case ')':
op = OP_CBRACE;
break;
@@ -624,10 +642,50 @@ rspamd_parse_expression (const gchar *line, gsize len,
continue;
}
else if (rspamd_expr_is_operation_symbol (*p)) {
+ /* Lookahead */
if (p + 1 < end) {
gchar t = *(p + 1);
- if (t != ':') {
+ if (t == ':') {
+ /* Special case, treat it as an atom */
+ }
+ else if (*p == '/') {
+ /* Lookahead for division operation to distinguish from regexp */
+ const gchar *track = p + 1;
+
+ /* Skip spaces */
+ while (track < end && g_ascii_isspace (*track)) {
+ track++;
+ }
+
+ /* Check for a number */
+ if (rspamd_regexp_search (num_re,
+ track,
+ end - track,
+ NULL,
+ NULL,
+ FALSE,
+ NULL)) {
+ state = PARSE_OP;
+ continue;
+ }
+
+ /* Fallback to PARSE_ATOM state */
+ }
+ else if (*p == '-') {
+ /* - is used in composites, so we need to distinguish - from
+ * 1) unary minus of a limit!
+ * 2) -BLAH in composites
+ * Decision is simple: require a space after binary `-` op
+ */
+ if (g_ascii_isspace (t)) {
+ state = PARSE_OP;
+ continue;
+ }
+ /* Fallback to PARSE_ATOM state */
+ }
+ else {
+ /* Generic operation */
state = PARSE_OP;
continue;
}
@@ -644,6 +702,7 @@ rspamd_parse_expression (const gchar *line, gsize len,
* 2) if we have full numeric string, then we check for
* the following expression:
* ^\d+\s*[><]$
+ * and check the operation on stack
*/
if ((gulong)(end - p) > sizeof ("and ") &&
(g_ascii_strncasecmp (p, "and ", sizeof ("and ") - 1) == 0 ||
@@ -656,12 +715,13 @@ rspamd_parse_expression (const gchar *line, gsize len,
}
else {
/*
- * If we have any comparison operator in the stack, then try
+ * If we have any comparison or arithmetic operator in the stack, then try
* to parse limit
*/
op = GPOINTER_TO_INT (rspamd_expr_stack_peek (e));
- if (op >= OP_LT && op <= OP_GE) {
+ if (op == OP_MULT || op == OP_MINUS || op == OP_DIVIDE ||
+ op == OP_PLUS || (op >= OP_LT && op <= OP_GE)) {
if (rspamd_regexp_search (num_re,
p,
end - p,
@@ -673,6 +733,7 @@ rspamd_parse_expression (const gchar *line, gsize len,
state = PARSE_LIM;
continue;
}
+ /* Fallback to atom parsing */
}
/* Try to parse atom */
@@ -973,7 +1034,16 @@ rspamd_ast_do_op (struct rspamd_expression_elt *elt, gdouble val,
ret = fabs (val) > DOUBLE_EPSILON ? 0.0 : 1.0;
break;
case OP_PLUS:
- ret = acc + val;
+ ret = first_elt ? (val) : (acc + val);
+ break;
+ case OP_MULT:
+ ret = first_elt ? (val) : (acc * val);
+ break;
+ case OP_MINUS:
+ ret = first_elt ? (val) : (acc - val);
+ break;
+ case OP_DIVIDE:
+ ret = first_elt ? (val) : (acc / val);
break;
case OP_GE:
ret = first_elt ? (val >= lim) : (acc >= lim);
@@ -987,7 +1057,6 @@ rspamd_ast_do_op (struct rspamd_expression_elt *elt, gdouble val,
case OP_LT:
ret = first_elt ? (val < lim) : (acc < lim);
break;
- case OP_MULT:
case OP_AND:
ret = first_elt ? (val) : (acc * val);
break;
diff --git a/src/libutil/expression.h b/src/libutil/expression.h
index bd18fa75f..3a4f1ac3f 100644
--- a/src/libutil/expression.h
+++ b/src/libutil/expression.h
@@ -30,8 +30,10 @@ extern "C" {
enum rspamd_expression_op {
OP_INVALID = 0,
- OP_PLUS, /* || or + */
- OP_MULT, /* && or * */
+ OP_PLUS, /* + */
+ OP_MULT, /* * */
+ OP_MINUS, /* - */
+ OP_DIVIDE, /* / */
OP_OR, /* || or | */
OP_AND, /* && or & */
OP_NOT, /* ! */
More information about the Commits
mailing list