Esc scripting language
Esc is a simple scripting language intended for embedding in Ultimate++ applications.
It is typeless, value oriented language with simple interfacing with C++/U++ code. It is very simple yet quite complete language.
Value types
voids
All variables have void value before assigned any other value. Void type has single value
void
and expression can be tested for voidness using is_void function.
numbers
Number is floating point number (corresponding to C type double). Examples of number literals:
1
1.123
1.123e96
0x123 // hexadecimal
0123 // octal
0b10100100 // binary
'x' // character code
Esc supports common Clike operations for number values.
arrays
Arrays are ordered random access sequences of other Esc values (nested arrays included). Array values are specified using [] brackets:
[] // empty array
[ 1, 2, 3, 4, 5 ]
[ 1, [2, 3], 4 ] // array contains nested array
"Hello" // equivalent to ['H', 'e', 'l', 'l', 'o']
[ 1, 2, 3 * alfa ] // expressions can be used as well
Number of elements in the array can be retrieved by standard function count.
Accessing elements of arrays is provided by subscript [ ] operator:
a[0]
a[1] = 3
First element of array corresponds to index [0].
Negative indexes are allowed and designate elements from the end of array: [1] is last element of array, [2] last but one etc.
a[1]
is equivalent to
a[count(a)  1]
When index is used for the rvalue (standing on the right side of =), index is range checked. For lvalue, if nonnegative index designates element past the of the array, array is expanded with void values to create this element.
"Empty" index [] designates element past last and can be used to add elements to the array:
x[] = item
is equivalent to
x[count(x)] = item
Range of element in array can be obtained or changed using slices:
array[pos, count]
designates array slice of count elements starting with pos element.
x[start:end]
designates array slice of end  start elements starting with start .
Parts of slices can be ommited
array[pos,]
or
array[pos:]
is equivalent to
array[pos : count(array)]
and
array[,count]
or
array[:count]
is equivalent to
array[0, count]
When slices are used as lvalue, corresponding part of the array is replaced:
s = "1234";
s[1: 1] = "xXx"; // s is now "1xXx4"
Several operators can be applied to arrays
array1 + array2
concatenates two arrays,
array * number
number * array
repeats array number times.
array += array1
is equivalent to
array = array + array1
also
array << array1 << array2 << array3
is equivalent to
array = array + array1 + array2 + array3
Esc allows void value on the right side of array concatenation expression  in such cases, operator has no effect.
maps
Maps contain keyvalue pairs as entries. Normal subscripts [] are used to access map entries:
map[key] = value
All entries in map that are not assigned a nonvoid value have void value. This way assigning void to the map key can be considered as removing entry from the map
map[key] = void
and testing entry for being void can be considered as test of key presence in map:
if(is_void(map[key])) { ... }
As the special exception, when a void value appears before an lvalue [], it is changed to the empty map:
x = void; // x is void
x[key] = value; // x is now map
Maps are also used to create compound data structures. To make this job easier, special .field syntax is supported:
x.field = value;
is equivalent to
x["field"] = value;
Map values can also be specified using {} braces:
{} // empty map
{ "alfa":10, "beta":20, 20:"40" }
{ 2 * a : "100" } // map values can contain expressions
lambdas
Lambdas represent executable Esc code. Lambda values are introduced using @ character:
@(x) { return 2 * x; }
Assigning lambda value to variable is equivalent to defining a function:
:foo = @(x) { return 2 * x; }; // defines global function foo
If lambda argument is preceded with & character, it designates inputoutput argument (other arguments are input only).
... at the end of the argument list allows variable number of arguments to be present. In that case, additional parameters are passed in argv variable of type array.
:sum = @(...) { s = 0; for(i in argv) s += argv[i]; }
Parameters can have default values separated by =:
:bar = @(x = 0) { ... }
To make life easier, alternative form of function definition is available:
#:foo(x) { return 2 * x; }
Variables and contexts
Variable names in Esc follow C principles (are case sensitive, start with alphabetic character or _ and can contain alphabetic characters, _ and numbers).
Esc distinguishes three types of variables contexts using . and : characters:
var // local
.var // instance
:var // global
Local variables are specific to function, global variables are shared among all functions. Instance variables
represent map values (keys designate variable names) of map whose lambda value is invoked, or can be forced using binary ! bind operator:
var.x = 0;
var.Next = @() { .x++; };
var.Next(); // var.x is now 1
var1.x = 0;
var.Next()! var1; // var1.x is now 1
To make programmer's life easier, one exception applies concerning context  when invoking lambda from local variable and lambda is not present in it, instance and global contexts (in this order) are tried as well:
beta(x)
Tries to get lambda form local beta variable first, then (if no lambda found) from instance beta variable and finally (if still no lambda) from global beta. Of course, . and : can still be used to designate context:
:beta(x) // calls global beta even if local or instance beta is present
Expressions
When expressions are used as logical values, void, zero number and map or array with zero elements represent false, other values are true.
In following table, thick lines divide operators with the same priority, with topmost items having the highest priority:
Operator

Comments

map[key]

Map value at key.

map.field

Same as map["field"].

array[index]

Array element at position index.

array[start, count]

Array slice starting at start of count elements.

array[start:end]

Array slice of elements start .. end  1

array[,count]
array[:count]

Same as array[0, count].

array[start:]
array[start,]

Same as array[start : count(array)].

lambda(args)

Invokes lambda with the set of args. If lambda is subscript of the map, map becomes instance for lambda execution (accessible via .name or self).

lambda(args) ! instance

Invokes lambda, using instance as instance for lambda execution (accessible via .name or self).

self

Instance.

++lnumber
lnumber

Increments/decrements number lvalue.

number

Unary minus.

~number

Bitwise complement.

!value

Logical not. 1 when value represents false, 0 otherwise.

lnumber
lnumber++

Postincrement / postdecrement of number lvalue.

array * number
number * array

Returns array repeated number times.

number * number

Multiplication.

number / number

Division.

number % number

Modulo.

array + array

Concatenates arrays.

number + number

Addition.

number  number

Subtraction.

larray << array

Concatenates array to larray, yielding larray as lvalue result.

number << number

Shift left.

number >> number

Shift right.

number < number
number > number
number <= number
number >= number

Comparison of numbers.

array < array
array > array
array <= array
array >= array

Comparison of arrays.

value == value

Equality.

value != value

Inequality.

number & number

Binary and.

number ^ number

Binary xor.

number  number

Binary or.

value && value

Logical and. If first value is false, second value is not evaluated, just skipped.

value  value

Logical or. If first value is true, second value is not evaluated, just skipped.

value ? value : value

Conditional expression. Only necessary expressions are evaluated.

lvalue = value

Assignment.

larray += array

Same as larray = larray + array.

lnumber += number

Same as lnumber = lnumber + number.

lnumber = number

Same as lnumber = lnumber  number.

lnumber *= number

Same as lnumber = lnumber * number.

lnumber /= number

Same as lnumber = lnumber / number.

lnumber %= number

Same as lnumber = lnumber % number.


Statements
Statement

Comments

;

Empty statement.

expression;

Expression. It gets evaluated.

{ statement; ... }

Compound statement.

if(condition) statement

Conditional statement.

if(condition) statement
else statement

Conditional statement with

while(condition) statement

Loop. Statement is performed as long as the condition is true.

do statement
while(condition)

Loop. Statement is performed once and then is repeated as long as the condition is true.

for(init, condition, increment)
statement

Same as
init;
while(condition) {
statement;
increment;
}

for(lvalue in array)
statement

Same as
for(lvalue = 0; lvalue < count(array);
lvalue++)
statement

for(lvalue in map)
statement

Iterates through map, assigning keys of elements with nonvoid value to the lvalue.

continue

Skips the rest of loop statement.

break

Causes exit from innermost loop or switch statement.

switch(value) statement

Matches value to all case statements inside the statement, continues at the case with the same value, or with default if no such case exists and default is present. If neither matching case and default exists, does nothing.

case value:

Switch case.

default:

Default switch case.

#name(args) { ... }

Same as name = @(args) { ... };

#.name(args) { ... }

Same as .name = @(args) { ... };

#:name(args) { ... }

Same as :name = @(args) { ... };


Standard library
Function

Comments

is_number(x)

Returns 1 if x is a number, 0 otherwise.

is_array(x)

Returns 1 if x is a array, 0 otherwise.

is_map(x)

Returns 1 if x is a map, 0 otherwise.

is_void(x)

Returns 1 if x is void, 0 otherwise.

int(number)

Returns the number rounded towards zero.

to_string(x)

Return x as array representing string representation.

to_number(x)

Converts an array (string) to the number.

count(x)

If x is void, returns 0.
If x is a number, returns 1.
If x is an array, returns number of elements of this array.
If x is an map, returns number of entries in this map with nonvoid values.

keys(map)

Returns array of keys of map (ordering is the same as for values function, otherwise is unspecified).

values(map)

Returns array of values of map (ordering is the same as for keys function, otherwise is unspecified).

rand()

Returns random number in range 0..32767.

reverse(array)

Returns reversed array.

sort(array)

Returns sorted array.

order(array)

Returns sort order of elements in the array.

IsDate(map)

Returns 1 if map contains "day", "month" and "year" keys, 0 otherwise.

IsTime(map)

Returns 1 if map contains "second", "minute", "hour", "day", "month" and "year" members, 0 otherwise.

GetSysTime()

Returns current time as map with "second", "minute", "hour", "day", "month" and "year" members.

sin(x)
cos(x)
tan(x)
asin(x)
acos(x)
atan(x)
atan2(a, b)
sinh(x)
cosh(x)
tanh(x)
asinh(x)
acosh(x)
atanh(x)
exp(x)
log(x)
log10(x)
exp2(x)
log2(x)
sqrt(x)
cbrt(x)
pow(base, exp)

Well know mathematical functions.


