Esc scripting language
Table of contents
1. Introduction
2. Value types
2.1 Voids
2.2 Numbers
2.3 Arrays
2.4 Maps
2.5 Lambdas
3. Variables and contexts
4. Expressions
5. Statements
6. Standard library
1. Introduction
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.
2. Value types
2.1 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.
2.2 Numbers
Number is floating point number (corresponding to C type double). Examples of number literals:
1
1.123
1.123e-96
0x123 // hexadecimal
0123 // octal
0b10100100 // binary
'x' // character code
Esc supports common C-like operations for number values.
2.3 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 r-value (standing on the right side of =), index is range checked. For l-value, if non-negative 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 omitted
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 l-value, 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.
2.4 Maps
Maps contain key-value pairs as entries. Normal subscripts [] are used to access map entries:
map[key] = value
All entries in map that are not assigned a non-void 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 l-value [], 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
2.5 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 input-output 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; }
3. 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
4. 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.
|
++l-number
--l-number
|
Increments/decrements number l-value.
|
-number
|
Unary minus.
|
~number
|
Bit-wise complement.
|
!value
|
Logical not. 1 when value represents false, 0 otherwise.
|
l-number--
l-number++
|
Post-increment / post-decrement of number l-value.
|
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.
|
l-array << array
|
Concatenates array to l-array, yielding l-array as l-value 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.
|
l-value = value
|
Assignment.
|
l-array += array
|
Same as l-array = l-array + array.
|
l-number += number
|
Same as l-number = l-number + number.
|
l-number -= number
|
Same as l-number = l-number - number.
|
l-number *= number
|
Same as l-number = l-number * number.
|
l-number /= number
|
Same as l-number = l-number / number.
|
l-number %= number
|
Same as l-number = l-number % number.
|
|
5. 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(l-value in array)
statement
|
Same as
for(l-value = 0; l-value < count(array);
l-value++)
statement
|
for(l-value in map)
statement
|
Iterates through map, assigning keys of elements with non-void value to the l-value.
|
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) { ... };
|
|
6. 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 non-void 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.
|
|
|