Skip to main content

Operator declarations

In ALFA, operators are declared using the "infix" keyword, followed by the operator name and a table of XACML functions that the operator has translated. The system.alfa file already declares operators for standard XACML functions, so typically you don't need to declare operators yourself.

For instance, the following snippet illustrates the declaration of the less-than operator:

infix allowbags (<) = {
"urn:oasis:names:tc:xacml:1.0:function:integer-less-than" : integer integer -> boolean
"urn:oasis:names:tc:xacml:1.0:function:double-less-than" : double double -> boolean

An infix operator takes two arguments and returns one value. The data types of the inputs and the outputs are declared after the XACML functions that implement the operator. For each operator there may be multiple implementing XACML functions so that the operator can be too overloaded to handle different data types. In the example above, the less-than operator is declared with implementations for both integer and double data types. The compiler automatically selects the appropriate XACML function based on the argument data types.

Operators must follow specific naming conventions, including characters such as *, /, %, +, @, ^, =, <, >, &, $, _, and |.

Important

The minus sign - is allowed only at the beginning of an operator name.

Optional features for operator declarations include inverses and bag overloading.

Operator inverses

An operator can declare another as its inverse, meaning reversing the arguments of the inverse produces the same result as the original operator. For example, the inverse of the < operator is the > operator.

Inverses are crucial because certain constructs in XACML, such as the <Match> in a target, require a specific argument order. In XACML, the constant value in the match expression always precedes the attribute designator. ALFA, on the other hand, allows you to write expressions with arguments in any order. If you arrange the arguments in the reverse order of the XACML language, the ALFA compiler automatically adjusts the order and substitutes the operator with its inverse.

This flexibility enables you to write expressions like Attributes.age < 40 and 40 > Attributes.age interchangeably. While the latter form is directly representable in XACML, the ALFA compiler will seamlessly convert the former into its equivalent form for XACML output.

Some operators, such as the == operator, are commutative, meaning their results remain the same regardless of the order of the arguments. You can declare an operator as commutative by using the comm modifier, as shown in the following example:

infix allowbags comm (==) = {
"urn:oasis:names:tc:xacml:1.0:function:string-equal" : string string -> boolean
"urn:oasis:names:tc:xacml:1.0:function:boolean-equal" : boolean boolean ->
boolean
}

Operator bag overloading

ALFA simplifies the expression of conditions within policies by enabling automatic translation of operators to handle attribute bags. This functionality is particularly useful when working with targets, which are simpler constructs for matching against constant values.

In XACML, targets can match any value within an attribute bag, while conditions require specific function calls to handle attribute bags. For instance, if you want to match the attribute role against doctor within a target, you can simply write 'doctor' == Attributes.role. However, to express the same comparison within a condition, you would need to use the any-of function: any-of(function[stringEquals], 'doctor', Attributes.role).

ALFA streamlines this process by automatically converting operators in conditions to handle attribute bags if the allowbags modifier is specified in the operator declaration. This allows you to write conditions in a more intuitive manner, similar to targets, without the need for explicit function calls.

However, some operators, such as arithmetic operators, should not be overloaded to handle bags. The following example declares the addition operator which must not be overloaded to accept bags:

infix comm (+) = {
"urn:oasis:names:tc:xacml:1.0:function:integer-add" : integer integer -> integer
"urn:oasis:names:tc:xacml:1.0:function:double-add" : double double -> double
}

Operator precedence

ALFA's grammar defines a fixed operator precedence, ensuring consistent evaluation of expressions. The order is the following, going from the operators that bind the weakest to those that bind the strongest.

OperatorPrecedence
|Right associative, meaning the right operand is evaluated first.
&Right associative, meaning the right operand is evaluated first.
=, <, > or $Left associative, implying that the left operand is evaluated first.
@ or ^Right associative, meaning the right operand is evaluated first.
+ or -.Left associative, implying that the left operand is evaluated first.
*, / or %Left associative, implying that the left operand is evaluated first.

Parentheses can be used to control the evaluation order of operators. For instance, you can write (2+3) * 5 to indicate that the addition should be performed before the multiplication.