mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 17:51:53 +00:00
Merge commit 'a3dc2645' into thread-next
This commit is contained in:
commit
de8288c679
@ -391,6 +391,7 @@ else: {
|
||||
\>\= return GEQ;
|
||||
\&\& return AND;
|
||||
\|\| return OR;
|
||||
\-\> return IMP;
|
||||
|
||||
\[\= return PO;
|
||||
\=\] return PC;
|
||||
|
@ -100,7 +100,7 @@ CF_DECLS
|
||||
}
|
||||
|
||||
%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
|
||||
%token GEQ LEQ NEQ AND OR
|
||||
%token GEQ LEQ NEQ AND OR IMP
|
||||
%token PO PC
|
||||
%token <i> NUM ENUM
|
||||
%token <ip4> IP4
|
||||
@ -128,7 +128,7 @@ CF_DECLS
|
||||
|
||||
%nonassoc PREFIX_DUMMY
|
||||
%left AND OR
|
||||
%nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA PO PC
|
||||
%nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA IMP PO PC
|
||||
%left '|' '&'
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
|
@ -551,7 +551,7 @@ include "tablename.conf";;
|
||||
Define a filter. You can learn more about filters in the following
|
||||
chapter.
|
||||
|
||||
<tag><label id="opt-function">function <m/type/ <m/name/ (<m/parameters/) <m/local variables/ { <m/commands/ }</tag>
|
||||
<tag><label id="opt-function">function <m/name/ (<m/parameters/) [ -> <m/return type/ ] <m/local variables/ { <m/commands/ }</tag>
|
||||
Define a function. You can learn more about functions in the following chapter.
|
||||
|
||||
<tag><label id="opt-protocol">protocol rip|ospf|bgp|<m/.../ [<m/name/ [from <m/name2/]] { <m>protocol options</m> }</tag>
|
||||
@ -1344,21 +1344,21 @@ can group several statements to a single compound statement by using braces
|
||||
(<cf>{ <M>statements</M> }</cf>) which is useful if you want to make a bigger
|
||||
block of code conditional.
|
||||
|
||||
<p>BIRD supports functions, so that you don't have to repeat the same blocks of
|
||||
code over and over. Functions can have zero or more parameters and they can have
|
||||
local variables. You should always specify the function return type and always
|
||||
return it. No-return functions and multiple-type returning functions are deprecated.
|
||||
Direct recursion is possible. Function definitions look like this:
|
||||
<p>BIRD supports functions, so that you don not have to repeat the same blocks
|
||||
of code over and over. Functions can have zero or more parameters and they can
|
||||
have local variables. If the function returns value, then you should always
|
||||
specify its return type. Direct recursion is possible. Function definitions look
|
||||
like this:
|
||||
|
||||
<code>
|
||||
function int name ()
|
||||
function name() -> int
|
||||
{
|
||||
int local_variable;
|
||||
int another_variable = 5;
|
||||
return 42;
|
||||
}
|
||||
|
||||
function pair with_parameters (int parameter)
|
||||
function with_parameters(int parameter) -> pair
|
||||
{
|
||||
print parameter;
|
||||
return (1, 2);
|
||||
|
@ -374,12 +374,12 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||
%nonassoc ELSE
|
||||
|
||||
%type <xp> cmds_int cmd_prep
|
||||
%type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
|
||||
%type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list var_list_r function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
|
||||
%type <fsa> static_attr
|
||||
%type <f> filter where_filter
|
||||
%type <fl> filter_body function_body
|
||||
%type <flv> lvalue
|
||||
%type <i> type maybe_type function_vars
|
||||
%type <i> type function_vars function_type
|
||||
%type <fa> function_argsn function_args
|
||||
%type <ecs> ec_kind
|
||||
%type <fret> break_command
|
||||
@ -527,6 +527,11 @@ function_vars:
|
||||
}
|
||||
;
|
||||
|
||||
function_type:
|
||||
/* EMPTY */ { $$ = T_VOID; }
|
||||
| IMP type { $$ = $2; }
|
||||
;
|
||||
|
||||
filter_body: function_body ;
|
||||
|
||||
filter:
|
||||
@ -566,29 +571,24 @@ function_body:
|
||||
;
|
||||
|
||||
conf: function_def ;
|
||||
maybe_type:
|
||||
/* EMPTY */ { $$ = T_VOID; }
|
||||
| type { $$ = $1; }
|
||||
;
|
||||
|
||||
function_def:
|
||||
FUNCTION maybe_type symbol {
|
||||
DBG( "Beginning of function %s\n", $3->name );
|
||||
this_function = cf_define_symbol(new_config, $3, SYM_FUNCTION, function, NULL);
|
||||
/* if ($2 == T_VOID) cf_warn("Support for functions without explicit return type will be removed soon" ); */
|
||||
FUNCTION symbol {
|
||||
DBG( "Beginning of function %s\n", $2->name );
|
||||
this_function = cf_define_symbol(new_config, $2, SYM_FUNCTION, function, NULL);
|
||||
cf_enter_filters();
|
||||
cf_push_scope(new_config, this_function);
|
||||
} function_args {
|
||||
} function_args function_type {
|
||||
/* Make dummy f_line for storing function prototype */
|
||||
struct f_line *dummy = cfg_allocz(sizeof(struct f_line));
|
||||
this_function->function = dummy;
|
||||
|
||||
dummy->return_type = $2;
|
||||
dummy->return_type = $5;
|
||||
|
||||
/* Revert the args */
|
||||
while ($5) {
|
||||
struct f_arg *tmp = $5;
|
||||
$5 = $5->next;
|
||||
while ($4) {
|
||||
struct f_arg *tmp = $4;
|
||||
$4 = $4->next;
|
||||
|
||||
tmp->next = dummy->arg_list;
|
||||
dummy->arg_list = tmp;
|
||||
@ -598,7 +598,7 @@ function_def:
|
||||
$7->args = this_function->function->args;
|
||||
$7->arg_list = this_function->function->arg_list;
|
||||
$7->return_type = this_function->function->return_type;
|
||||
$3->function = $7;
|
||||
$2->function = $7;
|
||||
cf_pop_scope(new_config);
|
||||
cf_exit_filters();
|
||||
}
|
||||
@ -828,10 +828,27 @@ constructor:
|
||||
;
|
||||
|
||||
|
||||
/* This generates the function_call variable list backwards. */
|
||||
var_list: /* EMPTY */ { $$ = NULL; }
|
||||
/* This generates the function_call variable list backwards */
|
||||
var_list_r:
|
||||
/* EMPTY */ { $$ = NULL; }
|
||||
| term { $$ = $1; }
|
||||
| var_list ',' term { $$ = $3; $$->next = $1; }
|
||||
| var_list_r ',' term { $$ = $3; $$->next = $1; }
|
||||
;
|
||||
|
||||
var_list: var_list_r
|
||||
{
|
||||
$$ = NULL;
|
||||
|
||||
/* Revert the var_list_r */
|
||||
while ($1) {
|
||||
struct f_inst *tmp = $1;
|
||||
$1 = $1->next;
|
||||
|
||||
tmp->next = $$;
|
||||
$$ = tmp;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
function_call:
|
||||
CF_SYM_KNOWN '(' var_list ')'
|
||||
@ -839,17 +856,7 @@ function_call:
|
||||
if ($1->class != SYM_FUNCTION)
|
||||
cf_error("You can't call something which is not a function. Really.");
|
||||
|
||||
/* Revert the var_list */
|
||||
struct f_inst *args = NULL;
|
||||
while ($3) {
|
||||
struct f_inst *tmp = $3;
|
||||
$3 = $3->next;
|
||||
|
||||
tmp->next = args;
|
||||
args = tmp;
|
||||
}
|
||||
|
||||
$$ = f_new_inst(FI_CALL, args, $1);
|
||||
$$ = f_new_inst(FI_CALL, $3, $1);
|
||||
}
|
||||
;
|
||||
|
||||
@ -885,12 +892,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 {
|
||||
$$ = f_dispatch_method($1, FM.object, NULL);
|
||||
$$ = f_dispatch_method($1, FM.object, NULL, 1);
|
||||
}
|
||||
| CF_SYM_METHOD_ARGS {
|
||||
f_method_call_args();
|
||||
} '(' var_list ')' {
|
||||
$$ = f_dispatch_method($1, FM.object, $4);
|
||||
$$ = f_dispatch_method($1, FM.object, $4, 1);
|
||||
}
|
||||
;
|
||||
|
||||
@ -927,7 +934,11 @@ term:
|
||||
| '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_CLIST)); }
|
||||
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_ECLIST)); }
|
||||
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_LCLIST)); }
|
||||
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
|
||||
|
||||
| PREPEND '(' term ',' term ')' {
|
||||
$$ = f_dispatch_method_x("prepend", $3->type, $3, $5);
|
||||
cf_warn("prepend(x,y) function is deprecated, please use x.prepend(y)");
|
||||
}
|
||||
| ADD '(' term ',' term ')' {
|
||||
$$ = f_dispatch_method_x("add", $3->type, $3, $5);
|
||||
cf_warn("add(x,y) function is deprecated, please use x.add(y)");
|
||||
@ -1039,13 +1050,13 @@ cmd:
|
||||
cf_error("Attribute %s is read-only", $3->attribute->name);
|
||||
$$ = f_new_inst(FI_EA_UNSET, $3->attribute);
|
||||
}
|
||||
| break_command var_list ';' {
|
||||
| break_command var_list_r ';' {
|
||||
$$ = f_print($2, !!$2, $1);
|
||||
}
|
||||
| PRINT var_list ';' {
|
||||
| PRINT var_list_r ';' {
|
||||
$$ = f_print($2, 1, F_NOP);
|
||||
}
|
||||
| PRINTN var_list ';' {
|
||||
| PRINTN var_list_r ';' {
|
||||
$$ = f_print($2, 0, F_NOP);
|
||||
}
|
||||
| function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
static const char * const f_type_str[] = {
|
||||
[T_VOID] = "void",
|
||||
[T_NONE] = "none",
|
||||
|
||||
[T_OPAQUE] = "opaque byte string",
|
||||
[T_IFACE] = "interface",
|
||||
|
||||
@ -62,10 +64,12 @@ static const char * const f_type_str[] = {
|
||||
[T_PREFIX_SET] = "prefix set",
|
||||
};
|
||||
|
||||
STATIC_ASSERT((1 << (8 * sizeof(btype))) == ARRAY_SIZE(f_type_str));
|
||||
|
||||
const char *
|
||||
f_type_name(btype t)
|
||||
{
|
||||
return (t < ARRAY_SIZE(f_type_str)) ? (f_type_str[t] ?: "?") : "?";
|
||||
return f_type_str[t] ?: "?";
|
||||
}
|
||||
|
||||
btype
|
||||
|
@ -251,8 +251,9 @@ const struct adata *lclist_filter(struct linpool *pool, const struct adata *list
|
||||
|
||||
|
||||
/* Special undef value for paths and clists */
|
||||
|
||||
static inline int
|
||||
undef_value(struct f_val v)
|
||||
val_is_undefined(struct f_val v)
|
||||
{
|
||||
return ((v.type == T_PATH) || (v.type == T_CLIST) ||
|
||||
(v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
|
||||
|
@ -380,7 +380,8 @@ m4_undivert(102)m4_dnl
|
||||
[[m4_dnl The one case in The Big Switch inside interpreter
|
||||
case INST_NAME():
|
||||
#define whati (&(what->i_]]INST_NAME()[[))
|
||||
m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]])
|
||||
m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow");
|
||||
fstk->vcnt -= INST_INVAL();]])
|
||||
m4_undivert(108)m4_dnl
|
||||
#undef whati
|
||||
break;
|
||||
@ -573,8 +574,8 @@ fi_constant(struct f_inst *what, struct f_val val)
|
||||
return what;
|
||||
}
|
||||
|
||||
static int
|
||||
f_const_promotion(struct f_inst *arg, btype want)
|
||||
int
|
||||
f_const_promotion_(struct f_inst *arg, btype want, int update)
|
||||
{
|
||||
if (arg->fi_code != FI_CONSTANT)
|
||||
return 0;
|
||||
@ -582,15 +583,17 @@ f_const_promotion(struct f_inst *arg, btype want)
|
||||
struct f_val *c = &arg->i_FI_CONSTANT.val;
|
||||
|
||||
if ((c->type == T_IP) && ipa_is_ip4(c->val.ip) && (want == T_QUAD)) {
|
||||
*c = (struct f_val) {
|
||||
.type = T_QUAD,
|
||||
.val.i = ipa_to_u32(c->val.ip),
|
||||
};
|
||||
if (update)
|
||||
*c = (struct f_val) {
|
||||
.type = T_QUAD,
|
||||
.val.i = ipa_to_u32(c->val.ip),
|
||||
};
|
||||
return 1;
|
||||
}
|
||||
|
||||
else if ((c->type == T_SET) && (!c->val.t) && (want == T_PREFIX_SET)) {
|
||||
*c = f_const_empty_prefix_set;
|
||||
if (update)
|
||||
*c = f_const_empty_prefix_set;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
103
filter/f-inst.c
103
filter/f-inst.c
@ -500,7 +500,7 @@
|
||||
|
||||
INST(FI_DEFINED, 1, 1) {
|
||||
ARG_ANY(1);
|
||||
RESULT(T_BOOL, i, (v1.type != T_VOID) && !undef_value(v1));
|
||||
RESULT(T_BOOL, i, (v1.type != T_VOID) && !val_is_undefined(v1));
|
||||
}
|
||||
|
||||
METHOD_R(T_NET, type, T_ENUM_NETTYPE, i, v1.val.net->type);
|
||||
@ -1101,8 +1101,6 @@
|
||||
NEVER_CONSTANT;
|
||||
VARARG;
|
||||
SYMBOL;
|
||||
|
||||
/* Fake result type declaration */
|
||||
RESULT_TYPE(sym->function->return_type);
|
||||
|
||||
FID_NEW_BODY()
|
||||
@ -1222,22 +1220,39 @@
|
||||
}
|
||||
|
||||
/* Community list add */
|
||||
INST(FI_CLIST_ADD, 2, 1) {
|
||||
INST(FI_CLIST_ADD_PAIR, 2, 1) {
|
||||
ARG(1, T_CLIST);
|
||||
ARG_ANY(2);
|
||||
ARG(2, T_PAIR);
|
||||
METHOD_CONSTRUCTOR("add");
|
||||
struct f_val dummy;
|
||||
if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
|
||||
RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
|
||||
/* IP->Quad implicit conversion */
|
||||
else if (val_is_ip4(&v2))
|
||||
RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
|
||||
else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
|
||||
runtime("Can't add set");
|
||||
else if (v2.type == T_CLIST)
|
||||
RESULT(T_CLIST, ad, [[ int_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
|
||||
else
|
||||
runtime("Can't add non-pair");
|
||||
RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
|
||||
}
|
||||
|
||||
INST(FI_CLIST_ADD_IP, 2, 1) {
|
||||
ARG(1, T_CLIST);
|
||||
ARG(2, T_IP);
|
||||
METHOD_CONSTRUCTOR("add");
|
||||
|
||||
FID_NEW_BODY();
|
||||
/* IP->Quad implicit conversion, must be before FI_CLIST_ADD_QUAD */
|
||||
cf_warn("Method add(clist, ip) is deprecated, please use add(clist, quad)");
|
||||
|
||||
FID_INTERPRET_BODY();
|
||||
if (!val_is_ip4(&v2)) runtime("Mismatched IP type");
|
||||
RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
|
||||
}
|
||||
|
||||
INST(FI_CLIST_ADD_QUAD, 2, 1) {
|
||||
ARG(1, T_CLIST);
|
||||
ARG(2, T_QUAD);
|
||||
METHOD_CONSTRUCTOR("add");
|
||||
RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
|
||||
}
|
||||
|
||||
INST(FI_CLIST_ADD_CLIST, 2, 1) {
|
||||
ARG(1, T_CLIST);
|
||||
ARG(2, T_CLIST);
|
||||
METHOD_CONSTRUCTOR("add");
|
||||
RESULT(T_CLIST, ad, [[ int_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
|
||||
}
|
||||
|
||||
INST(FI_ECLIST_ADD_EC, 2, 1) {
|
||||
@ -1287,22 +1302,50 @@
|
||||
}
|
||||
|
||||
/* Community list delete */
|
||||
INST(FI_CLIST_DELETE, 2, 1) {
|
||||
INST(FI_CLIST_DELETE_PAIR, 2, 1) {
|
||||
ARG(1, T_CLIST);
|
||||
ARG_ANY(2);
|
||||
ARG(2, T_PAIR);
|
||||
METHOD_CONSTRUCTOR("delete");
|
||||
/* Community (or cluster) list */
|
||||
struct f_val dummy;
|
||||
RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
|
||||
}
|
||||
|
||||
if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
|
||||
RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
|
||||
/* IP->Quad implicit conversion */
|
||||
else if (val_is_ip4(&v2))
|
||||
RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
|
||||
else 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, 0) ]]);
|
||||
else
|
||||
runtime("Can't delete non-pair");
|
||||
INST(FI_CLIST_DELETE_IP, 2, 1) {
|
||||
ARG(1, T_CLIST);
|
||||
ARG(2, T_IP);
|
||||
METHOD_CONSTRUCTOR("delete");
|
||||
|
||||
FID_NEW_BODY();
|
||||
/* IP->Quad implicit conversion, must be before FI_CLIST_DELETE_QUAD */
|
||||
cf_warn("Method delete(clist, ip) is deprecated, please use delete(clist, quad)");
|
||||
|
||||
FID_INTERPRET_BODY();
|
||||
if (!val_is_ip4(&v2)) runtime("Mismatched IP type");
|
||||
RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
|
||||
}
|
||||
|
||||
INST(FI_CLIST_DELETE_QUAD, 2, 1) {
|
||||
ARG(1, T_CLIST);
|
||||
ARG(2, T_QUAD);
|
||||
METHOD_CONSTRUCTOR("delete");
|
||||
RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
|
||||
}
|
||||
|
||||
INST(FI_CLIST_DELETE_CLIST, 2, 1) {
|
||||
ARG(1, T_CLIST);
|
||||
ARG(2, T_CLIST);
|
||||
METHOD_CONSTRUCTOR("delete");
|
||||
RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 0) ]]);
|
||||
}
|
||||
|
||||
INST(FI_CLIST_DELETE_SET, 2, 1) {
|
||||
ARG(1, T_CLIST);
|
||||
ARG(2, T_SET);
|
||||
METHOD_CONSTRUCTOR("delete");
|
||||
|
||||
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, 0) ]]);
|
||||
}
|
||||
|
||||
INST(FI_ECLIST_DELETE_EC, 2, 1) {
|
||||
|
@ -36,6 +36,16 @@ const char *f_instruction_name_(enum f_instruction_code fi);
|
||||
static inline const char *f_instruction_name(enum f_instruction_code fi)
|
||||
{ return f_instruction_name_(fi) + 3; }
|
||||
|
||||
|
||||
int f_const_promotion_(struct f_inst *arg, enum btype want, int update);
|
||||
|
||||
static inline int f_const_promotion(struct f_inst *arg, enum btype want)
|
||||
{ return f_const_promotion_(arg, want, 1); }
|
||||
|
||||
static inline int f_try_const_promotion(struct f_inst *arg, enum btype want)
|
||||
{ return f_const_promotion_(arg, want, 0); }
|
||||
|
||||
|
||||
struct f_arg {
|
||||
struct symbol *arg;
|
||||
struct f_arg *next;
|
||||
@ -96,7 +106,7 @@ 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(struct symbol *sym, struct f_inst *obj, struct f_inst *args, int skip);
|
||||
struct f_inst *f_dispatch_method_x(const char *name, enum btype 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_implicit_roa_check(struct rtable_config *tab);
|
||||
|
@ -45,25 +45,100 @@ f_new_where(struct f_inst *where)
|
||||
static inline int
|
||||
f_match_signature(const struct f_method *dsc, struct f_inst *args)
|
||||
{
|
||||
uint i;
|
||||
int i, arg_num = (int) dsc->arg_num;
|
||||
|
||||
for (i = 1; args && (i < dsc->arg_num); args = args->next, i++)
|
||||
if (dsc->args_type[i] && (args->type != dsc->args_type[i]))
|
||||
for (i = 1; args && (i < arg_num); args = args->next, i++)
|
||||
if (dsc->args_type[i] && (args->type != dsc->args_type[i]) &&
|
||||
!f_try_const_promotion(args, dsc->args_type[i]))
|
||||
return 0;
|
||||
|
||||
return !args && !(i < dsc->arg_num);
|
||||
return !args && !(i < arg_num);
|
||||
}
|
||||
|
||||
/* Variant of f_match_signature(), optimized for error reporting */
|
||||
static inline void
|
||||
f_match_signature_err(const struct f_method *dsc, struct f_inst *args, int *pos, int *want, int *got)
|
||||
{
|
||||
int i, arg_num = (int) dsc->arg_num;
|
||||
|
||||
for (i = 1; args && (i < arg_num); args = args->next, i++)
|
||||
if (dsc->args_type[i] && (args->type != dsc->args_type[i]) &&
|
||||
!f_try_const_promotion(args, dsc->args_type[i]))
|
||||
break;
|
||||
|
||||
*pos = i;
|
||||
*want = (i < arg_num) ? dsc->args_type[i] : T_NONE;
|
||||
*got = args ? args->type : T_NONE;
|
||||
}
|
||||
|
||||
struct f_inst *
|
||||
f_dispatch_method(struct symbol *sym, struct f_inst *obj, struct f_inst *args)
|
||||
f_dispatch_method(struct symbol *sym, struct f_inst *obj, struct f_inst *args, int skip)
|
||||
{
|
||||
/* Note! We should revert args */
|
||||
|
||||
/* Find match */
|
||||
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);
|
||||
|
||||
/* No valid match - format error message */
|
||||
|
||||
int best_pos = -1; /* Longest argument position with partial match */
|
||||
int best_got = 0; /* Received type at best partial match position */
|
||||
int best_count = 0; /* Number of partial matches at best position */
|
||||
const int best_max = 8; /* Max number of reported types */
|
||||
int best_want[best_max]; /* Expected types at best position */
|
||||
|
||||
for (const struct f_method *dsc = sym->method; dsc; dsc = dsc->next)
|
||||
{
|
||||
int pos, want, got;
|
||||
f_match_signature_err(dsc, args, &pos, &want, &got);
|
||||
|
||||
/* Ignore shorter match */
|
||||
if (pos < best_pos)
|
||||
continue;
|
||||
|
||||
/* Found longer match, reset existing results */
|
||||
if (pos > best_pos)
|
||||
{
|
||||
best_pos = pos;
|
||||
best_got = got;
|
||||
best_count = 0;
|
||||
}
|
||||
|
||||
/* Skip duplicates */
|
||||
for (int i = 0; i < best_count; i++)
|
||||
if (best_want[i] == want)
|
||||
goto next;
|
||||
|
||||
/* Skip if we have enough types */
|
||||
if (best_count >= best_max)
|
||||
continue;
|
||||
|
||||
/* Add new expected type */
|
||||
best_want[best_count] = want;
|
||||
best_count++;
|
||||
next:;
|
||||
}
|
||||
|
||||
/* There is at least one method */
|
||||
ASSERT(best_pos >= 0 && best_count > 0);
|
||||
|
||||
/* Update best_pos for printing */
|
||||
best_pos = best_pos - skip + 1;
|
||||
|
||||
if (!best_got)
|
||||
cf_error("Cannot infer type of argument %d of '%s', please assign it to a variable", best_pos, sym->name);
|
||||
|
||||
/* Format list of expected types */
|
||||
buffer tbuf;
|
||||
STACK_BUFFER_INIT(tbuf, 128);
|
||||
for (int i = 0; i < best_count; i++)
|
||||
buffer_print(&tbuf, " / %s", best_want[i] ? f_type_name(best_want[i]) : "any");
|
||||
char *types = tbuf.start + 3;
|
||||
char *dots = (best_count >= best_max) || (tbuf.pos == tbuf.end) ? " / ..." : "";
|
||||
|
||||
cf_error("Argument %d of '%s' expected %s%s, got %s",
|
||||
best_pos, sym->name, types, dots, f_type_name(best_got));
|
||||
}
|
||||
|
||||
struct f_inst *
|
||||
@ -75,7 +150,7 @@ f_dispatch_method_x(const char *name, enum btype t, struct f_inst *obj, struct f
|
||||
if (!sym)
|
||||
cf_error("Cannot dispatch method '%s'", name);
|
||||
|
||||
return f_dispatch_method(sym, obj, args);
|
||||
return f_dispatch_method(sym, obj, args, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -87,7 +162,7 @@ f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block)
|
||||
|
||||
/* Static type check */
|
||||
if (term->type == T_VOID)
|
||||
cf_error("Couldn't infer the type of FOR expression, please assign it to a variable.");
|
||||
cf_error("Cannot infer type of FOR expression, please assign it to a variable");
|
||||
|
||||
enum btype el_type = f_type_element_type(term->type);
|
||||
struct sym_scope *scope = el_type ? f_type_method_scope(term->type) : NULL;
|
||||
@ -131,7 +206,7 @@ f_implicit_roa_check(struct rtable_config *tab)
|
||||
|
||||
return f_new_inst(FI_ROA_CHECK,
|
||||
f_new_inst(FI_RTA_GET, fsa),
|
||||
f_dispatch_method(ms, path_getter, NULL),
|
||||
ms->method->new_inst(path_getter, NULL),
|
||||
tab);
|
||||
}
|
||||
|
||||
|
@ -124,17 +124,17 @@ attribute lclist test_ca_lclist_max21;
|
||||
define one = 1;
|
||||
define ten = 10;
|
||||
|
||||
function int onef(int a)
|
||||
function onef(int a) -> int
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
function int twof(int a)
|
||||
function twof(int a) -> int
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
function int oneg(int a)
|
||||
function oneg(int a) -> int
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@ -385,7 +385,7 @@ bt_test_suite(t_bytestring, "Testing bytestrings");
|
||||
* -------------
|
||||
*/
|
||||
|
||||
function pair 'mkpair-a'(int a)
|
||||
function 'mkpair-a'(int a) -> pair
|
||||
{
|
||||
return (1, a);
|
||||
}
|
||||
@ -860,7 +860,7 @@ bt_test_suite(t_flowspec, "Testing flowspec routes");
|
||||
* -------------
|
||||
*/
|
||||
|
||||
function bgpmask mkpath(int a; int b)
|
||||
function mkpath(int a; int b) -> bgpmask
|
||||
{
|
||||
return [= a b 3 2 1 =];
|
||||
}
|
||||
@ -1121,6 +1121,12 @@ clist r;
|
||||
l = filter(l2, [(3,1..4)]);
|
||||
l2 = filter(l2, [(3,3..6)]);
|
||||
|
||||
quad q = 2.0.1.0;
|
||||
clist ql = add(add(add(-empty-, 1.0.0.1), q), 3.1.0.0);
|
||||
bt_assert(delete(ql, 1.0.0.1) = add(add(-empty-, 2.0.1.0), 3.1.0.0));
|
||||
bt_assert(delete(ql, [2.0.0.0 .. 4.0.0.0]) = add(-empty-, 1.0.0.1));
|
||||
bt_assert(filter(ql, [3.0.0.0 .. 4.0.0.0]) = add(-empty-, 3.1.0.0));
|
||||
|
||||
# clist A (10,20,30)
|
||||
bt_assert(l = add(add(add(add(-empty-, (3,1)), (3,2)), (3,3)), (3,4)));
|
||||
bt_assert(format(l) = "(clist (3,1) (3,2) (3,3) (3,4))");
|
||||
@ -1243,6 +1249,12 @@ function t_clist_new()
|
||||
l = l2.filter([(3,1..4)]);
|
||||
l2.filter([(3,3..6)]);
|
||||
|
||||
quad q = 2.0.1.0;
|
||||
clist ql = -empty-.add(1.0.0.1).add(q).add(3.1.0.0);
|
||||
bt_assert(delete(ql, 1.0.0.1) = -empty-.add(2.0.1.0).add(3.1.0.0));
|
||||
bt_assert(delete(ql, [2.0.0.0 .. 4.0.0.0]) = -empty-.add(1.0.0.1));
|
||||
bt_assert(filter(ql, [3.0.0.0 .. 4.0.0.0]) = -empty-.add(3.1.0.0));
|
||||
|
||||
# clist A (10,20,30)
|
||||
bt_assert(l = -empty-.add((3,1)).add((3,2)).add((3,3)).add((3,4)));
|
||||
bt_assert(format(l) = "(clist (3,1) (3,2) (3,3) (3,4))");
|
||||
@ -1543,7 +1555,7 @@ bt_test_suite(t_ec_set, "Testing sets of extended communities");
|
||||
* -------------------------
|
||||
*/
|
||||
|
||||
function lc mktrip(int a)
|
||||
function mktrip(int a) -> lc
|
||||
{
|
||||
return (a, 2*a, 3*a);
|
||||
}
|
||||
@ -1858,7 +1870,7 @@ bt_test_suite(t_define, "Testing defined() function");
|
||||
* -------------------------
|
||||
*/
|
||||
|
||||
function int callme(int arg1; int arg2)
|
||||
function callme(int arg1; int arg2) -> int
|
||||
int i;
|
||||
{
|
||||
case arg1 {
|
||||
@ -1869,12 +1881,12 @@ int i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function int callmeagain(int a; int b; int c)
|
||||
function callmeagain(int a; int b; int c) -> int
|
||||
{
|
||||
return a + b + c;
|
||||
}
|
||||
|
||||
function int fifteen()
|
||||
function fifteen() -> int
|
||||
{
|
||||
return 15;
|
||||
}
|
||||
@ -1907,28 +1919,28 @@ function local_vars(int j)
|
||||
bt_assert(j = 35 && k = 20 && m = 100);
|
||||
}
|
||||
|
||||
function int factorial(int x)
|
||||
function factorial(int x) -> int
|
||||
{
|
||||
if x = 0 then return 0;
|
||||
if x = 1 then return 1;
|
||||
else return x * factorial(x - 1);
|
||||
}
|
||||
|
||||
function int fibonacci(int x)
|
||||
function fibonacci(int x) -> int
|
||||
{
|
||||
if x = 0 then return 0;
|
||||
if x = 1 then return 1;
|
||||
else return fibonacci(x - 1) + fibonacci(x - 2);
|
||||
}
|
||||
|
||||
function bgppath hanoi_init(int a; int b)
|
||||
function hanoi_init(int a; int b) -> bgppath
|
||||
{
|
||||
if b = 0
|
||||
then return +empty+;
|
||||
else return prepend(hanoi_init(a + 1, b - 1), a);
|
||||
}
|
||||
|
||||
function bgppath hanoi_solve(int n; bgppath h_src; bgppath h_dst; bgppath h_aux; bool x; bool y)
|
||||
function hanoi_solve(int n; bgppath h_src; bgppath h_dst; bgppath h_aux; bool x; bool y) -> bgppath
|
||||
{
|
||||
# x -> return src or dst
|
||||
# y -> print state
|
||||
|
@ -49,6 +49,7 @@ union bval_long {
|
||||
enum btype {
|
||||
/* Nothing. Simply nothing. */
|
||||
T_VOID = 0,
|
||||
T_NONE = 0xff,
|
||||
|
||||
/* Something but inaccessible. */
|
||||
T_OPAQUE = 0x02, /* Opaque byte string (not filterable) */
|
||||
|
Loading…
Reference in New Issue
Block a user