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