EMPTY,
FILTER, WHERE, EVAL, ATTRIBUTE,
FROM_HEX,
- BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
+ BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT, STACKS)
- CF_METHODS(IS_V4, TYPE, IP, RD, LEN, MAXLEN, ASN, SRC, DST, MASK,
- FIRST, LAST, LAST_NONAGGREGATED, DATA, DATA1, DATA2, MIN, MAX,
- EMPTY, PREPEND, ADD, DELETE, FILTER)
-
%nonassoc THEN
%nonassoc ELSE
%type <xp> cmds_int cmd_prep
- %type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor print_list 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 function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
-%type <fda> dynamic_attr
%type <fsa> static_attr
%type <f> filter where_filter
%type <fl> filter_body function_body
{ new_config->current_scope->active = 0; } term { new_config->current_scope->active = 1; }
DO cmd {
cf_pop_block_scope(new_config);
- $$ = f_new_inst(FI_FOR_INIT, $6, $3);
- $$->next = f_new_inst(FI_FOR_NEXT, $3, $9);
+ $$ = f_for_cycle($3, $6, $9);
}
- | symbol_known '=' term ';' {
+ | CF_SYM_KNOWN '=' term ';' {
switch ($1->class) {
case SYM_VARIABLE_RANGE:
$$ = f_new_inst(FI_VAR_SET, $3, $1);
cf_error( "This static attribute is read-only.");
$$ = f_new_inst(FI_RTA_SET, $3, $1);
}
- | UNSET '(' dynamic_attr ')' ';' {
- $$ = f_new_inst(FI_EA_UNSET, $3);
+ | UNSET '(' CF_SYM_KNOWN ')' ';' {
+ if ($3->class != SYM_ATTRIBUTE)
+ cf_error("Can't unset %s", $3->name);
+ if ($3->attribute->readonly)
+ cf_error("Attribute %s is read-only", $3->attribute->name);
+ $$ = f_new_inst(FI_EA_UNSET, $3->attribute);
}
- | break_command print_list ';' {
- struct f_inst *breaker = f_new_inst(FI_DIE, $1);
- if ($2) {
- struct f_inst *printer = f_new_inst(FI_PRINT, $2);
- struct f_inst *flusher = f_new_inst(FI_FLUSH);
- printer->next = flusher;
- flusher->next = breaker;
- $$ = printer;
- } else
- $$ = breaker;
+ | break_command var_list ';' {
+ $$ = f_print($2, !!$2, $1);
}
- | PRINT print_list ';' {
- $$ = f_new_inst(FI_PRINT, $2);
- $$->next = f_new_inst(FI_FLUSH);
+ | PRINT var_list ';' {
+ $$ = f_print($2, 1, F_NOP);
}
- | PRINTN print_list ';' {
- $$ = f_new_inst(FI_PRINT, $2);
+ | PRINTN var_list ';' {
+ $$ = f_print($2, 0, F_NOP);
}
| function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
| CASE term '{' switch_body '}' {
}
FID_METHOD_SCOPE_INIT()m4_dnl
-- [INST_METHOD_OBJECT_TYPE] = {},
++ [INST_METHOD_OBJECT_TYPE] = { .active = 1, },
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 = cf_root_symbol(INST_METHOD_NAME, &f_type_method_scopes[INST_METHOD_OBJECT_TYPE]);
sym->class = SYM_METHOD;
sym->method = method = lp_allocz(global_root_scope_linpool, sizeof(struct f_method));
LINE(3,0);
}
- INST(FI_PRINT, 0, 0) {
+ INST(FI_PRINT, 1, 0) {
NEVER_CONSTANT;
- VARARG;
+ ARG_ANY(1);
- if (whati->varcount && !(fs->flags & FF_SILENT))
+ if (!(fs->flags & FF_SILENT))
- val_format(&v1, &fs->buf);
+ {
+ if (!fs->buf.class)
+ log_prepare(&fs->buf, *L_INFO);
+
- for (uint i=0; i<whati->varcount; i++)
- val_format(&(vv(i)), &fs->buf.buf);
++ val_format(&v1, &fs->buf.buf);
+ }
}
INST(FI_FLUSH, 0, 0) {
INST(FI_EA_UNSET, 0, 0) {
DYNAMIC_ATTR;
ACCESS_RTE;
- ACCESS_EATTRS;
- f_rta_cow(fs);
- ea_unset_attr(fs->eattrs, fs->pool, 1, da.ea_code);
+ ea_unset_attr(&fs->rte->attrs, 1, da);
+ }
+
+ INST(FI_DEFAULT, 2, 1) {
+ ARG_ANY(1);
+ ARG_ANY(2);
+ RESULT_TYPE(f_type_element_type(v2.type));
+
+ log(L_INFO "Type of arg 1 is: %d", v1.type);
+
+ if (v1.type == T_VOID)
+ RESULT_VAL(v2);
+ else
+ RESULT_VAL(v1);
}
- INST(FI_NET_LENGTH, 1, 1) { /* Get length of */
- ARG(1, T_NET);
- METHOD_CONSTRUCTOR("len");
- RESULT(T_INT, i, net_pxlen(v1.val.net));
- }
-
- INST(FI_PATH_LENGTH, 1, 1) { /* Get length of */
- ARG(1, T_PATH);
- METHOD_CONSTRUCTOR("len");
- RESULT(T_INT, i, as_path_getlen(v1.val.ad));
- }
-
- INST(FI_CLIST_LENGTH, 1, 1) { /* Get length of */
- ARG(1, T_CLIST);
- METHOD_CONSTRUCTOR("len");
- RESULT(T_INT, i, int_set_get_size(v1.val.ad));
- }
-
- INST(FI_ECLIST_LENGTH, 1, 1) { /* Get length of */
- ARG(1, T_ECLIST);
- METHOD_CONSTRUCTOR("len");
- RESULT(T_INT, i, ec_set_get_size(v1.val.ad));
- }
-
- INST(FI_LCLIST_LENGTH, 1, 1) { /* Get length of */
- ARG(1, T_LCLIST);
- METHOD_CONSTRUCTOR("len");
- RESULT(T_INT, i, lc_set_get_size(v1.val.ad));
- }
+ /* Get length of */
+ METHOD_R(T_NET, len, 0, T_INT, i, net_pxlen(v1.val.net));
+ METHOD_R(T_PATH, len, 0, T_INT, i, as_path_getlen(v1.val.ad));
+ METHOD_R(T_CLIST, len, 0, T_INT, i, int_set_get_size(v1.val.ad));
+ METHOD_R(T_ECLIST, len, 0, T_INT, i, ec_set_get_size(v1.val.ad));
+ METHOD_R(T_LCLIST, len, 0, T_INT, i, lc_set_get_size(v1.val.ad));
INST(FI_NET_SRC, 1, 1) { /* Get src prefix */
ARG(1, T_NET);
struct filter *f_new_where(struct f_inst *);
-static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
-{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
-static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
-{ return (struct f_dynamic_attr) { .type = EAF_TYPE_BITFIELD, .bit = bit, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
-static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly)
-{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; }
+ 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);
+
+static inline struct f_static_attr f_new_static_attr(btype type, int code, int readonly)
+{ return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; }
+struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
/* Hook for call bt_assert() function in configuration */
extern void (*bt_assert_hook)(int result, const struct f_line_item *assert);
f->root = f_linearize(cond, 0);
return f;
}
- enum f_type el_type = f_type_element_type(term->type);
+
+ struct f_inst *
+ f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block)
+ {
+ ASSERT((var->class & ~0xff) == SYM_VARIABLE);
+ ASSERT(term->next == NULL);
+
+ /* Static type check */
+ if (term->type == T_VOID)
+ cf_error("Couldn't infer the type of FOR expression, please assign it to a variable.");
+
-
-
-#define CA_KEY(n) n->name, n->fda.type
-#define CA_NEXT(n) n->next
-#define CA_EQ(na,ta,nb,tb) (!strcmp(na,nb) && (ta == tb))
-#define CA_FN(n,t) (mem_hash(n, strlen(n)) ^ (t*0xaae99453U))
-#define CA_ORDER 8 /* Fixed */
-
-struct ca_storage {
- struct ca_storage *next;
- struct f_dynamic_attr fda;
- u32 uc;
- char name[0];
-};
-
-HASH(struct ca_storage) ca_hash;
-
-static struct idm ca_idm;
-static struct ca_storage **ca_storage;
-static uint ca_storage_max;
-
-static void
-ca_free(resource *r)
-{
- struct custom_attribute *ca = (void *) r;
- struct ca_storage *cas = HASH_FIND(ca_hash, CA, ca->name, ca->fda->type);
- ASSERT(cas);
-
- ca->name = NULL;
- ca->fda = NULL;
- if (!--cas->uc) {
- uint id = EA_CUSTOM_ID(cas->fda.ea_code);
- idm_free(&ca_idm, id);
- HASH_REMOVE(ca_hash, CA, cas);
- ca_storage[id] = NULL;
- mb_free(cas);
- }
-}
-
-static void
-ca_dump(resource *r)
-{
- struct custom_attribute *ca = (void *) r;
- debug("name \"%s\" id 0x%04x ea_type 0x%02x f_type 0x%02x\n",
- ca->name, ca->fda->ea_code, ca->fda->type, ca->fda->f_type);
-}
-
-static struct resclass ca_class = {
- .name = "Custom attribute",
- .size = sizeof(struct custom_attribute),
- .free = ca_free,
- .dump = ca_dump,
- .lookup = NULL,
- .memsize = NULL,
-};
-
-struct custom_attribute *
-ca_lookup(pool *p, const char *name, int f_type)
-{
- int ea_type;
-
- switch (f_type) {
- case T_INT:
- ea_type = EAF_TYPE_INT;
- break;
- case T_IP:
- ea_type = EAF_TYPE_IP_ADDRESS;
- break;
- case T_QUAD:
- ea_type = EAF_TYPE_ROUTER_ID;
- break;
- case T_PATH:
- ea_type = EAF_TYPE_AS_PATH;
- break;
- case T_CLIST:
- ea_type = EAF_TYPE_INT_SET;
- break;
- case T_ECLIST:
- ea_type = EAF_TYPE_EC_SET;
- break;
- case T_LCLIST:
- ea_type = EAF_TYPE_LC_SET;
- break;
- default:
- cf_error("Custom route attribute of unsupported type");
- }
-
- static int inited = 0;
- if (!inited) {
- idm_init(&ca_idm, config_pool, 8);
- HASH_INIT(ca_hash, config_pool, CA_ORDER);
-
- ca_storage_max = 256;
- ca_storage = mb_allocz(config_pool, sizeof(struct ca_storage *) * ca_storage_max);
-
- inited++;
- }
-
- struct ca_storage *cas = HASH_FIND(ca_hash, CA, name, ea_type);
- if (cas) {
- cas->uc++;
- } else {
-
- uint id = idm_alloc(&ca_idm);
-
- if (id >= EA_CUSTOM_BIT)
- cf_error("Too many custom attributes.");
-
- if (id >= ca_storage_max) {
- ca_storage_max *= 2;
- ca_storage = mb_realloc(ca_storage, sizeof(struct ca_storage *) * ca_storage_max * 2);
- }
-
- cas = mb_allocz(config_pool, sizeof(struct ca_storage) + strlen(name) + 1);
- cas->fda = f_new_dynamic_attr(ea_type, f_type, EA_CUSTOM(id));
- cas->uc = 1;
-
- strcpy(cas->name, name);
- ca_storage[id] = cas;
-
- HASH_INSERT(ca_hash, CA, cas);
- }
-
- struct custom_attribute *ca = ralloc(p, &ca_class);
- ca->fda = &(cas->fda);
- ca->name = cas->name;
- return ca;
-}
-
-const char *
-ea_custom_name(uint ea)
-{
- uint id = EA_CUSTOM_ID(ea);
- if (id >= ca_storage_max)
- return NULL;
-
- if (!ca_storage[id])
- return NULL;
-
- return ca_storage[id]->name;
-}
-
++ enum btype el_type = f_type_element_type(term->type);
+ struct sym_scope *scope = el_type ? f_type_method_scope(term->type) : NULL;
+ struct symbol *ms = scope ? cf_find_symbol_scope(scope, "!for_next") : NULL;
+
+ if (!ms)
+ cf_error("Type %s is not iterable, can't be used in FOR", f_type_name(term->type));
+
+ if (var->class != (SYM_VARIABLE | el_type))
+ cf_error("Loop variable '%s' in FOR must be of type %s, got %s",
+ var->name, f_type_name(el_type), f_type_name(var->class & 0xff));
+
+ /* Push the iterator auxiliary value onto stack */
+ struct f_inst *iter = term->next = f_new_inst(FI_CONSTANT, (struct f_val) {});
+
+ /* Initialize the iterator variable */
+ iter->next = f_new_inst(FI_CONSTANT, (struct f_val) { .type = el_type });
+
+ /* Prepend the loop block with loop beginning instruction */
+ struct f_inst *loop_start = f_new_inst(FI_FOR_LOOP_START, var);
+ loop_start->next = block;
+
+ return ms->method->new_inst(term, loop_start);
+ }
+
+ struct f_inst *
+ f_print(struct f_inst *vars, int flush, enum filter_return fret)
+ {
+ #define AX(...) do { struct f_inst *_tmp = f_new_inst(__VA_ARGS__); _tmp->next = output; output = _tmp; } while (0)
+ struct f_inst *output = NULL;
+ if (fret != F_NOP)
+ AX(FI_DIE, fret);
+
+ if (flush)
+ AX(FI_FLUSH);
+
+ while (vars)
+ {
+ struct f_inst *tmp = vars;
+ vars = vars->next;
+ tmp->next = NULL;
+
+ AX(FI_PRINT, tmp);
+ }
+
+ return output;
+ #undef AX
+ }
/* The same as with the value stack. Not resetting the stack for performance reasons. */
fstk->ecnt = 1;
- fstk->estk[0].line = line;
- fstk->estk[0].pos = 0;
+ fstk->estk[0] = (struct filter_exec_stack) {
+ .line = line,
+ .pos = 0,
+ };
#define curline fstk->estk[fstk->ecnt-1]
+ #define prevline fstk->estk[fstk->ecnt-2]
#ifdef LOCAL_DEBUG
debug("Interpreting line.");