Math::Script NSIS plugin.

Another huge, undocumented, bug-full, but "might be useful" plugin.

C-like style scripting (operators at least).
Tip1: plugin watches the case of the letters.
Tip2: plugin makes almost no error checks. So YOU should check your script
twice before run :)

New HOW TO USE: run the MathTest.Exe, and try yourself. After spending 
some minutes your should be able to write your script by yourself.
To include it to your NSIS script just insert that (don't forget /NOUNLOAD
in case of multiple calls): 
        Math::Script /NOUNLOAD "YourScript1"
        Math::Script /NOUNLOAD "YourScript2"
        Math::Script "YourScriptFinal"

How to use it? Simple:
        Strcpy $0 "Brainsucker"
        Math::Script "a = 'Math'; B = 'Script'; r0 += ' wants to use ' + a + '::' + b +'!'"
        DetailPrint "$0"
That string will fill r0 with some shit. 

Here are some other samples:
        10! (factorial, r0 will contain '10! = 362880'):
                r0 = '10! = ' + (1*2*3*4*5*6*7*8*9)
        the same:
                a = b = 1; {++a <= 10, b = b*a}; r0 = (a-1) + '! = ' + b
        Some floating point:
                Strcpy $R0 "1e1"
                Math::Script "pi = 3.14159; R1 = 2*pi*R0; r0 = 'Length of circle with radius ' + R0 + ' is equal to ' + R1 + '.'"
                Detailprint "$0"        

Ok. Variables. 
NSIS: r0-r9 -> $0-$9. R0-R9 -> $R0-$R9. 
Also CL ($CMDLINE), ID ($INSTDIR), OD ($OUTDIR), LG ($LANG), ED ($EXEDIR).
User definable: name starting from character, up to 28 letters long.

Stacks. Two stacks are supported: NSIS stack and plugin's own stack. I see no 
reasons for using plugin stack, but if you will, remember - the plugin stores
variables used at function to that stack before function execution, and restores
after execution. Even less I recommend you to use NSIS stack. You should use it
only for input/output.
How to use? It's variable styled. Plugins stack is associated with S variable,
and NSIS stack associated with NS variable. To push to stack just do "S=0" or
"NS=0", to pop from stack "a=S" or "b=NS". Combined operations supported too: 
"S += 1.5" will increment value at the top of stack by 1.5.

Supported types: int (in fact that is __int64), float (double in fact),
string.
Int: just numbers, may include sign.
Float: -123.456, 123.456e-78, 123e-45
String: something in quotes ("", '', ``).

There is also an array type. It is actually a reference type, so if b is array
and you will perform "a=b", the a and b will reference a single array.
To create a copy of array, use ca func: dest = ca(source). Btw - you couldn't
control dimensions of array - they are autosized.
To declare array:
array{};
To declare array and initialize some items with values:
array{"Hello!", "Use", "mixed types", 1.01e23, "like that" ,1234};
To access array:
array[index] = "Cool";

The function could be useful - is conversion of arrays to strings and back.
Example:
a = a("Hello"); str = s(a);
After running such script array a will contain 6 integers (chars and last zero 
- end of string), and str will contain your string back.

Operators (some binary, some unary):
>>= <<= -= += /= *= |= &= ^= %= -- ++ >> << && || <= =< >= => != ==
= + - * / % < > & | ^ ~ !
Only some are applicable to float (logic & arithmetic) and string (+ and logic) 
of course.

Script is set of expressions (mathematical in general) delimeted with ';'.
Processing is not mathematicaly right (2+2*2 will give 8, not 6), so use round
brakes (for ex: 2+(2*2) ).

Flow control:
        if-then-else like:      [if-expression, then-expr, else-expr]
                example:
                        [a==0, b=1; c=2, b *= (--c); c/=10]               
                C eq:
                        if (a==0) { b=1; c=2;} else { b*=(c++);c-=10; }
        while (expr) do; like    {expr, do}
                example:
                        {(c<1.1e25)&&(b < 10), b++; c*=1.23}
                C eq:
                        while ((c<1.1e25)&&(b<10)) { b++; c*=1.23; }

WATCH OUT! Comma (,) separates if-expr, then-expr, and else-expr from each 
other. All sub-expressions separated by (;) are the part of one expression,
and the result of the last one of these sub-exprs gives you the result of 
expression.

All the shit (like variables and functions) will be saved between calls if 
you'll use /NOUNLOAD or setpluginunload alwaysoff.

Functions:
        type conversions:
                len(string)     returns the length of string or array argument
                s(source)       converts source to string type
                i(source)       converts source to int type
                f(source)       converts source to float type
                a(source)       converts source to array (only string supported)
                ff(float, format)       converts float to string, with format
                                        options.
                        options = precision + flags.
                        Precision shows how many digits after decimal point
                        will be shown. Flags:
                                16 (or 0x10) - No Exponential View 
                                        (number will be shown as 123.123)
                                32 (or 0x20) - Only exponential view
                                        (number will be shown as 123.12e123)
                                64 (or 0x40) - use 'E' character instead of 'e' 
                        By default the plugin decides itself how to show your
                        number.

        math (description of all these functions is available at MSDN, use the
            second given name for search):
                sin(x),         sin     Sine of argument
                cos(x),         cos     Cosine of argument
                cel(x),         ceil    Ceil of argument (no fract. part) 
                csh(x),         cosh    Hyperbolic Cosine of Argument        
                exp(x),         exp     Exponential
                abs(x),         abs     Absolute value (warning: float)
                flr(x),         floor   Floor of argument (no fract. part) 
                asn(x),         asin    ArcSine of argument
                acs(x),         acos    ArcCosine of argument
                atn(x),         atan    ArcTangent of argument
                ln(x),          log     Exponential Logarithm
                log(x),         log10   Decimal logarithm
                snh(x),         sinh    Hyperbolic Sine of Argument
                sqt(x),         sqrt    Square root of argument
                tan(x),         tan     Tangent of argument
                tnh(x),         tanh    Hyperbolic tangent  of argument

          functions taking two arguments
                at2(x, y)       atan2    Arctangent of the value (y/x)
                pow(x, y)       pow      power, x^y
                fmd(x, y)       fmod     floating point remainder
                fex(x, o)       frexp    Gets the mantissa (result = r) 
                                        and exponent (o) of floating-point 
                                        number (x): x = r*(2^o)
                mdf(x, o)       modf    Splits a floating-point value into 
                                        fractional and integer parts.

User-defined functions.
It's very simple. Example:
        test(a,b)a+b;
After that test(1,2) will give you 3. If you need more than one expression, use
round brakes:
        test2(a,b) (a=a+b; b *= a);
The result of function is always the result of last expression.
As said before it better not to use stack (S) in between function calls.
It will be better to develop variable-safe functions, i.e. functions which will
not corrupt variables. For this you should either push/pop them to stack, or
declare as additional arguments, which will never be used. Example:
        test3(a,b,c) (c=10; {--c > 0, a=sqrt(a*b)}; a)
No matter how many arguments will be passed to function all three vars will be
saved. 
Such variable-safe functions could be recursive:
        Math::Script /NOUNLOAD 'rec(a) ([a > 0, rec(a-1), 0]+a);'
        Math::Script 'R1 = rec(10)'
will set R1 to right result 55.
Sometimes functions will need to return more than one value, in this case you
could declare argument as referent (b at example):
        test4(a, &b) (*b = a*a; a*a*a)
In this case test4 will return a^3, and if we will call it like that test4(a,c),
it will place a^2 to c. BUT! Note: you should use de-referencer (*) with variable,
at example *b. CAUTION: never use the same variable as function internal reference
variable and external argument variable (for example test4(a,b)). It will surely 
fail. Also: if you declared argument as reference - you should never supply
a constant expression to it. It could be either array item (array[1]), NSIS
register R0, and of the user variables (beside the variable with the same name:)
, but never the constant.
        
(c) Nik Medved (brainsucker)