Skip to content

Repository files navigation

Sable™

CI License: MIT

English · Русский

A general-purpose programming language whose interpreter compiles the AST to closures. Written in TypeScript, runs on Node with no build step and zero runtime dependencies — node src/cli.ts file.sable is the whole toolchain.

fn fib(n) { if n < 2 { return n }; return fib(n - 1) + fib(n - 2) }
print(fib(20))
6765
  • Nothing to install. Node executes the TypeScript sources natively; tsc is used for type checking only, and the runtime pulls in no packages at all.
  • Diagnostics meant to be read. Every error carries a position, the source line with a caret under the culprit, a call stack, and a suggestion when a name looks like a typo. All syntax errors are reported in a single pass.
  • Tooling in the box. A formatter (sable fmt), a static checker that runs without executing the program (sable --check), a VS Code syntax grammar, and two fuzzers that shrink any failure they find down to a few lines.
  • 536 checks in seven independent suites — including the exact text of every error message, every example program, every code block in the documentation, and the command-line behaviour itself. A full rewrite of the interpreter core passed them without touching a single expected output.

Try it in the browser — no install, runs the same interpreter compiled for the web. Full English documentation — language reference and internals.

node src/cli.ts examples/01_hello.sable   # run a file
node src/cli.ts                           # interactive session
node src/cli.ts --check file.sable        # analyse without running
npm test                                  # all ten suites

The reference, the tutorial and all diagnostics are written in Russian. Start at docs/TUTORIAL.md, the full reference is docs/LANGUAGE.md, the internals are in docs/ARCHITECTURE.md.


О языке

Язык программирования общего назначения: лексер → парсер → AST → компиляция в замыкания. Написан на TypeScript, работает на Node без сборки и без единой зависимости в рантайме.

struct Point {
  x = 0
  y = 0
  fn len() { return sqrt(self.x ^ 2 + self.y ^ 2) }
}

let points = [Point(3, 4), Point(1, 1)]
let longest = points.sort((a, b) -> b.len() - a.len()).first()

print("Самая длинная: ${longest.x}, ${longest.y} → ${round(longest.len(), 2)}")

Запуск

Требуется Node 22.18+ или 24+ — с этих версий TypeScript исполняется нативно без флагов, поэтому компилировать нечего. Проверено прогоном всего набора тестов на 22.18, 24 и 25; на 22.17 и раньше не запустится.

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

node src/cli.ts examples/01_hello.sable   # выполнить файл
node src/cli.ts                         # интерактивный режим: Tab, история, :помощь
node src/cli.ts -e 'print(2 ^ 10)'      # выполнить строку
node src/cli.ts --check файл.sable       # проверить, не запуская
node src/cli.ts fmt -w файл.sable        # привести к каноническому виду
node bench/run.ts                       # замеры производительности
npm test                                # прогнать все тесты

Чтобы вызывать просто sable:

npm link          # или: ln -s "$PWD/bin/sable.mjs" /usr/local/bin/nur
sable examples/04_shapes.sable

Что уже умеет язык

Типы number, string, bool, nil, list, map, range, fn, структуры
Переменные let (изменяемая), const (нет)
Функции значения по умолчанию, замыкания, первый класс, рекурсия, лямбды x -> x * 2
Структуры поля со значениями по умолчанию, методы, self
Управление if/else if/else, while, for … in, break, continue, тернарный ? :
Ошибки как значения try/catch, свой бросок через error(…), assert
Модули import "lib/math.sable" as math — файл выполняется один раз, циклы ловятся
Строки вставки ${…}, многострочные в `обратных кавычках`, ~15 методов
Коллекции map/filter/reduce/sort/find, срезы, отрицательные индексы
Диагностика позиция в исходнике, стрелка под виновником, стек вызовов, подсказки по опечаткам, все синтаксические ошибки за один проход
Прочее JSON, файлы, ввод с клавиатуры

Пошаговое введение — docs/TUTORIAL.md. Полный справочник — docs/LANGUAGE.md. Как устроен интерпретатор — docs/ARCHITECTURE.md.

Ошибки, на которые не стыдно смотреть

$ sable pay.sable
Ошибка выполнения: имя «blance» не определено — возможно, имелось в виду «balance»
  --> pay.sable:7:22
  |
7 |   let remaining = blance - amount
  |                   ^
  в withdraw (pay.sable:12:16)
  в main (pay.sable:18:5)

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

Устройство

src/
  lexer.ts        текст          → лексемы
  parser.ts       лексемы        → AST          (рекурсивный спуск)
  interpreter.ts  AST            → замыкания    (компиляция и выполнение)
  checker.ts      AST            → замечания    (проверка без запуска)
  modules.ts      загрузка import: кэш, циклы, пути
  values.ts       значения времени выполнения, равенство, печать
  environment.ts  области видимости и поиск имён
  stdlib.ts       встроенные функции и методы типов
  format.ts       AST            → канонический текст (sable fmt)
  errors.ts       единый формат ошибок со стрелкой
  cli.ts          запуск файла, REPL, -e, --check, fmt
tests/            golden-тесты: вывод программы сверяется с эталоном
examples/         примеры (их вывод тоже под замком тестов)
selfhost/         Sable, написанный на Sable: лексер, парсер, интерпретатор
docs/             учебник, справочник, устройство

Тесты

npm test                       # проверить всё: язык, анализатор, документацию
node tests/run.ts --only=maps  # только словари
node tests/run.ts --update     # перезаписать эталоны (после осознанной правки)

Десять независимых наборов:

Набор Что запирает
tests/run.ts вывод программ и текст каждой ошибки, плюс вывод всех примеров
tests/checker.ts статический анализ: каждая проверка «ловит» и «не ложно срабатывает»
tests/docs.ts код из документации выполняется, вывод сверяется с напечатанным
tests/grammar.ts подсветка знает те же слова, что и язык
tests/format.ts форматтер: идемпотентность, сохранение дерева, комментариев и вывода
tests/cli.ts сама команда: коды выхода, потоки, поведение при обрыве канала
tests/web.ts песочница: сборка не тянет ничего из Node, поведение как в терминале
tests/scale.ts посимвольный проход по строке растёт линейно, а не квадратично
tests/selfhost.ts перёд на Sable даёт те же лексемы и то же дерево, что настоящий
tests/selfrun.ts интерпретатор на Sable печатает то же, что настоящий, — на всех примерах

Отдельно живут два охотника, в npm test они не входят — это охота, а не проверка:

  • node tests/fuzz.ts — случайные программы: следы JavaScript наружу, зависания, расхождения --check с выполнением, нарушения законов языка;
  • node tests/fuzz-tools.ts — всё вокруг ядра: наборы модулей (цепочки, ромб, циклы импорта), форматтер как оракул (вывод до и после обязан совпасть), файловые функции, input() и интерактивный режим.

Найденный пример оба сокращают сами — из сотни строк остаётся несколько.

Отдельными кейсами покрыт каждый класс ошибки: неизвестное имя, несовпадение типов, деление на ноль, выход за границы, запись в const, неверное число аргументов, вызов не-функции, обращение к полю у nil, синтаксис, незакрытая строка, глубокая рекурсия, свои ошибки, отсутствующий модуль, try без catch.

Документация с выдуманным выводом хуже отсутствующей — поэтому она под тестом, а не под честным словом.

Что дальше

Сделано после 0.1: модули (import … as), перехват ошибок (try/catch), статическая проверка (--check), форматтер (sable fmt), расширенная библиотека, разбор с восстановлением, подсветка для VS Code, фаззеры, песочница в браузере, английская документация. Скорость выросла в 3,3 раза: точечные оптимизации по профилю, компиляция AST в замыкания, разрешение локальных имён в слоты.

Ближайшие шаги, в порядке пользы:

  1. Целочисленный тип — сейчас всё число с плавающей точкой, как в JS.
  2. Байткод и стековая ВМ вместо замыканий — следующий крупный шаг по скорости.
  3. Асинхронность или потоки — сейчас язык строго последовательный.
  4. Свободные функции для всех методов словаря — сейчас ключ с именем метода закрывает его, а обойти можно только четыре из шестнадцати.

Известное ограничение: глубина рекурсии. Порог языка — 900 вызовов, но реальная ёмкость зависит от тела функции: от ~1180 вызовов при плоском теле до ~150 при сорока уровнях вложенности выражений. Глубже — ошибка языка про вложенность вычислений, не стек JavaScript. Порог поднимается через SABLE_MAX_DEPTH вместе с node --stack-size=...; цифры и способ замера — в docs/ARCHITECTURE.md.

Автор

Дониёр Ботиров — основатель THE BOTIROFF LLC (США), компании по разработке программного обеспечения, и холдинга BOTIROFF.

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

Проект Что это
THE CRM CRM с искусственным интеллектом для учебных центров: финансы, посещаемость, зарплаты, ИИ-обзвон и боты в Telegram и Instagram
ULTRATHINK Премиальный учебный центр по искусственному интеллекту
BOTIROFF SPACE 3D-конфигуратор мебели с подбором через ИИ
dbit Разработка на заказ
Sable Этот язык программирования

Образование — Высшая школа экономики и Финансовый университет при Правительстве Российской Федерации. Сертификации Meta и Google, стажировки в Газпромбанке и Citibank. IELTS 9.0 — высший возможный балл, SAT 1590 из 1600.

Связь: botiroff.com · t.me/mrdoniyor · github.com/BOTIROFF-D

Лицензия и имя

Код — под MIT, Copyright © 2026 Doniyor Botirov. Форкайте, меняйте, берите в коммерческие проекты; единственное условие — сохранить копирайт.

Лицензия распространяется на исходный код и не даёт прав на название. «Sable» — имя проекта, принадлежащее THE BOTIROFF LLC; знак ™ означает заявленные права на название, регистрация не требуется. Выпускать форк под этим именем или так, чтобы он выглядел официальной версией, нельзя: назовите его своим именем, этого достаточно.

Name. The MIT license covers the source code and grants no rights to the project name. “Sable” is a project name of THE BOTIROFF LLC. Fork and use the code freely — just don't ship your fork under the Sable name, or in a way that implies it is the official version.

About

Sable — язык программирования: лексер, парсер, компиляция AST в замыкания. TypeScript на Node без сборки и без зависимостей.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages