Przeglądaj źródła

script engine: more operators supported

- support for more operators
- more helper functions
- small fixes
Andrei Pelinescu-Onciul 16 lat temu
rodzic
commit
68e5b7873e
2 zmienionych plików z 504 dodań i 42 usunięć
  1. 479 38
      rvalue.c
  2. 25 4
      rvalue.h

+ 479 - 38
rvalue.c

@@ -34,7 +34,7 @@
 #define rv_ref(rv) ((rv)->refcnt++)
 
 /** unref rv and returns true if 0 */
-#define rv_unref(rv) (((rv)->refcnt--)==0)
+#define rv_unref(rv) ((--(rv)->refcnt)==0)
 
 
 inline static void rval_force_clean(struct rvalue* rv)
@@ -316,6 +316,183 @@ error:
 
 
 
+/** guess the type of an expression.
+  * @return RV_INT, RV_STR or RV_NONE (when type could not be found,
+  * e.g. avp or pvar)
+  */
+enum rval_type rve_guess_type( struct rval_expr* rve)
+{
+	switch(rve->op){
+		case RVE_RVAL_OP:
+			switch(rve->left.rval.type){
+				case RV_STR:
+				case RV_SEL:
+					return RV_STR;
+				case RV_INT:
+				case RV_BEXPR:
+				case RV_ACTION_ST:
+					return RV_INT;
+				case RV_PVAR:
+				case RV_AVP:
+				case RV_NONE:
+					return RV_NONE;
+			}
+			break;
+		case RVE_UMINUS_OP:
+		case RVE_BOOL_OP:
+		case RVE_LNOT_OP:
+		case RVE_MINUS_OP:
+		case RVE_MUL_OP:
+		case RVE_DIV_OP:
+		case RVE_BOR_OP:
+		case RVE_BAND_OP:
+		case RVE_LAND_OP:
+		case RVE_LOR_OP:
+		case RVE_GT_OP:
+		case RVE_GTE_OP:
+		case RVE_LT_OP:
+		case RVE_LTE_OP:
+		case RVE_EQ_OP:
+		case RVE_DIFF_OP:
+			return RV_INT;
+		case RVE_PLUS_OP:
+			/* '+' evaluates to the type of the left operand */
+			return rve_guess_type(rve->left.rve);
+		case RVE_NONE_OP:
+			break;
+	}
+	return RV_NONE;
+}
+
+
+
+/** returns true if expression is constant.
+  * @return 0 or 1 on
+  *  non constant type
+  */
+int rve_is_constant(struct rval_expr* rve)
+{
+	switch(rve->op){
+		case RVE_RVAL_OP:
+			switch(rve->left.rval.type){
+				case RV_STR:
+					return 1;
+				case RV_INT:
+					return 1;
+				case RV_SEL:
+				case RV_BEXPR:
+				case RV_ACTION_ST:
+				case RV_PVAR:
+				case RV_AVP:
+				case RV_NONE:
+					return 0;
+			}
+			break;
+		case RVE_UMINUS_OP:
+		case RVE_BOOL_OP:
+		case RVE_LNOT_OP:
+			return rve_is_constant(rve->left.rve);
+		case RVE_MINUS_OP:
+		case RVE_MUL_OP:
+		case RVE_DIV_OP:
+		case RVE_BOR_OP:
+		case RVE_BAND_OP:
+		case RVE_LAND_OP:
+		case RVE_LOR_OP:
+		case RVE_GT_OP:
+		case RVE_GTE_OP:
+		case RVE_LT_OP:
+		case RVE_LTE_OP:
+		case RVE_EQ_OP:
+		case RVE_DIFF_OP:
+		case RVE_PLUS_OP:
+			return rve_is_constant(rve->left.rve) &&
+					rve_is_constant(rve->right.rve);
+		case RVE_NONE_OP:
+			break;
+	}
+	return 0;
+}
+
+
+
+/** returns 1 if expression is valid (type-wise).
+  * @return 0 or 1  and sets *type to the resulting type
+  * (RV_INT, RV_STR or RV_NONE if it can be found only at runtime)
+  */
+int rve_check_type(enum rval_type* type, struct rval_expr* rve)
+{
+	enum rval_type type1, type2;
+	
+	switch(rve->op){
+		case RVE_RVAL_OP:
+			*type=rve_guess_type(rve);
+			return 1;
+		case RVE_UMINUS_OP:
+		case RVE_BOOL_OP:
+		case RVE_LNOT_OP:
+			*type=RV_INT;
+			if (rve_check_type(&type1, rve->left.rve)){
+				if (type1==RV_STR)
+					return 0;
+				return 1;
+			}
+			return 0;
+			break;
+		case RVE_MINUS_OP:
+		case RVE_MUL_OP:
+		case RVE_DIV_OP:
+		case RVE_BOR_OP:
+		case RVE_BAND_OP:
+		case RVE_LAND_OP:
+		case RVE_LOR_OP:
+		case RVE_GT_OP:
+		case RVE_GTE_OP:
+		case RVE_LT_OP:
+		case RVE_LTE_OP:
+			*type=RV_INT;
+			if (rve_check_type(&type1, rve->left.rve)){
+				if (type1==RV_STR)
+					return 0;
+				if (rve_check_type(&type2, rve->right.rve)){
+					if (type2==RV_STR)
+						return 0;
+					return 1;
+				}
+			}
+			return 0;
+		case RVE_EQ_OP:
+		case RVE_DIFF_OP:
+			*type=RV_INT;
+			if (rve_check_type(&type1, rve->left.rve)){
+				if (rve_check_type(&type2, rve->right.rve)){
+					if ((type2!=type1) && (type1!=RV_NONE) &&
+							(type2!=RV_NONE) && 
+							!(type1==RV_STR && type2==RV_INT))
+						return 0;
+					return 1;
+				}
+			}
+			return 0;
+		case RVE_PLUS_OP:
+			if (rve_check_type(&type1, rve->left.rve)){
+				if (rve_check_type(&type2, rve->right.rve)){
+					if ((type2!=type1) && (type1!=RV_NONE) &&
+							(type2!=RV_NONE) && 
+							!(type1==RV_STR && type2==RV_INT))
+						return 0;
+					*type=type1;
+					return 1;
+				}
+			}
+		case RVE_NONE_OP:
+			break;
+	}
+	return 0;
+}
+
+
+
 /** get the integer value of an rvalue.
   * *i=(int)rv
   * @return 0 on success, \<0 on error and EXPR_DROP on drop
@@ -403,7 +580,7 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
 	return 0;
 rv_str:
 	/* rv is of string type => error */
-	ERR("string in int expression\n");
+	/* ERR("string in int expression\n"); */
 error:
 	return -1;
 }
@@ -672,6 +849,36 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
 			}
 			*res=v1/v2;
 			break;
+		case RVE_BOR_OP:
+			*res=v1|v2;
+			break;
+		case RVE_BAND_OP:
+			*res=v1&v2;
+			break;
+		case RVE_LAND_OP:
+			*res=v1 && v2;
+			break;
+		case RVE_LOR_OP:
+			*res=v1 || v2;
+			break;
+		case RVE_GT_OP:
+			*res=v1 > v2;
+			break;
+		case RVE_GTE_OP:
+			*res=v1 >= v2;
+			break;
+		case RVE_LT_OP:
+			*res=v1 < v2;
+			break;
+		case RVE_LTE_OP:
+			*res=v1 <= v2;
+			break;
+		case RVE_EQ_OP:
+			*res=v1 == v2;
+			break;
+		case RVE_DIFF_OP:
+			*res=v1 != v2;
+			break;
 		default:
 			BUG("rv unsupported intop %d\n", op);
 			return -1;
@@ -681,6 +888,20 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
 
 
 
+inline static int bool_strop2( enum rval_expr_op op, int* res,
+								str* s1, str* s2)
+{
+	if (s1->len!=s2->len)
+		*res= op==RVE_DIFF_OP;
+	else if (memcmp(s1->s, s2->s, s1->len)==0)
+		*res= op==RVE_EQ_OP;
+	else
+		*res= op==RVE_DIFF_OP;
+	return 0;
+}
+
+
+
 /** integer operation: ret= op v (returns a rvalue).
  * @return rvalue on success, 0 on error
  */
@@ -899,6 +1120,52 @@ error:
 
 
 
+/** bool operation on rval evaluated as strings.
+ * Can use cached rvalues (c1 & c2).
+ * @return 0 success, -1 on error
+ */
+inline static int rval_str_lop2(struct run_act_ctx* h,
+						 struct sip_msg* msg,
+						 int* res,
+						 enum rval_expr_op op,
+						 struct rvalue* l,
+						 struct rval_cache* c1,
+						 struct rvalue* r,
+						 struct rval_cache* c2)
+{
+	struct rvalue* rv1;
+	struct rvalue* rv2;
+	int ret;
+	
+	rv2=rv1=0;
+	ret=0;
+	if ((rv1=rval_convert(h, msg, RV_STR, l, c1))==0)
+		goto error;
+	if ((rv2=rval_convert(h, msg, RV_STR, r, c2))==0)
+		goto error;
+	ret=bool_strop2(op, res, &rv1->v.s, &rv2->v.s);
+	rval_destroy(rv1); 
+	rval_destroy(rv2); 
+	return ret;
+error:
+	rval_destroy(rv1); 
+	rval_destroy(rv2); 
+	return 0;
+}
+
+
+
+/* forward decl. */
+inline static int rval_expr_eval_rvint(struct run_act_ctx* h,
+									   struct sip_msg* msg,
+									   struct rvalue** res_rv,
+									   int* res_i,
+									   struct rval_expr* rve,
+									   struct rval_cache* cache
+									   );
+
+
+
 /** evals an integer expr  to an int.
  * 
  *  *res=(int)eval(rve)
@@ -908,7 +1175,11 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
 						int* res, struct rval_expr* rve)
 {
 	int i1, i2, ret;
+	struct rval_cache c1;
+	struct rvalue* rv1;
+	struct rvalue* rv2;
 	
+	ret=-1;
 	switch(rve->op){
 		case RVE_RVAL_OP:
 			ret=rval_get_int(h, msg, res,  &rve->left.rval, 0);
@@ -925,6 +1196,14 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
 		case RVE_DIV_OP:
 		case RVE_MINUS_OP:
 		case RVE_PLUS_OP:
+		case RVE_BOR_OP:
+		case RVE_BAND_OP:
+		case RVE_LAND_OP:
+		case RVE_LOR_OP:
+		case RVE_GT_OP:
+		case RVE_GTE_OP:
+		case RVE_LT_OP:
+		case RVE_LTE_OP:
 			if (unlikely(
 					(ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
 				break;
@@ -933,8 +1212,56 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
 				break;
 			ret=int_intop2(res, rve->op, i1, i2);
 			break;
+		case RVE_EQ_OP:
+		case RVE_DIFF_OP:
+			/* if left is string, eval left & right as string and
+			   use string diff, else eval as int */
+			rval_cache_init(&c1);
+			if (unlikely( (ret=rval_expr_eval_rvint(h, msg, &rv1, &i1,
+													rve->left.rve, &c1))<0)){
+				rval_cache_clean(&c1);
+				break;
+			}
+			if (likely(rv1==0)){
+				/* int */
+				rval_cache_clean(&c1);
+				if (unlikely( (ret=rval_expr_eval_int(h, msg, &i2,
+														rve->right.rve)) <0) )
+					break;
+				ret=int_intop2(res, rve->op, i1, i2);
+			}else{
+				if (unlikely((rv2=rval_expr_eval(h, msg,
+													rve->right.rve))==0)){
+					rval_destroy(rv1);
+					rval_cache_clean(&c1);
+					ret=-1;
+					break;
+				}
+				ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1, rv2, 0);
+				rval_cache_clean(&c1);
+				rval_destroy(rv1);
+				rval_destroy(rv2);
+			}
+			break;
+#if 0
+		case RVE_MATCH_OP:
+				if (unlikely((rv1=rval_expr_eval(h, msg, rve->left.rve))==0)){
+					ret=-1;
+					break;
+				}
+				if (unlikely((rv2=rval_expr_eval(h, msg,
+													rve->right.rve))==0)){
+					rval_destroy(rv1);
+					ret=-1;
+					break;
+				}
+				ret=rval_str_lop2(res, rve->op, rv1, 0, rv2, 0);
+				rval_destroy(rv1);
+				rval_destroy(rv2);
+			break;
+#endif
 		case RVE_NONE_OP:
-		default:
+		/*default:*/
 			BUG("invalid rval int expression operation %d\n", rve->op);
 			ret=-1;
 	};
@@ -943,6 +1270,115 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
 
 
 
+/** evals a rval expr. into an int or another rv(str).
+ * WARNING: rv result (rv_res) must be rval_destroy()'ed if non-null
+ * (it might be a reference to another rval). The result can be 
+ * modified only if rv_chg_in_place() returns true.
+ * @result  0 on success, -1 on error,  sets *res_rv or *res_i.
+ */
+inline static int rval_expr_eval_rvint(struct run_act_ctx* h,
+									   struct sip_msg* msg,
+									   struct rvalue** res_rv,
+									   int* res_i,
+									   struct rval_expr* rve,
+									   struct rval_cache* cache
+									   )
+{
+	struct rvalue* rv1;
+	struct rvalue* rv2;
+	struct rval_cache c1; /* local cache */
+	int ret;
+	int r, i, j;
+	enum rval_type type;
+	
+	rv1=0;
+	rv2=0;
+	switch(rve->op){
+		case RVE_RVAL_OP:
+			rv1=&rve->left.rval;
+			rv_ref(rv1);
+			type=rval_get_btype(h, msg, rv1, cache);
+			if (type==RV_INT){
+					r=rval_get_int(h, msg, res_i, rv1, cache);
+					if (unlikely(r<0)){
+						ERR("rval expression evaluation failed\n");
+						goto error;
+					}
+					*res_rv=0;
+					ret=0;
+			}else{
+				/* RV_STR, RV_PVAR, RV_AVP a.s.o => return rv1 and the 
+				   cached resolved value in cache*/
+					*res_rv=rv1;
+					rv_ref(rv1);
+					ret=0;
+			}
+			break;
+		case RVE_UMINUS_OP:
+		case RVE_BOOL_OP:
+		case RVE_LNOT_OP:
+		case RVE_MINUS_OP:
+		case RVE_MUL_OP:
+		case RVE_DIV_OP:
+		case RVE_BOR_OP:
+		case RVE_BAND_OP:
+		case RVE_LAND_OP:
+		case RVE_LOR_OP:
+		case RVE_GT_OP:
+		case RVE_GTE_OP:
+		case RVE_LT_OP:
+		case RVE_LTE_OP:
+		case RVE_EQ_OP:
+		case RVE_DIFF_OP:
+			/* operator forces integer type */
+			ret=rval_expr_eval_int(h, msg, res_i, rve);
+			*res_rv=0;
+			break;
+		case RVE_PLUS_OP:
+			rval_cache_init(&c1);
+			r=rval_expr_eval_rvint(h, msg, &rv1, &i, rve->left.rve, &c1);
+			if (unlikely(r<0)){
+				ERR("rval expression evaluation failed\n");
+				rval_cache_clean(&c1);
+				goto error;
+			}
+			if (rv1==0){
+				if (unlikely((r=rval_expr_eval_int(h, msg, &j,
+														rve->right.rve))<0)){
+						ERR("rval expression evaluation failed\n");
+						rval_cache_clean(&c1);
+						goto error;
+				}
+				int_intop2(res_i, rve->op, i, j);
+				*res_rv=0;
+			}else{
+				rv2=rval_expr_eval(h, msg, rve->right.rve);
+				if (unlikely(rv2==0)){
+					ERR("rval expression evaluation failed\n");
+					rval_cache_clean(&c1);
+					goto error;
+				}
+				*res_rv=rval_str_add2(h, msg, rv1, &c1, rv2, 0);
+				ret=-(*res_rv==0);
+			}
+			rval_cache_clean(&c1);
+			break;
+		case RVE_NONE_OP:
+		/*default:*/
+			BUG("invalid rval expression operation %d\n", rve->op);
+			goto error;
+	};
+	rval_destroy(rv1);
+	rval_destroy(rv2);
+	return ret;
+error:
+	rval_destroy(rv1);
+	rval_destroy(rv2);
+	return -1;
+}
+
+
+
 /** evals a rval expr..
  * WARNING: result must be rval_destroy()'ed if non-null (it might be
  * a reference to another rval). The result can be modified only
@@ -973,6 +1409,16 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
 		case RVE_MINUS_OP:
 		case RVE_MUL_OP:
 		case RVE_DIV_OP:
+		case RVE_BOR_OP:
+		case RVE_BAND_OP:
+		case RVE_LAND_OP:
+		case RVE_LOR_OP:
+		case RVE_GT_OP:
+		case RVE_GTE_OP:
+		case RVE_LT_OP:
+		case RVE_LTE_OP:
+		case RVE_EQ_OP:
+		case RVE_DIFF_OP:
 			/* operator forces integer type */
 			r=rval_expr_eval_int(h, msg, &i, rve);
 			if (likely(r==0)){
@@ -988,31 +1434,6 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
 				goto error;
 			}
 			break;
-#if 0
-		case RVE_UMINUS_OP:
-		case RVE_BOOL_OP:
-		case RVE_LNOT_OP:
-			rv1=rval_expr_eval(h, msg, rve->left.rve);
-			if (likely(rv1)){
-				ret=rv_intop1(op, rv1, 0);
-				rval_destroy(rv1);
-				return ret;
-			}else{
-				ERR("rval expression evaluation failed\n");
-				goto error;
-			}
-			break;
-		case RVE_MUL_OP:
-		case RVE_DIV_OP:
-			rv1=rval_expr_eval(h, msg, rve->left.rve);
-			rv2=rval_expr_eval(h, msg, rve->right.rve);
-			if (unlikely(rv1==0 || rv2==0)){
-				ERR("rval expression evaluation failed\n");
-				goto error;
-			}
-			ret=rv_intop2(rve->op, rv1, 0, rv2, 0);
-			break;
-#endif
 		case RVE_PLUS_OP:
 			rv1=rval_expr_eval(h, msg, rve->left.rve);
 			if (unlikely(rv1==0)){
@@ -1034,12 +1455,13 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
 						ERR("rval expression evaluation failed\n");
 						goto error;
 					}
+					int_intop2(&r, rve->op, i, j);
 					if (rv_chg_in_place(rv1)){
-						rv1->v.l=i+j;
+						rv1->v.l=r;
 						ret=rv1;
 						rv_ref(ret);
 					}else{
-						v.l=i+j;
+						v.l=r;
 						ret=rval_new(RV_INT, &v, 0);
 						if (unlikely(ret==0)){
 							rval_cache_clean(&c1);
@@ -1066,7 +1488,7 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
 			rval_cache_clean(&c1);
 			break;
 		case RVE_NONE_OP:
-		default:
+		/*default:*/
 			BUG("invalid rval expression operation %d\n", rve->op);
 			goto error;
 	};
@@ -1188,7 +1610,17 @@ struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1,
 		case RVE_MUL_OP:
 		case RVE_DIV_OP:
 		case RVE_MINUS_OP:
+		case RVE_BOR_OP:
+		case RVE_BAND_OP:
+		case RVE_LAND_OP:
+		case RVE_LOR_OP:
+		case RVE_GT_OP:
+		case RVE_GTE_OP:
+		case RVE_LT_OP:
+		case RVE_LTE_OP:
 		case RVE_PLUS_OP:
+		case RVE_EQ_OP:
+		case RVE_DIFF_OP:
 			break;
 		default:
 			BUG("unsupported operator %d\n", op);
@@ -1215,8 +1647,6 @@ static int rve_can_optimize_int(struct rval_expr* rve)
 {
 	if (rve->op == RVE_RVAL_OP)
 		return 0;
-	DBG("rve_can_optimize_int: left %d, right %d\n", 
-			rve->left.rve->op, rve->right.rve?rve->right.rve->op:0);
 	if (rve->left.rve->op != RVE_RVAL_OP)
 		return 0;
 	if (rve->left.rve->left.rval.type!=RV_INT)
@@ -1227,6 +1657,8 @@ static int rve_can_optimize_int(struct rval_expr* rve)
 		if (rve->right.rve->left.rval.type!=RV_INT)
 			return 0;
 	}
+	DBG("rve_can_optimize_int: left %d, right %d\n", 
+			rve->left.rve->op, rve->right.rve?rve->right.rve->op:0);
 	return 1;
 }
 
@@ -1289,10 +1721,9 @@ static int fix_rval(struct rvalue* rv)
 			return 0;
 		case RV_NONE:
 			BUG("uninitialized rvalue\n");
-			break;
-		default:
-			BUG("unknown rvalue type %d\n", rv->type);
+			return -1;
 	}
+	BUG("unknown rvalue type %d\n", rv->type);
 	return -1;
 }
 
@@ -1333,7 +1764,17 @@ int fix_rval_expr(void** p)
 		case RVE_MUL_OP:
 		case RVE_DIV_OP:
 		case RVE_MINUS_OP:
+		case RVE_BOR_OP:
+		case RVE_BAND_OP:
+		case RVE_LAND_OP:
+		case RVE_LOR_OP:
+		case RVE_GT_OP:
+		case RVE_GTE_OP:
+		case RVE_LT_OP:
+		case RVE_LTE_OP:
 		case RVE_PLUS_OP:
+		case RVE_EQ_OP:
+		case RVE_DIFF_OP:
 			ret=fix_rval_expr((void**)&rve->left.rve);
 			if (ret<0) return ret;
 			ret=fix_rval_expr((void**)&rve->right.rve);
@@ -1353,8 +1794,8 @@ int fix_rval_expr(void** p)
 		v.l=i;
 		rval_init(&rve->left.rval, RV_INT, &v, 0);
 		rval_init(&rve->right.rval, RV_NONE, 0, 0);
-		rve->op=RVE_RVAL_OP;
 		DBG("FIXUP RVE: optimized int rve/rves (op %d) to %d\n", rve->op, i);
+		rve->op=RVE_RVAL_OP;
 	}else if (rve_can_optimize_str(rve)){
 		if ((rv=rval_expr_eval(0, 0, rve))==0){
 			BUG("unexpected failure\n");
@@ -1369,9 +1810,9 @@ int fix_rval_expr(void** p)
 		rve_destroy(rve->right.rve);
 		rval_init(&rve->left.rval, RV_STR, &v, RV_CNT_ALLOCED_F);
 		rval_init(&rve->right.rval, RV_NONE, 0, 0);
-		rve->op=RVE_RVAL_OP;
 		DBG("FIXUP RVE: optimized str rves (op %d) to %.*s\n",
 				rve->op, v.s.len, v.s.s);
+		rve->op=RVE_RVAL_OP;
 	}
 	return 0;
 }

+ 25 - 4
rvalue.h

@@ -49,10 +49,20 @@ enum rval_expr_op{
 	RVE_BOOL_OP,  /* one member evaluate as bool. : (val!=0)*/
 	RVE_LNOT_OP,  /* one member evaluate as bool. : (!val)*/
 	RVE_MUL_OP,   /* 2 members, returns left * right */
-	RVE_DIV_OP,   /* 2 memebers, returns left / right */
-	RVE_MINUS_OP, /* 2 memebers, returns left - right */
+	RVE_DIV_OP,   /* 2 members, returns left / right */
+	RVE_MINUS_OP, /* 2 members, returns left - right */
+	RVE_BAND_OP,  /* 2 members, returns left | right */
+	RVE_BOR_OP,   /* 2 members, returns left & right */
+	RVE_LAND_OP,  /* 2 members, returns left && right */
+	RVE_LOR_OP,   /* 2 members, returns left || right */
+	RVE_GT_OP,    /*  2 members, returns left > right */
+	RVE_GTE_OP,   /*  2 members, returns left >= right */
+	RVE_LT_OP,    /*  2 members, returns left  < right */
+	RVE_LTE_OP,   /*  2 members, returns left <= right */
 	/* common int & str */
-	RVE_PLUS_OP  /* 2 members, returns left + right */
+	RVE_PLUS_OP,  /* 2 members, returns left + right  (int or str)*/
+	RVE_EQ_OP,    /*  2 members, returns left == right  (int)*/
+	RVE_DIFF_OP,  /*  2 members, returns left != right  (int)*/
 	/* str only */
 };
 
@@ -152,6 +162,11 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg, int* i,
 int rval_get_str(struct run_act_ctx* h, struct sip_msg* msg,
 								str* s, struct rvalue* rv,
 								struct rval_cache* cache);
+/** get the string value of an rv in a tmp variable */
+int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
+								str* tmpv, struct rvalue* rv,
+								struct rval_cache* cache,
+								struct rval_cache* tmp_cache);
 
 /** evals an integer expr  to an int. */
 int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
@@ -160,8 +175,14 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
 struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
 								struct rval_expr* rve);
 
+/** guess the type of an expression.  */
+enum rval_type rve_guess_type(struct rval_expr* rve);
+/** returns true if expression is constant. */
+int rve_is_constant(struct rval_expr* rve);
+/** returns 1 if expression is valid (type-wise).*/
+int rve_check_type(enum rval_type* type, struct rval_expr* rve);
 
-/** create a RVE_RVAL_OP rval_expr, containing a single rval of the given type.
+/** create a RVE_RVAL_OP rval_expr, containing a single rval of the given type
   */
 struct rval_expr* mk_rval_expr_v(enum rval_type rv_type, void* val);
 /** create a unary op. rval_expr.. */