The following sections describe the standard types that are built into the interpreter.
NXSL is loosely typed programming language. The system will automatically
determine each variable type, assign a certain type to a variable and convert a
variable type from one to another, if necessary. For example, a result for 3
+ "4" will be 7, because the system will automatically convert "4"
string into an integer. In case if the system is not able to automatically
convert a line into an appropriate integer, the operation will result in a
runtime error.
NXSL supports the following variable types:
-
integer (32 bit),
-
unsigned integer (32 bit),
-
integer (64 bit), unsigned integer (64 bit),
-
floating-point number,
-
string,
-
boolean,
-
array,
-
hash map,
-
object.
In addition to that, NXSL also supports a special variable type – NULL.
This value represents a variable with no value. NULL is the only possible
value of type NULL. An attempt to perform any type of arithmetical or
string operations with NULL variable will result in system runtime error.
It is possible to manually convert variable to a certain type, using a special
function, named depending on the variable type. For example, string(4).
That way it is also possible to convert NULL type variables. Therefore, to
avoid runtime errors while processing NULL type variables, it is advised to
use manual conversion.
NXSL does not require setting variable type beforehand. The only exception to
this is arrays. In case if an array is required, operator array defines its
subsequent variables as arrays. Accessing variable which was not previously
assigned will return NULL value.
Although NXSL has object type variables, it is not an object-oriented language. It is not possible to define classes or create objects at script level – only in extensions written in C++. Object type variables are used to return information about complex NetXMS objects, like nodes or events, in a convenient way. Please note that assigning object type variables actually holds reference to an object, so assigning object value to another variable does not duplicate actual object, but just copy reference to it.
To get a human-readable representation of a variable or expression type for
debugging, use the typeof() function, and to get a class name for object
type variables, use classof() function.
A string literal is where you specify the contents of a string in a program. There are few different string literal types:
-
"string" - string literal where some characters preceded by a backslash have special meaning. If you need to insert double quote character you should prepend it with backslash.
-
'string' - string literal with backslash being an ordinary character without special meaning. You cannot insert single quote character into such string literal.
-
""" Multi
line
string""" - string literal that can span multiple lines with backslash being an ordinary character.
The following character combinations are supported in "string" literals:
-
\b- produces Backspace character -
\t- produces Horizontal tab character -
\n- produces Newline character -
\r- produces Carriage return character -
\xhh- produces a character with code hh (where hh is two-digit hex number) -
\uhhhh- produces a character with code hhhh (where hhhh is four-digit hex number). E.g.\u2026produces Greek small letter Mu (μ) -
\\- produces Backslash character (\)
Any variable can be tested for truth value, for use in an if or while condition
or as operand of the Boolean operations below. The following values are considered false:
-
false -
NULL -
zero of any numeric type, for example,
0,0.0.
All other values are considered true — so objects of various types and arrays are always true.
Operations and built-in functions that have a Boolean result return boolean type. However,
there’s an exception to this due to optimizations related to short-circuit evaluation of
or and and operators. For or, if first operand not boolean type, but it’s value is
considered true, that operand will be returned as result. For and, if first operand is
considered false, that operand will be returned as result. This will not cause issues in
subsequent logical operations, as returned value will be correctly considered as true or false;
But when printing the result, it will not be converted to Boolean, so conversion
using boolean() function might be needed.
For example:
a = [1,2,3];
b = true;
c = a or b;
println(c); // will print "[1, 2, 3]" because first operand was returned by or operation
if (c) println("TRUE"); // will print "TRUE" as the array contained in c is considered as truea = 0;
b = true;
c = a and b;
println(c); // will print "0" because first operand was returned by and operation
println(boolean(c)); // will print "false"Variables in NXSL behave the same way as variables in most popular programming languages (C, C++, etc.) do, but in NXSL you don’t have to declare variables before you use them.
Scope of a variable can be either global (visible in any function in the script) or local (visible only in the function within which it was defined). Any variable is by default limited to the local function scope.
By default, variables are local to the function where they are first assigned. This means variables defined in the main script are not visible to other functions:
x = 1;
myFunction();
function myFunction()
{
println("x * 2 = " .. x * 2);
}This script will cause run time error Error 5 in line 6: Invalid operation
with NULL value, because variable x is local to the implicit main function
and is not visible in myFunction.
To make a variable accessible across all functions, declare it with the global keyword:
global x = 1;
myFunction();
function myFunction()
{
println("x * 2 = " .. x * 2);
}This script produces the expected result and prints x * 2 = 2.
By default, variables are local to the function where they are first assigned.
Starting with version 6.0, you can explicitly declare a variable as local using
the local keyword. This is useful for clarity and to ensure a variable is
local even if a global variable with the same name exists:
global x = 100;
function myFunction()
{
local x = 5; // Creates a new local variable, does not affect global x
println("local x = " .. x); // Prints: local x = 5
}
myFunction();
println("global x = " .. x); // Prints: global x = 100The local keyword can also be used without initialization:
function process()
{
local result; // Explicitly declare local variable
if (condition)
result = "yes";
else
result = "no";
return result;
}A function is a named code block that is generally intended to process
specified input values into an output value, although this is not always the
case. For example, the trace() function takes variables and static text and
prints the values into server log. Like many languages, NXSL provides for
user-defined functions. These may be located anywhere in the main program or
loaded in from other scripts via the import keywords.
To define a function, you can use the following form:
function NAME ( ARGUMENTS ) BLOCK
where NAME is any valid identifier, ARGUMENTS is optional list of
argument names, and BLOCK is code block.
To call a function you would use the following form:
NAME ( LIST )
where NAME is identifier used in function definition, and LIST is an
optional list of expressions passed as function arguments.
To give a quick example of a simple subroutine:
function message()
{
println("Hello!");
}NXSL provides four ways to access function arguments. In most cases, you should use standard named parameters (method 1).
Declare parameter names in the function signature. This is the clearest and most commonly used approach:
function add(numberA, numberB)
{
result = numberA + numberB;
println("The result was: " .. result);
}
add(5, 3); // Prints: The result was: 8If a parameter is not provided at function call, its value will be NULL:
function greet(name, title)
{
if (title == null)
title = "User";
println("Hello, " .. title .. " " .. name);
}
greet("Alice"); // Prints: Hello, User Alice
greet("Bob", "Dr."); // Prints: Hello, Dr. BobParameters can be named at the call site using param: value syntax. The function declaration has empty parentheses, and parameters are accessed with the $ prefix:
function process()
{
println("Name: " .. $name);
println("Age: " .. $age);
}
process(age: 30, name: "Alice");
// Prints:
// Name: Alice
// Age: 30This approach allows calling with parameters in any order but is less commonly used.
Arguments are automatically available as $1, $2, $3, etc., regardless of how the function is declared:
function add()
{
result = $1 + $2;
println("The result was: " .. result);
}
add(5, 3); // Prints: The result was: 8This is useful for quick scripts but makes code harder to read. Standard named parameters (method 1) are preferred.
All arguments passed to a script are available in the global $ARGS array. The first argument is $ARGS[1]:
function main()
{
println("Script received " .. $ARGS.size .. " arguments");
for (i = 1; i <= $ARGS.size; i++)
println("Argument " .. i .. ": " .. $ARGS[i]);
}This is primarily used when the number of arguments is variable or unknown.
You can combine positional and named arguments in the same function call. Named arguments count toward positional parameter indices:
function myFunc(arg1)
{
println("arg1: " .. arg1);
println("$2: " .. $2);
println("$arg3: " .. $arg3);
}
myFunc("first", arg3: "third", "second");
// Prints:
// arg1: first
// $2: third (named parameter arg3 occupies position 2)
// $arg3: third
myFunc("first", "second", arg3: "third");
// Prints:
// arg1: first
// $2: second (positional parameter in position 2)
// $arg3: thirdWhile this flexibility exists, mixing argument styles can make code harder to understand. For clarity, stick to standard named parameters (method 1) in most cases.
You can return a value from a function using the return keyword:
function pct(value, total)
{
return value / total * 100.0;
}When called, return immediately terminates the current function and returns the
value to the caller. If you don’t specify a value in return statement or
function ends implicitly by reaching end of function’s block, then the return
value is NULL.
NXSL handles script entry in two ways:
-
Explicit
main()function -
Implicit
$main()function
Explicit main() function:
If an explicitly defined main() function exists, it will be called. This approach
is recommended for scripts that accept parameters, as it allows you to declare
named parameters:
function main(nodeName, threshold)
{
println("Processing:", nodeName);
if (threshold == null)
threshold = 90;
// Script logic here
return 0;
}Script arguments are passed to main() parameters in order. Arguments are also
available via $1, $2, etc. and the $ARGS array within the function.
Implicit $main() function:
If an explicit main() doesn’t exist, the interpreter creates an implicit $main()
function from all code that is not part of any other function:
// This code becomes the implicit $main()
println("Script started");
result = calculate($1);
return result;
function calculate(value)
{
return value * 2;
}|
Warning
|
If both an explicit main() function and top-level code exist, the top-level code is silently discarded. Only the explicit main() function will execute:
|
println("This will NOT execute"); // Discarded when main() exists
function main()
{
println("Only this executes");
}You can call functions from scripts that are stored in Script Library. One way is
to use the import keyword accompanied by the name of the script:
import my_math_library;
println( add(1, 2) );The other way is shown in this example:
println( my_math_library::add(1, 2) );Added in version 6.0
To prevent script errors when calling a function that may not exist, use the
optional keyword. If the function is present, it is called, and the
expression evaluates to its return value. If the function does not exist, the
call is safely ignored, and the expression evaluates to NULL without halting
the script.
// If f() exists, v gets its return value. // If f() does not exist, v becomes NULL. v = optional f();
The same logic applies when calling a function from a specific library.
// If my_library and function f() in it exists, v gets its return value. // Otherwise, v becomes NULL. v = optional my_library::f();
Strings are not objects, it’s a separate variable type. However, strings have methods and attributes described below
- isEmpty: bool
-
Returns "true" if string is empty or "false" otherwise.
s = ""; println(s.isEmpty); // prints "true"
- length: int
-
Returns number of characters in the string.
s = "1234567890"; println(s.length); // prints '10'
- compareTo(string): int
-
Compares two strings lexicographically (alphabetical order). Returns
-1if the argument is a string lexicographically greater than this string,1if the argument is a string lexicographically less than this string or0if the argument is a string lexicographically equal to this string.The is a difference to
==comparison operator if strings contain numbers because values are converted to numberic type prior to comparison.println("a".compareTo("c")); // prints "-1" println("c".compareTo("a")); // prints "1" println("a".compareTo("aaa")); // prints "-1" println("aaa".compareTo("a")); // prints "1" println("100".compareTo("100.0")); // prints "-1" println("100" == "100.0"); // prints true
- compareToIgnoreCase(string): int
-
Same as
compareTo, but ignoring the case.println("aaa".compareToIgnoreCase("AAA")); // prints "0"
- contains(string): bool
-
Returns
trueif this string contains the argument string orfalseotherwise.println("aaa".contains("a")); // prints "true"
- endsWith(string): bool
-
Returns
trueif this string ends with the argument string orfalseotherwise.println("abc".endsWith("d")); // prints "false" println("Just a sentence".endsWith("a sentence")); // prints "true"
- equalsIgnoreCase(string): bool
-
Returns
trueif argument string is equal to this string ignoring the case orfalseotherwise.println("abc".equalsIgnoreCase("ABC")); // prints "true"
- fuzzyEquals(string, threshold): bool
-
Returns
trueif argument string is approximately equal to this string using fuzzy comparison based on similarity score. Optionalthresholdparameter (float, 0.0 to 1.0) sets the minimum similarity score required for a match — higher values require closer match. Default threshold is 0.2.Added in version 6.0
println("kitten".fuzzyEquals("kittens")); // prints "true" println("abc".fuzzyEquals("xyz")); // prints "false" println("hello".fuzzyEquals("hallo", 0.9)); // prints "false" (higher threshold)
- fuzzyEqualsIgnoreCase(string, threshold): bool
-
Same as fuzzyEquals, but ignoring the case.
Added in version 6.0
println("Kitten".fuzzyEqualsIgnoreCase("kittens")); // prints "true" println("Hello".fuzzyEqualsIgnoreCase("HALLO")); // prints "true"
- indexOf(string): int
-
Returns index of first occurence of argument string in this string or
-1if the argument is not a substring of the string.println("ABC-DEF-GHI".indexOf("-")); // prints "3" println("ABC-DEF-GHI".indexOf("ABC")); // prints "0" println("ABC-DEF-GHI".indexOf("JKL")); // prints "-1"
- lastIndexOf(string): int
-
Returns index of last occurence of argument string in this string or
-1if the argument is not a substring of the string.println("ABC-DEF-GHI".lastIndexOf("-")); // prints "7" println("ABC-DEF-GHI".lastIndexOf("ABC")); // prints "0" println("ABC-DEF-GHI".lastIndexOf("JKL")); // prints "-1"
- left(numberOfCharacters, paddingCharacter): String
-
Returns left
numberOfCharactersof this string. If string length is less thennumberOfCharacters, result will be padded on the right.paddingCharacteris optional, if not specified, space character will be used for padding.println("ABCDEFGHI".left(2)); // prints "AB" println("123".left(5)); // prints "123 " println("123".left(5, "_")); // prints "123__"
- replace(whatToReplace, replaceBy): String
-
Returns string where all occurencies of
whatToReplaceare replaced withreplaceBy.println("A B C A D K L".replace("A", "<A>")); // prints "<A> B C <A> D K L"
- right(numberOfCharacters, paddingCharacter): String
-
Returns right
numberOfCharactersof this string. If string length is less thennumberOfCharacters, result will be padded on the left.paddingCharacteris optional, if not specified, space character will be used for padding.println("ABCDEFGHI".right(2)); // prints "HI" println("123".right(5)); // prints " 123" println("123".right(5, "_")); // prints "__123"
- split(separator, trimWhitespace): Array
-
Split string into array of strings at given separator.
Added in version 5.1.4:
trimWhitespaceparametertrimWhitespaceparameter is optional and isfalseby default. If set totrue, space characters will be removed on both sides of strings produced by splitting.println("ABC--DEF--GHI".split("--")); // prints "[ABC, DEF, GHI]" s = "Alice, Bob, Carol"; for (a : s.split(",")) println("|"..a.."|"); // Will print: // |Alice | // | Bob| // | Carol| s = "Alice , Bob, Carol"; for (a : s.split(",", true)) println("|"..a.."|"); // Will print: // |Alice| // |Bob| // |Carol|
- startsWith(string): bool
-
Returns
trueif this string starts with the argument string orfalseotherwise.println("abc".startsWith("d")); // prints "false" println("Just a sentence".startsWith("Just a")); // prints "true"
- substring(position, numberOfCharacters): String
-
Returns substring of this string starting from
positionand containingnumberOfCharacters.println("ABCDEFGHIJK".substring(0,3)); // prints "ABC" println("ABCDEFGHIJK".substring(6,3)); // prints "GHI" println("ABCDEFGHIJK".substring(6,10)); // prints "GHIJK"
- toLowerCase(): String
-
Converts this string to lowercase.
println("ABC def".toLowerCase()); // prints "abc def"
- toUpperCase(): String
-
Converts this string to uppercase.
println("ABC def".toUpperCase()); // prints "ABC DEF"
- trim(): String
-
Returns this string with whitespace from both sides removed.
println("|" .. " ABC ".trim() .. "|") // prints "|ABC|"
- trimLeft(): String
-
Returns this string with whitespace from left side removed.
println("|" .. " ABC ".trimLeft() .. "|") // prints "|ABC |"
- trimRight(): String
-
Returns this string with whitespace from right side removed.
println("|" .. " ABC ".trimRight() .. "|") // prints "| ABC|"
An array in NXSL is an ordered, sparse, integer-indexed collection. It can be treated as an array, list (vector), stack, queue, and probably more. Nested arrays are supported, so elements of an array can be themselves arrays.
A key is 32-bit signed integer. When an array is created, its size is
not specified and its map can have empty spots in it. For example, an array can
have a element with a 0 key and an element with 4 key and no keys
in-between. Attempting to access an array key which has not been defined is the
same as accessing any other undefined variable: the result will be NULL.
Arrays are not objects, it’s a separate variable type. However, arrays have methods and attributes described below.
Array elements can be accessed using [index] operator. For example, to
access element with index 3 of array a you should use
a[3];To get subarray from the array use [a:b] operator. This operator returns
subarray of an array from the element with index a inclusive till the element
with index b exclusive. If a is omitted then subarray will be taken from the
start of the array and if b is omitted then subarray will be taken till the
end of the array.
Example:
a = [1, 2, 3, 4];
a2 = a[1:3]; // a2 will be [2, 3]
a3 = a[1:]; // a3 will be [2, 3, 4]Arrays can be created using the [] construct. This is the recommended method for array initialization.
An empty array can be created by assigning [] to a variable:
a = [];Arrays can also be initialized with values:
a = [1, 2, 3, 4];
println(a[0]); // will print 1, since 1 is the 0th element
println(a); // will print "[1, 2, 3, 4]"You can then assign values to the array. Please note arrays in NXSL are sparse, so indices can contain gaps:
a = [];
a[1] = 1;
a[2] = 2;
a[260] = 260;
println(a[1]); // will print 1
println(a); // will print "[1, 2, 260]"Array initialization can also be used directly in expressions, like this:
function f()
{
return [2, "text", [1, 2, 3]];
}In this example function f returns array of 3 elements - number, text, and
another array of 3 numeric elements.
Deprecated in version 5.0. The array keyword for declaring arrays is deprecated. New scripts should use [] syntax instead.
// Deprecated - do not use in new code
array a;
// Recommended - use this instead
a = [];maxIndex: int-
Returns highest index in the array.
a = [1, 2, 3]; println(a.maxIndex); // prints '2' println(a[a.maxIndex]); // prints '3'
minIndex: int-
Returns lowest index in the array.
a = [1, 2, 3]; println(a.minIndex); // prints '0'
size: int-
Returns number of elements in the array.
a = [1, 2, 3]; println(a.size); // prints '3'
append(newElement): int-
Appends new element to the array. Returns highest index in the array - that’s index of the appended element.
a = ["a","b","c"];
a.append("d");
println(a); // prints '[a, b, c, d]'
appendAll(anotherArray): int-
Appends elements of
anotherArrayto the array. Returns highest index in the array.
a = [1,2]; b = [3,4]; a.appendAll(b); println(a); // prints '[1, 2, 3, 4]'
indexOf(value): int-
Returns the index of first occurrence of the specified
valueor -1 ifvalueis not found in the array.
a = ["Normal", "Warning", "Minor", "Major", "Critical"];
println(a.indexOf("Major")); // Prints "3"
join(separator): String-
Returns concatenated string of all array elements separated by the specified separator.
separator |
String |
Separator between array elements |
a = [1, 2, 3, 4];
println(a.join(";")); // will print "1;2;3;4"
println(a.join("; ")); // will print "1; 2; 3; 4"insert(index, newElement): void-
Inserts new element to the array at
index. Indexes of existing elements that had index greater or equal toindexare incremented.
array a; a[0] = "aaa"; a[10] = "ccc"; a.insert(5, "bbb"); println(a[0]); // prints "aaa" println(a[5]); // prints "bbb" println(a[11]); // prints "ccc" - because of the insert operation this element's index is now 11.
insertAll(index, anotherArray): void-
Inserts elements of
anotherArrayto the array atindex. Indexes of existing elements that have index greater or equal toindexare incremented.
a = [1,2]; b = [3,4]; a.insertAll(1,b); println(a); // prints '[1, 3, 4, 2]'
pop(): any-
Removes and returns element with highest index from the array. Using
push(value)andpop()methods it’s possible to use array as a stack. Or, usinginsert(0,value)andpop(), array will work as FIFO queue.
a = [];
a.push("one");
a.push("two");
println(a.pop());
println(a.pop());
push(newElement): int-
Same as
append(). remove(index): void-
Removes element at specified
index. Indexes of elements that have index greater or equal toindexare decremented.
a = [1,2,3]; a.remove(0); println(a);
The spread operator (…) expands array elements in place. Use it when all elements from an array need to be included in a new array or applied one-by-one as function arguments.
function sum(i, j, k)
{
return i + j + k;
}
data = [10, 20, 30];
println(sum(...data)); // expands to sum(10, 20, 30), prints 60
a = ["one", "two"];
b = ["new", ...a];
println(b); // prints "[new, one, two]"String representation of array can be obtained by using string(array)
function. The string representation consists of all array’s elements, enclosed
in square brackets (“[]”). Adjacent elements are separated by the characters
“, ” (a comma followed by a space).
Printed array is automatically converted to string.
a = [1, 2, 3, 4, 5, 6, 7];
println(a); // will print "[1, 2, 3, 4, 5, 6, 7]"
println(a .. " is an array"); // will print "[1, 2, 3, 4, 5, 6, 7] is an array"
println(["one", "two"]); // will print "[one, two]"
println([2, "text", [1, 2, 3]]); // will print "[2, text, [1, 2, 3]]"Hash map allows to store data values in key:value pairs. A key is string. Numeric type can also be supplied as key, but it will be internally converted to string. Hash map cannot have two items with the same key. The values can be of any data type, including null, objects, arrays or hash maps.
Hash maps are not objects, it’s a separate variable type. However, hash maps have methods and attributes described below.
Array elements can be accessed using [key] operator. For example, to access element with key key of hash map h you should use
h["key"];This statement will create an empty hash map and assign reference to in to variable h:
h = %{};It’s also possible to create hash map already populated with values, e.g.:
h = %{"key":123, "another_key":456};keys: Array-
Returns array with keys of items in the hash map.
h = %{100:"value1", 101:"value2"};
println(h.keys); // prints '[100,101]'
size: int-
Returns number of items in the hash map.
h = %{"a":null, "b":null, "c":null};
println(h.size); // prints '3'
values: Array-
Returns array with values of items in the hash map.
h = %{"key1":123, "key2":456};
println(h.keys); // prints '[123,456]'
contains(key): bool-
Returns
true, if hash map contains specified key orfalseotherwise.
h = %{"key1":123, "key2":456};
println(h.contains("key2")); // prints 'true'
remove(key): void-
Removes item with specified
key.
h = %{"key1":123, "key2":456};
h.remove("key1");
println(h); // prints '{key2=456}'
Hash Map can be converted to string. string(hash-map) function is used to get string
representation of hash map. The string representation lists all key-value pairs
enclosed in curly brackets (“{}”). Value is separate from the key with equals sigh ("=").
Items are separated by the characters “, ” (a comma followed by a space).
Printed array is automatically converted to string.
h = %{"key1":123, "key2":456};
println("This is a hash map: " .. string(h));
println("Or we can just print it this way: " .. h);An operator is something that you feed with one or more values, which yields another value.
| Example | Name | Result |
|---|---|---|
|
Negation |
Opposite of |
|
Addition |
Sum of |
|
Subtraction |
Difference between |
|
Multiplication |
Product of |
|
Division |
Quotient of |
|
Modulus |
Remainder of |
The division operator (/) returns a float value unless the two operands are
integers (or strings that get converted to integers) and the numbers are evenly
divisible, in which case an integer value will be returned.
Calling modulus on float operands will yield runtime error.
The assignment operator is =, which means that the left operand gets set to
the value of the expression on the rights (that is, "gets set to").
| Example | Name | Result |
|---|---|---|
|
Not |
Bits that are set in |
|
And |
Bits that are set in both operand are set. |
|
Or |
Bits that are set in either operand are set. |
|
Xor |
Bits that are set in only one operand are set. |
|
Shift left |
Shift the bits of |
|
Shift right |
Shift the bits of |
Comparison operators allow you to compare two values.
| Example | Name | Result |
|---|---|---|
|
Equal |
|
|
Not equal |
|
|
Less than |
|
|
Greater than |
|
|
Less than or equal to |
|
|
Greater than or equal to |
|
|
Match |
Array containing full match of |
|
Match |
Same as |
|
Match (case insensitive) |
Same as |
|
Like |
Compare string value to a pattern using wildcard characters. Two wildcard characters
are supported: |
|
Like (case insensitive) |
Same as |
Example:
println("aaa bbb ccc" ~= "b+") // prints "[bbb]"
println("Username: John" ~= "Username: (\w+)"); // prints "[Username: John, John]"
println("abc" like "?bc*"); // prints "true"Note that strings which actually contain number are converted to numeric type prior to comparison. So, for example:
s1 = "1";
s2 = "1.0";
i = 1;
println(s1 == s2); // prints "true"
println(s1 == i); // prints "true"NXSL supports C-style pre- and post-increment and decrement operators.
| Example | Name | Result |
|---|---|---|
|
Pre-increment |
Increments |
|
Post-increment |
Returns |
|
Pre-decrement |
Decrements |
|
Post-decrement |
Returns |
| Example | Name | Result |
|---|---|---|
|
Not |
|
|
Not |
Same as above. |
|
And |
|
|
And |
Same as above. |
|
Or |
|
|
Or |
Same as above. |
| Example | Name | Result |
|---|---|---|
|
Concatenation operator |
Returns the concatenation of its right and left arguments. |
|
Concatenating assignment operator |
Appends the argument on the right side to the argument on the left side. |
|
Substring operator |
Returns substring of a string from the character with index |
| Example | Name | Result |
|---|---|---|
|
Member access |
Access attribute or method |
|
Safe navigation |
Access attribute or method |
The safe navigation operator ?. is useful for chaining method calls when intermediate results might be null:
node = FindObject("my-server");
println(node.name); // Runtime error if node is null
println(node?.name); // Safe: prints nothing if node is null
// Useful in conditions to avoid nested null checks
if ($node.createSNMPTransport()?.getValue("1.3.6.1.2.1.1.1.0") == 10)
{
// Process result
}
// Without safe navigation, you would need:
t = $node.createSNMPTransport();
if (t != null)
{
if (t.getValue("1.3.6.1.2.1.1.1.0") == 10)
{
// Process result
}
}Any NXSL script is built out of a series of statements. A statement can be an assignment, a function call, a loop, a conditional statement or even a statement that does nothing (an empty statement). Statements usually end with a semicolon. In addition, statements can be grouped into a statement-group by encapsulating a group of statements with curly braces. A statement-group is a statement by itself as well. The various statement types are supported:
-
if
-
else
-
while
-
do-while
-
for
-
break
-
continue
-
switch
-
with
-
return
-
exit
The if construct is one of the most important features of many languages. It allows for conditional execution of code fragments. NXSL features an if structure that is similar to that of C:
if (expr)
statementOften you’d want to execute a statement if a certain condition is met, and a
different statement if the condition is not met. This is what else is for.
else extends an if statement to execute a statement in case the
expression in the if statement evaluates to FALSE. The else
statement is only executed if the if expression evaluated to FALSE.
while loops are the simplest type of loop in NXSL. They behave just like
their C counterparts. The basic form of a while statement is:
while (expr)
statementThe meaning of a while statement is simple. It tells NXSL to execute the
nested statement(s) repeatedly, as long as the while expression evaluates
to TRUE. The value of the expression is checked each time at the beginning
of the loop, so even if this value changes during the execution of the nested
statement(s), execution will not stop until the end of the iteration.
do-while loops are very similar to while loops, except the truth
expression is checked at the end of each iteration instead of in the beginning.
The main difference from regular while loops is that the first iteration of
a do-while loop is guaranteed to run (the truth expression is only checked
at the end of the iteration), whereas it may not necessarily run with a regular
while loop (the truth expression is checked at the beginning of each
iteration, if it evaluates to FALSE right from the beginning, the loop
execution would end immediately).
for loops are the most complex loops in NXSL. They behave in two different ways:
like their C counterparts or in Java way. The syntax of a for loop is:
for (expr1; expr2; expr3)
statement
for (varName : array)
statementThe first expression (expr1) is evaluated (executed) once unconditionally
at the beginning of the loop.
In the beginning of each iteration, expr2 is evaluated. If it evaluates to
TRUE, the loop continues and the nested statement(s) are executed. If it
evaluates to FALSE, the execution of the loop ends.
At the end of each iteration, expr3 is evaluated (executed).
In the second example for cycle will call statement for each element in
array. Element will be available as varName.
continue is used within looping structures to skip the rest of the current
loop iteration and continue execution at the condition evaluation and then the
beginning of the next iteration.
The switch statement is similar to a series of if statements on the
same expression. In many occasions, you may want to compare the same variable
(or expression) with many different values, and execute a different piece of
code depending on which value it equals to. This is exactly what the switch
statement is for.
Example:
switch (input)
{
case "1":
trace(0,"Input is 1");
break;
case "2":
trace(0,"Input is 2");
break;
default:
trace(0, "Input is unknown");
}The switch statement also allows to check ranges:
switch (input)
{
case 1:
trace(0,"Input is 1");
break;
case 2:
trace(0,"Input is 2");
break;
case 3...7:
trace(0,"Input is from 3 till 7");
break;
default:
trace(0, "Input is unknown");
}With statement is made to make the code cleaner and much more readable and to expose variable section to global scope for "Object query" Dashboard element. This statement consists of 2 parts: variable declaration (optional) and expression.
Structure:
with
var = {code},
...
var = {code}
expressionExample for "Object query" Dashboard element. This example will filter out only nodes that are unreachable and will create 2 variables as data providers for columns: time node is down since and oldest alarm time.
with
_down = { return SecondsToUptime(time() - downSince); },
_oldestAlarm = {
oldestAlarmTime = 99999999999;
for (a : $node.alarms) {
oldestAlarmTime = min(oldestAlarmTime, a.creationTime);
}
return strftime("%Y-%m-%d %H:%M", oldestAlarmTime);
}
type == NODE and state & NodeState::Unreachable
//In Object query object attributes are available just using name.
//Like state ($node.state in other scripts)If called from within a function, the return statement immediately ends
execution of the current function, and returns its argument as the value of the
function call. Calling return from main() function (either explicitly
or implicitly defined) is equivalent of calling exit.
The simplest yet most accurate way to define an expression is "anything that has a value".
The most basic forms of expressions are constants and variables. When you type
a = 5, you’re assigning 5 into a. 5, obviously, has the value
5, or in other words 5 is an expression with the value of 5 (in this case,
5 is an integer constant).
Slightly more complex examples for expressions are functions. Functions are expressions with the value of their return value.
NXSL supports the following value types: integer values, floating point values (float), string values and arrays. Each of these value types can be assigned into variables or returned from functions.
Another good example of expression orientation is pre- and post-increment and
decrement. You might be familiar with the notation of variable++ and
variable--. These are increment and decrement operators. In NXSL, like in
C, there are two types of increment - pre-increment and post-increment. Both
pre-increment and post-increment essentially increment the variable, and the
effect on the variable is identical. The difference is with the value of the
increment expression. Pre-increment, which is written ++variable, evaluates
to the incremented value. Post-increment, which is written variable++
evaluates to the original value of variable, before it was incremented.
A very common type of expressions are comparison expressions. These expressions
evaluate to either FALSE or TRUE. NXSL supports > (bigger than),
>= (bigger than or equal to), = (equal), != (not equal), <
(less than) and <= (less than or equal to). These expressions are most
commonly used inside conditional execution, such as if statements.
The last example of expressions is combined operator-assignment expressions.
You already know that if you want to increment a by 1, you can simply write
a++ or ++a. But what if you want to add more than one to it, for
instance 3? In NXSL, adding 3 to the current value of a can be written a
+= 3. This means exactly "take the value of a, add 3 to it, and assign it
back into a ". In addition to being shorter and clearer, this also results
in faster execution. The value of a += 3, like the value of a regular
assignment, is the assigned value. Notice that it is NOT 3, but the combined
value of a plus 3 (this is the value that’s assigned into a). Any
two-place operator can be used in this operator-assignment mode.
Short-circuit evaluation denotes the semantics
of some Boolean operators in which the second argument is only executed or
evaluated if the first argument does not suffice to determine the value of the
expression: when the first argument of the AND function evaluates to false, the
overall value must be false; and when the first argument of the OR function
evaluates to true, the overall value must be true. NXSL uses short-circuit
evaluation for && and || boolean operators. This feature permits two
useful programming constructs. Firstly, if the first sub-expression checks
whether an expensive computation is needed and the check evaluates to false,
one can eliminate expensive computation in the second argument. Secondly, it
permits a construct where the first expression guarantees a condition without
which the second expression may cause a run-time error. Both are illustrated in
the following example:
if ((x != null) && ((trim(x) == "abc") || (long_running_test(x)))
do_something();Without short-circuit evaluation, trim(x) would cause run-time error if
x is NULL. Also, long running function will only be called if condition
(trim(x) == "abc") will be false.
If run-time error happens during NXSL code execution, the execution will normally stop and error message will be generated.
The try statement allows to define a block of code to be tested for errors
while it is being executed. Should run-time error occur within that block,
execution of code after the block will continue.
The catch statement allows to define a block of code to be executed, if an
error occurs in the try block.
The try and catch keywords come in pairs:
try
{
// Block to code to try
}
catch
{
// Block of code to handle errors
}The following variables with information about the error are available within the
catch block:
$errorcode |
Error code |
$errorline |
Line number |
$errormodule |
If error happened in a function of script imported using |
$errormsg |
Full error message including error code, line number, error text and, if available, module name. |
$errortext |
Error text |
Since version 3.0, regular expression engine is changed to PCRE (Perl
compatible). Syntax can be checked with pcregrep, perl itself or on
regex101.com (select PCRE flavour).
NXSL supports two kinds of comments: single-line comments and block (multi-line) comments.
-
Single-line comments start with
//and continue to the end of the current line. -
Block comments start with
/*and end with*/. Block comments may span multiple lines. -
Block comments in NXSL can be nested; an inner
/* … */pair is treated as part of the enclosing comment.
Comments are treated as whitespace by the parser and may appear wherever whitespace is allowed (between tokens, at line start, at end of line, inside code blocks, etc.). Comment markers that appear inside string literals are not recognized as comment delimiters.
Examples:
// Single-line comment
x = 1; // comment after code
/* Multi-line comment
spanning several lines */
y = 2;
/* Nested block comments are allowed:
outer open
/* inner comment */
outer continues
*/
z = 3;NXSL scripts may start with one or more metadata declarations. Metadata declarations must appear only at the very beginning of the script (before any other code or non-whitespace characters). Each declaration is a single line with the following syntax:
@meta(key1=value1, key2=value2, ...)Multiple @meta declarations are allowed; they are processed independently.
Metadata keys and their meanings are domain-specific.