Escribe como un lenguaje de alto nivel, ejecuta como C.
Descripción General • Comunidad • Inicio Rápido • Ecosistema • Referencia del Lenguaje • Biblioteca Estándar • Herramientas
Zen C es un lenguaje de programación de sistemas moderno que se compila a GNU C/C11 legible por humanos. Proporciona un conjunto rico de características que incluyen inferencia de tipos, coincidencia de patrones (pattern matching), genéricos, traits, async/await y gestión manual de memoria con capacidades RAII, todo manteniendo una compatibilidad total con el ABI de C.
¡Únete a la discusión, comparte demos, haz preguntas o reporta errores en el servidor oficial de Discord de Zen C!
- Discord: Únete aquí
- RFCs: Proponer características
El proyecto Zen C consta de varios repositorios. A continuación se presentan los principales:
| Repositorio | Descripción | Estado |
|---|---|---|
| zenc | El compilador central de Zen C (zc), la CLI y la biblioteca estándar. |
Desarrollo Activo |
| docs | La documentación técnica oficial y la especificación del lenguaje. | Activo |
| rfcs | El repositorio de Solicitud de Comentarios (RFC). Dale forma al futuro del lenguaje. | Activo |
| vscode-zenc | Extensión oficial de VS Code (Resaltado de sintaxis, Snippets). | Alpha |
| www | Código fuente de zenc-lang.org. |
Activo |
| awesome-zenc | Una lista curada de ejemplos asombrosos de Zen C. | Creciendo |
| zenc.vim | Plugin oficial para Vim/Neovim (Sintaxis, Sangría). | Activo |
Echa un vistazo a estos proyectos construidos con Zen C:
- ZC-pong-3ds: Un clon de Pong para Nintendo 3DS.
- zen-c-parin: Un ejemplo básico usando Zen C con Parin.
- almond: Un navegador web minimalista escrito en Zen C.
git clone https://github.com/zenc-lang/zenc.git
cd Zen-C
make clean # eliminar archivos de construcción antiguos
make
sudo make installZen C tiene soporte nativo completo para Windows (x86_64). Puedes construirlo usando el script de procesamiento por lotes (batch) proporcionado con GCC (MinGW):
build.batEsto construirá el compilador (zc.exe). Las operaciones de Red, Sistema de Archivos y Procesos están totalmente soportadas a través de la Capa de Abstracción de Plataforma (PAL).
Alternativamente, puedes usar make si tienes un entorno tipo Unix (MSYS2, Cygwin, git-bash).
Zen C puede compilarse como un Ejecutable Realmente Portable (APE) usando Cosmopolitan Libc. Esto produce un único binario (.com) que se ejecuta de forma nativa en Linux, macOS, Windows, FreeBSD, OpenBSD y NetBSD en arquitecturas x86_64 y aarch64.
Prerrequisitos:
- Toolchain
cosmocc(debe estar en tu PATH)
Construcción e Instalación:
make ape
sudo env "PATH=$PATH" make install-apeArtefactos:
out/bin/zc.com: El compilador Zen-C portable. Incluye la biblioteca estándar embebida dentro del ejecutable.out/bin/zc-boot.com: Un instalador bootstrap autónomo para configurar nuevos proyectos Zen-C.
Uso:
# Ejecutar en cualquier SO compatible
./out/bin/zc.com build hello.zc -o hello# Compilar y ejecutar
zc run hello.zc
# Construir ejecutable
zc build hello.zc -o hello
# Shell Interactiva
zc repl
# Mostrar Zen Facts
zc build hello.zc --zenPuedes configurar ZC_ROOT para especificar la ubicación de la Biblioteca Estándar (importaciones estándar como import "std/vector.zc"). Esto te permite ejecutar zc desde cualquier directorio.
export ZC_ROOT=/ruta/a/Zen-CZen C distingue entre constantes en tiempo de compilación y variables en tiempo de ejecución.
Valores que existen solo en tiempo de compilación (se pliegan en el código). Úsalos para tamaños de arrays, configuración fija y números mágicos.
def MAX_SIZE = 1024;
let buffer: char[MAX_SIZE]; // Tamaño de array válido
Ubicaciones de almacenamiento en memoria. Pueden ser mutables o de solo lectura (const).
let x = 10; // Mutable
x = 20; // OK
let y: const int = 10; // Solo lectura (Calificado por tipo)
// y = 20; // Error: no se puede asignar a una constante
Tip
Inferencia de tipos: Zen C infiere automáticamente los tipos para variables inicializadas. Se compila a auto de C23 en compiladores compatibles, o a la extensión __auto_type de GCC en otros casos.
| Tipo | Equivalente en C | Descripción |
|---|---|---|
int, uint |
int32_t, uint32_t |
Entero de 32 bits con signo/sin signo |
c_char, c_uchar |
char, unsigned char |
C char (Interoperabilidad) |
c_short, c_ushort |
short, unsigned short |
C short (Interoperabilidad) |
c_int, c_uint |
int, unsigned int |
C int (Interoperabilidad) |
c_long, c_ulong |
long, unsigned long |
C long (Interoperabilidad) |
c_long_long, c_ulong_long |
long long, unsigned long long |
C long long / unsigned long long (Interoperabilidad) |
I8 .. I128 o i8 .. i128 |
int8_t .. __int128_t |
Enteros con signo de ancho fijo |
U8 .. U128 o u8 .. u128 |
uint8_t .. __uint128_t |
Enteros sin signo de ancho fijo |
isize, usize |
ptrdiff_t, size_t |
Enteros del tamaño de un puntero |
byte |
uint8_t |
Alias para U8 |
F32, F64 o f32, f64 |
float, double |
Números de coma flotante |
bool |
bool |
true o false |
char |
char |
Carácter único |
string |
char* |
Cadena de C (terminada en null) |
U0, u0, void |
void |
Tipo vacío |
iN (ej. i256) |
_BitInt(N) |
Entero con signo de ancho arbitrario (C23) |
uN (ej. u42) |
unsigned _BitInt(N) |
Entero sin signo de ancho arbitrario (C23) |
- Enteros: Decimal (
123), Hex (0xFF), Octal (0o755), Binario (0b1011).- Nota: Los números con ceros a la izquierda se tratan como decimales (
0123es123), a diferencia de C. - Nota: Los números pueden contener guiones bajos para mejorar la legibilidad (
1_000_000,0b_1111_0000).
- Nota: Los números con ceros a la izquierda se tratan como decimales (
- Flotantes: Estándar (
3.14), Científico (1e-5,1.2E3). Los números de punto flotante también soportan guiones bajos (3_14.15_92).
Important
Mejores Prácticas para Código Portable
- Usa Tipos Portables (
int,uint,i64,u8, etc.) para toda la lógica pura de Zen C.intgarantiza ser 32-bits con signo en todas las arquitecturas. - Usa Tipos de Interoperabilidad C (
c_int,c_char,c_long,c_ulong,c_long_long,c_ulong_long) sólo al interactuar con bibliotecas C (FFI). Su tamaño varía según la plataforma y el compilador C. - Usa
isizeyusizepara indexado de arrays y aritmética de punteros.
Arrays de tamaño fijo con semántica de valor.
def SIZE = 5;
let ints: int[SIZE] = [1, 2, 3, 4, 5];
let zeros: [int; SIZE]; // Inicializado a cero
Agrupa múltiples valores, accede a los elementos por índice.
let pair = (1, "Hola");
let x = pair.0; // 1
let s = pair.1; // "Hola"
Múltiples Valores de Retorno
Las funciones pueden retornar tuplas para proporcionar múltiples resultados:
fn sumar_y_restar(a: int, b: int) -> (int, int) {
return (a + b, a - b);
}
let resultado = sumar_y_restar(3, 2);
let suma = resultado.0; // 5
let resta = resultado.1; // 1
Desestructuración
Las tuplas pueden desestructurarse directamente en variables:
let (suma, resta) = sumar_y_restar(3, 2);
// suma = 5, resta = 1
La desestructuración tipada permite anotaciones de tipo explícitas:
let (a: string, b: u8) = ("hello", 42);
let (x, y: i32) = (1, 2); // Mixto: x inferido, y explícito
Estructuras de datos con campos de bits opcionales.
struct Point {
x: int;
y: int;
}
// Inicialización de struct
let p = Point { x: 10, y: 20 };
// Campos de bits
struct Flags {
valid: U8 : 1;
mode: U8 : 3;
}
Note
Los structs usan Semántica de Movimiento por defecto. Los campos se pueden acceder mediante . incluso en punteros (Auto-Dereferencia).
Puedes definir un struct como opaque para restringir el acceso a sus campos solo al módulo que lo define, permitiendo aún que el struct sea asignado en el stack (el tamaño es conocido).
// En user.zc
opaque struct User {
id: int;
name: string;
}
fn new_user(name: string) -> User {
return User{id: 1, name: name}; // OK: Dentro del módulo
}
// En main.zc
import "user.zc";
fn main() {
let u = new_user("Alice");
// let id = u.id; // Error: No se puede acceder al campo privado 'id'
}
Uniones etiquetadas (Tipos suma) capaces de contener datos.
enum Shape {
Circle(float), // Contiene el radio
Rect(float, float), // Contiene ancho y alto
Point // Sin datos
}
Uniones estándar de C (acceso inseguro).
union Data {
i: int;
f: float;
}
Tipos de vectores SIMD nativos utilizando extensiones de vectores de GCC/Clang. Anota un struct con @vector(N) para definir un vector de N elementos.
import "std/simd.zc";
fn main() {
let a = f32x4{v: 1.0}; // Difusión: {1.0, 1.0, 1.0, 1.0}
let b = f32x4{1.0, 2.0, 3.0, 4.0}; // Inicialización por elemento
let c = a + b; // Suma por elementos
let x = c[0]; // Acceso a elementos (float)
}
Los operadores aritméticos (+, -, *, /) y bit a bit (&, |, ^) funcionan por elementos. Consulta std/simd.zc para los tipos predefinidos.
Crea un nuevo nombre para un tipo existente.
alias ID = int;
alias PointMap = Map<string, Point>
alias OpFunc = fn(int, int) -> int
Nota: El punto y coma final es opcional para los alias de tipo.
Puedes definir un alias de tipo como opaque para crear un nuevo tipo que sea distinto de su tipo subyacente fuera del módulo que lo define. Esto proporciona una fuerte encapsulación y seguridad de tipos sin la sobrecarga en tiempo de ejecución de un struct envoltorio.
// En library.zc
opaque alias Handle = int;
fn make_handle(v: int) -> Handle {
return v; // Conversión implícita permitida dentro del módulo
}
// En main.zc
import "library.zc";
fn main() {
let h: Handle = make_handle(42);
// let i: int = h; // Error: Falló la validación de tipos
// let h2: Handle = 10; // Error: Falló la validación de tipos
}
fn suma(a: int, b: int) -> int {
return a + b;
}
// Argumentos con nombre soportados en las llamadas
suma(a: 10, b: 20);
Note
Los argumentos con nombre deben seguir estrictamente el orden de los parámetros definidos. suma(b: 20, a: 10) es inválido.
Los argumentos de las funciones pueden marcarse como const para imponer una semántica de solo lectura. Este es un calificador de tipo, no una constante manifiesta.
fn print_val(v: const int) {
// v = 10; // Error: No se puede asignar a una variable const
println "{v}";
}
Las funciones pueden definir valores por defecto para los argumentos finales. Estos pueden ser literales, expresiones o código válido de Zen C (como constructores de structs).
// Valor por defecto simple
fn incrementar(val: int, cantidad: int = 1) -> int {
return val + cantidad;
}
// Valor por defecto por expresión (evaluado en el sitio de la llamada)
fn offset(val: int, pad: int = 10 * 2) -> int {
return val + pad;
}
// Valor por defecto de tipo struct
struct Config { debug: bool; }
fn init(cfg: Config = Config { debug: true }) {
if cfg.debug { println "Modo Debug"; }
}
fn main() {
incrementar(10); // 11
offset(5); // 25
init(); // Imprime "Modo Debug"
}
Funciones anónimas que pueden capturar su entorno.
let factor = 2;
let doble = x -> x * factor; // Sintaxis de flecha
let completo = fn(x: int) -> int { return x * factor; }; // Sintaxis de bloque
// Captura por Referencia (Sintaxis de Bloque)
let val = 10;
let modificar = fn[&]() { val += 1; };
modificar(); // val ahora es 11
// Captura por Referencia (Sintaxis de Flecha)
let modificar_flecha = [&] x -> val += x;
modificar_flecha(5); // val ahora es 16
// Captura por Referencia (Sintaxis de Flecha con Múltiples Argumentos)
let sumar_en = [&] (a, b) -> val += (a + b);
sumar_en(2, 2); // val ahora es 20
// Captura por Valor (Por Defecto)
let original = 100;
let implicita = x -> original + x; // Captura implícita por valor (sin corchetes)
let explicita = [=] x -> original + x; // Captura explícita por valor
// let fallar = x -> original += x; // Error: no se puede asignar a valor capturado
Zen C soporta punteros a funciones de C crudos usando la sintaxis fn*. Esto permite una interoperabilidad perfecta con bibliotecas de C que esperan punteros a funciones sin la sobrecarga de las clausuras.
// Función que recibe un puntero a función crudo
fn set_callback(cb: fn*(int)) {
cb(42);
}
// Función que retorna un puntero a función crudo
fn get_callback() -> fn*(int) {
return mi_manejador;
}
// Se soportan punteros a punteros de funciones (fn**)
let pptr: fn**(int) = &ptr;
Las funciones pueden aceptar un número variable de argumentos usando ... y el tipo va_list.
fn log(lvl: int, fmt: char*, ...) {
let ap: va_list;
va_start(ap, fmt);
vprintf(fmt, ap); // Usa stdio de C
va_end(ap);
}
if x > 10 {
print("Grande");
} else if x > 5 {
print("Mediano");
} else {
print("Pequeño");
}
// Ternario
let y = x > 10 ? 1 : 0;
// If-Expression (para condiciones complejas)
let categoria = if (x > 100) { "enorme" } else if (x > 10) { "grande" } else { "pequeño" };
Una alternativa potente al switch.
match val {
1 => { print "Uno" },
2 || 3 => { print "Dos o Tres" }, // OR con ||
4 or 5 => { print "Cuatro o Cinco" }, // OR con 'or'
6, 7, 8 => { print "Seis a Ocho" }, // OR con coma
10 .. 15 => { print "10 a 14" }, // Rango exclusivo (Legado)
10 ..< 15 => { print "10 a 14" }, // Rango exclusivo (Explícito)
20 ..= 25 => { print "20 a 25" }, // Rango inclusivo
_ => { print "Otro" },
}
// Desestructuración de Enums
match shape {
Shape::Circle(r) => { println "Radio: {r}" },
Shape::Rect(w, h) => { println "Área: {w*h}" },
Shape::Point => { println "Punto" },
}
Para inspeccionar un valor sin tomar posesión de él (sin moverlo), usa la palabra clave ref en el patrón. Esto es esencial para tipos que implementan la Semántica de Movimiento (como Option, Result, structs que no son Copy).
let opt = Some(ValorNoCopy{...});
match opt {
Some(ref x) => {
// 'x' es un puntero al valor dentro de 'opt'
// 'opt' NO se mueve ni se consume aquí
println "{x.field}";
},
None => {}
}
// Rango
for i in 0..10 { ... } // Exclusivo (0 al 9)
for i in 0..<10 { ... } // Exclusivo (Explícito)
for i in 0..=10 { ... } // Inclusivo (0 al 10)
for i in 0..10 step 2 { ... }
for i in 10..0 step -1 { ... } // Descending loop
// Iterador (Vec o Iterable personalizado)
for item in vec { ... }
// Enumerado: obtener índice y valor
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, ...
// Iterar sobre arrays de tamaño fijo directamente
let arr: int[5] = [1, 2, 3, 4, 5];
for val in arr {
// val es int
println "{val}";
}
// While
while x < 10 { ... }
// Infinito con etiqueta
externo: loop {
if terminado { break externo; }
}
// Repetir N veces
for _ in 0..5 { ... }
// Guard: Ejecuta else y retorna si la condición es falsa
guard ptr != NULL else { return; }
// Unless: Si no es verdadero
unless es_valido { return; }
Zen C soporta la sobrecarga de operadores para structs definidos por el usuario implementando nombres de métodos específicos.
| Categoría | Operador | Nombre del Método |
|---|---|---|
| Aritméticos | +, -, *, /, %, ** |
add, sub, mul, div, rem, pow |
| Comparación | ==, != |
eq, neq |
<, >, <=, >= |
lt, gt, le, ge |
|
| Bitwise | &, ` |
, ^` |
<<, >> |
shl, shr |
|
| Unarios | - |
neg |
! |
not |
|
~ |
bitnot |
|
| Índice | a[i] |
get(a, i) |
a[i, j] |
get(a, i, j) |
|
a[i] = v |
set(a, i, v) |
Nota sobre la igualdad de cadenas:
string == stringrealiza una comparación de valores (equivalente astrcmp).char* == char*realiza una comparación de punteros (comprueba direcciones de memoria).- Comparaciones mixtas (ej.
string == char*) por defecto realizan una comparación de punteros.
Ejemplo:
impl Point {
fn add(self, other: Point) -> Point {
return Point{x: self.x + other.x, y: self.y + other.y};
}
}
let p3 = p1 + p2; // Llama a p1.add(p2)
Ejemplo Multi-Índice:
struct Matriz {
data: int[9];
}
impl Matriz {
fn get(self, fila: int, col: int) -> int {
return self.data[fila * 3 + col];
}
}
let m = Matriz{data: [1,0,0, 0,1,0, 0,0,1]};
let val = m[1, 2]; // Llama a Matriz.get(m, 1, 2)
Estos operadores son características integradas del lenguaje y no pueden sobrecargarse directamente.
| Operador | Nombre | Descripción |
|---|---|---|
| ` | >` | Pipeline |
?? |
Null Coalescing | val ?? default retorna default si val es NULL (punteros) |
??= |
Null Assignment | val ??= init asigna si val es NULL |
?. |
Navegación Segura | ptr?.campo accede al campo solo si ptr no es NULL |
? |
Operador Try | res? retorna el error si está presente (tipos Result/Option) |
Auto-Dereferencia:
El acceso a campos por puntero (ptr.campo) y las llamadas a métodos (ptr.metodo()) dereferencian automáticamente el puntero, equivalente a (*ptr).campo.
Zen C proporciona opciones versátiles para imprimir en la consola, incluyendo palabras clave y abreviaturas concisas.
| Palabra Clave | Descripción |
|---|---|
print "texto" |
Imprime en stdout sin un salto de línea al final. |
println "texto" |
Imprime en stdout con un salto de línea al final. |
eprint "texto" |
Imprime en stderr sin un salto de línea al final. |
eprintln "texto" |
Imprime en stderr con un salto de línea al final. |
Zen C permite usar literales de cadena directamente como sentencias para una impresión rápida:
| Sintaxis | Equivalente | Descripción |
|---|---|---|
"Hz" |
println "Hz" |
Imprime en stdout con salto de línea. |
"Hz".. |
print "Hz" |
Imprime en stdout sin salto de línea. |
!"Err" |
eprintln "Err" |
Imprime en stderr con salto de línea. |
!"Err".. |
eprint "Err" |
Imprime en stderr sin salto de línea. |
Puedes embeber expresiones directamente dentro de literales de cadena usando la sintaxis {}. Esto funciona con todos los métodos de impresión y abreviaturas de cadena.
La interpolación de cadenas en Zen C es implícita: si tu cadena contiene {...}, se analizará automáticamente como una cadena interpolada. También puedes usar explícitamente el prefijo f (ej. f"...") para forzar la semántica de interpolación.
let x = 42;
let nombre = "Zen";
println "Valor: {x}, Nombre: {nombre}";
"Valor: {x}, Nombre: {nombre}"; // abreviatura println
Escapando Llaves: Usa {{ para producir una llave literal { y }} para una } literal:
let json = "JSON: {{\"clave\": \"valor\"}}";
// Salida: JSON: {"clave": "valor"}
Cadenas Crudas (Raw Strings): Para definir una cadena donde la interpolación y las secuencias de escape se ignoran por completo, usa el prefijo r (ej. r"..."):
let regex = r"\w+"; // Contiene exactamente \ w +
let raw_json = r'{"clave": "valor"}'; // No es necesario escapar llaves
Zen C soporta bloques de cadenas multilínea crudas usando el delimitador """. Esto es extremadamente útil para escribir lenguajes embebidos (GLSL, HTML) o para generar código C en bloques comptime sin tener que escapar manualmente los saltos de línea y las comillas internas.
Al igual que las cadenas estándar, las cadenas multilínea soportan interpolación implícita. También puedes prefijarlas explícitamente:
f"""...""": Marca explícitamente como un bloque de cadena interpolada.r"""...""": Marca explícitamente como un bloque de cadena cruda (sin interpolación, sin secuencias de escape).
let prompt = """
Por favor, introduzca su nombre:
Escribe "exit" para cancelar.
""";
let mundo = "mundo";
let script = """
fn hola() {
println "hola, {mundo}!";
}
""";
let pure_raw = r"""
Aquí las {llaves} son solo texto, y \n es literalmente una barra y una n.
""";
Zen C soporta una abreviatura para solicitar entrada al usuario usando el prefijo ?.
? "Texto del prompt": Imprime el prompt (sin salto de línea) y espera la entrada (lee una línea).? "Ingresa la edad: " (edad): Imprime el prompt y escanea la entrada en la variableedad.- Los especificadores de formato se infieren automáticamente según el tipo de variable.
let edad: int;
? "¿Cuántos años tienes? " (edad);
println "Tienes {edad} años.";
Zen C permite la gestión manual de memoria con ayudas ergonómicas.
Ejecuta código cuando el ámbito actual finaliza. Las sentencias defer se ejecutan en orden LIFO (último en entrar, primero en salir).
let f = fopen("archivo.txt", "r");
defer fclose(f);
Para prevenir comportamientos indefinidos, las sentencias de flujo de control (
return,break,continue,goto) no están permitidas dentro de un bloquedefer.
Libera automáticamente la variable cuando finaliza el ámbito.
autofree let tipos = malloc(1024);
Zen C trata los tipos con destructores (como File, Vec o punteros de malloc) como Recursos. Para prevenir errores de doble liberación (double-free), los recursos no pueden duplicarse implícitamente.
- Movimiento por Defecto: La asignación de una variable de recurso transfiere la posesión. La variable original se vuelve inválida (Movida).
- Tipos Copy: Los tipos sin destructores pueden optar por el comportamiento
Copy, haciendo que la asignación sea una duplicación.
Diagnóstico y Filosofía: Si ves un error "Use of moved value", el compilador te está diciendo: "Este tipo posee un recurso (como memoria o un manejador) y copiarlo a ciegas es inseguro."
Contraste: A diferencia de C/C++, Zen C no duplica implícitamente los valores que poseen recursos.
Argumentos de Función: Pasar un valor a una función sigue las mismas reglas que la asignación: los recursos se mueven a menos que se pasen por referencia.
fn procesar(r: Recurso) { ... } // 'r' se mueve dentro de la función
fn mirar(r: Recurso*) { ... } // 'r' es prestado (referencia)
Clonación Explícita: Si realmente quieres dos copias de un recurso, hazlo explícito:
let b = a.clone(); // Llama al método 'clone' del trait Clone
Optar por Copy (Tipos de Valor): Para tipos pequeños sin destructores:
struct Point { x: int; y: int; }
impl Copy for Point {} // Optar por la duplicación implícita
fn main() {
let p1 = Point { x: 1, y: 2 };
let p2 = p1; // Copiado. p1 sigue siendo válido.
}
Implementa Drop para ejecutar lógica de limpieza automáticamente.
impl Drop for MiEstructura {
fn drop(self) {
self.free();
}
}
Define métodos en los tipos usando impl.
impl Point {
// Método estático (convención de constructor)
fn new(x: int, y: int) -> Self {
return Point{x: x, y: y};
}
// Método de instancia
fn dist(self) -> float {
return sqrt(self.x * self.x + self.y * self.y);
}
}
Atajo de Self: En métodos con un parámetro self, puedes usar .campo como abreviatura de self.campo:
impl Point {
fn dist(self) -> float {
return sqrt(.x * .x + .y * .y); // Equivalente a self.x, self.y
}
}
Zen C permite definir métodos en tipos primitivos (como int, bool, etc.) usando la misma sintaxis 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)
Define un comportamiento compartido.
struct Circle { radio: f32; }
trait Dibujable {
fn dibujar(self);
}
impl Dibujable for Circle {
fn dibujar(self) { ... }
}
let circulo = Circle{};
let dibujable: Dibujable = &circulo;
Zen C incluye traits estándar que se integran con la sintaxis del lenguaje.
Iterable
Implementa Iterable<T> para habilitar bucles for-in para tus tipos personalizados.
import "std/iter.zc"
// Define un Iterador
struct MiIter {
actual: int;
final: int;
}
impl MiIter {
fn next(self) -> Option<int> {
if self.actual < self.final {
self.actual += 1;
return Option<int>::Some(self.actual - 1);
}
return Option<int>::None();
}
}
// Implementa Iterable
impl MiRango {
fn iterator(self) -> MiIter {
return MiIter{actual: self.inicio, final: self.fin};
}
}
// Uso en un Bucle
for i in mi_rango {
println "{i}";
}
Drop
Implementa Drop para definir un destructor que se ejecuta cuando el objeto sale de ámbito (RAII).
import "std/mem.zc"
struct Recurso {
ptr: void*;
}
impl Drop for Recurso {
fn drop(self) {
if self.ptr != NULL {
free(self.ptr);
}
}
}
Note
Si una variable es movida, no se llama a drop en la variable original. Se adhiere a la Semántica de Recursos.
Copy
Trait marcador para optar por el comportamiento Copy (duplicación implícita) en lugar de la semántica de movimiento. Se usa mediante @derive(Copy).
Caution
Regla: Los tipos que implementan Copy no deben definir un destructor (Drop).
@derive(Copy)
struct Point { x: int; y: int; }
fn main() {
let p1 = Point{x: 1, y: 2};
let p2 = p1; // ¡Copiado! p1 sigue siendo válido.
}
Clone
Implementa Clone para permitir la duplicación explícita de tipos que poseen recursos.
import "std/mem.zc"
struct MiBox { val: int; }
impl Clone for MiBox {
fn clone(self) -> MiBox {
return MiBox{val: self.val};
}
}
fn main() {
let b1 = MiBox{val: 42};
let b2 = b1.clone(); // Copia explícita
}
Usa use para embeber otros structs. Puedes mezclarlos (aplanar campos) o nombrarlos (anidar campos).
struct Entity { id: int; }
struct Player {
// Mezcla (Mixin - Sin nombre): Aplana los campos
use Entity; // Añade 'id' a Player directamente
nombre: string;
}
struct Match {
// Composición (Con nombre): Anida los campos
use p1: Player; // Accedido mediante match.p1
use p2: Player; // Accedido mediante match.p2
}
Plantillas seguras para tipos para Structs y Funciones.
// Struct Genérico
struct Box<T> {
item: T;
}
// Función Genérica
fn identidad<T>(val: T) -> T {
return val;
}
// Genéricos con múltiples parámetros
struct Par<K, V> {
llave: K;
valor: V;
}
Construido sobre pthreads.
async fn obtener_datos() -> string {
// Se ejecuta en segundo plano
return "Datos";
}
fn main() {
let futuro = obtener_datos();
let resultado = await futuro;
}
Ejecuta código en tiempo de compilación para generar código fuente o imprimir mensajes.
comptime {
// Genera código en tiempo de compilación (escrito en stdout)
println "let fecha_compilacion = \"2024-01-01\";";
}
println "Fecha de compilación: {fecha_compilacion}";
Funciones Auxiliares
Funciones especiales disponibles dentro de bloques comptime:
| Función | Descripción |
|---|---|
yield(str) |
Emite código generado explícitamente (alternativa a printf) |
code(str) |
Alias de yield() - intención más clara para generación de código |
compile_error(msg) |
Detiene la compilación con un mensaje de error fatal |
compile_warn(msg) |
Emite una advertencia en tiempo de compilación (permite continuar) |
Ejemplo:
comptime {
compile_warn("Generando código optimizado...");
let ENABLE_FEATURE = 1;
if (ENABLE_FEATURE == 0) {
compile_error("¡La función debe estar habilitada!");
}
// Usa code() con raw strings para generación limpia
code(r"let FEATURE_ENABLED = 1;");
}
Metadatos de Construcción
Accede a información de construcción del compilador en tiempo de compilación:
| Constante | Tipo | Descripción |
|---|---|---|
__COMPTIME_TARGET__ |
string | Plataforma: "linux", "windows" o "macos" |
__COMPTIME_FILE__ |
string | Nombre del archivo fuente actual siendo compilado |
Ejemplo:
comptime {
// Generación de código específica de plataforma
println "let PLATFORM = \"{__COMPTIME_TARGET__}\";";
}
println "Ejecutando en: {PLATFORM}";
Tip
Usa raw strings (r"...") en comptime para evitar escapar llaves: code(r"fn test() { return 42; }"). De lo contrario, usa {{ y }} para escapar llaves en strings regulares.
Embebe archivos como los tipos especificados.
// Por defecto (Slice_char)
let datos = embed "assets/logo.png";
// Embed tipado
let texto = embed "shader.glsl" as string; // Embebe como C-string
let rom = embed "bios.bin" as u8[1024]; // Embebe como array fijo
let wav = embed "sound.wav" as u8[]; // Embebe como Slice_u8
Importa plugins del compilador para extender la sintaxis.
import plugin "regex"
let re = regex! { ^[a-z]+$ };
Pasa macros del preprocesador directamente a C.
Tip
Para constantes simples, usa def en su lugar. Usa #define cuando necesites macros del preprocesador de C o flags de compilación condicional.
#define MAX_BUFFER 1024
Usa @cfg() para incluir o excluir condicionalmente cualquier declaración de nivel superior basándote en flags -D.
// Compilar 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 "No se seleccionó backend"; }
| Forma | Significado |
|---|---|
@cfg(NAME) |
Incluir si -DNAME está definido |
@cfg(not(NAME)) |
Incluir si -DNAME NO está definido |
@cfg(any(A, B, ...)) |
Incluir si ALGUNA condición es verdadera (OR) |
@cfg(all(A, B, ...)) |
Incluir si TODAS las condiciones son verdaderas (AND) |
Múltiples @cfg en una declaración se combinan con AND. not() se puede usar dentro de any() y all(). Funciona con cualquier declaración de nivel superior: fn, struct, import, impl, raw, def, test, etc.
Decora funciones y structs para modificar el comportamiento del compilador.
| Atributo | Ámbito | Descripción |
|---|---|---|
@must_use |
Fn | Advierte si el valor de retorno es ignorado. |
@deprecated("msg") |
Fn/Struct | Advierte sobre el uso con un mensaje. |
@inline |
Fn | Sugiere al compilador hacer inlininig. |
@noinline |
Fn | Previene el inlining. |
@packed |
Struct | Elimina el padding entre campos. |
@align(N) |
Struct | Fuerza el alineamiento a N bytes. |
@constructor |
Fn | Se ejecuta antes de main. |
@destructor |
Fn | Se ejecuta después de que main termine. |
@unused |
Fn/Var | Suprime advertencias de variables no usadas. |
@weak |
Fn | Enlace de símbolo débil (weak symbol linkage). |
@section("nombre") |
Fn | Coloca el código en una sección específica. |
@noreturn |
Fn | La función no retorna (ej. exit). |
@pure |
Fn | La función no tiene efectos secundarios (sugestión de optimización). |
@cold |
Fn | Es poco probable que la función se ejecute (sugestión de predicción de saltos). |
@hot |
Fn | La función se ejecuta frecuentemente (sugestión de optimización). |
@export |
Fn/Struct | Exporta el símbolo (visibilidad por defecto). |
@global |
Fn | CUDA: Punto de entrada del kernel (__global__). |
@device |
Fn | CUDA: Función de dispositivo (__device__). |
@host |
Fn | CUDA: Función de host (__host__). |
@comptime |
Fn | Función auxiliar disponible para ejecución en tiempo de compilación. |
@cfg(NAME) |
Cualquiera | Compilación condicional: incluye solo si se pasa -DNAME. Soporta not(), any(), all(). |
@derive(...) |
Struct | Implementa traits automáticamente. Soporta Debug, Eq (Derivación Inteligente), Copy, Clone. |
@ctype("tipo") |
Parámetro Fn | Sobrescribe el tipo C generado para un parámetro. |
@<custom> |
Cualquier | Pasa atributos genéricos a C (ej. @flatten, @alias("nombre")). |
Zen C soporta un potente sistema de Atributos Personalizados que te permite usar cualquier __attribute__ de GCC/Clang directamente en tu código. Cualquier atributo que no sea reconocido explícitamente por el compilador de Zen C es tratado como un atributo genérico y se pasa al código C generado.
Esto proporciona acceso a características avanzadas del compilador, optimizaciones y directivas del enlazador sin necesidad de soporte explícito en el núcleo del lenguaje.
Los atributos de Zen C se mapean directamente a atributos de C:
@nombre→__attribute__((nombre))@nombre(args)→__attribute__((nombre(args)))@nombre("string")→__attribute__((nombre("string")))
Zen C proporciona "Derivaciones Inteligentes" que respetan la Semántica de Movimiento:
@derive(Eq): Genera un método de igualdad que recibe los argumentos por referencia (fn eq(self, other: T*)).- Al comparar dos structs que no son Copy (
a == b), el compilador pasa automáticamentebpor referencia (&b) para evitar moverlo. - Las comprobaciones de igualdad recursivas en los campos también prefieren el acceso por puntero para prevenir la transferencia de posesión.
- Al comparar dos structs que no son Copy (
Zen C proporciona soporte de primera clase para ensamblador inline, transpilando directamente a asm extendido de estilo GCC.
Escribe ensamblador crudo dentro de bloques asm. Las cadenas se concatenan automáticamente.
asm {
"nop"
"mfence"
}
Previene que el compilador optimice y elimine el ensamblador que tiene efectos secundarios.
asm volatile {
"rdtsc"
}
Zen C simplifica la compleja sintaxis de restricciones de GCC con vinculaciones con nombre.
// Sintaxis: : out(variable) : in(variable) : clobber(reg)
// Usa la sintaxis de marcador de posición {variable} para legibilidad
fn sumar(x: int) -> int {
let resultado: int;
asm {
"mov {x}, {resultado}"
"add $5, {resultado}"
: out(resultado)
: in(x)
: clobber("cc")
}
return resultado;
}
| Tipo | Sintaxis | Equivalente GCC |
|---|---|---|
| Salida | : out(variable) |
"=r"(variable) |
| Entrada | : in(variable) |
"r"(variable) |
| Clobber | : clobber("rax") |
"rax" |
| Memoria | : clobber("memory") |
"memory" |
Nota: Cuando uses la sintaxis de Intel (mediante
-masm=intel), debes asegurarte de que tu construcción esté configurada correctamente (por ejemplo,//> cflags: -masm=intel). TCC no soporta el ensamblador con sintaxis Intel.
Zen C soporta comentarios especiales en la parte superior de tu archivo fuente para configurar el proceso de construcción sin necesidad de un complejo sistema de construcción o Makefile.
| Directiva | Argumentos | Descripción |
|---|---|---|
//> link: |
-lfoo o ruta/a/lib.a |
Enlaza contra una biblioteca o archivo objeto. |
//> lib: |
ruta/a/libs |
Añade una ruta de búsqueda de biblioteca (-L). |
//> include: |
ruta/a/headers |
Añade una ruta de búsqueda de cabeceras (-I). |
//> framework: |
Cocoa |
Enlaza contra un framework de macOS. |
//> cflags: |
-Wall -O3 |
Pasa flags arbitrarios al compilador de C. |
//> define: |
MACRO o LLAVE=VAL |
Define una macro del preprocesador (-D). |
//> pkg-config: |
gtk+-3.0 |
Ejecuta pkg-config y añade --cflags y --libs. |
//> shell: |
comando |
Ejecuta un comando de shell durante la construcción. |
//> get: |
http://url/archivo |
Descarga un archivo si el archivo específico no existe. |
1. Protección de SO (OS Guarding)
Prefija las directivas con el nombre de un SO para aplicarlas solo en plataformas específicas.
Prefijos soportados: linux:, windows:, macos: (o darwin:).
//> linux: link: -lm
//> windows: link: -lws2_32
//> macos: framework: Cocoa
2. Expansión de Variables de Entorno
Usa la sintaxis ${VAR} para expandir variables de entorno en tus directivas.
//> 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() { ... }
Las siguientes palabras clave están reservadas en 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
Los siguientes identificadores están reservados porque son palabras clave en 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
Zen C ofrece dos formas de interactuar con código C: Importaciones de Confianza (Conveniente) y FFI Explícita (Seguro/Preciso).
Puedes importar una cabecera C directamente usando la palabra clave import con la extensión .h. Esto trata la cabecera como un módulo y asume que todos los símbolos accedidos existen.
//> link: -lm
import "math.h" as c_math;
fn main() {
// El compilador confía en la corrección; emite 'cos(...)' directamente
let x = c_math::cos(3.14159);
}
Pros: Cero código repetitivo. Acceso a todo el contenido de la cabecera inmediato. Cons: Sin seguridad de tipos desde Zen C (errores capturados por el compilador C después).
Para una comprobación estricta de tipos o cuando no quieres incluir el texto de una cabecera, usa extern fn.
include <stdio.h> // Emite #include <stdio.h> en el C generado
// Define firma estricta
extern fn printf(fmt: char*, ...) -> c_int;
fn main() {
printf("Hola FFI: %d\n", 42); // Comprobado por tipos por Zen C
}
Pros: Zen C asegura que los tipos coincidan. Cons: Requiere declaración manual de funciones.
import "file.h": Registra la cabecera como un módulo con nombre. Habilita el acceso implícito a símbolos (ej.file::function()).include <file.h>: Puramente emite#include <file.h>en el código C generado. No introduce ningún símbolo al compilador de Zen C; debes usarextern fnpara acceder a ellos.
Zen C incluye una biblioteca estándar (std) que cubre las funcionalidades esenciales.
Explorar la Documentación de la Biblioteca Estándar
Click para ver todos los módulos de la Biblioteca Estándar
| Módulo | Descripción | Docs |
|---|---|---|
std/bigfloat.zc |
Aritmética de punto flotante de precisión arbitraria. | Docs |
std/bigint.zc |
Entero de precisión arbitraria BigInt. |
Docs |
std/bits.zc |
Operaciones bit a bit de bajo nivel (rotl, rotr, etc). |
Docs |
std/complex.zc |
Aritmética de números complejos Complex. |
Docs |
std/vec.zc |
Array dinámico creíble Vec<T>. |
Docs |
std/string.zc |
Tipo String asignado en el heap con soporte UTF-8. |
Docs |
std/queue.zc |
Cola FIFO (Ring Buffer). | Docs |
std/map.zc |
Mapa Hash Genérico Map<V>. |
Docs |
std/fs.zc |
Operaciones del sistema de archivos. | Docs |
std/io.zc |
Entrada/Salida estándar (print/println). |
Docs |
std/option.zc |
Valores opcionales (Some/None). |
Docs |
std/result.zc |
Gestión de errores (Ok/Err). |
Docs |
std/path.zc |
Manipulación de rutas multiplataforma. | Docs |
std/env.zc |
Variables de entorno del proceso. | Docs |
std/net/ |
TCP, UDP, HTTP, DNS, URL. | Docs |
std/thread.zc |
Hilos y Sincronización. | Docs |
std/time.zc |
Medición de tiempo y espera (sleep). | Docs |
std/json.zc |
Parseo y serialización de JSON. | Docs |
std/stack.zc |
Pila LIFO Stack<T>. |
Docs |
std/set.zc |
Conjunto Hash Genérico Set<T>. |
Docs |
std/process.zc |
Ejecución y gestión de procesos. | Docs |
std/regex.zc |
Expresiones Regulares (basado en TRE). | Docs |
std/simd.zc |
Tipos de vectores SIMD nativos. | Docs |
Zen C proporciona un Servidor de Lenguaje y un REPL integrados para mejorar la experiencia de desarrollo.
El Servidor de Lenguaje de Zen C (LSP) soporta las características estándar de LSP para integración con editores, proporcionando:
- Ir a la Definición
- Encontrar Referencias
- Información al pasar el ratón (Hover)
- Autocompletado (Nombres de funciones/structs, autocompletado tras punto para métodos/campos)
- Símbolos del Documento (Esquema)
- Ayuda de Firma
- Diagnósticos (Errores sintácticos/semánticos)
Para iniciar el servidor de lenguaje (normalmente configurado en los ajustes de LSP de tu editor):
zc lspSe comunica mediante I/O estándar (JSON-RPC 2.0).
El bucle Read-Eval-Print te permite experimentar con el código de Zen C de forma interactiva.
zc repl- Codificación Interactiva: Escribe expresiones o sentencias para su evaluación inmediata.
- Historial Persistente: Los comandos se guardan en
~/.zprep_history. - Script de Inicio: Carga automáticamente comandos desde
~/.zprep_init.zc.
| Comando | Descripción |
|---|---|
:help |
Muestra los comandos disponibles. |
:reset |
Limpia el historial de la sesión actual (variables/funciones). |
:vars |
Muestra las variables activas. |
:funcs |
Muestra las funciones definidas por el usuario. |
:structs |
Muestra los structs definidos por el usuario. |
:imports |
Muestra las importaciones activas. |
:history |
Muestra el historial de entrada de la sesión. |
:type <expr> |
Muestra el tipo de una expresión. |
:c <stmt> |
Muestra el código C generado para una sentencia. |
:time <expr> |
Benchmark de una expresión (ejecuta 1000 iteraciones). |
:edit [n] |
Edita el comando n (por defecto: el último) en $EDITOR. |
:save <file> |
Guarda la sesión actual en un archivo .zc. |
:load <file> |
Carga y ejecuta un archivo .zc en la sesión. |
:watch <expr> |
Observa una expresión (se revalúa tras cada entrada). |
:unwatch <n> |
Elimina una observación. |
:undo |
Elimina el último comando de la sesión. |
:delete <n> |
Elimina el comando en el índice n. |
:clear |
Limpia la pantalla. |
:quit |
Sale del REPL. |
! <cmd> |
Ejecuta un comando de shell (ej. !ls). |
Zen C incluye un Servidor de Lenguaje integrado para la integración con editores.
- Guía de Instalación y Configuración
- Editores Soportados: VS Code, Neovim, Vim, Zed, y cualquier editor capaz de LSP.
Usa zc lsp para iniciar el servidor.
Los programas de Zen C se pueden depurar utilizando depuradores de C estándar como LLDB o GDB.
Para obtener la mejor experiencia en VS Code, instale la extensión oficial de Zen C. Para la depuración, puede utilizar la extensión C/C++ (de Microsoft) o CodeLLDB.
Agregue estas configuraciones a su directorio .vscode para habilitar la depuración con un solo clic:
tasks.json (Tarea de compilación):
{
"label": "Zen C: Build Debug",
"type": "shell",
"command": "zc",
"args": [ "${file}", "-g", "-o", "${fileDirname}/app", "-O0" ],
"group": { "kind": "build", "isDefault": true }
}launch.json (Depurador):
{
"name": "Zen C: Debug (LLDB)",
"type": "lldb",
"request": "launch",
"program": "${fileDirname}/app",
"preLaunchTask": "Zen C: Build Debug"
}Zen C está diseñado para funcionar con la mayoría de los compiladores C11. Algunas características dependen de extensiones de GNU C, pero estas suelen funcionar en otros compiladores. Usa la flag --cc para cambiar de backend.
zc run app.zc --cc clang
zc run app.zc --cc zigClick para ver detalles de Soporte del Compilador
| Compilador | Tasa de Acierto | Características Soportadas | Limitaciones Conocidas |
|---|---|---|---|
| GCC | 100% (Completo) | Todas las características | Ninguna. |
| Clang | 100% (Completo) | Todas las características | Ninguna. |
| Zig | 100% (Completo) | Todas las características | Ninguna. Usa zig cc como compilador C. |
| TCC | 98% (Alto) | Estructuras, Genéricos, Traits, Coincidencia de Patrones | Sin ASM Intel, Sin __attribute__((constructor)). |
Warning
ADVERTENCIA DE COMPILACIÓN: Aunque Zig CC funciona excelentemente como backend para tus programas Zen C, compilar el propio compilador Zen C con el puede verificar pero producir un binario inestable que falla en las pruebas. Recomendamos compilar el compilador con GCC o Clang y usar Zig solo como backend para tu código operativo.
El comando zig cc de Zig proporciona un reemplazo directo para GCC/Clang con un excelente soporte de compilación cruzada (cross-compilation). Para usar Zig:
# Compilar y ejecutar un programa Zen C con Zig
zc run app.zc --cc zig
# Construir el propio compilador Zen C con Zig
make zigZen C puede generar código compatible con C++ con la flag --cpp, permitiendo una integración perfecta con bibliotecas de C++.
# Compilación directa con g++
zc app.zc --cpp
# O transpilar para construcción manual
zc transpile app.zc --cpp
g++ out.c mi_lib_cpp.o -o appIncluye cabeceras de C++ y usa bloques raw para el código C++:
include <vector>
include <iostream>
raw {
std::vector<int> hacer_vec(int a, int b) {
return {a, b};
}
}
fn main() {
let v = hacer_vec(1, 2);
raw { std::cout << "Tamaño: " << v.size() << std::endl; }
}
Note
La flag --cpp cambia el backend a g++ y emite código compatible con C++ (usa auto en lugar de __auto_type, sobrecarga de funciones en lugar de _Generic, y casts explícitos para void*).
Zen C soporta la programación de GPU transpilando a CUDA C++. Esto te permite aprovechar las potentes características de C++ (plantillas, constexpr) dentro de tus kernels mientras mantienes la sintaxis ergonómica de Zen C.
# Compilación directa con nvcc
zc run app.zc --cuda
# O transpilar para construcción manual
zc transpile app.zc --cuda -o app.cu
nvcc app.cu -o app| Atributo | Equivalente CUDA | Descripción |
|---|---|---|
@global |
__global__ |
Función de kernel (se ejecuta en GPU, se llama desde el host) |
@device |
__device__ |
Función de dispositivo (se ejecuta en GPU, se llama desde GPU) |
@host |
__host__ |
Función de host (explícitamente solo CPU) |
Zen C proporciona una sentencia launch limpia para invocar kernels de CUDA:
launch nombre_del_kernel(args) with {
grid: num_bloques,
block: hilos_por_bloque,
shared_mem: 1024, // Opcional
stream: mi_stream // Opcional
};
Esto se transpila a: nombre_del_kernel<<<grid, bloque, compartido, stream>>>(args);
Usa la sintaxis de funciones de Zen C con @global y la sentencia launch:
import "std/cuda.zc"
@global
fn kernel_suma(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);
// ... inicialización de datos ...
launch kernel_suma(d_a, d_b, d_c, N) with {
grid: (N + 255) / 256,
block: 256
};
cuda_sync();
}
Zen C proporciona una biblioteca estándar para operaciones comunes de CUDA para reducir los bloques raw:
import "std/cuda.zc"
// Gestión de memoria
let d_ptr = cuda_alloc<float>(1024);
cuda_copy_to_device(d_ptr, h_ptr, 1024 * sizeof(float));
defer cuda_free(d_ptr);
// Sincronización
cuda_sync();
// Indexación de hilos (usar dentro de kernels)
let i = thread_id(); // Índice global
let bid = block_id();
let tid = local_id();
Note
Nota: La flag --cuda establece nvcc como el compilador e implica el modo --cpp. Requiere el NVIDIA CUDA Toolkit.
Zen C soporta características modernas de C23 cuando se utiliza un compilador backend compatible (GCC 14+, Clang 14+).
auto: Zen C mapea automáticamente la inferencia de tipos aautoestándar de C23 si__STDC_VERSION__ >= 202300L._BitInt(N): Use tiposiNyuN(ej.i256,u12,i24) para acceder a enteros de ancho arbitrario de C23.
Zen C puede compilarse a Objective-C (.m) usando la flag --objc, permitiéndote usar frameworks de Objective-C (como Cocoa/Foundation) y su sintaxis.
# Compilar con clang (o gcc/gnustep)
zc app.zc --objc --cc clangUsa include para las cabeceras y bloques raw para la sintaxis de 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(@"¡Hola desde Objective-C!");
[pool drain];
}
println "¡Zen C también funciona!";
}
Note
Nota: La interpolación de cadenas de Zen C funciona con objetos de Objective-C (id) llamando a debugDescription o description.
¡Damos la bienvenida a las contribuciones! Ya sea corrigiendo errores, añadiendo documentación o proponiendo nuevas características.
Por favor, consulta CONTRIBUTING_ES.md para ver las guías detalladas sobre cómo contribuir, ejecutar pruebas y enviar pull requests.
Para instrucciones sobre reportes de seguridad, por favor vea SECURITY_ES.md.
Este proyecto utiliza bibliotecas de terceros. Los textos completos de las licencias pueden encontrarse en el directorio LICENSES/.
- cJSON (Licencia MIT): Usado para el parseo y generación de JSON en el Servidor de Lenguaje.
- zc-ape (Licencia MIT): El port original de Ejecutable Realmente Portable de Zen-C por Eugene Olonov.
- Cosmopolitan Libc (Licencia ISC): La biblioteca fundamental que hace posible APE.
- TRE (Licencia BSD): Usado para el motor de expresiones regulares en la biblioteca estándar.
- zenc.vim (Licencia MIT): El plugin oficial para Vim/Neovim, escrito principalmente por davidscholberg.
Copyright © 2026 Lenguaje de Programación Zen C.
Comienza tu viaje hoy.
Discord • GitHub • Documentación • Ejemplos • RFCs • Contribuir