]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Implement type checks for function calls
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 3 Mar 2022 02:38:12 +0000 (03:38 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Mon, 27 Jun 2022 19:13:31 +0000 (21:13 +0200)
Keep list of function parameters in f_line and use it to verify
types of arguments for function calls. Only static type checks
are implemented.

conf/confbase.Y
filter/config.Y
filter/f-inst.c
filter/f-inst.h

index 5f45c5075e576c10dd7092d237636325b2059e05..18ca8489af5ca797ecebc47ac05f70c60da8e382 100644 (file)
@@ -75,6 +75,7 @@ CF_DECLS
   struct f_static_attr fsa;
   struct f_lval flv;
   struct f_line *fl;
+  struct f_arg *fa;
   const struct filter *f;
   struct f_tree *e;
   struct f_trie *trie;
index 0ab32a579fffcb1c668317bc88e0cd3a70a684f9..a4b4d3d34cb4bbea9c765d6b01d24ae08e2ce2f0 100644 (file)
@@ -302,9 +302,10 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 %type <f> filter where_filter
 %type <fl> filter_body function_body
 %type <flv> lvalue
-%type <i> type function_args function_vars
+%type <i> type function_vars
+%type <fa> function_argsn function_args
 %type <ecs> ec_kind
-%type <fret> break_command 
+%type <fret> break_command
 %type <i32> cnum
 %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
 %type <trie> fprefix_set
@@ -403,18 +404,21 @@ type:
  ;
 
 function_argsn:
-   /* EMPTY */
+   /* EMPTY */ { $$ = NULL; }
  | function_argsn type symbol ';' {
      if ($3->scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed");
-     cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++);
+     $$ = cfg_alloc(sizeof(struct f_arg));
+     $$->arg = cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++);
+     $$->next = $1;
    }
  ;
 
 function_args:
-   '(' ')' { $$ = 0; }
+   '(' ')' { $$ = NULL; }
  | '(' function_argsn type symbol ')' {
-     cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++);
-     $$ = $4->scope->slots;
+     $$ = cfg_alloc(sizeof(struct f_arg));
+     $$->arg = cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++);
+     $$->next = $2;
    }
  ;
 
@@ -459,9 +463,21 @@ function_def:
    FUNCTION symbol { DBG( "Beginning of function %s\n", $2->name );
      $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL);
      cf_push_scope($2);
-   } function_args function_body {
-     DBG("Definition of function %s with %u args and %u local vars.\n", $2->name, $4, $5->vars);
-     $5->args = $4;
+   }  function_args function_body
+   {
+     $5->arg_list = NULL;
+     $5->args = 0;
+
+     /* Revert the args */
+     while ($4) {
+       struct f_arg *tmp = $4;
+       $4 = $4->next;
+
+       tmp->next = $5->arg_list;
+       $5->arg_list = tmp;
+       $5->args++;
+     }
+
      $2->function = $5;
      cf_pop_scope();
    }
index 0d935859c429a358b05467a8f8383649025be89c..e9bae684ec810dd2532f63a7e6a478916c9ed34f 100644 (file)
       cf_error("Function '%s' expects %u arguments, got %u arguments",
               sym->name, sym->function->args, whati->varcount);
 
+    /* Typecheck individual arguments */
+    struct f_inst *a = fvar;
+    struct f_arg *b = sym->function->arg_list;
+    for (uint i = 1; a && b; a = a->next, b = b->next, i++)
+    {
+      enum f_type b_type = b->arg->class & 0xff;
+
+      if (a->type && (a->type != b_type) && !f_const_promotion(a, b_type))
+       cf_error("Argument %u of '%s' must be %s, got %s",
+                i, sym->name, f_type_name(b_type), f_type_name(a->type));
+    }
+    ASSERT(!a && !b);
+
     /* Add implicit void slot for the return value */
     struct f_inst *tmp = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
     tmp->next = whati->fvar;
index df45f88e6ddaf1588d819269e749130615451c5c..12df40f68e5d9df33f0138e8169195770d7b7b4c 100644 (file)
@@ -35,12 +35,18 @@ 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; }
 
+struct f_arg {
+  struct symbol *arg;
+  struct f_arg *next;
+};
+
 /* Filter structures for execution */
 /* Line of instructions to be unconditionally executed one after another */
 struct f_line {
   uint len;                            /* Line length */
   u8 args;                             /* Function: Args required */
   u8 vars;
+  struct f_arg *arg_list;
   struct f_line_item items[0];         /* The items themselves */
 };