Awesome ! Checking it out now. Obviously this is another thing to go in post 0.84 but this looks like a great start.
Thanks !
Ian
Hi!
As I've promised some time ago on the list, I've implemented a simple, yet very powerful, expression evaluator for NAnt. See below for a full list of features. You can now write quite sophisticated expressions, like:
<if test="tolower(${somefilename}) = ${someotherfilename} + '.txt'"> ... </if>
I've added my parser to "NAnt.Core.ExpressionEval" namespace and I've modified <if> and <ifnot> tasks to support a new attribute called "test" (named after XSLT ;-)
It's ultra-easy to add new functions. You simply add new public C# function in "NAnt/Core/ExpressionEval/ExpressionEvaluator.cs" and it works!
The code should be considered alpha-quality, but should work in most cases. I've taken some well-tested parts from another project of mine, yet some parts are new and they may not work correctly in 100% cases.
Can someone please take a look at this patch and commit to CVS if it's ok?
Jarek
P.S. No NUnit-style unit tests yet, but I'm working on them.
Full list of features: ======================
Data types: integer, double, string, boolean and date
Operators: and, or, not =, <>, <, >, <=, >= (because NAnt is XML I'm considering renaming them to lt, gt, le, ge) unary minus, +,-,*,/,%(modulo) with natural precedence, braces (), property access: ${propertyname}
Functions: propertyexists(name) - returns true when the property exists, false otherwise propertyvalue(name) - returns the value of the named property, fails when it's not present
Conversion operators: int(a) - converts a to integer (if possible) and returns the value double(a) - converts a to double (if possible) and returns the value string(a) - converts a to string and returns the value date(a) - converts a to date
String functions:
length(a) - returns the length of the string substring(a,b,c) - equivalent to a.Substring(b,c) in .NET tolower(s) - returns s converted to lower-case toupper(s) - returns s converted to upper-case contains(str,subs) - returns true when subs is a substring of str indexof(a,b) - equivalent to a.IndexOf(b) in .NET padleft(a,b,c) - equivalent to a.PadStart(a,b,c) in .NET padright(a,b,c) - equivalent to a.PadEnd(a,b,c) in .NET trim(a) - equivalent to a.Trim() in .NET trimstart(a) - equivalent to a.TrimStart() in .NET trimend(a) - equivalent to a.TrimEnd() in .NET
Math functions:
round(v) floor(v) ceiling(v) abs(v)
File functions:
getcreationtime(filename) getlastwritetime(file) getlastaccesstime(file) fileexists(file) filesize(file)
Date functions:
now() datediff(d1,d2) - returns date difference in seconds dateadd(d1,seconds) - returns d1 + seconds
Here are some examples of things that are known to work, taken from my unit tests:
Assert("1+2", 3);
Assert("1+2+3", 6);
Assert("1+2*3", 7);
Assert("2*1*3", 6);
Assert("1/2+3", 3);
Assert("5.0/(2+8)", 0.5);
Assert("double(5)/(2+8)", 0.5);
Assert("double(1)/2+3", 3.5);
Assert("((((1))))", 1);
Assert("((((1+2))))", 3);
Assert("((((1+2)+(2+1))))", 6);
Assert("((((1+2)/(2+1))))", 1);
Assert("length('')", 0);
Assert("length('')=0", true);
Assert("length('')=1", false);
Assert("length('test')", 4);
Assert("length('test')=4", true);
Assert("length('test')=5", false);
Assert("length('d''Artagnan')", 10);
Assert("length('d''Artagnan')=10", true);
Assert("length('d''Artagnan')=11", false);
Assert("-1", -1);
Assert("--1", 1);
Assert("'a' = 'a'", true);
Assert("'a' = 'b'", false);
Assert("'a' <> 'a'", false);
Assert("'a' <> 'b'", true);
Assert("1 = 1", true);
Assert("1 <> 1", false);
Assert("1 = 2", false);
Assert("1 <> 2", true);
Assert("1.0 = 1.0", true);
Assert("1.0 <> 1.0", false);
Assert("1.0 = 2.0", false);
Assert("1.0 <> 2.0", true);
Assert("true", true);
Assert("false", false);
Assert("true==true", true);
Assert("true==false", false);
Assert("true<>false", true);
Assert("true<>true", false);
Assert("!true", false);
Assert("!false", true);
Assert("!(1=1)", false);
Assert("substring('abcde',1,2)='bc'", true);
Assert("trim(' ab ')='ab'", true);
Assert("trimstart(' ab ')='ab '", true);
Assert("trimend(' ab ')=' ab'", true);
Assert("padleft('ab',5,'.')='...ab'", true);
Assert("padright('ab',5,'.')='ab...'", true);
Assert("indexof('abc','c')=2", true);
Assert("indexof('abc','d')=-1", true);
Assert("indexof('abc','d')=-1", true);
Assert("round(0.1)", 0.0);
Assert("round(0.7)", 1.0);
Assert("floor(0.1)", 0.0);
Assert("floor(0.7)", 0.0);
Assert("ceiling(0.1)", 1.0);
Assert("ceiling(0.7)", 1.0);
Assert("if(true,1,2)", 1);
Assert("if(true,'a','b')", "a");
Assert("if(false,'a','b')", "b");
Assert("abs(1)", 1.0);
Assert("abs(-1)", 1.0);
Assert("fileexists('c:\\notthere.txt')", false);
Assert("dateadd(${somedate},3600) = ${someotherdate}", true);
Assert("'a' + 'b' = 'ab'", true);
--
Ian MacLean, Developer, ActiveState, a division of Sophos
http://www.ActiveState.com
------------------------------------------------------- This SF.net email is sponsored by: SF.net Giveback Program. Does SourceForge.net help you be more productive? Does it help you create better code? SHARE THE LOVE, and help us help YOU! Click Here: http://sourceforge.net/donate/ _______________________________________________ nant-developers mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/nant-developers