diff --git a/conf/cf-lex.l b/conf/cf-lex.l index c4760e40..dcd54b81 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -687,7 +687,7 @@ cf_lex_symbol(const char *data) return ENUM; } case SYM_METHOD: - return sym->method->arg_num ? CF_SYM_METHOD_ARGS : CF_SYM_METHOD_BARE; + return (sym->method->arg_num > 1) ? CF_SYM_METHOD_ARGS : CF_SYM_METHOD_BARE; case SYM_VOID: return CF_SYM_UNDEFINED; default: diff --git a/filter/config.Y b/filter/config.Y index ffa8f115..7cc6f882 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -869,12 +869,12 @@ static_attr: term_dot_method: term '.' { f_method_call_start($1); } method_name_cont { f_method_call_end(); $$ = $4; }; method_name_cont: CF_SYM_METHOD_BARE { - $$ = $1->method->new_inst(FM.object, NULL); + $$ = f_dispatch_method($1, FM.object, NULL); } | CF_SYM_METHOD_ARGS { f_method_call_args(); } '(' var_list ')' { - $$ = $1->method->new_inst(FM.object, $4); + $$ = f_dispatch_method($1, FM.object, $4); } ; @@ -913,32 +913,15 @@ term: | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_const_empty(T_LCLIST); } | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); } | ADD '(' term ',' term ')' { - switch ($3->type) { - case T_CLIST: $$ = f_new_inst(FI_CLIST_ADD, $3, $5); break; - case T_ECLIST: $$ = f_new_inst(FI_ECLIST_ADD, $3, $5); break; - case T_LCLIST: $$ = f_new_inst(FI_LCLIST_ADD, $3, $5); break; - default: cf_error("Can't add to type %s", f_type_name($3->type)); - } + $$ = f_dispatch_method_x("add", $3->type, $3, $5); cf_warn("add(x,y) function is deprecated, please use x.add(y)"); } | DELETE '(' term ',' term ')' { - switch ($3->type) { - case T_PATH: $$ = f_new_inst(FI_PATH_DEL, $3, $5); break; - case T_CLIST: $$ = f_new_inst(FI_CLIST_DEL, $3, $5); break; - case T_ECLIST: $$ = f_new_inst(FI_ECLIST_DEL, $3, $5); break; - case T_LCLIST: $$ = f_new_inst(FI_LCLIST_DEL, $3, $5); break; - default: cf_error("Can't delete from type %s", f_type_name($3->type)); - } + $$ = f_dispatch_method_x("delete", $3->type, $3, $5); cf_warn("delete(x,y) function is deprecated, please use x.delete(y)"); } | FILTER '(' term ',' term ')' { - switch ($3->type) { - case T_PATH: $$ = f_new_inst(FI_PATH_FILTER, $3, $5); break; - case T_CLIST: $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); break; - case T_ECLIST: $$ = f_new_inst(FI_ECLIST_FILTER, $3, $5); break; - case T_LCLIST: $$ = f_new_inst(FI_LCLIST_FILTER, $3, $5); break; - default: cf_error("Can't filter type %s", f_type_name($3->type)); - } + $$ = f_dispatch_method_x("filter", $3->type, $3, $5); cf_warn("filter(x,y) function is deprecated, please use x.filter(y)"); } diff --git a/filter/data.h b/filter/data.h index baa7114c..e136b65f 100644 --- a/filter/data.h +++ b/filter/data.h @@ -67,7 +67,9 @@ enum f_type { struct f_method { struct symbol *sym; struct f_inst *(*new_inst)(struct f_inst *obj, struct f_inst *args); + const struct f_method *next; uint arg_num; + enum f_type args_type[]; }; /* Filter value; size of this affects filter memory consumption */ diff --git a/filter/decl.m4 b/filter/decl.m4 index cc5e9d8e..217488ec 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -53,6 +53,7 @@ m4_define(FID_NEW_ATTRIBUTES, `m4_divert(110)') m4_define(FID_NEW_BODY, `m4_divert(103)') m4_define(FID_NEW_METHOD, `m4_divert(111)') m4_define(FID_METHOD_CALL, `m4_divert(112)') +m4_define(FID_TYPE_SIGNATURE, `m4_divert(113)') m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])') m4_define(FID_LINEARIZE_BODY, `m4_divert(105)') m4_define(FID_SAME_BODY, `m4_divert(106)') @@ -125,7 +126,7 @@ FID_IFCONST([[ constargs = 0; ]]) } while (child$1 = child$1->next); -m4_define([[INST_METHOD_NUM_ARGS]],m4_eval($1-1))m4_dnl +m4_define([[INST_METHOD_NUM_ARGS]],$1)m4_dnl m4_ifelse($1,1,,[[FID_NEW_METHOD()m4_dnl struct f_inst *arg$1 = args; if (args == NULL) cf_error("Not enough arguments"); /* INST_NAME */ @@ -183,6 +184,8 @@ m4_define(ARG_TYPE, `ARG_TYPE_STATIC($1,$2) ARG_TYPE_DYNAMIC($1,$2)') m4_define(ARG_TYPE_STATIC, `m4_dnl m4_ifelse($1,1,[[m4_define([[INST_METHOD_OBJECT_TYPE]],$2)]],)m4_dnl +FID_TYPE_SIGNATURE()m4_dnl + method->args_type[m4_eval($1-1)] = $2; FID_NEW_BODY()m4_dnl if (f$1->type && (f$1->type != ($2)) && !f_const_promotion(f$1, ($2))) cf_error("Argument $1 of %s must be of type %s, got type %s", @@ -230,7 +233,7 @@ FID_NEW_ARGS()m4_dnl , struct f_inst * f$1 FID_NEW_BODY()m4_dnl whati->f$1 = f$1; -m4_define([[INST_METHOD_NUM_ARGS]],m4_eval($1-1))m4_dnl +m4_define([[INST_METHOD_NUM_ARGS]],$1)m4_dnl FID_NEW_METHOD()m4_dnl struct f_inst *arg$1 = args; if (args == NULL) cf_error("Not enough arguments"); /* INST_NAME */ @@ -421,17 +424,11 @@ m4_undivert(112) FID_METHOD_SCOPE_INIT()m4_dnl [INST_METHOD_OBJECT_TYPE] = {}, FID_METHOD_REGISTER()m4_dnl - sym = cf_new_symbol(&f_type_method_scopes[INST_METHOD_OBJECT_TYPE], - global_root_scope_pool, global_root_scope_linpool, - INST_METHOD_NAME); - sym->class = SYM_METHOD; - sym->method = method = lp_allocz(global_root_scope_linpool, sizeof(struct f_method)); - - *method = (struct f_method) { - .sym = sym, - .new_inst = f_new_method_]]INST_NAME()[[, - .arg_num = INST_METHOD_NUM_ARGS, - }; + method = lp_allocz(global_root_scope_linpool, sizeof(struct f_method) + INST_METHOD_NUM_ARGS * sizeof(enum f_type)); + method->new_inst = f_new_method_]]INST_NAME()[[; + method->arg_num = INST_METHOD_NUM_ARGS; +m4_undivert(113) + f_register_method(INST_METHOD_OBJECT_TYPE, INST_METHOD_NAME, method); ]])m4_dnl @@ -634,10 +631,27 @@ struct sym_scope *f_type_method_scope(enum f_type t) return (t < ARRAY_SIZE(f_type_method_scopes)) ? &f_type_method_scopes[t] : NULL; } +static void +f_register_method(enum f_type t, const byte *name, struct f_method *dsc) +{ + struct sym_scope *scope = &f_type_method_scopes[t]; + struct symbol *sym = cf_find_symbol_scope(scope, name); + + if (!sym) + { + sym = cf_new_symbol(scope, global_root_scope_pool, global_root_scope_linpool, name); + sym->class = SYM_METHOD; + } + + dsc->sym = sym; + dsc->next = sym->method; + sym->method = dsc; +} + void f_type_methods_register(void) { - struct symbol *sym; struct f_method *method; + FID_WR_PUT(13) for (uint i = 0; i < ARRAY_SIZE(f_type_method_scopes); i++) diff --git a/filter/f-inst.c b/filter/f-inst.c index 8c4d15d5..a9de0960 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -1246,7 +1246,8 @@ RESULT(T_PATH, ad, [[ as_path_prepend(fpool, v1.val.ad, v2.val.i) ]]); } - INST(FI_CLIST_ADD, 2, 1) { /* (Extended) Community list add */ + /* Community list add */ + INST(FI_CLIST_ADD, 2, 1) { ARG(1, T_CLIST); ARG_ANY(2); METHOD_CONSTRUCTOR("add"); @@ -1264,47 +1265,54 @@ runtime("Can't add non-pair"); } - INST(FI_ECLIST_ADD, 2, 1) { + INST(FI_ECLIST_ADD_EC, 2, 1) { ARG(1, T_ECLIST); - ARG_ANY(2); + ARG(2, T_EC); METHOD_CONSTRUCTOR("add"); - /* v2.val is either EC or EC-set */ - if ((v2.type == T_SET) && eclist_set_type(v2.val.t)) - runtime("Can't add set"); - else if (v2.type == T_ECLIST) - RESULT(T_ECLIST, ad, [[ ec_set_union(fpool, v1.val.ad, v2.val.ad) ]]); - else if (v2.type != T_EC) - runtime("Can't add non-ec"); - else - RESULT(T_ECLIST, ad, [[ ec_set_add(fpool, v1.val.ad, v2.val.ec) ]]); + RESULT(T_ECLIST, ad, [[ ec_set_add(fpool, v1.val.ad, v2.val.ec) ]]); } - INST(FI_LCLIST_ADD, 2, 1) { + INST(FI_ECLIST_ADD_ECLIST, 2, 1) { + ARG(1, T_ECLIST); + ARG(2, T_ECLIST); + METHOD_CONSTRUCTOR("add"); + RESULT(T_ECLIST, ad, [[ ec_set_union(fpool, v1.val.ad, v2.val.ad) ]]); + } + + INST(FI_LCLIST_ADD_LC, 2, 1) { ARG(1, T_LCLIST); - ARG_ANY(2); + ARG(2, T_LC); METHOD_CONSTRUCTOR("add"); - /* v2.val is either LC or LC-set */ - if ((v2.type == T_SET) && lclist_set_type(v2.val.t)) - runtime("Can't add set"); - else if (v2.type == T_LCLIST) - RESULT(T_LCLIST, ad, [[ lc_set_union(fpool, v1.val.ad, v2.val.ad) ]]); - else if (v2.type != T_LC) - runtime("Can't add non-lc"); - else - RESULT(T_LCLIST, ad, [[ lc_set_add(fpool, v1.val.ad, v2.val.lc) ]]); + RESULT(T_LCLIST, ad, [[ lc_set_add(fpool, v1.val.ad, v2.val.lc) ]]); } - INST(FI_PATH_DEL, 2, 1) { /* Path delete */ + INST(FI_LCLIST_ADD_LCLIST, 2, 1) { + ARG(1, T_LCLIST); + ARG(2, T_LCLIST); + METHOD_CONSTRUCTOR("add"); + RESULT(T_LCLIST, ad, [[ lc_set_union(fpool, v1.val.ad, v2.val.ad) ]]); + } + + INST(FI_PATH_DELETE_INT, 2, 1) { ARG(1, T_PATH); - ARG_ANY(2); + ARG(2, T_INT); METHOD_CONSTRUCTOR("delete"); - if ((v2.type == T_SET) && path_set_type(v2.val.t) || (v2.type == T_INT)) - RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, &v2, 0) ]]); - else - runtime("Can't delete non-integer (set)"); + RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, &v2, 0) ]]); } - INST(FI_CLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */ + INST(FI_PATH_DELETE_SET, 2, 1) { + ARG(1, T_PATH); + ARG(2, T_SET); + METHOD_CONSTRUCTOR("delete"); + + if (!path_set_type(v2.val.t)) + runtime("Mismatched set type"); + + RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, &v2, 0) ]]); + } + + /* Community list delete */ + INST(FI_CLIST_DELETE, 2, 1) { ARG(1, T_CLIST); ARG_ANY(2); METHOD_CONSTRUCTOR("delete"); @@ -1322,76 +1330,119 @@ runtime("Can't delete non-pair"); } - INST(FI_ECLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */ + INST(FI_ECLIST_DELETE_EC, 2, 1) { ARG(1, T_ECLIST); - ARG_ANY(2); + ARG(2, T_EC); METHOD_CONSTRUCTOR("delete"); - /* v2.val is either EC or EC-set */ - if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST)) - RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]); - else if (v2.type != T_EC) - runtime("Can't delete non-ec"); - else - RESULT(T_ECLIST, ad, [[ ec_set_del(fpool, v1.val.ad, v2.val.ec) ]]); + RESULT(T_ECLIST, ad, [[ ec_set_del(fpool, v1.val.ad, v2.val.ec) ]]); } - INST(FI_LCLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */ + INST(FI_ECLIST_DELETE_ECLIST, 2, 1) { + ARG(1, T_ECLIST); + ARG(2, T_ECLIST); + METHOD_CONSTRUCTOR("delete"); + RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]); + } + + INST(FI_ECLIST_DELETE_SET, 2, 1) { + ARG(1, T_ECLIST); + ARG(2, T_SET); + METHOD_CONSTRUCTOR("delete"); + + if (!eclist_set_type(v2.val.t)) + runtime("Mismatched set type"); + + RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]); + } + + INST(FI_LCLIST_DELETE_LC, 2, 1) { ARG(1, T_LCLIST); - ARG_ANY(2); + ARG(2, T_LC); METHOD_CONSTRUCTOR("delete"); - /* v2.val is either LC or LC-set */ - if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST)) - RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]); - else if (v2.type != T_LC) - runtime("Can't delete non-lc"); - else - RESULT(T_LCLIST, ad, [[ lc_set_del(fpool, v1.val.ad, v2.val.lc) ]]); + RESULT(T_LCLIST, ad, [[ lc_set_del(fpool, v1.val.ad, v2.val.lc) ]]); } - INST(FI_PATH_FILTER, 2, 1) { /* (Extended) Community list add or delete */ + INST(FI_LCLIST_DELETE_LCLIST, 2, 1) { + ARG(1, T_LCLIST); + ARG(2, T_LCLIST); + METHOD_CONSTRUCTOR("delete"); + RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]); + } + + INST(FI_LCLIST_DELETE_SET, 2, 1) { + ARG(1, T_LCLIST); + ARG(2, T_SET); + METHOD_CONSTRUCTOR("delete"); + + if (!lclist_set_type(v2.val.t)) + runtime("Mismatched set type"); + + RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]); + } + + INST(FI_PATH_FILTER_SET, 2, 1) { ARG(1, T_PATH); - ARG_ANY(2); + ARG(2, T_SET); METHOD_CONSTRUCTOR("filter"); - if ((v2.type == T_SET) && path_set_type(v2.val.t)) - RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, &v2, 1) ]]); - else - runtime("Can't filter integer"); - } + if (!path_set_type(v2.val.t)) + runtime("Mismatched set type"); - INST(FI_CLIST_FILTER, 2, 1) { + RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, &v2, 1) ]]); + } + + INST(FI_CLIST_FILTER_CLIST, 2, 1) { ARG(1, T_CLIST); - ARG_ANY(2); + ARG(2, T_CLIST); METHOD_CONSTRUCTOR("filter"); - /* Community (or cluster) list */ - struct f_val dummy; - - if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST)) - RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]); - else - runtime("Can't filter pair"); + RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]); } - INST(FI_ECLIST_FILTER, 2, 1) { + INST(FI_CLIST_FILTER_SET, 2, 1) { + ARG(1, T_CLIST); + ARG(2, T_SET); + METHOD_CONSTRUCTOR("filter"); + + if (!clist_set_type(v2.val.t, &(struct f_val){})) + runtime("Mismatched set type"); + + RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]); + } + + INST(FI_ECLIST_FILTER_ECLIST, 2, 1) { ARG(1, T_ECLIST); - ARG_ANY(2); + ARG(2, T_ECLIST); METHOD_CONSTRUCTOR("filter"); - /* v2.val is either EC or EC-set */ - if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST)) - RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]); - else - runtime("Can't filter ec"); + RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]); } - INST(FI_LCLIST_FILTER, 2, 1) { - ARG(1, T_LCLIST); - ARG_ANY(2); + INST(FI_ECLIST_FILTER_SET, 2, 1) { + ARG(1, T_ECLIST); + ARG(2, T_SET); METHOD_CONSTRUCTOR("filter"); - /* v2.val is either LC or LC-set */ - if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST)) - RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]); - else - runtime("Can't filter lc"); + + if (!eclist_set_type(v2.val.t)) + runtime("Mismatched set type"); + + RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]); + } + + INST(FI_LCLIST_FILTER_LCLIST, 2, 1) { + ARG(1, T_LCLIST); + ARG(2, T_LCLIST); + METHOD_CONSTRUCTOR("filter"); + RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]); + } + + INST(FI_LCLIST_FILTER_SET, 2, 1) { + ARG(1, T_LCLIST); + ARG(2, T_SET); + METHOD_CONSTRUCTOR("filter"); + + if (!lclist_set_type(v2.val.t)) + runtime("Mismatched set type"); + + RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]); } INST(FI_ROA_CHECK_IMPLICIT, 0, 1) { /* ROA Check */ diff --git a/filter/f-inst.h b/filter/f-inst.h index 8c304de5..f5dfcd20 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -96,6 +96,8 @@ void f_add_lines(const struct f_line_item *what, struct filter_iterator *fit); struct filter *f_new_where(struct f_inst *); +struct f_inst *f_dispatch_method(struct symbol *sym, struct f_inst *obj, struct f_inst *args); +struct f_inst *f_dispatch_method_x(const char *name, enum f_type t, struct f_inst *obj, struct f_inst *args); struct f_inst *f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block); struct f_inst *f_print(struct f_inst *vars, int flush, enum filter_return fret); diff --git a/filter/f-util.c b/filter/f-util.c index 98b7d1a8..7ce3f9c8 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -30,7 +30,8 @@ filter_name(const struct filter *filter) return filter->sym->name; } -struct filter *f_new_where(struct f_inst *where) +struct filter * +f_new_where(struct f_inst *where) { struct f_inst *cond = f_new_inst(FI_CONDITION, where, f_new_inst(FI_DIE, F_ACCEPT), @@ -41,6 +42,43 @@ struct filter *f_new_where(struct f_inst *where) return f; } +static inline int +f_match_signature(const struct f_method *dsc, struct f_inst *args) +{ + uint i; + + for (i = 1; args && (i < dsc->arg_num); args = args->next, i++) + if (dsc->args_type[i] && (args->type != dsc->args_type[i])) + return 0; + + return !args && !(i < dsc->arg_num); +} + +struct f_inst * +f_dispatch_method(struct symbol *sym, struct f_inst *obj, struct f_inst *args) +{ + /* Note! We should revert args */ + + for (const struct f_method *dsc = sym->method; dsc; dsc = dsc->next) + if (f_match_signature(dsc, args)) + return dsc->new_inst(obj, args); + + cf_error("Cannot dispatch method '%s'", sym->name); +} + +struct f_inst * +f_dispatch_method_x(const char *name, enum f_type t, struct f_inst *obj, struct f_inst *args) +{ + struct sym_scope *scope = f_type_method_scope(t); + struct symbol *sym = cf_find_symbol_scope(scope, name); + + if (!sym) + cf_error("Cannot dispatch method '%s'", name); + + return f_dispatch_method(sym, obj, args); +} + + struct f_inst * f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block) {