Skip to content

justmc-os/jmcc

Repository files navigation

JMCC

JustMC Code Compiler - компилятор языка JustCode в структуру файлов кодинга, используемого на сервере JustMC

Содержание

  1. Установка
  2. Использование
  3. Синтаксис
  4. Документация
  5. Примеры
  6. Подсветка синтаксиса

История изменения

Установка

Для работы с JMCC нужно:

  1. Открыть страницу релизов GitHub

  2. Выбрать подходящий файл с компилятором для вашей операционной системы (-win для Windows, -linux для Linux) и установить его

  3. Открыть командную строку в папке с установленным файлом:

    • Win + R на Windows, затем вписать cmd в появивщееся окно
    • На Unix системах - открыть терминал
  4. Использовать компилятор:

    # Для Windows
    $ jmcc-win.exe compile example.jc
    
    # Для Linux
    $ ./jmcc-linux compile example.jc

Для просмотра помощи о командах, используйте команду help

Использование

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

Создайте файл с расширением .jc и таким содержанием:

event<player_join> {
  player::message("Привет!")
}

Скомпилируйте данный файл:

$ jmcc compile [имя файла].jc

Если компиляция была успешной, в папке с вашим файлом должен появиться новый файл, с таким же названием, но с расширением .json. Чтобы использовать его на сервере, вам нужно загрузить его на файлообменник, либо использовать аргумент -u:

$ jmcc compile -u [имя файла].jc

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

Важно: Облачные ссылки, созданные при использовании аргумента -u будут хранить код только 3 минуты. После этого времени они будут удаляться. Если вы хотите сохранить скомпилированный код на большее время, вам нужно будет сохранять его в сторонних файлообменниках.

Синтаксис

Значения

"Текст!"      // Текст
1             // Число
[1, 2]        // Список

value::health // Игровое значение
              // (об этом будет дальше)

item("stone") // Значения, созданные фабриками
              // (об этом будет дальше)

Переменные

Переменные можно использовать только после их определения. До определения такие переменные не будут доступны, и будут вызывать ошибку при их использовании. Так же, определять переменные можно только один раз.

Определение локальных переменных

var a = 1;

Определение игровых переменных

game var a = 1;

Определение сохранённых переменных

save var a = 1;
Встроенные (inline) переменные

Встроенные (inline) переменные — переменные, значение которых просчитывается при компиляции, и заменяется при каждом их использовании. Им нельзя присвоить динамические значения, типо результатов действий с переменных.

Определение встроенных переменных

inline var a = 1;
Переменные с динамическим именем

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

Использование селектора в имени

var %player%_переменная = 1;

Использование нестандартных символов в имени

var `странная переменная ⛏️` = 2;

Использование других значений в имени

var a = 1;
var `переменная $a` = 2;
//  ^^^^^^^^^^^^^^^
//  Данная переменная после компиляции будет
//  иметь имя "переменная %var_local(a)"

// ...или со скобками:

var `переменная 2 ${a}` = 2;
//  ^^^^^^^^^^^^^^^^^^^
//  Данная переменная после компиляции будет
//  иметь имя "переменная 2 %var_local(a)"

Использование встроенных переменных в имени

inline var a = 1 + 1; // <--- Эта переменная встроена!
var `переменная $a` = 2;
//  ^^^^^^^^^^^^^^^
//  Данная переменная после компиляции будет
//  иметь имя "переменная 2"
Неопределённые переменные

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

var a;
game var a;

В таком случае не будет создано действия "Установить переменную", но эта переменная может быть использована как обычно.

Inline переменные нельзя не определять. Они всегда должны иметь значение при создании.

Фабрики

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

var a = location(1, 2, 3);

📓 Список фабрик

Математические функции

Математические функции - фабрики, которые аналогичны функциям из %math. Доступные функций:

  • abs(число) - Абсолютное значение числа
  • sqrt(число) - Квадратные корень числа
  • cbrt(число) - Кубический корень числа
  • ceil(число) - Округление числа до большего значения
  • floor(число) - Округление числа до меньшего значения
  • sin(число) - Синус числа
  • cos(число) - Косинус числа
  • round(число, N) - Округление числа до N цифер после запятой
  • pow(число, степень) - Возведение числа в степень
  • min(число, число) - Минимальное из значений
  • max(число, число) - Максимальное из значений

Использование:

var a = floor(0.3) + abs(-3) + sqrt(2);

Действия

Вызов действий должен происходить от объекта или переменной.

Анатомия вызова:

player::message("Привет мир!")
^^^^^^
переменная или объект

player::message("Привет мир!")
      ^^
      разделитель, определяющий тип вызова:
      :: для объектов
       . для переменных

player::message("Привет мир!")
        ^^^^^^^
        имя функции

player::message("Привет мир!")
                ^^^^^^^^^^^^^
                аргумент вызова

Аргументы вызова могут определяться:

  • позиционно

    player::message("Привет мир!")
  • с именем

    player::message(text = "Привет мир!")
  • комбинированно

    player::message("Привет мир!", merging = "SPACES")

При вызове действий компилятор проверяет соответствие типов значений, переданных действию. При этом, переменные не проверяются на соответствие (так как могут изменить своё значение).

К примеру, если действие принимает в качестве аргумента только число, то и вызвать его можно только с числом либо переменной:

var a = 1;
a.increment('Не число!');
//          ^^^^^^^^^^^
//  Ошибка: Аргумент с типом текст не может быть
//          установлен параметру с типом число

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

player::message("Привет мир!")
//              ^^^^^^^^^^^^^
//              Действие player::message принимает список,
//              но ему можно передать одно значение

player::message(["Привет", " ", "мир!"])
//              ^^^^^^^^^^^^^^^^^^^^^^^
//              Так тоже работает

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

player::message(["Привет", "мир"], merging = "SEPARATE_LINES")
Объекты

Объекты аналогичны категориям действий: действия игрока (player), действия сущности (entity), действия мира (world), действия с переменными (variable). Все остальные действия находятся в объекте code

Вызов действия от объекта:

player::message("Привет мир!")
code::wait(10, time_unit = "SECONDS")
player::message("Привет мир спустя 10 секунд!")
Специальные действия

Получение значения из списка по индексу

var a = [1, 2];
var b = a[0];

Установка значения в списке по индексу

var a = [1, 2];
a[0] = 3;
Переменные

От переменных можно вызвать некоторые действия, которые принимают переменные (либо значения, которые изменяют):

Действие принимает переменную

var a = 1;
a.increment();

Действие принимает значение, которое изменяют

var a = ['Привет', 'мир'];
a.set_at(1, 'сервер');

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

var a = variable::create_list([1, 2])
// Эквивалентно:
// var a = [1, 2]

var b = variable::get_at(a, 0)
// Эквивалентно:
// var b = a[0]

var C = 3;
var D = C.clamp(1, 2);
// Переменная D будет равна результату применения
// действия clamp к переменной C
Повторения

Обычное повторение:

repeat::forever() {
  player::message("Я буду выполняться вечно");
  code::wait(1);
}

Повторения с условием:

var a = 1;
repeat::while(a.less(10)) {
  player::message("A меньше 10!");
  a++;
  code::wait(1);
}

Повторения с параметрами:

repeat::on_range(0, 10) { index ->
  player::message("Текущий индекс: $index");
  code::wait(1);
}

События

📓 Список событий

Все действия, созданные вне определения события, будут добавлены к событию запуска мира, поэтому код:

player::message("Привет!");

никогда не сработает, так как при запуске мира в нём нет игроков. Такой код нужно переделать на:

event<player_join> {
  player::message("Привет!");
}

Теперь при входе игрока ему будет писаться сообщение "Привет!".

Другие события определяются аналогичным способом, только айди события player_join будет изменяться на 📓 другое нужное.

Функции и процессы

Функции (и процессы) могут иметь параметры и определяются так:

function abc(a, b) {
  player::message("Аргументы! $a $b")
}
process abc(a, b) {
  player::message("Аргументы! $a $b")
}

Импортирование

Не стоит сваливать весь код в один файл. Разделяйте свой код на несколько модулей, которые вы потом можете импортировать в один файл:

// variables.jc

var a = 1;
var b = 2;
// utils.jc

function say_hello() {
  player::message("Привет!")
}
// index.jc

import './variables.jc';
import './utils.jc';

event<player_join> {
  player::message("Данный код состоит из 3 модулей!");
}

Документация

Для подробной информации воспользуйтесь документацией:

Примеры

Подсветка синтаксиса

Подсветка синтаксиса поддерживается только в среде разработки Visual Studio Code. Расширение можно установить, перейдя по ссылке