]> git.ipfire.org Git - thirdparty/bird.git/blobdiff - filter/f-inst.c
Merge branch 'master' into mq-filter-stack
[thirdparty/bird.git] / filter / f-inst.c
index 8505534ade4a1a23fda96e0a7bf1bcc0f0d9e39d..8d5c6656f37cad1eee033e29bd21c7ef33c7305e 100644 (file)
@@ -7,47 +7,89 @@
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  *
+ *     Filter instructions. You shall define your instruction only here
+ *     and nowhere else.
+ *
+ *     Beware. This file is interpreted by M4 macros. These macros
+ *     may be more stupid than you could imagine. If something strange
+ *     happens after changing this file, compare the results before and
+ *     after your change (see the Makefile to find out where the results are)
+ *     and see what really happened.
+ *
+ *     This file is not directly a C source code -> it is a generator input
+ *     for several C sources; every instruction block gets expanded into many
+ *     different places.
+ *
+ *     All the arguments are processed literally; if you need an argument including comma,
+ *     you have to quote it by [[ ... ]]
+ *
+ *     What is the syntax here?
+ *     m4_dnl  INST(FI_NOP, in, out) {                 enum value, input args, output args
+ *     m4_dnl    ARG(num, type);                       argument, its id (in data fields) and type
+ *     m4_dnl    ARG_ANY(num);                         argument with no type check
+ *     m4_dnl    LINE(num, unused);                    this argument has to be converted to its own f_line
+ *     m4_dnl    SYMBOL;                               symbol handed from config
+ *     m4_dnl    STATIC_ATTR;                          static attribute definition
+ *     m4_dnl    DYNAMIC_ATTR;                         dynamic attribute definition
+ *     m4_dnl    RTC;                                  route table config
+ *     m4_dnl    ACCESS_RTE;                           this instruction needs route
+ *     m4_dnl    ACCESS_EATTRS;                        this instruction needs extended attributes
+ *
+ *     m4_dnl    FID_MEMBER(                           custom instruction member
+ *     m4_dnl      C type,                             for storage in structs
+ *     m4_dnl      name,                               how the member is named
+ *     m4_dnl      comparator for same(),              if different, this should be TRUE (CAVEAT)
+ *     m4_dnl      dump format string                  debug -> format string for bvsnprintf
+ *     m4_dnl      dump format args                    appropriate args
+ *     m4_dnl    )
+ *
+ *     m4_dnl    RESULT(type, union-field, value);     putting this on value stack
+ *     m4_dnl    RESULT_VAL(value-struct);             pass the struct f_val directly
+ *     m4_dnl    RESULT_VOID;                          return undef
+ *     m4_dnl  }
+ *
+ *     Other code is just copied into the interpreter part.
+ *
+ *     If you want to write something really special, see FI_CALL
+ *     or FI_CONSTANT or whatever else to see how to use the FID_*
+ *     macros.
  */
 
 /* Binary operators */
   INST(FI_ADD, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
-    res.val.i += v2.val.i;
-    RESULT_OK;
+    RESULT(T_INT, i, v1.val.i + v2.val.i);
   }
   INST(FI_SUBTRACT, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
-    res.val.i -= v2.val.i;
-    RESULT_OK;
+    RESULT(T_INT, i, v1.val.i - v2.val.i);
   }
   INST(FI_MULTIPLY, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
-    res.val.i *= v2.val.i;
-    RESULT_OK;
+    RESULT(T_INT, i, v1.val.i * v2.val.i);
   }
   INST(FI_DIVIDE, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
     if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
-    res.val.i /= v2.val.i;
-    RESULT_OK;
+    RESULT(T_INT, i, v1.val.i / v2.val.i);
   }
   INST(FI_AND, 1, 1) {
     ARG(1,T_BOOL);
-    if (res.val.i)
+    if (v1.val.i)
       LINE(2,0);
     else
-      RESULT_OK;
+      RESULT_VAL(v1);
   }
   INST(FI_OR, 1, 1) {
     ARG(1,T_BOOL);
-    if (!res.val.i)
+    if (!v1.val.i)
       LINE(2,0);
     else
-      RESULT_OK;
+      RESULT_VAL(v1);
   }
   INST(FI_PAIR_CONSTRUCT, 2, 1) {
     ARG(1,T_INT);
   INST(FI_EC_CONSTRUCT, 2, 1) {
     ARG_ANY(1);
     ARG(2, T_INT);
-    ECS;
+
+    FID_MEMBER(enum ec_subtype, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs));
 
     int check, ipv4_used;
     u32 key, val;
 
   INST(FI_PATHMASK_CONSTRUCT, 0, 1) {
     ARG_ANY(1);
-    COUNT(2);
+    FID_MEMBER(uint, count, f1->count != f2->count, number of items %u, item->count);
 
     FID_NEW_BODY
       uint len = 0;
-      uint dyn = 0;
-      for (const struct f_inst *tt = f1; tt; tt = tt->next, len++)
-       if (tt->fi_code != FI_CONSTANT)
-         dyn++;
-
-      what->count = len;
-    FID_ALL
+      for (const struct f_inst *tt = f1; tt; tt = tt->next, len++);
+
+      whati->count = len;
+      struct f_inst **items;
+      if (constargs) {
+       items = alloca(len * sizeof(struct f_inst *));
+       for (uint i=0; f1; i++) {
+         items[i] = f1;
+         f1 = f1->next;
+         items[i]->next = 0;
+       }
+       whati->f1 = NULL;
+      }
+    FID_INTERPRET_BODY
 
-    if (vstk.cnt < whati->count) /* TODO: make this check systematic */
+    FID_INTERPRET_EXEC
+    if (fstk->vcnt < whati->count) /* TODO: make this check systematic */
       runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count);
 
-    struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item));
+#define pv fstk->vstk[fstk->vcnt - whati->count + i]
+
+    FID_INTERPRET_NEW
+#define pv items[i]->i_FI_CONSTANT.val
+
+    FID_INTERPRET_BODY
+    struct f_path_mask *pm = falloc(sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item));
     for (uint i=0; i<whati->count; i++) {
-#define pv vstk.val[vstk.cnt - whati->count + i]
       switch (pv.type) {
        case T_PATH_MASK_ITEM:
          pm->item[i] = pv.val.pmi;
       }
     }
 
-    vstk.cnt -= whati->count;
-    pm->len = whati->count;
+    FID_INTERPRET_EXEC
+      fstk->vcnt -= whati->count;
+    FID_INTERPRET_BODY
 
+    pm->len = whati->count;
     RESULT(T_PATH_MASK, path_mask, pm);
   }
 
     ARG_ANY(1);
     ARG_ANY(2);
     int i = val_in_range(&v1, &v2);
-    if (res.val.i == F_CMP_ERROR)
+    if (i == F_CMP_ERROR)
       runtime( "!~ applied on unknown type pair" );
     RESULT(T_BOOL, i, !i);
   }
   }
 
   /* Set to indirect value prepared in v1 */
-  INST(FI_SET, 1, 0) {
-    ARG_ANY(2);
-    SYMBOL(1);
+  INST(FI_VAR_SET, 1, 0) {
+    NEVER_CONSTANT;
+    ARG_ANY(1);
+    SYMBOL;
+
     if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID))
     {
       /* IP->Quad implicit conversion */
       if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1))
-      {
-       *(sym->val) = (struct f_val) {
+       v1 = (struct f_val) {
          .type = T_QUAD,
          .val.i = ipa_to_u32(v1.val.ip),
-       }; 
-       break;
-      }
-      runtime( "Assigning to variable of incompatible type" );
+       };
+      else 
+       runtime( "Assigning to variable of incompatible type" );
     }
-    *(sym->val) = v1;
-  }
 
-    /* some constants have value in a[1], some in *a[0].p, strange. */
-  INST(FI_CONSTANT, 0, 1) {    /* integer (or simple type) constant, string, set, or prefix_set */
-    FID_LINE_IN
-      struct f_val val;
-    FID_STRUCT_IN
-      struct f_val val;
-    FID_NEW_ARGS
-    , const struct f_val val
-    FID_NEW_BODY
-      what->val = val;
-    FID_POSTFIXIFY_BODY
-      item->val = what->val;
-    FID_SAME_BODY
-      if (!val_same(&(f1->val), &(f2->val))) return 0;
-    FID_DUMP_BODY
-      debug("%svalue %s\n", INDENT, val_dump(&item->val));
-    FID_ALL
-
-    res = whati->val;
-    RESULT_OK;
+    fstk->vstk[curline.vbase + sym->offset] = v1;
   }
-  INST(FI_VARIABLE, 0, 1) {
-    FID_STRUCT_IN
-      const struct symbol *sym;
-    FID_LINE_IN
-      const struct symbol *sym;
-      const struct f_val *valp;
-    FID_NEW_ARGS
-      , const struct symbol *sym
-    FID_NEW_BODY
-      what->sym = sym;
-    FID_POSTFIXIFY_BODY
-      item->valp = (item->sym = what->sym)->val;
-    FID_SAME_BODY
-      if (strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)) return 0;
-    FID_DUMP_BODY
-      switch (item->sym->class) {
-       case SYM_CONSTANT_RANGE:
-         debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp));
-         break;
-       case SYM_VARIABLE_RANGE:
-         debug("%svariable %s with current value %s\n", INDENT, item->sym->name, val_dump(item->valp));
-         break;
-       default:
-         bug("Symbol %s of type %d doesn't reference a value", item->sym->name, item->sym->class);
-      }
-    FID_ALL
 
-    res = *whati->valp;
-    RESULT_OK;
+  INST(FI_VAR_GET, 0, 1) {
+    SYMBOL;
+    NEVER_CONSTANT;
+    RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]);
   }
-  INST(FI_PRINT, 1, 0) {
-    ARG_ANY(1);
-    val_format(&(v1), &fs->buf);
+
+    /* some constants have value in a[1], some in *a[0].p, strange. */
+  INST(FI_CONSTANT, 0, 1) {    /* integer (or simple type) constant, string, set, or prefix_set */
+    FID_MEMBER(
+      struct f_val,
+      val,
+      [[ !val_same(&(f1->val), &(f2->val)) ]],
+      value %s,
+      val_dump(&(item->val))
+    );
+
+    RESULT_VAL(val);
   }
   INST(FI_CONDITION, 1, 0) {
     ARG(1, T_BOOL);
-    if (res.val.i)
+    if (v1.val.i)
       LINE(2,0);
     else
       LINE(3,1);
   }
-  INST(FI_PRINT_AND_DIE, 0, 0) {
-    FID_POSTFIXIFY_BODY
-    {
-      uint opos = pos;
-      FID_ALL
 
+  INST(FI_PRINT, 0, 0) {
+    NEVER_CONSTANT;
     ARG_ANY(1);
+    FID_MEMBER_IN(uint, count, f1->count != f2->count, number of items %u, item->count);
 
-      FID_POSTFIXIFY_BODY
-      if (opos < pos)
-       dest->items[pos].flags |= FIF_PRINTED;
-    }
-    FID_ALL
+    FID_NEW_BODY
+      uint len = 0;
+      for (const struct f_inst *tt = f1; tt; tt = tt->next, len++)
+       ;
+      whati->count = len;
 
-    FRET(2);
+    FID_INTERPRET_BODY
 
-    if ((fret == F_NOP || (fret != F_NONL && (what->flags & FIF_PRINTED))) &&
-       !(fs->flags & FF_SILENT))
+#define pv fstk->vstk[fstk->vcnt - whati->count + i]
+    if (whati->count)
+      for (uint i=0; i<whati->count; i++)
+       val_format(&(pv), &fs->buf);
+#undef pv
+
+    fstk->vcnt -= whati->count;
+  }
+
+  INST(FI_DIE, 0, 0) {
+    NEVER_CONSTANT;
+    FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret));
+
+    if (fs->buf.start < fs->buf.pos)
       log_commit(*L_INFO, &fs->buf);
 
-    switch (fret) {
+    switch (whati->fret) {
     case F_QUITBIRD:
       die( "Filter asked me to die" );
     case F_ACCEPT:
     case F_ERROR:
     case F_REJECT:     /* FIXME (noncritical) Should print complete route along with reason to reject route */
       return fret;     /* We have to return now, no more processing. */
-    case F_NONL:
     case F_NOP:
       break;
     default:
        }
 
        /* Undefined value */
-       res.type = T_VOID;
-       RESULT_OK;
+       RESULT_VOID;
        break;
       }
 
        RESULT(T_LCLIST, ad, e->u.ptr);
        break;
       case EAF_TYPE_UNDEF:
-       res.type = T_VOID;
-       RESULT_OK;
+       RESULT_VOID;
        break;
       default:
        bug("Unknown dynamic attribute type");
       l->count = 1;
       l->attrs[0].id = da.ea_code;
       l->attrs[0].flags = 0;
-      l->attrs[0].type = EAF_TYPE_UNDEF | EAF_TEMP | EAF_ORIGINATED | EAF_FRESH;
+      l->attrs[0].type = EAF_TYPE_UNDEF | EAF_ORIGINATED | EAF_FRESH;
       l->attrs[0].u.data = 0;
 
       f_rta_cow(fs);
       runtime( "SADR expected" );
 
     net_addr_ip6_sadr *net = (void *) v1.val.net;
-    net_addr *src = lp_alloc(fs->pool, sizeof(net_addr_ip6));
+    net_addr *src = falloc(sizeof(net_addr_ip6));
     net_fill_ip6(src, net->src_prefix, net->src_pxlen);
 
     RESULT(T_NET, net, src);
   }
 
   INST(FI_RETURN, 1, 1) {
+    NEVER_CONSTANT;
     /* Acquire the return value */
     ARG_ANY(1);
-    uint retpos = vstk.cnt;
+    uint retpos = fstk->vcnt;
 
     /* Drop every sub-block including ourselves */
-    while ((estk.cnt-- > 0) && !(estk.item[estk.cnt].emask & FE_RETURN))
+    while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN))
       ;
 
     /* Now we are at the caller frame; if no such, try to convert to accept/reject. */
-    if (!estk.cnt)
-      if (vstk.val[retpos].type == T_BOOL)
-       if (vstk.val[retpos].val.i)
+    if (!fstk->ecnt)
+      if (fstk->vstk[retpos].type == T_BOOL)
+       if (fstk->vstk[retpos].val.i)
 
          return F_ACCEPT;
        else
       else
        runtime("Can't return non-bool from non-function");
 
-    /* Set the value stack position */
-    vstk.cnt = estk.item[estk.cnt].ventry;
+    /* Set the value stack position, overwriting the former implicit void */
+    fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1;
 
     /* Copy the return value */
-    RESULT_VAL(vstk.val[retpos]);
+    RESULT_VAL(fstk->vstk[retpos]);
   }
 
   INST(FI_CALL, 0, 1) {
-    FID_LINE_IN
-      const struct f_line *args;
-      const struct f_line *body;
-      struct symbol *sym;
-    FID_STRUCT_IN
-      struct symbol *sym;
-      const struct f_inst *args;
-    FID_NEW_ARGS
-      , struct symbol * sym
-      , const struct f_inst *args
-    FID_NEW_BODY
-      if (sym->class != SYM_FUNCTION)
-       cf_error("You can't call something which is not a function. Really.");
-
-      uint count = 0;
-      for (const struct f_inst *inst = args; inst; inst = inst->next)
-       count++;
-
-      if (count != sym->function->args)
-       cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->function->args, count);
-
-      what->sym = sym;
-      what->args = args;
-    FID_DUMP_BODY
-      debug("%scalling %s with following args\n", INDENT, item->sym->name);
-      f_dump_line(item->args, indent + 1);
-    FID_POSTFIXIFY_BODY
-      item->args = f_postfixify(what->args);
-      item->body = (item->sym = what->sym)->function;
-    FID_SAME_BODY
-      /* To be done better */
-      if (strcmp(f1->sym->name, f2->sym->name)) return 0;
-      if (!f_same(f1->args, f2->args)) return 0;
-      if (!f_same(f1->body, f2->body)) return 0;
-    FID_ALL
-
-    /* First push the body on stack */
-    LINEX(whati->body);
-    curline.emask |= FE_RETURN;
+    NEVER_CONSTANT;
+    SYMBOL;
 
-    /* Then push the arguments */
-    LINEX(whati->args);
+    /* Push the body on stack */
+    LINEX(sym->function);
+    curline.emask |= FE_RETURN;
+  
+    /* Before this instruction was called, there was the T_VOID
+     * automatic return value pushed on value stack and also
+     * sym->function->args function arguments. Setting the
+     * vbase to point to first argument. */
+    ASSERT(curline.ventry >= sym->function->args);
+    curline.ventry -= sym->function->args;
+    curline.vbase = curline.ventry;
+
+    /* Storage for local variables */
+    memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars);
+    fstk->vcnt += sym->function->vars;
   }
 
   INST(FI_DROP_RESULT, 1, 0) {
+    NEVER_CONSTANT;
     ARG_ANY(1);
   }
 
   INST(FI_SWITCH, 1, 0) {
     ARG_ANY(1);
-    TREE;
+
+    FID_MEMBER(struct f_tree *, tree, [[!same_tree(f1->tree, f2->tree)]], tree %p, item->tree);
+
     const struct f_tree *t = find_tree(tree, &v1);
     if (!t) {
       v1.type = T_VOID;
       t = find_tree(tree, &v1);
       if (!t) {
        debug( "No else statement?\n");
-       break;
+       FID_HIC(,break,return NULL);
       }
     }
     /* It is actually possible to have t->data NULL */
   INST(FI_PATH_PREPEND, 2, 1) {        /* Path prepend */
     ARG(1, T_PATH);
     ARG(2, T_INT);
-    RESULT(T_PATH, ad, [[ as_path_prepend(fs->pool, v1.val.ad, v2.val.i) ]]);
+    RESULT(T_PATH, ad, [[ as_path_prepend(fpool, v1.val.ad, v2.val.i) ]]);
   }
 
   INST(FI_CLIST_ADD, 2, 1) {   /* (Extended) Community list add */
       struct f_val dummy;
 
       if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
-       RESULT(T_CLIST, ad, [[ int_set_add(fs->pool, v1.val.ad, v2.val.i) ]]);
+       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(fs->pool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
+       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(fs->pool, v1.val.ad, v2.val.ad) ]]);
+       RESULT(T_CLIST, ad, [[ int_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
       else
        runtime("Can't add non-pair");
     }
       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(fs->pool, v1.val.ad, v2.val.ad) ]]);
+       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(fs->pool, v1.val.ad, v2.val.ec) ]]);
+       RESULT(T_ECLIST, ad, [[ ec_set_add(fpool, v1.val.ad, v2.val.ec) ]]);
     }
 
     else if (v1.type == T_LCLIST)
       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(fs->pool, v1.val.ad, v2.val.ad) ]]);
+       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(fs->pool, v1.val.ad, v2.val.lc) ]]);
+       RESULT(T_LCLIST, ad, [[ lc_set_add(fpool, v1.val.ad, v2.val.lc) ]]);
 
     }
 
       else
        runtime("Can't delete non-integer (set)");
 
-      RESULT(T_PATH, ad, [[ as_path_filter(fs->pool, v1.val.ad, set, key, 0) ]]);
+      RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, set, key, 0) ]]);
     }
 
     else if (v1.type == T_CLIST)
       struct f_val dummy;
 
       if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
-       RESULT(T_CLIST, ad, [[ int_set_del(fs->pool, v1.val.ad, v2.val.i) ]]);
+       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(fs->pool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
+       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(fs->pool, v1.val.ad, &v2, 0) ]]);
+       RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 0) ]]);
       else
        runtime("Can't delete non-pair");
     }
     {
       /* 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(fs->pool, v1.val.ad, &v2, 0) ]]);
+       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(fs->pool, v1.val.ad, v2.val.ec) ]]);
+       RESULT(T_ECLIST, ad, [[ ec_set_del(fpool, v1.val.ad, v2.val.ec) ]]);
     }
 
     else if (v1.type == T_LCLIST)
     {
       /* 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(fs->pool, v1.val.ad, &v2, 0) ]]);
+       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(fs->pool, v1.val.ad, v2.val.lc) ]]);
+       RESULT(T_LCLIST, ad, [[ lc_set_del(fpool, v1.val.ad, v2.val.lc) ]]);
     }
 
     else
       u32 key = 0;
 
       if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
-       RESULT(T_PATH, ad, [[ as_path_filter(fs->pool, v1.val.ad, v2.val.t, key, 1) ]]);
+       RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, v2.val.t, key, 1) ]]);
       else
        runtime("Can't filter integer");
     }
       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(fs->pool, v1.val.ad, &v2, 1) ]]);
+       RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]);
       else
        runtime("Can't filter pair");
     }
     {
       /* 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(fs->pool, v1.val.ad, &v2, 1) ]]);
+       RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
       else
        runtime("Can't filter ec");
     }
     {
       /* 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(fs->pool, v1.val.ad, &v2, 1) ]]);
+       RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
       else
        runtime("Can't filter lc");
     }
   }
 
   INST(FI_ROA_CHECK_IMPLICIT, 0, 1) {  /* ROA Check */
+    NEVER_CONSTANT;
     RTC(1);
+    struct rtable *table = rtc->table;
     ACCESS_RTE;
     ACCESS_EATTRS;
     const net_addr *net = (*fs->rte)->net->n.addr;
   }
 
   INST(FI_ROA_CHECK_EXPLICIT, 2, 1) {  /* ROA Check */
+    NEVER_CONSTANT;
     ARG(1, T_NET);
     ARG(2, T_INT);
     RTC(3);
+    struct rtable *table = rtc->table;
 
     u32 as = v2.val.i;
 
 
   INST(FI_FORMAT, 1, 0) {      /* Format */
     ARG_ANY(1);
-    RESULT(T_STRING, s, val_format_str(fs, &v1));
+    RESULT(T_STRING, s, val_format_str(fpool, &v1));
   }
 
   INST(FI_ASSERT, 1, 0) {      /* Birdtest Assert */
+    NEVER_CONSTANT;
     ARG(1, T_BOOL);
-    STRING;
+
+    FID_MEMBER(char *, s, [[strcmp(f1->s, f2->s)]], string %s, item->s);
+
+    ASSERT(s);
+
     if (!bt_assert_hook)
       runtime("No bt_assert hook registered, can't assert");
 
-    bt_assert_hook(res.val.i, what);
+    bt_assert_hook(v1.val.i, what);
   }