Caramel - экспериментальный декларативный язык и набор инструментов для описания моделей данных, интеграций, поведения генераторов и кода, зависящего от целевого языка.
package("main")
use (
"github.com/caramelang/plugins/db" as db
)
#[db::sqlite::table("User")]
go::model User {
pub (
Id: string
Name: string = "none"
)
}
Caramel находится в активной разработке. Сейчас команда build разбирает и
анализирует исходный файл, но пока не генерирует итоговый код.
- Состояние проекта
- Быстрый старт
- Установка
- Командная строка
- Синтаксис языка
- Полный пример
- Пакеты
- Импорты
- Конфигурация
- Атрибуты
- Квалифицированные объявления
- Переменные и поля
- Группы публичных объявлений
- Методы
- Типы
- Комментарии и разделители
- Диагностика и языки
- Разработка
- Участие в проекте
- Лицензия и безопасность
- Текущие ограничения
| Возможность | Состояние |
|---|---|
| Лексер и токены с позициями | Готово |
| Парсер и AST | Готово |
| Восстановление после синтаксических ошибок | Готово |
| Импорты и псевдонимы | Готово |
| Атрибуты и квалифицированные пути | Готово |
| Глобальные переменные и поля моделей | Готово |
| Базовая проверка типов | Готово |
| Локализованная диагностика | Готово |
| Постоянный кэш переводов | Готово |
| Интерактивный просмотр AST | Готово |
| Генерация кода | В разработке |
| Выполнение плагинов | В разработке |
Команда caramel install |
Не реализовано |
git clone https://github.com/caramelang/caramel.git
cd caramel
make build
./bin/caramel build examples/models/1-model.cmПоказать справку:
./bin/caramel helpПоказать справку на русском:
./bin/caramel -L ru helpОткрыть визуализатор AST:
go run ./cmd/lipa examples/models/1-model.cmДля сборки Caramel требуются Go 1.25.6 или новее, Make и компилятор C для
драйвера SQLite.
make buildИсполняемый файл будет создан по пути bin/caramel.
Релизная сборка увеличивает текстовую branding.ReleaseVersion перед
компиляцией:
make build -rВерсия имеет формат YY.M.D.N, например 26.7.18.1. Последнее число
увеличивается с каждой релизной сборкой в течение дня, а в новый день начинается
с единицы.
make installПо умолчанию Caramel устанавливается в ~/.local/bin/caramel. Другой каталог можно
указать через INSTALL_DIR:
make install INSTALL_DIR=/usr/local/binЕсли стандартного каталога нет в PATH, добавьте его в настройки оболочки:
export PATH="$HOME/.local/bin:$PATH"go run ./cmd/release help
go run ./cmd/release build examples/models/1-model.cmmake test # запустить тесты
make build-all # собрать артефакты для настроенных платформ
make list-platforms # вывести список платформ
make clean # удалить каталог bin/CLI использует go-sqlite3, поэтому для полноценной кросс-компиляции нужен
подходящий набор инструментов CGO. Текущая команда build-all отключает CGO.
caramel [глобальные параметры] <команда> [аргументы]
| Параметр | Описание |
|---|---|
-h, --help |
Показать справку. |
-L <lang>, --lang <lang> |
Выбрать язык вывода. |
--lang=<lang> |
Выбрать язык вывода. |
Примеры:
caramel -L ru help
caramel --lang=uk help
caramel help --lang=rucaramel build <путь> [имя]
Путь вычисляется относительно каталога, из которого была запущена Caramel. Если имя проекта не указано, используется имя исходного файла без расширения.
caramel build examples/models/1-model.cm
caramel build src/user.cm usersСейчас команда читает файл, разбирает его, запускает базовый анализ и завершается с ошибкой при наличии критических диагностик. Выходные файлы пока не генерируются.
caramel help
caramel --lang ru helpКоманда caramel install зарезервирована для будущей установки пакетов и
инструментов. Для установки исполняемого файла Caramel используйте make install.
Актуальный пример синтаксиса находится в
examples/models/1-model.cm и проверяется тестами
парсера.
Исходный файл может содержать:
- объявление
package(...); - импорты
use (...); - глобальные настройки через
let; - глобальные атрибуты;
- объявления
letиpub let; - группы публичных объявлений;
- квалифицированные объявления, например
go::model User; - поля, атрибуты и методы внутри объявлений;
- литералы, арифметические выражения, идентификаторы и квалифицированные вызовы.
Названия model, impl, sqlite и table являются сегментами пути, а не
фиксированными ключевыми словами. Благодаря этому плагины и генераторы могут
создавать собственные пути без расширения основной грамматики.
package("main")
use (
"github.com/caramelang/plugins/db" as db
"github.com/caramelang/plugins/std" as std
)
let lang = custom("github.com/caramelang/LangEngines/Go@latest")
#[db::sqlite::table("User")]
go::model User {
pub id: string = go::lib("github.com/google/uuid").NewString()
pub (
name: *[]*string = "none"
enabled: *bool = true
)
}
#[composer::file::no_edit(true)]
go::impl User {
#[db::go::func::delete_rec]
pub banned()
pub validate() -> (User error)
}
package("main")
В объявлении package допускается только один сегмент пути и список аргументов.
Более длинная форма, например package::nested(...), считается ошибкой.
Импорты объединяются внутри use (...):
use (
"github.com/caramelang/plugins/db"
"github.com/caramelang/plugins/http" as http
)
Ключевое слово as назначает импорту псевдоним. Старый оператор -> пока
поддерживается для совместимости. Импорты записываются подряд без разделителей.
use (
"github.com/caramelang/plugins/database" as db
)
Для настроек используется обычное объявление let на верхнем уровне. В AST оно
представлено тем же LetDecl, что и остальные переменные:
let lang = custom("github.com/caramelang/LangEngines/Go@latest")
Атрибуты записываются внутри #[...] и могут находиться на верхнем уровне или
внутри тела объявления:
#[db::sqlite::table("User")]
#[db::sqlite::index]
В одном блоке можно указать несколько атрибутов:
#[db::sqlite::index cache::enabled(true)]
Позиционные аргументы:
#[database::column("name")]
Именованные аргументы:
#[database::column("name" nullable: false)]
Вложенные квалифицированные вызовы:
#[db::sqlite(db::std::name())]
Атрибуты с присваиванием подходят для настроек:
#[lang=custom("github.com/caramelang/LangEngines/Go@latest")]
Квалифицированное объявление состоит из пути, имени и тела:
go::model User {
}
go::impl User {
}
custom::backend::entity Order {
}
У пути нет обязательного последнего слова. Парсер не обрабатывает go::model
особым образом. Пути из одного сегмента также поддерживаются:
model User {
}
Глобальные переменные объявляются через let или pub let:
let port: int = 8080
pub let name: string = "Caramel"
let enabled = true
let title: string
У переменной должен быть тип, начальное значение или оба элемента.
У полей внутри квалифицированного объявления слово let можно опустить:
go::model User {
pub Id: string = "none"
let Internal: bool = false
Name: string = "unknown"
}
Форма pub let внутри тела также поддерживается:
go::model User {
pub let Id: string = "none"
}
На верхнем уровне элементы публичной группы записываются с let:
pub (
let host: string = "localhost"
let port: int = 8080
)
Внутри квалифицированного объявления слово let можно не указывать:
go::model User {
pub (
Id: string = "none"
Name: string = "unknown"
)
}
Одиночные формы продолжают поддерживаться:
pub let globalName: string = "Caramel"
go::model User {
pub Id: string = "none"
}
Методы объявляются внутри квалифицированных тел:
go::impl User {
pub save()
pub banned() -> go::type::error
pub validate() -> (go::type::error go::type::error)
}
Возвращаемый тип необязателен. Один тип указывается сразу после ->, а несколько
типов записываются подряд в круглых скобках. Типизированные параметры
функций пока не реализованы: аргументы метода используют тот же синтаксис
вызовов, что и аргументы атрибутов.
string
int
uint
complex
[]array
[]*array // array of pointers
*[]*array // pointer to an array of pointers
// однострочный комментарий
/* блочный комментарий */
Точки с запятой не входят в синтаксис Caramel и считаются ошибкой:
package("main")
#[db::sqlite::table("User")]
Поля, методы, аргументы, атрибуты, импорты, элементы pub (...) и возвращаемые
типы записываются подряд без разделителей. Точки с запятой и запятые не входят в
синтаксис Caramel и всегда считаются ошибкой.
Диагностика Caramel содержит положение в исходном коде, уровень важности, подсвеченный диапазон и локализованное описание. После некорректной конструкции парсер старается продолжить работу, чтобы за один запуск показать несколько независимых ошибок.
Основной язык - английский. Для текущих диагностик также добавлены переводы на русский. Текст CLI без готового перевода может переводиться автоматически:
caramel --lang ru help
caramel --lang uk helpАвтоматические переводы кэшируются в памяти и SQLite. Постоянный кэш хранится в пользовательском каталоге настроек операционной системы:
<каталог-настроек-пользователя>/Caramel/caramel.sqlite
Если автоматический перевод завершился ошибкой или указан некорректный код языка, Caramel использует исходный текст.
Запустить тесты основного модуля:
make testЗапустить тесты отдельных пакетов:
go test ./internal/parser
go test ./internal/parser/analyzerУ независимых модулей собственные наборы тестов:
(cd pkg/lipa && go test ./...)
(cd pkg/digreyt && go test ./...)Модели базы данных и SQL-запросы генерируются из
internal/database/cache.rpl. Файлы с пометкой Code generated by RPL. DO NOT EDIT. необходимо перегенерировать, а не изменять вручную.
Правила оформления изменений, тестирования и работы с RPL описаны в
CONTRIBUTING.md. Для генерации базы данных проект использует
RPL 0.7.2.
Для ошибок и предложений используйте GitHub Issues, а вопросы по использованию и разработке задавайте в Discussions.
Caramel распространяется по лицензии GNU GPL v3.0.
Уязвимости необходимо отправлять приватно по инструкции из SECURITY.md. Не публикуйте сведения об уязвимости в обычном Issue. Общие вопросы поддержки описаны в SUPPORT.md.
buildпока не генерирует исходный код или исполняемые файлы.- Команда
caramel installне реализована. - Сейчас проект загружает только один исходный файл.
- Вывод типов ограничен литералами и простыми арифметическими выражениями.
- Возвращаемые типы квалифицированных вызовов не выводятся.
- Типизированные параметры методов не реализованы.
- Псевдонимы импортов разбираются, но пока не используются анализатором.
- Значение атрибутов пока не проверяется по схемам плагинов.
- Внешний код не может импортировать внутренний API парсера Caramel.
- Для кросс-компиляции версии с SQLite требуется дополнительная настройка CGO.
- До стабильного выпуска совместимость синтаксиса не гарантируется.