]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
remove "auto", and allow just foreach foo (&bar) { ... }
authorAlan T. DeKok <aland@freeradius.org>
Fri, 30 Aug 2024 19:59:36 +0000 (15:59 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 30 Aug 2024 19:59:36 +0000 (15:59 -0400)
doc/antora/modules/reference/pages/unlang/foreach.adoc
src/lib/server/cf_file.c
src/lib/unlang/compile.c
src/tests/keywords/foreach-variable

index 50cd11d9d47a77362b33f6ca4e16ea2c7a0431b9..bbb9ea1b536a9268f6abbe96a55852ce7b4e6032 100644 (file)
@@ -3,7 +3,7 @@
 .Syntax
 [source,unlang]
 ----
-foreach <type> <key-name> (<attribute-reference>) {
+foreach <key-name> (<attribute-reference>) {
     [ statements ]
 }
 ----
@@ -14,16 +14,14 @@ xref:unlang/break.adoc[break] keyword.
 
 There is no limit on how many `foreach` statements can be nested.
 
-<type>::
-
-A xref:type/index.adoc[data type], or the string `auto`.
-
 <key-name>::
 
 The name of the local variable which is used as the name of key when iterating over the attributes.
 
 The local variable is created automatically when the `foreach` loop is entered, and is deleted automatically when the `foreach` loop exits.
 
+The data type of the local variable is taken from the attribute reference.
+
 The `<key-name>` can be modified during the course of the `foreach` loop.  Modifications to the variable are copied back to the referenced attribute when the loop is done.  See below for an example.
 
 The only limitation on the `<key-name>` is that it must be unique.
@@ -34,36 +32,6 @@ The xref:unlang/attr.adoc[attribute reference] which will will be looped
 over.  The reference can be to one attribute, to an array, a child, or
 be a subset of attributes.
 
-== Data type of the Key
-
-The key variable can be given an explicit data type.  This data type does not have to be the same data type as the attribute being looped over.  If the types are different, then the data is cast from the source type to the key type.
-
-The explicit data type is needed for future functionality, which will allow `foreach` to iterate over xref:xlat/index.adoc[dynamic expansions].
-
-.Example
-[source,unlang]
-----
-foreach string child (&TLV[*].Child-1) {
-    &reply += {
-        Reply-Message = "TLV contains %{child}"
-    }
-}
-----
-
-When the iterator is an attribute reference, it is simplest to use `auto` as the data type.  The `foreach` iterator will then create the local variable `<key-name>`, with the data type given by the attribute which is being looped over.
-
-In the example below, the `key` variable will have data type `octets`, as the `Class` attribute has data type `octets`.
-
-.Example of 'auto' type
-[source,unlang]
-----
-foreach auto key (&Class) {
-    &reply += {
-        Reply-Message = "Contains %{key}"
-    }
-}
-----
-
 == Modifying Loop variables
 
 An attribute which is a "leaf" data type (e.g. `uint32`, and not
@@ -77,7 +45,7 @@ the execution of the loop.
 ----
 &Tmp-Integer-0 := { 1, 3, 5, 11 }
 
-foreach uint32 self (&Tmp-Integer-0) {
+foreach self (&Tmp-Integer-0) {
        &self += 19
 }
 ----
index 2178d663b0ea96b52a40fbe850a168b465d539f4..d12c0aa07463ec6784f9092266efc0eec04d3131 100644 (file)
@@ -2045,22 +2045,29 @@ static CONF_ITEM *process_foreach(cf_stack_t *stack)
                return cf_section_to_item(css);
        }
 
-       if (strcmp(stack->buff[1], "auto") == 0) {
-               type = FR_TYPE_VOID;
+       fr_skip_whitespace(ptr);
 
-       } else {
-               type = fr_table_value_by_str(fr_type_table, stack->buff[1], FR_TYPE_NULL);
-               switch (type) {
-               default:
-                       break;
+       /*
+        *
+        */
+       if (*ptr == '(') {
+               type = FR_TYPE_NULL;
 
-               case FR_TYPE_NULL:
-               case FR_TYPE_VOID:
-               case FR_TYPE_VALUE_BOX:
-               case FR_TYPE_MAX:
-                       (void) parse_error(stack, ptr2, "Unknown or invalid variable type in 'foreach'");
-                       return NULL;
-               }
+               strcpy(stack->buff[2], stack->buff[1]);
+               goto parse_expression;
+       }
+
+       type = fr_table_value_by_str(fr_type_table, stack->buff[1], FR_TYPE_NULL);
+       switch (type) {
+       default:
+               break;
+
+       case FR_TYPE_NULL:
+       case FR_TYPE_VOID:
+       case FR_TYPE_VALUE_BOX:
+       case FR_TYPE_MAX:
+               (void) parse_error(stack, ptr2, "Unknown or invalid variable type in 'foreach'");
+               return NULL;
        }
 
        fr_skip_whitespace(ptr);
@@ -2087,6 +2094,7 @@ static CONF_ITEM *process_foreach(cf_stack_t *stack)
        /*
         *      "(" whitespace EXPRESSION whitespace ")"
         */
+parse_expression:
        ptr++;
        fr_skip_whitespace(ptr);
 
index 8d2fff0d6c5560d94aa4d54eb4874b19413a7323..b673e00e4ee6a95657d26719c3568268b6866dc9 100644 (file)
@@ -3336,10 +3336,10 @@ static unlang_t *compile_foreach(unlang_t *parent, unlang_compile_t *unlang_ctx,
                unlang_variable_t *var;
                fr_dict_attr_t const *da = tmpl_attr_tail_da(vpt);
 
-               type = fr_table_value_by_str(fr_type_table, type_name, FR_TYPE_NULL);
-               fr_assert(type != FR_TYPE_NULL);
+               type = fr_table_value_by_str(fr_type_table, type_name, FR_TYPE_VOID);
+               fr_assert(type != FR_TYPE_VOID);
 
-               if (type == FR_TYPE_VOID) type = da->type;
+               if (type == FR_TYPE_NULL) type = da->type;
 
                variable_name = cf_section_argv(cs, 1);
 
index b60d93f6476d185b605be56baa453fefdf492f9c..a9db8ea4c08a4d954c47b252c4c6f7f285d12701 100644 (file)
@@ -3,7 +3,7 @@
 #
 #  New syntax
 #
-foreach string thing ( &Filter-Id )  {
+foreach thing ( &Filter-Id )  {
        &reply += {
                &Called-Station-Id = &thing
        }