**** xref:unlang/edit.adoc[editing]
**** xref:unlang/else.adoc[else]
**** xref:unlang/elsif.adoc[elsif]
+**** xref:unlang/expression.adoc[expressions]
**** xref:unlang/foreach.adoc[foreach]
**** xref:unlang/group.adoc[group]
**** xref:unlang/if.adoc[if]
*** xref:unlang/condition/index.adoc[Conditional Expressions]
**** xref:unlang/condition/cmp.adoc[Comparisons]
-**** xref:unlang/expression.adoc[expressions]
+**** xref:unlang/condition/expression.adoc[mathematical expressions]
**** xref:unlang/condition/operands.adoc[Operands]
**** xref:unlang/condition/return_code.adoc[The Return Code Operator]
**** xref:unlang/condition/eq.adoc[The '==' Operator]
| !== | not equals, or they are not of the same type
| >= | greater than or equals
| > | greater than
-| xref:condition/regex.adoc[=~] | regular expression matches
-| xref:condition/regex.adoc[!~] | regular expression does not match
+| xref:unlang/condition/regex.adoc[=~] | regular expression matches
+| xref:unlang/condition/regex.adoc[!~] | regular expression does not match
|=====
The comparison operators perform _type-specific_ comparisons. The
-only exceptions are the xref:condition/regex.adoc[regular expression] operators,
+only exceptions are the xref:unlang/condition/regex.adoc[regular expression] operators,
which interpret the `lhs` as a printable string, and the `rhs` as a
regular expression.
--- /dev/null
+= Mathematical expressions.
+
+It is now possible to use xref:unlang/expression.adoc[expressions] inside of xref:unlang/condition/index.adoc[conditions].
+
+.Syntax
+[source,unlang]
+----
+if (&NAS-Port + 1 == 2 + 3) {
+ ...
+}
+----
+
+There is no longer any need to use the `%{expr:...}` expansion inside of a condition.
+
+See the main xref:unlang/expression.adoc[expressions] page for a list
+of supported operators. In short, mathematical operations will work,
+and will do what you expect.
+
+// Copyright (C) 2022 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// Development of this documentation was sponsored by Network RADIUS SAS.
= Conditional Expressions
-Conditions are evaluated when parsing xref:if.adoc[if] and
-xref:elsif.adoc[elsif] statements. These conditions allow the server to
+Conditions are evaluated when parsing xref:unlang/if.adoc[if] and
+xref:unlang/elsif.adoc[elsif] statements. These conditions allow the server to
make complex decisions based on one of a number of possible criteria.
.Syntax
[options="header"]
|=====
| Syntax | Description
-| xref:attr.adoc[&Attribute-Name] | Check for attribute existence.
-| xref:condition/return_code.adoc[rcode] | Check return code of a previous module.
-| xref:condition/operands.adoc[data] | Check value of data.
-| xref:condition/cmp.adoc[lhs OP rhs] | Compare two kinds of data.
-| xref:condition/para.adoc[( condition )] | Check sub-condition
-| xref:condition/not.adoc[! condition] | Negate a conditional check
-| xref:condition/and.adoc[( condition ) && ...] | Check a condition AND the next one
-| xref:condition/or.adoc[( condition ) \|\| ...] | Check a condition OR the next one
+| xref:unlang/attr.adoc[&Attribute-Name] | Check for attribute existence.
+| xref:unlang/return_codes.adoc[rcode] | Check return code of a previous module.
+| xref:unlang/condition/operands.adoc[data] | Check value of data.
+| xref:unlang/condition/cmp.adoc[lhs OP rhs] | Compare two kinds of data.
+| xref:unlang/condition/expression.adoc[1 + 2 ...] | Mathematical expressions.
+| xref:unlang/condition/para.adoc[( condition )] | Check sub-condition
+| xref:unlang/condition/not.adoc[! condition] | Negate a conditional check
+| xref:unlang/condition/and.adoc[( condition ) && ...] | Check a condition AND the next one
+| xref:unlang/condition/or.adoc[( condition ) \|\| ...] | Check a condition OR the next one
|=====
.Example
[source,unlang]
----
-if ( 0 == 1 ) {
+if (0) {
...
}
----
-The condition `0 == 1` is static and will evaluate to `false`. Since
+The condition `0` is static and will evaluate to `false`. Since
it evaluates to `false`, the configuration inside of the `if`
statement is ignored. Any modules referenced inside of the `if`
statement will not be loaded.
was used in version 2, then the configuration inside of the `if` statement
would be loaded, even though it would never be used.
+== Practical Suggestions
+
+We have seen many configurations where conditions are written using
+dynamic expansions and double-quoted strings for almost everything.
+For example, the following condition is unnecessarily complex:
+
+.Example with over-use of quotation
+[source,unlang]
+----
+if ("%{Framed-IP-Address}" == "192.0.2.1") {
+ ...
+}
+----
+
+This kind of condition is unnecessarily complex, and over-uses quotes.
+It should instead be written as:
+
+.Simplified Example
+[source,unlang]
+----
+if (&Framed-IP-Address == 192.0.2.1) {
+ ...
+}
+----
+
+In general, the following rules apply:
+
+* There is no need to quote attributes. `&User-Name` is almost always preferable to `%{User-Name}`.
+
+* There is no need to quote values, unless the value is a string. `192.0.2.1` is always preferable to `"192.0.2.1"`
+
+* There is no longer a need to use `%{expr:..}` to do math in conditions. `if (1 + 2 == 3)` will work. See xref:unlang/condition/expression.adoc[expressions].
+
+* If you want to check that an attribute exists _and_ has a particular value, use `if !(&Attr == value)`, instead of `if (&Attr != value)`.
+
+
// Copyright (C) 2021 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
// Development of this documentation was sponsored by Network RADIUS SAS.
----
Any text not matching xref:attr.adoc[&Attribute-Name] or
-xref:condition/return_code.adoc[Return Code] is interpreted as a value for a
+xref:unlang/condition/return_code.adoc[Return Code] is interpreted as a value for a
particular xref:type/index.adoc[data type].
Double-quoted strings and back-quoted strings are dynamically expanded
== Matching
The regular expression operators perform regular expression matching
on the data. The `<subject>` field can be an attribute reference or data,
-as with the other xref:condition/cmp.adoc[comparison] operators. The `/<pattern>/`
+as with the other xref:unlang/condition/cmp.adoc[comparison] operators. The `/<pattern>/`
field must be a valid regular expression.
The `=~` operator evaluates to `true` when `data` matches the
.Syntax
[source,unlang]
----
-if (condition-1) {
+if <condition-1> {
[ statements-1 ]
}
-elsif (condition-2) {
+elsif <condition-2> {
[ statements-2 ]
}
else {
----
An `elsif` statement is used to evaluate a subsequent
-xref:condition/index.adoc[condition] after a preceding xref:unlang/if.adoc[if] statement
-evaluates to `false`. In the example above, when _condition-1_
-evaluates to false, then _statements-1_ are skipped and _condition-2_
+xref:unlang/condition/index.adoc[condition] after a preceding xref:unlang/if.adoc[if] statement
+evaluates to `false`. In the example above, when _<condition-1>_
+evaluates to false, then _statements-1_ are skipped and _<condition-2>_
is checked. When _condition-2_ evaluates true, then _statements-2_
-are executed. When _condition-2_ evaluates false, then
+are executed. When _<condition-2>_ evaluates false, then
_statements-2_ are skipped and _statements-3_ are executed.
As with xref:unlang/if.adoc[if], an `elsif` clause does not need to be followed by
= Expressions
-Expressions can be used inside of xref:xlat/index.adoc[dynamic expansions], or inside of xref:condition/index.adoc[conditions].
+Expressions can be used inside of xref:xlat/index.adoc[dynamic expansions], or inside of xref:unlang/condition/index.adoc[conditions].
The following operators are supported (in order of precedence).
Operator precedence follows the normal rules.
Division by zero means that the entire expression is invalid.
+See the xref:unlang/edit.adoc[edit] documentation for a list of attribute editing operators.
+
== Conditions
-xref:condition/index.adoc[Conditions] in expressions are also
+xref:unlang/condition/index.adoc[Conditions] in expressions are also
supported. For example:
[source,unlang]
.Syntax
[source,unlang]
----
-if (condition) {
+if <condition> {
[ statements ]
}
----
.Description
-The `if` statement evaluates a xref:condition/index.adoc[condition]. When the
-_condition_ evaluates to `true`, the statements within the subsection
-are executed. When the _condition_ evaluates to `false`, those
+The `if` statement evaluates a xref:unlang/condition/index.adoc[condition]. When the
+_<condition>_ evaluates to `true`, the statements within the subsection
+are executed. When the _<condition>_ evaluates to `false`, those
statements are skipped.
An `if` statement can optionally be followed by an xref:unlang/else.adoc[else] or
}
----
+== Practical Suggestions
+
+There are a number of practical suggestions which make it easier to work with conditions.
+
+=== Brackets are usually optional.
+
+There is no need to put brackets around a _<condition>_. The following two examples work identically:
+
+.Example With Brackets
+[source,unlang]
+----
+if (&User-Name == "bob") {
+ reject
+}
+----
+
+And without:
+
+.Example Without Brackes
+[source,unlang]
+----
+if &User-Name == "bob" {
+ reject
+}
+----
+
+The same behavior applies to conditions with complex statements using
+`&&` and `||`. So long as the text between the `if` and the `{` is a
+valid condition, it will be parsed correctly.
+
+=== Multi-line conditions
+
+A _<condition>_ can span multiple lines. There is no need to use `\\` at the end of a line. The following condition is valid:
+
+.Example With Brackets
+[source,unlang]
+----
+if (&User-Name ==
+ "bob") {
+ reject
+}
+----
+
+=== Actions
+
The last entry in an `if` section can also be an xref:unlang/actions.adoc[actions] subsection.
// Copyright (C) 2021 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
== Conditional Expressions
-xref:condition/index.adoc[Conditional expressions], which are used to check
+xref:unlang/condition/index.adoc[Conditional expressions], which are used to check
if conditions evaluate to _true_ or _false_. Conditional expressions
can be used to control the flow of processing.
include::partial$rcode_table.adoc[]
These return codes can be used in a subsequent
-xref:condition/index.adoc[conditional expression] thus allowing policies to
+xref:unlang/condition/index.adoc[conditional expression] thus allowing policies to
perform different actions based on the behaviour of the modules.
.Example
A `switch` statement causes the server to evaluate _<expansion>_,
which can be an xref:unlang/attr.adoc[&Attribute-Name] or
-xref:condition/operands.adoc[data]. The result is compared against
+xref:unlang/condition/operands.adoc[data]. The result is compared against
_<match-1>_ and _<match-2>_, etc. in order to find a match. If no
match is found, then the server looks for the `default`
xref:unlang/case.adoc[case] statement.