Operator declarations

Operators are declared with the keyword "infix", followed by the name and a table of the XACML functions that the operator has translated. system.alfa declares operators for the standard XACML functions, so in most cases there is no need for a user to declare operators.

The following is an example for declaring 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 will be able to work on both integers and doubles. The compiler will automatically select the right XACML function depending on the argument data types.

The name of the operator must consist of the following characters: '*', '/', '%', '+', '@', '\^', '=', '\<', '>', '&', '\$', '_', '|'. In addition the operator name may begin with the minus sign '-', but the minus sign may not appear anywhere except in the first position.

There are two optional features for an operator declaration:  inverses and bag overloading.

Operator inverses

An operator may declare another operator to be its inverse. An operator inverse is another operator that has the property that by reversing the two arguments the inverse then returns the same result as the operator.

For instance, in the example above, the inverse of the "\<" operator is the ">" operator. Inverses are needed because some constructs in XACML, like the \<Match> in a target, require a particular argument order. In XACML, the constant value in the match expression always comes before the attribute designator. ALFA allows the user to use operators with its arguments in any order and if the user wrote the arguments in the reverse order of the XACML language, the ALFA compiler will change the order and replace the operator with its inverse..

Because of this, the user can write both "Attributes.age \< 40" and "40 > Attributes.age", although only the latter can be directly represented in XACML. If the user writes the former, the compiler will transparently produce the equivalent second form in the XACML output.

Some functions are commutative, that is, they always give the same result even if the order of the arguments is reversed. One example is the "==" operator. An operator is declared commutative with the "comm" modifier, as 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

XACML has two different forms of expression for writing the conditions of rules: conditions and targets. The structure of a condition is more free form, while the target requires less XML for simple matching against constant values.

In XACML a match in a target will look for a match with any value in the attribute bag. For instance, if a target contains the expression '"doctor" == Attributes.role', then the expression will be true if any of several possible values for the role attributes is "doctor". Thus, if the subject has the roles "doctor" and "employee", then the expression will be true.

In contrast, using the XACML string-equals function in a condition is more cumbersome. The function expects two atomic string values, so writing an equivalent expression in a condition would require using the any-of function: 'any-of(function[stringEquals], "doctor", Attributes.role)'.

To make this more convenient for the user, ALFA can automatically translate operators in a condition to this form. To enable this translation for an operator, use the "allowbags" modifier in the operator declaration. The less-than operator in the example above makes use of this feature.

Some operators should not do this translation--arithmetic operators, for instance. Here is an example that 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

Operator precedence is fixed in the ALFA grammar. The order is as follow, going from the operators that bind the weakest to the operators that bind the strongest.

  • Operators starting with '|'. These are right associative.
  • Operators starting with '&'. These are right associative.
  • Operators starting with '=', '<', '>' or '$'. These are left associative.
  • Operators starting with '@' or '^'. These are right associative.
  • Operators starting with '+' or '-'. These are left associative.
  • Operators starting with '*', '/' or '%'. These are left associative.

Parenthesis can be used to control the evaluation order of operators. For instance, you can write "(2+3) * 5" to perform the addition of 2 and 3 before the multiplication by 5.

Axiomatics
The Visual Studio Code extension for ALFA was developed by Axiomatics.
FOLLOW US