1. введение в urbiScript — часть 1
2. введение в urbiScript — часть 2
3. введение в urbiScript — часть 3
4. введение в urbiScript — часть 4
5. введение в urbiScript — часть 5
Продолжаем рассмотрение возможностей скриптового языка urbiScript от компании Gostai, предназначенного для управления роботами.
Последовательное программирование не удобно при работе с высоко-интерактивными агентами (роботами). Для этого требуется реагировать на внешние случайные события, а не линейно выполнять заданный код.
urbiScript полностью отвечает этому требованию, т.к. поддерживает программирование на основе событий (event-based programming).
25. Конструкции контроля событий
25.1 at
Первая конструкция событийного программирования — это ключевое слово at.
at(выражение) код onleave код2
Код будет выполняться всякий раз, когда выражение будет истинно.
var x = 0;
[00000000] 0
at (x > 5)
echo("ping");
x = 5;
[00000000] 5
// это запустит(trigger) событие
x = 6;
[00000000] 6
[00000000] *** ping
// код не запускается(trigger), т.к. выражение уже истинно.
x = 7;
[00000000] 7
// выражение станет ложным
x = 3;
[00000000] 3
x = 10;
[00000000] 10
[00000000] *** ping
Блок onleave может определять код для выполнения, кода выражение становится ложным.
var x = false;
[00000000] false
at (x)
echo("x")
onleave
echo("!x");
x = true;
[00000000] true
[00000000] *** x
x = false;
[00000000] false
[00000000] *** !x
25.2 whenever
Ключевое слово whenever аналогично at, однако выполнение кода систематически перезапускается в случае если условие/выражение остаётся истинным.
var x = false;
[00000000] false
whenever (x)
{
echo("ping");
sleep(1s);
};
x = true;
[00000000] true
sleep(3s);
// код whenever выполняется снова и снова
[00000000] *** ping
[00001000] *** ping
[00002000] *** ping
x = false;
[00002000] false
// код whenever не выполняется
Как at имеет onleave, так и whenever имеет else: код будет выполняться снова и снова пока выражение/условие остаётся ложным.
var x = false;
[00002000] false
whenever (x)
{
echo("ping");
sleep(1s);
}
else
{
echo("pong");
sleep(1s);
};
sleep (3s);
[00000000] *** pong
[00001000] *** pong
[00002000] *** pong
x = true;
[00003000] true
sleep (3s);
[00003000] *** ping
[00004000] *** ping
[00005000] *** ping
x = false;
[00006000] false
sleep (2s);
[00006000] *** pong
[00007000] *** pong
25.3 every
Ключевое слово every позволяет запустить повторение выполнения кода через заданный период времени.
// печатает сообщение каждую секунду
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?
25.4 waituntil
конструкция waituntil схожа c at, она используется для задержки выполнения участка кода, пока не будет выполнено заданное условие, которое может быть либо событием, либо логическим выражением.
var e = Event.new;
{
waituntil (e?);
echo ("caught e");
},
e!;
[00021054] *** caught e
26. События
urbiScript позволяет определять события, которые должны обрабатываться с помощью конструкций at и whenever.
Событие может быть создано с использованием прототипа Event. Запуск события можно выполнить с помощью команды (!).
var myEvent = Event.new;
[00000000] Event_0x0
at (myEvent?)
echo("ping");
myEvent!;
[00000000] *** ping
// события хорошо работают параллельно
myEvent! & myEvent!;
[00000000] *** ping
[00000000] *** ping
С событиями at и whenever работают, как и было показано ранее. Т.е. at отрабатывает один раз при изменении/переключении условия/выражения. А код whenever выполняется снова и снова.
var myEvent = Event.new;
[00000000] Event_0x0
whenever (myEvent?)
{
echo("ping (whenever)")|
sleep(200ms)
};
at (myEvent?)
{
echo("ping (at)")|
sleep(200ms)
};
// запустим myEvent на 0.3 секунды
myEvent! ~ 300ms;
[00000000] *** ping (whenever)
[00000100] *** ping (whenever)
[00000000] *** ping (at)
27. Исключения
Для вызова исключения используется ключевое слово throw. Вызов исключения прерывает выполнение пока оно не будет обработано или пока не достигнут верхний уровень:
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
27.1 Перехват исключений
Перехват исключений осуществляется конструкцией try/catch.
В блоке try заключается операция, которая может вызвать исключение. Перехват исключения осуществляется последующими блоками catch, каждый из которых имеет паттерн с которым сравнивается возникшее исключение.
Возникшее исключение в блоке try последовательно сравнивается с паттерном блоков catch.
В случае совпадения, выполняется код соответствующего блока и выполнение продолжается после блока try/catch.
Если подходящего паттерна не нашлось, то исключение не будет перехвачено и оно пройдёт дальше.
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
27.2 Просмотр исключений
Исключение — это объект Exception, у которого можно посмотреть свойства.
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);
};
};
28. Проверки с помощью assert
функция assert позволяет осуществлять проверки в коде. Эта функция очень полезна для отладки и отлова ошибок во время написания программы.
Однако использование этой функции в конечной версии программы нежелательно, т.к. сильно влияет на производительность.
Поэтому assert-ы можно отключить через System.ndebug.
Если переменную System.ndebug установить в true, то assert-ы выполняться не будут.
function one() { echo("called!"); 1 }|;
assert(!System.ndebug);
assert(one);
[00000617] *** called!
System.ndebug = true|;
assert(one);
System.ndebug = false|;
assert(one);
[00000622] *** called!
assert можно вызывать как обычную функцию, либо применительно к целой области
assert(1 == 1 + 1);
[00000002:error] !!! failed assertion: 1 == 1.'+'(1) (1 != 2)
assert
{
1==1;
2==2;
};
assert
{
1==1;
2==3;
};
[00000000:error] !!! 30.1588-1591: failed assertion: 2 == 3 (2 != 3)
[00000000:error] !!! called from: 30.1588-1591: assertCall
