# Выражения фильтра посылок

## Содержание

1. Типы данных
2. Статусы посылок
3. Преобразования типов
4. Примитивы доступа к базе посылок
5. Другие примитивы
6. Приоритеты операций
7. Операции
8. Примеры

Выражение фильтра посылок позволяет задать условия, которым должны удовлетворять параметры посылок, чтобы быть показанными в списке посылок, генерируемом CGI-программами `new-master` и `new-judge`. Выражение фильтра должно иметь тип `bool`, а в противном случае генерируется ошибка.

При генерации страницы привилегированного пользователя в CGI-программах `new-judge` или `new-master` выражение фильтра используется следующим образом. Выражение фильтра применяется ко всем записям в базе посылок, и если на некоторой записи результат вычисления выражения равен `true`, то данная запись помечается как удовлетворяющая фильтру. Если при вычислении выражения фильтра хотя бы для одной посылки возникла ошибка, отображается информация об ошибке, а не результаты фильтрации. Если при вычислении выражения фильтра для всех записей завершилось успешно, из записей, удовлетворяющих выражению фильтра, отображаются записи в соответствии с заданным номером первой и номером последней записей.

Выражение фильтра посылок имеет Си-подобный синтаксис. Пробельные символы, разделяющие элементы выражения, игнорируются. В именах типов и полей регистр символов является значимым.

## Типы данных

Выражение фильтра посылок строго типизировано. Выражение может состоять из операций над значениями следующих типов:

- Булевский. Булевский тип обозначается `bool`. Литералы булевского типа обозначаются `false` и `true` соответственно.
- Целый. Целый тип обозначается `int`. В текущей реализации целый тип является 32-битным знаковым типом (диапазон значений от -2147483648 до 2147483647). Литералы целого типа могут записываться в восьмеричной, десятичной и шестнадцатеричной системах счисления как в языке Си. Знак «минус» перед числом не является частью числа, а рассматривается как унарная операция изменения знака.
- Строковой. Строковой тип обозначается `string`. Литералы строкового типа записываются либо в кавычках (`"`), либо в апострофах (`'`). Литералы первого вида не могут содержать внутри себя символ кавычки, а литералы второго вида — символ апострофа.
- Календарный. Календарный тип обозначается `date_t` и предназначен для записи астрономического времени. Литералов календарного типа не существует. Астрономическое время при расчётах представляется в формате POSIX, то есть как количество секунд, прошедших с 1 января 1970 года.
- Длительностный. Длительностный тип обозначается `dur_t` и предназначен для записи длительностей. При расчётах длительностный тип рассматривается как целый тип, и все длительности представляются в секундах. Литералов длительностного типа не существует.
- Размерный. Размерный тип обозначается `size_t` и предназначен для представления размеров объектов. Литералов размерного типа не существует. При расчётах размерный тип рассматривается как беззнаковый целый тип.
- Статусный. Статусный тип обозначается `result_t` и предназначен для представления статуса посылки. Статусный тип — это перечислимый тип, состоящий из литералов `OK`, `CE`, `RT`, `TL`, `PE`, `WA`, `CF`, `PT`, `AC`, `IG`, `DQ`, `PD`, `ML`, `SE`, `RU`, `CD`, `CG`, `AV`, `EM`, `VS`, `VT`.
- Контрольный. Контрольный тип обозначается `hash_t` и предназначен для представления значений контрольной суммы SHA1. Литералов контрольного типа не существует.
- Адресный. Адресный тип обозначается `ip_t` и предназначен для представления IP-адресов. Литералов адресного типа не существует.

## Статусы посылок

`OK` | OK
`CE` | Compilation error
`RT` | Run-time error
`TL` | Time-limit exceeded
`PE` | Presentation error
`WA` | Wrong answer
`CF` | Check failed (internal error)
`PT` | Partial solution
`AC` | Accepted
`IG` | Ignored
`DQ` | Disqualified
`PD` | Pending
`ML` | Memory-limit error
`SE` | Security violation
`SY` | Synchronization error
`SV` | Style violation
`WT` | Wall time (real time) limit exceeded
`PR` | Pending review
`SM` | Summoned for defence
`RJ` | Rejected
`RU` | Running (in testing queue or being tested)
`CD` | Compiled (but not yet running)
`CG` | Compiling (in compile queue or being compiled)
`AV` | Available for testing
`EM` | Empty record
`VS` | Virtual start
`VT` | Virtual stop

## Преобразования типов

Выражение фильтра посылок строго типизировано, но для преобразований значений одного типа в значения другого типа могут использоваться операции преобразования типа. Операция преобразования типа записывается в стиле Си++, то есть следующим образом:

    type-cast-op = type-name "(" expr ")"

Здесь `type-name` — имя типа, одно из перечисленных выше `bool`, `int`, `string`, `date_t`, `dur_t`, `size_t`, `result_t`, `hash_t`, `ip_t`. Не все возможные преобразования типов допустимы. Возможные комбинации исходного типа и целевого типа показаны в таблице ниже. В строках таблицы записан исходный тип, а в столбцах таблицы — целевой тип.

| `bool` | `int` | `string` | `date_t` | `dur_t` | `size_t` | `result_t` | `hash_t` | `ip_t`
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
`bool` | + | + | + |  |  |  |  |  |
`int` | + | + | + | + | + | + | + |  | +
`string` | + | + | + | + | + | + | + | + | +
`date_t` | + | + | + | + |  |  |  |  |
`dur_t` | + | + | + |  | + |  |  |  |
`size_t` | + | + | + |  |  | + |  |  |
`result_t` | + | + | + |  |  |  | + |  |
`hash_t` | + | + | + |  |  |  |  | + |
`ip_t` | + | + | + |  |  |  |  |  | +

Рассмотрим подробнее каждое нетривиальное преобразование типов.

- `int` к `bool`.
  Даёт результат `false`, если приводимое целое значение равно нулю, и `true` иначе.
- `string` к `bool`.
  Даёт результат `false`, если значение строки равно `false` (без учёта регистра), и результат `true`, если значение строки равно `true` (без учёта регистра). Если значение строки не может быть распознано как булевский литерал, генерируется ошибка вычисления выражения.
- `date_t` к `bool`.
  Даёт результат `false`, если значение астрономического времени во внутреннем формате равно нулю, и `true` иначе. На практике астрономическое время может быть равно нулю (то есть 00:00:00 1 января 1970 года по Гринвичу), когда значение соответствующей переменной или поля не установлено.
- `dur_t` к `bool`.
  Даёт результат `false`, если значение длительности равно 0 секундам, и `true` иначе.
- `size_t` к `bool`.
  Даёт результат `false`, если значение размера равно 0 байтам, и `true` иначе.
- `result_t` к `bool`.
  Даёт результат `true`, если значение статуса равно `OK`, и `false` иначе. Обратите внимание на отличие семантики этой операции от других операций преобразования в булевский тип.
- `hash_t` к `bool`.
  Даёт результат `false`, если значение хэш-кода равно нулю, то есть все 20 байт хэш-кода равны нулю, и `true` иначе. Нулевой хэш-код означает, что значение соответствующего поля или переменной не установлено.
- `ip_t` к `bool`.
  Даёт результат `false`, если значение IP-адреса равно нулю, то есть все 4 байта IP-адреса нулевые, и `true` иначе. Нулевой IP-адрес означает, то значение соответствующего поля или переменной не установлено.
- `bool` к `int`.
  Булевское значение `false` преобразуется в целое значение 0, а булевское значение `true` — в целое значение 1.
- `string` к `int`.
  Строка рассматривается как запись числа в восьмеричной, десятичной или шестнадцатеричной нотации (в синтаксисе Си), возможно со знаком. Если число записано корректно и при переводе в 32-битный знаковый тип не возникает переполнения, результатом операции является соответствующее число. В противном случае генерируется ошибка.
- `date_t` к `int`.
  Поскольку в настоящее время внутреннее представление типа `date_t` — это 32-битное знаковое число, то значением такого преобразования типов будет внутреннее представление астрономического времени.
- `dur_t` к `int`.
  Поскольку в настоящее время внутреннее представление типа `dur_t` — это 32-битное знаковое число, то значением такого преобразования типов будет внутреннее представление промежутка времени, то есть число секунд в нём.
- `size_t` к `int`.
  В настоящее время тип `size_t` — это 32-битный беззнаковый целый тип. Если значение размера при переводе из беззнакового представления в знаковое не вызывает переполнение (то есть значение размера не превосходит 231-1), выполняется преобразование из беззнакового типа в знаковый без изменения представления числа. В противном случае генерируется ошибка.
- `result_t` к `int`.
  Результатом такого преобразования является числовое значение, соответствующее коду статуса.
- `hash_t` к `int`.
  Результатом такого преобразования является целое значение, составленное из первых 4 байтов хэш-кода. Предполагается, что байты в числе записываются в порядке от младшего к старшему (litte-endian).
- `ip_t` к `int`.
  Поскольку IP-адрес (IPv4) состоит из 4 байт, эти 4 байта рассматриваются как целое число со знаком, записанное в порядке байт от старшего к младшему.
- `bool` к `string`.
  Значение `false` преобразовывается в строку `false`, а значение `true` — в строку `true`.
- `int` к `string`.
  Целое значение преобразуется в строку, содержащую запись десятичного целого числа со знаком.
- `date_t` к `string`.
  Астрономическое время преобразуется в строку вида

      YYYY/MM/DD hh:mm:ss

  Здесь `YYYY` — год, `MM` — месяц (от 01 до 12), `DD` — день месяца (от 01 до 31), `hh` — час (от 00 до 23), `mm` — минута (от 00 до 59), `ss` — секунда (от 00 до 59).
- `dur_t` к `string`.
  Продолжительность преобразуется в строку вида

      #h:mm:ss

  Здесь `#` — знак продолжительности (для положительной продолжительности знак не выводится, а для отрицательной печатается знак `-`), `h` — число полных часов, `mm` — число минут в последнем неполном часе (от 00 до 59), `ss` — число секунд в последней неполной минуте (от 00 до 59).
- `size_t` к `string`.
  Значение размера преобразуется в строку, содержащую запись десятичного целого числа без знака.
- `result_t` к `string`.
  Значение статуса преобразовывается в строку в соответствии с таблицей (столбец «Выражение фильтра»). Например, значение статуса `RUN_TIME_ERR` преобразуется в строке `RT`.
- `hash_t` к `string`.
  Значение хэш-кода распечатывается в виде 40 шестнадцатеричных цифр (по два символа на байт от первого байта хэш-кода к последнему). В качестве шестнадцатеричных цифр используются десятичные цифры и строчные латинские буквы от `a` до `f`.
- `ip_t` к `string`.
  IP-адрес переводится в строку, содержащую запись адреса в стандартной точечной нотации (то есть 4 десятичных числа от 0 до 255, разделённые точками).
- `int` к `date_t`.
  Поскольку тип `date_t` представляется как 32-битное целое знаковое число, при данном преобразование целое значение рассматривается как внутреннее представление астрономического времени.
- `string` к `date_t`.
  Для преобразования строки к типу астрономического времени строка должна иметь значение, удовлетворяющее следующему формату

      Y / M / D [ h [ : m [ : s ] ] ]

  Здесь запись `[ X ]`, означает, что элемент `X` может отсутствовать, символы `/` и `:` представляют сами себя, а `Y`, `M`, `D`, `h`, `m`, `s` — это целые десятичные числа. Они могут отделяться от `/` и `:` произвольным количеством пробельных символов. `Y` — это год, который должен находиться в интервале от 1900 до 2100, `M` — порядковый номер месяца (от 1 до 12), `D` — порядковый номер дня в месяце (от 1 до 31), `h` — час суток (от 0 до 23), `m` — минута (от 0 до 59), `s` — секунда (от 0 до 59). Если часы, минуты или секунды опущены, они полагаются равными 0. Кроме того, дата должна находится в диапазоне представимых в POSIX дат (то есть примерно от 1906 до 2038 года). Если все условия выполняются, строковая запись астрономического времени конвертируется во внутреннее представление, а в противном случае генерируется ошибка.
- `int` к `dur_t`.
  Поскольку тип `dur_t` представляется как 32-битное целое знаковое число, при данном преобразование целое значение рассматривается как внутреннее представление промежутка времени.
- `string` к `dur_t`.
  Для преобразования строки к длительностному значению строка должна иметь значение, удовлетворяющее следующему формату.

      [ # ] h [ : m [ : s ] ]

  Здесь запись `[ X ]`, означает, что элемент `X` может отсутствовать. `#` — это знак `+` или `-`. `h`, `m` и `s` — положительные целые числа. `h` — количество часов, `m` — количество минут (от 0 до 59), `s` — количество секунд (от 0 до 59). Если минуты или секунды опущены, их число полагается равным 0. После перевода в секунды длительность должна находится в диапазоне целых чисел, представимых 32-битными знаковыми числами. Если все условия выполняются, то строковая запись длительностного значения конвертируется во внутреннее представление, а в противном случае генерируется ошибка.
- `int` к `size_t`.
  Поскольку `int` — это 32-битный знаковый тип, а `size_t` — 32-битный беззнаковый тип, неотрицательные значения типа `int` преобразовываются в значения типа `size_t` тривиально. При попытке преобразования отрицательных чисел генерируется ошибка.
- `string` к `size_t`.
  Строка должна содержать запись беззнакового целого числа в восьмеричной, десятичной или шестнадцатеричной системе (как в языке Си). Число должно быть представимо 32-битным беззнаковым числом. Если эти условия выполняются, происходит преобразование строки в значение типа `size_t`, а в противном случае генерируется ошибка.
- `int` к `result_t`.
  Целое значение должно быть равным одному из значений статусов, перечисленных в таблице. В этом случае выполняется преобразование типа, а иначе генерируется ошибка.
- `string` к `result_t`.
  Строка должна быть равна одной из строк, перечисленных в таблице в столбце «Выражение фильтра». В этом случае выполняется преобразование, а иначе генерируется ошибка.
- `string` к `hash_t`.
  Строка должна содержать 40 шестнадцатеричных цифр (буквы от `a` до `f` могут быть как заглавными, так и строчными). Пробельные символы в начале и конце строки игнорируются. 40 шестнадцатеричных цифр конвертируются в 20-байтное значение хэш-кода. Предполагается, что порядок байт в слове — от младшего к старшему (little-endian).
- `int` к `ip_t`.
  Поскольку значения типа `ip_t` представляются 32-битными числами, преобразование из типа `int` не изменяет представления данных, то есть целое число рассматривается как запись IP-адреса во внутреннем представлении.
- `string` к `ip_t`.
  Для преобразования строки к типу `ip_t` строка должна иметь значение, удовлетворяющее следующему шаблону.

      A.B.C.D

  Здесь `.` — это символ «точка», а `A`, `B`, `C` и `D` — целые беззнаковые числа от 0 до 255. Если эти условия выполняются строка конвертируется в соответствующее значение типа `ip_t`, а в противном случае генерируется ошибка.

## Примитивы доступа к базе посылок

Текущей посылкой назовём обрабатываемую при вычислении выражения фильтра посылку. На основании результата вычисления выражения фильтра определяется, может ли быть отображена текущая посылка.

Примитивы доступа к базе посылок позволяют получать значения полей как текущей посылки, так и любой другой посылки с заданным номером. Примитивы имеют следующий общий вид:

    f [ ( expr ) ]

Здесь в квадратных скобках `[` и `]` записана необязательная часть. Круглые скобки `(` и `)` обозначают сами себя. \V{f} — это имя примитива, а `expr` — это выражение целого типа. Если выражение в скобках не задано, то берётся значение поля, соответствующего имени примитива `f`, текущей посылки. Если выражение в скобках не является выражением целого типа, генерируется ошибка. В противном случае выражение вычисляется, и пусть при вычислении выражения ошибок не возникло, а n — результат вычисления выражения.

Если n < 0, то n задаёт номер посылки начиная от последней, то есть n' = N + n$, где N — общее количество посылок в базе посылок в данный момент. В противном случае предполагаем, что n задаёт номер посылки начиная от нулевой, то есть n' = n. Если теперь n' < 0 или n' ≥ N, то генерируется ошибка вычисления выражения фильтра. Если же n' удовлетворяет ограничениям, берётся значение поля, соответствующего имени примитива `f`, в посылке с номером n'.

Примитивы доступа к базе посылок перечислены в таблице.

Имя примитива | Тип значения | Описание
--- | --- | ---
`id` или `run_id` | `int` | Номер посылки (значение поля `run_id`). Посылки нумеруются от 0.
`time` | `time_t` | Астрономическое время получения посылки сервером (значение поля `time`)
`dur` | `dur_t` | Длительность времени от начала турнира до получения посылки сервером (то есть разность между временем получения посылки и моментом начала турнира)
`size` | `size_t` | Размер исходного текста программы в байтах (значение поля `size`).
`hash` | `hash_t` | Хэш-код текста программы (значение поля `sha1`).
`uuid` | `string` | Уникальный идентификатор посылки (значение поля `run_uuid`).
`ip` | `ip_t` | IP-адрес клиента, на котором работает веб-браузер, и с которого была получена данная посылка (значение поля `ip`).
`uid` или `user_id` | `int` | Идентификатор пользователя, от имени которого была выполнена данная посылка (значение поля `user_id`). Идентификатор пользователя всегда больше нуля.
`login` | `string` | Регистрационное имя (login) пользователя, от имени которого была выполнена данная посылка.
`name` | `string` | Имя (name) пользователя, от имени которого была выполнена данная посылка.
`group` | `string` | Группа первого участника пользователя, от имени которого была выполнена данная посылка.
`cypher` | `string` | Шифр пользователя, от имени которого была выполнена данная посылка.
`lang` или `lang_id` | `string` | Короткое имя языка программирования, который был использован в данной посылке. Идентификатор языка программирования находится в поле `lang_id` записи базы посылок, а короткое имя языка программирования берётся из значения конфигурационной переменной `short_name` секции описания языка программирования файла конфигурации турнира `serve.cfg`.
`arch` | `string` | Архитектура языка программирования
`prob` или `prob_id` | `string` | Короткое имя задачи, решаемой в данной посылке. Идентификатор задачи находится в поле `prob_id` записи базы посылок, а короткое имя задачи берётся из значения конфигурационной переменной `short_name` секции описания задачи файла конфигурации турнира `serve.cfg`.
`result` или `status` | `result_t` | Статус посылки (значение поля `status`).
`score` | `int` | Балл за данную посылку без учёта штрафных баллов за посылки (значение поля `score`).
`test` | `int` | Минимальный номер теста, на котором программа дала неверный результат, или количество успешно пройденных тестов в зависимости от типа турнира.
`imported` | `bool` | Флаг импортированной посылки (значение поля `is_imported`).
`hidden` | `bool` | Флаг скрытой посылки (значение поля `is_hidden`).
`readonly` | `bool` | Флаг неизменяемой посылки (значение поля `is_readonly`).
`variant` | `int` | Действительный вариант. Если для вариантной задачи номер варианта, хранящийся в базе посылок (значение поля `variant`), равен 0, используется номер варианта, установленный в файле карты вариантов, устанавливаемом глобальной конфигурационной переменной `variant_map_file` конфигурационного файла описания турнира `serve.cfg`.
`rawvariant` | `int` | Хранимый вариант задачи в посылке (значение поля `variant`).
`userinvisible` | `bool` | `true`, если посылка выполнена пользователем, у которого установлен статус invisible.
`userbanned` | `bool` | `true`, если посылка выполнена пользователем, у которого установлен статус banned.
`userlocked` | `bool` | `true`, если посылка выполнена пользователем, у которого установлен статус locked.
`userincomplete` | `bool` | `true`, если посылка выполнена пользователем, у которого установлен статус incomplete.
`userdisqualified` | `bool` | `true`, если посылка выполнена пользователем, у которого установлен статус disqualified.
`latest` | `bool` | `true`, если посылка имеет статус OK, Partial solution или Accepted for testing и после нее нет посылок того же пользователя по той же задаче с этими статусами. Предикат может применяться в турнирах типа Olympiad для отбора посылок для полной проверки.
`afterok` | `bool` | `true`, если у этого пользователя уже была посылка по этой же задаче, которая получила статус OK
`judge_id` | `int` | Идентификационный номер запроса на тестирование (поле `judge_id`). Идентификационный номер изменяется в диапазоне от 1 до 65535. Число 0 означает отсутствие идентификационного номера.
`inusergroup(GRP)` | `bool` | `true`, если этот пользователь принадлежит указанной группе пользователей. Название группы пользователей записывается как строка. Пример: `inusergroup("Group1")`.

## Другие примитивы

В выражении фильтра можно использовать примитивы для получения текущего времени, текущей продолжительности турнира и некоторые другие. Все такие примитивы рассмотрены в данном разделе. Примитивы имеют следующий общий вид:

    p

где `p` — это имя примитива. Примитивы перечислены в таблице.

Имя примитива | Тип значения | Описание
--- | --- | ---
`now` | `time_t` | Текущее астрономическое время.
`start` | `time_t` | Астрономическое время начала турнира.
`finish` | `time_t` | Астрономическое время завершения турнира.
`total` | `int` | Общее количество записей в базе посылок.

## Приоритеты операций

В данном разделе перечислены все операции, допустимые в выражении фильтра. Операции перечисляются в порядке убывания приоритета от наиболее приоритетных к наименее приоритетным. Приоритеты операций совпадают с приоритетами операций в языках Си, Си++, Java.

1. Все литеральные значения (булевские, целые, строковые, статусные), все примитивы, операции преобразования типа, операция записи выражения в скобках `(`expr`)`.
2. Префиксные операции `~`, `!`, `-`, `+`. Префиксные операции читаются справа налево.
3. Мультипликативные операции `*`, `/`, `%`. Мультипликативные операции левоассоциативны, то есть читаются слева направо.
4. Аддитивные операции `+`, `-`. Они читаются также слева направо.
5. Операции сдвига `<<` и `>>`. Читаются слева направо.
6. Операции отношений `==`, `!=`, `<`, `>`, `<=`, `>=`, `~=`. Читаются слева направо.
7. Операция побитового «и» `&`. Читается слева направо.
8. Операция побитового исключающего «или» `^`. Читается слева направо.
9. Операция побитового «или» `|`. Читается слева направо.
10. Операция логического «и» `&&` или `and` (эти формы записи синонимичны). Читается слева направо.
11. Операция логического «или» `||` или `or` (эти формы записи синонимичны). Читается слева направо.

Далее рассмотрим все перечисленные операции.

## Операции

### Операция побитового отрицания `~`

Операция применима только к значению типа `int`. Результат операции — значение типа `int`, получаемое побитовым отрицанием первого значения.

### Операция логического отрицания `!`

Операция применима только к значению типа `bool`. Результат операции — значение типа `bool`, получаемое логическим отрицанием исходного значения.

### Операция смены знака `-`

Унарная операция смены знака применима только к значению типа `int`. Результат операции — значение типа `int` с противоположным знаком. Если результат операции не представим в типе `int` (то есть 32-битным знаковым числом), диагностируется ошибка переполнения.

### «Пустая» операция `+`

Данная операция применима только к значению типа `int` и даёт результат типа `int`. Результирующее значение равно исходному.

### Операция умножения `*`

Для операции умножения возможны следующие комбинации типов операндов.

- Оба аргумента имеют тип `int`. Результат имеет тип `int`. Если результат не представим в типе `int` диагностируется переполнение.
- Один аргумент имеет тип `int`, а другой — `dur_t`. В этом случае результат имеет тип `dur_t`. Если произведение аргументов не представимо в типе `dur_t`, диагностируется переполнение.
- Один аргумент имеет тип `int`, а другой — `size_t`. Значение аргумента целого типа в данном случае должно быть больше нуля. Произведение имеет тип `size_t`. Если значение произведения не представимо в типе `size_t`, диагностируется переполнение.

### Операция целочисленного деления `/`

Для операции целочисленного деления возможны следующие комбинации типов операндов. Если делитель равен нулю, диагностируется ошибка деления на ноль. Если результат операции не представим в типе результата, диагностируется ошибка переполнения. Например, при делении минимального значения типа `int`, равного −231 на −1 получается значение 231, не представимое в типе `int`.

- Оба аргумента имеют тип `int`. Тогда результат имеет тип `int`.
- Оба аргумента имеют тип `dur_t`. Тогда результат имеет тип `int`.
- Оба аргумента имеют тип `size_t`. Тогда результат имеет тип `int`.
- Делимое имеет тип `dur_t`, а делитель — тип `int`. Тогда результат имеет тип `dur_t`.
- Делимое имеет тип `size_t`, а делитель — тип `int`. Результат в этом случае имеет тип `size_t`. Делитель должен быть положителен.

### Операция взятия остатка от деления `%`

Операция взятия остатка поддерживает несколько комбинаций типов аргументов. Если делитель равен нулю, диагностируется ошибка деления на ноль. Если тип делителя — какой-либо знаковый тип (например, `int` или `dur_t`), и делитель отрицателен, диагностируется ошибка неверного аргумента. Если результат операции не представим в типе результата, диагностируется ошибка переполнения. Допустимые комбинации типов операндов перечислены ниже.

- Оба аргумента имеют тип `int`. Тогда результат имеет тип `int`.
- Оба аргумента имеют тип `dur_t`. Тогда результат имеет тип `int`.
- Оба аргумента имеют тип `size_t`. Тогда результат имеет тип `int`.
- Делимое имеет тип `dur_t`, а делитель — тип `int`. Тогда результат имеет тип `dur_t`.
- Делимое имеет тип `size_t`, а делитель — тип `int`. Результат в этом случае имеет тип `size_t`.

### Операция сложения `+`

Операция сложения применима ко многим комбинациям типов операндов. В любом случае, если результат операции не представим в типе результата, генерируется ошибка переполнения. Допустимые комбинации типов операндов перечислены ниже.

- Оба аргумента имеют тип `int`. Результат также имеет тип `int`.
- Оба аргумента имеют тип `string`. Результат имеет тип `string` и равен конкатенации двух строк.
- Оба аргумента имеют тип `dur_t`. Результат также имеет тип `dur_t`.
- Оба аргумента имеют тип `size_t`. Результат также имеет тип `size_t`.
- Один аргумент имеет тип `int`, а другой — `time_t`. Результат имеет тип `time_t`.
- Один аргумент имеет тип `int`, а другой — `dur_t`. Результат имеет тип `dur_t`.
- Один аргумент имеет тип `time_t`, а другой — `dur_t`. Результат имеет тип `time_t`.

### Операция вычитания `-`

Операция вычитания применима ко многим комбинациям типов операндов. В любом случае, если результат операции не представим в типе результата, генерируется ошибка переполнения. Допустимые комбинации типов операндов перечислены ниже.

- Оба аргумента операции имеют тип `int`. Результат также имеет тип `int`.
- Первый аргумент операции имеет тип `int`, а второй — `dur_t`. Результат операции имеет тип `dur_t`.
- Первый аргумент операции имеет тип `time_t`, а второй — `int`. Результат операции имеет тип `time_t`.
- Оба аргумента операции имеют тип `time_t`. В этом случае результат имеет тип `dur_t`.
- Первый аргумент операции имеет тип `time_t`, а второй — `dur_t`. Результат имеет тип `time_t`.
- Первый аргумент имеет тип `dur_t`, а второй — `int`. Результат имеет тип `dur_t`.
- Оба аргумента операции имеют тип `dur_t`. В этом случае результат имеет тип `dur_t`.
- Первый аргумент операции имеет тип `size_t`, а второй — `int`. Тогда результат имеет тип `size_t`.
- Оба аргумента операции имеют тип `size_t`. В этом случае результат имеет тип `int`.

### Операции сдвига `<<` и `>>`

Операции побитового сдвига влево `<<` и побитового сдвига вправо `>>` применимы только к операндам типа `int`. Результат операции имеет тип `int`. Второй аргумент операции (количество бит сдвига) должен находиться в отрезке от 0 до 32 включительно. Если это условие не выполняется, генерируется ошибка недопустимого аргумента операции. Сдвиг вправо выполняется как побитовый сдвиг, то есть на место старших разрядов числа помещаются нулевые биты. Переполнения при сдвиге влево не диагностируется.

### Операции отношения `==` и `!=`

Операции проверки на равенство или неравенство применимы ко всем типам данных. Оба аргумента должны иметь один и тот же тип. Неявных преобразований типа не производится. Результат операции имеет тип `bool`.

### Операции отношения `<`, `>`, `<=`, `>=`

Данные операции применимы ко всем типам данных, кроме `result_t`, `hash_t` и `ip_t`. Оба аргумента операции должны иметь один и тот же тип данных. Результат операции имеет тип `bool`.

### Сопоставление с регулярным выражением `~=`

Данная операция применима к двум строкам. Первая строка проверяется на соответствие регулярному выражению, записанному во второй строке.

### Побитовые операции `^`, `&`, `|`

Побитовые операции применимы только к аргументам типа `int` и в результате дают значение типа `int`.

### Логические операции `&&` и `||`

Логические операции применимы только к аргументам типа `bool` и дают в результате значение типа `bool`. Как и в языке Си значение второго аргумента операции не вычисляется, если значение всего выражение известно.

## Примеры

- Показать посылки на языке `gcc`:

      lang == "gcc"

- Показать посылки по задаче `A`:

      prob == "A"

- Показать успешные посылки пользователя с логином `serge`:

      login == "serge" && status == OK