Next

Prev

Prev-tail

Tail

Up

Chapter 18
urbiscript Language Reference Manual

 18.1 Syntax
  18.1.1 Characters, encoding
  18.1.2 Comments
  18.1.3 Synclines
  18.1.4 Identifiers
  18.1.5 Keywords
  18.1.6 Literals
  18.1.7 Statement Separators
  18.1.8 Operators
 18.2 Scopes and local variables
  18.2.1 Scopes
  18.2.2 Local variables
 18.3 Functions
  18.3.1 Function Definition
  18.3.2 Arguments
  18.3.3 Return value
  18.3.4 Call messages
  18.3.5 Strictness
  18.3.6 Lexical closures
 18.4 Objects
  18.4.1 Slots
  18.4.2 Prototypes
  18.4.3 Sending messages
 18.5 Imperative flow control
  18.5.1 break
  18.5.2 continue
  18.5.3 do
  18.5.4 if
  18.5.5 for
  18.5.6 if
  18.5.7 loop
  18.5.8 switch
  18.5.9 while
 18.6 Exceptions
  18.6.1 Throwing exceptions
  18.6.2 Catching exceptions
  18.6.3 Inspecting exceptions
 18.7 Assertions
 18.8 Parallel and event-based flow control
  18.8.1 at
  18.8.2 every
  18.8.3 for
  18.8.4 loop,
  18.8.5 waituntil
  18.8.6 whenever
  18.8.7 While
 18.9 Trajectories

18.1 Syntax

18.1.1 Characters, encoding

Currently urbiscript makes no assumptions about the encoding used in the programs, but the streams are handled as 8-bit characters.

While you are allowed to use whatever character you want in the string literals (especially using the binary escapes, Section 18.1.6.6), only plain ASCII characters are allowed in the program body. Invalid characters are reported, possibly escaped if they are not “printable”. If you enter UTF-8 characters, since they possibly span over several 8-bit characters, a single (UTF-8) character may be reported as several invalid (8-bit) characters.

 
#
t
; 
[00048238:error] !!! syntax error: invalid character: ‘#’ 
[00048239:error] !!! syntax error: invalid character: ‘\xc3 
[00048239:error] !!! syntax error: invalid character: ‘\x89 
[00048239:error] !!! syntax error: invalid character: ‘\xc3 
[00048239:error] !!! syntax error: invalid character: ‘\xa9  

18.1.2 Comments

Comments are used to document the code, they are ignored by the urbiscript interpreter. Both C ++ comment types are supported.

 
// C++ style comment 
/* C style comment */ 
/* These comments /* do */ nest */  

18.1.3 Synclines

While the interaction with an urbiscript kernel is usually performed via a network connection, programmers are used to work with files which have names, line numbers and so forth. This is most important in error messages. Since even loading a file actually means sending its content as if it were typed in the network session, in order to provide the user with meaningful locations in error messages, urbiscript features synclines, a means to change the “current location”, similarly to #line in C-like languages. This is achieved using special //# comments.

The following special comments are recognized only as a whole line. If some component does not match exactly the expected syntax, or if there are trailing items, the whole line is treated as a comment.

18.1.4 Identifiers

Identifiers in urbiscript are composed of one or more alphanumeric or underscore (_) characters, not starting by a digit, i.e., identifiers match the [a-zA-Z_][a-zA-Z0-9_]* regular expression. Additionally, identifiers must not match any of the urbiscript reserved words1 documented in Section 18.1.5. Identifiers can also be written between simple quotes (), in which case they may contain any character.

 
var x; 
var foobar51; 
var this.a_name_with_underscores; 
// Invalid. 
// var 3x; 
// obj.3x(); 
 
// Invalid because "if" is a keyword. 
// var if; 
// obj.if(); 
// However, keywords can be escaped with simple quotes. 
var if’; 
var this.’else’; 
 
// Identifiers can be escaped with simple quotes 
var ’%x’; 
var ’1 2 3’; 
var this.’[]’;  

18.1.5 Keywords

Keywords are reserved words that cannot be used as identifiers, for instance. They are listed in Section 18.1.






Keyword Remark Keyword Remark




and

Synonym for

&&

long

Reserved

and_eq

Synonym for

&=

loop

loop& and

loop| flavors

asm

Reserved

loopn

Deprecated, use

for

at

mutable

Reserved

auto

Reserved

namespace

Reserved

bitand

Synonym for

& operator

new

bitor

Synonym for

| operator

not

Synonym for

! operator

bool

Reserved

not_eq

Synonym for

!= operator

break

object

call

onleave

case

or

Synonym for

|| operator

catch

Reserved

or_eq

Synonym for

|= operator

char

Reserved

private

Ignored

class

protected

Ignored

closure

public

Ignored

compl

Synonym for

~

register

Reserved

const

Reserved

reinterpret_cast

Reserved

const_cast

Reserved

return

continue

short

Reserved

default

Reserved

signed

Reserved

delete

sizeof

Reserved

do

static

Deprecated

double

Reserved

static_cast

Reserved

dynamic_cast

Reserved

stopif

else

struct

Reserved

emit

Deprecated

switch

enum

Reserved

template

Reserved

this

every

throw

Reserved

explicit

Reserved

timeout

export

Reserved

try

Reserved

extern

Reserved

typedef

Reserved

external

typeid

Reserved

float

Reserved

typename

Reserved

for

for& and

for| flavors

union

Reserved

foreach

Deprecated, use

for

unsigned

Reserved

freezeif

using

Reserved

friend

Reserved

var

from

virtual

Reserved

function

volatile

Reserved

goto

Reserved

waituntil

if

wchar_t

Reserved

in

whenever

inline

Reserved

while

while& and

while| flavors

int

Reserved

xor

Synonym for

^ operator

internal

Deprecated

xor_eq

Synonym

^= operator






Table 18.1: Keywords

18.1.6 Literals

18.1.6.1 Angles

Angles are floats (see Section 18.1.6.4) followed by an angle unit. They are simply equivalent to the same float, expressed in radians. For instance, 180deg (180 degrees) is equal to pi. Available units and their equivalent are presented in Section 18.2.





unit abbreviation equivalence for n



radian rad n
degree deg n∕180 * π
grad grad n∕200 * π




Table 18.2: Angle units

 
pi == 180deg; 
pi == 200grad;  
18.1.6.2 Dictionaries

Literal dictionaries are represented with a comma-separated, potentially empty list of arbitrary associations enclosed in square brackets ([]), as shown in the listing below. Empty dictionaries are represented with an association arrow between the brackets to avoid confusion with empty lists. See Dictionary (Section 19.10) for more details.

Each association is composed of a key, which is represented by a string, an arrow (=>) and an expression.

 
[ => ]; // The empty dictionary 
[00000000] [ => ] 
["a" => 1, "b" => 2, "c" => 3]; 
[00000000] ["a" => 1, "b" => 2, "c" => 3]  

18.1.6.3 Durations

Durations are floats (see Section 18.1.6.4) followed by a time unit. They are simply equivalent to the same float, expressed in seconds. For instance, 1s 1ms, which stands for “one second and one millisecond”, is strictly equivalent to 1.0001. Available units and their equivalent are presented in Section 18.3.





unit abbreviation equivalence for n



millisecond ms n∕1000
second s n
minute min n × 60
hour h n × 60 × 60
day d n × 60 × 60 × 24




Table 18.3: Duration units

 
1d == 24h; 
1h == 60min; 
1min == 60s; 
1s == 1000ms; 
 
1s == 1; 
1s2s3s == 6; 
1s 2s 3s == 6; 
1s 1ms == 1.001; 
1ms 1s == 1.001;  
18.1.6.4 Floats

urbiscript supports the scientific notation for floating-point literals. See Float (Section 19.18) for more details. Examples include:

 
            1 == 1; 
            1 == 1.0; 
          1.2 == 1.2000; 
      1.234e6 == 1234000; 
        1e+11 == 1E+11;  

Numbers are displayed rounded by the top level, but internally, as seen above, they keep their accurate value.

 
0.000001; 
[00000011] 1e-06 
 
0.0000001; 
[00000012] 1e-07 
 
0.00000000001; 
[00000013] 1e-11 
 
1e+3; 
[00000014] 1000 
 
1E-5; 
[00000014] 1e-05  

In order to make numbers with units (1cm) and calling a method on a number (1.cm), numbers that include a period must have a fractional part. In other words, 1., if not followed by digits, is available read as 1 .:

 
1.; 
[00004701:error] !!! syntax error: unexpected ;  

Hexadecimal notation is supported for integers: 0x followed by one or more hexadecimal digits, whose case is irrelevant.

 
    0x2a == 42; 
    0x2A == 42; 
0xabcdef == 11259375; 
0xABCDEF == 11259375  

18.1.6.5 Lists

Literal lists are represented with a comma-separated, potentially empty list of arbitrary expressions enclosed in square brackets ([]), as shown in the listing below. See List (Section 19.27) for more details.

 
[]; // The empty list 
[00000000] [] 
[1, 2, 3]; 
[00000000] [1, 2, 3]  

18.1.6.6 Strings

String literals are enclosed in double quotes (") and can contain arbitrary characters, which stand for themselves, with the exception of the escape character, backslash (\), see below. The escapes sequences are defined in Section 18.4.




\\

backslash

\"

double-quote

\a

bell ring

\b

backspace

\f

form feed

\n

line feed

\r

carriage return

\t

tabulation

\v

vertical tabulation

\[0-7]{1,3}

eight-bit character corresponding to a one-, two- or three-digit octal number. For instance, \0, \000 and 177. The matching is greedy: as many digits as possible are taken: \0, \000 are both resolved in the null character.

\x[0-9a-fA-F]{2}

eight-bit character corresponding to a two-digit hexadecimal number. For instance, 0xfF.

\B(length)(content)

binary blob. A length-long sequence of verbatim content. length is expressed in decimal. content is not interpreted in any way. The parentheses are part of the syntax, they are mandatory. For instance \B(2)(\B)




Table 18.4: String escapes

 
// Special characters. 
"\"" == "\""; 
"\\" == "\\"; 
 
// ASCII characters. 
"\a" == "\007"; "\a" == "\x07"; 
"\b" == "\010"; "\b" == "\x08"; 
"\f" == "\014"; "\f" == "\x0c"; 
"\n" == "\012"; "\n" == "\x0a"; 
"\r" == "\015"; "\r" == "\x0d"; 
"\t" == "\011"; "\t" == "\x09"; 
"\v" == "\013"; "\v" == "\x0b"; 
 
// Octal escapes. 
"\0" == "\00"; "\0" == "\000"; 
"\0000" == "\0""0"; 
"\062\063" == "23"; 
 
// Hexadecimal escapes. 
"\x00" == "\0"; 
"\x32\x33" == "23"; 
 
// Binary blob escape. 
"\B(3)("\")" == "\"\\\"";  

Consecutive string literals are glued together into a single string. This is useful to split large strings into chunks that fit usual programming widths.

 
"foo" "bar" "baz" == "foobarbaz";  

The interpreter prints the strings escaped; for instance, line feed will be printed out as \n when a string result is dumped and so forth. An actual line feed will of course be output if a string content is printed with echo for instance.

 
""; 
[00000000] "" 
"foo"; 
[00000000] "foo" 
"a\nb"; // urbiscript escapes string when dumping them 
[00000000] "a\nb" 
echo("a\nb"); // We can see there is an actual line feed 
[00000000] *** a 
b 
echo("a\\nb"); 
[00000000] *** a\nb  

See String (Section 19.53) for more details.

18.1.6.7 Tuples

Literal tuples are represented with a comma-separated, potentially empty list of arbitrary elements enclosed in parenthesis (()), as shown in the listing below. One extra comma can be added after the last element. To avoid confusion between a 1 member Tuple and a parenthesized expression, the extra comma must be added. See Tuple (Section 19.60) for more details.

 
(); 
[00000000] () 
(1,); 
[00000000] (1,) 
(1, 2); 
[00000000] (1, 2) 
(1, 2, 3, 4,); 
[00000000] (1, 2, 3, 4)  

18.1.7 Statement Separators

Sequential languages such as C ++ support a single way to compose two statements: the sequential composition, “denoted” by ‘;’. To support concurrency and more fined tuned sequentiality, urbiscript features four different statement-separators (or connectors):

;
sequentiality
|
tight sequentiality
,
background concurrency
&
fair-start concurrency

18.1.7.1 ;

The ‘;’-connector waits for the first statement to finish before starting the second statement. When used in the top-level interactive session, both results are displayed.

 
1; 2; 3; 
[00000000] 1 
[00000000] 2 
[00000000] 3  

18.1.7.2 ,

The ‘,’-connector sends the first statement in background for concurrent execution, and starts the second statement when possible. When used in interactive sessions, the value of back-grounded statements are not printed — the time of their arrival being unpredictable, such results would clutter the output randomly. Use Channels (Section 19.5) or Events (Section 19.13) to return results asynchronously.

 
{ 
  for (3) 
  { 
    sleep(1s); 
    echo("ping"); 
  }, 
  sleep(0.5s); 
  for (3) 
  { 
    sleep(1s); 
    echo("pong"); 
  }, 
}; 
[00000316] *** ping 
[00000316] *** pong 
[00000316] *** ping 
[00000316] *** pong 
[00000316] *** ping 
[00000316] *** pong  

Both ‘;’ and ‘,’ have equal precedence. They are scoped too: the execution follow “waits” for the end of the jobs back-grounded with ‘,’ before proceeding. Compare the two following executions.

 
{ 
  sleep(100ms) | echo("1"), 
  sleep(400ms) | echo("2"), 
  echo("done"); 
}; 
[00000316] *** done 
[00000316] *** 1 
[00000316] *** 2  
 
{ 
  sleep(100ms) | echo("1"), 
  sleep(400ms) | echo("2"), 
}; 
echo("done"); 
[00000316] *** 1 
[00000316] *** 2 
[00000316] *** done  

18.1.7.3 |

When using the ‘;’ connector, the scheduler is allowed to run other commands between the first and the second statement. The ‘|’ does not yield between both statements. It is therefore more efficient, and, in a way, provides some atomicity for concurrent tasks.

 
{ 
  { echo("11") ; sleep(100ms) ; echo("12") }, 
  { echo("21") ; sleep(400ms) ; echo("22") }, 
}; 
[00000316] *** 11 
[00000316] *** 21 
[00000316] *** 12 
[00000316] *** 22  
 
{ 
  { echo("11") | echo("12") }, 
  { echo("21") | echo("22") }, 
}; 
[00000316] *** 11 
[00000316] *** 12 
[00000316] *** 21 
[00000316] *** 22  

In an interactive session, both statements must be “known” before launching the sequence. The value of the composed statement is the value of the second statement.

18.1.7.4 &

The ‘&’ is very similar to the ‘,’ connector, but for its precedence. Urbi expects to process the whole statement before launching the connected statements. This is especially handy in interactive sessions, as a means to fire a set of tasks concurrently.

18.1.8 Operators

urbiscript supports many operators, most of which are inspired from C ++. Their syntax is presented here, and they are sorted and described with their original semantics — that is, + is an arithmetic operator that sums two numeric values. However, as in C ++, these operators might be use for any other purpose — that is, + can also be used as the concatenation operator on lists and strings. Their semantics is thus not limited to what is presented here.

Tables in this section sort operators top-down, by precedence order. Group of rows (not separated by horizontal lines) describe operators that have the same precedence. Many operators are syntactic sugar that bounce on a method. In this case, the equivalent desugared expression is shown in the “Equivalence” column. This can help you determine what method to override to define an operator for an object (see Section 9.6).

This section defines the syntax, precedence and associativity of the operators. Their semantics is described in Section 19 in the documentation of the classes that provide them.

18.1.8.1 Arithmetic operators

urbiscript supports classic arithmetic operators, with the classic semantics on numeric values. See Section 18.5 and the listing below.







Operator Syntax Associativity Semantics Equivalence





+

+a

- Identity

a.’+’()

-

-a

- Opposite

a.’-’()






**

a ** b

Right Exponentiation

a.’**’(b)






*

a * b

Left Multiplication

a.’*’(b)

/

a / b

Left Division

a.’/’(b)

%

a % b

Left Modulo

a.’%’(b)






+

a + b

Left Sum

a.’+’(b)

-

a - b

Left Difference

a.’-’(b)






Table 18.5: Arithmetic operators

 
       1 + 1 ==    2; 
       1 - 2 ==   -1; 
       2 * 3 ==    6; 
      10 / 2 ==    5; 
     2 ** 10 == 1024; 
    -(1 + 2) ==   -3; 
   1 + 2 * 3 ==    7; 
 (1 + 2) * 3 ==    9; 
     -2 ** 2 ==   -4; 
   - - - - 1 ==    1;  
18.1.8.2 Assignment operators

Assignment in urbiscript can be performed with the = operator. Shorthands such as += exist; they are not redefinable since they are equivalent to a regular assignment combined with another operator. See Section 18.6 and the listing below.







Operator Syntax Associativity Semantics Equivalence





=

a = b

Right Assignment

updateSlot("a", b) 2

+=

a += b

Right In place assignment

a = a + b

-=

a -= b

Right In place assignment

a = a - b

*=

a *= b

Right In place assignment

a = a * b

/=

a /= b

Right In place assignment

a = a / b

%=

a %= b

Right In place assignment

a = a % b

^=

a ^= b

Right In place assignment

a = a ^ b






Table 18.6: Assignment operators

 
var y = 0; 
[00000000] 0 
y = 10; 
[00000000] 10 
y += 10; 
[00000000] 20 
y /= 5; 
[00000000] 4 
y++; 
[00000000] 4 
y; 
[00000000] 5  
18.1.8.3 Bitwise operators

urbiscript features bitwise operators. They are also used for other purpose than bit-related operations. See Section 18.7 and the listing below.







Operator Syntax Associativity Semantics Equivalence





<<

a << b

Left Left bit shift

a.’<<’(b)

>>

a >> b

Left Right bit shift

a.’>>’(b)






^

a ^ b

Left Bitwise exclusive or

a.’^’(b)






Table 18.7: Bitwise operators

 
4 << 2 == 16; 
4 >> 2 ==  1;  
18.1.8.4 Logical operators

urbiscript supports the usual Boolean operators. See the table and the listing below. The operators && and || are short-circuiting: their right-hand side is evaluated only if needed.







Operator Syntax Associativity Semantics Equivalence





!

!a

Left Logical negation

a.’!’()






&&

a && b

Left Logical and

a.’&&’(b)






||

a || b

Left Logical or

a.’||’(b)






Table 18.8: Boolean operators

 
true && true; 
true || false; 
!true == false; 
true || (1 / 0); 
(false && (1 / 0)) == false;  
18.1.8.5 Comparison operators

urbiscript supports classical comparison operators. See Section 18.9 and the listing below.







Operator Syntax Associativity Semantics Equivalence





==

a == b

None Equality

a.’==’(b)

!=

a != b

None Inequality

a.’!=’(b)

===

a === b

None Physical equality

a.’===’(b)

!==

a !== b

None Physical inequality

a.’!==’(b)

~=

a ~= b

None Relative approximate equality

a.’~=’(b)

=~=

a =~= b

None Absolute approximate equality

a.’=~=’(b)

<

a < b

None Less than

a.’<’(b)

<=

a <= b

None Less than or equal to

a.’<=’(b)

>

a > b

None Greater than

a.’>’(b)

>=

a >= b

None Greater than or equal to

a.’>=’(b)






Table 18.9: Comparison operators

 
assert 
{ 
 ! (0 < 0); 
    0 <= 0; 
    0 == 0; 
   0 !== 0; 
}; 
var z = 0; 
[00000000] 0 
assert 
{ 
  z === z; 
  ! (z !== z); 
};  
18.1.8.6 Container operators

These operators work on containers and their members. See Section 18.10.







Operator Syntax Associativity Semantics Equivalence





in

a in b

- Membership

b.has(a)

not in

a not in b

- Non-membership

! b.has(a)






[]

a[args]

- Subscript

a.’[]’(args)

[] =

a[args] = v

- Subscript assignment

a.’[]=’(args, v)






Table 18.10: Container operators

The in and not in operators test the membership of an element in a container. They bounce to the container’s has method. They are non-associative.

 
1     in [0, 1, 2]; 
3 not in [0, 1, 2]; 
 
"one"   in     ["zero" => 0, "one" => 1, "two" => 2]; 
"three" not in ["zero" => 0, "one" => 1, "two" => 2];  

The following operators use an index. Note that the subscript (square bracket) operator is variadic: it takes any number of arguments that will be passed to the ’[]’ method of the targeted object.

 
// On lists. 
var l = [1, 2, 3, 4, 5]; 
[00000000] [1, 2, 3, 4, 5] 
assert 
{ 
  l[0] == 1; 
  l[-1] == 5; 
  (l[0] = 10) == 10; 
  l == [10, 2, 3, 4, 5]; 
}; 
 
// On strings. 
var s = "abcdef"; 
[00000005] "abcdef" 
assert 
{ 
  s[0] == "a"; 
  s[1,3] == "bc"; 
  (s[1,3] = "foo") == "foo"; 
  s == "afoodef"; 
};  
18.1.8.7 Object operators

These core operators provide access to slots and their properties. See Section 18.11.







Operator Syntax Associativity Semantics Equivalence





.

a.b

- Message sending

Not redefinable

.

a.b(args)

- Message sending

Not redefinable






->

a->b

- Property access

getProperty("a", "b")

->

a->b = v

- Property assignment

setProperty("a", "b", v)






Table 18.11: Object operators

18.1.8.8 All operators summary

Section 18.12 is a summary of all operators, to highlight the overall precedences. Operators are sorted by decreasing precedence. Groups of rows represent operators with the same precedence.







Operator Syntax Associativity Semantics Equivalence





.

a.b

- Message sending

Not redefinable

.

a.b(args)

- Message sending

Not redefinable






->

a->b

- Property access

getProperty("a", "b")

->

a->b = v

- Property assignment

setProperty("a", "b", v)






[]

a[args]

- Subscript

a.’[]’(args)

[] =

a[args] = v

- Subscript assignment

a.’[]=’(args, v)






+

+a

- Identity

a.’+’()

-

-a

- Opposite

a.’-’()






**

a ** b

Right Exponentiation

a.’**’(b)






*

a * b

Left Multiplication

a.’*’(b)

/

a / b

Left Division

a.’/’(b)

%

a % b

Left Modulo

a.’%’(b)






+

a + b

Left Sum

a.’+’(b)

-

a - b

Left Difference

a.’-’(b)






<<

a << b

Left Left bit shift

a.’<<’(b)

>>

a >> b

Left Right bit shift

a.’>>’(b)






==

a == b

None Equality

a.’==’(b)

!=

a != b

None Inequality

a.’!=’(b)

===

a === b

None Physical equality

a.’===’(b)

!==

a !== b

None Physical inequality

a.’!==’(b)

=~=

a =~= b

None Absolute approximate equality

a.’=~=’(b)

~=

a ~= b

None Relative approximate equality

a.’~=’(b)

<

a < b

None Less than

a.’<’(b)

<=

a <= b

None Less than or equal to

a.’<=’(b)

>

a > b

None Greater than

a.’>’(b)

>=

a >= b

None Greater than or equal to

a.’>=’(b)






^

a ^ b

Left Bitwise exclusive or

a.’^’(b)






!

!a

Left Logical negation

a.’!’()






in

a in b

- Membership

b.has(a)

not in

a not in b

- Non-membership

! b.has(a)






&&

a && b

Left Logical and

a.’&&’(b)






||

a || b

Left Logical or

a.’||’(b)






=

a = b

Right Assignment

updateSlot("a", b)

+=

a += b

Right In place assignment

a = a + b

-=

a -= b

Right In place assignment

a = a - b

*=

a *= b

Right In place assignment

a = a * b

/=

a /= b

Right In place assignment

a = a / b

%=

a %= b

Right In place assignment

a = a % b

^=

a ^= b

Right In place assignment

a = a ^ b






++

a++

- Incrementation

(a = a + 1) - 1

--

a--

- Incrementation

(a = a - 1) + 1






Table 18.12: Operators summary

18.2 Scopes and local variables

18.2.1 Scopes

Scopes are sequences of statements, enclosed in curly brackets ({}). Statements are separated with the four statements separators (see Section 18.1.7). A trailing ‘;’ or ‘,’ is ignored. A trailing ‘&’ or ‘|’ behaves as if & {} or | {} was used. This particular case is heavily used by urbiscript programmers to discard the value of an expression:

 
// Return value is 1.  Displayed. 
1; 
[00000000] 1 
// Return value is that of {}, i.e., void.  Nothing displayed. 
1 | {}; 
// Same as "1 | {}", a valueless expression. 
1|;  

Scopes are themselves expressions, and can thus be used in composite expressions, nested, and so forth.

 
// Scopes evaluate to their last expression 
{ 
  1; 
  2; 
  3; // This last separator is optional. 
}; 
[00000000] 3 
// Scopes can be used as expressions 
{1; 2; 3} + 1; 
[00000000] 4  

18.2.2 Local variables

Local variables are introduced with the var keyword, followed by an identifier (see Section 18.1.4) and an optional initialization value assignment. If the initial value is omitted, it defaults to void (Section 19.64). Variable declarations evaluate to the initialization value. They can later be referred to by their name. Their value can be changed with the assignment operator; such an assignment expression returns the new value. The use of local variables is illustrated below.

 
// This declare variable x with value 42, and evaluates to 42. 
var t = 42; 
[00000000] 42 
// x equals 42 
t; 
[00000000] 42 
// We can assign it a new value 
t = 51; 
[00000000] 51 
t; 
[00000000] 51 
// Initialization defaults to void 
var u; 
u.isVoid; 
[00000000] true  

The lifespan of local variables is the same as their enclosing scope. They are thus only accessible from their scope and its sub-scopes3 . Two variables with the same name cannot be defined in the same scope. A variable with the same name can be defined in an inner scope, in which case references refer to the innermost variable, as shown below.

 
{ 
  var x = "x"; 
  var y = "outer y"; 
  { 
    var y = "inner y"; 
    var z = "z"; 
    // We can access variables of parent scopes. 
    echo(x); 
    // This refers to the inner y. 
    echo(y); 
    echo(z); 
  }; 
  // This refers to the outer y. 
  echo(y); 
  // This would be invalid: z does not exist anymore. 
  // echo(z); 
  // This would be invalid: x is already declared in this scope. 
  // var x; 
}; 
[00000000] *** x 
[00000000] *** inner y 
[00000000] *** z 
[00000000] *** outer y  

18.3 Functions

18.3.1 Function Definition

Functions in urbiscript are first class citizens: a function is a value, like floats and strings, and can be handled as such. This is different from most C-like languages. One can create a functional value thanks to the function keyword, followed by the list of formal arguments and a compound statement representing the body of the function. Formal arguments are a possibly-empty comma-separated list of identifiers. Non-empty lists of formal arguments may optionally end with a trailing comma. The listing below illustrates this.

 
function () { echo(0) }; 
[00000000] function () { 
  echo(0) 
} 
 
function (arg1, arg2) { echo(0) }; 
[00000000] function (arg1, arg2) { 
  echo(0) 
} 
 
function ( 
           arg1, // Ignored argument. 
           arg2, // Also ignored. 
          ) 
{ 
  echo(0) 
}; 
[00000000] function (arg1, arg2) { 
  echo(0) 
}  

Usually functions are bound to an identifier to be invoked later. The listing below shows a short-hand to define a named function.

 
// Functions are often stored in variables to call them later. 
var f1 = function () { 
  echo("hello") 
}| 
f1(); 
[00000000] *** hello 
 
// This form is strictly equivalent, yet simpler. 
function f2() 
{ 
  echo("hello") 
}| 
f2(); 
[00000000] *** hello  

18.3.2 Arguments

The list of formal arguments defines the number of argument the function requires. They are accessible by their name from within the body. If the list of formal arguments is omitted, the number of effective arguments is not checked, and arguments themselves are not evaluated. Arguments can then be manipulated with the call message, explained below.

 
var f = function(a, b) { 
  echo(b + a); 
}| 
f(1, 0); 
[00000000] *** 1 
// Calling a function with the wrong number of argument is an error. 
f(0); 
[00000000:error] !!! f: expected 2 arguments, given 1 
f(0, 1, 2); 
[00000000:error] !!! f: expected 2 arguments, given 3  

Non-empty lists of effective arguments may end with an optional comma.

 
f( 
  "bar", 
  "foo", 
 ); 
[00000000] *** foobar  

18.3.3 Return value

The return value of the function is the evaluation of its body — that is, since the body is a scope, the last evaluated expression in the scope. Values can be returned manually with the return keyword followed by the value, in which case the evaluation of the function is stopped. If return is used with no value, the function returns void.

 
function g1(a, b) 
{ 
  echo(a); 
  echo(b); 
  a // Return value is a 
}| 
g1(1, 2); 
[00000000] *** 1 
[00000000] *** 2 
[00000000] 1 
 
function g2(a, b) 
{ 
  echo(a); 
  return a; // Stop execution at this point and return a 
  echo(b); // This is not executed 
}| 
g2(1, 2); 
[00000000] *** 1 
[00000000] 1 
 
function g3() 
{ 
  return; // Stop execution at this point and return void 
  echo(0); // This is not executed 
}| 
g3(); // Returns void, so nothing is printed.  

18.3.4 Call messages

Functions can access meta-information about how they were called, through a CallMessage object. The call message associated with a function can be accessed with the call keyword. It contains several information such as not-yet evaluated arguments, the name of the function, the target …

18.3.5 Strictness

urbiscript features two different function calls: strict function calls, effective arguments are evaluated before invoking the function, and lazy function calls, arguments are passed as-is to the function. As a matter of fact, the difference is rather that there are strict functions and lazy functions.

Functions defined with a (possibly empty) list of formal arguments in parentheses are strict: the effective arguments are first evaluated, and then their value is given to the called function.

 
function first1(a, b) { 
  echo(a); echo(b) 
}| 
first1({echo("Arg1"); 1}, 
       {echo("Arg2"); 2}); 
[00000000] *** Arg1 
[00000000] *** Arg2 
[00000000] *** 1 
[00000000] *** 2  

A function declared with no formal argument list is lazy. Use its call message to manipulate its unevaluated arguments. The listing below gives an example. More information about this can be found in the CallMessage (Section 19.4) class documentation.

 
function first2 
{ 
  echo(call.evalArgAt(0)); 
  echo(call.evalArgAt(1)); 
}| 
first2({echo("Arg1"); 1}, 
       {echo("Arg2"); 2}); 
[00000000] *** Arg1 
[00000000] *** 1 
[00000000] *** Arg2 
[00000000] *** 2  

A lazy function may implement a strict interface by evaluating its arguments and storing them as local variables, see below. This is less efficient than defining a strict function.

 
function first3 
{ 
  var a = call.evalArgAt(0); 
  var b = call.evalArgAt(1); 
  echo(a); echo(b); 
}| 
first3({echo("Arg1"); 1}, 
       {echo("Arg2"); 2}); 
[00000000] *** Arg1 
[00000000] *** Arg2 
[00000000] *** 1 
[00000000] *** 2  

18.3.6 Lexical closures

Lexical closures are an additional scoping rule, with which a function can refer to a local variable located outside the function — but still in the current context. urbiscript supports read/write lexical closures, meaning that the variable is shared between the function and the outer environment, as shown below.

 
var n = 0| 
function cl() 
{ 
  // x refers to a variable outside the function 
  n++; 
  echo(n); 
}| 
cl(); 
[00000000] *** 1 
n; 
[00000000] 1 
n++; 
[00000000] 1 
cl(); 
[00000000] *** 3  

The following listing illustrate that local variables can even escape their declaration scope by lexical closure.

 
function wrapper() 
{ 
  // Normally, x is local to wrapper’, and is limited to this scope. 
  var x = 0; 
  at (x > 1) 
    echo("ping"); 
  // Here we make it escape the scope by returning a closure on it. 
  return function() { x++ }; 
} | 
 
var w = wrapper()| 
w(); 
[00000000] 0 
w(); 
[00000000] 1 
[00000000] *** ping  

18.4 Objects

Any value in urbiscript is an object. Objects contain:

18.4.1 Slots

18.4.1.1 Manipulation

Objects can contain any number of slots, every slot has a name and a value. Slots are often called “fields”, “attributes” or “members” in other object-oriented languages.

The createSlot function adds a slot to an object with the void (Section 19.64) value. The updateSlot function changes the value of a slot; getSlot reads it. The setSlot method creates a slot with a given value. Finally, the localSlotNames method returns the list of the object slot’s name. The listing below shows how to manipulate slots. More documentation about these methods can be found in Section 19.34.

 
var o = Object.new| 
o.localSlotNames; 
[00000000] [] 
o.createSlot("test"); 
o.localSlotNames; 
[00000000] ["test"] 
o.getSlot("test").asString; 
[00000000] "void" 
o.updateSlot("test", 42); 
[00000000] 42 
o.getSlot("test"); 
[00000000] 42  

18.4.1.2 Syntactic Sugar

There is some syntactic sugar for slot methods:

18.4.2 Prototypes

18.4.2.1 Manipulation

urbiscript is a prototype-based language, unlike most classical object oriented language, which are class-based. In prototype-based languages, objects have no type, only prototypes, from which they inherit behavior.

urbiscript objects can have several prototypes. The list of prototypes is given by the protos method; they can be added or removed with addProto and removeProto. See Section 19.34 for more documentation.

 
var ob = Object.new| 
ob.protos; 
[00000000] [Object] 
ob.addProto(Pair); 
[00000000] (nil, nil) 
ob.protos; 
[00000000] [(nil, nil), Object] 
ob.removeProto(Object); 
[00000000] (nil, nil) 
ob.protos; 
[00000000] [(nil, nil)]  

18.4.2.2 Inheritance

Objects inherit their prototypes’ slots: getSlot will also look in an object prototypes’ slots. getSlot performs a depth-first traversal of the prototypes hierarchy to find slots. That is, when looking for a slot in an object:

This listing shows how slots are inherited.

 
var a = Object.new| 
var b = Object.new| 
var c = Object.new| 
a.setSlot("x", "slot in a")| 
b.setSlot("x", "slot in b")| 
// c has no "x" slot 
c.getSlot("x"); 
[00000000:error] !!! lookup failed: x 
// c can inherit the "x" slot from a. 
c.addProto(a)| 
c.getSlot("x"); 
[00000000] "slot in a" 
// b is prepended to the prototype list, and has thus priority 
c.addProto(b)| 
c.getSlot("x"); 
[00000000] "slot in b" 
// a local slot in c has priority over prototypes 
c.setSlot("x", "slot in c")| 
c.getSlot("x"); 
[00000000] "slot in c"  

18.4.2.3 Copy on write

The updateSlot method has a particular behavior with respect to prototypes. Although performing an updateSlot on a non existent slot is an error, it is valid if the slot is inherited from a prototype. In this case, the slot is however not updated in the prototype, but rather created in the object itself, with the new value. This process is called copy on write; thanks to it, prototypes are not altered when the slot is overridden in a child object.

 
var p = Object.new| 
var p.slot = 0| 
var d = Object.new| 
d.addProto(p)| 
d.slot; 
[00000000] 0 
d.slot = 1; 
[00000000] 1 
// ps slot was not altered 
p.slot; 
[00000000] 0 
// It was copied in d 
d.slot; 
[00000000] 1  

18.4.3 Sending messages

A message in urbiscript consists in a message name and arguments. One can send a message to an object with the dot (.) operator, followed by the message name (which can be any valid identifier) and the arguments, as shown below. When there are no arguments, the parentheses can be omitted. As you might see, sending messages is very similar to calling methods in classical languages.

 
// Send the message msg to object obj, with arguments arg1 and arg2. 
obj.msg(arg1, arg2); 
// Send the message msg to object obj, with no arguments. 
obj.msg(); 
// This is strictly equivalent. 
obj.msg;  

When a message msg is sent to object obj:

Such message sending is illustrated below.

 
var obj = Object.new| 
var obj.a = 42| 
var obj.b = function (x) { x + 1 }| 
obj.a; 
[00000000] 42 
obj.a(); 
[00000000] 42 
obj.a(50); 
[00000000:error] !!! a: expected 0 argument, given 1 
obj.b; 
[00000000:error] !!! b: expected 1 argument, given 0 
obj.b(); 
[00000000:error] !!! b: expected 1 argument, given 0 
obj.b(50); 
[00000000] 51  

18.5 Imperative flow control

18.5.1 break

When encountered within a for or a while loop, break makes the execution jump after the loop.

 
var i = 5| 
for (; true; echo(i)) 
{ 
  if (i > 8) 
    break; 
  i++; 
}; 
[00000000] *** 6 
[00000000] *** 7 
[00000000] *** 8 
[00000000] *** 9  

18.5.2 continue

When encountered within a for or a while loop, continue short-circuits the rest of the loop-body, and runs the next iteration (if there remains one).

 
for (var i = 0; i < 8; i++) 
{ 
  if (i % 2 != 0) 
    continue; 
  echo(i); 
}; 
[00000000] *** 0 
[00000000] *** 2 
[00000000] *** 4 
[00000000] *** 6  

18.5.3 do

The do construct changes the target (this) when evaluating an expression. It is a convenient means to avoid repeating the same target several times.

 
do (target) 
{ 
  body 
};  

It evaluates body, with this being target, as shown below. The whole construct evaluates to the value of body.

 
do (1024) 
{ 
  assert(this == 1024); 
  assert(sqrt == 32); 
  setSlot("y", 23); 
}.y; 
[00000000] 23  

18.5.4 if

As in most programming languages, conditionals are expressed with if.

 
if (condition) then-clause 
if (condition) then-clause else else-clause  

First condition is evaluated; if it evaluates to a value which is true (Section 19.3.3), evaluate then-clause, otherwise, if applicable, evaluate else-clause.

 
if (true) assert(true) else assert(false); 
if (false) assert(false) else assert(true); 
if (true) assert(true);  

Beware that there must not be a terminator after the then-clause :

 
if (true) 
  assert(true); 
else 
  assert(false); 
[00000002:error] !!! syntax error: unexpected else  

Contrary to C/C ++, it has value: it also implements the condition ? then-clause : else-clause construct. Unfortunately, due to syntactic constraints inherited from C, it is a statement: it cannot be used directly as an expression. But as everywhere else in urbiscript, to use a statement where an expression is expected, use braces:

 
assert(1 + if (true) 3 else 4 == 4); 
[00000003:error] !!! syntax error: unexpected if 
assert(1 + { if (true) 3 else 4 } == 4);  

The condition can be any statement list. Variables which it declares are visible in both the then-clause and the else-clause, but do not escape the if construct.

 
assert({if (false) 10 else 20} == 20); 
assert({if (true)  10 else 20} == 10); 
 
assert({if (true) 10         } == 10); 
 
assert({if (var x = 10) x + 2 else x - 2} == 12); 
assert({if (var x = 0)  x + 2 else x - 2} == -2); 
 
if (var xx = 123) xx | xx; 
[00000005:error] !!! lookup failed: xx  

18.5.5 for

for comes in several flavors.

18.5.5.1 C-like for

urbiscript support the classical C-like for construct.

 
for (initialization; condition; increment) 
  body  

It has the exact same behavior as C’s for:

  1. The initialization is evaluated.
  2. condition is evaluated. If the result is false, executions jump after for.
  3. body is evaluated. If continue is encountered, execution jumps to point 4. If break is encountered, executions jumps after the for.
  4. The increment is evaluated.
  5. Execution jumps to point 2.
  6. The loop evaluates to void.

18.5.5.2 Range-for

urbiscript supports iteration over a collection with another form of the for loop.

 
for (var name : collection) 
   body;  

It evaluates body for each element in collection. The loop evaluates to void. Inside body, the current element is accessible via the name local variable. The listing below illustrates this.

 
for (var x : [0, 1, 2, 3, 4]) 
  echo(x.sqr); 
[00000000] *** 0 
[00000000] *** 1 
[00000000] *** 4 
[00000000] *** 9 
[00000000] *** 16  

This form of for simply sends the each message to collection with one argument: the function that takes the current element and performs action over it. Thus, you can make any object acceptable in a for by defining an adequate each method.

 
var Hobbits = Object.new| 
function Hobbits.each (action) 
{ 
  action("Frodo"); 
  action("Merry"); 
  action("Pippin"); 
  action("Sam"); 
}| 
for (var name in Hobbits) 
  echo("%s is a hobbit." % [name]); 
[00000000] *** Frodo is a hobbit. 
[00000000] *** Merry is a hobbit. 
[00000000] *** Pippin is a hobbit. 
[00000000] *** Sam is a hobbit. 
// This for statement is equivalent to: 
Hobbits.each(function (name) { echo("%s is a hobbit." % [name]) }); 
[00000000] *** Frodo is a hobbit. 
[00000000] *** Merry is a hobbit. 
[00000000] *** Pippin is a hobbit. 
[00000000] *** Sam is a hobbit.  

18.5.5.3 for n-times

urbiscript provides some support for simple replication of computations: it allow to repeat a loop body n-times. With the exception that the loop index is not available within the body, for (n) is equivalent to for (var i: n). It supports the same flavors: for;, for|, and for&. The loop evaluates to void.

 
{ var res = []; for (3) { res << 1; res << 2 } ; res } 
        == [1, 2, 1, 2, 1, 2]; 
 
{ var res = []; for|(3) { res << 1; res << 2 } ; res } 
        == [1, 2, 1, 2, 1, 2]; 
 
{ var res = []; for&(3) { res << 1; res << 2 } ; res } 
        == [1, 1, 1, 2, 2, 2];  

Note that since these for loops are merely anonymous foreach-style loops, the argument needs not being an integer, any iterable value can be used.

 
3 == { var r = 0; for ([1, 2, 3]) r += 1; r}; 
3 == { var r = 0; for ("123")     r += 1; r};  

18.5.6 if

urbiscript supports the usual if constructs.

 
if (condition) 
  action; 
 
if (condition) 
  action 
else 
  otherwise;  

If the condition evaluation is true, action is evaluated. Otherwise, in the latter version, otherwise is executed. Contrary to C/C ++, there must not be a semicolon after the action; it would end the if/else construct prematurely.

18.5.7 loop

Endless loops can be created with loop, which is equivalent to while (true). The loop evaluates to void. Both sequential flavors, loop; and loop;, are supported. The default flavor is loop;.

 
{ 
  var n = 10|; 
  var res = []|; 
  loop; 
  { 
    n--; 
    res << n; 
    if (n == 0) 
      break 
  }; 
  res 
} 
== 
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0];  

 
{ 
  var n = 10|; 
  var res = []|; 
  loop| 
  { 
    n--; 
    res << n; 
    if (n == 0) 
      break 
  }; 
  res 
} 
== 
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0];  

18.5.8 switch

The switch statement in urbiscript is similar to C’s one.

 
switch (value) 
{ 
  case value_one: 
    action_one; 
  case value_two: 
    action_two; 
//case ...: 
//  ... 
  default: 
    default_action; 
};  

It might contain an arbitrary number of cases, and optionally a default case. The value is evaluated first, and then the result is compared sequentially with the evaluation of all cases values, with the == operator, until one comparison is true. If such a match is found, the corresponding action is executed, and execution jumps after the switch. Otherwise, the default case — if any — is executed, and execution jumps after the switch. The switch itself evaluates to case that was evaluated, or to void if no match was found and there’s no default case. The listing below illustrates switch usage.

Unlike C, there are no break to end case clauses: execution will never span over several cases. Since the comparisons are performed with the generic == operator, switch can be performed on any comparable data type.

 
function sw(v) 
{ 
  switch (v) 
  { 
    case "": 
      echo("Empty string"); 
    case "foo": 
      "bar"; 
    default: 
      v[0]; 
  } 
}|; 
sw(""); 
[00000000] *** Empty string 
sw("foo"); 
[00000000] "bar" 
sw("foobar"); 
[00000000] "f"  

18.5.9 while

The while loop is similar to C’s one.

 
while (condition) 
  body;  

If condition evaluation, is true, body is evaluated and execution jumps before the while, otherwise execution jumps after the while.

 
var j = 3| 
while (0 < j) 
{ 
  echo(j); 
  j--; 
}; 
[00000000] *** 3 
[00000000] *** 2 
[00000000] *** 1  

The default flavor for while is while;.

18.5.9.1 while;

The semantics of

 
while; (condition) 
  body;  

is the same as

 
condition | body ; condition | body ; ...  

as long as cond evaluates to true, or until break is invoked. If continue is evaluated, the rest of the body is skipped, and the next iteration is started.

 
{ 
  var i = 4| 
  while (true) 
  { 
    i -= 1; 
    echo ("in: " + i); 
    if (i == 1) 
      break 
    else if (i == 2) 
      continue; 
    echo ("out: " + i); 
  }; 
}; 
[00000000] *** in: 3 
[00000000] *** out: 3 
[00000000] *** in: 2 
[00000000] *** in: 1  

18.5.9.2 while—

The semantics of

 
while| (condition) 
  body;  

is the same as

 
condition | body | condition | body | ...  

The execution is can be controlled by break and continue.

 
{ 
  var i = 4| 
  while| (true) 
  { 
    i -= 1; 
    echo ("in: " + i); 
    if (i == 1) 
      break 
    else if (i == 2) 
      continue; 
    echo ("out: " + i); 
  }; 
}; 
[00000000] *** in: 3 
[00000000] *** out: 3 
[00000000] *** in: 2 
[00000000] *** in: 1  

18.6 Exceptions

18.6.1 Throwing exceptions

Use the throw keyword to throw exceptions, as shown below. Thrown exceptions will break the execution upward until they are caught, or until they reach the top-level — as in C ++. Contrary to C++, exceptions reaching the top-level are printed, and won’t abort the kernel — other and new connections will continue to execute normally.

 
throw 42; 
[00000000:error] !!! 42 
function inner() { throw "exn" } | 
function outer() { inner() }| 
// Exceptions propagate to parent call up to the top-level 
outer(); 
[00000000:error] !!! exn 
[00000000:error] !!!    called from: 3.20-26: inner 
[00000000:error] !!!    called from: 4.1-7: outer  

18.6.2 Catching exceptions

Exceptions are caught with the try/catch construct. It consists of a first block (the try-block), from which we want to catch exceptions, and one or more catch clauses to stop the exception (catch-blocks). Each catch clause defines a pattern against which the thrown exception is matched. If no pattern is specified, the catch clause matches systematically (equivalent to catch (...) in C++).

Exceptions thrown from the try block are matched sequentially against all catch clauses. The first matching clause is executed, and control jumps after the whole try/catch block. If no catch clause matches, the exceptions isn’t stopped and continues upward.

 
function test(e) 
{ 
  try 
  { throw e;  } 
  catch (0) 
  { echo("zero") } 
  catch ([var x, var y]) 
  { echo(x + y) } 
} | {}; 
test(0); 
[00002126] *** zero 
test([22, 20]); 
[00002131] *** 42 
test(51); 
[00002143:error] !!! 51 
[00002143:error] !!!    called from: 12.1-8: test  

18.6.3 Inspecting exceptions

An Exception (Section 19.14) is a regular object, on which introspection can be performed.

 
try 
{ 
  Math.cos(3,1415); 
} 
catch (var e) 
{ 
  echo ("Exception type: %s" % e.type); 
  if (e.isA(Exception.Arity)) 
  { 
    echo("Routine: %s" % e.routine); 
    echo("Number of effective arguments: %s" % e.effective); 
  }; 
}; 
[00000132] *** Exception type: Arity 
[00000133] *** Routine: cos 
[00000134] *** Number of effective arguments: 2  

18.7 Assertions

Assertions allow to embed consistency checks in the code. They are particularly useful when developing a program since they allow early catching of errors. Yet, they can be costly in production mode: the run-time cost of verifying every single assertion might be prohibitive. Therefore, as in C-like languages, assertions are disabled when System.ndebug is true, see System (Section 19.55).

urbiscript supports assertions in two different ways: with a function-like syntax, which is adequate for single claims, and a block-like syntax, to group claims together.

The assert(expression) bounces to the System.’assert function, see System (Section 19.55).

 
assert(true); 
assert(42); 
assert(1 == 1 + 1); 
[00000002:error] !!! failed assertion: 1 == 1 . ’+’(1) (1 != 2)  

Groups of assertions are more readable when used with the assert{exp1; exp2; ...} construct. The (possibly empty) list of claims may be ended with a semicolon.

 
assert 
{ 
  true; 
  42; 
  1 == 1 + 1; 
}; 
[00000002:error] !!! failed assertion: 1 . ’==’(1 . ’+’(1))  

For sake of readability and compactness, this documentation shows assertion blocks as follows.

 
true; 
42; 
1 == 1 + 1; 
[00000002:error] !!! failed assertion: 1 . ’==’(1 . ’+’(1))  

18.8 Parallel and event-based flow control

18.8.1 at

Using the at construct, one can arm code that will be triggered each time some condition is true.

The at construct is as follows:

 
at (condition) 
  statement1 
onleave 
  statement2  

The condition can be of two different kinds: e?(args) to catch when events are sent, or exp to catch each time a Boolean exp becomes true.

The onleave statement2 part is optional. Note that, as is the case for the if statement, there must not be a semicolon after statement1 if there is an onleave clause.

18.8.1.1 at on Events

See Section 12.2 for an example of using at statements to watch events.

18.8.1.2 at on Boolean Expressions

The at construct can be used to watch a given Boolean expression.

 
var x = 0 | 
var x_is_two = false | 
at (x == 2) 
  x_is_two = true 
onleave 
  x_is_two = false; 
 
x = 3|;  assert(!x_is_two); 
x = 2|;  assert( x_is_two); 
x = 2|;  assert( x_is_two); 
x = 3|;  assert(!x_is_two);  

It can also wait for some condition to hold long enough: exp ~ duration, as a condition, denotes the fact that exp was true for duration seconds.

 
var x = 0 | 
var x_was_two_for_two_seconds = false | 
at (x == 2 ~ 2s) 
  x_was_two_for_two_seconds = true 
onleave 
  x_was_two_for_two_seconds = false; 
 
x = 2       | assert(!x_was_two_for_two_seconds); 
sleep(1.5s) | assert(!x_was_two_for_two_seconds); 
sleep(1.5s) | assert( x_was_two_for_two_seconds); 
 
x = 3|; sleep(0.1s);  assert(!x_was_two_for_two_seconds); 
 
x = 2       | assert(!x_was_two_for_two_seconds); 
sleep(1.5s) | assert(!x_was_two_for_two_seconds); 
x = 3|; x = 2|; sleep (1s) | assert(!x_was_two_for_two_seconds);  

18.8.1.3 Scoping at at

at statements are not scoped. But, using a Tag (Section 19.56) object, one can control them. In the following example, scopeTag is used to label the at statement. When the function ends, the at is no longer active.

 
var x = 0 | 
var x_is_two = false |; 
 
{ 
  scopeTag: 
    at (x == 2) 
      x_is_two = true 
    onleave 
      x_is_two = false; 
  sleep(2s); 
}, 
x = 2 |; assert(x_is_two); 
x = 1 |; assert(!x_is_two); 
sleep(3s); 
x = 2 | assert(!x_is_two);  

18.8.2 every

The every statement enables to execute a block of code repeatedly, with the given period.

 
// Print out a message every second. 
timeout (2.1s) 
  every (1s) 
    echo("Are you still there?"); 
[00000000] *** Are you still there? 
[00001000] *** Are you still there? 
[00002000] *** Are you still there?  

It exists in several flavors.

18.8.2.1 every|

The whole every| statement itself remains in foreground: statements attached after it with ; or | will not be reached unless you break out of it. You may use continue to finish one iteration. In that case, the following iteration is not immediately started, it will be launched as expected, at the given period.

 
{ 
  var count = 4; 
  var start = time; 
  echo("before"); 
  every| (1s) 
  { 
    count -= 1; 
    echo("begin: %s @ %1.0fs" % [count, time - start]); 
    if (count == 2) 
      continue; 
    if (count == 0) 
      break; 
    echo("end:   " + count); 
  }; 
  echo("after"); 
}; 
[00000597] *** before 
[00000598] *** begin: 3 @ 0s 
[00000599] *** end:   3 
[00000698] *** begin: 2 @ 1s 
[00000798] *** begin: 1 @ 2s 
[00000799] *** end:   1 
[00000898] *** begin: 0 @ 3s 
[00000899] *** after  

The every| flavor does not let iterations overlap. If an iteration takes too long, the following iterations are delayed. That is, the next iterations will start immediately after the end of the current one, and next iterations will occur normally from this point.

 
{ 
  var too_long = true|; 
 
  var count = 5; 
  // Every other iteration exceeds the period, and will delay the 
  // following one. 
  every| (1s) 
  { 
    if (! count -=1) 
      break; 
 
    if (too_long) 
    { 
      too_long = false; 
      echo("Long in"); 
      sleep(1.5s); 
      echo("Long out"); 
    } 
    else 
    { 
      too_long = true; 
      echo("Short"); 
    }; 
  }; 
}; 
[00000000] *** Long in 
[00001500] *** Long out 
[00001500] *** Short 
[00002500] *** Long in 
[00004000] *** Long out 
[00004000] *** Short  

The flow-control constructs break and continue are supported.

 
{ 
  var count = 0; 
  every| (250ms) 
  { 
    count += 1; 
    if (count == 2) 
      continue; 
    if (count == 4) 
      break; 
    echo(count); 
  } 
}; 
 
[00000000] *** 1 
[00001500] *** 3  

18.8.2.2 every,

The default flavor, every, launches the execution of the block in the background every given period. Iterations may overlap.

 
// If an iteration is longer than the given period, it will overlap 
// with the next one. 
timeout (2.8s) 
  every (1s) 
  { 
    echo("In"); 
    sleep(1.5s); 
    echo("Out"); 
  }; 
[00000000] *** In 
[00001000] *** In 
[00001500] *** Out 
[00002000] *** In 
[00002500] *** Out  

18.8.3 for

The for loops come into several flavors, depending one the actual kind of for loop.

18.8.3.1 C-for,

This feature is experimental. It might be changed, or even removed.Feedback on its use would be appreciated.

for, is syntactic sugar for while,, see Section 18.8.7.1.

 
for, (var i = 3; 0 < i; i -= 1) 
{ 
  var j = i | 
  echo ("in: i = %s, j = %s" % [i, j]); 
  sleep(j/10); 
  echo ("out: i = %s, j = %s" % [i, j]); 
}; 
echo ("done"); 
[00000144] *** in: i = 3, j = 3 
[00000145] *** in: i = 2, j = 2 
[00000145] *** in: i = 1, j = 1 
[00000246] *** out: i = 0, j = 1 
[00000346] *** out: i = 0, j = 2 
[00000445] *** out: i = 0, j = 3 
[00000446] *** done  
 
for, (var i = 9; 0 < i; i -= 1) 
{ 
  var j = i; 
  if (j % 2) 
    continue 
  else if (j == 4) 
    break 
  else 
    echo("%s: done" % j) 
}; 
echo("done"); 
[00000146] *** 8: done 
[00000148] *** 6: done 
[00000150] *** done  

18.8.3.2 range-for& (:)

One can iterate concurrently over the members of a collection.

 
for& (var i: [0, 1, 2]) 
{ 
  echo (i * i); 
  echo (i * i); 
}; 
[00000000] *** 0 
[00000000] *** 1 
[00000000] *** 4 
[00000000] *** 0 
[00000000] *** 1 
[00000000] *** 4  

If an iteration executes continue, it is stopped; the other iterations are not affected.

 
for& (var i: [0, 1, 2]) 
{ 
  var j = i; 
  if (j == 1) 
    continue; 
  echo (j); 
}; 
[00020653] *** 0 
[00021054] *** 2  

If an iteration executes break, all the iterations including this one, are stopped.

 
for& (var i: [0, 1, 2]) 
{ 
  var j = i; 
  echo (j); 
  if (j == 1) 
   { echo ("break"); 
    break;}; 
  sleep(1s); 
  echo (j); 
}; 
[00000001] *** 0 
[00000001] *** 1 
[00000001] *** 2 
[00000002] *** break  

18.8.3.3 for& (n)

Since for& (n) body is processed as for& (var tmp: n) body, which tmp a hidden variable, see Section 18.8.3.2 for details.

18.8.4 loop,

This feature is experimental. It might be changed, or even removed.Feedback on its use would be appreciated.

This is syntactic sugar for while,(true). In the following example, care must be taken that concurrent executions don’t modify n simultaneously. This would happen had ; been used instead of |.

 
{ 
  var n = 10|; 
  var res = []|; 
  loop, 
  { 
    n-- | 
    res << n | 
    if (n == 0) 
      break 
  }; 
  res.sort 
} 
== 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];  

18.8.5 waituntil

The waituntil construct is used to hold the execution until some condition is verified. Similarly to at (Section 18.8.1) and the other event-based constructs, waituntil may work on events, or on Boolean expressions.

18.8.5.1 waituntil on Events

When the execution flow enters a waituntil, the execution flow is held until the event is fired. Once caught, the event is consumed, another waituntil will require another event emission.

 
{ 
  var e = Event.new; 
  { 
    waituntil (e?); 
    echo ("caught e"); 
  }, 
  e!; 
[00021054] *** caught e 
  e!; 
};  

In the case of lasting events (see Event.trigger), the condition remains verified as long as the event is “on”.

 
{ 
  var e = Event.new; 
  e.trigger; 
  { 
    waituntil (e?); 
    echo ("caught e"); 
  }; 
[00021054] *** caught e 
  { 
    waituntil (e?); 
    echo ("caught e"); 
  }; 
[00021054] *** caught e 
  { 
    waituntil (e?); 
    echo ("caught e"); 
  }; 
[00021054] *** caught e 
};  

The event specification may use pattern-matching to specify the accepted events.

 
{ 
  var e = Event.new; 
  { 
    waituntil (e?(1, var b)); 
    echo ("caught e(1, %s)" % b); 
  }, 
  e!; 
  e!(1); 
  e!(2, 2); 
  e!(1, 2); 
[00021054] *** caught e(1, 2) 
  e!(1, 2); 
};  

Events sent before do not release the construct.

 
{ 
  var e = Event.new; 
  e!; 
  { 
    waituntil (e?); 
    echo ("caught e"); 
  }, 
  e!; 
[00021054] *** caught e 
};  

18.8.5.2 waituntil on Boolean Expressions

You may use any expression that evaluates to a truth value as argument to waituntil.

 
{ 
  var foo = Object.new; 
  { 
    waituntil (foo.hasLocalSlot("bar")); 
    echo(foo.getLocalSlot("bar")); 
  }, 
  var foo.bar = 123|; 
}; 
[00021054] *** 123  

18.8.6 whenever

The whenever construct really behaves like a never-ending loop if construct. It also works on events and Boolean expressions, and triggers each time the condition becomes verified.

 
whenever (condition) 
  statement1  

It supports an optional else clause, which is run whenever the condition changes “from true to false”.

 
whenever (condition) 
  statement1 
else 
  statement2  

The execution of a whenever clause is “instantaneous”, there is no mean to use ‘,’ to put it in background. It is also asynchronous with respect to the condition: the emission of an event is not held until all its watchers have completed their job.

18.8.6.1 whenever on Events

A whenever clause can be used to catch events with or without payloads.

 
var e = Event.new|; 
whenever (e?) 
  echo("e on") 
else 
  echo("e off"); 
[00000001] *** e off 
[00000002] *** e off 
[00000003] *** ... 
e!; 
[00000004] *** e on 
[00000005] *** e off 
[00000006] *** e off 
[00000007] *** ... 
e!(1) & e!(2); 
[00000008] *** e on 
[00000009] *** e on 
[00000010] *** e off 
[00000011] *** e off 
[00000012] *** ...  

The pattern-matching and guard on the payload is available.

 
var e = Event.new|; 
whenever (e?("arg", var arg) if arg % 2) 
  echo("e (%s) on" % arg) 
else 
  echo("e off"); 
e!("param", 23); 
e!("arg", 52); 
e!("arg", 23); 
[00000001] *** e (23) on 
[00000002] *** e off 
[00000003] *** e off 
[00000004] *** ... 
e!("arg", 52); 
e!("arg", 17); 
[00000005] *** e (17) on 
[00000006] *** e off 
[00000007] *** e off 
[00000008] *** ...  

If the body of the whenever lasts for a long time, it is possible that two executions be run concurrently.

 
var e = Event.new|; 
whenever (e?(var d)) 
{ 
  echo("e (%s) on begin" % d); 
  sleep(d); 
  echo("e (%s) on end" % d); 
}; 
 
e!(0.3s) & e!(1s); 
sleep(3s); 
[00000202] *** e (1) on begin 
[00000202] *** e (0.3) on begin 
[00000508] *** e (0.3) on end 
[00001208] *** e (1) on end  

18.8.6.2 whenever on Boolean Expressions

A whenever construct will repeatedly evaluate its body as long as its condition holds. The number of evaluation of the bodies is typically non-deterministic, as not only does it depend on how long the condition holds, but also “how fast” the Urbi kernel runs.

 
var x = 0|; 
var count = 0|; 
var t = Tag.new|; 
t: 
  whenever (x % 2) 
  { 
    if (!count) 
      echo("x is now odd (%s)" % x); 
    count++; 
  } 
  else 
  { 
    if (!count) 
      echo("x is now even (%s)" % x); 
    count++; 
  }; 
 
t: 
  whenever (100 < count) 
  { 
    count = 0 | 
    x++; 
  }; 
waituntil(x == 4); 
[00000769] *** x is now even (0) 
[00000809] *** x is now odd (1) 
[00000846] *** x is now even (2) 
[00000886] *** x is now odd (3) 
[00000924] *** x is now even (4) 
t.stop;  

18.8.7 While

18.8.7.1 while,

This feature is experimental. It might be changed, or even removed.Feedback on its use would be appreciated.

This construct provides a means to run concurrently multiple instances of statements. The semantics of

 
while, (condition) 
  body;  

is the same as

 
condition | body , condition | body , ...  

Attention must be paid to the fact that the (concurrent) iterations share a common access to the environment, therefore if, for instance, you want to keep the value of some index variable, use a local variable inside the loop body:

 
{ 
  var i = 4| 
  while, (i) 
  { 
    var j = i -= 1; 
    echo ("in: i = %s, j = %s" % [i, j]); 
    sleep(j/10); 
    echo ("out: i = %s, j = %s" % [i, j]); 
  }| 
  echo ("done"); 
}| 
[00000144] *** in: i = 2, j = 3 
[00000145] *** in: i = 1, j = 2 
[00000145] *** in: i = 0, j = 1 
[00000146] *** in: i = 0, j = 0 
[00000146] *** out: i = 0, j = 0 
[00000246] *** out: i = 0, j = 1 
[00000346] *** out: i = 0, j = 2 
[00000445] *** out: i = 0, j = 3 
[00000446] *** done  

As for the other flavors, continue skips the current iteration, and break ends the loop. Note that break stops all the running iterations. This semantics is likely to be changed to “break ends the current iteration and stops the generation of others, but lets the other concurrent iterations finish”, so do not rely on this feature.

Control flow is passed to the following statement when all the iterations are done.

 
{ 
  var i = 10| 
  while, (i) 
  { 
    var j = i -= 1; 
    if (j % 2) 
      continue 
    else if (j == 4) 
      break 
    else 
      echo("%s: done" % j) 
  }| 
  echo("done"); 
}; 
[00000146] *** 8: done 
[00000148] *** 6: done 
[00000150] *** done  

18.9 Trajectories

In robotics, trajectories are often used: they are a means to change the value of a variable (actually, a slot) over time. This can be done using detached executions, for instance using a combination of every and detach, but urbiscript provides syntactic sugar to this end.

For instance the following drawing shows how the y variable is moved smoothly from its initial value (0) to its target value (100) in 3 seconds (the value given to the smooth attribute.

 
var y = 0; 
{ 
  sleep(0.5s); 
  y = 100 smooth:3s, 
},
PICT

Trajectories can be frozen and unfrozen, using tags (Section 11.3). In that case, “time is suspended”, and the trajectory resumes as if the trajectory was never interrupted.

 
var y = 0; 
{ 
  sleep(0.5s); 
  assign: y = 100 smooth:2s, 
  sleep(1s); 
  assign.freeze; 
  sleep(1s); 
  assign.unfreeze; 
},
PICT

When the target value is reached, the trajectory generator is detached from the variables: changes to the value of the variable no longer trigger the trajectory generator.

 
var y = 0; 
{ 
  sleep(1s); 
  assign: y = 10 smooth:2s, 
  sleep(1s); 
  y = 0; 
  sleep(1s); 
  y = 0; 
},
PICT

See the specifications of TrajectoryGenerator (Section 19.58) for the list of supported trajectories.