Skip to content

Latest commit

 

History

History
1832 lines (1414 loc) · 60.2 KB

File metadata and controls

1832 lines (1414 loc) · 60.2 KB

Zen C

Ergonomia Moderna. Zero Overhead. C Puro.


Stato Build Licenza Versione Piattaforma

Comodità di un linguaggio ad alto livello, veloce come il C



Panoramica

Zen C è un linguaggio di programmazione di sistemi moderno che genera codice GNU C/C11. Fornisce allo sviluppatore un ricco set di funzionalità, tra cui inferenza di tipo, pattern matching, generici, tratti, async/await, e gestione manuale della memoria con funzionalità RAII, mantenendo al contempo una compatibilità al 100% con l'ABI C

Community

Unisciti alla conversazione, condividi delle demo, fai domande o segnala dei bug nel server ufficiale Discord Zen C

Ecosistema

Il progetto Zen C è composto da diversi repository. Di seguito trovi i principali:

Repository Descrizione Stato
zenc Il compilatore core di Zen C (zc), CLI e libreria standard. Sviluppo Attivo
docs La documentazione tecnica ufficiale e la specifica del linguaggio. Attivo
rfcs Il repository delle Request for Comments (RFC). Dai forma al futuro del linguaggio. Attivo
vscode-zenc Estensione ufficiale di VS Code (Sintassi, Snippet). Alpha
www Codice sorgente di zenc-lang.org. Attivo
awesome-zenc Una lista curata di fantastici esempi di Zen C. In crescita

Vetrina

Dai un'occhiata a questi progetti creati con Zen C:

  • ZC-pong-3ds: Un clone di Pong per Nintendo 3DS.
  • zen-c-parin: Un esempio base usando Zen C con Parin.
  • almond: Un browser web minimale scritto in Zen C.

Indice

Generale Riferimenti del Linguaggio

Guida Rapida

Installazione

git clone https://github.com/zenc-lang/zenc.git
cd Zen-C
make clean # rimuove i vecchi file di build
make
sudo make install

Windows

Zen C ha il pieno supporto nativo per Windows (x86_64). È possibile compilare utilizzando lo script batch fornito con GCC (MinGW):

build.bat

Questo costruirà il compilatore (zc.exe). Le operazioni di Rete, File System e Processo sono completamente supportate tramite il Platform Abstraction Layer (PAL).

In alternativa, è possibile utilizzare make se si dispone di un ambiente Unix-like (MSYS2, Cygwin, git-bash).

Build Portatile (APE)

Il codice Zen C può come un Actually Portable Executable (APE) (lett. Eseguibile Effetivamente Portatile) utilizzando la Cosmopolitan Libc. Ciò produrrà un singolo eseguibile (.com) che potrà essere eseguito nativamente su Linux, macOS, Windows, FreeBSD, OpenBSD e NetBSD sia sulle architetture x86_64 e aarch64.

Prerequisiti:

  • Strumenti cosmocc (deve trovarsi nella tua PATH)

Builda e Installa:

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

Artefatti:

  • out/bin/zc.com: Il compilatore Zen-C portatile. Inlude la libreria standard, incorporata nell'eseguibile.
  • out/bin/zc-boot.com: Un installer bootstrap auto-contenuto per configurare nuovi progetti Zen-C rapidamente.

Utilizzo:

# Eseguibile su qualunque OS supportato
./out/bin/zc.com build hello.zc -o hello

Utilizzo

# Compila e avvia
zc run hello.zc

# Builda eseguibile
zc build hello.zc -o hello

# Shell interattiva
zc repl

# Mostra curiosità Zen
zc build hello.zc --zen

Variabili d'ambiente

Puoi impostare ZC_ROOT per specificare la posizione della Libreria Standard (per inclusioni standard come import "std/vector.zc"). Ciò ti permetterà di eseguire il comando zc da qualsiasi directory.

export ZC_ROOT=/path/to/Zen-C

Riferimenti Del Linguaggio

1. Variabili e Costanti

Zen C differenzia le costanti al tempo di compilazione e le variabili di esecuzione.

Costanti Manifesto (def)

Valori che esistono solo durante la compilazione (integrate nel codice). Utilizzale per le grandezze degli array, configurazioni fisse, e numeri magici.

def MAX_SIZE = 1024;
let buffer: char[MAX_SIZE]; // Grandezza valida per l'array

Variabili (let)

Locazioni di memoria. Possono essere mutabili o di sola lettura (const).

let x = 10;             // Mutabile
x = 20;                 // OK

let y: const int = 10;  // Sola lettura (Tipo qualificato)
// y = 20;              // Errore: impossibile assegnare un valore ad una variabile costante

Tip

Inferenza di tipo: Zen C inferisce automaticamente il tipo per le variabili inizializzate. Compilando ciò alla keyword auto dello standard C23 nei compilatori supportati, oppure alla estensione GCC __auto_type.

2. Tipi Primitivi

Tipo C Equivalent Descrizione
int, uint int32_t, uint32_t Intero a 32 bit con segno/senza segno
c_char, c_uchar char, unsigned char C char (Interop)
c_short, c_ushort short, unsigned short C short (Interop)
c_int, c_uint int, unsigned int C int (Interop)
c_long, c_ulong long, unsigned long C long (Interop)
c_long_long, c_ulong_long long long, unsigned long long C long long / unsigned long long (Interop)
I8 .. I128 or i8 .. i128 int8_t .. __int128_t Interi a grandezza fissa con segno
U8 .. U128 or u8 .. u128 uint8_t .. __uint128_t Interi a grandezza fissa senza segno
isize, usize ptrdiff_t, size_t Interi con grandezza di un puntatore
byte uint8_t Alias per U8
F32, F64 or f32, f64 float, double Numeri con parte decimale
bool bool true (lett. vero) o false (lett. falso)
char char Carattere singolo
string char* Stringhe C terminate da NULL
U0, u0, void void Tipo vuoto
iN (Per esempio, i256) _BitInt(N) Intero con segno a larghezza arbitraria di bit (C23)
uN (Per esempio, u42) unsigned _BitInt(N) Intero senza segno a larghezza arbitraria di bit (C23)

Letterali

  • Interi: Decimali (123), Hex (0xFF), Ottali (0o755), Binari (0b1011).
    • Nota: I numeri con zeri iniziali sono trattati come decimali (0123 è 123), a differenza del C.
    • Nota: I numeri possono contenere trattini bassi per leggibilità (1_000_000, 0b_1111_0000).
  • A virgola mobile: Standard (3.14), Scientifico (1e-5, 1.2E3). I numeri in virgola mobile supportano anche i trattini bassi (3_14.15_92).

Important

Best Practice per Codice Portabile

  • Usa Tipi Portabili (int, uint, i64, u8, ecc.) per tutta la logica Zen C pura. int è garantito essere a 32-bit con segno su tutte le architetture.
  • Usa Tipi di Interop C (c_int, c_char, c_long, c_ulong, c_long_long, c_ulong_long) solo quando interagisci con librerie C (FFI). La loro dimensione varia in base alla piattaforma e al compilatore C.
  • Usa isize e usize per indicizzazione di array e aritmetica dei puntatori.

3. Tipi Aggregati

Array

Array a lunghezza fissa con valori arbitrari.

def GRANDEZZA = 5;
let interi: int[GRANDEZZA] = [1, 2, 3, 4, 5];
let zeri: [int; GRANDEZZA]; // Inizializzato a zero

Tuple

Valori molteplici raggruppati assieme, accesso agli elementi indicizzato.

let paio = (1, "Ciao!");
let x = paio.0;  // 1
let s = paio.1;  // "Ciao!"

Molteplici Valori di Ritorno

Le funzioni posso restituire delle tuple per fornire diversi risultati:

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

let risultato = somma_e_differenza(3, 2);
let somma = risultato.0;   // 5
let differenza = risultato.1;  // 1

Separazione

Le tuple possono essere separate direttamente in variabili singole.

let (somma, differenza) = somma_e_differenza(3, 2);
// somma = 5, differenza = 1

La separazione delle tuple tipizzata permette annotazioni di tipo esplicite:

let (a: string, b: u8) = ("hello", 42);
let (x, y: i32) = (1, 2);  // Misto: x inferito, y esplicito

Structs

Strutture dati con campi di bit opzionali.

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

// Inizializzazione struct
let p = Punto { x: 10, y: 20 };

// Campi di bit
struct Flags {
    valido: U8 : 1;
    modalità:  U8 : 3;
}

Note

Gli struct usano le Semantiche di Spostamento di default. I campi di uno struct possono essere acceduti via . anche sui puntatori (Dereferenza-Automatica).

Struct Opachi

Puoi definire uno struct come opaque (lett. opaco) per restringere l'accesso ai suoi campi al modulo che lo ha definito, permettendo comunque l'allocazione sullo stack dello struct (la grandezza è data).

// In utente.zc
opaque struct Utente {
    id: int;
    nome: string;
}

fn nuovo_utente(nome: string) -> Utente {
    return Utente{id: 1, nome: nome}; // OK: Dentro il modulo
}

// In main.zc
import "utente.zc";

fn main() {
    let u = nuovo_utente("Alice");
    // let id = u.id; // Error: Impossibile accedere al campo privato 'id'
}

Enum

Unioni taggate (tipi somma) capaci di contenere dati.

enum Forma {
    Cerchio(float),           // Contiene il raggio
    Rettangolo(float, float), // Contiene la larghezza e l'altezza
    Punto                     // Non contiene dati
}

Unioni

Unioni standard C (accesso non sicuro).

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

Vettori SIMD

Tipi di vettore SIMD nativi utilizzando le estensioni vettoriali di GCC/Clang. Annota uno struct con @vector(N) per definire un vettore di N elementi.

import "std/simd.zc";

fn main() {
    let a = f32x4{v: 1.0};              // Broadcast: {1.0, 1.0, 1.0, 1.0}
    let b = f32x4{1.0, 2.0, 3.0, 4.0};  // Inizializzazione per elemento
    let c = a + b;                       // Addizione per elemento
    let x = c[0];                        // Accesso all'elemento (float)
}

Gli operatori aritmetici (+, -, *, /) e bitwise (&, |, ^) funzionano per elemento. Vedi std/simd.zc per i tipi predefiniti.

Alias del tipo

Crea un alias per un tipo già esistente.

alias ID = int;
alias PuntoDellaMappa = Mappa<string, Punto>
alias OpFunc = fn(int, int) -> int

Nota: Il punto e virgola finale è opzionale per gli alias di tipo.

Alias del tipo opachi

Puoi definire un alias del tipo come opaque (lett. opaco) per creare un nuovo tipo che si distingue dal suo tipo sottostante al di fuori del modulo che l'ha definito. Questo permette una forte incapsulamento e sicurezza dei tipi senza overhead extra durante l'esecuzione di un wrapper struct.

// In libreria.zc
opaque alias Handle = int;

fn crea_handle(v: int) -> Handle {
    return v; // Conversione implicita consentita all'interno del modulo
}

// In main.zc
import "libreria.zc";

fn main() {
    let h: Handle = crea_handle(42);
    // let i: int = h; // Errore: Validazione del tipo fallita
    // let h2: Handle = 10; // Errore: Validazione del tipo fallita
}

4. Funzioni e Lambda

Funzioni

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

// Supporto per argomenti nominati nelle chiamate
somma(a: 10, b: 20);

Note

Gli argomenti nominati devono seguire rigorosamente l'ordine predefinito dei parametri. somma(b: 20, a: 10) è errato.

Argomenti Costanti

Gli argomenti di una funzione possono essere marcati come const (lett. costanti) per reinforzare semantiche di sola lettura. Questo è un qualificatore del tipo, non una costante esplicita.

fn stampa_valore(v: const int) {
    // v = 10; // Errore: Impossibile assegnare un valore ad una variabile costante
    println "{v}";
}

Argomenti di default

Le funzioni posso definire dei valori default per gli argomenti in caso che questi non vengano specificati durante la chiamata. Questi valori possono essere letterali, espressioni, o codice Zen C valido (come il costruttore di uno struct).

// Valore default semplice
fn incrementa(val: int, quantità: int = 1) -> int {
    return val + quantità;
}

// Espressione come valore default (calcolato)
fn offset(val: int, pad: int = 10 * 2) -> int {
    return val + pad;
}

// Struct come valore default
struct Config { debug: bool; }
fn init(cfg: Config = Config { debug: true }) {
    if cfg.debug { println "Modalità Debug"; }
}

fn main() {
    incrementa(10);      // 11
    offset(5);          // 25
    init();             // Stampa "Modalità Debug"
}

Lambda (Closure)

Funzioni anonime che possono catturare il loro ambiente.

let fattore = 2;
let raddoppia = x -> x * fattore;  // Sintassi con freccia
let pieno = fn(x: int) -> int { return x * fattore; }; // Sintassi a blocco

// Cattura per Riferimento (Sintassi a Blocco)
let val = 10;
let modify = fn[&]() { val += 1; }; 
modify(); // val ora è 11

// Cattura per Riferimento (Sintassi a Freccia)
let modify_arrow = [&] x -> val += x;
modify_arrow(5); // val ora è 16

// Cattura per Riferimento (Sintassi a Freccia con Argomenti Multipli)
let sum_into = [&] (a, b) -> val += (a + b);
sum_into(2, 2); // val ora è 20

// Cattura per Valore (Predefinito)
let original = 100;
let implicit = x -> original + x;       // Cattura implicita per valore (senza parentesi)
let explicit = [=] x -> original + x;   // Cattura esplicita per valore
// let fail = x -> original += x;       // Errore: impossibile assegnare a valore catturato

Puntatori-Funzione grezzi

Zen C supporta i puntatori-funzione grezzi utilizzando la sintassi fn*. Questo permette un'interoperabilità fluida con le librerie C che si aspettano puntatori-funzione senza overhead di closure.

// Funzione che prende un puntatore-funzione grezzo
fn imposta_callback(cb: fn*(int)) {
    cb(42);
}

// Funzione che restituisce un puntatore-funzione grezzo
fn ottieni_callback() -> fn*(int) {
    return il_mio_handler;
}

// I puntatori a puntatori-funzione sono supportati (fn**)
let pptr: fn**(int) = &ptr;

Argomenti Variadici

Le funzioni possono accettare un numero variabile di argomenti utilizzando la sintassi ... e il tipo va_list.

fn log(lvl: int, fmt: char*, ...) {
    let ap: va_list;
    va_start(ap, fmt);
    vprintf(fmt, ap); // Usa lo stdio C
    va_end(ap);
}

5. Controllo di Flusso

Condizionali

if x > 10 {
    print("Grande");
} else if x > 5 {
    print("Medio");
} else {
    print("Piccolo");
}

// Operatore ternario
let y = x > 10 ? 1 : 0; // Se x è maggiore di 10 y sarà uguale a 1, in ogni altro caso, y sarà uguale a 0

// If-Expression (per condizioni complesse)
let categoria = if (x > 100) { "enorme" } else if (x > 10) { "grande" } else { "piccolo" };

Pattern Matching

Alternativa potente agli switch.

match val {
    1         => { print "Uno" },
    2 || 3    => { print "Due o Tre" },           // OR logico con ||
    4 or 5    => { print "Quattro or Cinque" },   // OR logico con 'or'
    6, 7, 8   => { print "Da Sei a Otto" },       // OR logico con la virgola (,)
    10 .. 15  => { print "Da 10 a 14" },          // Range Esclusivo (Legacy)
    10 ..< 15 => { print "Da 10 a 14" },          // Range Esclusivo (Esplicito)
    20 ..= 25 => { print "Da 20 a 25" },          // Range Inclusivo
    _         => { print "Altro" },
}

// Destrutturazione degli Enums
match forma {
    Forma::Cerchio(r)        => { println "Raggio: {r}" },
    Forma::Rettangolo(w, h)  => { println "Area: {w*h}" },
    Forma::Punto             => { println "Punto" },
}

Associaione di riferiemnto

Per ispezionare un valore senza assumerne la proprietà (spostarlo) puoi usare la keyword ref nel pattern. Questo è essenziale per i tipi che implementano Semantiche di Movimento (come Option, Result, struct non-copiabile).

let opt = Qualche(ValoreNonCopiable{...});
match opt {
    Some(ref x) => {
        // 'x' è un puntatore che punta al valore contenuto in 'opt'
        // 'opt' NON viene né mosso né consumato qui
        println "{x.field}"; 
    },
    None => {}
}

Loops

// Range
for i in 0..10 { ... }      // Esclusivo (Da 0 a 9)
for i in 0..<10 { ... }     // Esclusivo (Esplicito)
for i in 0..=10 { ... }     // Inclusivo (Da 0 a 10)
for i in 0..10 step 2 { ... }
for i in 10..0 step -1 { ... }  // Descending loop

// Iteratore (Vec, Array, oppure un Iteratore personalizzato)
for item in collection { ... }

// Enumerato: ottieni indice e valore
for i, val in collection { ... }   // i = 0, 1, 2, ...
for i, val in 0..10 step 2 { ... } // i = 0, 1, 2, ...; val = 0, 2, 4, ...

// While (lett. mentre)
while x < 10 { ... }

// Infinito con etichetta
esterno: loop {
    if done { break esterno; }
}

// Ripeti N volte
for _ in 0..5 { ... }

Controllo Avanzato

// Guard (lett. 'guardia'): Esegue il caso 'else' e ritorna se la condizione è falsa
guard ptr != NULL else { return; }

// Unless (lett. 'a meno che'): Se non vero
unless è_valido { return; }

6. Operatori

Zen C supporta l'overloading di operatori per gli struct definiti dall'utente per implementare nomi specifici di metodi.

Operatori Overload-abili

Categoria Operatore Nome del Metodo
Aritmetico +, -, *, /, %, ** add, sub, mul, div, rem, pow
Paragone ==, != eq, neq
<, >, <=, >= lt, gt, le, ge
Bitwise &, |, ^ bitand, bitor, bitxor
<<, >> shl, shr
Unari - neg
! not
~ bitnot
Indice a[i] get(a, i)
a[i, j] get(a, i, j)
a[i] = v set(a, i, v)

Nota sull'uguaglianza delle stringhe:

  • string == string performa un controllo del valore (equivalente a strcmp).
  • char* == char* performa un controllo dei puntatori (controlla gli indirizzi di memoria).
  • Paragoni misti (e.g. string == char*) defaulta al controllo dei pointer.

Esempio:

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

let p3 = p1 + p2; // Chiama p1.somma(p2)

Esempio Multi-Indice:

struct Matrice {
    data: int[9];
}

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

let m = Matrice{data: [1,0,0, 0,1,0, 0,0,1]};
let val = m[1, 2]; // Chiama Matrice.get(m, 1, 2)

Zucchero Sintattico

Questi operatori sono funzionalità integrate del linguaggio e non è possibile overloadarli.

Operatore Nome Descrizione
|> Pipeline x |> f(y) viene dezuccherato a f(x, y)
?? Coalescenza nulla val ?? default restituisce default se val è NULL (puntatori)
??= Assegnazione nulla val ??= init assegna se val è NULL
?. Safe Navigation ptr?.campo accede a 'campo' solo se ptr non è NULL
? Try Operator res? restituisce un errore se presente (tipi Result/Option)

Dereferenza Automatica: Pointer field access (ptr.field) and method calls (ptr.method()) automatically dereference the pointer, equivalent to (*ptr).field. Accesso ai campi da un puntatore (puntatore.campo) e chiamate ai metodi (puntatore.metodo()) dereferenzano automaticamente il puntatore, ciò è equivalente a (*puntatore).campo

7. Stampaggio e Interpolazione delle Stringhe

Zen C fornisce opzioni versatili per stampare alla console, includendo keyword e scorciatoie coincise.

Keyword

Keyword Descrizione
print "testo" Stampa a stdout senza aggiunzione di una newline automatica.
println "testo" Stampa a stdout aggiungendo una newline automatica.
eprint "testo" Stampa a stderr senza aggiunzione di una newline automatica.
eprintln "testo" Stampa a stderr aggiungendo una newline automatica.

Scorciatoie

Zen C ti permette di utilizzare stringhe letterali direttamente come istruzione di stampaggio veloce:

Sintassi Equivalente Descrizione
"Ciao!" println "Ciao!" Aggiunge una newline implicitamente.
"Ciao!".. print "Ciao!" Non aggiunge una newline.
!"Errore" eprintln "Errore" Output a stderr.
!"Errore".. eprint "Errore" Output a stderr, senza newline.

Interpolazione delle Stringhe

Puoi incorporare espressioni direttamente all'interno di stringhe letterali utilizzando la sintassi {}. Questo funziona con tutti i metodi di stampaggio, incluse le scorciatoie.

L'interpolazione di stringhe in Zen C è implicita: se la tua stringa contiene {...}, verrà analizzata automaticamente come una stringa interpolata. Puoi anche usare esplicitamente il prefisso f (es. f"...") per forzare la semantica di interpolazione.

let x = 42;
let nome = "Max";
println "Valore: {x}, Nome: {name}";
"Valore: {x}, Nome: {name}"; // scorciatoia per println

Escape delle Parentesi Graffe: Usa {{ per produrre una parentesi graffa letterale { e }} per una } letterale:

let json = "JSON: {{\"chiave\": \"valore\"}}";
// Output: JSON: {"chiave": "valore"}

Stringhe Grezze (Raw Strings): Per definire una stringa in cui le sequenze di interpolazione e di escape vengono completamente ignorate, inserici il prefisso r (es. r"..."):

let regex = r"\w+"; // Contiene esattamente \ w +
let raw_json = r'{"chiave": "valore"}'; // Non è necessario l'escape delle parentesi

Stringhe Multilinea

Zen C supporta blocchi di stringhe multilinea grezzi utilizzando il delimitatore """. Questo è estremamente utile per la scrittura di linguaggi incorporati (GLSL, HTML) o per la generazione di codice C all'interno di blocchi comptime senza il bisogno di inserire manualmente l'escape a capo ed alle virgolette all'interno.

Come le stringhe standard, le stringhe multilinea supportano l'interpolazione implicita. Puoi aggiugere l'escape in maniera esplicita usando:

  • f"""...""": Contrassegna in modo esplicito un blocco di stringa interpolato.
  • r"""...""": Contrassegna in modo esplicito un blocco di stringa grezzo (nessuna interpolazione, nessuna sequenza di escape).
let prompt = """
  Per favore, inserisci il tuo nome:
  Digita "exit" per annullare.
""";

let mondo = "mondo";
let script = """
  fn ciao() {
      println "ciao, {mondo}!";
  }
""";

let pure_raw = r"""
  Qui le {parentesi} sono solo testo, e \n e' letteralmente barra ed n.
""";

Prompt di Input (?)

Zen C supporta una scorciatoia per richiedere input dall'utente utilizzando il prefisso ?.

  • ? "Inserisci il tuo nome": Stampa il prompt (senza newline) e aspetta per dell'input (legge una linea).
  • ? "Inserisci la tua età: " (età): Stampa il prompt e memorizza l'input nella variabile età.
    • Gli specificatori del formato vengono automaticamente inferiti in base al tipo della variabile.
let età: int;
? "Inserisci la tua età: " (età);
println "Hai {età} anni.";

8. Gestione della memoria

Zen C permette una gestione manuale della memoria con aiuti ergonomici.

Rimando

Esegui il codice quando l’ambito corrente termina. Le istruzioni defer vengono eseguite in ordine LIFO (last-in, first-out).

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

Per prevenire comportamenti indefiniti, le istruzioni del controllo di flusso (return, break, continue, goto) non sono ammesse dentro un blocco defer.

Liberazione automatica

Libera automaticamente la memoria occupata dalla variabile quando l'ambito corrente termina.

autofree let tipi = malloc(1024);

Semantiche delle risorse (Muovi di Default)

Zen C tratta i tipi con distruttori (come File, Vec, o puntatori allocati manualmente con malloc) come Risorse. Per prevenire errori di doppia-liberazione, le risorse non possono essere implicitamente duplicate.

  • Muovi di Default: Assegnare una risorsa variabile ne trasferisce il proprietario. La variabile originale diventa invalida (Spostata).
  • Tipi di Copia: Tipi senza distruttori possono opzionalmente avere un comportamento Copy, rendendo l'assegnazione una duplicazione.

Diagnostica & Filosofia: Se vedi un errore "Utilizzo di una variabile spostata", il compilatore ti sta dicendo: "Questo tipo è proprietario di una risorsa (come memoria o un handle) e copiarlo ciecamente non è sicuro."

Contrasto: Al contrario di come fanno C/C++, Zen C non duplica implicitamente i valori che posseggono risorse.

Argomento di una funzione: Passare un valore ad una funzione segue le stesse regole dell'assegnazione: le risorse vengono spostate se non passate per referenza.

fn processo(r: Risorsa) { ... } // 'r' viene spostato nella funzione
fn peek(r: Risorsa*) { ... }    // 'r' viene preso in prestito (referenza)

Clonazione Esplicita: Se vuoi avere più copie di una risorsa, rendilo esplicito:

let b = a.clona(); // Chiama il metodo `clona` dal tratto `Clone`

Duplicazione opt-in (Tipi dei valori): Per tipi piccoli senza distruttore:

struct Punto { x: int; y: int; }
impl Copy for Punto {} // Opt-in per la duplicazione implicita

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = p1; // Copiato. p1 rimane valido.
}

RAII / Rilascio Tratti

Implementa Drop per una logica di pulizia automatica.

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

9. Programmazione Orientata a Oggetti

Metodi

Definisci metodi sui tipi utilizziando impl.

impl Punto {
    // Metodo statico (convenzione del costruttore)
    fn nuovo(x: int, y: int) -> Self {
        return Point{x: x, y: y};
    }

    // Metodo d'instanza
    fn dist(self) -> float {
        return sqrt(self.x * self.x + self.y * self.y);
    }
}

Scorciatoia di Self: Nei metodi con un parametro self, puoi usare .campo come abbreviazione per self.campo:

impl Point {
    fn dist(self) -> float {
        return sqrt(.x * .x + .y * .y);  // Equivalente a self.x, self.y
    }
}

Métodos primitivos

Zen C permette di definire metodi su tipi primitivi (come int, bool, etc.) usando la stessa sintassi 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)

Tratti

Definisci un comportamento condiviso.

struct Cerchio { raggio: f32; }

trait Disegnabile {
    fn disegna(self);
}

impl Disegna for Cerchio {
    fn disegna(self) { ... }
}

let cerchio = Cerchio{};
let disegnabile: Disegnabile = &cerchio;

Tratti Standard

Zen C include dei tratti standard che si integrano con la sintassi del linguaggio.

Iterable (lett. Iterabile)

Implementa Iterable<T> per abilitare loop for-in (lett. per in) nei tuoi tipi personalizzati.

import "std/iter.zc"

// Definisci un Iteratore
struct MioIteratore {
    curr: int;
    stop: int;
}

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

// Implementa Iterable
impl MioRange {
    fn iterator(self) -> MioIteratore {
        return MioIteratore{curr: self.start, stop: self.end};
    }
}

// Usalo in un loop
for i in mio_range {
    println "{i}";
}

Drop (lett. rilascia)

Implementa Drop per definire un distruttore che esegue quando l'oggetto va fuori ambito (RAII).

import "std/mem.zc"

struct Risorsa {
    ptr: void*;
}

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

Note

Se una variabile viene spostata, drop NON verrà chiamato sulla variabile originale. Aderisce alle Semantiche delle Risorse

Copy (lett. copia)

Tratto marcatore opt-in per il comportamento Copy (duplicazione implicita) al posto delle semantiche Move. Utilizzato tramite @derive(Copy)

Regola: I tipi che implementano Copy non dovrà definire un distruttore (Drop).

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

fn main() {
    let p1 = Punto{x: 1, y: 2};
    let p2 = p1; // Copiato! p1 rimane valido.
}

Clone (lett. clona)

Implementa Clone per permettere la duplicazione esplicita di tipi che posseggono risorse.

import "std/mem.zc"

struct Scatola { val: int; }

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

fn main() {
    let b1 = Scatola{val: 42};
    let b2 = b1.clone(); // Explicit copy
}

Composizione

Usa use per incorporare altri struct. Puoi mischiarli (campi piatti) o nominarli (campi nidificato).

struct Entità { id: int; }

struct Giocatore {
    // Mischiati (Non nominati): Campi piatti
    use Entità;  // Aggiunge 'id' a 'Giocatore' direttamente
    nome: string;
}

struct Partita {
    // Composizione (Nominati): Campi nidificati
    use p1: Giocatore; // Vi si accede tramite partita.p1
    use p2: Giocatore; // Vi si accede tramite partita.p2
}

11. Generici

Template type-safe per struct e funzioni.

// Struct Generico
struct Scatola<T> {
    oggetto: T;
}

// Funzione Generica
fn identità<T>(valore: T) -> T {
    return valore;
}

// Generici Multi-parametro
struct Paio<K, V> {
    chiavi: K;
    valore: V;
}

11. Concorrenza Asincrona (Async/Await)

Costruito sui pthreads.

async fn ottieni_dati() -> string {
    // Esegue in background
    return "Dati";
}

fn main() {
    let futuro    = ottieni_dati();
    let risultato = await futuro; // (lett. 'aspetta')
}

12. Metaprogramming

Comptime

Esegui codice al momento della compilazione per generare sorgente o stampare messaggi.

comptime {
    // Genera codice al momento della compilazione (scritto su stdout)
    println "let data_compilazione = \"2024-01-01\";";
}

println "Data compilazione: {data_compilazione}";
Funzioni Helper

Funzioni speciali disponibili all'interno dei blocchi comptime:

Funzione Descrizione
yield(str) Emette esplicitamente codice generato (alternativa a printf)
code(str) Alias di yield() - intento più chiaro per generazione codice
compile_error(msg) Interrompe la compilazione con un messaggio di errore fatale
compile_warn(msg) Emette un avviso al momento della compilazione (consente di continuare)

Esempio:

comptime {
    compile_warn("Generazione codice ottimizzato...");
    
    let ENABLE_FEATURE = 1;
    if (ENABLE_FEATURE == 0) {
        compile_error("La funzionalità deve essere abilitata!");
    }
    
    // Usa code() con raw strings per generazione pulita
    code(r"let FEATURE_ENABLED = 1;");
}
Metadati di Build

Accedi alle informazioni di build del compilatore al momento della compilazione:

Costante Tipo Descrizione
__COMPTIME_TARGET__ string Piattaforma: "linux", "windows" o "macos"
__COMPTIME_FILE__ string Nome del file sorgente corrente in compilazione

Esempio:

comptime {
    // Generazione codice specifico per piattaforma
    println "let PLATFORM = \"{__COMPTIME_TARGET__}\";";
}

println "In esecuzione su: {PLATFORM}";

Tip

Usa raw strings (r"...") in comptime per evitare di eseguire l'escape delle parentesi graffe: code(r"fn test() { return 42; }"). Altrimenti, usa {{ e }} per l'escape nelle stringhe normali.

Incorporati

Incorpora file come tipi specificati.

// Default (Slice_char)
let data = embed "assets/logo.png";

// Incorporazioni tipizzate
let testo = embed "shader.glsl" as string;    // Incorpora come una stringa C
let rom   = embed "bios.bin" as u8[1024];     // Incorpora come un array a dimensione fissa
let wav   = embed "sound.wav" as u8[];        // Incorpora come Slice_u8

Plugin

Importa plugin del compilatore per estendere la sintassi.

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

Macro C Generiche

Passa delle macro del preprocessore C.

Tip

Per delle semplici costanti, utilizza def. Usa #define solo quanto ti servono macro del preprocessore C o flag di compilazione condizionale.

#define BUFFER_MASSIMO 1024

Compilazione Condizionale

Usa @cfg() per includere o escludere condizionalmente qualsiasi dichiarazione di livello superiore in base ai flag -D.

// Compila con: 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 "Nessun backend selezionato"; }
Forma Significato
@cfg(NAME) Includi se -DNAME è definito
@cfg(not(NAME)) Includi se -DNAME NON è definito
@cfg(any(A, B, ...)) Includi se QUALSIASI condizione è vera (OR)
@cfg(all(A, B, ...)) Includi se TUTTE le condizioni sono vere (AND)

Più @cfg su una dichiarazione vengono combinati con AND. not() può essere usato dentro any() e all(). Funziona con qualsiasi dichiarazione di livello superiore: fn, struct, import, impl, raw, def, test, ecc.

13. Attributi

Decora le funzioni e gli struct per modificare il comportamento del compilatore.

Attributo Ambito Descrizione
@must_use Fn Avvereti se il valore di ritorno viene ignorato.
@deprecated("msg") Fn/Struct Avverti all'uso con 'msg'
@inline Fn Suggerisci al compilatore di rendere il codice inline
@noinline Fn Previeni l'inline automatico
@packed Struct Rimuovi il padding (lett. imbottitura) automatico in mezzo ai campi.
@align(N) Struct Forza l'allineamento a N byte.
@constructor Fn Esegui prima di main.
@destructor Fn Esegue dopo la terminazione di main.
@unused Fn/Var Sopprimi gli errori di 'variabile inutilizzata'
@weak Fn Linking dei simboli weak (lett. debole).
@section("name") Fn Inserisci il codice in una specifica sezione.
@noreturn Fn La funzione non restituisce valori. (e.g. exit).
@pure Fn La funzione non ha effetti collaterali (indizio per l'ottimizzazione).
@cold Fn La funzione è usata poco spesso (indizio per la branch prediction).
@hot Fn La funzione è usata molto spesso (indizio per l'ottimizzazione).
@export Fn/Struct Esporta simbolo (visibilità default).
@global Fn CUDA: Entry point del Kernel (__global__).
@device Fn CUDA: Funzione del Device (__device__).
@host Fn CUDA: Funzione dell'Host (__host__).
@comptime Fn Funzione di supporto disponibile per l'esecuzione al tempo di compilazione.
@cfg(NAME) Qualsiasi Compilazione condizionale: includi solo se viene passato -DNAME. Supporta not(), any(), all().
@derive(...) Struct Implementa automaticamente i tratti. Supporta Debug, Eq (Derivazione Intelligente), Copy, Clone.
@<custom> Any Passa gli attributi generici direttamente al C (e.g. @flatten, @alias("nome"))

Attributi Personalizzati

Zen C supporta un potente sistema di Attributi Personalizzati che ti permettono di utilizzare ogni __attributo__ GCC/Clang direttamente nel tuo codice Zen C. Qualsiasi attributo non riconosciuto dal compilatore Zen C viene trattato come un attributo generico e passato direttamente nel codice C generato.

Ciò fornisce accesso a delle avanzate funzionalità, ottimizzazioni e direttive del linker senza necessitare di un supporto esplicito nel cuore del linguaggio.

Mappatura della Sintassi

Zen C attributes are mapped directly to C attributes:

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

Derivazioni Intelligenti

Zen C fornisce delle "derivazioni intelligenti" che rispettano le Semantiche di Movimento:

  • @derive(Eq): Genera un metodo di uguaglianza che prende argomenti per referenza (fn eq(self, other: T*)).
    • Quando si confrontano due struct non-Copy (a == b), il compilatore passa automaticamente b per referenza (&b) per non doverlo spostare.
    • I controlli di uguaglianza ricorsivi preferiscono l'accesso da puntatore per prevenire il trasferimento del proprietario.

14. Assembly Inline

Zen C fornisce supporto di prima-classe per l'assembly inline, traspilando direttamente ad asm con estensioni in stile GCC.

Utilizzo Base

Scrivi assembly grezzo all'interno di blocchi asm. Le stringhe vengono concatenate automaticamente.

asm {
    "nop"
    "mfence"
}

Volatile

Impedisci al compilatore di eliminare automaticamente istruzioni assembly (e.g. ottimizzazione) se ciò potrebbe avere ripercussioni.

asm volatile {
    "rdtsc"
}

Vincoli Nominati

Zen C semplifica la sintassi complessa dei vincoli di GCC con dei binding nominati.

Nota per i lettori italiani: Con 'clobber' si intende la sovrascrizione.

// Sintassi: : out(variable) : in(variable) : clobber(reg)
// Usa una sintassi placeholder (`{variabile}`) per la leggibilità

fn aggiungi_cinque(x: int) -> int {
    let risultato: int;
    asm {
        "mov {x}, {risultato}"
        "add $5, {risultato}"
        : out(risultato)
        : in(x)
        : clobber("cc")
    }
    return risultato;
}
Tipo Sintassi Equivalente GCC
Output : out(variabile) "=r"(variabile)
Input : in(variabile) "r"(variabile)
Clobber : clobber("rax") "rax"
Memory : clobber("memoria") "memoria"

Note

Quando si usa la sintassi Intel (via -masm=intel), dovrai assicurarti che la tua build sia configurata correttamente (per esempio, //> cflags: -masm=intel). TCC non supporta la sintassi assembly Intel.

15. Direttive della Build

Zen C supporta dei commenti speciali all'inizio del tuo file sorgente che ti permettono di configurare il processo di build senza necessitare di un sistema di build complesso o di un Makefile.

Direttiva Argomenti Descrizione
//> link: -lfoo oppure path/to/lib.a Linka con una libreria o un file object.
//> lib: path/to/libs Aggiunge una directory dove cercare le librerie (-L).
//> include: path/to/headers Aggiunge una directory dove cercare i file include (-I).
//> framework: Cocoa Linka con un framework macOS.
//> cflags: -Wall -O3 Passa flag arbitrare al compilatore C.
//> define: MACRO or KEY=VAL Definisci una macro del preprocessore (-D).
//> pkg-config: gtk+-3.0 Esegui pkg-config e aggiungi --cflags e --libs.
//> shell: command Esegui un comando sulla shell durante il processo di build.
//> get: http://url/file Scarica un file se un file specifico non esiste.

Feature

1. OS Guarding (lett. Protezione OS) Prefissa delle direttive con il nome di un OS per applicarle solo su piattaforme specifiche. Prefissi supportati: linux:, windows:, macos: (or darwin:).

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

2. Environment Variable Expansion Utilizza la sintassi ${VAR} per espandare variabili d'ambiente nelle tue direttive.

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

Esempi

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

import "raylib.h"

fn main() { ... }

16. Keyword

Le keyword che seguono sono riservate in Zen C.

Dichiarazioni

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

Controllo del Flusso

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

Speciali

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

Costanti

true, false, null

Riservate del C

Gli identifiers seguenti sono riservati poiché sono keyword nello standard 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

Operatori

and, or

17. Interoperabilità C

Zen C offre due modi per interagire con il codice C: Import Trusted (Conveniente) e FFI Esplicita (Sicuro/Preciso).

Metodo 1: Import Trusted (Conveniente)

Puoi importare un header C direttamente usando la parola chiave import con l'estensione .h. Questo tratta l'header come un modulo e assume che tutti i simboli acceduti esistano.

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

fn main() {
    // Il compilatore si fida della correttezza; emette 'cos(...)' direttamente
    let x = c_math::cos(3.14159);
}

Pro: Zero boilerplate. Accesso immediato a tutto nell'header. Contro: Nessuna sicurezza dei tipi da Zen C (errori catturati dal compilatore C dopo).

Metodo 2: FFI Esplicita (Sicuro)

Per un controllo rigoroso dei tipi o quando non vuoi includere il testo di un header, usa extern fn.

include <stdio.h> // Emette #include <stdio.h> nel C generato

// Definisci firma rigorosa
extern fn printf(fmt: char*, ...) -> c_int;

fn main() {
    printf("Ciao FFI: %d\n", 42); // Controllato nei tipi da Zen C
}

Pro: Zen C assicura che i tipi corrispondano. Contro: Richiede dichiarazione manuale delle funzioni.

import vs include

  • import "file.h": Registra l'header come un modulo con nome. Abilita l'accesso implicito ai simboli (es. file::function()).
  • include <file.h>: Emette puramente #include <file.h> nel codice C generato. Non introduce alcun simbolo nel compilatore Zen C; devi usare extern fn per accedervi.

Libreria Standard

Zen C include una libreria standard (std) che ricopre funzionalità essenziali.

Scopri la documentazione della Libreria Standard

Moduli Chiave

Clicca per vedere tutti i moduli della Libreria Standard
Modulo Descrizione Documentazione
std/bigfloat.zc Aritmetica in virgola mobile a precisione arbitraria. Docs
std/bigint.zc Intero a precisione arbitraria BigInt. Docs
std/bits.zc Operazioni bit a bit a basso livello (rotl, rotr, ecc.). Docs
std/complex.zc Aritmetica dei numeri complessi Complex. Docs
std/vec.zc Array dinamico espandibile Vec<T>. Docs
std/string.zc Tipo String allocato sull'Heap con supporto UTF-8. Docs
std/queue.zc Coda FIFO (Buffer Circolare). Docs
std/map.zc Hash Map Generica Map<V>. Docs
std/fs.zc Operazioni del File System. Docs
std/io.zc Standard Input/Output (print/println). Docs
std/option.zc Valori opzionali (Some/None). Docs
std/result.zc Gestione degli errori (Ok/Err). Docs
std/path.zc Manipolazione dei percorsi Cross-platform. Docs
std/env.zc Variabili d'ambiente del processo. Docs
std/net/ TCP, UDP, HTTP, DNS, URL. Docs
std/thread.zc Thread e Sincronizzazione. Docs
std/time.zc Misuramenti di tempo e sleep. Docs
std/json.zc Parsing JSON e serializzazione. Docs
std/stack.zc Stack LIFO Stack<T>. Docs
std/set.zc Hash Set Generico Set<T>. Docs
std/process.zc Esecuzione e gestione di processi. Docs
std/regex.zc Espressioni Regolari (basato su TRE). Docs
std/simd.zc Tipi di vettore SIMD nativi. Docs

Tooling

Zen C fornisce un Language Server (LSP) e un REPL per migliorare l'esperienza degli sviluppatori.

Language Server (LSP)

Il server del linguaggio (LSP) di Zen C supporta le feature standard per l'integrazione con gli editor, esso fornisce:

  • Vai alla definizione
  • Trova riferimenti
  • Informazioni sull'hover
  • Completamenti automatici (Nomi di funzioni/struct, Completamento dal punto per i methods/campi)
  • Simboli dei documenti (Outline)
  • Aiuto con le signature delle funzioni
  • Diagnostiche (Errori sintattici/semantici)

Per avviare il server del linguaggio (tipicamente configurato nelle impostazioni LSP del tuo editor):

zc lsp

Il server comunica via lo Standard I/o (JSON-RPC 2.0).

REPL

Il Read-Eval-Print-Loop (REPL, lett. Leggi-Esegui-Stampa-Ripeti) ti permette ti sperimentare con il codice Zen C in maniera interattiva.

zc repl

Funzionalità

  • Coding interattivo: Scrivi espressioni o istruzioni per una esecuzione immediata.
  • Storia persistente: I comandi vengono salvati in ~/.zprep_history.
  • Script di avvio: I comandi di avvio (auto-load) sono salvati in ~/.zprep_init.zc.

Comandi

Comande Descrizione
:help Mostra i comandi disponibili.
:reset Cancella la storia della sessione corrente (variabili/funzioni).
:vars Mostra le variabili attive.
:funcs Mostra le funzioni definite dall'utente.
:structs Mostra gli struct definiti dall'utente.
:imports Mostra gli 'import' attivi.
:history Mostra la storia dell'input della sessione.
:type <expr> Mostra il tipo di un espressione.
:c <stmt> Mostra il codice C generato per un istruzione.
:time <expr> Esegui un benchmark per l'espressione data. (Esegue 1000 iterazioni).
:edit [n] Modifica il comando n (default: l'ultimo comando) in $EDITOR.
:save <file> Salva la sessione corrente in un file .zc.
:load <file> Carica ed esegui un file .zc nella sessione corrente.
:watch <expr> Watch (lett. guarda) un espressione (rieseguita dopo ogni entry).
:unwatch <n> Rimuovi un watch.
:undo Rimuovi l'ultimo comando dalla sessione.
:delete <n> Rimuovi il comando all'indice n.
:clear Pulisce lo schermo.
:quit Esce dal REPL.
! <cmd> Esegue un comando sulla shell (e.g. !ls).

Protocollo Server di Linguaggio (LSP)

Zen C include un Server di Linguaggio integrato per l'integrazione con gli editor.

Usa zc lsp per avviare il server.

Debugging Zen C

I programmi Zen C possono essere sottoposti a debug utilizzando i debugger C standard come LLDB o GDB.

Visual Studio Code

Per la migliore esperienza in VS Code, installa l'estensione ufficiale Zen C. Per il debugging, puoi utilizzare l'estensione C/C++ (di Microsoft) o CodeLLDB.

Aggiungi queste configurazioni alla tua directory .vscode per abilitare il debugging con un clic:

tasks.json (Attività di compilazione):

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

launch.json (Debugger):

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

Supporto del Compilatore e Compatibilità

Zen C è stato creato in modo tale da poter funzionare con la maggior parte dei compilatori C11. Alcune funzionalità potrebbero affidarsi ad estensioni GNU C, ma spesso queste funzionano anche su altri compilatori. Utilizza la flag --cc per modificare il backend.

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

Stato della suite di test

Clicca per vedere i dettagli del supporto del compilatore
Compilatore Percentuale di Superamento Funzionalità Supportate Limitazioni Nota
GCC 100% (Completo) Tutte le funzionalità Nessuna.
Clang 100% (Completo) Tutte le funzionalità Nessuna.
Zig 100% (Completo) Tutte le funzionalità Nessuna. Usa zig cc come compilatore C.
TCC 98% (Alto) Strutture, Generici, Tratti, Pattern Matching Niente ASM Intel, Niente __attribute__((constructor)).

Warning

AVVISO DI COMPILAZIONE: Sebbene Zig CC funzioni ottimamente come backend per i tuoi programmi Zen C, compilare il compilatore Zen C stesso con esso potrebbe verificare ma produrre un binario instabile che fallisce i test. Consigliamo di compilare il compilatore con GCC o Clang e usare Zig solo come backend per il tuo codice operativo.

Tip

Buildare con Zig

Il comando zig cc di Zig fornisce un rimpiazzamento drop-in per GCC/Clang con eccellente supporto per la cross-compilation. Per usare Zig:

# Compila ed esegui un programma Zen C con Zig
zc run app.zc --cc zig

# Puoi compilare persino il compilatore Zen C stesso con Zig
make zig

Interop C++

Zen C può generare codice compatibile con C++ utilizzando l'opzione --cpp, permettendo una integrazione fluida con le librerie C++.

# Compilazione diretta con g++
zc app.zc --cpp

# O traspila per le build manuali
zc transpile app.zc --cpp
g++ out.c my_cpp_lib.o -o app

Usare C++ in Zen C

Includi header C++ e usa blocchi grezzi per codice C++:

include <vector>
include <iostream>

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

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

Nota: L'opzione --cpp rende il backend g++ ed emette codice valido per C++ (utilizza auto al posto di __auto_type, overload delle funzioni al posto di _Generic e i cast espliciti per void*)

Interop CUDA

Zen C supporta la programmazione GPU traspilando a CUDA C++. Questo ti permette di utilizzare potenti funzionalità C++ (template, constexpr) all'interno dei tuoi kernel mantenendo la sintassi ergonomica di Zen C.

# Compilazione diretta con nvcc
zc run app.zc --cuda

# O traspila per le build manuali
zc transpile app.zc --cuda -o app.cu
nvcc app.cu -o app

Attributi specifici CUDA

Attributo Equivalente CUDA Descrizione
@global __global__ Function Kernel (esegue sulla GPU, chiamato dall'host)
@device __device__ Funzione Device (esegue sulla GPU, chiamato dalla GPU)
@host __host__ Funzione Host (Solo CPU esplicita)

Kernel Launch Syntax

Zen C fornisce un'istruzione chiara launch per richiamare kernel CUDA:

launch kernel_name(args) with {
    grid: num_blocks,
    block: threads_per_block,
    shared_mem: 1024,  // Opzionale
    stream: my_stream   // Opzionale
};

Questo traspila a: kernel_name<<<grid, block, shared, stream>>>(args);

Scrivere kernel CUDA

Utilizza la sintassi delle funzioni Zen C con @global e l'istruzione launch:

import "std/cuda.zc"

@global
fn aggiungi_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 aggiungi_kernel(d_a, d_b, d_c, N) with {
        grid: (N + 255) / 256,
        block: 256
    };
    
    cuda_sync();
}

Libreria Standard (std/cuda.zc)

Zen C fornisce una libreria standard per delle operazioni comuni in CUDA per ridurre la mole di blocchi raw (grezzi):

import "std/cuda.zc"

// Gestione della memoria
let d_ptr = cuda_alloc<float>(1024);
cuda_copy_to_device(d_ptr, h_ptr, 1024 * sizeof(float));
defer cuda_free(d_ptr);

// Sincronizzazione
cuda_sync();

// Indicizzazione dei thread (usa all'interno del kernel)
let i = thread_id(); // Indice globale
let bid = block_id();
let tid = local_id();

Note

Nota: La flag --cuda imposta nvcc come compilatore e implica la modalità --cpp. Richiede l'installazione dell'NVIDIA CUDA Toolkit.

Supporto C23

Zen C supporta le funzionalità moderne dello standard C23 quando si usa un backend compatibile (GCC 14+, Clang 14+, TCC (parziale)).

  • auto: Zen C mappa automaticamente l'inferenza del tipo alla keyword auto di C23 (se __STDC_VERSION__ >= 202300L).
  • _BitInt(N): Usa i tipi iN e uN (e.g., i256, u12, i24) per accedere agli interi di lunghezza arbitraria di C23.

Interop Objective-C

Zen C può compilare a Objective-C (.m) utilizzando la flag --objc, permettendoti di utilizzare i framework (come Cocoa/Foundation) e la sintassi Obj-C

# Compila con clang (o gcc/gnustep)
zc app.zc --objc --cc clang

Usando l'Objective-C in Zen C

Utilizza include per gli header e i blocchi raw per la sintassi Obj-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(@"Ciao da Objective-C!");
        [pool drain];
    }
    println "Funziona anche Zen C!";
}

Note

Nota: L'interpolazione delle stringhe di Zen C funziona con gli oggetti dell'Objective-C (id) chiamando debugDescription oppure description.


Contribuisci

Qui accogliamo tutti i contributi! Che siano fix di bug, miglioramenti alla documentazione, o la proposta di nuove funzionalità.

Per favore, consulta CONTRIBUTING_IT.md per le linee guida dettagliate su come contribuire, eseguire i test e inviare pull request.


Sicurezza

Per istruzioni sulla segnalazione di vulnerabilità, vedi SECURITY_IT.md.


Attribuzioni

Questo progetto utilizza librerie esterne. I testi di licenza completi possono essere trovati nella directory LICENSES/.

  • cJSON (Licenza MIT): Usato per il parsing e la generazione di JSON nel Language Server.
  • zc-ape (Licenza MIT): La versione originale di Actually Portable Executable di Zen-C, realizzata da Eugene Olonov.
  • Cosmopolitan Libc (Licenza ISC): La libreria fondamentale che rende possibile APE.
  • TRE (Licenza BSD): Usato per il motore di espressioni regolari nella libreria standard.
  • zenc.vim (Licenza MIT): Il plugin ufficiale per Vim/Neovim, scritto principalmente da davidscholberg.

Copyright © 2026 Zen C Programming Language.
Inizia il tuo viaggio oggi.

DiscordGitHubDocumentazioneEsempiRFCContribuisci