4.1. Expression Language¶
Contenuti
4.1.1. Basics¶
4.1.1.1. Supported values types¶
The language supports many value types. Values can be stored inside variables, used in expressions, passed to/returned by functions, ecc.
Some values have no literal rappresentation in the language. This means that you can create/use them (es: as a function return value), but you can not rappresent them as a sequence of character in the expression string).
Base values
Types
Description
Literal rappresentation
Example
numbers
intergers and floats values
number literal
123
booleans
true or false values
boolean literal
True , False
characters
A single unicode point
string literal (ascii characters & escaped)
"w" "n" "xa0"
strings
Sequence of unicode code points.
string literal (ascii characters & escaped)
"world", 'world'
byte strings
Sequence of 8-bit values.
bytes
8-bit values
Special values used when working with SNMP protocol.
Types
Description
Literal rappresentation
Example
OIDs
OID strings (1.3.6.1.2.1.1)
OID literal
1.3.6.1.2.1.1.1
Data structures
Types
Description
Literal rappresentation
Example
arrays
Sequence of other values
[ .... ]
[ 'a', 3.14, "foo" ]
dictionaries
Mapping objects
objects
Objects (with fields and methods)
Objects
TODO
4.1.1.2. Unicode String and Byte strings (arrays)¶
byte strings consists of sequences of 8-bit unsigned values, while unicode strings consists of sequences of Unicode code points that represent textual characters from human languages.
Examples of byte strings:
b'hello' b'Intel Corporation 82540EM Gigabit Ethernet Controller' b'Citt\xc3\xa0' b'Citt\xe0'
Examples of unicode strings:
'hello' 'Intel Corporation 82540EM Gigabit Ethernet Controller' 'Città'
Note
In Sanet, a byte string cannot be written as literal but can be obtained as result of a OID or a function.
4.1.1.2.1. Conversions¶
To obtain unicode strings from byte strings you have to decode them using the appropriate encoding.
b'hello' --> decode ascii --> 'hello' b'Citt\xc3\xa0' --> decode utf-8 --> 'Città' b'Citt\xe0' --> decode iso-8859-1 --> 'Città'
To obtain byte strings from unicode strings you have to encode them using the appropriate encoding.
'hello' --> encode ascii --> b'hello' 'Città' --> encode utf-8 --> b'Citt\xc3\xa0' 'Città' --> encode iso-8859-1 --> b'Citt\xe0'
See encode for more details about encode and decode functions.
4.1.1.2.2. Comparisons¶
Between byte strings
You can compare and use operators like > and + between byte strings but if the byte strings have different encoding maybe you are doing it wrong.
For example, compare with == these 2 byte strings: b'Cittxc3xa0' b'Cittxe0' it probably does not make sense because it will return False even if they both have the same unicode strings representation (if decoded with utf-8 and iso-8859-1 respectively).
b'hello' == b'hello' --> True b'Citt\xc3\xa0' == b'Citt\xc3\xa0' --> True b'Citt\xc3\xa0' == b'Citt\xe0' --> False
Between byte strings and unicode strings
In Sanet, byte strings and unicode strings can be used together with operators like >, + or == but with some limitations.
To safetly compare a byte string with a unicode string, Sanet assume that the unicode string is a ascii string. If the unicode string isn't a ascii string and exception will be raised.
To compare a byte string with a unicode string which is not a ascii string you must either explicitly decode the byte string or explicitly encoding the unicode string.
b'hello == 'hello' --> True b'Citt\xc3\xa0' == 'Città' --> ERROR: Operation not allowed between bytes (b'Citt\xc3\xa0') and non-ascii unicode string ('Città'). decode(b'Citt\xc3\xa0', 'utf-8') == 'Città' --> True b'Citt\xc3\xa0' == encode('Città', 'utf-8) --> True
4.1.1.2.3. Functions¶
In Sanet, byte strings and unicode strings can be used together in functions with backward compatibility, where possible. In that case 'ascii' or 'utf-8' encode could be used as default.
4.1.1.3. Language Literals¶
4.1.1.3.1. Numbers¶
Numbers can be expressed as:
Integer values
Sequence of decimal characters starting with a decimal.
Examples:
expression
value
1
1
-1982
-1982
Floating point values
They follow the following sintax:
integer part . decimal part [ (e | E) ( - | + ) exponent ]
Examples:
expression
value
1.0
1.0
3.14
3.14
4.0e+10
40000000000.0
1.0E-3
0.0001
Hexadecimals values
Sequence of hexadecimal characaters with the prefix 0x.
Examples:
expression
value
0x1
1
0xff
255
0xFF
255
0x80000
32768
Octal values
Sequence of octal characters startring with 0.
Examples:
expression
value
01
1
07
7
010
8
011
9
4.1.1.3.2. Booleans¶
Booleans values can be true or false. These values are represented by the constants: True or False.
Example:
Expression
Value
True
true
False
false
4.1.1.3.3. Strings¶
A string is a sequence of characters delimited by single quotes or double quotes:
'a', 'b', 'c'
"a", "b", "c"
"foo", 'bar'
"Hello world"
Character escaping
Few special characters can be inserted into a string by prepending the escape character *.
Escape sequence
Character
Description
\t
tab
\b
Back Space
\n
new line
\f
line feed
\r
Carriage Return
\"
"
double quote
\'
'
single quote
\ \
\
backslash
You can use escaped characters inside strings delimited by single (')or double quotes (").
Examples
Input string
Value
"Hello\nWorld"
Hello World
"Hello 'World'"
Hello 'World'
'Hello "World"'
Hello "World"
'Hello \'World\' '
Hello 'World'
"Hello \"World\""
Hello "World"
4.1.1.3.3.1. Disable string escaping¶
It is possible to disable string escaping by prepending the prefix r to any string.
r " ... "
r ' ... '
Examples
Input string
Value
Description
"Hello\nWorld"
Hello World
"Hello\\World"
Hello\World
"Hello\"World"
Hello"World
r"Hello\nWorld"
Hello\nWorld
unescaped
r"Hello\\nWorld"
Hello\\nWorld
unescaped
r"Hello\"nWorld"
Hello\"World
unescaped
4.1.1.3.4. OIDs¶
When speaking about SNMP, OIDs (or Object Identifiers) uniquely identify managed objects in a MIB hierarchy.
They are expressed with a sequence of at least three decimal strings separated by a dot ".".
IMPORTANT: An OID are a special kind of literal and can be used only inside SNMP sub-expression. You can not use OID literals inside mathematical expressions or comparisons.
Examples:
Expression
1.2.3
1.3.6.1.2.1.1.1.18.241
4.1.1.4. Vectors¶
Vectors are sequence values.
[ val1 [ , ... ] ]
Examples:
[]
[ 1, 2, 3, 4, "foo" ][ 1.3.6.1.2.1.1.1.0@ , 1.3.6.1.2.1.1.2.0@ ]
Functions and variables can be used to handle vectors and the sintax to access vector elements is:
expression [ n ]
Example:
[ 1, 2, 3, 'a', "foo", ][4] -> "foo""hello world"[6] -> 'w'my_function_returns_a_vector()[1] --> second value of the returned vector
Note
Strings are vectors or characters.
4.1.1.5. Dictionaries¶
A dictionary is an hashtable, a mapping object that maps values to arbitrary objects.
Functions and variables can be used to handle vectors and the sintax to access vector elements is:
*expression* [ *key* ]
Example:
dict(a=1,b="foo")["b"] --> "foo" dict(a=1,b="foo",c2="bar")["c2"] --> "bar" my_function_returns_a_dictionary()["key1"] --> value for the key "key1" my_function_returns_a_dictionary()[1] --> value for the key 1
4.1.1.6. Variables¶
A variable is represented by a initial $ followed by a sequence of alphanumeric characters or _.
Every variable has a value. The value can be a string, a number, a boolean, ecc.
Examples:
$foo
$BAR
$_
$foo_Bar
4.1.1.7. Functions¶
Functions are represented by a sequence of alphanumeric characters or _.
Examples:
power
round
sqrt
substr
4.1.1.8. Expressions¶
4.1.1.8.1. Operators¶
The language supports the following operators:
Arithmetical
Operator
Meaning
a + b
sum
a - b
subtraction
a / b
division
a % b
module division
a * b
multiplication
+a
positive
-a
negative
Comparison
Operator
Meaning
a == b , a eq b
a != b
a =~ b
a matches regular expression represented by b
a < b
a <= b
a > b
a >= b
BIT operators
Operator
Meaning
a & b
bit and
a | b
bit or
a ^ b
bit xor
~a
one's complement
Logical operators
Operator
Meaning
a && b , a and b
and
a || b , a or b
or
!a , not a
not
Object operators
Operator
Meaning
a . b
get attribute "b" from object "a"
4.1.1.8.2. Operators precedence¶
Operators listed in descening precedence.
Operators
Description
(), [] , "."
Call, range and attr operator
+,-,~,!,not
unary operator ( +10, -30, !b, not b)
||, or
&&, and
^
&
==, !=, ~= , eq
<, <=, >, >=
*
*, /, %
+, -
Warning
binary logical operators (|, &&, and, or) and binary bit operators (&, |, ^) are not short-circuited.
4.1.1.8.3. Function call¶
This is the syntax for function call:
function name ( [ param , param , .... ] [, name = param , name = param ] )
expression ( [ param , param , .... ] [, name = param , name = param ] )
You can specify simple parameters, also called positional parameters, and named parameters.
All named parameters can be specified in any order, but must appear after any other positional parameter.
Not all functions support named parameters. Read functions' documentation for more details.
Examples:
myfunction1() myfunction2( 10 ) myfunction2( "Hello", 'World', 42 ) myfunction3( "Hello", 'World', 42 , timeout=10, shorttries=(3+2)) myfunction4(timeout=10) myfunction5(probesize=1472, "localhost") **WRONG PARAMETERS SEQUENCE**
4.1.1.8.4. Object attribute operator¶
When handling object values, you access to objects's attributes and methods with the "dot" (".") operator.
<obj> . <identifier>
Esample:
$node.__str__ "ciao".encode (1.3.6.1.2.1.1.1.0@).snmp_port
4.1.1.9. SNMP Sub-expressions¶
An SNMP sub-expression, or simply SNMP expression, is a special syntax element of the language.
It is used to reference (and retrieve) the value of a managed object (OID) in the MIB hierarchy.
There are two kind of SNMP expressions and they reppresent two kind of values:
Current SNMP value
Old SNMP value
4.1.1.9.1. Current snmp values¶
These expressions reppresent the current value of an OID. When the SNMP expression is evaluated the value is read from the network throw SNMP protocol.
The full syntax is:
OID expr [ : [ community expr ] [ : [ version expr ] ] [ : [ timeout expr ] ] [ : [ tries expr ] ] ] @ [ [ node expr ] [ : [ port expr ] ] ]
Examples:
1.3.6.1.2.1.1.1.0@ 1.3.6.1.2.1.1.1.0:$community@ 1.3.6.1.2.1.1.1.0:$community:$snmpversion@ 1.3.6.1.2.1.1.1.0::$snmpversion@ 1.3.6.1.2.1.1.1.0@$node 1.3.6.1.2.1.1.1.0@$node:$snmpport 1.3.6.1.2.1.1.1.0@:$snmpport 1.3.6.1.2.1.1.1.0:$community:$snmpversion@$node 1.3.6.1.2.1.1.1.0:$community:$snmpversion@$node:$port 1.3.6.1.2.1.1.1.0@"mason" 1.3.6.1.2.1.1.1.0@$node+"1" 1.3.6.1.2.1.1.1.0@"mason":161 1.3.6.1.2.1.1.1.0@$node:$port 1.3.6.1.2.1.1.1.0:"public"@"mason":161 1.3.6.1.2.1.2.(0+2)."1.1.1":$community@$node:($port+0)
If one of the optional expressions is missing, the default value is taken from the execution context.
The execution context is a set of variables created when the expression evaluation starts. This is a SANET related topic and will be explained later in this document.
Expressions
type
Optional
context's variable name
*OID expr *
string
community expr
string
$community
version expr
integer
$snmpversion
timeout expr
float
$snmpversion
tries expr
integer
$shorttries
node expr
string
$node
port expr
integer
$snmpport
4.1.1.9.2. OID Expression ambiguities¶
The OID expr is a special type of expression. It must have the following sintax:
OID [ . expression [ . .... ] ]
Example:
1.3.6.1.2.1.(1+0).1.0@ 1.3.6.1.2.1.(1+0).$instance.43.2.14@
An OID can contain the dot (".") character. This could lead to ambiguieties in the expression and an error
Examples: with $instance = 666 (integer) then:
1.3.6.1.2.1.$instance.43@ | v 1.3.6.1.2.1. 666 .43@1.3.6.1.2.1.$instance.43.1.1.oidString("123")@ | v 1.3.6.1.2.1. $instance .43.1.1. oidString("123") @ | | v v 1.3.6.1.2.1. 666 .43.1.1. "3.49.50.51" @1.3.6.1.2.1.$instance.oidString("123")@ | v 1.3.6.1.2.1. $instance.oidString("123") @ | v *ERROR* can not apply method "upper()" on an value returned by "$instance".1.3.6.1.2.1.$instance.oidString("123")@ | v 1.3.6.1.2.1. $instance.upper() @ | v *ERROR* can not apply method "upper()" on an value returned by "$instance".
4.1.1.9.3. Old snmp values¶
The syntax is:
OID [ : community ] [ : version ] # [ node [ : port ] ]
These sub-expressions represent the previous value of a managed object inside a MIB.
The term previous value means the value read throw SNMP the last time the expression containing the SNMP sub-expression was evaluated.
This is a SANET related topic and will be explained later in this document.
4.1.2. Statements¶
4.1.2.1. TRY/CATCH statement¶
This statement is useful when you need to detect and handle special errors/exceptions execution cases.
Read the section Gestione delle eccezioni nei controlli for more details about known and unknown exceptions types.
The syntax is:
try expression1 catch exception name1 ( expression2 )
When an exception of the specified type expression name1 is raised, the returned value is the value for expression2.
Examples:
try 1 + 1 catch ValueError (666) -> 2 try 1.3.6.1.2.1.1.1.0@ catch ValueError (666) -> Linux debiantest 3.2.0-3-486 #1 Thu Jun 28 08:08:24 UTC 2012 i686 try 1/0 catch ZeroDivisionError (666) -> 666 try 1/0 catch TimeoutException (666) -> *EXCEPTION* -> *UNCHECKABLE* try 1.3.6.1.2.1.1.1.2.3.4.5@ catch UndefinedSnmpValueException (666) -> 666 try 1.3.6.1.2.1.1.1.2.3.4.5@ catch TimeoutException (666) -> *EXCEPTION* -> *UNCHECKABLE*Danger
- This statement will catch every exception:
try ..... catch Exception ( ... )You SHOULD NEVE USE this statement, UNLESS YOU ARE REALLY SURE your expressions never raise dangerous exceptions.
You can omit the expression2 part:
try expression1 catch exception name1 ( )
Executes expression1 and returns the calculated value.
When an exception of the specified type expression name1 is raised, the returned value is a string with the exception description.
Examples:
try 1 + 1 catch ValueError () -> 2 try 1.3.6.1.2.1.1.1.0@ catch ValueError () -> Linux debiantest 3.2.0-3-486 #1 Thu Jun 28 08:08:24 UTC 2012 i686 try 1/0 catch ZeroDivisionError () -> ZeroDivisionError:division 1 / 0.0division 1 / 0.0 try 1/0 catch TimeoutException () -> *EXCEPTION* -> *UNCHECKABLE* try 1.3.6.1.2.1.1.1.2.3.4.5@ catch UndefinedSnmpValueException () -> 666 try 1.3.6.1.2.1.1.1.2.3.4.5@ catch TimeoutException () -> UndefinedSnmpValueException:Current variable 1.3.6.1.2.1.1.1.2.3.4.5:public@localhost:161 can't be read or is not present (GET)Danger
This statement will catch every exception:
try ..... catch Exception ()You SHOULD NEVE USE this statement, UNLESS YOU ARE REALLY SURE your expressions never raise dangerous exceptions.
You can omit the exception name:
try expression1 catch ( expression2 )
Executes expression1 and returns the calculated value.
When any exception is raised, the returned value is the value calculated by expression2.
Warning
any exception raised by expression2 is not catched.
Examples:
try 1 + 1 catch (666) -> 2 try 1.3.6.1.2.1.1.1.0@ catch (666) -> Linux debiantest 3.2.0-3-486 #1 Thu Jun 28 08:08:24 UTC 2012 i686 try 1/0 catch (666) -> 666 try 1.3.6.1.2.1.1.1.2.3.4.5@ catch (666) -> 666Danger
You SHOULD NEVE USE this statement, UNLESS YOU ARE REALLY SURE your expressions never raise dangerous exceptions.
You can omit both exception name and secondary expression:
try expression1 catch ( )
Executes expression1 and returns the calculated value.
When any exception is raised, the returned value is a string with the exception's description.
Example:
try 1 + 1 catch () -> 2 try 1.3.6.1.2.1.1.1.0@ catch () -> Linux debiantest 3.2.0-3-486 #1 Thu Jun 28 08:08:24 UTC 2012 i686 try 1/0 catch () -> ZeroDivisionError:division 1 / 0.0division 1 / 0.0 try 1.3.6.1.2.1.1.1.2.3.4.5@ catch () -> UndefinedSnmpValueException:Current variable 1.3.6.1.2.1.1.1.2.3.4.5:public@localhost:161 can't be read or is not present (GET)Danger
You SHOULD NEVE USE this statement, UNLESS YOU ARE REALLY SURE your expressions never raise dangerous exceptions.
4.1.2.1.1. Handle multiple exceptions¶
You can catch multiple exceptions with the same expression:
try expression1 catch ... catch ... catch ...
The statement will try to catch any exception in order.
Examples:
try 1/0 catch ZeroDivisionExcption ( "a" ) catch ExecutionError ("b") catch ("c") -> "a" try xyz() catch ZeroDivisionExcption ( "a" ) catch ExecutionError ("b") catch ("c") -> "b" try pollerror() catch ZeroDivisionExcption ( "a" ) catch ExecutionError ("b") catch ("c") -> "c"
Attention: never use the generic catch before other catches because they will be ignored.
try 1/0 catch ("c") catch ZeroDivisionExcption ( "a" ) catch ExecutionError ("b") -> "c"
4.1.2.2. IF statement¶
The syntax is:
if expression1 then expression2 else expression3
The statement calculate the value for the expression1. If the computed value is true, expression2 is calculated, otherwise expressione3.
Example:
if 1 + 1 >= 2 then "Hello" else "Goodbye" if try 1.3.6.1.2.1.1.1.10@ catch (False) then 1.3.6.1.2.1.1.1.0@ else "Goodbye"
Attention
this statement is dangerous when used with Old snmp values. If you do not write your statement properly, some SNMP variables could never be fetched.
if 1 + 1 >= 2 then 1.3.6.1.2.1.1.2.3.4.0# else (1.3.6.1.2.1.1.2.3.4.0@ - 1.3.6.1.2.1.1.2.3.4.0#)
4.1.2.3. FOR statement¶
The syntax is:
for symbol [, ...] in range expression
[ if test ]
do body
Iterates the values calculated by range expression, assign them to symbol and excecutes body at each iteration; returns a list of all values calculated by body.
The scope of symbol is only inside the test or body expression.
When test expression is specified, body is calculated only when test is not False.
Warning
When body is executed, symbol variable will override any other variable with the same name in the current execution context.
Example:
The range expression must calculate a list of values. Each element of the list can be a tuple of elements; in this case
for $a, $b in list( list(1,1) , list(2,5), list(0,3)) do $a+$b
4.1.2.3.1. Set statement¶
The set statement is a special expression that assign to symbol the value of expression and returns the value itself.
set symbol as expression
Example 1:
with $tot as 0 , $temp as ( for $row in list(list('a',1),list('b',99)) do set $tot as $tot + $row[1] ) do $tot
Example 2:
with $vals as ( for $row in list(list('a',1),list('b',99)) do $row[1] ) do sum($vals)100
4.1.2.4. WITH statement¶
The syntax is:
- with
$symbol1 as expr1
[, ... ]
- do
body expr
Update execution context with every $symbol1 defined by expr1 expressions and executes body expr.
Example:
with $a as 1, $b as 2 do $a + $b3
Example 2:
with $sysdescr as 1.3.6.1.2.1.1.1.0@ do $sysdescrb'Linux debian.....'
4.1.2.4.1. Complex Example¶
Check if all "admin enabled" ifaces are active:
export EXPR=' with $num_ifaces as 1.3.6.1.2.1.2.1.0@ , $enabled_ifaces as ( for $n in range($num_ifaces) if 1.3.6.1.2.1.2.2.1.7.($n+1)@ == 1 do $n+1 ) , $active_ifaces as ( for $ifidx in $enabled_ifaces if 1.3.6.1.2.1.2.2.1.8.$ifidx@ == 1 do $ifidx ) do len($enabled_ifaces) == len($active_ifaces) ' sanet-manage exec_expr localhost "$EXPR"
4.1.2.5. Function value definition¶
You can define new "inline" functions and pass/use them as values in your expression.
The syntax is:
fun ( param1 [, ...] ) ( expr )
Defines a new inline-function value that can be passed to other functions as a value.
Warning
the final result of an expression can not return a inline-function. The execution will raise an exception.
Example 1: define a new inline function
fun(a)($a+1)*EXCEPTION* (Expression value is a function)
Example 2:
( fun(a)($a+1) ) (3)4
Examples: define a new inline function, assign it to a variable and call it with call operator '()':
with $f as fun(a)($a+1) do $f(5)6
Example: define a function and pass as value to an other function:
map( fun(a)($a + 1.5), list(1,2,3) )[2.5, 3.5, 4.5]