Разделы сайта находятся в разработке.

Материалы могут быть неполными или содержать ошибки. Содержимое сайта будет синхронизировано с реализацией при выходе следующей версии, тогда как текущая (0.6.0) предназначена для прототипирования синтаксиса и создания песочницы.

Условия и циклы

В TrustLang нет ключевого слова if: условие проверяется конструкцией, которая по смыслу соответствует математическому «следует» — два тире и угловая скобка -->. Запись легко объединяется в цепочки для проверки нескольких условий вида «else if». Ниже конструкция показана обеими формами — DSL-макросом и базовым синтаксисом (о двух формах записи см. Макросы и DSL):

Макросы DSLБазовый синтаксис
@if( условие1 ) {
    действие1
} @elif( условие2 ) действие2
@else {
    действие_иначе
};
[ условие1 ] --> { действие1 },
[ условие2 ] --> действие2,
[ ... ] --> { действие_иначе };

Для записи циклов используется оператор <-> (в базовой записи) или макросы @while/@dowhile (в DSL). Условие записывается в квадратных скобках; в зависимости от взаимного расположения условия и тела цикл бывает с предусловием (while) или с постусловием (do while). Эквивалентные формы:

Макросы DSLБазовый синтаксис
@while( cond ) {
    тело цикла
};
[ cond ] <-> {
    тело цикла
};
{
    тело цикла
} @dowhile( cond );   # постусловие
{
    тело цикла
} <-> [ cond ];   # постусловие
@while( cond ) {
    ...
} @else {
    ...    # если cond == false при входе
};
[ cond ] <-> {
    ...
}, [ ... ] --> {
    ...    # ветка else
};

Цикл с предусловием (while) поддерживает ветку else, которая выполняется, если условие входа в цикл не было выполнено ни разу.

Внимание: это отличается от аналогичной конструкции в Python, где секция else выполняется всегда, кроме прерывания цикла по break.

Перебор коллекций (foreach)

У цикла foreach нет отдельного ключа DSL — он реализуется циклом с деструктуризацией элемента и мутацией источника (оператор раскрытия списка). Пример суммирования элементов словаря:

summa := 0;
dict := (1,2,3,4,5,);
[ dict ] <-> {          # условие цикла — пока в dict есть данные
    # распаковка: первый элемент переходит в item, суффикс dict... — оставшиеся
    item, dict... := ... dict;
    summa += item;      # накопление суммы
};

Сопоставление с образцом (match)

Оператор оценки выражения (match) — приблизительный аналог операторов switch/match в других языках. Он задаётся конструкцией [ выражение ] ==> { ... } (базовый синтаксис) или макросом @match (DSL), в теле которых перечисляются ветки-условия. Эквивалентные формы:

Макросы DSLБазовый синтаксис
@match( $var ) ==> {
    @case( 1 ) { code };
    @case( 1, 2 ) { code };
    @default { code default };
};
[ $var ] ==> {
    [1] --> { code };             # $var == 1
    [1, 2] --> { code };          # ($var == 1 || $var == 2)
    [...] --> { code default };   # иначе
};

Хотя оператор внешне похож на сопоставление с образцом (pattern matching), по сути это краткая запись множественного оператора сравнения: в качестве оператора оценки можно использовать любой оператор сравнения:

  • ==> — равенство с приведением типов;
  • ===> — точное равенство;
  • ~> — проверка типа (имени класса);
  • ~~> — утиная типизация;
  • ~~~> — строгая утиная типизация.

Если в качестве оператора сравнения используется утиная типизация, оценка превращается в классическое сопоставление с образцом по полям (пример приведён на форме @match):

$value := (f1=1, f2='2',);
@match( $value ) ~~> {
    @case((f1=_,), (f1=_, f2=0,)) { ... }; # поле f2 отсутствует или является числом
    @case((f1=_, f2="",), (f1=_, f2='',)) { ... }; # поле f2 — строка
    @default { ... };
};

Переопределение функции сравнения (атрибут @[matcher("fn")])

Если сравнение по значению не сводится к == (например, сопоставление строки с регулярным выражением), функцию сравнения match можно переопределить атрибутом @[matcher("fn")], где fn — объявленная ранее функция-предикат с сигнатурой bool fn(T_value, T_pattern). В каждой ветке вместо сравнения (value == pattern) вызывается предикат fn(value, pattern); проверяемое выражение (scrutinee) вычисляется один раз во временную переменную. При заданном матчере ветки всегда порождаются как if/else-цепочка (оператор switch неприменим — шаблон не обязан быть константой).

Атрибут ставится между значением и оператором (на «сырой» форме, так как макрос @match требует оператор сразу после себя):

@func matches_regex(value:StrChar, pattern:StrChar):Bool { ... };
$s := 'foobar';
[ $s ] @[matcher("matches_regex")@] ==> {
    @case('^foo') { ... };
    @case('bar$', 'baz') { ... };
    @default { ... };
};

Семантика проверяет, что fn — объявленная функция-предикат ровно с двумя параметрами и логическим (булевским) возвратом. Атрибут @[matcher] несовместим с сопоставлением по типу (~>/~~>/~~~>).