]> git.ipfire.org Git - thirdparty/bird.git/blobdiff - filter/config.Y
Filter: Implement type checks for function calls
[thirdparty/bird.git] / filter / config.Y
index 5cd52e40e4411d0236f430d8fcd525726b5f1aa3..a4b4d3d34cb4bbea9c765d6b01d24ae08e2ce2f0 100644 (file)
@@ -278,14 +278,16 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
        IF, THEN, ELSE, CASE,
        TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
-       FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT,
+       FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS,
        PREFERENCE,
        ROA_CHECK, ASN, SRC, DST,
        IS_V4, IS_V6,
        LEN, MAXLEN,
+       DATA, DATA1, DATA2,
        DEFINED,
        ADD, DELETE, CONTAINS, RESET,
        PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
+       MIN, MAX,
        EMPTY,
        FILTER, WHERE, EVAL, ATTRIBUTE,
        BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
@@ -300,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
@@ -401,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;
    }
  ;
 
@@ -457,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();
    }
@@ -698,27 +716,22 @@ var_list: /* EMPTY */ { $$ = NULL; }
  | var_list ',' term { $$ = $3; $$->next = $1; }
 
 function_call:
-   CF_SYM_KNOWN '(' var_list ')' {
+   CF_SYM_KNOWN '(' var_list ')'
+   {
      if ($1->class != SYM_FUNCTION)
        cf_error("You can't call something which is not a function. Really.");
 
-     struct f_inst *fc = f_new_inst(FI_CALL, $1);
-     uint args = 0;
+     /* Revert the var_list */
+     struct f_inst *args = NULL;
      while ($3) {
-       args++;
-       struct f_inst *tmp = $3->next;
-       $3->next = fc;
+       struct f_inst *tmp = $3;
+       $3 = $3->next;
 
-       fc = $3;
-       $3 = tmp;
+       tmp->next = args;
+       args = tmp;
      }
 
-     if (args != $1->function->args)
-       cf_error("Function call '%s' got %u arguments, need %u arguments.",
-          $1->name, args, $1->function->args);
-
-     $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
-     $$->next = fc;
+     $$ = f_new_inst(FI_CALL, args, $1);
    }
  ;
 
@@ -751,6 +764,7 @@ static_attr:
  | IFNAME  { $$ = f_new_static_attr(T_STRING,     SA_IFNAME,   0); }
  | IFINDEX { $$ = f_new_static_attr(T_INT,        SA_IFINDEX,  1); }
  | WEIGHT  { $$ = f_new_static_attr(T_INT,        SA_WEIGHT,   0); }
+ | GW_MPLS { $$ = f_new_static_attr(T_INT,        SA_GW_MPLS,  0); }
  ;
 
 term:
@@ -788,13 +802,18 @@ term:
  | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
  | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
  | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
- | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
+ | term '.' ASN { $$ = f_new_inst(FI_ASN, $1); }
  | term '.' SRC { $$ = f_new_inst(FI_NET_SRC, $1); }
  | term '.' DST { $$ = f_new_inst(FI_NET_DST, $1); }
  | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
  | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
  | term '.' LAST  { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
  | term '.' LAST_NONAGGREGATED  { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
+ | term '.' DATA { $$ = f_new_inst(FI_PAIR_DATA, $1); }
+ | term '.' DATA1 { $$ = f_new_inst(FI_LC_DATA1, $1); }
+ | term '.' DATA2 { $$ = f_new_inst(FI_LC_DATA2, $1); }
+ | term '.' MIN  { $$ = f_new_inst(FI_MIN, $1); }
+ | term '.' MAX  { $$ = f_new_inst(FI_MAX, $1); }
 
 /* Communities */
 /* This causes one shift/reduce conflict