Skip to content

Latest commit

 

History

History
1777 lines (1379 loc) · 85.8 KB

File metadata and controls

1777 lines (1379 loc) · 85.8 KB

Zen C

Современная эргономика. Никаких накладных расходов. Чистый Си.


Build Status License Version Platform

Пишите как на высокоуровневом языке, запускайте как Си.



Обзор

Zen C — это современный язык системного программирования, который компилируется в человекочитаемом GNU C/C11. Он предоставляет богатый набор возможностей, включая вывод типов, сопоставление с паттернами, генерику, трейты, async/await и ручное управление памятью с возможностями RAII, при этом поддерживая 100% совместимость с ABI Си.

Сообщество

Приглашаем вас присоединиться к нам на официальном Discord-сервере Zen C! Здесь можно обсуждать проект, делиться примерами, задавать вопросы и сообщать об ошибках.

Экосистема

Проект Zen C состоит из нескольких репозиториев. Ниже приведены основные из них:

Репозиторий Описание Статус
zenc Ядро компилятора Zen C (zc), CLI и стандартная библиотека. Активная разработка
docs Официальная техническая документация и спецификация языка. Активен
rfcs Репозиторий запросов на комментарии (RFC). Формируйте будущее языка. Активен
vscode-zenc Официальное расширение VS Code (подсветка синтаксиса, сниппеты). Alpha
www Исходный код zenc-lang.org. Активен
awesome-zenc Курируемый список отличных примеров Zen C. Растет
zenc.vim Официальный плагин для Vim/Neovim (Синтаксис, Отступы). Активен

Галерея

Посмотрите на эти проекты, созданные на Zen C:

  • ZC-pong-3ds: Клон Pong для Nintendo 3DS.
  • zen-c-parin: Базовый пример использования Zen C с Parin.
  • almond: Минималистичный веб-браузер, написанный на Zen C.

Содержание

Общее Справочник
---

Быстрый старт

Установка

git clone https://github.com/zenc-lang/zenc.git
cd Zen-C
make clean # удалить старые файлы сборки
make
sudo make install

Windows

Zen C имеет полную нативную поддержку Windows (x86_64). Вы можете выполнить сборку, используя прилагаемый пакетный скрипт с GCC (MinGW):

build.bat

Это соберет компилятор (zc.exe). Сетевые операции, операции с файловой системой и процессами полностью поддерживаются через уровень абстракции платформы (PAL).

Кроме того, вы можете использовать make, если у вас есть Unix-подобная среда (MSYS2, Cygwin, git-bash).

Портативная сборка (APE)

Zen C можно скомпилировать как Actually Portable Executable (APE) с помощью Cosmopolitan Libc. Это создаёт один исполняемый файл (.com), работающий нативно на Linux, macOS, Windows, FreeBSD, OpenBSD и NetBSD на архитектурах x86_64 и aarch64.

Требования:

  • Набор инструментов cosmocc (должен быть в PATH)

Сборка и установка:

make ape
sudo env "PATH=$PATH" make install-ape

Созданные файлы:

  • out/bin/zc.com: Портативный компилятор Zen-C с встроенной стандартной библиотекой.
  • out/bin/zc-boot.com: Установщик для создания новых проектов Zen-C.

Использование:

# Запустить на любой поддерживаемой ОС
./out/bin/zc.com build hello.zc -o hello

Использование

# Компилировать и запустить
zc run hello.zc

# Создать исполняемый файл
zc build hello.zc -o hello

# Интерактивная оболочка
zc repl

# Показать Дзэн факты
zc build hello.zc --zen

Переменные окружения

Установите ZC_ROOT для указания пути к стандартной библиотеке (для импортов типа import "std/vec.zc"). Это позволяет запускать zc из любого каталога.

export ZC_ROOT=/path/to/Zen-C

Справочник

1. Переменные и константы

Zen C различает константы времени компиляции и переменные времени выполнения.

Манифест-константы (def)

Значения, которые существуют только во время компиляции (встраиваются в код). Используйте их для размеров массивов, фиксированной конфигурации и магических чисел.

def MAX_SIZE = 1024;
let buffer: char[MAX_SIZE]; // Допустимый размер массива

Переменные (let)

Расположения в памяти. Могут быть изменяемыми или только для чтения (const).

let x = 10;             // Переменная
x = 20;                 // ОК

let y: const int = 10;  // Только для чтения (квалификатор типа)
// y = 20;              // Ошибка: невозможно присвоить const переменной

Tip

Вывод типов: Zen C автоматически выводит типы для инициализированных переменных. Он компилируется в C23 auto на поддерживаемых компиляторах или, в противном случае, с помощью GCC __auto_type.

2. Примитивные типы

Тип Эквивалент Си Описание
int, uint int32_t, uint32_t 32-битовое целое число со знаком/без знака
c_char, c_uchar char, unsigned char C char / unsigned char (Interop)
c_short, c_ushort short, unsigned short C short / unsigned short (Interop)
c_int, c_uint int, unsigned int C int / unsigned int (Interop)
c_long, c_ulong long, unsigned long C long / unsigned long (Interop)
c_long_long, c_ulong_long long long, unsigned long long C long long / unsigned long long (Interop)
I8 .. I128 или i8 .. i128 int8_t .. __int128_t Целые числа со знаком фиксированной ширины
U8 .. U128 или u8 .. u128 uint8_t .. __uint128_t Целые числа без знака фиксированной ширины
isize, usize ptrdiff_t, size_t Целые числа размером с указатель
byte uint8_t Псевдоним для U8
F32, F64 или f32, f64 float, double Числа с плавающей точкой
bool bool true или false
char char Одиночный символ
string char* Си-строка (с нулевым завершением)
U0, u0, void void Пустой тип
iN (например, i256) _BitInt(N) Целое число со знаком произвольной ширины (C23)
uN (например, u42) unsigned _BitInt(N) Целое число без знака произвольной ширины (C23)

Литералы

  • Целые: Десятичные (123), Шестнадцатеричные (0xFF), Восьмеричные (0o755), Двоичные (0b1011).
    • Примечание: Числа с ведущими нулями считаются десятичными (0123 это 123), в отличие от C.
    • Примечание: Числа могут содержать подчеркивания для читаемости (1_000_000, 0b_1111_0000).
  • С плавающей точкой: Стандартные (3.14), Научные (1e-5, 1.2E3). Числа с плавающей точкой также поддерживают подчеркивания (3_14.15_92).

Important

Лучшие практики для портативного кода

  • Используйте Портативные типы (int, uint, i64, u8 и т.д.) для чистой логики Zen C. int гарантированно имеет "ширину" в 32 бита и является знаковым на всех архитектурах.
  • Используйте Типы Interop C (c_int, c_char, c_long, ``c_ulong``, ``c_long_long``, ``c_ulong_long``) **только** при взаимодействии с библиотеками C (FFI). Их размер зависит от платформы и компилятора C (например, размер c_long` отличается между Windows и Linux).
  • Используйте isize и usize для индексирования массивов и арифметики указателей на память.

3. Составные типы

Массивы

Массивы фиксированного размера с семантикой значения.

def SIZE = 5;
let ints: int[SIZE] = [1, 2, 3, 4, 5];
let zeros: [int; SIZE]; // Инициализировано нулями

Кортежи

Группируйте несколько значений вместе, получайте доступ к элементам по индексу.

let pair = (1, "Hello");
let x = pair.0;  // 1
let s = pair.1;  // "Hello"

Множественные возвращаемые значения

Функции могут возвращать кортежи для предоставления нескольких результатов:

fn add_and_subtract(a: int, b: int) -> (int, int) {
    return (a + b, a - b);
}

let result = add_and_subtract(3, 2);
let sum = result.0;   // 5
let diff = result.1;  // 1

Деструктуризация

Кортежи могут быть деструктурированы прямо в переменные:

let (sum, diff) = add_and_subtract(3, 2);
// sum = 5, diff = 1

Типизированная деструктуризация позволяет указывать явные аннотации типов:

let (a: string, b: u8) = ("hello", 42);
let (x, y: i32) = (1, 2);  // Смешанный: x выводится, y явный

Структуры

Структуры данных с опциональными битовыми полями.

struct Point {
    x: int;
    y: int;
}

// Инициализация структуры
let p = Point { x: 10, y: 20 };

// Битфилды
struct Flags {
    valid: U8 : 1;
    mode:  U8 : 3;
}

Note

Структуры используют Move Semantics по умолчанию. Доступ к полям можно получить через . даже на указателях (Auto-Dereference).

Непрозрачные структуры

Вы можете определить структуру как opaque, чтобы ограничить доступ к её полям только определяющим модулем, при этом позволяя структуре размещаться на стеке (размер известен).

// В user.zc
opaque struct User {
    id: int;
    name: string;
}

fn new_user(name: string) -> User {
    return User{id: 1, name: name}; // ОК: внутри модуля
}

// В main.zc
import "user.zc";

fn main() {
    let u = new_user("Alice");
    // let id = u.id; // Ошибка: нет доступа к приватному полю 'id'
}

Перечисления

Теговые объединения (Sum types), способные содержать данные.

enum Shape {
    Circle(float),      // Держит радиус
    Rect(float, float), // Держит ширину, высоту
    Point               // Нет данных
}

Объединения

Стандартные C объединения (небезопасно).

union Data {
    i: int;
    f: float;
}

SIMD-векторы

Нативные SIMD-векторные типы с использованием расширений GCC/Clang. Аннотируйте структуру с помощью @vector(N) для определения вектора из N элементов.

import "std/simd.zc";

fn main() {
    let a = f32x4{v: 1.0};              // Широковещание: {1.0, 1.0, 1.0, 1.0}
    let b = f32x4{1.0, 2.0, 3.0, 4.0};  // Поэлементная инициализация
    let c = a + b;                       // Поэлементное сложение
    let x = c[0];                        // Доступ к элементу (float)
}

Арифметические (+, -, *, /) и побитовые (&, |, ^) операторы работают поэлементно. См. std/simd.zc для предопределённых типов.

Псевдонимы типов

Создайте новое имя для существующего типа.

alias ID = int;
alias PointMap = Map<string, Point>
alias OpFunc = fn(int, int) -> int

Примечание: Завершающая точка с запятой необязательна для псевдонимов типов.

Непрозрачные псевдонимы типов

Вы можете определить псевдоним типа как opaque, чтобы создать новый тип, который отличается от своего базового типа вне определяющего модуля. Это обеспечивает сильную инкапсуляцию и безопасность типов без накладных расходов времени выполнения структуры-оболочки.

// В library.zc
opaque alias Handle = int;

fn make_handle(v: int) -> Handle {
    return v; // Неявное преобразование разрешено внутри модуля
}

// В main.zc
import "library.zc";

fn main() {
    let h: Handle = make_handle(42);
    // let i: int = h; // Ошибка: проверка типа не прошла
    // let h2: Handle = 10; // Ошибка: проверка типа не прошла
}

4. Функции и лямбды

Функции

fn add(a: int, b: int) -> int {
    return a + b;
}

// Именованные аргументы поддерживаются при вызовах
add(a: 10, b: 20);

Note

Именованные аргументы должны строго следовать порядку определённых параметров. add(b: 20, a: 10) недопустимо.

Константные аргументы

Аргументы функции могут быть помечены как const для обеспечения семантики только для чтения. Это квалификатор типа, а не манифест-константа.

fn print_val(v: const int) {
    // v = 10; // Ошибка: невозможно присвоить const переменной
    println "{v}";
}

Аргументы по умолчанию

Функции могут определять значения по умолчанию для завершающих аргументов. Это могут быть литералы, выражения или допустимый код Zen C (например, конструкторы структур).

// Простое значение по умолчанию
fn increment(val: int, amount: int = 1) -> int {
    return val + amount;
}

// Значение по умолчанию как выражение (вычисляется в месте вызова)
fn offset(val: int, pad: int = 10 * 2) -> int {
    return val + pad;
}

// Значение по умолчанию для структуры
struct Config { debug: bool; }
fn init(cfg: Config = Config { debug: true }) {
    if cfg.debug { println "Debug Mode"; }
}

fn main() {
    increment(10);      // 11
    offset(5);          // 25
    init();             // Выводит "Debug Mode"
}

Лямбды

Анонимные функции, которые могут захватывать своё окружение.

let factor = 2;
let udvoit = x -> x * factor; // Синтаксис стрелок
let full = fn(x: int) -> int { return x * factor; }; // Блочный синтаксис

// Захват по ссылке (Блочный синтаксис)
let val = 10;
let modify = fn[&]() { val += 1; }; 
modify(); // val теперь 11

// Захват по ссылке (Стрелочный синтаксис)
let modify_arrow = [&] x -> val += x;
modify_arrow(5); // val теперь 16

// Захват по ссылке (Стрелочный синтаксис с несколькими аргументами)
let sum_into = [&] (a, b) -> val += (a + b);
sum_into(2, 2); // val теперь 20

// Захват по значению (По умолчанию)
let original = 100;
let implicit = x -> original + x;       // Неявный захват по значению (без скобок)
let explicit = [=] x -> original + x;   // Явный захват по значению
// let fail = x -> original += x;       // Ошибка: нельзя присвоить захваченному значению

Сырые указатели на функции

Zen C поддерживает сырые (Raw) указатели на функции Си, используя синтаксис fn*. Это позволяет беспрепятственно взаимодействовать с библиотеками Си, которые ожидают указателей на функции без накладных расходов замыкания.

// Функция, принимающая сырой указатель на функцию
fn set_callback(cb: fn*(int)) {
    cb(42);
}

// Функция, возвращающая сырой указатель на функцию
fn get_callback() -> fn*(int) {
    return my_handler;
}

// Поддерживаются указатели на указатели функций (fn**)
let pptr: fn**(int) = &ptr;

Вариадические функции

Функции могут принимать переменное число аргументов, используя ... и тип va_list.

fn log(lvl: int, fmt: char*, ...) {
    let ap: va_list;
    va_start(ap, fmt);
    vprintf(fmt, ap); // Используем C stdio
    va_end(ap);
}

5. Управление потоком

Условные операторы

if x > 10 {
    print("Large");
} else if x > 5 {
    print("Medium");
} else {
    print("Small");
}

// Тернарно
let y = x > 10 ? 1 : 0;

// If-выражение (для сложных условий)
let категория = if (x > 100) { "огромный" } else if (x > 10) { "большой" } else { "маленький" };

Сопоставление с образцом

Мощная альтернатива switch.

match val {
    1         => { print "One" },
    2 || 3    => { print "Two or Three" },    // ИЛИ с ||
    4 or 5    => { print "Four or Five" },    // ИЛИ с 'or'
    6, 7, 8   => { print "Six to Eight" },    // ИЛИ с запятой
    10 .. 15  => { print "10 to 14" },        // Исключающий диапазон (устаревший)
    10 ..< 15 => { print "10 to 14" },        // Исключающий диапазон (явно)
    20 ..= 25 => { print "20 to 25" },        // Включающий диапазон
    _         => { print "Other" },
}

// Деструктуризация перечислений
match shape {
    Shape::Circle(r)   => { println "Radius: {r}" },
    Shape::Rect(w, h)  => { println "Area: {w*h}" },
    Shape::Point       => { println "Point" },
}

Привязка ссылок

Чтобы проверить значение без передачи владения (перемещения), используйте ключевое слово ref в паттерне. Это необходимо для типов, которые реализуют Move Semantics (такие как Option, Result, структуры без Copy).

let opt = Some(NonCopyVal{...});
match opt {
    Some(ref x) => {
        // 'x' - это указатель на значение внутри 'opt'
        // 'opt' НЕ перемещается/не потребляется здесь
        println "{x.field}"; 
    },
    None => {}
}

Циклы

// Диапазон
for i in 0..10 { ... }      // Исключительно (0 до 9)
for i in 0..<10 { ... }     // Исключительно (явно)
for i in 0..=10 { ... }     // Включительно (0 до 10)
for i in 0..10 step 2 { ... }
for i in 10..0 step -1 { ... }  // Descending loop

// Итератор (Vec или пользовательский Iterable)
for item in vec { ... }

// Нумерованный: получить индекс и значение
for i, val in arr { ... }       // i = 0, 1, 2, ...
for i, val in 0..10 step 2 { ... } // i = 0, 1, 2, ...; val = 0, 2, 4, ...

// Итерация по массивам фиксированного размера напрямую
let arr: int[5] = [1, 2, 3, 4, 5];
for val in arr {
    // val - это int
    println "{val}";
}

// While
while x < 10 { ... }

// Бесконечный цикл с меткой
outer: loop {
    if done { break outer; }
}

// Повторить N раз
for _ in 0..5 { ... }

Продвинутое управление

// Guard: выполнить else и вернуться, если условие ложно
guard ptr != NULL else { return; }

// Unless: если не верно
unless is_valid { return; }

6. Операторы

Zen C поддерживает перегрузку операторов для пользовательских структур путём реализации специфических имён методов.

Перегружаемые операторы

Категория Оператор Имя метода
Арифметика +, -, *, /, %, ** add, sub, mul, div, rem, pow
Сравнение ==, != eq, neq
<, >, <=, >= lt, gt, le, ge
Побитовые &, |, ^ bitand, bitor, bitxor
<<, >> shl, shr
Унарные - neg
! not
~ bitnot
Индекс a[i] get(a, i)
a[i, j] get(a, i, j)
a[i] = v set(a, i, v)

Note

Примечание о равенстве строк:

  • string == string выполняет сравнение значений (эквивалент strcmp).
  • char* == char* выполняет сравнение указателей (проверяет адреса памяти).
  • Смешанные сравнения (например string == char*) по умолчанию используют сравнение указателей.

Пример:

impl Point {
    fn add(self, other: Point) -> Point {
        return Point{x: self.x + other.x, y: self.y + other.y};
    }
}

let p3 = p1 + p2; // Вызывает p1.add(p2)

Пример мульти-индекса:

struct Matrix {
    data: int[9];
}

impl Matrix {
    fn get(self, row: int, col: int) -> int {
        return self.data[row * 3 + col];
    }
}

let m = Matrix{data: [1,0,0, 0,1,0, 0,0,1]};
let val = m[1, 2]; // Вызывает Matrix.get(m, 1, 2)

| \|> | Pipeline | x \|> f(y) раскрывается в f(x, y) | | ?? | Null Coalescing | val ?? default возвращает default, если val равно NULL (указатели) | | ??= | Null Assignment | val ??= init присваивает, если val равно NULL | | ?. | Safe Navigation | ptr?.field получает доступ к полю только если ptr не равно NULL | | ? | Try Operator | res? возвращает ошибку, если она присутствует (типы Result/Option) |

Auto-Dereference: Доступ к полям указателя (ptr.field) и вызовы методов (ptr.method()) автоматически разыменовывают указатель, эквивалентно (*ptr).field.

7. Печать и интерполяция строк

Zen C предоставляет универсальные опции для печати на консоль, включая ключевые слова и краткие сокращения.

Ключевые слова

Ключевое слово Описание
print "text" Выводит на stdout без перевода строки.
println "text" Выводит на stdout с переводом строки.
eprint "text" Выводит на stderr без перевода строки.
eprintln "text" Выводит на stderr с переводом строки.

Сокращения

Zen C позволяет использовать строковые литералы непосредственно как операторы для быстрой печати:

Синтаксис Эквивалент Описание
"Hello World" println "Hello World" Неявно добавляет перевод строки.
"Hello World".. print "Hello World" Без перевода строки.
!"Error" eprintln "Error" Вывод на stderr.
!"Error".. eprint "Error" Вывод на stderr, без перевода строки.

Интерполяция строк

Вы можете встраивать выражения непосредственно в строковые литералы, используя синтаксис {}. Это работает со всеми методами вывода и сокращениями строк.

Интерполяция строк в Zen C неявная: если ваша строка содержит {...}, она будет автоматически обработана как интерполированная строка. Вы также можете явно использовать префикс f (например, f"..."), чтобы принудительно задать семантику интерполяции.

let x = 42;
let name = "Zen";
println "Значение: {x}, Имя: {name}";
"Значение: {x}, Имя: {name}"; // сокращение println

Экранирование фигурных скобок: Используйте {{ для вывода литеральной { и }} для литеральной }:

let json = "JSON: {{\"ключ\": \"значение\"}}";
// Вывод: JSON: {"ключ": "значение"}

Сырые строки (Raw Strings): Чтобы определить строку, в которой интерполяция и escape-последовательности полностью игнорируются, используйте префикс r (например, r"..."):

let regex = r"\w+"; // Содержит ровно \ w +
let raw_json = r'{"ключ": "значение"}'; // Экранирование фигурных скобок не требуется

Многострочные строки

Zen C поддерживает блоки сырых многострочных строк, используя разделитель """. Это чрезвычайно полезно для написания встроенных языков (GLSL, HTML) или генерации C-кода в блоках comptime без необходимости ручного экранирования переносов строк и внутренних кавычек.

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

  • f"""...""": Явно помечает их как блок интерполированной строки.
  • r"""...""": Явно помечает их как блок сырой строки (без интерполяции, без escape-последовательностей).
let prompt = """
  Пожалуйста, введите ваше имя:
  Введите "exit" для отмены.
""";

let world = "мир";
let script = """
  fn hello() {
      println "привет, {world}!";
  }
""";

let pure_raw = r"""
  Здесь {скобки} - это просто текст, а \n - буквально слэш-n.
""";

Запросы ввода (?)

Zen C поддерживает сокращение для запроса ввода пользователя с использованием префикса ?.

  • ? "Prompt text": Выводит подсказку (без перевода строки) и ожидает ввода (читает строку).
  • ? "Enter age: " (age): Выводит подсказку и сканирует ввод в переменную age.
    • Спецификаторы формата автоматически выводятся на основе типа переменной.
let age: int;
? "How old are you? " (age);
println "You are {age} years old.";

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

Zen C позволяет ручное управление памятью с удобными помощниками.

Defer

Выполните код при выходе из текущей области видимости. Операторы Defer выполняются в порядке LIFO (последний вошёл, первый вышел).

let f = fopen("file.txt", "r");
defer fclose(f);

Чтобы предотвратить неопределённое поведение, операторы управления потоком (return, break, continue, goto) недопустимы внутри блока defer.

Autofree

Автоматически освобождает переменную при выходе из области видимости.

autofree let types = malloc(1024);

Семантика ресурсов (Move по умолчанию)

Zen C рассматривает типы с деструкторами (такие как File, Vec или выделённые malloc указатели) как Ресурсы. Чтобы предотвратить ошибки двойного освобождения, ресурсы не могут быть неявно дублированы.

  • Move по умолчанию: Присвоение переменной ресурса передаёт владение. Исходная переменная становится недействительной (Moved).
  • Типы Copy: Типы без деструкторов могут выбрать поведение Copy, делая присвоение дублированием.

Диагностика и философия: Если вы видите ошибку "Use of moved value", компилятор говорит вам: "Этот тип владеет ресурсом (типа память или дескриптор) и слепое копирование небезопасно."

Контраст: В отличие от C/C++, Zen C не неявно дублирует значения, владеющие ресурсами.

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

fn process(r: Resource) { ... } // 'r' перемещается в функцию
fn peek(r: Resource*) { ... }   // 'r' заимствуется (ссылка)

Явное клонирование: Если вы действительно хотите две копии ресурса, сделайте это явным:

let b = a.clone(); // Вызывает метод 'clone' из трейта Clone

Opt-in Copy (типы значений): Для малых типов без деструкторов:

struct Point { x: int; y: int; }
impl Copy for Point {} // Opt-in для неявного дублирования

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = p1; // Скопирована. p1 остаётся допустимой.
}

RAII / Трейт Drop

Реализуйте Drop для автоматического запуска логики очистки.

impl Drop for MyStruct {
    fn drop(self) {
        self.free();
    }
}

9. Объектно-ориентированное программирование

Методы

Определяйте методы на типах с помощью impl.

impl Point {
    // Статический метод (соглашение конструктора)
    fn new(x: int, y: int) -> Self {
        return Point{x: x, y: y};
    }

    // Метод экземпляра
    fn dist(self) -> float {
        return sqrt(self.x * self.x + self.y * self.y);
    }
}

Сокращение self: В методах с параметром self можно использовать .поле как сокращение для self.поле:

impl Point {
    fn dist(self) -> float {
        return sqrt(.x * .x + .y * .y);  // Эквивалентно self.x, self.y
    }
}

Методы примитивных типов

Zen C позволяет определить методы на примитивных типах (например, int, bool, и т.д.) с помощью той же синтаксиса impl.

impl int {
    fn abs(self) -> int {
        return *self < 0 ? -(*self) : *self;
    }
}

let x = -10;
let y = x.abs(); // 10
let z = (-5).abs(); // 5 (Literals supported)

Трейты

Определяйте общее поведение.

struct Circle { radius: f32; }

trait Drawable {
    fn draw(self);
}

impl Drawable for Circle {
    fn draw(self) { ... }
}

let circle = Circle{};
let drawable: Drawable = &circle;

Стандартные трейты

Zen C включает стандартные трейты, которые интегрируются с синтаксисом языка.

Iterable

Реализуйте Iterable<T> для включения циклов for-in для ваших пользовательских типов.

import "std/iter.zc"

// Определите итератор
struct MyIter {
    curr: int;
    stop: int;
}

impl MyIter {
    fn next(self) -> Option<int> {
        if self.curr < self.stop {
            self.curr += 1;
            return Option<int>::Some(self.curr - 1);
        }
        return Option<int>::None();
    }
}

// Реализуйте Iterable
impl MyRange {
    fn iterator(self) -> MyIter {
        return MyIter{curr: self.start, stop: self.end};
    }
}

// Используйте в цикле
for i in my_range {
    println "{i}";
}

Drop

Реализуйте Drop для определения деструктора, который запускается при выходе объекта из области видимости (RAII).

import "std/mem.zc"

struct Resource {
    ptr: void*;
}

impl Drop for Resource {
    fn drop(self) {
        if self.ptr != NULL {
            free(self.ptr);
        }
    }
}

Note

Если переменная перемещена, drop не вызывается для оригинала. Подробнее в семантике ресурсов.

Copy

Маркерный трейт для выбора поведения Copy (неявное дублирование) вместо Move семантики. Используется через @derive(Copy).

Caution

Типы, которые реализуют Copy, не должны определять деструктор (Drop).

@derive(Copy)
struct Point { x: int; y: int; }

fn main() {
    let p1 = Point{x: 1, y: 2};
    let p2 = p1; // Скопирована! p1 остаётся допустимой.
}

Clone

Реализуйте Clone для разрешения явного дублирования типов, владеющих ресурсами.

import "std/mem.zc"

struct MyBox { val: int; }

impl Clone for MyBox {
    fn clone(self) -> MyBox {
        return MyBox{val: self.val};
    }
}

fn main() {
    let b1 = MyBox{val: 42};
    let b2 = b1.clone(); // Явное копирование
}

Композиция

Используйте use для встраивания других структур. Вы можете либо смешивать их (уплощение полей), либо давать им названия (вложение полей).

struct Entity { id: int; }

struct Player {
    // Миксин (без имени): уплощает поля
    use Entity;  // добавляет 'id' в Player напрямую
    name: string;
}

struct Match {
    // Композиция (с именем): вложение полей
    use p1: Player; // доступ через match.p1
    use p2: Player; // доступ через match.p2
}

10. Обобщения

Типобезопасные шаблоны для структур и функций.

// Обобщённая структура
struct Box<T> {
    item: T;
}

// Обобщённая функция
fn identity<T>(val: T) -> T {
    return val;
}

// Обобщения с несколькими параметрами
struct Pair<K, V> {
    key: K;
    value: V;
}

11. Параллелизм (Async/Await)

Встроен на основе pthreads.

async fn fetch_data() -> string {
    // Запускается в фоне
    return "Data";
}

fn main() {
    let future = fetch_data();
    let result = await future;
}

12. Метапрограммирование

Comptime

Выполняйте код во время компиляции для генерации исходного кода или вывода сообщений.

comptime {
    // Генерирует код во время компиляции (выводится в stdout)
    println "let build_date = \"2024-01-01\";";
}

println "Build Date: {build_date}";

Вспомогательные функции

Специальные функции, доступные внутри блоков comptime:

  • yield(str) - Явно выводит сгенерированный код (альтернатива printf)
  • compile_error(msg) - Прерывает компиляцию с фатальной ошибкой
  • compile_warn(msg) - Выводит предупреждение во время компиляции (позволяет продолжить компиляцию)
comptime {
    compile_warn("Генерация оптимизированного кода...");
    
    let ENABLE_FEATURE = 1;
    if (ENABLE_FEATURE == 0) {
        compile_error("Функция должна быть включена!");
    }
    
    println "let FEATURE_ENABLED = 1;";
}

Метаданные сборки

Доступ к информации о сборке компилятора во время компиляции:

  • __COMPTIME_TARGET__ - Строка платформы: "linux", "windows" или "macos"
  • __COMPTIME_FILE__ - Имя текущего исходного файла
comptime {
    // Генерация кода для конкретной платформы
    println "let PLATFORM = \"{__COMPTIME_TARGET__}\";";
}

println "Запуск на: {PLATFORM}";

Note

Используйте {{ и }} для экранирования фигурных скобок внутри строк comptime.

Embed

Встраивайте файлы как указанные типы.

// По умолчанию (Slice_char)
let data = embed "assets/logo.png";

// Типизированное встраивание
let text = embed "shader.glsl" as string;    // Встроить как C-строку
let rom  = embed "bios.bin" as u8[1024];     // Встроить как фиксированный массив
let wav  = embed "sound.wav" as u8[];        // Встроить как Slice_u8

Плагины

Импортируйте плагины компилятора для расширения синтаксиса.

import plugin "regex"
let re = regex! { ^[a-z]+$ };

Обобщённые макросы C

Передавайте макросы препроцессора в C.

Tip

Для простых констант используйте def. Используйте #define, когда вам нужны макросы препроцессора C или флаги условной компиляции.

#define MAX_BUFFER 1024

Условная компиляция

Используйте @cfg() для условного включения или исключения любого объявления верхнего уровня на основе флагов -D.

// Сборка: zc build app.zc -DUSE_OPENGL

@cfg(USE_OPENGL)
import "opengl_backend.zc";

@cfg(USE_VULKAN)
import "vulkan_backend.zc";

@cfg(not(USE_OPENGL))
@cfg(not(USE_VULKAN))
fn fallback_init() { println "Бэкенд не выбран"; }
Форма Значение
@cfg(NAME) Включить, если -DNAME установлен
@cfg(not(NAME)) Включить, если -DNAME НЕ установлен
@cfg(any(A, B, ...)) Включить, если ЛЮБОЕ условие истинно (OR)
@cfg(all(A, B, ...)) Включить, если ВСЕ условия истинны (AND)

Несколько @cfg на одном объявлении объединяются через AND. not() можно использовать внутри any() и all(). Работает с любыми объявлениями верхнего уровня: fn, struct, import, impl, raw, def, test и т.д.

13. Атрибуты

Украшайте функции и структуры для изменения поведения компилятора.

Атрибут Область Описание
@must_use Fn Предупредить, если возвращаемое значение проигнорировано.
@deprecated("msg") Fn/Struct Предупредить при использовании с сообщением.
@inline Fn Подсказка компилятору встроить.
@noinline Fn Предотвратить встраивание.
@packed Struct Удалить заполнение между полями.
@align(N) Struct Принудительное выравнивание на N байт.
@constructor Fn Запустить перед main.
@destructor Fn Запустить после выхода из main.
@unused Fn/Var Подавить предупреждения о неиспользуемых переменных.
@weak Fn Слабая символьная компоновка.
@section("name") Fn Поместить код в специальный раздел.
@noreturn Fn Функция не возвращается (например exit).
@pure Fn Функция не имеет побочных эффектов (подсказка оптимизации).
@cold Fn Функция вряд ли будет выполняться (подсказка предсказания ветви).
@hot Fn Функция часто выполняется (подсказка оптимизации).
@export Fn/Struct Экспортировать символ (видимость по умолчанию).
@global Fn CUDA: Точка входа ядра (__global__).
@device Fn CUDA: Функция устройства (__device__).
@host Fn CUDA: Функция хоста (__host__).
@comptime Fn Вспомогательная функция, доступная для выполнения во время компиляции.
@cfg(NAME) Любое Условная компиляция: включает только если передан -DNAME. Поддерживает not(), any(), all().
@derive(...) Struct Автоматически реализовать трейты. Поддерживает Debug, Eq (Smart Derive), Copy, Clone.
@ctype("type") Fn Param Переопределяет созданный тип C для параметра.
@<custom> Any Передаёт пользовательские атрибуты в C (например @flatten, @alias("name")).

Пользовательские атрибуты

Zen C поддерживает мощную систему Пользовательских атрибутов, которая позволяет использовать любой __attribute__ GCC/Clang прямо в вашем коде. Любой атрибут, который не явно признан компилятором Zen C, рассматривается как обобщённый атрибут и передаётся в сгенерированный код C.

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

Отображение синтаксиса

Атрибуты Zen C отображаются прямо на атрибуты Си:

  • @name__attribute__((name))
  • @name(args)__attribute__((name(args)))
  • @name("string")__attribute__((name("string")))

Умные производные

Zen C предоставляет "Умные производные", которые уважают Move Semantics:

  • @derive(Eq): Генерирует метод равенства, который принимает аргументы по ссылке (fn eq(self, other: T*)).
    • При сравнении двух структур без Copy (a == b), компилятор автоматически передаёт b по ссылке (&b), чтобы избежать его перемещения.
    • Рекурсивные проверки равенства на полях также предпочитают доступ по указателю, чтобы предотвратить передачу владения.

14. Встроение ассемблера

Zen C предоставляет первоклассную поддержку встроения ассемблера прямо в код, транспилируя в GCC-стиле расширенный asm.

Базовое использование

Напишите сырой ассемблер в блоках asm. Строки автоматически конкатенируются.

asm {
    "nop"
    "mfence"
}

Volatile

Предотвратите оптимизацию ассемблера компилятором, который имеет побочные эффекты.

asm volatile {
    "rdtsc"
}

Именованные ограничения

Zen C упрощает сложный синтаксис ограничений GCC с именованными привязками.

// Синтаксис: : out(variable) : in(variable) : clobber(reg)
// Использует синтаксис заполнителя {variable} для читаемости

fn add_five(x: int) -> int {
    let result: int;
    asm {
        "mov {x}, {result}"
        "add $5, {result}"
        : out(result)
        : in(x)
        : clobber("cc")
    }
    return result;
}
Тип Синтаксис Эквивалент GCC
Output : out(variable) "=r"(variable)
Input : in(variable) "r"(variable)
Clobber : clobber("rax") "rax"
Memory : clobber("memory") "memory"

Note

При использовании синтаксиса Intel (через -masm=intel) убедитесь, что ваша сборка правильно настроена (например, //> cflags: -masm=intel). TCC не поддерживает синтаксис Intel ассемблера.

15. Директивы сборки

Zen C поддерживает специальные комментарии в начале вашего исходного файла для настройки процесса сборки без необходимости сложной системы сборки или Makefile.

Директива Аргументы Описание
//> link: -lfoo или path/to/lib.a Ссылка на библиотеку или объектный файл.
//> lib: path/to/libs Добавить путь поиска библиотеки (-L).
//> include: path/to/headers Добавить путь поиска заголовков (-I).
//> framework: Cocoa Ссылка на фреймворк macOS.
//> cflags: -Wall -O3 Передать произвольные флаги компилятору C.
//> define: MACRO или KEY=VAL Определить макрос препроцессора (-D).
//> pkg-config: gtk+-3.0 Запустить pkg-config и добавить --cflags и --libs.
//> shell: command Выполнить команду оболочки во время сборки.
//> get: http://url/file Загрузить файл, если конкретный файл не существует.

Возможности

1. Защита ОС Префиксируйте директивы названием ОС, чтобы применить их только на определённых платформах. Поддерживаемые префиксы: linux:, windows:, macos: (или darwin:).

//> linux: link: -lm
//> windows: link: -lws2_32
//> macos: framework: Cocoa

2. Расширение переменных окружения Используйте синтаксис ${VAR} для расширения переменных окружения в ваших директивах.

//> include: ${HOME}/mylib/include
//> lib: ${ZC_ROOT}/std

Примеры

//> include: ./include
//> lib: ./libs
//> link: -lraylib -lm
//> cflags: -Ofast
//> pkg-config: gtk+-3.0

import "raylib.h"

fn main() { ... }

16. Ключевые слова

Следующие ключевые слова зарезервированы в Zen C.

Объявления

alias, def, enum, fn, impl, import, let, module, opaque, struct, trait, union, use

Управление потоком

async, await, break, catch, continue, defer, else, for, goto, guard, if, loop, match, return, try, unless, while

Специальное

asm, assert, autofree, comptime, const, embed, launch, ref, sizeof, static, test, volatile

Константы

true, false, null

Зарезервировано в Си

Следующие идентификаторы зарезервированы, так как они являются ключевыми словами в C11: auto, case, char, default, do, double, extern, float, inline, int, long, register, restrict, short, signed, switch, typedef, unsigned, void, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn, _Static_assert, _Thread_local

Операторы

and, or

17. Взаимодействие с Си

Zen C предлагает два способа взаимодействия с кодом Си: Доверительные импорты (Удобно) и Явный FFI (Безопасно/Точно).

Способ 1: Импорт заголовков

Вы можете импортировать заголовок Си напрямую, используя ключевое слово import с расширением .h. Это рассматривает заголовок как модуль и предполагает, что все доступные символы существуют.

//> link: -lm
import "math.h" as c_math;

fn main() {
    // Компилятор доверяет корректности; выводит 'cos(...)' напрямую
    let x = c_math::cos(3.14159);
}

Note

Плюсы: Просто и быстро. Минусы: Нет проверки типов со стороны Zen C (ошибки перехватываются позже компилятором Си).

Метод 2: Явный FFI (Безопасно)

Для строгой проверки типов или когда вы не хотите включать текст заголовка, используйте extern fn.

include <stdio.h> // Выводит #include <stdio.h> в сгенерированный Си код

// Определите строгую сигнатуру
extern fn printf(fmt: char*, ...) -> c_int;

fn main() {
    printf("Hello FFI: %d\n", 42); // Проверено типами Zen C
}

Note

Плюсы: Zen C гарантирует совпадение типов. Минусы: Нужно писать сигнатуры.

Разница между import и include

  • import "file.h": Регистрирует заголовок как именованный модуль. Включает неявный доступ к символам (например, file::function()).
  • include <file.h>: Просто выводит #include <file.h> в сгенерированный код C. Не вводит никаких символов в компилятор Zen C; вы должны использовать extern fn для их доступа.

Стандартная библиотека

Zen C включает стандартную библиотеку (std), охватывающую основную функциональность.

Просмотрите документацию стандартной библиотеки

Ключевые модули

Нажмите, чтобы посмотреть все модули стандартной библиотеки
Модуль Описание Docs
std/bigfloat.zc Арифметика с плавающей запятой произвольной точности. Docs
std/bigint.zc Целое число произвольной точности BigInt. Docs
std/bits.zc Низкоуровневые побитовые операции (rotl, rotr и т.д.). Docs
std/complex.zc Арифметика комплексных чисел Complex. Docs
std/vec.zc Растущий динамический массив Vec<T>. Docs
std/string.zc Выделенный в heap тип String с поддержкой UTF-8. Docs
std/queue.zc FIFO очередь (Ring Buffer). Docs
std/map.zc Обобщённая хеш-таблица Map<V>. Docs
std/fs.zc Операции файловой системы. Docs
std/io.zc Стандартный ввод/вывод (print/println). Docs
std/option.zc Опциональные значения (Some/None). Docs
std/result.zc Обработка ошибок (Ok/Err). Docs
std/path.zc Кроссплатформенная манипуляция путями. Docs
std/env.zc Переменные окружения процесса. Docs
std/net/ TCP, UDP, HTTP, DNS, URL. Docs
std/thread.zc Потоки и синхронизация. Docs
std/time.zc Измерение времени и сон. Docs
std/json.zc Парсинг и сериализация JSON. Docs
std/stack.zc LIFO стек Stack<T>. Docs
std/set.zc Обобщённое хеш-множество Set<T>. Docs
std/process.zc Выполнение и управление процессами. Docs
std/regex.zc Регулярные выражения (на основе TRE). Docs
std/simd.zc Нативные SIMD-векторные типы. Docs

Инструменты

Zen C предоставляет встроенный языковой сервер и REPL для того, чтобы вам было комфортно программировать на этом ЯП!

Языковой сервер (LSP)

Языковой сервер Zen C (LSP) поддерживает стандартные функции LSP для интеграции в редактор, предоставляя:

  • Переходы к определению
  • Нахождения ссылок
  • Информация при наведении
  • Автозаполнения: (имена функций/структур, dot-дополнение для методов/полей)
  • Символы документа (outline)
  • Справка для сигнатур
  • Диагностика (ошибки синтаксиса/семантики)

Чтобы запустить языковой сервер (обычно настраивается в настройках LSP вашего редактора):

zc lsp

Работает это через стандартный I/O (JSON-RPC 2.0).

REPL

Цикл Read-Eval-Print позволяет вам интерактивно экспериментировать с кодом Zen C.

zc repl

Возможности

  • Интерактивное кодирование: Вводите выражения или операторы для немедленного вычисления.
  • Постоянная история: Команды сохраняются в ~/.zprep_history.
  • Стартовый скрипт: Автоматически загружает команды из ~/.zprep_init.zc.

Команды

Команда Описание
:help Показать доступные команды.
:reset Очистить историю текущей сессии (переменные/функции).
:vars Показать активные переменные.
:funcs Показать определённые пользователем функции.
:structs Показать определённые пользователем структуры.
:imports Показать активные импорты.
:history Показать историю ввода сессии.
:type <expr> Показать тип выражения.
:c <stmt> Показать сгенерированный код C для оператора.
:time <expr> Провести бенчмарк выражения (запускает 1000 итераций).
:edit [n] Редактировать команду n (по умолчанию: последняя) в $EDITOR.
:save <file> Сохранить текущую сессию в файл .zc.
:load <file> Загрузить и выполнить файл .zc в сессию.
:watch <expr> Наблюдать за выражением (переоценивается после каждого ввода).
:unwatch <n> Удалить наблюдение.
:undo Удалить последнюю команду из сессии.
:delete <n> Удалить команду с индексом n.
:clear Очистить экран.
:quit Выйти из REPL.
! <cmd> Запустить команду оболочки (например !ls).

Протокол языкового сервера (LSP)

Zen C включает встроенный языковой сервер для интеграции с редакторами.

Используйте zc lsp для запуска сервера.

Отладка Zen C

Программы на Zen C можно отлаживать с помощью стандартных отладчиков C, таких как LLDB или GDB.

Visual Studio Code

Для наилучшей работы в VS Code установите официальное расширение Zen C. Для отладки вы можете использовать расширения C/C++ (от Microsoft) или CodeLLDB.

Добавьте эти конфигурации в вашу директорию .vscode, чтобы включить отладку одним щелчком мыши:

tasks.json (Задача сборки):

{
    "label": "Zen C: Build Debug",
    "type": "shell",
    "command": "zc",
    "args": [ "${file}", "-g", "-o", "${fileDirname}/app", "-O0" ],
    "group": { "kind": "build", "isDefault": true }
}

launch.json (Отладчик):

{
    "name": "Zen C: Debug (LLDB)",
    "type": "lldb",
    "request": "launch",
    "program": "${fileDirname}/app",
    "preLaunchTask": "Zen C: Build Debug"
}

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

Zen C разработан для работы с большинством компиляторов C11. Некоторые функции полагаются на расширения GNU C, но они часто работают на других компиляторах. Используйте флаг --cc для переключения бэкендов.

zc run app.zc --cc clang
zc run app.zc --cc zig

Статус набора тестов

Нажмите, чтобы посмотреть детали поддержки компиляторов
Компилятор Процент успеха Поддерживаемые функции Известные ограничения
GCC 100% (Полная) Все функции Нет.
Clang 100% (Полная) Все функции Нет.
Clang 100% (Полная) Все функции Нет.
Zig 100% (Полная) Все функции Нет. Использует zig cc как замену C компилятора.
TCC 98% (Высокая) Структуры, Дженерики, Трейты, Сопоставление с образцом Нет Intel ASM, Нет __attribute__((constructor)).

Warning

ПРЕДУПРЕЖДЕНИЕ О СБОРКЕ: Хотя Zig CC отлично работает в качестве бэкенда для ваших программ Zen C, сборка самого компилятора Zen C с его помощью может пройти проверку, но создать нестабильный бинарный файл, который не пройдет тесты. Мы рекомендуем собирать компилятор с помощью GCC или Clang и использовать Zig только как бэкенд для вашего рабочего кода.

Tip

Сборка с Zig

Команда zig cc Zig предоставляет drop-in замену для GCC/Clang с отличной поддержкой кроссплатформенной компиляции. Чтобы использовать Zig:

# Компилировать и запустить программу Zen C с Zig
zc run app.zc --cc zig

# Собрать сам компилятор Zen C с Zig
make zig

Взаимодействие с C++

Zen C может генерировать код, совместимый с C++, с флагом --cpp, позволяя беспрепятственную интеграцию с библиотеками C++.

# Прямая компиляция с g++
zc app.zc --cpp

# Или транспилировать для ручной сборки
zc transpile app.zc --cpp
g++ out.c my_cpp_lib.o -o app

Использование C++ в Zen C

Включите заголовки C++ и используйте сырые блоки для кода C++:

include <vector>
include <iostream>

raw {
    std::vector<int> make_vec(int a, int b) {
        return {a, b};
    }
}

fn main() {
    let v = make_vec(1, 2);
    raw { std::cout << "Size: " << v.size() << std::endl; }
}

Примечание: Флаг --cpp переключает бэкенд на g++ и выводит совместимый с C++ код (использует auto вместо __auto_type, перегрузки функций вместо _Generic и явные приведения для void*).

Взаимодействие с CUDA

Zen C поддерживает GPU-программирование путём транспиляции в CUDA C++. Это позволяет вам использовать мощные функции C++ (шаблоны, constexpr) в ваших ядрах, сохраняя эргономичный синтаксис Zen C.

# Прямая компиляция с nvcc
zc run app.zc --cuda

# Или транспилировать для ручной сборки
zc transpile app.zc --cuda -o app.cu
nvcc app.cu -o app

Специфичные для CUDA атрибуты

Атрибут Эквивалент CUDA Описание
@global __global__ Функция ядра (запускается на GPU, вызывается с хоста).
@device __device__ Функция устройства (запускается на GPU, вызывается с GPU).
@host __host__ Функция хоста (явно только для CPU).

Синтаксис запуска ядра

Zen C предоставляет чистый оператор launch для вызова ядер CUDA:

launch kernel_name(args) with {
    grid: num_blocks,
    block: threads_per_block,
    shared_mem: 1024,  // Опционально
    stream: my_stream  // Опционально
};

Это транспилируется в: kernel_name<<<grid, block, shared, stream>>>(args);

Написание ядер CUDA

Используйте синтаксис функции Zen C с @global и оператором launch:

import "std/cuda.zc"

@global
fn add_kernel(a: float*, b: float*, c: float*, n: int) {
    let i = thread_id();
    if i < n {
        c[i] = a[i] + b[i];
    }
}

fn main() {
    def N = 1024;
    let d_a = cuda_alloc<float>(N);
    let d_b = cuda_alloc<float>(N); 
    let d_c = cuda_alloc<float>(N);
    defer cuda_free(d_a);
    defer cuda_free(d_b);
    defer cuda_free(d_c);

    // ... init data ...
    
    launch add_kernel(d_a, d_b, d_c, N) with {
        grid: (N + 255) / 256,
        block: 256
    };
    
    cuda_sync();
}

Стандартная библиотека (std/cuda.zc)

Zen C предоставляет стандартную библиотеку для общих операций CUDA, чтобы уменьшить использование raw блоков:

import "std/cuda.zc"

// Управление памятью
let d_ptr = cuda_alloc<float>(1024);
cuda_copy_to_device(d_ptr, h_ptr, 1024 * sizeof(float));
defer cuda_free(d_ptr);

// Синхронизация
cuda_sync();

// Индексирование потоков (использование внутри ядер)
let i = thread_id(); // Глобальный индекс
let bid = block_id();
let tid = local_id();

Note

Примечание: Флаг --cuda устанавливает nvcc как компилятор и подразумевает режим --cpp. Требует NVIDIA CUDA Toolkit.

Поддержка C23

Zen C поддерживает современные функции стандарта C23 при использовании совместимого компилятора бэкенда (GCC 14+, Clang 14+, TCC (частичная)).

  • auto: Zen C автоматически отображает вывод типов на стандартный C23 auto, если __STDC_VERSION__ >= 202300L.
  • _BitInt(N): Используйте типы iN и uN (например, i256, u12, i24) для доступа к целым числам произвольной ширины C23.

Взаимодействие с Objective-C

Zen C может компилировать в Objective-C (.m), используя флаг --objc, позволяя вам использовать фреймворки Objective-C (такие как Cocoa/Foundation) и синтаксис.

# Компилировать с clang (или gcc/gnustep)
zc app.zc --objc --cc clang

Использование Objective-C в Zen C

Используйте include для заголовков и raw блоки для синтаксиса Objective-C (@interface, [...], @"").

//> macos: framework: Foundation
//> linux: cflags: -fconstant-string-class=NSConstantString -D_NATIVE_OBJC_EXCEPTIONS
//> linux: link: -lgnustep-base -lobjc

include <Foundation/Foundation.h>

fn main() {
    raw {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSLog(@"Hello from Objective-C!");
        [pool drain];
    }
    println "Zen C works too!";
}

Note

Примечание: Интерполяция строк Zen C работает с объектами Objective-C (id), вызывая debugDescription или description.


Участие в разработке

Мы приветствуем ваш вклад! Исправление ошибок, добавление документации или предложение новых функций.

Пожалуйста, ознакомьтесь с CONTRIBUTING_RU.md для получения подробных инструкций о том, как внести свой вклад, запустить тесты и отправить запрос на слияние.


Безопасность

Инструкции по сообщению об уязвимостях см. в SECURITY_RU.md.


Благодарности

Этот проект использует сторонние библиотеки. Полные тексты лицензий можно найти в каталоге LICENSES/.

  • cJSON (MIT License): Используется для парсинга JSON и генерации в языковом сервере.
  • zc-ape (MIT License): Оригинальный порт Actually Portable Executable Zen-C от Eugene Olonov.
  • Cosmopolitan Libc (ISC License): Основополагающая библиотека, которая делает APE возможной.
  • TRE (BSD License): Используется для движка регулярных выражений в стандартной библиотеке.
  • zenc.vim (лицензия MIT): Официальный плагин для Vim/Neovim, основной автор — davidscholberg.

Copyright © 2026 Язык Программирования Zen C.
Начните своё путешествие сегодня.

DiscordGitHubДокументацияПримерыRFCВнести вклад