Tick-tock, v2.0, описание
Posted on

Tick-tock — интерпретируемый высокоуровневый язык программирования. Представляет собой конкурентную (по модели акторов) машину Тьюринга.
Общее описание
Структура программы
Программы на данном языке представляют собой список акторов. Каждый актор имеет текущее состояние (по умолчанию — __initialization__) и список всех поддерживаемых состояний. Каждое из состояний характеризуется именем (уникальным в пределах актора) и списком обработчиков сообщений. Обработчик сообщений так же имеет имя (уникальное в пределах состояния) и список команд. Например:
actor Main()
state __initialization__()
message __initialize__()
outln("Hello, world!")
;
;
;
Кроме прямого описания акторы могут быть созданы во время работы программы по образцу (классу актора).
Работа программы заключается в обмене сообщениями между акторами, переключении их состояний и выполнении соответствующих принятым сообщениям команд.
У каждого актора есть очередь входящих сообщений, имеющая некоторый размер. Актор по очереди забирает по одному сообщению из очереди, выбирает список обработчиков, соответствующий текущему состоянию, и ищет среди них соответствующий принятому сообщению. После чего выполняет команды из него.
Ключевых команд три:
startсоздаёт актор по указанному классу (как образцу);sendотправляет сообщение всем акторам;setпереключает состояние у того актора, в котором она указана.
Выполнение скрипта начинается с автоматической рассылки всем акторам сообщения __initialize__.
Гарантии выполнения
Акторы работают независимо друг от друга — конкурентно.
Акторы обрабатывают строго по одному сообщению за раз — обработка принятого сообщения будет обязательно полностью завершена до начала обработки следующего.
Создание актора командой start выполняется синхронно. Таким образом сразу после завершения обработки данной команды созданный актор уже начнёт принимать сообщения.
Отправка сообщения командой send выполняется асинхронно. Таким образом побочные эффекты последующей команды (в том числе другой команды send) могут возникнуть до побочных эффектов предыдующей команды send.
Установка состояния командой set выполняется синхронно. Таким образом следующее сообщение обязательно будет обрабатываться уже одним из обработчиков того состояния, которое будет установлено данной командой. При этом установка параметров состояния будет иметь эффект начиная с обработки только следующего сообщения.
Вычисление аргументов описанных выше команд выполняется синхронно и до обработки самих команд. Таким образом все побочные эффекты этого вычисления возникнут так же до обработки команд.
Каждый актор обрабатывает все рассылаемые сообщения. Так что, если в его текущем состоянии имеется подходящий обработчик, сообщение обязательно будет обработано. В этом случае потерь сообщений быть не может.
Исходники
Файлы исходного кода должны быть в кодировке UTF-8 и иметь концы строк как в UNIX (LF).
Ключевые слова
10 ключевых слов: actor, class, state, message, let, start, send, set, return, when.
Типы
Типизация: строгая динамическая.
Менеджмент памяти: сборка мусора.
Нулевой тип
Название: nil.
Тип: фиктивный тип; не хранит значение, а служит маркером его отсутствия; существует единственное значение данного типа.
Копирование: по значению.
Хранение: на стеке.
Определение: значение данного типа доступно через вызов функции рантайма nil.
Вещественные числа
Название: num.
Тип: с плавающей запятой, 8 байт.
Копирование: по значению.
Хранение: на стеке.
Определение:
- целые —
/\b((0x[\da-f]+)|(0[0-7]+)|(\d+(e\d+)?)|(\d+e[\+\-]\d+))\b/i; - вещественные —
/(\.\d+(e[\+\-]\d+)?)\b|\b\d+\.\d*((e[\+\-]\d+)?\b)?/i; - символы —
/'(\\x[\da-f]{2}|\\.|[^'\n])'/i.
Списки
Название: list.
Тип: LISP-подобный список — или пустой список, или пара из головы и хвоста, где голова может иметь любой тип (и является хранимым элементом), а хвост является аналогичным списком.
Копирование: по ссылке.
Хранение:
- ссылки — на стеке;
- значения — в куче.
Определение:
- пустого списка — через оператор
[...]или вызов функции рантайма__empty_list__; - списка из головы и хвоста — через оператор
:или вызов функции рантайма__cons__; - списка из набора элементов — через оператор
[...].
Доступ к элементам:
- к количеству элементов — через вызов функции рантайма
size; - к голове списка — через вызов функции рантайма
head; - к хвосту списка — через вызов функции рантайма
tail; - к элементу по индексу — через оператор
...[...]или вызов функции рантайма__item__.
Строки
Строками являются списки, хранящие коды символов. Используется кодировка UTF-32.
Определение:
- интерпретируемые:
- в одинарных кавычках —
/'(\\x[\da-f]{2}|\\.|[^'\n])*?'/i; - в двойных кавычках —
/"(\\x[\da-f]{2}|\\.|[^"\n])*?"/i;
- в одинарных кавычках —
- сырые —
/`[^`]*?`/.
В интерпретируемых преобразуются управляющие последовательности.
Строки в одинарных кавычках допускаются, только если они длиннее 1 символа.
Классы акторов
Название: class.
Тип: фиктивный тип; не хранит значение, а служит образцом для создания акторов; каждое значение данного типа является отдельным подтипом и существует в единственном экземпляре.
Копирование: по ссылке.
Хранение:
- ссылки — на стеке;
- значения — в куче.
Определение:
"class", identifier, "(", [identifier, {",", identifier}, [","]], ")",
state, {state},
";"
Здесь первый identifier — имя класса актора, а также имя переменной, в которой будет хранится значение, соответствующее определяемому подтипу. Остальные identifier — имена параметров класса актора.
Если число установленных аргументов больше числа объявленных параметров, лишние аргументы отбрасываются. Если число установленных аргументов меньше числа объявленных параметров, параметры, которым не хватает аргументов, получают значение nil.
Поддерживается висящая запятая на конце списка параметров.
Логический тип
В качестве значений логического типа используются значения других типов:
- ложным логическим значением являются:
- значение
nil; - число 0;
- пустой список;
- значение
- истинным логическим значением являются:
- числа, отличные от 0;
- непустые списки;
- любые классы акторов.
Сущности
Обработчики сообщений
Содержат имя обрабатываемого сообщения, список параметров обрабатываемого сообщения и список команд, которые необходимо выполнить при получении данного сообщения.
Объявление:
"message", identifier, "(", [identifier, {",", identifier}, [","]], ")",
{command},
";"
Здесь первый identifier — имя обрабатываемого сообщения. Остальные identifier — имена параметров обрабатываемого сообщения.
Если число отправленных аргументов больше числа объявленных параметров, лишние аргументы отбрасываются. Если число отправленных аргументов меньше числа объявленных параметров, параметры, которым не хватает аргументов, получают значение nil.
Поддерживается висящая запятая на конце списка параметров.
Состояния акторов
Содержат имя состояния актора, список параметров состояния актора и список обработчиков сообщений, относящихся к этому состоянию.
Объявление:
"state", identifier, "(", [identifier, {",", identifier}, [","]], ")",
{message},
";"
Здесь первый identifier — имя состояния актора. Остальные identifier — имена параметров состояния актора.
Если число установленных аргументов больше числа объявленных параметров, лишние аргументы отбрасываются. Если число установленных аргументов меньше числа объявленных параметров, параметры, которым не хватает аргументов, получают значение nil.
Поддерживается висящая запятая на конце списка параметров.
Акторы
Представляют собой зелёные (легковесные) потоки. Содержат список поддерживаемых состояний. По умолчанию находятся в состоянии __initialization__.
Объявление:
"actor", identifier, "(", [identifier, {",", identifier}, [","]], ")",
state, {state},
";"
При объявлении актора неявно определяется соответсвующий ему класс.
Здесь первый identifier — имя актора, имя определяемого класса, а также имя переменной, в которой будет хранится значение, соответствующее определяемому классу. Остальные identifier — имена параметров актора и определяемого класса.
Если число установленных аргументов больше числа объявленных параметров, лишние аргументы отбрасываются. Если число установленных аргументов меньше числа объявленных параметров, параметры, которым не хватает аргументов, получают значение nil.
Поддерживается висящая запятая на конце списка параметров.
Команды
Команда let
Вычисляет выражение, результат вычисления устанавливает указанной переменной. Если такой переменной ещё нет, то она будет объявлена. Изменение значения переменной, равно как и её объявление, имеет эффект только ниже текущей команды. Операция синхронная.
Синтаксис:
"let", identifier, "=", expression
Здесь identifier — имя переменной.
Результатом команды является значение выражения.
Команда start
Создаёт актор по указанному классу (как образцу). Операция синхронная.
Синтаксис:
"start",
(identifier | "[", expression, "]"),
"(", [expression, {",", expression}, [","]], ")"
Здесь identifier — имя класса актора. expression — выражение, результат вычисления которого должен представлять собой значение, соответствующее классу акторов. Список expression — список выражений, результаты вычисления которых используются в качестве аргументов класса актора.
Поддерживается висящая запятая на конце списка выражений.
Результатом команды является значение nil.
Команда send
Отправляет всем акторам указанное сообщение с указанными аргументами. Операция асинхронная.
Синтаксис:
"send", identifier, "(", [expression, {",", expression}, [","]], ")"
Здесь identifier — имя сообщения. Список expression — список выражений, результаты вычисления которых используются в качестве аргументов сообщения.
Поддерживается висящая запятая на конце списка выражений.
Результатом команды является значение nil.
Команда set
Устанавливает текущему актору указанное состояние с указанными аргументами. Операция синхронная.
Синтаксис:
"set", identifier, "(", [expression, {",", expression}, [","]], ")"
Здесь identifier — имя состояния. Список expression — список выражений, результаты вычисления которых используются в качестве аргументов состояния.
Поддерживается висящая запятая на конце списка выражений.
Результатом команды является значение nil.
Команда return
Прерывает выполнение команд текущего обработчика сообщений.
Синтаксис:
"return"
Результатом команды является значение nil.
Выражение
Выражение может выступать в роли команды. В этом случае оно просто вычисляется, а результат вычисления отбрасывается. Может использоваться ради побочных эффектов вычисления. Операция синхронная.
Результатом команды является значение выражения.
Операции
Перечислены в порядке убывания приоритета.
| Приоритет | Операция | Описание | Ассоциативность | Типы | Функция |
|---|---|---|---|---|---|
| 0 | (...) |
вложенное выражение | — | — | — |
| 0 | [...] |
определение списка из набора элементов | — | — | — |
| 0 | ...(...) |
вызов функции | — | — | — |
| 0 | when...; |
условное выражение | — | — | — |
| 1 | ...[...] |
доступ к элементам списка | левая | список + число | __item__ |
| 2 | - |
унарный минус | правая | число | __neg__ |
| 2 | ~ |
побитовое отрицание | правая | число | __bitwise_not__ |
| 2 | ! |
логическое отрицание | правая | любой | __logical_not__ |
| 3 | * |
умножение | левая | числа | __mul__ |
| 3 | / |
деление | левая | числа | __div__ |
| 3 | % |
остаток от деления | левая | числа | __mod__ |
| 4 | + |
сложение/конкатенация | левая | числа/списки | __add__ |
| 4 | - |
вычитание | левая | числа | __sub__ |
| 5 | << |
сдвиг влево | левая | числа | __lshift__ |
| 5 | >> |
сдвиг вправо | левая | числа | __rshift__ |
| 5 | >>> |
беззнаковый сдвиг вправо | левая | числа | __urshift__ |
| 6 | & |
побитовая конъюнкция | левая | числа | __and__ |
| 7 | ^ |
побитовая исключающая дизъюнкция | левая | числа | __xor__ |
| 8 | | |
побитовая дизъюнкция | левая | числа | __or__ |
| 9 | < |
меньше | левая | nil/числа/списки | __lt__ |
| 9 | <= |
меньше или равно | левая | nil/числа/списки | __le__ |
| 9 | > |
больше | левая | nil/числа/списки | __gt__ |
| 9 | >= |
больше или равно | левая | nil/числа/списки | __ge__ |
| 10 | == |
равно | левая | любые | __eq__ |
| 10 | != |
не равно | левая | любые | __ne__ |
| 11 | && |
конъюнкция | левая | любые | — |
| 12 | || |
дизъюнкция | левая | любые | — |
| 13 | : |
определение списка из головы и хвоста | правая | любой + список | __cons__ |
Вложенное выражение
Синтаксис:
"(", expression, ")"
Определение списка из набора элементов
Синтаксис:
"[", [expression, {",", expression}, [","]], "]"
Здесь список expression — список выражений, результаты вычисления которых используются в качестве элементов списка.
Поддерживается висящая запятая на конце списка выражений.
Вызов функции
Синтаксис:
identifier, "(", [expression, {",", expression}, [","]], ")"
Здесь identifier — имя функции. Список expression — список выражений, результаты вычисления которых используются в качестве аргументов функции.
Поддерживается висящая запятая на конце списка выражений.
Условное выражение
Синтаксис:
"when",
{conditional case},
";"
Здесь conditional case — ветка условия.
Синтаксис ветки условия:
"=>", expression,
{command}
При вычислении условного выражения ветки условия вычисляются последовательно одна за другой до тех пор, пока выражение в ветке не будет истинным. Если такая ветка будет найдена, вычисление веток останавливается, и начинают выполняться команды в найденной ветке. Результат последней выполненной команды будет возвращён как результат условного выражения.
Битовые операции
Перед применением битовой операции её операнды преобразуются из числа с плавающей запятой в целое размером 8 байт. Результат битовой операции преобразуется обратно в число с плавающей запятой размером 8 байт.
В большинстве случаев операнды преобразуются в знаковое целое число. Исключением являются операции сдвига — их второй операнд преобразуется в беззнаковое целое указанного выше размера.
Так же особым случаем является беззнаковый сдвиг вправо. Если его первый аргумент отрицательный, к нему прибавляется число 1 << 32. Так что для верности вычислений в этом случае размер операнда не должен превышать 4 байт.
Конъюнкция и дизъюнкция
Конъюнкция и дизъюнкция являются ленивыми операциями — они вычисляют правый операнд только при необходимости. При этом результатом данных операций является последний вычисленный операнд.
Точка входа
Интерпретатор асинхронно запускает все предоставленные акторы. После чего отправляет всем сообщение __initialize__.
Комментарии
Определение:
- однострочные —
/\/\/.*/; - многострочные —
/\/\*.*?\*\//s.
Полная грамматика
program = {definition};
definition =
actor
| actor class;
actor =
"actor", identifier, "(", [identifier, {",", identifier}, [","]], ")",
state, {state},
";";
actor class =
"class", identifier, "(", [identifier, {",", identifier}, [","]], ")",
state, {state},
";";
state =
"state", identifier, "(", [identifier, {",", identifier}, [","]], ")",
{message},
";";
message =
"message", identifier, "(", [identifier, {",", identifier}, [","]], ")",
{command},
";";
command =
let command
| start command
| send command
| set command
| return command
| expression;
let command = "let", identifier, "=", expression;
start command =
"start", (identifier | "[", expression, "]"),
"(", [expression, {",", expression}, [","]], ")";
send command = "send", identifier, "(", [expression, {",", expression}, [","]], ")";
set command = "set", identifier, "(", [expression, {",", expression}, [","]], ")";
return command = "return";
expression = list construction;
list construction = disjunction, [":", list construction];
disjunction = conjunction, ["||", disjunction];
conjunction = equality, ["&&", conjunction];
equality = comparison, [("==" | "!="), equality];
comparison = bitwise disjunction, [("<=" | "<" | ">=" | ">"), comparison];
bitwise disjunction = bitwise exclusive disjunction, ["|", bitwise disjunction];
bitwise exclusive disjunction = bitwise conjunction, ["^", bitwise exclusive disjunction];
bitwise conjunction = shift, ["&", bitwise conjunction];
shift = addition, [("<<" | ">>>" | ">>"), shift];
addition = multiplication, [("+" | "-"), addition];
multiplication = unary, [("*" | "/" | "%"), multiplication];
unary = (("-" | "~" | "!"), unary) | accessor;
accessor = atom, {list item access};
list item access = "[", expression, "]";
atom =
number
| string
| list definition
| function call
| conditional expression
| identifier
| ("(", expression, ")");
number = INTEGER NUMBER | FLOATING-POINT NUMBER | SYMBOL;
string =
SINGLE-QUOTED INTERPRETED STRING
| DOUBLE-QUOTED INTERPRETED STRING
| RAW STRING;
list definition = "[", [expression, {",", expression}, [","]], "]";
function call = identifier, "(", [expression, {",", expression}, [","]], ")";
conditional expression = "when", {conditional case}, ";";
conditional case = "=>", expression, {command};
identifier = IDENTIFIER - key words;
key words =
"actor"
| "class"
| "state"
| "message"
| "let"
| "start"
| "send"
| "set"
| "return"
| "when";
LINE COMMENT = ? /\/\/.*/ ?;
BLOCK COMMENT = ? /\/\*.*?\*\//s ?;
INTEGER NUMBER = ? /\b((0x[\da-f]+)|(0[0-7]+)|(\d+(e\d+)?)|(\d+e[\+\-]\d+))\b/i ?;
FLOATING-POINT NUMBER = ? /(\.\d+(e[\+\-]\d+)?)\b|\b\d+\.\d*((e[\+\-]\d+)?\b)?/i ?;
SYMBOL = ? /'(\\x[\da-f]{2}|\\.|[^'\n])'/i ?;
SINGLE-QUOTED INTERPRETED STRING = ? /'(\\x[\da-f]{2}|\\.|[^'\n])*?'/i ?;
DOUBLE-QUOTED INTERPRETED STRING = ? /"(\\x[\da-f]{2}|\\.|[^"\n])*?"/i ?;
RAW STRING = ? /`[^`]*?`/ ?
IDENTIFIER = ? /[a-z_]\w*/i ?;
Рантайм
- константы:
- общие константы:
nil: nil— значение нулевого типа;
- логические константы:
false— число 0;true— число 1;
- математические константы:
nan: num;inf: num— положительная бесконечность;pi: num;e: num;
- константы для работы со списками:
__empty_list__: list<any>— пустой список;
- общие константы:
- функции:
- общие функции:
- функции для сравнения:
__eq__(x: any, y: any): bool— равно;__ne__(x: any, y: any): bool— не равно;__lt__(x: any, y: any): bool— меньше;__le__(x: any, y: any): bool— меньше или равно;__gt__(x: any, y: any): bool— больше;__ge__(x: any, y: any): bool— больше или равно;
__add__(x: num|list<any>, y: num|list<any>): num|list<any>— возвращает результат комбинирования переданных аргументов:- если оба аргумента имеют тип
num, то функция возвращает результат их сложения; - если оба аргумента имеют тип
list<any>, то функция возвращает результат их конкатенации;
- если оба аргумента имеют тип
type(value: any): str— возвращает имя типа значенияvalue;
- функции для сравнения:
- функции для работы с логическими значениями:
__logical_not__(value: any): bool— логическое отрицание;bool(value: any): bool— преобразует значение в логический тип: возвращает строго 0 или 1;
- функции для работы с числами:
__neg__(x: num): num— унарный минус;__sub__(x: num, y: num): num— вычитание;__mul__(x: num, y: num): num— умножение;__div__(x: num, y: num): num— деление;__mod__(x: num, y: num): num— остаток от деления;- битовые функции:
__bitwise_not__(x: num): num— побитовое отрицание;__lshift__(x: num, y: num): num— сдвиг влево;__rshift__(x: num, y: num): num— сдвиг вправо;__urshift__(x: num, y: num): num— беззнаковый сдвиг вправо;__and__(x: num, y: num): num— побитовая конъюнкция;__xor__(x: num, y: num): num— побитовая исключающая дизъюнкция;__or__(x: num, y: num): num— побитовая дизъюнкция;
- математические функции:
floor(x: num): num;ceil(x: num): num;trunc(x: num): num;round(x: num): num;sin(x: num): num;cos(x: num): num;tn(x: num): num;arcsin(x: num): num;arccos(x: num): num;arctn(x: num): num;angle(x: num, y: num): num— atan2;pow(base: num, exponent: num): num;sqrt(x: num): num;exp(x: num): num;ln(x: num): num;lg(x: num): num;abs(x: num): num;is_nan(x: num): bool;- генерация псевдослучайных чисел:
seed(seed: num): nil— устанавливает начальное состояние генератора псевдослучайных чисел;random(): num— возвращает псевдослучайное число в диапазоне [0; 1);
- функции для работы со списками:
__cons__(head: any, tail: list<any>): list<any>— конструирует новый список из головыheadи хвостаtail;__item__(list: list<any>, index: num): any— возвращает элемент с индексомindexиз спискаlist; если индекс выходит за границы списка, будет возвращёнnil;size(list: list<any>): num— возвращает размер (длину) спискаlist;head(list: list<any>): any— возвращает голову спискаlist; список не должен быть пустым;tail(list: list<any>): list<any>— возвращает хвост спискаlist; список не должен быть пустым;
- функции для работы со строками:
num(text: str): nil|num— парсит число из строкиtext; при ошибке парсинга будет возвращёнnil;str(value: any): str— преобразует значениеvalueв строку;strb(value: any): str— преобразует значениеvalueв строку, как логическое: еслиvalueистинно, возвращает"true", иначе —"false";strs(text: str): str— преобразует строкуtextв другую строку, экранируя её символы и окружая всю строку кавычками;strl(list: list<str>): str— преобразует список строкlistв строку, отображая при этом строки как строки;
- функции для работы с классами акторов:
name(actorClass: class): str— возвращает имя класса акторовactorClass;
- системные функции:
env(name: str): nil|str— возвращает значение переменной окруженияname, если она установлена; в противном случае возвращаетсяnil;time(): num— возвращает текущее UNIX-время по UTC в секундах;sleep(duration: num): nil— останавливает выполнение скрипта наdurationсекунд;durationможет быть вещественным числом;exit(exitCode: num): nil— завершает выполнение скрипта; код возврата будет равенexitCode;- функции для ввода/вывода:
in(count: num): nil|str— считываетcountсимволов из stdin и возвращает их в виде строки; если количество будет отрицательным, то будут считаны все доступные символы; при ошибке чтения будет возвращёнnil;inln(count: num): nil|str— считываетcountсимволов из stdin и возвращает их в виде строки; если количество будет отрицательным, то будут считаны все символы до символа'\n'; при ошибке чтения или отсутствии символа'\n'будет возвращёнnil;out(text: str): nil— выводит строкуtextв stdout;outln(text: str): nil— выводит строкуtextв stdout и переводит строку (добавляет символ'\n');err(text: str): nil— выводит строкуtextв stderr;errln(text: str): nil— выводит строкуtextв stderr и переводит строку (добавляет символ'\n').
- общие функции: