Skip to content

Advanced ru

Enoch-199811 edited this page Aug 9, 2026 · 2 revisions

Эксперт — умные ссылки, библиотеки, память и реальные проекты

English | 中文 | Русский | Español | Português | 繁體中文 | Deutsch

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

Типизированные умные ссылки

Умная ссылка — это типизированное значение, указывающее на lvalue. Она объявляется как право доступа × уровень × базовый тип:

&<permission> <follow> <base type> <name> = &<lvalue>;
  • Права доступа (7 стеков): r чтение, w запись, m перемещение (указателя), rw, rm, wm, rwm.
  • Уровни (4): u уровень программы (Unistream), f уровень метода, a уровень области видимости, t уровень нити.
  • Базовый тип: int / double / float / string / char / массивы / классы — обобщённый.

Итого 7 × 4 = 28 типов ссылок.

Чтение, запись, перемещение

int counter = 0;
&w u int wr = &counter;          // writable program-level ref
Ref::write(wr, 10);

&r u int rr = &counter;          // read-only ref
CIO::println(get Ref::read(rr)); // 10

&rw u int rw = &counter;         // read-write
CIO::println(get rw);            // 10
rw = 5;
CIO::println(counter);           // 5

Перемещение указателя (право m)

С правом m ссылка — это перемещающийся указатель (как a++ в C):

ALL a = new int[3];
a[0] = 10; a[1] = 20; a[2] = 30;
&m u int mp = &a[1];
CIO::println(get mp);            // 20
mp++;
CIO::println(get mp);            // 30
mp = 99;                         // writes through the pointer
CIO::println(a[2]);              // 99
CIO::println(cause Ref::move(mp));  // refused: pointer moved out of bounds

Отказы как инструмент проектирования

Ссылки отказывают в том, что запрещает их право доступа, — а причина отказа — просто значение:

CIO::println(cause Ref::write(rr, 99));
// Ref refused: reference is read-only, cannot write

Аннотации: @read, @write, @onlyread, @unfork

Аннотации объявляют контракты потоков и методов:

// A stream that must never be forked again:
Stream Sealed {
    void ping();
} @unfork
Sealed BadFork {}       // startup: refused: stream Sealed is @unfork, cannot fork

// A read-only stream: users may not call write methods:
Stream ReadOnly {
    int count;
    void bump();
    int get();
}
ReadOnly RO {
    void bump() { this::count = count + 1; } @write
    int get() { res count; } @read
} @onlyread
  • @write / @read на методе явно объявляют его природу чтения/записи — они имеют приоритет над эвристиками AST (тело, выглядящее как read-only, можно объявить методом записи, и наоборот).
  • @onlyread отказывает в любом вызове методов записи на потоке.
  • @unfork отказывает во всех путях разветвления, включая new на классе @unfork.

Вызов нативных библиотек C

Поток может привязаться к разделяемой библиотеке:

Stream m & "libm.so.6";          // bind libm

Main {
    void exec() {
        CIO::println(get m::sin(0));    // 0
        CIO::println(get m::pow(2, 10)); // 1024
    }
}

Бинарные функции вызываются как double(*)(double, ...) (до 6 аргументов); экспортируемые символы становятся методами потока. bio_dlsym / платформенный шим обрабатывает различия dlopen/LoadLibrary, так что это работает и в Windows.

Управление памятью

  • Интерпретатор использует арену на основе блоков — выделения никогда не перемещаются.
  • Ограничение по умолчанию: 256 МиБ в режиме интерпретации; 0 — без ограничений.
  • Флаги ограничения: bio -e 256M script.bio (или -e 1G, -e 0).
  • Скомпилированные продукты: без ограничений, если BIO_MEM_LIMIT не задан в окружении; bio shell build встраивает это поведение в сгенерированный main.
  • При достижении лимита программа останавливается с понятным сообщением: memory limit exceeded (limit N bytes).

Производительность

  • Кэширование: потоки и методы кэшируются на горячем пути (stream_cache / method_cache) — повторные поиски по одному и тому же имени выполняются за O(1).
  • Инкрементальная компиляция: bio build хэширует исходники каждого модуля; перекомпилируются только изменённые модули (N module(s) cached, M recompiled).
  • Режим компиляции: bio shell build компонует среду выполнения интерпретатора в автономный исполняемый файл — запуск мгновенный, а продукт работает где угодно без bio.

Кроссплатформенные сборки

make bin (через tools/make-dist.sh) кросс-компилирует релизные деревья для всех платформ с помощью zig — без сторонних SDK:

make bin
# bin/linux-x86_64/bin/bio + lib/libbio.so
# bin/win64/bin/bio.exe + lib/bio.dll + bio.bat
# bin/macos-arm64/bin/bio + lib/libbio.dylib
# ...

Платформы: linux-x86_64, linux-arm64, win32, win64, win-arm64, macos-x86_64, macos-arm64. Требуется zig >= 0.14 в PATH.

Внутреннее устройство: загрузчик динамически слинкован с разделяемой средой выполнения в lib/ (rpath $ORIGIN/../lib); Windows использует bio.bat для установки PATH. Нити используют ucontext на POSIX и Win32 fibers в Windows; бинарные библиотеки подключаются через dlopen или LoadLibrary с помощью платформенного шима.

Практика: реальный проект

Давайте соберём счётчик частоты слов, который читает файл, подсчитывает слова и выводит отсортированный отчёт.

1. Каркас

bio init wordcount

2. src/main.bio

program main;

need function countWords;          // provided by utils/counter.bio

Main {
    void exec() {
        if (CIO::getln() == "") { }   // (placeholder for arg reading)
        FIO::open("input.txt");
        string text = FIO::readFile("input.txt");
        ALL report = countWords(text);
        CIO::println(get report);
    }
}

3. utils/counter.bio

program utils;

function countWords(text string) {
    // SIO lets us scan word by word through a string buffer.
    int words = 0;
    for (int i = 0; i < text::length(); i = i + 1;) {
        char c = text[i];
        if (c == ' ' || c == '\n' || c == '\t') {
            words = words + 1;
        }
    }
    res words + 1;    // last word has no trailing space
}

4. Сборка и запуск

bio build . -s                 # standalone executable
bio build . -m                 # packaged .img with the platform runtime
bio run .                      # interpret directly

5. Пакет для распространения

bio build . -m wordcount.zip   # one distributable file

Вот и весь цикл: исходник → проверенный бандл → автономный бинарник → кроссплатформенный пакет.

Отладка

  • bio --tokens file.bio — дамп потока токенов лексера.
  • Сообщения об отказах — первоклассные: cause expr показывает точно, почему запрос не удался.
  • Собирайте с make PROFILE=sanitize для сборок ASan + UBSan.

Дополнительное чтение

  • Введение — основы и управляющий поток.
  • Продвинутый — потоки, классы, проекты, нити.
  • Packaging — форматы и релизные деревья.
  • Примеры — 15 прокомментированных программ, покрывающих все возможности (особенно 11-smart-refs.bio, 14-binary-lib.bio, 15-annotations.bio).

Clone this wiki locally