Difference between revisions of "UM:NetXMS Scripting Language (NXSL)"

m
Text replacement - "^" to "{{deprecated}}"
m (Text replacement - "^" to "{{deprecated}}")
 
(14 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{DISPLAYTITLE:NetXMS Scripting Language (NXSL)}}
{{deprecated}}{{DISPLAYTITLE:NetXMS Scripting Language (NXSL)}}
 
 
{| style="border-spacing: 20px; border: 20px solid red;"
|
'''WARNING''': This page is no longer updated. Please visit '''[https://www.netxms.org/documentation/nxsl-latest/#_language_syntax Language syntax]''' for current version of the documentation.
|}
 
 
 
 
= NXSL Overview =
= NXSL Overview =
In many parts of the system, fine tuning can be done by using NetXMS built-in scripting language called NXSL (stands for NetXMS Scripting Language). NXSL was designed specifically to be used as embedded scripting language within NetXMS, and because of this has some specific features and limitations. Most notable is very limited access to data outside script boundaries – for example, from NXSL script you cannot access files on server, nor call external programs, nor even access data of the node object other than script is running for without explicit permission. NXSL is interpreted language – scripts first compiled into internal representation (similar to byte code in Java), which than executed inside NXSL VM.
In many parts of the system, fine tuning can be done by using NetXMS built-in scripting language called NXSL (stands for NetXMS Scripting Language). NXSL was designed specifically to be used as embedded scripting language within NetXMS, and because of this has some specific features and limitations. Most notable is very limited access to data outside script boundaries – for example, from NXSL script you cannot access files on server, nor call external programs, nor even access data of the node object other than script is running for without explicit permission. NXSL is interpreted language – scripts first compiled into internal representation (similar to byte code in Java), which than executed inside NXSL VM.
Line 32: Line 42:
Everything inside /* */ is considered a comment and will be ignored by interpreter. You can enclose comments, like below:
Everything inside /* */ is considered a comment and will be ignored by interpreter. You can enclose comments, like below:


<syntaxhighlight>
<syntaxhighlight lang="c">
/* comment /* another comment */ still comment */
/* comment /* another comment */ still comment */
</syntaxhighlight>
</syntaxhighlight>
Line 76: Line 86:


return is another built-in operator which exits the function and sets it's return value.
return is another built-in operator which exits the function and sets it's return value.
= Script entry point =
NXSL handles script entry in 2 ways:<br>
* Explicit main() function
* Implicit $main() fucntion
If an explicitelly defined main() exists, it will be called.
If an explicit main() doesnt exist, an implicit $main() fucntion will be created by the script interpreter and the script will enter at the $main() function.<br>
The $main() fucntion is constructed from code that is not a part of any other functions.




Line 130: Line 151:
}
}
</syntaxhighlight>
</syntaxhighlight>


= Functions =
= Functions =
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 [[NXSL:trace|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 use keywords.
To define a function, you can use the following form:
'''sub''' ''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:
<syntaxhighlight lang="c">
sub message()
{
  println "Hello!";
}
</syntaxhighlight>
== Function Arguments ==
The first argument you pass to the function is available within the function as $1, the second argument is $2, and so on. For example, this simple function adds two numbers and prints the result:
<syntaxhighlight lang="c">
sub add()
{
  result = $1 + $2;
  println "The result was: " . result;
}
</syntaxhighlight>
To call the subroutine and get a result:
<syntaxhighlight lang="c">
add(1, 2);
</syntaxhighlight>
If you want named arguments, list of aliases for $1, $2, etc. can be provided in function declaration inside the brackets:
<syntaxhighlight lang="c">
sub add(numberA, numberB)
{
  result = numberA + numberB;
  println "The result was: " . result;
}
</syntaxhighlight>
If parameter was not provided at function call, value of appropriate variable will be '''null'''.
== Return Values from a Function ==
You can return a value from a function using the '''return''' keyword:
<syntaxhighlight lang="c">
sub pct(value, total)
{
  return value / total * 100.0;
}
</syntaxhighlight>
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'''.




Line 138: Line 224:


A ''key'' must be a non-negative 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 <tt>NULL</tt>.
A ''key'' must be a non-negative 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 <tt>NULL</tt>.
Array elements can be accessed using [''index''] operator. For example, to access element with index 3 of array ''a'' you should use
<syntaxhighlight lang="c">
a[3];
</syntaxhighlight>
== Array Initialization ==
New array can be created in two ways. First is to use '''array''' operator. <br>
This statement will create empty array and assign reference to it to variable ''a''.
<syntaxhighlight lang="c">
array a;
</syntaxhighlight>
You can then assign values to the array like this.<br>
Please note arrays in NXSL are sparse, so you can have elements with nothing in between.
<syntaxhighlight lang="c">
array a;
a[1] = 1;
a[2] = 2;
a[260] = 260;
println(a[1]); // will print 1
</syntaxhighlight>
Second way is to use %( ) construct to create array already populated with values.<br>
This statement will create array with four elements at positions 0, 1, 2, and 3, and assign reference to this array to variable ''a''.
<syntaxhighlight lang="c">
// no need to use "array a;" here, since we are creating it dirrectly
a = %(1, 2, 3, 4);
println(a[0]); // will actually print 1, since 1 is the 0th member
</syntaxhighlight>
Array initialization can also be used directly in expressions, like this:
<syntaxhighlight lang="c">
sub f()
{
  return %(2, "text", %(1, 2, 3));
}
</syntaxhighlight>
In this example function ''f'' returns array of 3 elements - number, text, and another array of 3 numeric elements.


= Operators =
= Operators =
Line 143: Line 278:


== Arithmetic Operators ==
== Arithmetic Operators ==
''Table 1: Arithmetic Operators''
{| style="border-spacing:0;"
! <center>Example</center>
! <center>Name</center>
! <center>Result</center>


{| class="wikitable"
|-
! Example !! Name !! Result
|-
|-
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| -a
| -a || Negation || Opposite of ''a''.
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Negation
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Opposite of ''a''.
 
|-
|-
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a + b
| a + b || Addition || Sum of ''a'' and ''b''.
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Addition
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Sum of ''a'' and ''b''.
 
|-
|-
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a - b
| a - b || Subtraction || Difference of ''a'' and ''b''.
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Subtraction
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Difference of ''a'' and ''b''.
 
|-
|-
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a * b
| a * b || Multiplication || Product of ''a'' and ''b''.
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Multiplication
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Product of ''a'' and ''b''.
 
|-
|-
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a / b
| a / b || Division || Quotient of ''a'' and ''b''.
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Division
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Quotient of ''a'' and ''b''.
 
|-
|-
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a % b
| a % b || Modulus || Remainder of ''a'' divided by ''b''.
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Modulus
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Remainder of ''a'' divided by ''b''.
 
|}
|}
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.  
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.  
Line 192: Line 305:


== Bitwise Operators ==
== Bitwise Operators ==
''Table 2: Bitwise Operators''


{| style="border-spacing:0;"
{| style="border-spacing:0;"
Line 276: Line 387:
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Match
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Match
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if ''a'' is matched to regular expression ''b''. As a side effect, assigns values to special variables $1, $2, $3, etc. See ''Regular Expressions'' for details.
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if ''a'' is matched to regular expression ''b''. As a side effect, assigns values to special variables $1, $2, $3, etc. See ''Regular Expressions'' for details.
|-
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a match b
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Match
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if ''a'' is matched to regular expression ''b''. As a side effect, assigns values to special variables $1, $2, $3, etc. See ''Regular Expressions'' for details.
|-
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a imatch b
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Match (case insensitive)
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if ''a'' is matched to regular expression ''b'' (case insensitive). As a side effect, assigns values to special variables $1, $2, $3, etc. See ''Regular Expressions'' for details.


|}
|}
Line 330: Line 451:


|-
|-
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a || b
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a <nowiki>||</nowiki> b
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Or
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Or
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if either ''a'' or ''b'' is <tt>TRUE</tt>.
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if either ''a'' or ''b'' is <tt>TRUE</tt>.


|}
|}
== String Operators ==
== String Operators ==
There are two string operators. The first is the concatenation operator ('.'), which returns the concatenation of its right and left arguments. The second is the concatenating assignment operator ('''.='''), which appends the argument on the right side to the argument on the left side.
There are two string operators. The first is the concatenation operator ('.'), which returns the concatenation of its right and left arguments. The second is the concatenating assignment operator ('''.='''), which appends the argument on the right side to the argument on the left side.


= Control structures =
= Control structures =
Line 402: Line 523:


== switch ==
== switch ==
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.  
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:
<syntaxhighlight lang="c">
  switch (input)
  {
    case "1":
      trace(0,"Input is 1");
      break;
    case "2":
      trace(0,"Input is 2");
      break;
    default:
      trace(0, "Input is unknown");
  }
</syntaxhighlight>




Line 429: Line 565:


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.
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 ==
[http://en.wikipedia.org/wiki/Short-circuit_evaluation 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:
<syntaxhighlight lang="c">
if ((x != null) && ((trim(x) == "abc") || (long_running_test(x))) 
  do_something();
</syntaxhighlight>
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.
[[Category:Scripting Guide]]