Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
UppHub
Status & Roadmap
FAQ
Authors & License
Forums
Funding U++
Search on this site











SourceForge.net Logo

SourceForge.net Logo

GitHub Logo

Discord Logo

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.

 

Do you want to contribute?