Tick-tock, v1.1, описание
Posted on

Tick-tock — интерпретируемый высокоуровневый язык программирования. Представляет собой конкурентную (по модели акторов) машину Тьюринга.
Общее описание
Структура программы
Программы на данном языке представляют собой список акторов. Каждый актор имеет текущее состояние (по умолчанию — __initialization__) и список всех поддерживаемых состояний. Каждое из состояний характеризуется именем (уникальным в пределах актора) и списком обработчиков сообщений. Обработчик сообщений так же имеет имя (уникальное в пределах состояния) и список команд. Например:
actor
state __initialization__
message __initialize__
outln("Hello, world!")
;
;
;
Работа программы заключается в обмене сообщениями между акторами, переключении их состояний и выполнении соответствующих принятым сообщениям команд.
У каждого актора есть очередь входящих сообщений, имеющая некоторый размер. Актор по очереди забирает по одному сообщению из очереди, выбирает список обработчиков, соответствующий текущему состоянию, и ищет среди них соответствующий принятому сообщению. После чего выполняет команды из него.
Ключевых команд две:
sendотправляет сообщение всем акторам;setпереключает состояние у того актора, в котором она указана.
Выполнение скрипта начинается с автоматической рассылки всем акторам сообщения __initialize__.
Гарантии выполнения
Акторы работают независимо друг от друга — конкурентно.
Акторы обрабатывают строго по одному сообщению за раз — обработка принятого сообщения будет обязательно полностью завершена до начала обработки следующего.
Команда send выполняется асинхронно. Таким образом побочные эффекты последующей команды (в том числе другой команды send) могут возникнуть до побочных эффектов предыдующей команды send.
Команда set выполняется синхронно. Таким образом следующее сообщение обязательно будет обрабатываться уже одним из обработчиков того состояния, которое будет установлено данной командой.
Каждый актор обрабатывает все рассылаемые сообщения. Так что, если в его текущем состоянии имеется подходящий обработчик, сообщение обязательно будет обработано. В этом случае потерь сообщений быть не может.
Исходники
Файлы исходного кода должны быть в кодировке UTF-8 и иметь концы строк как в UNIX (LF).
Ключевые слова
6 ключевых слов: actor, state, message, let, send, set.
Типы
Типизация: строгая динамическая.
Менеджмент памяти: сборка мусора.
Нулевой тип
Название: 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.
Списки
Название: list.
Тип: LISP-подобный список — или пустой список, или пара из головы и хвоста, где голова может иметь любой тип (и является хранимым элементом), а хвост является аналогичным списком.
Копирование: по ссылке.
Хранение:
- ссылки — на стеке;
- значения — в куче.
Определение:
- пустого списка — через оператор
[...]или вызов функции рантайма__empty_list__; - списка из головы и хвоста — через оператор
:или вызов функции рантайма__cons__; - списка из набора элементов — через оператор
[...].
Доступ к элементам:
- к количеству элементов — через вызов функции рантайма
size; - к голове списка — через вызов функции рантайма
head; - к хвосту списка — через вызов функции рантайма
tail; - к элементу по индексу — через оператор
...[...]или вызов функции рантайма__item__.
Строки
Строками являются списки, хранящие коды символов. Используется кодировка UTF-32.
Определение:
- интерпретируемые —
/"(\\x[\da-f]{2}|\\.|[^"\n])*?"/i; - сырые —
/`[^`]*?`/.
В интерпретируемых преобразуются управляющие последовательности.
Сущности
Обработчики сообщений
Содержат имя обрабатываемого сообщения и список команд, которые необходимо выполнить при получении данного сообщения.
Объявление:
"message", identifier,
command, {command},
";"
Здесь identifier — имя обрабатываемого сообщения.
Состояния
Содержат имя состояния актора и список обработчиков сообщений, относящихся к этому состоянию.
Объявление:
"state", identifier,
message, {message},
";"
Здесь identifier — имя состояния актора.
Акторы
Представляют собой зелёные (легковесные) потоки. Содержат список поддерживаемых состояний. По умолчанию находятся в состоянии __initialization__.
Объявление:
"actor",
state, {state},
";"
Команды
Команда let
Вычисляет выражение, результат вычисления устанавливает указанной переменной. Если такой переменной ещё нет, то она будет объявлена. Изменение значения переменной, равно как и её объявление, имеет эффект только ниже текущей команды. Операция синхронная.
Синтаксис:
"let", identifier, "=", expression
Здесь identifier — имя переменной.
Команда send
Отправляет указанное сообщение всем акторам. Операция асинхронная.
Синтаксис:
"send", identifier
Здесь identifier — имя сообщения.
Команда set
Устанавливает указанное состояние текущему актору. Операция синхронная.
Синтаксис:
"set", identifier
Здесь identifier — имя состояния.
Выражение
Выражение может выступать в роли команды. В этом случае оно просто вычисляется, а результат вычисления отбрасывается. Может использоваться ради побочных эффектов вычисления. Операция синхронная.
Операции
Перечислены в порядке убывания приоритета.
| Приоритет | Операция | Описание | Ассоциативность | Типы |
|---|---|---|---|---|
| 0 | (...) |
вложенное выражение | — | — |
| 0 | [...] |
определение списка из набора элементов | — | — |
| 0 | ...(...) |
вызов функции | — | — |
| 1 | ...[...] |
доступ к элементам списка | левая | список + число |
| 2 | - |
унарный минус | правая | числа |
| 3 | * |
умножение | левая | числа |
| 3 | / |
деление | левая | числа |
| 3 | % |
остаток от деления | левая | числа |
| 4 | + |
сложение/конкатенация | левая | числа/списки |
| 4 | - |
вычитание | левая | числа |
| 5 | : |
определение списка из головы и хвоста | правая | любой + список |
Вложенное выражение
Синтаксис:
"(", expression, ")"
Определение списка из набора элементов
Синтаксис:
"[", [expression, {",", expression}, [","]], "]"
Поддерживаются висящие запятые на конце списка элементов.
Вызов функции
Синтаксис:
identifier, "(", [expression, {",", expression}, [","]], ")"
Здесь identifier — имя функции.
Поддерживаются висящие запятые на конце списка аргументов.
Точка входа
Интерпретатор асинхронно запускает все предоставленные акторы. После чего отправляет всем сообщение __initialize__.
Комментарии
Определение:
- однострочные —
/\/\/.*/; - многострочные —
/\/\*.*?\*\//s.
Полная грамматика
program = actor list;
actor list = actor, {actor};
actor = "actor", state list, ";";
state list = state, {state};
state = "state", identifier, message list, ";";
message list = message, {message};
message = "message", identifier, command list, ";";
command list = command, {command};
command = let command | send command | set command | expression;
let command = "let", identifier, "=", expression;
send command = "send", identifier;
set command = "set", identifier;
expression = list construction;
list construction = addition, [":", list construction];
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
| identifier
| ("(", expression, ")");
number = INTEGER NUMBER | FLOATING-POINT NUMBER;
string = INTERPRETED STRING | RAW STRING;
list definition = "[", [expression, {",", expression}, [","]], "]";
function call = identifier, "(", [expression, {",", expression}, [","]], ")";
identifier = IDENTIFIER - key words;
key words = "actor" | "state" | "message" | "let" | "send" | "set";
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 ?;
INTERPRETED STRING = ? /"(\\x[\da-f]{2}|\\.|[^"\n])*?"/i ?;
RAW STRING = ? /`[^`]*?`/ ?
IDENTIFIER = ? /[a-z_]\w*/i ?;
Рантайм
- константы:
- общие константы:
nil: nil— значение нулевого типа;
- математические константы:
nan: num;inf: num— положительная бесконечность;pi: num;e: num;
- константы для работы со списками:
__empty_list__: list<any>— пустой список;
- общие константы:
- функции:
- общие функции:
__add__(x: num|list<any>, y: num|list<any>): num|list<any>— возвращает результат комбинирования переданных аргументов:- если оба аргумента имеют тип
num, то функция возвращает результат их сложения; - если оба аргумента имеют тип
list<any>, то функция возвращает результат их конкатенации;
- если оба аргумента имеют тип
type(value: any): str— возвращает имя типа значенияvalue;
- функции для работы с числами:
__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— остаток от деления;- математические функции:
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;- генерация псевдослучайных чисел:
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в строку;strs(text: str): str— преобразует строкуtextв другую строку, экранируя её символы и окружая всю строку кавычками;strl(list: list<str>): str— преобразует список строкlistв строку, отображая при этом строки как строки;
- системные функции:
env(name: str): nil|str— возвращает значение указанной переменной окружения, если она установлена; в противном случае возвращается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'или, если он отсутствует, все доступные символы; при ошибке чтения будет возвращён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').
- общие функции: