From e61cfd0d01dfebd290beb499fce6476443018c98 Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Fri, 30 Aug 2024 15:59:36 -0400 Subject: [PATCH] remove "auto", and allow just foreach foo (&bar) { ... } --- .../reference/pages/unlang/foreach.adoc | 40 ++----------------- src/lib/server/cf_file.c | 36 ++++++++++------- src/lib/unlang/compile.c | 6 +-- src/tests/keywords/foreach-variable | 2 +- 4 files changed, 30 insertions(+), 54 deletions(-) diff --git a/doc/antora/modules/reference/pages/unlang/foreach.adoc b/doc/antora/modules/reference/pages/unlang/foreach.adoc index 50cd11d9d4..bbb9ea1b53 100644 --- a/doc/antora/modules/reference/pages/unlang/foreach.adoc +++ b/doc/antora/modules/reference/pages/unlang/foreach.adoc @@ -3,7 +3,7 @@ .Syntax [source,unlang] ---- -foreach () { +foreach () { [ statements ] } ---- @@ -14,16 +14,14 @@ xref:unlang/break.adoc[break] keyword. There is no limit on how many `foreach` statements can be nested. -:: - -A xref:type/index.adoc[data type], or the string `auto`. - :: 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 `` 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 `` 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 ``, 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 } ---- diff --git a/src/lib/server/cf_file.c b/src/lib/server/cf_file.c index 2178d663b0..d12c0aa074 100644 --- a/src/lib/server/cf_file.c +++ b/src/lib/server/cf_file.c @@ -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); diff --git a/src/lib/unlang/compile.c b/src/lib/unlang/compile.c index 8d2fff0d6c..b673e00e4e 100644 --- a/src/lib/unlang/compile.c +++ b/src/lib/unlang/compile.c @@ -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); diff --git a/src/tests/keywords/foreach-variable b/src/tests/keywords/foreach-variable index b60d93f647..a9db8ea4c0 100644 --- a/src/tests/keywords/foreach-variable +++ b/src/tests/keywords/foreach-variable @@ -3,7 +3,7 @@ # # New syntax # -foreach string thing ( &Filter-Id ) { +foreach thing ( &Filter-Id ) { &reply += { &Called-Station-Id = &thing } -- 2.47.2