---
# System prepended metadata

title: Slime

---

# Slime

![](https://i.imgur.com/lepTKFG.png)
<!-- ![](https://i.imgur.com/pLVexp9.png) -->

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

*некоторые из перечисленных средств требуют реализации собственного парсера и интерпретатора текстового содержания функций

## Спецификация

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

- Массив - последовательный контейнер произвольного доступа, элементами которого могут быть данные любого типа.
    Массив имеет заранее определённую длину - целое число (неограниченного диапазона). Модуль длины массива определяет количество содержащихся в нём элементов, а знак - порядок индексации
    - массивы положительной длины - индексируются с нуля
        ```slime
        array = ["a", "b", "c"];
        print(array[0]);
        print(array[1]);
        print(array[2]);
        ```
        Вывод:
        ```bash
        abc
        ```
    - массивы отрицательной длины - индексируются также с нуля, но уже в отрицательном направлении
        ```slime
        array = -["a", "b", "c"];
        print(array[0]);
        print(array[-1]);
        print(array[-2]);
        ```
        Вывод:
        ```bash
        abc
        ```
    Обращение к элементу массива за пределами его диапазона возвращает пустой массив, а запись по такому индексу не производит никакого эффекта (такая операция записи также возвращает `[]`).


### Комментарии

Комментарии как в питоне `#`

### Способы определить массив

```slime
# Просто как массив
x = [[], [[], [], []], [[[]]]];

# Числовые литералы
# Определяют массив, длина которого соответствует значению литерала,
# заполненный пустыми массивами
x = 4;          # эквивалентно [[], [], [], []]
# Также поддерживаются двоичные, восьмеричные и шестнадцатеричные числовые литералы
bin = 0b001001;
oct = 010;      # Это 8
hex = 0xC0FFEE;


# символьные литералы
# Эквивалентны числовым литералам, определяющим соответствующую кодовую точку Unicode
x = 'x';        # эквивалентно 120

# Строковые литералы
# Эквивалентны определению массива символьных литералов,
# составляющих данную строку
str = "Hello Slime!";
# эквивалентно ['H', 'e', 'l', 'l', 'o', ' ', 'S', 'l', 'i', 'm', 'e', '!']

# Строковые и символьные литералы поддерживают escape последовательности,
# аналогично языку Си
str = "\t***\n\t*x*\n\t***"

# Объявление функции
fib = {
    @[0] <= 0 || (fib(@[0] - 1) + fib(@[0] - 2))
};
# Объявление функции всегда создаёт массив из двух элементов,
# первый из которых число (на самом деле массив, длина которого равна этому числу),
# равное индексу фрейма стека, в котором объявлена функция,
# а второй - исходный текст тела функции

# Объявление функции fib в глобальном пространстве эквивалентно следующей записи
fib = [0, "\n    @[0] <= 0 || (fib(@[0] - 1) + fib(@[0] - 2))\n"];
```

### Операторы

#### Унарные операторы

- `+` — ничего не делает
    ```slime 
    simple_x = [1, 2, 3];
    added_x = +[1, 2, 3];
    if {simple_x == added_x} {
        print("simple_x == added_x");
    }
    ```
    Вывод:
    ```
    simple_x == added_x
    ```
- `-` — создаёт массив с таким же числом элементов, но инвертированным знаком длины. Элемент с индексом `i` исходного массива равен элементу с индексом `-i` результирующего
    ```slime
    x = -[1, 2, 3]; # x[0] == 1, x[-1] == 2, x[-2] == 3
    ```
- `!` - пустой массив превращает в массив, содержащий один пустой массив, любой другой - в пустой массив
    ```slime
    x = ![];        # [[]]
    x = ![1, 2, 3]  # []
    ```

#### Бинарные операторы

- Операции сравнения `>`, `<`, `>=`, `<=`, `==`, `!=` - реализуют полное глубокое лексикографическое сравнение. Массив отрицательной длины всегда считается меньше массивов положительной или нулевой длины. Сравнение двух массивов отрицательной длины на `>`, `<`, `>=`, `<=`, `==`, `!=` эквивалентно сравнению обратным им массивов (взятых со знаком `-`) на `<`, `>`, `<=`, `>=`, `==`, `!=` соответственно.
    ```slime
    # (a > b) эквивалентно (-a > -b)
    # (a <= b) эквивалентно (-a <= -b)
    ```
    Операции сравнения возвращают `[]` если результат сравнения ложь, и `[[]]`, если истина

- `+` — конкатенирует массивы. 
    ```slime
    x = [1, 2, 3] + ["hello", "slime"]; # [1, 2, 3, "hello", "slime"]
    y = -[1, 2, 3] + -[4, 5];           # -[1, 2, 3, 4, 5] ?

    # Отрицательные массив при конкатенации с положительным
    # уменьшает его размер на собственную длину
    a = [1, 2, 3] + -["hello", "slime"];                # [1]
    b = [1, 2, 3] + -["hello", "slime", "!", "!!!"];    # -["!!!"]
    c = [1] + -["hello", "slime", "!", "!!!"];          # -["slime", "!", "!!!"]

    # Для конкатенации применимо следующее правило
    # -(a + b) == (-b + -a)
    p = -[1] + [a, b, c]                    # -([1] + -[a, b, c]) => [b, c]
    q = -[1, 2, 3] + -["hello", "slime"];   # -[1, 2, 3, "hello", "slime"]
    ```

- `-` — эквивалентен сложению с отрицательным массивом
    ```slime
    # x - y == x + -y
    ```

- `*` — умножение, конкатенирует первый массив сам с собой столько раз, каков модуль длина второго. Если второй массив отрицательный, от результата берётся отрицание
    ```slime
    x = "Slime!" * 3;   # "Slime!Slime!Slime!"
    y = "Slime!" * -3;  # -"Slime!Slime!Slime!"
    z = -"Slime!" * 3;  # -"Slime!Slime!Slime!"
    t = -"Slime!" * -3; # "Slime!Slime!Slime!"
    ```

- `/` и `%` деление и остаток от деления. Если длины массивов положительны, то длина первого массива целочисленно делится на длину второго, в результате оператор `/` возвращает первые p элементов первого массива, где p - результат деления, а операция `%` возвращает последние q элементов, где q - остаток от деления. Если один из массивов отрицательный, результат берётся обратный; если оба отрицательные, знаки отбрасываются.
    ```slime
    x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    x / 3;      # [1, 2, 3]
    x % 3;      # [10]
    -x / 3;     # -[1, 2, 3]
    x / -3;     # -[1, 2, 3]
    -x / -3;    # [1, 2, 3]
    ```

- `&&` и `||` работают примерно как в js.
    + `&&` - возвращает левый операнд если он `[]` и второй операнд в противном случае
    + `||` - возвращает левый операнд если он не`[]` и второй операнд в противном случае
    если операция возвращает левый операнд, значение правого не подсчитывается

- Оператор добавления `.` — `a.b` эквивалентно `a + [b]` (TODO: возможно, стоит выбрать другой символ для этого оператора, например, `^`)

- Оператор `,` — выполняет левую часть, затем правую, возвращает результат правой.

- `=` — оператор присваивания. Левый операнд этого оператора обязан быть lvalue (в ином случае операция не производит никаких действий, и возвращает `[]`). Lvalue в Slime являются идентификаторы(включая @), и результат операции взятия элемента по индексу `[]`.


#### Операторы скобок

- `()` - вызов функции. Параметры, перечисленные внутри скобок через запятую, превращаются в массив - входной параметр функции `@`
    ```slime
    fun = {
        print(@[0]);
        print(@[1]);
        print(@[2]);
    };
    fun("Hello ", "Slime", "!!!")
    ```
    Вывод:
    ```bash
    Hello Slime!!!
    ```

- `{}` - вызов функции с передачей функционального параметра. Трактует содержимое скобок как тело функции, и передаёт в `@` как функцию, задавая в качестве индекса стека индекс стека вызывающего контекста
    ```slime
    if = { @() && { @() }}  # реализация if из стандартной библиотеки

    if { 3 > 0 } {
        print("3 > 0");
    }
    ```
    Вывод:
    ```bash
    3 > 0
    ```

- `[]` - оператор доступа по индексу. Возвращает элемент массива. Результат этой операции является lvalue.


#### Приоритет операторов

Как в js. Можно пользоваться круглыми скобками для изменения приоритета. Вызов функции фигурными скобками имеет такой же приоритет, как и вызов обычными круглыми.

#### Идентификаторы

Идентификатор в Slime определяется так же, как и в языке Си. Помимо этого существует специальный идентификатор `@`, для доступа ко входным параметрам функции.

### Функции

Функция — массив вида:

`[<frame_index>, <code>, <p_0>, <p_1>, ...]`

- `<frame_index>` — неотрицательное slime-число (массив, длина которого трактуется как число), определяющее индекс кадра стека, в котором была создана функция
- `<code>` — slime-строка, содержащая исходный код функции
- `<p_i>` — необязательные предварительно связанные параметры функции

При попытке вызвать функцию, не удовлетворяющую этому формату, или если `<code>` не является валидным кодом на slime, возвращается `[]`.

#### Программный стек

При вызове функции создаётся новый кадр программного стека, хранящий информацию о локальных переменных. Индекс кадра стека всегда на 1 больше индекса кадра, вызвавшего функцию. Индекс кадра глобального контекста 0.

Каждая выполняемая функция имеет возможность обращаться в текущий, её собственный, кадр; кадр контекста, в котором она была создана; кадр глобального контекста. Если внутри функции происходит обращение к переменной, она ищется в порядке: текущий контекст, контекст создания; глобальный контекст. Если переменная не найдена, она создаётся в текущем кадре.

#### Содержимое функции

Функция — набор строк кода, отделённых символом `;`. Внутри функции можно использовать обращение к идентификаторам (переменным), операторами языка и круглыми скобками.

В текущем кадре функции всегда определён идентификатор `@`, содержащий ещё входные параметры.

При вызове функции через круглые скобки `@` заполняется набором предварительно связанных параметров, и и набором переданных через запятую входных параметров в скобках.

```slime
foo = {
    print(@[0]);
    print(@[1]);
    print(@[2]);
    print(@[3]);
    print(@[4]);
};
bar = foo."Slime "."is ";
bar("the best ", "language", "in the world!!!");
```
Вывод
```bash
Slime is the best language in the world!!!
```

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

```slime
foo = {
    @();
};
bar = foo.{ print("Slime is the worst language in the world") };
bar{ print("Slime is the best language in the world!!!") };
```
Вывод
```bash
Slime is the best language in the world!!!
```

Результатом выполнения функции является результат её последней непустой строки.

Так, любая программа на Slime является slime-функцией, в которой `@` инициализирован набором входных параметров, а её результат — результат выполнения всей программы.


## Стандартная библиотека (TODO)

```slime
null = [];

false = [];
true = [[]];

if = { @() && { @() }};
while = # в разработке
...

```
