[SR-Dev] git:andrei/script_vars: script engine: different operators for int and str +

Andrei Pelinescu-Onciul andrei at iptel.org
Thu Dec 18 17:00:55 CET 2008


Module: sip-router
Branch: andrei/script_vars
Commit: 1b9b3fd68c37ac7e3b4afb753c8424ae3f6c6e0f
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=1b9b3fd68c37ac7e3b4afb753c8424ae3f6c6e0f

Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei at iptel.org>
Date:   Thu Dec 18 14:46:05 2008 +0100

script engine: different operators for int and str +

- different operators for integer + (RVE_IPLUS_OP) and str plus
  (RVE_CONCAT_OP). The generic plus (RVE_PLUS_OP) is still
  present, the new operators are only used in internal
  optimizations (see below) for now.
- if an expression involving the generic '+' is always of type int
  or str, replace the generic '+' with the interger or string
  version (makes further optimizations possible).

---

 rvalue.c |  112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 rvalue.h |    4 ++-
 2 files changed, 110 insertions(+), 6 deletions(-)

diff --git a/rvalue.c b/rvalue.c
index 2a1ea88..6471e85 100644
--- a/rvalue.c
+++ b/rvalue.c
@@ -385,10 +385,13 @@ enum rval_type rve_guess_type( struct rval_expr* rve)
 		case RVE_LTE_OP:
 		case RVE_EQ_OP:
 		case RVE_DIFF_OP:
+		case RVE_IPLUS_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_CONCAT_OP:
+			return RV_STR;
 		case RVE_NONE_OP:
 			break;
 	}
@@ -437,6 +440,8 @@ int rve_is_constant(struct rval_expr* rve)
 		case RVE_EQ_OP:
 		case RVE_DIFF_OP:
 		case RVE_PLUS_OP:
+		case RVE_IPLUS_OP:
+		case RVE_CONCAT_OP:
 			return rve_is_constant(rve->left.rve) &&
 					rve_is_constant(rve->right.rve);
 		case RVE_NONE_OP:
@@ -473,6 +478,8 @@ static int rve_op_unary(enum rval_expr_op op)
 		case RVE_EQ_OP:
 		case RVE_DIFF_OP:
 		case RVE_PLUS_OP:
+		case RVE_IPLUS_OP:
+		case RVE_CONCAT_OP:
 			return 0;
 		case RVE_NONE_OP:
 			return -1;
@@ -532,6 +539,7 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
 		case RVE_GTE_OP:
 		case RVE_LT_OP:
 		case RVE_LTE_OP:
+		case RVE_IPLUS_OP:
 			*type=RV_INT;
 			if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
 				if (type1==RV_STR){
@@ -587,6 +595,28 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
 					return 1;
 				}
 			}
+		case RVE_CONCAT_OP:
+			*type=RV_STR;
+			if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
+				if (rve_check_type(&type2, rve->right.rve, bad_rve, bad_t,
+									exp_t)){
+					if ((type2!=type1) && (type1!=RV_NONE) &&
+							(type2!=RV_NONE) && 
+							!(type1==RV_STR && type2==RV_INT)){
+						if (bad_rve) *bad_rve=rve->right.rve;
+						if (bad_t) *bad_t=type2;
+						if (exp_t) *exp_t=type1;
+						return 0;
+					}
+					if (type1==RV_INT){
+						if (bad_rve) *bad_rve=rve->left.rve;
+						if (bad_t) *bad_t=type1;
+						if (exp_t) *exp_t=RV_STR;
+						return 0;
+					}
+					return 1;
+				}
+			}
 		case RVE_NONE_OP:
 			break;
 	}
@@ -936,6 +966,7 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
 {
 	switch(op){
 		case RVE_PLUS_OP:
+		case RVE_IPLUS_OP:
 			*res=v1+v2;
 			break;
 		case RVE_MINUS_OP:
@@ -981,6 +1012,10 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
 		case RVE_DIFF_OP:
 			*res=v1 != v2;
 			break;
+		case RVE_CONCAT_OP:
+			*res=0;
+			/* invalid operand for int */
+			return -1;
 		default:
 			BUG("rv unsupported intop %d\n", op);
 			return -1;
@@ -1286,6 +1321,7 @@ 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_IPLUS_OP:
 		case RVE_BOR_OP:
 		case RVE_BAND_OP:
 		case RVE_GT_OP:
@@ -1376,6 +1412,10 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
 				rval_destroy(rv2);
 			break;
 #endif
+		case RVE_CONCAT_OP:
+			*res=0;
+			ret=-1;
+			break;
 		case RVE_NONE_OP:
 		/*default:*/
 			BUG("invalid rval int expression operation %d\n", rve->op);
@@ -1446,6 +1486,7 @@ int rval_expr_eval_rvint(			   struct run_act_ctx* h,
 		case RVE_LTE_OP:
 		case RVE_EQ_OP:
 		case RVE_DIFF_OP:
+		case RVE_IPLUS_OP:
 			/* operator forces integer type */
 			ret=rval_expr_eval_int(h, msg, res_i, rve);
 			*res_rv=0;
@@ -1479,6 +1520,10 @@ int rval_expr_eval_rvint(			   struct run_act_ctx* h,
 			}
 			rval_cache_clean(&c1);
 			break;
+		case RVE_CONCAT_OP:
+			*res_rv=rval_expr_eval(h, msg, rve);
+			ret=-(*res_rv==0);
+			break;
 		case RVE_NONE_OP:
 		/*default:*/
 			BUG("invalid rval expression operation %d\n", rve->op);
@@ -1535,6 +1580,7 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
 		case RVE_LTE_OP:
 		case RVE_EQ_OP:
 		case RVE_DIFF_OP:
+		case RVE_IPLUS_OP:
 			/* operator forces integer type */
 			r=rval_expr_eval_int(h, msg, &i, rve);
 			if (likely(r==0)){
@@ -1603,6 +1649,19 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
 			}
 			rval_cache_clean(&c1);
 			break;
+		case RVE_CONCAT_OP:
+			rv1=rval_expr_eval(h, msg, rve->left.rve);
+			if (unlikely(rv1==0)){
+				ERR("rval expression evaluation failed\n");
+				goto error;
+			}
+			rv2=rval_expr_eval(h, msg, rve->right.rve);
+			if (unlikely(rv2==0)){
+				ERR("rval expression evaluation failed\n");
+				goto error;
+			}
+			ret=rval_str_add2(h, msg, rv1, 0, rv2, 0);
+			break;
 		case RVE_NONE_OP:
 		/*default:*/
 			BUG("invalid rval expression operation %d\n", rve->op);
@@ -1767,8 +1826,10 @@ struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1,
 		case RVE_LT_OP:
 		case RVE_LTE_OP:
 		case RVE_PLUS_OP:
+		case RVE_IPLUS_OP:
 		case RVE_EQ_OP:
 		case RVE_DIFF_OP:
+		case RVE_CONCAT_OP:
 			break;
 		default:
 			BUG("unsupported operator %d\n", op);
@@ -1802,6 +1863,8 @@ static int rve_op_is_assoc(enum rval_expr_op op)
 		case RVE_MINUS_OP:
 			return 0;
 		case RVE_PLUS_OP:
+		case RVE_IPLUS_OP:
+		case RVE_CONCAT_OP:
 		case RVE_MUL_OP:
 		case RVE_BAND_OP:
 		case RVE_BOR_OP:
@@ -1838,6 +1901,7 @@ static int rve_op_is_commutative(enum rval_expr_op op, enum rval_type type)
 			return 0;
 		case RVE_PLUS_OP:
 			return type==RV_INT; /* commutative only for INT*/
+		case RVE_IPLUS_OP:
 		case RVE_MUL_OP:
 		case RVE_BAND_OP:
 		case RVE_BOR_OP:
@@ -1851,6 +1915,7 @@ static int rve_op_is_commutative(enum rval_expr_op op, enum rval_type type)
 		case RVE_LTE_OP:
 		case RVE_EQ_OP:
 		case RVE_DIFF_OP:
+		case RVE_CONCAT_OP:
 			return 0;
 	}
 	return 0;
@@ -2158,9 +2223,10 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
 				}
 				break;
 			case RVE_PLUS_OP:
+			case RVE_IPLUS_OP:
 				/* we must make sure that this is an int PLUS
 				   (because "foo"+0 is valid => "foo0") */
-				if ((i==0) && (rve_type==RV_INT)){
+				if ((i==0) && ((op==RVE_IPLUS_OP)||(rve_type==RV_INT))){
 					/* $v +  0 -> $v
 					 *  0 + $v -> $v */
 					rve_destroy(ct_rve);
@@ -2206,14 +2272,32 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
 							op, i);
 			}
 		}
-	}
-	/* no optimization for strings for now
+	}else if (rv->type==RV_STR){
+		switch(op){
+			case RVE_CONCAT_OP:
+				if (rv->v.s.len==0){
+					/* $v . "" -> $v 
+					   "" . $v -> $v */
+					rve_destroy(ct_rve);
+					pos=rve->fpos;
+					*rve=*v_rve; /* replace current expr. with $v */
+					rve->fpos=pos;
+					pkg_free(v_rve);/* rve_destroy(v_rve) would free
+									   everything*/
+					ret=1;
+				}
+				break;
+			default:
+				break;
+		}
+	/* no optimization for generic RVE_PLUS_OP for now, only for RVE_CONCAT_OP
 	   (We could optimize $v + "" or ""+$v, but this ""+$v is a way
 	    to force convert $v to str , it might mess up type checking
 	    (e.g. errors w/o optimization and no errors with) and it brings
 	    a very small benefit anyway (it's unlikely we'll see a lot of
 	    "")
 	*/
+	}
 	if (rv) rval_destroy(rv);
 	return ret;
 error:
@@ -2232,7 +2316,7 @@ static int rve_optimize(struct rval_expr* rve)
 	enum rval_expr_op op;
 	int flags;
 	struct rval_expr tmp_rve;
-	enum rval_type type;
+	enum rval_type type, l_type;
 	struct rval_expr* bad_rve;
 	enum rval_type bad_type, exp_type;
 	
@@ -2285,7 +2369,7 @@ static int rve_optimize(struct rval_expr* rve)
 				rv->v.l=-rv->v.l;
 				if (rve_replace_with_ct_rv(rve->right.rve, rv)<0)
 					goto error;
-				rve->op=RVE_PLUS_OP;
+				rve->op=RVE_IPLUS_OP;
 				DBG("FIXUP RVE: optimized $v - a into $v + (%d)\n",
 								(int)rve->right.rve->left.rval.v.l);
 			}
@@ -2293,6 +2377,22 @@ static int rve_optimize(struct rval_expr* rve)
 			rv=0;
 		}
 		
+		/* e1 PLUS_OP e2 -> change op if we know e1 basic type */
+		if (rve->op==RVE_PLUS_OP){
+			l_type=rve_guess_type(rve->left.rve);
+			if (l_type==RV_INT){
+				rve->op=RVE_IPLUS_OP;
+				DBG("FIXUP RVE (%d,%d-%d,%d): changed + into interger plus\n",
+						rve->fpos.s_line, rve->fpos.s_col,
+						rve->fpos.e_line, rve->fpos.e_col);
+			}else if (l_type==RV_STR){
+				rve->op=RVE_CONCAT_OP;
+				DBG("FIXUP RVE (%d,%d-%d,%d): changed + into string concat\n",
+						rve->fpos.s_line, rve->fpos.s_col,
+						rve->fpos.e_line, rve->fpos.e_col);
+			}
+		}
+		
 		/* $v * 0 => 0; $v * 1 => $v (for *, /, &, |, &&, ||, +, -) */
 		if (rve_opt_01(rve, type)==1){
 			/* success, rve was changed => return now
@@ -2510,8 +2610,10 @@ int fix_rval_expr(void** p)
 		case RVE_LT_OP:
 		case RVE_LTE_OP:
 		case RVE_PLUS_OP:
+		case RVE_IPLUS_OP:
 		case RVE_EQ_OP:
 		case RVE_DIFF_OP:
+		case RVE_CONCAT_OP:
 			ret=fix_rval_expr((void**)&rve->left.rve);
 			if (ret<0) return ret;
 			ret=fix_rval_expr((void**)&rve->right.rve);
diff --git a/rvalue.h b/rvalue.h
index f36f189..a694c0d 100644
--- a/rvalue.h
+++ b/rvalue.h
@@ -59,10 +59,12 @@ enum rval_expr_op{
 	RVE_GTE_OP,   /*  2 members, returns left >= right */
 	RVE_LT_OP,    /*  2 members, returns left  < right */
 	RVE_LTE_OP,   /*  2 members, returns left <= right */
+	RVE_IPLUS_OP, /* 2 members, integer +, returns int(a)+int(b) */
 	/* common int & str */
-	RVE_PLUS_OP,  /* 2 members, returns left + right  (int or str)*/
+	RVE_PLUS_OP,  /* generic plus (int or str) returns left + right */
 	RVE_EQ_OP,    /*  2 members, returns left == right  (int)*/
 	RVE_DIFF_OP,  /*  2 members, returns left != right  (int)*/
+	RVE_CONCAT_OP,/* string concatenation, returns left . right */
 	/* str only */
 };
 




More information about the sr-dev mailing list