Expressions

[This is preliminary documentation and subject to change.]

Expressions are simple, yet powerful mechanism that allows you to write advanced formulas to be used in task arguments and conditions that direct the build process. Expressions can access project properties and call builtin or user-defined functions.

NAnt provides a rich set of bulitin functions, that allow you to:

For a full list of supported functions, click here.

Expression Syntax

Expressions can be used in all task arguments, by using ${...} notation. You may use standard syntax for arithmetical (addition, subtraction, multiplication, division, modulus), logical (negation, conjunction, alternative) and relational operators (equality, inequality). To call functions, use prefix::function-name(argument1, ..., argumentN) syntax. To access properties, you simply use their names without any prefix or suffix. See the examples section below for more information.

Examples:

  1. Accessing a property:

    <property name="build.version" value="3" />
    <echo message="The current date is: ${build.version}" />

    This will output the current value of build.version property.

  2. Calling a function

    <echo message="The current date is: ${datetime::now()}" />

    This will output the current date and time.

  3. Storing the result of an expression

    To store the result of an expression in a property, use the <property> task:

    <property name="autoexec-present" value="${file::exists('c:\autoexec.bat')}" />

    This will set the property autoexec-present to either true or false depending on whether the specified file exists or not.

  4. Real-life expression use

    <property name="myprj.basedir" value="c:\" />
    <property name="filename" value="${path::combine(myprj.basedir,'version.txt')}" />

    <if test="${not file::exists(filename) or file::get-length(filename) = 0}">
        <echo message="The version file ${filename} doesn't exist or is empty!" />
    </if>

    This will check for the existence of a file version.txt in a directory specified by myprj.basedir. Note that this makes use of the short-circuit evaluation supported by NAnt, so you can test for the existence of the file and check its length in the same expression. ( ie like C, NAnt will not evaluate the second part of an 'or' expression if the first evaluates to true )

  5. Using expressions to conditionally execute tasks

    All tasks support if and unless attributes. Expressions can be used there to control which tasks get executed:

    <property name="myprj.basedir" value="c:\" unless="property::exists('myprj.basedir')" />
    <csc target="library" output="out.dll" ...
         if="${datetime::diff(file::get-last-write-time('out.dll'), datetime::now()) > 3600}">
    ...
    </csc>

    This will rebuild the C# library only if it was last rebuilt more than an hour ago.

Operators

The following operators are supported:

Op. Description Example Remarks
String operators
+ string concatenation operator 'aaa' + 'bbb' evaluates to 'aaabbb'
When either side of + operator is a string, the operator is considered to be a string concatenation.
Arithmetical operators
+ addition operator 1 + 2 evaluates to 3
1.0 + 2 evaluates to 3.0
When at least one argument is of type double, the result is a double, otherwise it's an int.
- subtraction operator 5 - 2 evaluates to 3
1.5 - 3 evaluates to -1.5
When at least one argument is of type double, the result is a double, otherwise it's an int.
* multiplication operator 7 * 2 evaluates to 14
1.5 * 4 evaluates to 6.0
When at least one argument is of type double, the result is a double, otherwise it's an int.
* division operator 9 / 4 evaluates to 2 (integer division)
9 / 4.0 evaluates to 2.25 (floating point division)
When at least one argument is of type double, the result is a double, otherwise it's an int. It's illegal to divide by zero.
% modulus operator 9 % 4 evaluates to 1 Both arguments must be convertible to type int
Logical operators
not boolean negation operator not (1=1) evaluates to false
not false evaluates to true
The argument must be convertible to type boolean
and boolean conjunction operator true and false evaluates to false
true and true evaluates to true
Both arguments must be convertible to type boolean. A short-circuit evaluation is used. If the value of the conjunction is known to be false, subsequent terms aren't evaluated. For example: (1=0) and (2=3) and (1=3) will stop the evaluation after the 1=0 is evaluated because its value is false.
or boolean alternative operator true or false evaluates to true
false or false evaluates to false
Both arguments must be convertible to type boolean. A short-circuit evaluation is used. If the value of the alternative is known to be true, subsequent terms aren't evaluated. For example: (1=1) or (2=3) or (3=3) will stop the evaluation after the 1=1 is evaluated because its value is true.
Relational operators
= equality operator 'a'='a' evaluates to true
1 = '3' evaluates to false
The result is true if the arguments are equal, otherwise the result is false. Arguments must be of the same or compatible type.
<> inequality operator 'a'<>'b' evaluates to true
1 = '3' evaluates to false
The result is false if the arguments are equal, otherwise the result is true. Arguments must be of the same or compatible type. NOTE: in XML you must write &lt;&gt; instead of <>
< less-than operator 'a'<'b' evaluates to true
1 < 0 evaluates to false
The result is true if the value of the first argument is less than the value of the second argument, otherwise the result is false. Arguments must be of the same or compatible type. NOTE: in XML you must write &lt; instead of <
> greater-than operator 'b'>'a' evaluates to true
0 > 1 evaluates to false
The result is true if the value of the first argument is greater than the value of the second argument, otherwise the result is false. Arguments must be of the same or compatible type. NOTE: in XML you must write &gt; instead of >
<= less-or-equal operator 'a'<= 'b' evaluates to true
1 <= 0 evaluates to false
The result is true if the value of the first argument is less than or equal to the value of the second argument, otherwise the result is false. Arguments must be of the same or compatible type. NOTE: in XML you must write &lt;= instead of <=
>= greater-or-equal operator 'b'>='a' evaluates to true
0 >= 1 evaluates to false
The result is true if the value of the first argument is greater than than or equal to the value of the second argument, otherwise the result is false. Arguments must be of the same or compatible type. NOTE: in XML you must write &gt;= instead of >=

NOTE: Because NAnt supports properties whose names can contain dashes, there's a possible ambiguity between the subtraction of two properties and accessing a single property with a name containing a dash:

aaa-bbb - this is ambiguous. It could either be property aaa MINUS property bbb or property aaa-bbb.

To avoid confusion, it's recommended to surround the subtraction operator (or even better, all binary operators) with spaces. The expression aaa - bbb always evaluates as a subtraction.

Operator precedence

NAnt expressions support standard ( c style ) operator precedence, that we're accustomed to:

Data types

Expressions can access, pass and return values of the following types:

Type Allowed values
int 32-bit signed integer value
double 64-bit signed double precision floating point value
boolean true or false
string strings of characters of any length.
datetime values represeting date & time (range is from 00:00:00, January 1, 1 AD to 23:59:59, December 31, 9999 AD)
timespan represents a time interval.

In addition, the expression evaluation engine allows you to return and pass values of any CLI type through the use of custom functions. Note that there's no support for implicit type conversions.