From 472434301940015365f7ed303f52d71c505ac487 Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Fri, 30 Jan 2026 19:44:32 +0000 Subject: Improvements for the standard library + '@ctype'. --- README_ES.md | 1 + 1 file changed, 1 insertion(+) (limited to 'README_ES.md') diff --git a/README_ES.md b/README_ES.md index 9040ea8..999a7b4 100644 --- a/README_ES.md +++ b/README_ES.md @@ -938,6 +938,7 @@ Decora funciones y structs para modificar el comportamiento del compilador. | `@host` | Fn | CUDA: Función de host (`__host__`). | | `@comptime` | Fn | Función auxiliar disponible para ejecución en tiempo de compilación. | | `@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. | | `@` | Cualquier | Pasa atributos genéricos a C (ej. `@flatten`, `@alias("nombre")`). | #### Atributos Personalizados -- cgit v1.2.3 From 51638176265392c70ca2e0014de95867bac4991e Mon Sep 17 00:00:00 2001 From: Zuhaitz Date: Fri, 30 Jan 2026 21:57:35 +0000 Subject: Fix format error in READMEs --- README.md | 2 +- README_ES.md | 2 +- README_ZH_CN.md | 2 +- README_ZH_TW.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'README_ES.md') diff --git a/README.md b/README.md index 001e590..ab51b83 100644 --- a/README.md +++ b/README.md @@ -607,7 +607,7 @@ Zen C supports a shorthand for prompting user input using the `?` prefix. - `? "Enter age: " (age)`: Prints prompt and scans input into the variable `age`. - Format specifiers are automatically inferred based on variable type. -```c +```zc let age: int; ? "How old are you? " (age); println "You are {age} years old."; diff --git a/README_ES.md b/README_ES.md index 999a7b4..d2cfbbb 100644 --- a/README_ES.md +++ b/README_ES.md @@ -606,7 +606,7 @@ Zen C soporta una abreviatura para solicitar entrada al usuario usando el prefij - `? "Ingresa la edad: " (edad)`: Imprime el prompt y escanea la entrada en la variable `edad`. - Los especificadores de formato se infieren automáticamente según el tipo de variable. -```c +```zc let edad: int; ? "¿Cuántos años tienes? " (edad); println "Tienes {edad} años."; diff --git a/README_ZH_CN.md b/README_ZH_CN.md index daa8a3d..2ac38a2 100644 --- a/README_ZH_CN.md +++ b/README_ZH_CN.md @@ -606,7 +606,7 @@ Zen C 支持使用 `?` 前缀进行用户输入提示的简写。 - `? "输入年龄: " (age)`: 打印提示并扫描输入到变量 `age` 中。 - 格式说明符会根据变量类型自动推断。 -```c +```zc let age: int; ? "你多大了? " (age); println "你 {age} 岁了。"; diff --git a/README_ZH_TW.md b/README_ZH_TW.md index 2707caa..13591cf 100644 --- a/README_ZH_TW.md +++ b/README_ZH_TW.md @@ -606,7 +606,7 @@ Zen C 支持使用 `?` 前綴進行用戶輸入提示的簡寫。 - `? "輸入年齡: " (age)`: 打印提示並掃描輸入到變量 `age` 中。 - 格式說明符會根據變量類型自動推斷。 -```c +```zc let age: int; ? "你多大了? " (age); println "你 {age} 歲了。"; -- cgit v1.2.3 From 856c9fe56b412779e045ef86a767b93d5c7f563b Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Sat, 31 Jan 2026 01:15:25 +0000 Subject: Improvements for slice + better iteration for arrays --- README.md | 11 ++- README_ES.md | 12 ++- README_ZH_CN.md | 27 ++++-- README_ZH_TW.md | 11 ++- docs/std/slice.md | 90 ++++++++++++++++++ src/codegen/codegen.c | 88 +++++++++++++++++- src/codegen/codegen_utils.c | 25 ++++- src/parser/parser_stmt.c | 152 ++++++++++++++++++++++++++++--- std/slice.zc | 35 +++++++ tests/std/test_direct_array_iteration.zc | 37 ++++++++ tests/std/test_slice_iteration.zc | 29 ++++++ 11 files changed, 479 insertions(+), 38 deletions(-) create mode 100644 docs/std/slice.md create mode 100644 tests/std/test_direct_array_iteration.zc create mode 100644 tests/std/test_slice_iteration.zc (limited to 'README_ES.md') diff --git a/README.md b/README.md index ab51b83..ecdf8fc 100644 --- a/README.md +++ b/README.md @@ -494,8 +494,15 @@ for i in 0..<10 { ... } // Exclusive (Explicit) for i in 0..=10 { ... } // Inclusive (0 to 10) for i in 0..10 step 2 { ... } -// Iterator (Vec, Array, or custom Iterable) -for item in collection { ... } +// Iterator (Vec or custom Iterable) +for item in vec { ... } + +// Iterate over fixed-size arrays directly +let arr: int[5] = [1, 2, 3, 4, 5]; +for val in arr { + // val is int + println "{val}"; +} // While while x < 10 { ... } diff --git a/README_ES.md b/README_ES.md index d2cfbbb..d73e9ca 100644 --- a/README_ES.md +++ b/README_ES.md @@ -493,8 +493,15 @@ for i in 0..<10 { ... } // Exclusivo (Explícito) for i in 0..=10 { ... } // Inclusivo (0 al 10) for i in 0..10 step 2 { ... } -// Iterador (Vec, Array, o Iterable personalizado) -for item in coleccion { ... } +// Iterador (Vec o Iterable personalizado) +for item in vec { ... } + +// 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 { ... } @@ -508,6 +515,7 @@ externo: loop { for _ in 0..5 { ... } ``` + #### Control Avanzado ```zc // Guard: Ejecuta else y retorna si la condición es falsa diff --git a/README_ZH_CN.md b/README_ZH_CN.md index 2ac38a2..51689f6 100644 --- a/README_ZH_CN.md +++ b/README_ZH_CN.md @@ -485,26 +485,33 @@ match opt { } ``` -#### 循环 +#### 循環 ```zc -// 区间迭代 -for i in 0..10 { ... } // 左闭右开 (0 到 9) -for i in 0..<10 { ... } // 左闭右开 (显式) -for i in 0..=10 { ... } // 全闭 (0 到 10) +// 區間迭代 +for i in 0..10 { ... } // 左閉右開 (0 到 9) +for i in 0..<10 { ... } // 左閉右開 (顯式) +for i in 0..=10 { ... } // 全閉 (0 到 10) for i in 0..10 step 2 { ... } -// 迭代器 (Vec, Array, 或自定义 Iterable) -for item in collection { ... } +// 迭代器 (Vec 或自定義 Iterable) +for item in vec { ... } -// While 循环 +// 直接迭代固定大小数组 +let arr: int[5] = [1, 2, 3, 4, 5]; +for val in arr { + // val 是 int + println "{val}"; +} + +// While 循環 while x < 10 { ... } -// 带标签的无限循环 +// 帶標籤的無限循環 outer: loop { if done { break outer; } } -// 重复 N 次 +// 重複 N 次 for _ in 0..5 { ... } ``` diff --git a/README_ZH_TW.md b/README_ZH_TW.md index 13591cf..6fa0dbd 100644 --- a/README_ZH_TW.md +++ b/README_ZH_TW.md @@ -493,8 +493,15 @@ for i in 0..<10 { ... } // 左閉右開 (顯式) for i in 0..=10 { ... } // 全閉 (0 到 10) for i in 0..10 step 2 { ... } -// 迭代器 (Vec, Array, 或自定義 Iterable) -for item in collection { ... } +// 迭代器 (Vec 或自定義 Iterable) +for item in vec { ... } + +// 直接迭代固定大小數組 +let arr: int[5] = [1, 2, 3, 4, 5]; +for val in arr { + // val 是 int + println "{val}"; +} // While 循環 while x < 10 { ... } diff --git a/docs/std/slice.md b/docs/std/slice.md new file mode 100644 index 0000000..b70c5fe --- /dev/null +++ b/docs/std/slice.md @@ -0,0 +1,90 @@ +# Standard Library: Slice (`std/slice.zc`) + +`Slice` is a lightweight, non-owning view into a contiguous sequence of elements. It's particularly useful for working with fixed-size arrays and enabling iteration. + +## Usage + +```zc +import "std/slice.zc" + +fn main() { + let arr: int[5] = [1, 2, 3, 4, 5]; + + // Direct iteration (Recommended) + for val in arr { + println "{val}"; + } + + // Manual slice creation (for partial views or specific needs) + let slice = Slice::from_array((int*)(&arr), 5); + for val in slice { + println "{val}"; + } +} +``` + +## Structure + +```zc +struct Slice { + data: T*; + len: usize; +} +``` + +## Methods + +### Construction + +| Method | Signature | Description | +| :--- | :--- | :--- | +| **from_array** | `Slice::from_array(arr: T*, len: usize) -> Slice` | Creates a slice view over an array. | + +### Iteration + +| Method | Signature | Description | +| :--- | :--- | :--- | +| **iterator** | `iterator(self) -> SliceIter` | Returns an iterator for `for-in` loops. | + +`SliceIter` implements the iterator protocol with a `next() -> Option` method. + +### Access & Query + +| Method | Signature | Description | +| :--- | :--- | :--- | +| **length** | `length(self) -> usize` | Returns the number of elements. | +| **is_empty** | `is_empty(self) -> bool` | Returns true if length is 0. | +| **get** | `get(self, idx: usize) -> Option` | Returns the element at index, or None if out of bounds. | +| **at** | `at(self, idx: usize) -> Option` | Alias for `get`. | + +## Examples + +### Iterating over fixed-size arrays + +```zc +let numbers: int[3] = [10, 20, 30]; +let slice = Slice::from_array((int*)(&numbers), 3); + +for n in slice { + println "Number: {n}"; +} +``` + +### Safe indexed access + +```zc +let arr: int[3] = [1, 2, 3]; +let slice = Slice::from_array((int*)(&arr), 3); + +let opt = slice.get(1); +if (!opt.is_none()) { + println "Value: {opt.unwrap()}"; // Prints: Value: 2 +} +``` + +## Notes + +- `Slice` does not own its data - it's just a view +- No memory management needed (no `free()` method) +- Must specify the generic type explicitly: `Slice`, `Slice`, etc. +- The array pointer cast `(T*)(&arr)` is required for fixed-size arrays diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index a66f179..7a67428 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -65,6 +65,52 @@ static void codegen_var_expr(ParserContext *ctx, ASTNode *node, FILE *out) zwarn_at(node->token, "%s\n = help: %s", msg, help); } } + + // Check for static method call pattern: Type::method or Slice::method + char *double_colon = strstr(node->var_ref.name, "::"); + if (double_colon) + { + // Extract type name and method name + int type_len = double_colon - node->var_ref.name; + char *type_name = xmalloc(type_len + 1); + strncpy(type_name, node->var_ref.name, type_len); + type_name[type_len] = 0; + + char *method_name = double_colon + 2; // Skip :: + + // Handle generic types: Slice -> Slice_int + char mangled_type[256]; + if (strchr(type_name, '<')) + { + // Generic type - need to mangle it + char *lt = strchr(type_name, '<'); + char *gt = strchr(type_name, '>'); + + if (lt && gt) + { + // Extract base type and type argument + *lt = 0; + char *type_arg = lt + 1; + *gt = 0; + + sprintf(mangled_type, "%s_%s", type_name, type_arg); + } + else + { + strcpy(mangled_type, type_name); + } + } + else + { + strcpy(mangled_type, type_name); + } + + // Output as Type__method + fprintf(out, "%s__%s", mangled_type, method_name); + free(type_name); + return; + } + fprintf(out, "%s", node->var_ref.name); } @@ -348,6 +394,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) } // Check for Static Enum Variant Call: Enum.Variant(...) + if (target->type == NODE_EXPR_VAR) { ASTNode *def = find_struct_def(ctx, target->var_ref.name); @@ -418,11 +465,43 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) base += 7; } + char *mangled_base = base; + char base_buf[256]; + + // Mangle generic types: Slice -> Slice_int, Vec -> Vec_Point + char *lt = strchr(base, '<'); + if (lt) + { + char *gt = strchr(lt, '>'); + if (gt) + { + int prefix_len = lt - base; + int arg_len = gt - lt - 1; + snprintf(base_buf, 255, "%.*s_%.*s", prefix_len, base, arg_len, lt + 1); + mangled_base = base_buf; + } + } + if (!strchr(type, '*') && target->type == NODE_EXPR_CALL) { - fprintf(out, "({ %s _t = ", type); + char *type_mangled = type; + char type_buf[256]; + char *t_lt = strchr(type, '<'); + if (t_lt) + { + char *t_gt = strchr(t_lt, '>'); + if (t_gt) + { + int p_len = t_lt - type; + int a_len = t_gt - t_lt - 1; + snprintf(type_buf, 255, "%.*s_%.*s", p_len, type, a_len, t_lt + 1); + type_mangled = type_buf; + } + } + + fprintf(out, "({ %s _t = ", type_mangled); codegen_expression(ctx, target, out); - fprintf(out, "; %s__%s(&_t", base, method); + fprintf(out, "; %s__%s(&_t", mangled_base, method); ASTNode *arg = node->call.args; while (arg) { @@ -435,10 +514,11 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) else { // Mixin Lookup Logic - char *call_base = base; + char *call_base = mangled_base; + int need_cast = 0; char mixin_func_name[128]; - sprintf(mixin_func_name, "%s__%s", base, method); + sprintf(mixin_func_name, "%s__%s", call_base, method); char *resolved_method_suffix = NULL; diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c index 0d03661..8d9cb28 100644 --- a/src/codegen/codegen_utils.c +++ b/src/codegen/codegen_utils.c @@ -64,13 +64,28 @@ void emit_c_decl(FILE *out, const char *type_str, const char *name) } else if (generic && (!bracket || generic < bracket)) { - // Strip generic part for C output - int base_len = generic - type_str; - fprintf(out, "%.*s %s", base_len, type_str, name); + char *gt = strchr(generic, '>'); + if (gt) + { + int base_len = generic - type_str; + int arg_len = gt - generic - 1; + + fprintf(out, "%.*s_%.*s %s", base_len, type_str, arg_len, generic + 1, name); - if (bracket) + if (bracket) + { + fprintf(out, "%s", bracket); + } + } + else { - fprintf(out, "%s", bracket); + int base_len = generic - type_str; + fprintf(out, "%.*s %s", base_len, type_str, name); + + if (bracket) + { + fprintf(out, "%s", bracket); + } } } else if (bracket) diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c index a471fe6..4c24de3 100644 --- a/src/parser/parser_stmt.c +++ b/src/parser/parser_stmt.c @@ -1133,6 +1133,7 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) ASTNode *obj_expr = start_expr; char *iter_method = "iterator"; + ASTNode *slice_decl = NULL; // Track if we need to add a slice declaration // Check for reference iteration: for x in &vec if (obj_expr->type == NODE_EXPR_UNARY && obj_expr->unary.op && @@ -1142,6 +1143,78 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) iter_method = "iter_ref"; } + // Check for array iteration: wrap with Slice::from_array + if (obj_expr->type_info && obj_expr->type_info->kind == TYPE_ARRAY && + obj_expr->type_info->array_size > 0) + { + // Create a var decl for the slice + slice_decl = ast_create(NODE_VAR_DECL); + slice_decl->var_decl.name = xstrdup("__zc_arr_slice"); + + // Build type string: Slice + char *elem_type_str = type_to_string(obj_expr->type_info->inner); + char slice_type[256]; + sprintf(slice_type, "Slice<%s>", elem_type_str); + slice_decl->var_decl.type_str = xstrdup(slice_type); + + ASTNode *from_array_call = ast_create(NODE_EXPR_CALL); + ASTNode *static_method = ast_create(NODE_EXPR_VAR); + + // The function name for static methods is Type::method format + char func_name[512]; + snprintf(func_name, 511, "%s::from_array", slice_type); + static_method->var_ref.name = xstrdup(func_name); + + from_array_call->call.callee = static_method; + + // Create arguments + ASTNode *arr_addr = ast_create(NODE_EXPR_UNARY); + arr_addr->unary.op = xstrdup("&"); + arr_addr->unary.operand = obj_expr; + + ASTNode *arr_cast = ast_create(NODE_EXPR_CAST); + char cast_type[256]; + sprintf(cast_type, "%s*", elem_type_str); + arr_cast->cast.target_type = xstrdup(cast_type); + arr_cast->cast.expr = arr_addr; + + ASTNode *size_arg = ast_create(NODE_EXPR_LITERAL); + size_arg->literal.type_kind = LITERAL_INT; + size_arg->literal.int_val = obj_expr->type_info->array_size; + char size_buf[32]; + sprintf(size_buf, "%d", obj_expr->type_info->array_size); + size_arg->literal.string_val = xstrdup(size_buf); + + arr_cast->next = size_arg; + from_array_call->call.args = arr_cast; + from_array_call->call.arg_count = 2; + + slice_decl->var_decl.init_expr = from_array_call; + + // Manually trigger generic instantiation for Slice + // This ensures that Slice_int, Slice_float, etc. structures are generated + Token dummy_tok = {0}; + instantiate_generic(ctx, "Slice", elem_type_str, elem_type_str, dummy_tok); + + // Instantiate SliceIter and Option too for the loop logic + char iter_type[256]; + sprintf(iter_type, "SliceIter<%s>", elem_type_str); + instantiate_generic(ctx, "SliceIter", elem_type_str, elem_type_str, dummy_tok); + + char option_type[256]; + sprintf(option_type, "Option<%s>", elem_type_str); + instantiate_generic(ctx, "Option", elem_type_str, elem_type_str, dummy_tok); + + // Replace obj_expr with a reference to the slice variable + ASTNode *slice_ref = ast_create(NODE_EXPR_VAR); + slice_ref->var_ref.name = xstrdup("__zc_arr_slice"); + slice_ref->resolved_type = + xstrdup(slice_type); // Explicitly set type for codegen + obj_expr = slice_ref; + + free(elem_type_str); + } + // var __it = obj.iterator(); ASTNode *it_decl = ast_create(NODE_VAR_DECL); it_decl->var_decl.name = xstrdup("__it"); @@ -1182,6 +1255,34 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) stmts_tail = node; \ } + char *iter_type_ptr = NULL; + char *option_type_ptr = NULL; + + if (slice_decl) + { + char *slice_t = slice_decl->var_decl.type_str; + char *start = strchr(slice_t, '<'); + if (start) + { + char *end = strrchr(slice_t, '>'); + if (end) + { + int len = end - start - 1; + char *elem = xmalloc(len + 1); + strncpy(elem, start + 1, len); + elem[len] = 0; + + iter_type_ptr = xmalloc(256); + sprintf(iter_type_ptr, "SliceIter<%s>", elem); + + option_type_ptr = xmalloc(256); + sprintf(option_type_ptr, "Option<%s>", elem); + + free(elem); + } + } + } + // var __opt = __it.next(); ASTNode *opt_decl = ast_create(NODE_VAR_DECL); opt_decl->var_decl.name = xstrdup("__opt"); @@ -1192,6 +1293,10 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) ASTNode *memb_next = ast_create(NODE_EXPR_MEMBER); ASTNode *it_ref = ast_create(NODE_EXPR_VAR); it_ref->var_ref.name = xstrdup("__it"); + if (iter_type_ptr) + { + it_ref->resolved_type = xstrdup(iter_type_ptr); + } memb_next->member.target = it_ref; memb_next->member.field = xstrdup("next"); call_next->call.callee = memb_next; @@ -1204,15 +1309,22 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) ASTNode *memb_is_none = ast_create(NODE_EXPR_MEMBER); ASTNode *opt_ref1 = ast_create(NODE_EXPR_VAR); opt_ref1->var_ref.name = xstrdup("__opt"); + if (option_type_ptr) + { + opt_ref1->resolved_type = xstrdup(option_type_ptr); + } memb_is_none->member.target = opt_ref1; memb_is_none->member.field = xstrdup("is_none"); call_is_none->call.callee = memb_is_none; + call_is_none->call.args = NULL; + call_is_none->call.arg_count = 0; - ASTNode *break_stmt = ast_create(NODE_BREAK); - + // if (__opt.is_none()) break; ASTNode *if_break = ast_create(NODE_IF); if_break->if_stmt.condition = call_is_none; + ASTNode *break_stmt = ast_create(NODE_BREAK); if_break->if_stmt.then_body = break_stmt; + if_break->if_stmt.else_body = NULL; APPEND_STMT(if_break); // var = __opt.unwrap(); @@ -1225,25 +1337,28 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) ASTNode *memb_unwrap = ast_create(NODE_EXPR_MEMBER); ASTNode *opt_ref2 = ast_create(NODE_EXPR_VAR); opt_ref2->var_ref.name = xstrdup("__opt"); + if (option_type_ptr) + { + opt_ref2->resolved_type = xstrdup(option_type_ptr); + } memb_unwrap->member.target = opt_ref2; memb_unwrap->member.field = xstrdup("unwrap"); call_unwrap->call.callee = memb_unwrap; + call_unwrap->call.args = NULL; + call_unwrap->call.arg_count = 0; user_var_decl->var_decl.init_expr = call_unwrap; APPEND_STMT(user_var_decl); - // User Body + // User body statements enter_scope(ctx); add_symbol(ctx, var_name, NULL, NULL); - ASTNode *user_body_node; - if (lexer_peek(l).type == TOK_LBRACE) - { - user_body_node = parse_block(ctx, l); - } - else + // Body block + ASTNode *stmt = parse_statement(ctx, l); + ASTNode *user_body_node = stmt; + if (stmt && stmt->type != NODE_BLOCK) { - ASTNode *stmt = parse_statement(ctx, l); ASTNode *blk = ast_create(NODE_BLOCK); blk->block.statements = stmt; user_body_node = blk; @@ -1256,10 +1371,21 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) loop_body->block.statements = stmts_head; while_loop->while_stmt.body = loop_body; - // Wrap entire thing in a block to scope _it + // Wrap entire thing in a block to scope __it (and __zc_arr_slice if present) ASTNode *outer_block = ast_create(NODE_BLOCK); - it_decl->next = while_loop; - outer_block->block.statements = it_decl; + if (slice_decl) + { + // Chain: slice_decl -> it_decl -> while_loop + slice_decl->next = it_decl; + it_decl->next = while_loop; + outer_block->block.statements = slice_decl; + } + else + { + // Chain: it_decl -> while_loop + it_decl->next = while_loop; + outer_block->block.statements = it_decl; + } return outer_block; } diff --git a/std/slice.zc b/std/slice.zc index 778c6ed..7ace396 100644 --- a/std/slice.zc +++ b/std/slice.zc @@ -1,10 +1,45 @@ +import "./option.zc" + struct Slice { data: T*; len: usize; } +struct SliceIter { + data: T*; + count: usize; + idx: usize; +} + +impl SliceIter { + fn next(self) -> Option { + if (self.idx < self.count) { + let item = self.data[self.idx]; + self.idx = self.idx + 1; + return Option::Some(item); + } + return Option::None(); + } + + fn iterator(self) -> SliceIter { + return *self; + } +} + impl Slice { + fn from_array(arr: T*, len: usize) -> Slice { + return Slice { data: arr, len: len }; + } + + fn iterator(self) -> SliceIter { + return SliceIter { + data: self.data, + count: self.len, + idx: 0 + }; + } + fn length(self) -> usize { return self.len; } diff --git a/tests/std/test_direct_array_iteration.zc b/tests/std/test_direct_array_iteration.zc new file mode 100644 index 0000000..359951f --- /dev/null +++ b/tests/std/test_direct_array_iteration.zc @@ -0,0 +1,37 @@ +import "std/slice.zc" + +test "direct array iteration" { + let arr: int[5] = [1, 2, 3, 4, 5]; + + let sum = 0; + for val in arr { + sum = sum + val; + } + + assert(sum == 15, "Sum should be 1+2+3+4+5 = 15"); +} + +test "direct array iteration with different types" { + let floats: float[3] = [1.5, 2.5, 3.0]; + let count = 0; + + for f in floats { + count = count + 1; + } + + assert(count == 3, "Should iterate over all 3 elements"); +} + +// TODO: Nested array iteration needs special handling +// test "nested array iteration" { +// let matrix: int[2][3] = [[1, 2, 3], [4, 5, 6]]; +// let total = 0; +// +// for row in matrix { +// for val in row { +// total = total + val; +// } +// } +// +// assert(total == 21, "Sum should be 1+2+3+4+5+6 = 21"); +// } diff --git a/tests/std/test_slice_iteration.zc b/tests/std/test_slice_iteration.zc new file mode 100644 index 0000000..b7eddf4 --- /dev/null +++ b/tests/std/test_slice_iteration.zc @@ -0,0 +1,29 @@ +import "std/slice.zc" +import "std/io.zc" + +test "slice from array iteration" { + let ints: int[5] = [1, 2, 3, 4, 5]; + let slice = Slice::from_array((int*)(&ints), 5); + + // Test iteration + let sum = 0; + for val in slice { + sum = sum + val; + } + + if (sum != 15) { + panic("Slice iteration failed: expected sum 15"); + } +} + +test "slice methods" { + let arr: int[3] = [10, 20, 30]; + let slice = Slice::from_array((int*)(&arr), 3); + + if (slice.length() != 3) panic("Slice length wrong"); + if (slice.is_empty()) panic("Slice should not be empty"); + + let opt = slice.get(1); + if (opt.is_none()) panic("Slice get failed"); + if (opt.unwrap() != 20) panic("Slice get returned wrong value"); +} -- cgit v1.2.3 From 705733a604a39e9f2b0e21ad77a3dbb97a2019a2 Mon Sep 17 00:00:00 2001 From: czjstmax Date: Sat, 31 Jan 2026 20:10:20 +0100 Subject: Italian translation - Added italian translation (`README_IT.md`) for the documentation. - Added links for the italian translation in the other documents. (`README.md` and `README_*.md`) Signed-off-by: czjstmax --- README.md | 2 +- README_ES.md | 2 +- README_IT.md | 1439 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ README_ZH_CN.md | 2 +- README_ZH_TW.md | 2 +- 5 files changed, 1443 insertions(+), 4 deletions(-) create mode 100644 README_IT.md (limited to 'README_ES.md') diff --git a/README.md b/README.md index bf4962e..786e32c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@
-[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md) +[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md) • [Italiano](README_IT.md)
diff --git a/README_ES.md b/README_ES.md index d73e9ca..4f1e4be 100644 --- a/README_ES.md +++ b/README_ES.md @@ -1,7 +1,7 @@
-[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md) +[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md) • [Italiano](README_IT.md)
diff --git a/README_IT.md b/README_IT.md new file mode 100644 index 0000000..9b48e62 --- /dev/null +++ b/README_IT.md @@ -0,0 +1,1439 @@ + +
+ +[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md) • [Italiano](README_IT.md) + +
+ +
+ +# Zen C + +**Ergonomia Moderna. Zero Overhead. C puro.** + +[![Stato Build](https://img.shields.io/badge/build-passing-brightgreen)]() +[![Licenza](https://img.shields.io/badge/license-MIT-blue)]() +[![Versione](https://img.shields.io/badge/version-0.1.0-orange)]() +[![Piattaforma](https://img.shields.io/badge/platform-linux-lightgrey)]() + +*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 matcing, 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 comande o segnala dei bug nel server ufficiale Discord Zen C + +- Discord: [Unisciti qui](https://discord.com/invite/q6wEsCmkJP) + +--- + +## Indice + +- [Panoramica](#panoramica) +- [Community](#community) +- [Guida Rapida](#guida-rapida) + - [Installazione](#installazione) + - [Utilizzo](#utilizzo) + - [Variabili d'ambiente](#variabili-d-ambiente) +- [Riferimenti Del Linguaggio](#riferimenti-del-linguaggio) + - [1. Variabili e Costanti](#1-variabili-e-costanti) + - [2. Tipi Primitivi](#2-tipi-primitivi) + - [3. Tipi Aggregati](#3-tipi-aggregati) + - [Array](#array) + - [Tuple](#tuple) + - [Struct](#struct) + - [Struct Opachi](#struct-opachi) + - [Enum](#enum) + - [Unioni](#unioni) + - [Alias del tipo](#alias-del-tipo) + - [Alias del tipo opachi](#alias-del-tipo-opachi) + - [4. Funzioni e Lambda](#4-funzioni-e-lambda) + - [Funzioni](#funzioni) + - [Argomenti Costanti](#argomenti-costanti) + - [Argomenti di default](#argomenti-di-default) + - [Lambda (Closure)](#lambda-closure) + - [Puntatori-Funzione Grezzi](#puntatori-funzione-grezzi) + - [Argomenti Variadici](#argomenti-variadici) + - [5. Controllo di Flusso](#5-controllo-di-flusso) + - [Condizionali](#condizionali) + - [Pattern Matching](#pattern-matching) + - [Loop](#loop) + - [Controllo Avanzato](#controllo-avanzato) + - [6. Operators](#6-operatori) + - [Operatori Overload-abili](#operatori-overload-abili) + - [Zucchero Sintattico](#zucchero-sintattico) + - [7. Stampaggio e Interpolazione delle Stringhe](#7-stampaggio-e-interpolazione-delle-stringhe) + - [Keyword](#keyword) + - [Scorciatoie](#scorciatoie) + - [Interpolazione delle Stringhe (F-strings)](#interpolazione-delle-stringhe-f-strings) + - [Prompt di Input (`?`)](#prompt-di-input) + - [8. Gestione della memoria](#8-gestione-della-memoria) + - [Rimando](#rimando) + - [Liberazione-automatica](#liberazione-automatica) + - [Semantiche delle risorse (Muovi di default)](#semantiche-delle-risorse-muovi-di-default) + - [RAII / Rilascio Tratti](#raii--rilascio-tratti) + - [9. Programmazione Orientata a Oggetti](#9-programmazione-orientata-a-oggetti) + - [Metodi](#metodi) + - [Tratti](#tratti) + - [Tratti Standard](#tratti-standard) + - [Composizione](#composizione) + - [10. Generici](#10-generici) + - [11. Concorrenza Asincrona (Async/Await)](#11-concorrenza-asincrona-asyncawait) + - [12. Metaprogramming](#12-metaprogramming) + - [Comptime](#comptime) + - [Incorporati](#incorporati) + - [Plugin](#plugin) + - [Macro C Generiche](#macro-c-generiche) + - [13. Attributi](#13-attributi) + - [Attributi Personalizzati](#attributi-personalizzati) + - [Mappatura della Sintassi](#mappatura-della-sintassi) + - [Derivazioni Intelligenti](#derivazioni-intelligenti) + - [14. Assembly Inline](#14-assembly-inline) + - [Utilizzo Base](#utilizzo-base) + - [Volatile](#volatile) + - [Vincoli Nominati](#vincoli-nominati) + - [15. Direttive della Buil](#15-direttive-della-build) + - [16. Keyword](#16-keyword) +- [Libreria Standard](#liberia-standard) +- [Tooling](#tooling) + - [Language Server (LSP)](#language-server-lsp) + - [REPL](#repl) +- [Supporto del Compilatore e Compatibilità](#supporto-del-compilatore-e-compatibilità) + - [Stato della suite di test](#stato-della-suite-di-test) + - [Buildare con Zig](#buildare-con-zig) + - [Interop C++](#interop-c) + - [Interop CUDA](#interop-cuda) + - [Interop Objective-C](#interop-objective-c) + - [Supporto ISO C23](#supporto-iso-c23) +- [Contribuisci](#contribuisci) +- [Attribuzioni](#attribuzioni) + +--- + +## Guida Rapida + +### Installazione + +```bash +git clone https://github.com/z-libs/Zen-C.git +cd Zen-C +make +sudo make install +``` + +### Build Portatile (APE) + +Il codice Zen C può come un **Actually Portable Executable (APE)** (lett. _Eseguibile Effetivamente Portatile_) utilizzando la [Cosmopolitan Libc](https://github.com/jart/cosmopolitan). 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:** +```bash +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. + +**Usage:** +```bash +# Eseguibile su qualunque OS supportato +./out/bin/zc.com build hello.zc -o hello +``` + +### Utilizzo + +```bash +# Compila e avvia +zc run hello.zc + +# Builda eseguibile +zc build hello.zc -o hello + +# Shell interattiva +zc repl +``` + +### 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. + +```bash +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 varaibili di esecuzione. + +#### Manifest Constants (`def`) +#### Costanti Manifesto (`def`) +Valori che esistono solo durante la compilazione (integrate nel codice). Utilizzale per le grandezze degli array, configurazioni fisse, e numeri magici. + +```zc +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`). + +```zc +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 +``` + +> **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` | `int`, `unsigned int` | Intero standard della piattaforma | +| `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) | + +### 3. Tipi Aggregati + +#### Array +Array a lunghezza fissa con valori arbitrari. +```zc +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. +```zc +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: +```zc +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 irettamente in variabili singole. +```zc +let (somma, differenza) = somma_e_differenza(3, 2); +// somma = 5, differenza = 1 +``` + +#### Structs +Strutture dati con campi di bit opzionali. +```zc +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; +} +``` + +> **Nota**: Gli struct usano le [Semantiche di Spostatmento](#semantiche-di-movimento--copia-sicura) 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). + +```zc +// 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. +```zc +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). +```zc +union Dati { + i: int; + f: float; +} +``` + +#### Alias del tipo +Crea un alias per un tipo già esistente. +```zc +alias ID = int; +alias PuntoDellaMappa = Mappa; +``` + +#### Opaque Type Aliases +#### 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. + +```zc +// 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. Functions & Lambdas + +#### Funzioni +```zc +fn somma(a: int, b: int) -> int { + return a + b; +} + +// Supporto per argomenti nominati nelle chiamate +somma(a: 10, b: 20); +``` + +> **Nota**: 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. + +```zc +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). +```zc +// Valore default semplice +fn incrementa(val: int, quantità: int = 1) -> int { + return val + quantità; +} + +// Expression default value (evaluated at call site) +// 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" +} +``` + +#### Lambdas (Closures) +#### Lambda (Closure) +Funzioni anonime che possono catturare il loro ambiente. +```zc +let fattore = 2; +let double = x -> x * fattore; // Sintassi con freccia +let pieno = fn(x: int) -> int { return x * fattore; }; // Sintassi a blocco +``` + +#### 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. + +```zc +// 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`. +```zc +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 +```zc +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 +``` + +#### Pattern Matching +Alternativa potente agli `switch`. +```zc +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). + +```zc +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 +```zc +// 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 { ... } + +// Iteratore (Vec, Array, oppure un Iteratore personalizzato) +for item in collection { ... } + +// While (lett. mentre) +while x < 10 { ... } + +// Infinito con etichetta +esterno: loop { + if done { break esterno; } +} + +// Ripeti N volte +for _ in 0..5 { ... } +``` + +#### Controllo Avanzato +```zc +// 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` | +| **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] = 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:** +```zc +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) +``` + +#### 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 + +- `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: + +- `"Ciao Mondo!"`: Equivalente a `println "Ciao Mondo!"`. (Aggiunge una newline implicitamente) +- `"Ciao Mondo!"..`: Equivalente a `print "Ciao Mondo!"`. (Non aggiunge una newline) +- `!"Errore"`: Equivalente a `eprintln "Errore"`. (Output a stderr) +- `!"Errore"..`: Equivalente a `eprint "Errore"`. (Output a stderr, senza newline) + +#### Interpolazione delle Stringhe (F-strings) + +Puoi incorporare espressioni direttamente all'interno di stringhe letterali utilizzando la sintassi `{}`. Questo funziona con tutti i metodi di stampaggio, incluse le scorciatoie. + +```zc +let x = 42; +let nome = "Max"; +println "Valore: {x}, Nome: {name}"; +"Valore: {x}, Nome: {name}"; // scorciatoia per println +``` + +#### 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. + +```zc +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). +```zc +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. +```zc +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. + +```zc +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 risorsas, rendilo esplicito: + +```zc +let b = a.clona(); // Chiama il metodo `clona` dal tratto `Clone` +``` + +**Duplicazione opt-in (Tipi dei valori)**: +Per tipi piccoli senza distruttore: + +```zc +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. +```zc +impl Drop for MioStruct { + fn drop(self) { + self.free(); + } +} +``` + +### 9. Programmazione Orientata a Oggetti + +#### Metodi +Definisci metodi sui tipi utilizziando `impl`. +```zc +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); + } +} +``` + +#### Tratti +Definisci un comportamento condiviso. +```zc +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` per abilitare loop `for-in` (lett. _per in_) nei tuoi tipi personalizzati. + +```zc +import "std/iter.zc" + +// Definisci un Iteratore +struct MioIteratore { + curr: int; + stop: int; +} + +impl MioIteratore { + fn next(self) -> Option { + if self.curr < self.stop { + self.curr += 1; + return Option::Some(self.curr - 1); + } + return Option::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). + +```zc +import "std/mem.zc" + +struct Risorsa { + ptr: void*; +} + +impl Drop for Risorsa { + fn drop(self) { + if self.ptr != NULL { + free(self.ptr); + } + } +} +``` + +> **Nota:** Se una variabile viene spostata, `drop` NON verrà chiamato sulla variabile originale. Aderisce alle [Semantiche delle Risorse](#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`). + +```zc +@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. + +```zc +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). + +```zc +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. + +```zc +// Struct Generico +struct Scatola { + oggetto: T; +} + +// Funzione Generica +fn identità(valore: T) -> T { + return valore; +} + +// Generici Multi-parametro +struct Paio { + chiavi: K; + valore: V; +} +``` + +### 11. Concorreza Asincrona (Async/Await) + +Costruito sui pthreads. + +```zc +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 tempo di compilazione per generare sorgente o stampare messaggi. +```zc +comptime { + // Genera codice al tempo di compilazione (scritto a stdout) + println "let data_della_build = \"2024-01-01\";"; +} + +println "Data della build: {data_della_build}"; +``` + +#### Incorporati +Incorpora file come tipi specificati. +```zc +// 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. +```zc +import plugin "regex" +let re = regex! { ^[a-z]+$ }; +``` + +#### Macro C Generiche +Passa delle macro del preprocessore C. + +> **Consiglio**: Per delle semplici costanti, utilizza `def`. Usa `#define` solo quanto ti servono macro del preprocessore C o flag di compilazione condizionale. + +```zc +#define BUFFER_MASSIMO 1024 +``` + +### 13. Attributti + +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 | Export symbol (visibility 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. | +| `@derive(...)` | Struct | Implementa automaticamente i tratti. Supporta `Debug`, `Eq` (Derivazione Intelligente), `Copy`, `Clone`. | +| `@` | 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. +```zc +asm { + "nop" + "mfence" +} +``` + +#### Volatile +Impedisci al compilatore di eliminare automaticamente istruzioni assembly (e.g. ottimizzazione) se ciò potrebbe avere ripercussioni. +```zc +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*. + +```zc +// Sintassi: : out(variable) : in(variable) : clobber(reg) +// Usa una sintassi placeholder (`{variabile}`) per la leggibilità + +fn somma(a: int, b: int) -> int { + let risultato: int; + asm { + "add {risultato}, {a}, {b}" + : out(risultato) + : in(a), in(b) + : 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"` | + +> **Nota:** Quando si usa la sintassi Intel (via `-masm=intel`), dovrai assicurartic 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 process 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 ricercare 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 spefico 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:`). + +```zc +//> 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. + +```zc +//> include: ${HOME}/MiaLibreria/include +//> lib: ${ZC_ROOT}/std +``` + +#### Esempi + +```zc +//> 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` + +--- + +## Libreria Standard + +Zen C include una libreria standard (`std`) che ricopre funzionalità essenziali. + +[Scopri la documentazione della Libreria Standard](docs/std/README.md) + +### Moduli Chiave + +| Modulo | Descrizione | Documentazione | +| :--- | :--- | :--- | +| **`std/vec.zc`** | Array dinamico espandibile `Vec`. | [Docs](docs/std/vec.md) | +| **`std/string.zc`** | Tipo `String` allocato sull'Heap con supporto UTF-8. | [Docs](docs/std/string.md) | +| **`std/queue.zc`** | Coda FIFO (Buffer Circolare). | [Docs](docs/std/queue.md) | +| **`std/map.zc`** | Hash Map Generica `Map`. | [Docs](docs/std/map.md) | +| **`std/fs.zc`** | Operazioni del File System. | [Docs](docs/std/fs.md) | +| **`std/io.zc`** | Standard Input/Output (`print`/`println`). | [Docs](docs/std/io.md) | +| **`std/option.zc`** | Valori opzionali (`Some`/`None`). | [Docs](docs/std/option.md) | +| **`std/result.zc`** | Gestione degli errori (`Ok`/`Err`). | [Docs](docs/std/result.md) | +| **`std/path.zc`** | Manipolazione dei percorsi Cross-platform. | [Docs](docs/std/path.md) | +| **`std/env.zc`** | Variabili d'ambiente del processo. | [Docs](docs/std/env.md) | +| **`std/net.zc`** | Networking TCP (Socket). | [Docs](docs/std/net.md) | +| **`std/thread.zc`** | Threads and Synchronization. | [Docs](docs/std/thread.md) | +| **`std/time.zc`** | Misuramenti di tempo e `sleep`. | [Docs](docs/std/time.md) | +| **`std/json.zc`** | Parsing JSON e serializzazione. | [Docs](docs/std/json.md) | +| **`std/stack.zc`** | Stack LIFO `Stack`. | [Docs](docs/std/stack.md) | +| **`std/set.zc`** | Hash Set Generico `Set`. | [Docs](docs/std/set.md) | +| **`std/process.zc`** | Esecuzione e gestione di processi. | [Docs](docs/std/process.md) | + +--- + +## 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): + +```bash +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. + +```bash +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 ` | Mostra il tipo di un espressione. | +| `:c ` | Mostra il codice C generato per un istruzione. | +| `:time ` | Esegui un benchmark per l'espressione data. (Esegue 1000 iterazioni). | +| `:edit [n]` | Modifica il comando `n` (default: l'ultimo comando) in `$EDITOR`. | +| `:save ` | Salva la sessione corrente in un file `.zc`. | +| `:load ` | Carica ed esegui un file `.zc` nella sessione corrente. | +| `:watch ` | Watch (lett. _guarda_) un espressione (rieseguita dopo ogni entry). | +| `:unwatch ` | Rimuovi un watch. | +| `:undo` | Rimuovi l'ultimo comando dalla sessione. | +| `:delete ` | Rimuovi il comando all'indice `n`. | +| `:clear` | Pulisce lo schermo. | +| `:quit` | Esce dal REPL. | +| `! ` | Esegue un comando sulla shell (e.g. `!ls`). | + +--- + + +## 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. + +```bash +zc run app.zc --cc clang +zc run app.zc --cc zig +``` + +### Stato della suite di test + +| Compilatore | Percentuale di Superamento | Funzionalità Supportate | Limitazioni Nota | +|:---|:---:|:---|:---| +| **GCC** | **100%** | Tutte le funzioni. | Nessuna. | +| **Clang** | **100%** | Tutte le funzioni. | Nessuna. | +| **Zig** | **100%** | Tutte le funzioni. | Nessuna. Usa `zig cc` come compilatore C _drop-in_. | +| **TCC** | **~70%** | Sintassi base, Generici, Tratti | Nessun `__auto_type`, Nessuna sintassi Intel per ASM, Nessuna funzione innestata. | + +> **Consiglio:** Usag **GCC**, **Clang**, o **Zig** per le build di produzione. TCC è eccellente per prototipazione rapida per via dei suoi tempi di compilazione molto brevi ma è carente di alcune estensioni C avanzate che servono a Zen C per un set completo di funzionalità. + +### 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: + +```bash +# 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++. + +```bash +# 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++: + +```zc +include +include + +raw { + std::vector 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. + +```bash +# 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: + +```zc +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<<>>(args);` + +#### Scrivere kernel CUDA + +Utilizza la sintassi delle funzioni Zen C con `@global` e l'istruzione `launch`: + +```zc +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(N); + let d_b = cuda_alloc(N); + let d_c = cuda_alloc(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): + +```zc +import "std/cuda.zc" + +// Gestione della memoria +let d_ptr = cuda_alloc(1024); +cuda_copy_to_device(d_ptr, h_ptr, 1024 * sizeof(float)); +defer cuda_free(d_ptr); + +// Sincronizzazione +cuda_sync(); + +// Thread Indexing (use inside kernels) +// Indicizzazione dei thread (usa all'interno del kernel) +let i = thread_id(); // Indice globale +let bid = block_id(); +let tid = local_id(); +``` + + +> **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 + +```bash +# 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`, `[...]`, `@""`). + +```zc +//> macos: framework: Foundation +//> linux: cflags: -fconstant-string-class=NSConstantString -D_NATIVE_OBJC_EXCEPTIONS +//> linux: link: -lgnustep-base -lobjc + +include + +fn main() { + raw { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSLog(@"Ciao da Objective-C!"); + [pool drain]; + } + println "Funziona anche Zen C!"; +} +``` + +> **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 contributori! Che siano fix di bug, miglioramenti alla documentazione, o la proposta di nuove funzionalità. + +### Come contribuire +1. **Forka la repository**: Workflow standard di GitHub. +2. **Crea un Branch per la funzionalità**: `git checkout -b feature/NewThing`. +3. **Guide Linea per il Codice**: + * Segui lo stile C esistente. + * Assicurati che passino tutti i test: `make test`. + * Aggiungi nuovi test per la tua nuova funzionalità in `tests/`. +4. **Crea una Pull Request**: Descrivi chiaramente le modifiche apportate. + +### Eseguire i test +La suite di test è il tuo miglior amico. + +```bash +# Esegui tutti i test (GCC) +make test + +# Esegui test specifici +./zc run tests/test_match.zc + +# Esegui test con un compilatore differente +./tests/run_tests.sh --cc clang +./tests/run_tests.sh --cc zig +./tests/run_tests.sh --cc tcc +``` + +### Estendere il Compilatore +* **Parser**: `src/parser/` - Parser a discesa ricorsiva. +* **Codegen**: `src/codegen/` - Logica di traspilazione (Zen C -> GNU C/C11). +* **Standard Library**: `std/` - Written in Zen C itself. + +--- + +## Attribuzioni + +Questo progetto utilizza librerie esterne. I testi di licenza completi possono essere trovati nella directory `LICENSES/`. + +* **[cJSON](https://github.com/DaveGamble/cJSON)** (Licenza MIT): Usato per il parsing e la generazione di JSON nel Language Server. +* **[zc-ape](https://github.com/OEvgeny/zc-ape)** (Licenza MIT): La versione originale di Actually Portable Executable di Zen-C, realizzata da [Eugene Olonov](https://github.com/OEvgeny). +* **[Cosmopolitan Libc](https://github.com/jart/cosmopolitan)** (Licenza ISC): La libreria fondamentale che rende possibile APE. + diff --git a/README_ZH_CN.md b/README_ZH_CN.md index 51689f6..09b9bc3 100644 --- a/README_ZH_CN.md +++ b/README_ZH_CN.md @@ -1,7 +1,7 @@
-[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md) +[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md) • [Italiano](README_IT.md)
diff --git a/README_ZH_TW.md b/README_ZH_TW.md index 6fa0dbd..b0a98b8 100644 --- a/README_ZH_TW.md +++ b/README_ZH_TW.md @@ -1,7 +1,7 @@
-[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md) +[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md) • [Italiano](README_IT.md)
-- cgit v1.2.3 From aafd7e8739b14dd89b2e81148f2b07710f3c2c42 Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Sat, 31 Jan 2026 22:53:52 +0000 Subject: Automatic versioning --- README.md | 2 +- README_ES.md | 2 +- README_IT.md | 2 +- README_ZH_CN.md | 2 +- README_ZH_TW.md | 2 +- examples/networking/echo_server.zc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'README_ES.md') diff --git a/README.md b/README.md index 786e32c..2f0832f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ [![Build Status](https://img.shields.io/badge/build-passing-brightgreen)]() [![License](https://img.shields.io/badge/license-MIT-blue)]() -[![Version](https://img.shields.io/badge/version-0.1.0-orange)]() +[![Version](https://img.shields.io/github/v/release/z-libs/Zen-C?label=version&color=orange)]() [![Platform](https://img.shields.io/badge/platform-linux-lightgrey)]() *Write like a high-level language, run like C.* diff --git a/README_ES.md b/README_ES.md index 4f1e4be..2feb762 100644 --- a/README_ES.md +++ b/README_ES.md @@ -13,7 +13,7 @@ [![Estado de la Construcción](https://img.shields.io/badge/build-passing-brightgreen)]() [![Licencia](https://img.shields.io/badge/license-MIT-blue)]() -[![Versión](https://img.shields.io/badge/version-0.1.0-orange)]() +[![Versión](https://img.shields.io/github/v/release/z-libs/Zen-C?label=version&color=orange)]() [![Plataforma](https://img.shields.io/badge/platform-linux-lightgrey)]() *Escribe como un lenguaje de alto nivel, ejecuta como C.* diff --git a/README_IT.md b/README_IT.md index 7d14165..ba49e46 100644 --- a/README_IT.md +++ b/README_IT.md @@ -13,7 +13,7 @@ [![Stato Build](https://img.shields.io/badge/build-passing-brightgreen)]() [![Licenza](https://img.shields.io/badge/license-MIT-blue)]() -[![Versione](https://img.shields.io/badge/version-0.1.0-orange)]() +[![Versione](https://img.shields.io/github/v/release/z-libs/Zen-C?label=version&color=orange)]() [![Piattaforma](https://img.shields.io/badge/platform-linux-lightgrey)]() *Comodità di un linguaggio ad alto livello, veloce come il C* diff --git a/README_ZH_CN.md b/README_ZH_CN.md index 09b9bc3..796eb66 100644 --- a/README_ZH_CN.md +++ b/README_ZH_CN.md @@ -13,7 +13,7 @@ [![构建状态](https://img.shields.io/badge/build-passing-brightgreen)]() [![许可证](https://img.shields.io/badge/license-MIT-blue)]() -[![版本](https://img.shields.io/badge/version-0.1.0-orange)]() +[![版本](https://img.shields.io/github/v/release/z-libs/Zen-C?label=version&color=orange)]() [![平台](https://img.shields.io/badge/platform-linux-lightgrey)]() *像高级语言一样编写,像 C 一样运行。* diff --git a/README_ZH_TW.md b/README_ZH_TW.md index b0a98b8..5b4d484 100644 --- a/README_ZH_TW.md +++ b/README_ZH_TW.md @@ -13,7 +13,7 @@ [![構建狀態](https://img.shields.io/badge/build-passing-brightgreen)]() [![許可證](https://img.shields.io/badge/license-MIT-blue)]() -[![版本](https://img.shields.io/badge/version-0.1.0-orange)]() +[![版本](https://img.shields.io/github/v/release/z-libs/Zen-C?label=version&color=orange)]() [![平台](https://img.shields.io/badge/platform-linux-lightgrey)]() *像高級語言一樣編寫,像 C 一樣運行。* diff --git a/examples/networking/echo_server.zc b/examples/networking/echo_server.zc index 64c60da..82ecd82 100644 --- a/examples/networking/echo_server.zc +++ b/examples/networking/echo_server.zc @@ -4,7 +4,7 @@ import "std/net.zc" def SIZE = 1024; fn main() { - raw { setbuf(stdout, NULL); } + setbuf(stdout, NULL); "Starting Echo Server on 127.0.0.1:8080..."; let listener_res = TcpListener::bind("127.0.0.1", 8080); -- cgit v1.2.3 From f14c26996e2f69aaa25e284dd40320f9c00079e3 Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Sun, 1 Feb 2026 11:19:34 +0000 Subject: Fix for #167 --- README.md | 7 ++--- README_ES.md | 7 ++--- README_IT.md | 7 ++--- README_ZH_CN.md | 7 ++--- README_ZH_TW.md | 7 ++--- src/codegen/codegen.c | 55 +++++++++++++++++++++++++------------- src/parser/parser_stmt.c | 35 ++++++++++++++++++------ tests/features/test_asm_clobber.zc | 20 ++++++++++++++ 8 files changed, 103 insertions(+), 42 deletions(-) create mode 100644 tests/features/test_asm_clobber.zc (limited to 'README_ES.md') diff --git a/README.md b/README.md index 2f0832f..87f95af 100644 --- a/README.md +++ b/README.md @@ -997,12 +997,13 @@ Zen C simplifies the complex GCC constraint syntax with named bindings. // Syntax: : out(variable) : in(variable) : clobber(reg) // Uses {variable} placeholder syntax for readability -fn add(a: int, b: int) -> int { +fn add_five(x: int) -> int { let result: int; asm { - "add {result}, {a}, {b}" + "mov {x}, {result}" + "add $5, {result}" : out(result) - : in(a), in(b) + : in(x) : clobber("cc") } return result; diff --git a/README_ES.md b/README_ES.md index 2feb762..11c4d89 100644 --- a/README_ES.md +++ b/README_ES.md @@ -997,12 +997,13 @@ Zen C simplifica la compleja sintaxis de restricciones de GCC con vinculaciones // Sintaxis: : out(variable) : in(variable) : clobber(reg) // Usa la sintaxis de marcador de posición {variable} para legibilidad -fn sumar(a: int, b: int) -> int { +fn sumar(x: int) -> int { let resultado: int; asm { - "add {resultado}, {a}, {b}" + "mov {x}, {resultado}" + "add $5, {resultado}" : out(resultado) - : in(a), in(b) + : in(x) : clobber("cc") } return resultado; diff --git a/README_IT.md b/README_IT.md index ba49e46..9bf804e 100644 --- a/README_IT.md +++ b/README_IT.md @@ -993,12 +993,13 @@ Zen C semplifica la sintassi complessa dei vincoli di GCC con dei binding nomina // Sintassi: : out(variable) : in(variable) : clobber(reg) // Usa una sintassi placeholder (`{variabile}`) per la leggibilità -fn somma(a: int, b: int) -> int { +fn aggiungi_cinque(x: int) -> int { let risultato: int; asm { - "add {risultato}, {a}, {b}" + "mov {x}, {risultato}" + "add $5, {risultato}" : out(risultato) - : in(a), in(b) + : in(x) : clobber("cc") } return risultato; diff --git a/README_ZH_CN.md b/README_ZH_CN.md index 796eb66..aa1130b 100644 --- a/README_ZH_CN.md +++ b/README_ZH_CN.md @@ -996,12 +996,13 @@ Zen C 通过命名绑定简化了复杂的 GCC 约束语法。 // 语法: : out(变量) : in(变量) : clobber(寄存器) // 使用 {变量} 占位符语法以提高可读性 -fn add(a: int, b: int) -> int { +fn add_five(x: int) -> int { let result: int; asm { - "add {result}, {a}, {b}" + "mov {x}, {result}" + "add $5, {result}" : out(result) - : in(a), in(b) + : in(x) : clobber("cc") } return result; diff --git a/README_ZH_TW.md b/README_ZH_TW.md index 5b4d484..5d85a76 100644 --- a/README_ZH_TW.md +++ b/README_ZH_TW.md @@ -996,12 +996,13 @@ Zen C 通過命名綁定簡化了複雜的 GCC 約束語法。 // 語法: : out(變量) : in(變量) : clobber(寄存器) // 使用 {變量} 佔位符語法以提高可讀性 -fn add(a: int, b: int) -> int { +fn add_five(x: int) -> int { let result: int; asm { - "add {result}, {a}, {b}" + "mov {x}, {result}" + "add $5, {result}" : out(result) - : in(a), in(b) + : in(x) : clobber("cc") } return result; diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 37415c2..0496a46 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -225,8 +225,9 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) int is_basic = IS_BASIC_TYPE(t1); ASTNode *def = t1 ? find_struct_def(ctx, t1) : NULL; - - if (t1 && def && (def->type == NODE_STRUCT || def->type == NODE_ENUM) && !is_basic && !is_ptr) + + if (t1 && def && (def->type == NODE_STRUCT || def->type == NODE_ENUM) && !is_basic && + !is_ptr) { char *base = t1; if (strncmp(base, "struct ", 7) == 0) @@ -335,7 +336,10 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) codegen_expression(ctx, node->binary.right, out); fprintf(out, ")"); } - if (t1) free(t1); + if (t1) + { + free(t1); + } } else { @@ -413,7 +417,8 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) fprintf(out, ", "); } - Type *param_t = (arg_idx < sig->total_args) ? sig->arg_types[arg_idx] : NULL; + Type *param_t = + (arg_idx < sig->total_args) ? sig->arg_types[arg_idx] : NULL; if (param_t && param_t->kind == TYPE_STRUCT && strncmp(param_t->name, "Tuple_", 6) == 0 && sig->total_args == 1 && @@ -528,13 +533,13 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) { char trait_mangled[256]; snprintf(trait_mangled, sizeof(trait_mangled), "%s__%s_%s", base, - ref->node->impl_trait.trait_name, method); + ref->node->impl_trait.trait_name, method); if (find_func(ctx, trait_mangled)) { - size_t suffix_len = strlen(ref->node->impl_trait.trait_name) + - strlen(method) + 2; + size_t suffix_len = strlen(ref->node->impl_trait.trait_name) + + strlen(method) + 2; char *suffix = xmalloc(suffix_len); - snprintf(suffix, suffix_len, "%s_%s", + snprintf(suffix, suffix_len, "%s_%s", ref->node->impl_trait.trait_name, method); resolved_method_suffix = suffix; break; @@ -553,8 +558,8 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) { tname = it->impl_node->impl_trait.trait_name; char trait_mangled[512]; - snprintf(trait_mangled, sizeof(trait_mangled), - "%s__%s_%s", base, tname, method); + snprintf(trait_mangled, sizeof(trait_mangled), "%s__%s_%s", + base, tname, method); if (find_func(ctx, trait_mangled)) { size_t suffix_len = strlen(tname) + strlen(method) + 2; @@ -580,7 +585,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) for (int k = 0; k < def->strct.used_struct_count; k++) { char mixin_check[128]; - snprintf(mixin_check, sizeof(mixin_check), "%s__%s", + snprintf(mixin_check, sizeof(mixin_check), "%s__%s", def->strct.used_structs[k], method); if (find_func(ctx, mixin_check)) { @@ -611,7 +616,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) arg = arg->next; } fprintf(out, ")"); - + if (resolved_method_suffix) { free(resolved_method_suffix); @@ -621,9 +626,12 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) free(type); return; } - if (type) free(type); + if (type) + { + free(type); + } } - + if (node->call.callee->type == NODE_EXPR_VAR) { ASTNode *def = find_struct_def(ctx, node->call.callee->var_ref.name); @@ -807,8 +815,11 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) { actually_ptr = 1; } - if (lt) free(lt); - + if (lt) + { + free(lt); + } + char *field = node->member.field; if (field && field[0] >= '0' && field[0] <= '9') { @@ -831,7 +842,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) is_slice_struct = 1; } } - + if (!is_slice_struct && node->index.array->resolved_type) { if (strncmp(node->index.array->resolved_type, "Slice_", 6) == 0) @@ -847,7 +858,10 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) { is_slice_struct = 1; } - if (inferred) free(inferred); + if (inferred) + { + free(inferred); + } } if (is_slice_struct) @@ -962,7 +976,10 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) fprintf(out, "(Slice_%s){ .data = _arr + _start, .len = _len, .cap = _len }; })", tname); } - if (tname && strcmp(tname, "unknown") != 0) free(tname); + if (tname && strcmp(tname, "unknown") != 0) + { + free(tname); + } break; } case NODE_BLOCK: diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c index 0677cf5..ae16243 100644 --- a/src/parser/parser_stmt.c +++ b/src/parser/parser_stmt.c @@ -842,7 +842,7 @@ ASTNode *parse_asm(ParserContext *ctx, Lexer *l) } } - // Parse clobbers (: "eax", "memory") + // Parse clobbers (: "eax", "memory" OR : clobber("eax"), clobber("memory")) char **clobbers = NULL; int num_clobbers = 0; @@ -865,17 +865,36 @@ ASTNode *parse_asm(ParserContext *ctx, Lexer *l) continue; } - if (t.type == TOK_STRING) + // check for clobber("...") + if (t.type == TOK_IDENT && strncmp(t.start, "clobber", 7) == 0) { - lexer_next(l); - // Extract string content - char *clob = xmalloc(t.len); - strncpy(clob, t.start + 1, t.len - 2); - clob[t.len - 2] = 0; - clobbers[num_clobbers++] = clob; + lexer_next(l); // eat clobber + if (lexer_peek(l).type != TOK_LPAREN) + { + zpanic_at(lexer_peek(l), "Expected ( after clobber"); + } + lexer_next(l); // eat ( + + Token clob = lexer_next(l); + if (clob.type != TOK_STRING) + { + zpanic_at(clob, "Expected string literal for clobber"); + } + + if (lexer_peek(l).type != TOK_RPAREN) + { + zpanic_at(lexer_peek(l), "Expected ) after clobber string"); + } + lexer_next(l); // eat ) + + char *c = xmalloc(clob.len); + strncpy(c, clob.start + 1, clob.len - 2); + c[clob.len - 2] = 0; + clobbers[num_clobbers++] = c; } else { + zpanic_at(t, "Expected 'clobber(\"...\")' in clobber list"); break; } } diff --git a/tests/features/test_asm_clobber.zc b/tests/features/test_asm_clobber.zc new file mode 100644 index 0000000..2ba74da --- /dev/null +++ b/tests/features/test_asm_clobber.zc @@ -0,0 +1,20 @@ +fn add(a: int, b: int) -> int { + let result: int; + asm { + "mov {a}, {result}" + "add {b}, {result}" + : out(result) + : in(a), in(b) + : clobber("cc") + } + return result; +} + +test "asm_clobber" { + let res = add(10, 20); + if (res != 30) { + println "Failed: Expected 30, got {res}"; + exit(1); + } + println "Success: asm with clobber works properly"; +} -- cgit v1.2.3 From fbfce63744882d48ea2fc514ab1594000254db80 Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Sun, 1 Feb 2026 14:01:51 +0000 Subject: Related to #138 --- README.md | 58 +++++++++++++++++++- README_ES.md | 57 +++++++++++++++++++- README_IT.md | 55 ++++++++++++++++++- README_ZH_CN.md | 58 +++++++++++++++++++- README_ZH_TW.md | 60 ++++++++++++++++++++- src/ast/ast.c | 56 +++++++++++++++++-- src/ast/ast.h | 58 +++++++++++--------- src/codegen/codegen.c | 92 ++++++++++++++++++++++++++++++- src/codegen/codegen_decl.c | 19 +++++-- src/parser/parser_expr.c | 4 +- src/parser/parser_struct.c | 6 +-- src/parser/parser_type.c | 62 ++++++++++++++++++--- src/parser/parser_utils.c | 22 ++++++-- std/fs.zc | 53 ++++++++++-------- std/io.zc | 23 ++++---- std/net.zc | 98 +++++++++++++++++++++------------- std/process.zc | 8 +-- std/string.zc | 9 ++-- std/thread.zc | 35 ++++++------ tests/collections/test_string_suite.zc | 4 +- tests/features/test_portable_types.zc | 46 ++++++++++++++++ 21 files changed, 737 insertions(+), 146 deletions(-) create mode 100644 tests/features/test_portable_types.zc (limited to 'README_ES.md') diff --git a/README.md b/README.md index 87f95af..fc1aa27 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ Join the discussion, share demos, ask questions, or report bugs in the official - [Named Constraints](#named-constraints) - [15. Build Directives](#15-build-directives) - [16. Keywords](#16-keywords) + - [17. C Interoperability](#17-c-interoperability) - [Standard Library](#standard-library) - [Tooling](#tooling) - [Language Server (LSP)](#language-server-lsp) @@ -204,7 +205,11 @@ let y: const int = 10; // Read-only (Type qualified) | Type | C Equivalent | Description | |:---|:---|:---| -| `int`, `uint` | `int`, `unsigned int` | Platform standard integer | +| `int`, `uint` | `int32_t`, `uint32_t` | 32-bit signed/unsigned integer | +| `c_char`, `c_uchar` | `char`, `unsigned char` | C char / unsigned char (Interop) | +| `c_short`, `c_ushort` | `short`, `unsigned short` | C short / unsigned short (Interop) | +| `c_int`, `c_uint` | `int`, `unsigned int` | C int / unsigned int (Interop) | +| `c_long`, `c_ulong` | `long`, `unsigned long` | C long / unsigned long (Interop) | | `I8` .. `I128` or `i8` .. `i128` | `int8_t` .. `__int128_t` | Signed fixed-width integers | | `U8` .. `U128` or `u8` .. `u128` | `uint8_t` .. `__uint128_t` | Unsigned fixed-width integers | | `isize`, `usize` | `ptrdiff_t`, `size_t` | Pointer-sized integers | @@ -217,6 +222,12 @@ let y: const int = 10; // Read-only (Type qualified) | `iN` (for example, `i256`) | `_BitInt(N)` | Arbitrary bit-width signed integer (C23) | | `uN` (for example, `u42`) | `unsigned _BitInt(N)` | Arbitrary bit-width unsigned integer (C23) | +> **Best Practices for Portable Code** +> +> - Use **Portable Types** (`int`, `uint`, `i64`, `u8`, etc.) for all pure Zen C logic. `int` is guaranteed to be 32-bit signed on all architectures. +> - Use **C Interop Types** (`c_int`, `c_char`, `c_long`) **only** when interacting with C libraries (FFI). Their size varies by platform and C compiler (e.g. `c_long` size differs between Windows and Linux). +> - Use `isize` and `usize` for array indexing and memory pointer arithmetic. + ### 3. Aggregate Types #### Arrays @@ -1092,6 +1103,51 @@ The following identifiers are reserved because they are keywords in C11: #### Operators `and`, `or` +### 17. C Interoperability + +Zen C offers two ways to interact with C code: **Trusted Imports** (Convenient) and **Explicit FFI** (Safe/Precise). + +#### Method 1: Trusted Imports (Convenient) + +You can import a C header directly using the `import` keyword with the `.h` extension. This treats the header as a module and assumes all symbols accessed through it exist. + +```zc +//> link: -lm +import "math.h" as c_math; + +fn main() { + // Compiler trusts correctness; emits 'cos(...)' directly + let x = c_math::cos(3.14159); +} +``` + +> **Pros**: Zero boilerplate. Access everything in the header immediately. +> **Cons**: No type safety from Zen C (errors caught by C compiler later). + +#### Method 2: Explicit FFI (Safe) + +For strict type checking or when you don't want to include the text of a header, use `extern fn`. + +```zc +include // Emits #include in generated C + +// Define strict signature +extern fn printf(fmt: char*, ...) -> c_int; + +fn main() { + printf("Hello FFI: %d\n", 42); // Type checked by Zen C +} +``` + +> **Pros**: Zen C ensures types match. +> **Cons**: Requires manual declaration of functions. + +#### `import` vs `include` + +- **`import "file.h"`**: Registers the header as a named module. Enables implicit access to symbols (for example, `file::function()`). +- **`include `**: Purely emits `#include ` in the generated C code. Does not introduce any symbols to the Zen C compiler; you must use `extern fn` to access them. + + --- ## Standard Library diff --git a/README_ES.md b/README_ES.md index 11c4d89..07234f0 100644 --- a/README_ES.md +++ b/README_ES.md @@ -100,6 +100,7 @@ - [Restricciones con Nombre](#restricciones-con-nombre) - [15. Directivas de Construcción](#15-directivas-de-construcción) - [16. Palabras Clave](#16-palabras-clave) + - [17. Interoperabilidad C](#17-interoperabilidad-c) - [Biblioteca Estándar](#biblioteca-estándar) - [Herramientas](#herramientas) - [Servidor de Lenguaje (LSP)](#servidor-de-lenguaje-lsp) @@ -203,7 +204,11 @@ let y: const int = 10; // Solo lectura (Calificado por tipo) | Tipo | Equivalente en C | Descripción | |:---|:---|:---| -| `int`, `uint` | `int`, `unsigned int` | Entero estándar de la plataforma | +| `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) | | `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 | @@ -216,6 +221,12 @@ let y: const int = 10; // Solo lectura (Calificado por tipo) | `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) | +> **Mejores Prácticas para Código Portable** +> +> - Usa **Tipos Portables** (`int`, `uint`, `i64`, `u8`, etc.) para toda la lógica pura de Zen C. `int` garantiza ser 32-bits con signo en todas las arquitecturas. +> - Usa **Tipos de Interoperabilidad C** (`c_int`, `c_char`, `c_long`) **sólo** al interactuar con bibliotecas C (FFI). Su tamaño varía según la plataforma y el compilador C. +> - Usa `isize` y `usize` para indexado de arrays y aritmética de punteros. + ### 3. Tipos Agregados #### Arrays @@ -1092,6 +1103,50 @@ Los siguientes identificadores están reservados porque son palabras clave en C1 #### Operadores `and`, `or` +### 17. Interoperabilidad C +Zen C ofrece dos formas de interactuar con código C: **Importaciones de Confianza** (Conveniente) y **FFI Explícita** (Seguro/Preciso). + +#### Método 1: Importaciones de Confianza (Conveniente) + +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. + +```zc +//> 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). + +#### Método 2: FFI Explícita (Seguro) + +Para una comprobación estricta de tipos o cuando no quieres incluir el texto de una cabecera, usa `extern fn`. + +```zc +include // Emite #include 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` vs `include` + +- **`import "file.h"`**: Registra la cabecera como un módulo con nombre. Habilita el acceso implícito a símbolos (ej. `file::function()`). +- **`include `**: Puramente emite `#include ` en el código C generado. No introduce ningún símbolo al compilador de Zen C; debes usar `extern fn` para acceder a ellos. + + --- ## Biblioteca Estándar diff --git a/README_IT.md b/README_IT.md index 9bf804e..be48cda 100644 --- a/README_IT.md +++ b/README_IT.md @@ -101,6 +101,7 @@ Unisciti alla conversazione, condividi delle demo, fai domande o segnala dei bug - [Vincoli Nominati](#vincoli-nominati) - [15. Direttive della Buil](#15-direttive-della-build) - [16. Keyword](#16-keyword) + - [17. Interoperabilità C](#17-interoperabilità-c) - [Libreria Standard](#liberia-standard) - [Tooling](#tooling) - [Language Server (LSP)](#language-server-lsp) @@ -205,7 +206,11 @@ let y: const int = 10; // Sola lettura (Tipo qualificato) | Tipo | C Equivalent | Descrizione | |:---|:---|:---| -| `int`, `uint` | `int`, `unsigned int` | Intero standard della piattaforma | +| `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) | | `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 | @@ -218,6 +223,12 @@ let y: const int = 10; // Sola lettura (Tipo qualificato) | `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) | +> **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`) **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 @@ -1089,6 +1100,48 @@ Gli identifiers seguenti sono riservati poiché sono keyword nello standard C11: #### 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. + +```zc +//> 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`. + +```zc +include // Emette #include 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 `**: Emette puramente `#include ` nel codice C generato. Non introduce alcun simbolo nel compilatore Zen C; devi usare `extern fn` per accedervi. + + --- ## Libreria Standard diff --git a/README_ZH_CN.md b/README_ZH_CN.md index aa1130b..af83e8c 100644 --- a/README_ZH_CN.md +++ b/README_ZH_CN.md @@ -100,6 +100,7 @@ - [命名约束](#命名约束) - [15. 构建指令](#15-构建指令) - [16. 关键字](#16-关键字) + - [17. C 互操作性](#17-c-互操作性) - [标准库](#标准库) - [工具链](#工具链) - [语言服务器 (LSP)](#语言服务器-lsp) @@ -203,7 +204,11 @@ let y: const int = 10; // 只读 (类型修饰) | 类型 | C 等效类型 | 描述 | |:---|:---|:---| -| `int`, `uint` | `int`, `unsigned int` | 平台标准整数 | +| `int`, `uint` | `int32_t`, `uint32_t` | 32位有符号/无符号整数 | +| `c_char`, `c_uchar` | `char`, `unsigned char` | C char (互操作) | +| `c_short`, `c_ushort` | `short`, `unsigned short` | C short (互操作) | +| `c_int`, `c_uint` | `int`, `unsigned int` | C int (互操作) | +| `c_long`, `c_ulong` | `long`, `unsigned long` | C long (互操作) | | `I8` .. `I128` 或 `i8` .. `i128` | `int8_t` .. `__int128_t` | 有符号固定宽度整数 | | `U8` .. `U128` 或 `u8` .. `u128` | `uint8_t` .. `__uint128_t` | 无符号固定宽度整数 | | `isize`, `usize` | `ptrdiff_t`, `size_t` | 指针大小的整数 | @@ -216,6 +221,12 @@ let y: const int = 10; // 只读 (类型修饰) | `iN` (例 `i256`) | `_BitInt(N)` | 任意位宽有符号整数 (C23) | | `uN` (例 `u42`) | `unsigned _BitInt(N)` | 任意位宽无符号整数 (C23) | +> **可移植代码最佳实践** +> +> - 对于所有纯 Zen C 逻辑,请使用 **可移植类型** (`int`、`uint`、`i64`、`u8` 等)。`int` 保证在所有架构上都是 32 位有符号整数。 +> - 仅在与 C 库 (FFI) 交互时使用 **C 互操作类型** (`c_int`、`c_char`、`c_long`)。它们的大小因平台和 C 编译器而异。 +> - 使用 `isize` 和 `usize` 进行数组索引和内存指针运算。 + ### 3. 复合类型 #### 数组 @@ -1091,6 +1102,51 @@ fn main() { ... } #### 运算符 `and`, `or` +### 17. C 互操作性 + +Zen C 提供了两种与 C 代码交互的方式:**信任导入 (Trusted Imports)** (方便) 和 **显式 FFI** (安全/精确)。 + +#### 方法 1: 信任导入 (方便) + +你可以使用 `import` 关键字直接导入 `.h` 扩展名的 C 头文件。这会将头文件视为一个模块,并假设通过它访问的所有符号都存在。 + +```zc +//> link: -lm +import "math.h" as c_math; + +fn main() { + // 编译器信任不仅正确;直接生成 'cos(...)' + let x = c_math::cos(3.14159); +} +``` + +> **优点**: 零样板代码。立即访问头文件中的所有内容。 +> **缺点**: Zen C 不提供类型安全 (错误将在稍后由 C 编译器捕获)。 + +#### 方法 2: 显式 FFI (安全) + +对于严格的类型检查,或当你不想包含头文件文本时,请使用 `extern fn`. + +```zc +include // 在生成的 C 代码中发出 #include + +// 定义严格签名 +extern fn printf(fmt: char*, ...) -> c_int; + +fn main() { + printf("Hello FFI: %d\n", 42); // 由 Zen C 进行类型检查 +} +``` + +> **优点**: Zen C 确保类型匹配。 +> **缺点**: 需要手动声明函数。 + +#### `import` vs `include` + +- **`import "file.h"`**: 将头文件注册为命名模块。启用对符号的隐式访问 (例如 `file::function()`)。 +- **`include `**: 纯粹在生成的 C 代码中发出 `#include `。不向 Zen C 编译器引入任何符号;必须使用 `extern fn` 才能访问它们。 + + --- ## 标准库 diff --git a/README_ZH_TW.md b/README_ZH_TW.md index 5d85a76..3a18a53 100644 --- a/README_ZH_TW.md +++ b/README_ZH_TW.md @@ -100,6 +100,7 @@ - [命名約束](#命名約束) - [15. 構建指令](#15-構建指令) - [16. 關鍵字](#16-關鍵字) + - [17. C 互操作性](#17-c-互操作性) - [標準庫](#標準庫) - [工具鏈](#工具鏈) - [語言服務器 (LSP)](#語言服務器-lsp) @@ -203,7 +204,11 @@ let y: const int = 10; // 只讀 (類型修飾) | 類型 | C 等效類型 | 描述 | |:---|:---|:---| -| `int`, `uint` | `int`, `unsigned int` | 平台標準整數 | +| `int`, `uint` | `int32_t`, `uint32_t` | 32位元有號/無號整數 | +| `c_char`, `c_uchar` | `char`, `unsigned char` | C char (互操作) | +| `c_short`, `c_ushort` | `short`, `unsigned short` | C short (互操作) | +| `c_int`, `c_uint` | `int`, `unsigned int` | C int (互操作) | +| `c_long`, `c_ulong` | `long`, `unsigned long` | C long (互操作) | | `I8` .. `I128` 或 `i8` .. `i128` | `int8_t` .. `__int128_t` | 有符號固定寬度整數 | | `U8` .. `U128` 或 `u8` .. `u128` | `uint8_t` .. `__uint128_t` | 無符號固定寬度整數 | | `isize`, `usize` | `ptrdiff_t`, `size_t` | 指針大小的整數 | @@ -214,7 +219,13 @@ let y: const int = 10; // 只讀 (類型修飾) | `string` | `char*` | C-string (以 null 結尾) | | `U0`, `u0`, `void` | `void` | 空類型 | | `iN` (例 `i256`) | `_BitInt(N)` | 任意位元寬度有號整數 (C23) | -| `uN` (例 `u42`) | `unsigned _BitInt(N)` | 任意位元寬度無號整數 (C23) | +| `uN` (例 `u42`) | `unsigned _BitInt(N)` | 任意位寬無號整數 (C23) | + +> **可移植代碼最佳實踐** +> +> - 對於所有純 Zen C 邏輯,請使用 **可移植類型** (`int`、`uint`、`i64`、`u8` 等)。`int` 保證在所有架構上都是 32 位元有號整數。 +> - 僅在與 C 庫 (FFI) 交互時使用 **C 互操作類型** (`c_int`、`c_char`、`c_long`)。它們的大小因平台和 C 編譯器而異。 +> - 使用 `isize` 和 `usize` 進行數組索引和內存指針運算。 ### 3. 複合類型 @@ -1091,6 +1102,51 @@ fn main() { ... } #### 運算符 `and`, `or` +### 17. C 互操作性 + +Zen C 提供了兩種與 C 代碼交互的方式:**信任導入 (Trusted Imports)** (方便) 和 **顯式 FFI** (安全/精確)。 + +#### 方法 1: 信任導入 (方便) + +你可以使用 `import` 關鍵字直接導入 `.h` 擴展名的 C 頭文件。這會將頭文件視為一個模塊,並假設通過它訪問的所有符號都存在。 + +```zc +//> link: -lm +import "math.h" as c_math; + +fn main() { + // 編譯器信任不僅正確;直接生成 'cos(...)' + let x = c_math::cos(3.14159); +} +``` + +> **優點**: 零樣板代碼。立即訪問頭文件中的所有內容。 +> **缺點**: Zen C 不提供類型安全 (錯誤將在稍後由 C 編譯器捕獲)。 + +#### 方法 2: 顯式 FFI (安全) + +對於嚴格的類型檢查,或當你不想包含頭文件文本時,請使用 `extern fn`. + +```zc +include // 在生成的 C 代碼中發出 #include + +// 定義嚴格簽名 +extern fn printf(fmt: char*, ...) -> c_int; + +fn main() { + printf("Hello FFI: %d\n", 42); // 由 Zen C 進行類型檢查 +} +``` + +> **優點**: Zen C 確保類型匹配。 +> **缺點**: 需要手動聲明函數。 + +#### `import` vs `include` + +- **`import "file.h"`**: 將頭文件註冊為命名模塊。啟用對符號的隱式訪問 (例如 `file::function()`)。 +- **`include `**: 純粹在生成的 C 代碼中發出 `#include `。不向 Zen C 編譯器引入任何符號;必須使用 `extern fn` 才能訪問它們。 + + --- ## 標準庫 diff --git a/src/ast/ast.c b/src/ast/ast.c index 439a9f5..1b35500 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -259,6 +259,25 @@ static char *type_to_string_impl(Type *t) return xstrdup("int32_t"); case TYPE_UINT: return xstrdup("unsigned int"); + + // Portable C Types + case TYPE_C_INT: + return xstrdup("c_int"); + case TYPE_C_UINT: + return xstrdup("c_uint"); + case TYPE_C_LONG: + return xstrdup("c_long"); + case TYPE_C_ULONG: + return xstrdup("c_ulong"); + case TYPE_C_SHORT: + return xstrdup("c_short"); + case TYPE_C_USHORT: + return xstrdup("c_ushort"); + case TYPE_C_CHAR: + return xstrdup("c_char"); + case TYPE_C_UCHAR: + return xstrdup("c_uchar"); + case TYPE_INT: return xstrdup("int"); case TYPE_FLOAT: @@ -461,8 +480,29 @@ static char *type_to_c_string_impl(Type *t) return xstrdup("int32_t"); case TYPE_UINT: return xstrdup("unsigned int"); - case TYPE_INT: + + // Portable C Types (Map directly to C types) + case TYPE_C_INT: return xstrdup("int"); + case TYPE_C_UINT: + return xstrdup("unsigned int"); + case TYPE_C_LONG: + return xstrdup("long"); + case TYPE_C_ULONG: + return xstrdup("unsigned long"); + case TYPE_C_SHORT: + return xstrdup("short"); + case TYPE_C_USHORT: + return xstrdup("unsigned short"); + case TYPE_C_CHAR: + return xstrdup("char"); + case TYPE_C_UCHAR: + return xstrdup("unsigned char"); + + case TYPE_INT: + // 'int' in Zen C maps to 'i32' now for portability. + // FFI should use c_int. + return xstrdup("int32_t"); case TYPE_FLOAT: return xstrdup("float"); case TYPE_BITINT: @@ -519,8 +559,11 @@ static char *type_to_c_string_impl(Type *t) return res; } - char *res = xmalloc(strlen(inner) + 7); - sprintf(res, "Slice_%s", inner); + char *inner_zens = type_to_string(t->inner); + char *res = xmalloc(strlen(inner_zens) + 7); + sprintf(res, "Slice_%s", inner_zens); + free(inner_zens); + free(inner); return res; } @@ -561,7 +604,12 @@ static char *type_to_c_string_impl(Type *t) return xstrdup("z_closure_T"); case TYPE_GENERIC: - return xstrdup(t->name); + // Use type_to_string to get the mangled name (e.g. Option_int) instead of raw C string + // composition This ensures consistency with struct definitions. + { + char *s = type_to_string(t); + return s; + } case TYPE_ALIAS: return type_to_c_string(t->inner); diff --git a/src/ast/ast.h b/src/ast/ast.h index 4498d7c..fa67043 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -28,30 +28,40 @@ typedef enum */ typedef enum { - TYPE_VOID, ///< `void` type. - TYPE_BOOL, ///< `bool` type. - TYPE_CHAR, ///< `char` type. - TYPE_STRING, ///< `string` type. - TYPE_U0, ///< `u0` type. - TYPE_I8, ///< `i8` type. - TYPE_U8, ///< `u8` type. - TYPE_I16, ///< `i16` type. - TYPE_U16, ///< `u16` type. - TYPE_I32, ///< `i32` type. - TYPE_U32, ///< `u32` type. - TYPE_I64, ///< `i64` type. - TYPE_U64, ///< `u64` type. - TYPE_I128, ///< `i128` type. - TYPE_U128, ///< `u128` type. - TYPE_F32, ///< `f32` type. - TYPE_F64, ///< `f64` type. - TYPE_INT, ///< `int` (alias, usually i32). - TYPE_FLOAT, ///< `float` (alias). - TYPE_USIZE, ///< `usize` (pointer size unsigned). - TYPE_ISIZE, ///< `isize` (pointer size signed). - TYPE_BYTE, ///< `byte`. - TYPE_RUNE, ///< `rune`. - TYPE_UINT, ///< `uint` (alias). + TYPE_VOID, ///< `void` type. + TYPE_BOOL, ///< `bool` type. + TYPE_CHAR, ///< `char` type. + TYPE_STRING, ///< `string` type. + TYPE_U0, ///< `u0` type. + TYPE_I8, ///< `i8` type. + TYPE_U8, ///< `u8` type. + TYPE_I16, ///< `i16` type. + TYPE_U16, ///< `u16` type. + TYPE_I32, ///< `i32` type. + TYPE_U32, ///< `u32` type. + TYPE_I64, ///< `i64` type. + TYPE_U64, ///< `u64` type. + TYPE_I128, ///< `i128` type. + TYPE_U128, ///< `u128` type. + TYPE_F32, ///< `f32` type. + TYPE_F64, ///< `f64` type. + TYPE_INT, ///< `int` (alias, usually i32). + TYPE_FLOAT, ///< `float` (alias). + TYPE_USIZE, ///< `usize` (pointer size unsigned). + TYPE_ISIZE, ///< `isize` (pointer size signed). + TYPE_BYTE, ///< `byte`. + TYPE_RUNE, ///< `rune`. + TYPE_UINT, ///< `uint` (alias). + // Portable C Types (FFI) + TYPE_C_INT, ///< `c_int` (int). + TYPE_C_UINT, ///< `c_uint` (unsigned int). + TYPE_C_LONG, ///< `c_long` (long). + TYPE_C_ULONG, ///< `c_ulong` (unsigned long). + TYPE_C_SHORT, ///< `c_short` (short). + TYPE_C_USHORT, ///< `c_ushort` (unsigned short). + TYPE_C_CHAR, ///< `c_char` (char). + TYPE_C_UCHAR, ///< `c_uchar` (unsigned char). + TYPE_STRUCT, ///< Struct type. TYPE_ENUM, ///< Enum type. TYPE_POINTER, ///< Pointer type (*). diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 0496a46..384820b 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -1150,14 +1150,102 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) break; } case NODE_EXPR_CAST: - fprintf(out, "((%s)(", node->cast.target_type); + { + const char *t = node->cast.target_type; + const char *mapped = t; + if (strcmp(t, "c_int") == 0) + { + mapped = "int"; + } + else if (strcmp(t, "c_uint") == 0) + { + mapped = "unsigned int"; + } + else if (strcmp(t, "c_long") == 0) + { + mapped = "long"; + } + else if (strcmp(t, "c_ulong") == 0) + { + mapped = "unsigned long"; + } + else if (strcmp(t, "c_short") == 0) + { + mapped = "short"; + } + else if (strcmp(t, "c_ushort") == 0) + { + mapped = "unsigned short"; + } + else if (strcmp(t, "c_char") == 0) + { + mapped = "char"; + } + else if (strcmp(t, "c_uchar") == 0) + { + mapped = "unsigned char"; + } + else if (strcmp(t, "int") == 0) + { + mapped = "int32_t"; + } + else if (strcmp(t, "uint") == 0) + { + mapped = "unsigned int"; + } + + fprintf(out, "((%s)(", mapped); codegen_expression(ctx, node->cast.expr, out); fprintf(out, "))"); break; + } case NODE_EXPR_SIZEOF: if (node->size_of.target_type) { - fprintf(out, "sizeof(%s)", node->size_of.target_type); + const char *t = node->size_of.target_type; + const char *mapped = t; + if (strcmp(t, "c_int") == 0) + { + mapped = "int"; + } + else if (strcmp(t, "c_uint") == 0) + { + mapped = "unsigned int"; + } + else if (strcmp(t, "c_long") == 0) + { + mapped = "long"; + } + else if (strcmp(t, "c_ulong") == 0) + { + mapped = "unsigned long"; + } + else if (strcmp(t, "c_short") == 0) + { + mapped = "short"; + } + else if (strcmp(t, "c_ushort") == 0) + { + mapped = "unsigned short"; + } + else if (strcmp(t, "c_char") == 0) + { + mapped = "char"; + } + else if (strcmp(t, "c_uchar") == 0) + { + mapped = "unsigned char"; + } + else if (strcmp(t, "int") == 0) + { + mapped = "int32_t"; // Strict mapping + } + else if (strcmp(t, "uint") == 0) + { + mapped = "unsigned int"; // uint alias + } + + fprintf(out, "sizeof(%s)", mapped); } else { diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c index 31bd2ee..1623ffc 100644 --- a/src/codegen/codegen_decl.c +++ b/src/codegen/codegen_decl.c @@ -1130,12 +1130,23 @@ void print_type_defs(ParserContext *ctx, FILE *out, ASTNode *nodes) fprintf(out, "typedef struct Tuple_%s Tuple_%s;\nstruct Tuple_%s { ", t->sig, t->sig, t->sig); char *s = xstrdup(t->sig); - char *p = strtok(s, "_"); + char *current = s; + char *next_sep = strstr(current, "__"); int i = 0; - while (p) + while (current) { - fprintf(out, "%s v%d; ", p, i++); - p = strtok(NULL, "_"); + if (next_sep) + { + *next_sep = 0; + fprintf(out, "%s v%d; ", current, i++); + current = next_sep + 2; + next_sep = strstr(current, "__"); + } + else + { + fprintf(out, "%s v%d; ", current, i++); + break; + } } free(s); fprintf(out, "};\n"); diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c index 7c53d96..5bf0089 100644 --- a/src/parser/parser_expr.c +++ b/src/parser/parser_expr.c @@ -1908,7 +1908,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) { Type *formal_type = parse_type_formal(ctx, l); concrete_types[arg_count] = type_to_string(formal_type); - unmangled_types[arg_count] = type_to_c_string(formal_type); + unmangled_types[arg_count] = type_to_string(formal_type); arg_count++; if (lexer_peek(l).type == TOK_COMMA) @@ -2944,7 +2944,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) { if (i > 0) { - strcat(sig, "_"); + strcat(sig, "__"); } strcat(sig, type_strs[i]); } diff --git a/src/parser/parser_struct.c b/src/parser/parser_struct.c index e53b56c..c89ad34 100644 --- a/src/parser/parser_struct.c +++ b/src/parser/parser_struct.c @@ -863,7 +863,7 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union, int is_opaque) Token field_name = lexer_next(l); lexer_next(l); // eat : Type *ft = parse_type_formal(ctx, l); - char *field_type_str = type_to_string(ft); + char *field_type_str = type_to_c_string(ft); expect(l, TOK_SEMICOLON, "Expected ;"); ASTNode *nf = ast_create(NODE_FIELD); @@ -947,7 +947,7 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union, int is_opaque) Token f_name = lexer_next(l); expect(l, TOK_COLON, "Expected :"); Type *ft = parse_type_formal(ctx, l); - char *f_type = type_to_string(ft); + char *f_type = type_to_c_string(ft); ASTNode *f = ast_create(NODE_FIELD); f->field.name = token_strdup(f_name); @@ -1120,7 +1120,7 @@ ASTNode *parse_enum(ParserContext *ctx, Lexer *l) while (lexer_peek(l).type == TOK_COMMA) { lexer_next(l); // eat , - strcat(sig, "_"); + strcat(sig, "__"); Type *next_t = parse_type_obj(ctx, l); char *ns = type_to_string(next_t); if (strlen(sig) + strlen(ns) + 2 > 510) diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c index 49e961c..fcbe12d 100644 --- a/src/parser/parser_type.c +++ b/src/parser/parser_type.c @@ -427,13 +427,13 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l) if (strcmp(name, "uint") == 0) { free(name); - return type_new(TYPE_UINT); + return type_new(TYPE_U32); // Strict uint32_t } if (strcmp(name, "int") == 0) { free(name); - return type_new(TYPE_INT); + return type_new(TYPE_I32); // Strict int32_t } if (strcmp(name, "float") == 0) { @@ -467,23 +467,31 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l) } if (strcmp(name, "long") == 0) { + zwarn_at(t, "'long' is treated as portable 'int64_t' in Zen C. Use 'c_long' for " + "platform-dependent C long."); free(name); return type_new(TYPE_I64); } if (strcmp(name, "short") == 0) { + zwarn_at(t, "'short' is treated as portable 'int16_t' in Zen C. Use 'c_short' for " + "platform-dependent C short."); free(name); return type_new(TYPE_I16); } if (strcmp(name, "unsigned") == 0) { + zwarn_at(t, "'unsigned' is treated as portable 'uint32_t' in Zen C. Use 'c_uint' for " + "platform-dependent C unsigned int."); free(name); - return type_new(TYPE_UINT); + return type_new(TYPE_U32); } if (strcmp(name, "signed") == 0) { + zwarn_at(t, "'signed' is treated as portable 'int32_t' in Zen C. Use 'c_int' for " + "platform-dependent C int."); free(name); - return type_new(TYPE_INT); + return type_new(TYPE_I32); } if (strcmp(name, "int8_t") == 0) { @@ -536,6 +544,48 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l) return type_new(TYPE_ISIZE); } + // Portable C Types + if (strcmp(name, "c_int") == 0) + { + free(name); + return type_new(TYPE_C_INT); + } + if (strcmp(name, "c_uint") == 0) + { + free(name); + return type_new(TYPE_C_UINT); + } + if (strcmp(name, "c_long") == 0) + { + free(name); + return type_new(TYPE_C_LONG); + } + if (strcmp(name, "c_ulong") == 0) + { + free(name); + return type_new(TYPE_C_ULONG); + } + if (strcmp(name, "c_short") == 0) + { + free(name); + return type_new(TYPE_C_SHORT); + } + if (strcmp(name, "c_ushort") == 0) + { + free(name); + return type_new(TYPE_C_USHORT); + } + if (strcmp(name, "c_char") == 0) + { + free(name); + return type_new(TYPE_C_CHAR); + } + if (strcmp(name, "c_uchar") == 0) + { + free(name); + return type_new(TYPE_C_UCHAR); + } + // Relaxed Type Check: If explicit 'struct Name', trust the user. if (explicit_struct) { @@ -677,7 +727,7 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l) zpanic_at(t, "Expected > after generic"); } - char *unmangled_arg = type_to_c_string(first_arg); + char *unmangled_arg = type_to_string(first_arg); int is_single_dep = 0; for (int k = 0; k < ctx->known_generics_count; ++k) @@ -791,7 +841,7 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l) if (lexer_peek(l).type == TOK_COMMA) { lexer_next(l); - strcat(sig, "_"); + strcat(sig, "__"); } else { diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c index 28d2c11..8ea2934 100644 --- a/src/parser/parser_utils.c +++ b/src/parser/parser_utils.c @@ -691,16 +691,22 @@ void register_tuple(ParserContext *ctx, const char *sig) s_def->strct.name = xstrdup(struct_name); char *s_sig = xstrdup(sig); - char *tok = strtok(s_sig, "_"); + char *current = s_sig; + char *next_sep = strstr(current, "__"); ASTNode *head = NULL, *tail = NULL; int i = 0; - while (tok) + while (current) { + if (next_sep) + { + *next_sep = 0; + } + ASTNode *f = ast_create(NODE_FIELD); char fname[32]; sprintf(fname, "v%d", i++); f->field.name = xstrdup(fname); - f->field.type = xstrdup(tok); + f->field.type = xstrdup(current); if (!head) { @@ -712,7 +718,15 @@ void register_tuple(ParserContext *ctx, const char *sig) } tail = f; - tok = strtok(NULL, "_"); + if (next_sep) + { + current = next_sep + 2; + next_sep = strstr(current, "__"); + } + else + { + break; + } } free(s_sig); s_def->strct.fields = head; diff --git a/std/fs.zc b/std/fs.zc index a00993b..5b2cb21 100644 --- a/std/fs.zc +++ b/std/fs.zc @@ -15,9 +15,9 @@ include include // Direct externs for simple functions with const char* parameters -extern fn access(pathname: const char*, mode: int) -> int; -extern fn unlink(pathname: const char*) -> int; -extern fn rmdir(pathname: const char*) -> int; +extern fn access(pathname: const char*, mode: c_int) -> c_int; +extern fn unlink(pathname: const char*) -> c_int; +extern fn rmdir(pathname: const char*) -> c_int; extern fn malloc(size: usize) -> void*; extern fn free(ptr: void*); @@ -90,17 +90,17 @@ raw { } } -extern fn _z_fs_mkdir(path: const char*) -> int; -extern fn _z_fs_get_metadata(path: const char*, size: U64*, is_dir: int*, is_file: int*) -> int; -extern fn _z_fs_read_entry(dir: void*, out_name: char*, buf_size: int, is_dir: int*) -> int; +extern fn _z_fs_mkdir(path: const char*) -> c_int; +extern fn _z_fs_get_metadata(path: const char*, size: U64*, is_dir: c_int*, is_file: c_int*) -> c_int; +extern fn _z_fs_read_entry(dir: void*, out_name: char*, buf_size: c_int, is_dir: c_int*) -> c_int; extern fn _z_fs_fopen(path: const char*, mode: const char*) -> void*; -extern fn _z_fs_fclose(stream: void*) -> int; +extern fn _z_fs_fclose(stream: void*) -> c_int; extern fn _z_fs_fread(ptr: void*, size: usize, nmemb: usize, stream: void*) -> usize; extern fn _z_fs_fwrite(ptr: void*, size: usize, nmemb: usize, stream: void*) -> usize; -extern fn _z_fs_fseek(stream: void*, offset: I64, whence: int) -> int; +extern fn _z_fs_fseek(stream: void*, offset: I64, whence: c_int) -> c_int; extern fn _z_fs_ftell(stream: void*) -> I64; extern fn _z_fs_opendir(name: const char*) -> void*; -extern fn _z_fs_closedir(dir: void*) -> int; +extern fn _z_fs_closedir(dir: void*) -> c_int; struct File { @@ -191,41 +191,50 @@ impl File { } fn exists(path: char*) -> bool { - return access(path, Z_F_OK) == 0; + let zero: c_int = 0; + return access(path, Z_F_OK) == zero; } fn metadata(path: char*) -> Result { let size: uint64_t; - let is_d: int; - let is_f: int; + let is_d: c_int; + let is_f: c_int; - if (_z_fs_get_metadata(path, &size, &is_d, &is_f) != 0) { + let res = _z_fs_get_metadata(path, &size, &is_d, &is_f); + let non_zero: c_int = 0; + if (res != non_zero) { return Result::Err("Failed to get metadata"); } return Result::Ok(Metadata { size: (U64)size, - is_dir: is_d != 0, - is_file: is_f != 0 + is_dir: is_d != non_zero, + is_file: is_f != non_zero }); } fn create_dir(path: char*) -> Result { - if (_z_fs_mkdir(path) != 0) { + let res = _z_fs_mkdir(path); + let zero: c_int = 0; + if (res != zero) { return Result::Err("Failed to create directory"); } return Result::Ok(true); } fn remove_file(path: char*) -> Result { - if (unlink(path) != 0) { + let res = unlink(path); + let zero: c_int = 0; + if (res != zero) { return Result::Err("Failed to remove file"); } return Result::Ok(true); } fn remove_dir(path: char*) -> Result { - if (rmdir(path) != 0) { + let res = rmdir(path); + let zero: c_int = 0; + if (res != zero) { return Result::Err("Failed to remove directory"); } return Result::Ok(true); @@ -245,17 +254,19 @@ impl File { return Result< Vec >::Err("Out of memory"); } - let is_d: int = 0; + let is_d: c_int = 0; + let is_d_zero: c_int = 0; while (_z_fs_read_entry(dir, name_buf, 256, &is_d)) { - if (strcmp(name_buf, ".") == 0 || strcmp(name_buf, "..") == 0) { + let zero_cmp: c_int = 0; + if (strcmp(name_buf, ".") == zero_cmp || strcmp(name_buf, "..") == zero_cmp) { continue; } let s = String::new(name_buf); let ent = DirEntry { name: s, - is_dir: is_d != 0 + is_dir: is_d != is_d_zero }; // Transfer ownership: String -> DirEntry diff --git a/std/io.zc b/std/io.zc index a5a7359..d9829dd 100644 --- a/std/io.zc +++ b/std/io.zc @@ -6,11 +6,11 @@ include include // These work directly with const char* in extern declarations -extern fn vprintf(fmt: const char*, ap: va_list) -> int; +extern fn vprintf(fmt: const char*, ap: va_list) -> c_int; // vsnprintf is problematic on macOS because it's a macro that expands to a builtin with a different signature // so we wrap it in a C function to avoid the conflict -extern fn _z_vsnprintf(str: char*, size: usize, fmt: const char*, ap: va_list) -> int; +extern fn _z_vsnprintf(str: char*, size: usize, fmt: const char*, ap: va_list) -> c_int; // EOF is typically -1, but we define it for portability def Z_EOF = -1; @@ -27,7 +27,7 @@ raw { } extern fn _z_get_stdin() -> void*; -extern fn _z_fgetc(stream: void*) -> int; +extern fn _z_fgetc(stream: void*) -> c_int; fn format(fmt: char*, ...) -> char* { static let buffer: char[1024]; @@ -40,7 +40,7 @@ fn format(fmt: char*, ...) -> char* { return (char*)buffer; } -fn format_into(buffer: char*, size: usize, fmt: char*, ...) -> int { +fn format_into(buffer: char*, size: usize, fmt: char*, ...) -> c_int { let ap: va_list; va_start(ap, fmt); @@ -63,7 +63,7 @@ fn format_new(fmt: char*, ...) -> char* { return buffer; } -fn print(fmt: char*, ...) -> int { +fn print(fmt: char*, ...) -> c_int { let ap: va_list; va_start(ap, fmt); let ret = vprintf(fmt, ap); @@ -71,7 +71,7 @@ fn print(fmt: char*, ...) -> int { return ret; } -fn println(fmt: char*, ...) -> int { +fn println(fmt: char*, ...) -> c_int { let ap: va_list; va_start(ap, fmt); let ret = vprintf(fmt, ap); @@ -86,13 +86,15 @@ fn readln() -> char* { let line: char* = malloc(cap); if (line == NULL) return NULL; - let c: int; + let c: c_int; let std_in = _z_get_stdin(); while (true) { c = _z_fgetc(std_in); - if (c == Z_EOF) break; - if (c == 10) break; // '\n' + let eof_c: c_int = Z_EOF; + if (c == eof_c) break; + let nl_c: c_int = 10; + if (c == nl_c) break; // '\n' if (len + 1 >= cap) { cap = cap * 2; @@ -108,7 +110,8 @@ fn readln() -> char* { len = len + 1; } - if (len == 0 && c == Z_EOF) { + let eof_final: c_int = Z_EOF; + if (len == 0 && c == eof_final) { free(line); return NULL; } diff --git a/std/net.zc b/std/net.zc index 826b795..dce1a01 100644 --- a/std/net.zc +++ b/std/net.zc @@ -14,9 +14,9 @@ def Z_AF_INET = 2; def Z_SOCK_STREAM = 1; // Direct externs for simple socket functions -extern fn socket(domain: int, type: int, proto: int) -> int; -extern fn close(fd: int) -> int; -extern fn read(fd: int, buf: void*, count: usize) -> isize; +extern fn socket(domain: c_int, type: c_int, proto: c_int) -> c_int; +extern fn close(fd: c_int) -> c_int; +extern fn read(fd: c_int, buf: void*, count: usize) -> isize; // Minimal raw block: required for struct sockaddr_in usage // These functions encapsulate sockaddr_in setup because the struct layout @@ -56,47 +56,63 @@ raw { } } -extern fn _z_net_bind(fd: int, host: const char*, port: int) -> int; -extern fn _z_net_connect(fd: int, host: const char*, port: int) -> int; -extern fn _z_net_accept(fd: int) -> int; -extern fn _z_net_write(fd: int, buf: const char*, n: usize) -> isize; +extern fn _z_net_bind(fd: c_int, host: const char*, port: c_int) -> c_int; +extern fn _z_net_connect(fd: c_int, host: const char*, port: c_int) -> c_int; +extern fn _z_net_accept(fd: c_int) -> c_int; +extern fn _z_net_write(fd: c_int, buf: const char*, n: usize) -> isize; struct TcpStream { - handle: int; + handle: c_int; } -extern fn strerror(errnum: int) -> char*; +extern fn strerror(errnum: c_int) -> char*; impl TcpStream { fn read(self, buf: char*, len: usize) -> Result { let n = read(self.handle - 1, (void*)buf, len); - if (n < 0) return Result::Err(strerror(errno)); + let zero: c_int = 0; + if (n < (isize)zero) return Result::Err(strerror(errno)); return Result::Ok((usize)n); } - fn write(self, buf: char*, len: usize) -> Result { - let n = _z_net_write(self.handle - 1, buf, len); - if (n < 0) return Result::Err("Write failed"); + fn write(self, buf: u8*, len: usize) -> Result { + let one: c_int = 1; + let n: isize = _z_net_write(self.handle - one, buf, len); + let zero: isize = 0; + if (n < zero) return Result::Err("Write failed"); return Result::Ok((usize)n); } fn close(self) { - if (self.handle > 0) { - close(self.handle - 1); - self.handle = 0; + let zero: c_int = 0; + if (self.handle > zero) { + let one: c_int = 1; + close(self.handle - one); + self.handle = zero; } } - fn connect(host: char*, port: int) -> Result { - let fd = socket(Z_AF_INET, Z_SOCK_STREAM, 0); - if (fd < 0) return Result::Err("Failed to create socket"); + fn connect(host: char*, port: c_int) -> Result { + let zero: c_int = 0; + let fd = socket(Z_AF_INET, Z_SOCK_STREAM, zero); + if (fd < zero) return Result::Err("Failed to create socket"); + + // C constants like -1 + let neg_one: c_int = -1; let res = _z_net_connect(fd, host, port); - if (res == -1) { close(fd); return Result::Err("Invalid address"); } - if (res == -2) { close(fd); return Result::Err("Connection failed"); } + if (res == neg_one) { close(fd); return Result::Err("Invalid address"); } + // _z_net_connect might return -2? The original code had it. + // Assuming -2 is also possible... check implementation or just assume logic was correct. + // But wait, the original code had: + // if (res == -1) ... if (res == -2) ... + // I will keep it but cast strict. + let neg_two: c_int = -2; + if (res == neg_two) { close(fd); return Result::Err("Connection failed"); } - return Result::Ok(TcpStream { handle: fd + 1 }); + let one: c_int = 1; + return Result::Ok(TcpStream { handle: fd + one }); } } @@ -107,32 +123,42 @@ impl Drop for TcpStream { } struct TcpListener { - handle: int; + handle: c_int; } impl TcpListener { - fn bind(host: char*, port: int) -> Result { - let fd = socket(Z_AF_INET, Z_SOCK_STREAM, 0); - if (fd < 0) return Result::Err("Failed to create socket"); + fn bind(host: char*, port: c_int) -> Result { + let zero: c_int = 0; + let fd = socket(Z_AF_INET, Z_SOCK_STREAM, zero); + if (fd < zero) return Result::Err("Failed to create socket"); let res = _z_net_bind(fd, host, port); - if (res == -1) { close(fd); return Result::Err("Invalid address"); } - if (res == -2) { close(fd); return Result::Err("Bind failed"); } - if (res == -3) { close(fd); return Result::Err("Listen failed"); } + let neg_one: c_int = -1; + let neg_two: c_int = -2; + let neg_three: c_int = -3; + + if (res == neg_one) { close(fd); return Result::Err("Invalid address"); } + if (res == neg_two) { close(fd); return Result::Err("Bind failed"); } + if (res == neg_three) { close(fd); return Result::Err("Listen failed"); } - return Result::Ok(TcpListener { handle: fd + 1 }); + let one: c_int = 1; + return Result::Ok(TcpListener { handle: fd + one }); } fn accept(self) -> Result { - let client_fd = _z_net_accept(self.handle - 1); - if (client_fd < 0) return Result::Err("Accept failed"); - return Result::Ok(TcpStream { handle: client_fd + 1 }); + let one: c_int = 1; + let client_fd = _z_net_accept(self.handle - one); + let zero: c_int = 0; + if (client_fd < zero) return Result::Err("Accept failed"); + return Result::Ok(TcpStream { handle: client_fd + one }); } fn close(self) { - if (self.handle > 0) { - close(self.handle - 1); - self.handle = 0; + let zero: c_int = 0; + if (self.handle > zero) { + let one: c_int = 1; + close(self.handle - one); + self.handle = zero; } } } diff --git a/std/process.zc b/std/process.zc index 3ce43b6..9f432c0 100644 --- a/std/process.zc +++ b/std/process.zc @@ -9,7 +9,7 @@ include include // system() can be externed directly with const char* -extern fn system(command: const char*) -> int; +extern fn system(command: const char*) -> c_int; // Minimal raw block: only for opaque FILE* types // popen/pclose/fgets use FILE* which conflicts with void* @@ -28,8 +28,8 @@ raw { } extern fn _z_popen(command: const char*, type: const char*) -> void*; -extern fn _z_pclose(stream: void*) -> int; -extern fn _z_fgets(s: char*, size: int, stream: void*) -> char*; +extern fn _z_pclose(stream: void*) -> c_int; +extern fn _z_fgets(s: char*, size: c_int, stream: void*) -> char*; struct Output { stdout: String; @@ -88,7 +88,7 @@ impl Command { let buf = (char*)malloc(buf_size); while (true) { - let res = _z_fgets(buf, (int)buf_size, fp); + let res = _z_fgets(buf, (c_int)buf_size, fp); if (res == 0) break; let chunk = String::from(buf); diff --git a/std/string.zc b/std/string.zc index 0bc9539..54f11b2 100644 --- a/std/string.zc +++ b/std/string.zc @@ -90,7 +90,8 @@ impl String { } fn eq(self, other: String*) -> bool { - return strcmp(self.c_str(), (*other).c_str()) == 0; + let zero: c_int = 0; + return strcmp(self.c_str(), (*other).c_str()) == zero; } fn length(self) -> usize { @@ -146,7 +147,8 @@ impl String { fn starts_with(self, prefix: char*) -> bool { let plen = strlen(prefix); if plen > self.length() { return false; } - return strncmp(self.c_str(), prefix, plen) == 0; + let zero: c_int = 0; + return strncmp(self.c_str(), prefix, plen) == zero; } fn ends_with(self, suffix: char*) -> bool { @@ -154,7 +156,8 @@ impl String { let len = self.length(); if slen > len { return false; } let offset = (int)(len - slen); - return strcmp(self.c_str() + offset, suffix) == 0; + let zero: c_int = 0; + return strcmp(self.c_str() + offset, suffix) == zero; } fn free(self) { diff --git a/std/thread.zc b/std/thread.zc index 16f3ca1..78d2547 100644 --- a/std/thread.zc +++ b/std/thread.zc @@ -35,11 +35,11 @@ raw { if (ret == 0) { *out_handle = (size_t)pt; } - return ret; + return (int)ret; } static int _z_thread_join(void *handle) { - return pthread_join((pthread_t)handle, NULL); + return (int)pthread_join((pthread_t)handle, NULL); } static void _z_mutex_init(void *ptr) { @@ -63,13 +63,13 @@ raw { } } -extern fn _z_thread_spawn(ctx: void*, out: usize*) -> int; -extern fn _z_thread_join(handle: void*) -> int; +extern fn _z_thread_spawn(ctx: void*, out: usize*) -> c_int; +extern fn _z_thread_join(handle: void*) -> c_int; extern fn _z_mutex_init(ptr: void*); extern fn _z_mutex_lock(ptr: void*); extern fn _z_mutex_unlock(ptr: void*); extern fn _z_mutex_destroy(ptr: void*); -extern fn _z_usleep(micros: int); +extern fn _z_usleep(micros: c_int); @@ -79,26 +79,28 @@ struct Thread { impl Thread { fn spawn(func: fn()) -> Result { - let t: usize = 0; + let out_handle: usize = 0; - let ctx_copy = malloc(16); // z_closure_T is 16 bytes - if (ctx_copy == NULL) return Result::Err("OOM"); + let ctx = malloc(16); // z_closure_T is 16 bytes + if (ctx == NULL) return Result::Err("OOM"); - memcpy(ctx_copy, &func, 16); + memcpy(ctx, &func, 16); - let ret = _z_thread_spawn(ctx_copy, &t); - - if (ret != 0) { - free(ctx_copy); + let ret = _z_thread_spawn(ctx, &out_handle); + let zero: c_int = 0; + if (ret != zero) { + // Failed to spawn + free(ctx); return Result::Err("Failed to create thread"); } - return Result::Ok(Thread { handle: (void*)t }); + return Result::Ok(Thread { handle: (void*)out_handle }); } fn join(self) -> Result { let ret = _z_thread_join(self.handle); - if (ret != 0) return Result::Err("Join failed"); + let zero: c_int = 0; + if (ret != zero) return Result::Err("Join failed"); return Result::Ok(true); } } @@ -138,5 +140,6 @@ impl Drop for Mutex { } fn sleep_ms(ms: int) { - _z_usleep(ms * 1000); + let micros: c_int = (c_int)(ms * 1000); + _z_usleep(micros); } diff --git a/tests/collections/test_string_suite.zc b/tests/collections/test_string_suite.zc index afe08af..64ed9d8 100644 --- a/tests/collections/test_string_suite.zc +++ b/tests/collections/test_string_suite.zc @@ -91,7 +91,9 @@ test "test_fstrings_return" { let inner = f"Inner({x})"; let outer = f"Outer({inner})"; println "Composed: {outer}"; - assert(strcmp(outer, "Outer(Inner(100))") == 0, "Composed f-string failed"); + let outer_res = strcmp(outer, "Outer(Inner(100))"); + let zero: c_int = 0; + assert(outer_res == zero, "Composed f-string failed"); } test "test_string_std_ops" { diff --git a/tests/features/test_portable_types.zc b/tests/features/test_portable_types.zc new file mode 100644 index 0000000..8f54fcb --- /dev/null +++ b/tests/features/test_portable_types.zc @@ -0,0 +1,46 @@ + +import "std/io.zc"; + +// This test verifies the new portable integer types and C interop types. + +extern fn abs(x: c_int) -> c_int; +extern fn labs(x: c_long) -> c_long; + +fn main() -> int { + // Portable types + let a: i32 = -42; + let b: u32 = 42; + let c: i64 = -1000000; + let d: u64 = 1000000; + + if (a != -42) return 1; + if (b != 42) return 2; + if (c != -1000000) return 3; + if (d != 1000000) return 4; + + // C Types + let ca: c_int = -10; + let cb: c_long = -20; + let cc: c_short = -5; + let cd: c_char = 65; // 'A' + + // Test C interaction + let abs_val = abs(ca); + let expected_abs: c_int = 10; + if (abs_val != expected_abs) return 5; + + let labs_val = labs(cb); + let expected_labs: c_long = 20; + if (labs_val != expected_labs) return 6; + + // Size checks (these are platform dependent but we can check relations) + // sizeof(c_char) is always 1 + if (sizeof(c_char) != 1) return 7; + + // sizeof(c_short) <= sizeof(c_int) <= sizeof(c_long) + if (sizeof(c_short) > sizeof(c_int)) return 8; + if (sizeof(c_int) > sizeof(c_long)) return 9; + + printf("Portable types test passed.\n"); + return 0; +} -- cgit v1.2.3