Module: sip-router Branch: andrei/script_vars Commit: 1b9b3fd68c37ac7e3b4afb753c8424ae3f6c6e0f URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=1b9b3fd6...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@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 */ };