Можно было бы взять существующие простые языки типа Луа или вообще пойти в сторону языков не для программирования, а для данных типа JSON/TOML/YAML и т.д. Разница, к слову, только в объёме работы. Но в качестве примера для ролика я посчитал даже Луа слишком большим языком, а парсить форматы данных не так интересно. Поэтому будем пилить свой собственный скриптовый язык программирования (однажды программист не изобрёл велосипед, и больше его никто не видел). Сразу скажу, что то, что я сейчас буду рассказывать — моё видение в данный момент. К моменту выхода ролика всё может поменяться ещё 100 раз.
Язык будет предельно минималистичный. Простой настолько, насколько это возможно. Это относится как к синтаксису, так и к фичам. Давайте сначала разберёмся с синтаксисом. Например, есть языки со значимыми отступами типа Питона:
def greet(name):
print("Hello,", name)
Решение сделать синтаксис именно таким понятно — такой код кажется менее шумным по сравнению с классическим си-лайк синтаксисом:
#include <iostream>
void main(string name) {
std::cout << "Hello, " << name << std::endl;
}
Я же хочу пойти в сторону ещё большей лаконичности:
fun greet name
print "Hello, " name
Тут сразу две идеи. Первая — использовать значимые отступы вместо фигурных скобок или иных способов обозначения границ блока кода. Вторая — там, где можно однозначно распарсить выражение без скобок и прочих символов, позволять не использовать эти символы. Естественно, тут сразу всплывает множество эдж-кейсов. Например, что если я захочу передать в вызов функции вызов другой функции? Тогда такое выражение заключается в скобки для избежания неоднозначности прочтения:
print "Hello, " (getNameByUserID 42)
В идеале хочется получить синтаксис, где небуквенные символы не используются вообще. Ну либо оставить их в тех местах, где с ними реально проще и удобнее.
Всякие операторы логических выражений тоже пишутся словами:
&& → and
|| → or
! → not
Единственное исключение — знаки равенства и неравенства:
!= == < > <= >=
А, да, ещё оператора
else не будет. Вообще. Я тут посмотрел, и понял, что я не использовал этот оператор прям очень давно. Обычно когда руки почему-то на автомате набирают else, я сразу выношу блок с условиями в отдельную функцию, а там уже всё решается ретёрнами. Для кейса, когда нужно рассмотреть много разных вариантов скорее всего сделаем что-то типа switch-case.Фич в языке тоже по-минимуму:
- Типы
-- Простые типы данных: числа, целые числа, строки и логический тип
-- Составные типы данных: список, мапа
-- Сущности (entities) — как структуры, только поля могут быть уложены в памяти разреженно
-- Енамы (такого даже в Go нет!)
- Функции
- Конструкции для управления логикой
-- Условия (только if)
-- switch-case
-- Циклы
--- со счётчиком
--- с условием
--- по коллекции
Типы динамические, указывать их явно не нужно (и не факт, что можно будет). Для полей сущностей типы определяются через значения по умолчанию:
entity Player
name = ""
x = 0.0
y = 0.0
hp = 100
Импортов и вообще системы управления модулями не будет — всё-таки язык встраиваемый. По этой же причине стандартная библиотека предельно аскетичная — немного математики и хэлперы для работы со встроенными типами.
Рабочее название — Lisi. Изначально я хотел сделать что-то похожее на Лисп, поэтому нашел созвучный топоним, соответствующий одному из озёр в Тбилиси. Как вы понимаете, название потеряло былой смысл, но я решил ничего не менять.