Справочник по синтаксису Ray

Ray на самом деле является языком программирования Noct с дополнительными API Suika3.

Присваивания

Переменные в Noct имеют динамическую типизацию и не требуют явного объявления. Оператор присваивания (=) используется для создания переменных и присваивания им значений.

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

func main() {
    var a = 123;
    print(a);

    var b = 1.0;
    print(b);

    var c = "string";
    print(c);
}

Глобальные переменные

Глобальные переменные можно определять в функциях, но нельзя определять вне функций.

func main() {
    globalVariable = 123;
    print(globalVariable);
}

Локальные переменные

Ключевое слово var позволяет объявить переменную как локальную. Без объявления var присваивание переменной создает глобальную переменную.

func main() {
    var a = 123;
    print(a);
}

Массив

Массивы - это упорядоченные коллекции значений, доступных по индексу. Массивы поддерживают итерацию через конструкцию цикла for, позволяя перебирать каждое значение напрямую.

func main() {
    var array = [0, 1, 2];
    for (value in array) {
        print(value);
    }
}

Массивы могут одновременно содержать значения разных типов, что отражает динамическую систему типов.

func main() {
    var array = [123, "string"];
}

Язык предоставляет встроенную функцию push() для добавления элементов в конец массива. Кроме того, pop() удаляет последний элемент.

func main() {
    var array = []
    array->push(0);
    array->push(1);
    array->push(2);

    var last = array->pop();

    print("Длина = " + array.length);
}

Словарь

Словари хранят пары ключ-значение, подобно хеш-таблицам или объектам в других языках. Они задаются фигурными скобками с парами ключ-значение, разделенными двоеточиями. Словари поддерживают итерацию, при которой одновременно доступны и ключ, и значение.

func main() {
    var dict = {key1: "value1", key2: "value2"};
    for (key, value in dict) {
        print("ключ = " + key);
        print("значение = " + value);
    }

    print("Длина = " + dict.length);
}

Словари можно строить пошагово. Присваивание может использовать стиль массива с [] или объектный стиль с ..

func main() {
    var dict = {};
    dict["key1"] = "value1";
    dict.key2 = "value2";
}

Встроенная функция remove() позволяет удалять записи по ключу.

func main() {
    var dict = {key1: "value1", key2: "value2"};
    remove(dict, "key1");
}

Цикл for

Конструкция цикла for предоставляет краткий синтаксис для перебора последовательностей, таких как диапазоны, массивы и словари.

Синтаксис диапазона (с оператором ..) создает итератор, который генерирует значения от начального значения до значения на единицу меньше конечного.

func main() {
    for (i in 0..10) {
        print(i);
    }
}

Циклы for также могут напрямую перебирать массивы и другие типы коллекций.

Массивы можно перебирать с помощью синтаксиса for-value.

func main() {
    array = [0, 1, 2];
    for (value in array) {
        print(value);
    }
}

Словари можно перебирать с помощью синтаксиса for-key-value.

func main() {
    var dict = {key1: "value1", key2: "value2"};
    for (key, value in dict) {
        print(key + "=" + value);
    }
}

Циклы while

Цикл while предоставляет традиционный механизм итерации, который продолжает выполнение, пока указанное условие остается истинным. В отличие от циклов for, предназначенных для перебора коллекций, циклы while более гибкие и могут использоваться для реализации различных алгоритмов, где число итераций заранее неизвестно. В примере показана базовая реализация счетчика, увеличивающегося от 0 до 9.

func main() {
    var i = 0;
    while (i < 10) {
        print(i);
        i = i + 1;
    }
}

Блоки if и else

Потоки управления позволяют выполнять условное выполнение на основе вычисленных выражений. Конструкция if-else использует привычный синтаксис, в котором условия проверяются последовательно.

func main() {
    var a = readint();
    if (a == 0) {
        print("0");
    } else if (a == 1) {
        print("1");
    } else {
        print("другое");
    }
}

Лямбда-функции

Функции являются объектами первого класса в языке. Анонимные функции, также известные как выражения lambda, позволяют создавать функции без имен.

func main() {
    var f = (a, b) => { return a + b; }
    print(f(1, 2));
}

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

Инкремент/декремент (+=, -=, ++, --)

func main() {
    var a = 123;
    a += 321;
    a++;

    var b = 123;
    b -= 321;
    b--;
}

++ и -- поддерживаются только как самостоятельные инструкции (a++;, b--;). Использовать их внутри выражений запрещено, чтобы избежать сложных побочных эффектов.

ООП в Noct

Объектно-ориентированная модель в Noct - это облегченный вариант ООП на основе прототипов.

  • Классы являются просто шаблонами словарей
  • Наследование и создание экземпляров реализуются слиянием словарей
  • Цепочки прототипов нет, и изменение класса не влияет на существующие экземпляры

Эта модель рассматривает словари как объекты первого класса, а автор называет ее Dictionary-based OOP (D-OOP).

func main() {
    // Определение базового класса. (Класс - это просто словарь.)
    Animal = class {
        name: "Animal",
        cry: (this) => {
        }
    };

    // Определение подкласса. (Просто слияние словарей.)
    Cat = extend Animal {
        name: "Cat",
        voice: "meow",
        cry: (this) => {
            print(this.name + " издает звук " + this.voice);
        }
    };

    // Создание экземпляра. (Просто слияние словарей.)
    var myCat = new Cat {
        voice: "neee"
    };

    // Вызов this использует синтаксис -> (). (Эквивалентно myCat.cry(myCat))
    myCat->cry();
}

Встроенные функции

int()

var i = int(1.23);

float()

var f = float(123);

newArray()

var array = newArray(10);

push()

var array = [1, 2, 3];
array->push(4);

pop()

var array = [1, 2, 3];
var last = array->pop();

resize()

var array = [1, 2, 3];
array->resize(2);

charCount()

var s = "ABC文あいう";
var l = s->charCount();

charAt()

var s = "ABC文あいう";
for (i in 0 .. s.length) {
   var c = s->charAt(i);
   print(c);
}

substring()

var s1 = "ABCDEFG";
var s2 = s1.substring(0, 3); // от символа 0, три символа
var s3 = s1.substring(2, -1); // от символа 1 до конца
}

unset()

var dic = {key1: "ABC"};
dic->unset("key1");

Math API

Math

abs()

var a = abs(x);

random()

var r = random(); // 0 .. 1.0

Math.sin()

var y = sin(x);

Math.cos()

var y = cos(x);

Math.tan()

var y = tan(x);