diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-02-02 01:05:54 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-02-02 01:05:54 +0000 |
| commit | 4f72798ac1518def38b49c0d9d9a686b43302689 (patch) | |
| tree | 022190e48e99210ef3eeeed0461eede7a132aed5 | |
| parent | 15975aadfb8030b03e614acc3024001c201aefe6 (diff) | |
| parent | f86ef2bbc1248bba9ebfd322c96a0f4c8e028148 (diff) | |
Merge branch 'main' of https://github.com/z-libs/Zen-C into arsmotorin/main
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | README_ES.md | 6 | ||||
| -rw-r--r-- | README_IT.md | 6 | ||||
| -rw-r--r-- | README_ZH_CN.md | 6 | ||||
| -rw-r--r-- | README_ZH_TW.md | 6 | ||||
| -rw-r--r-- | src/ast/ast.c | 3 | ||||
| -rw-r--r-- | src/parser/parser_expr.c | 52 | ||||
| -rw-r--r-- | src/parser/parser_struct.c | 10 | ||||
| -rw-r--r-- | std/thread.zc | 56 | ||||
| -rw-r--r-- | tests/std/test_thread.zc | 42 |
10 files changed, 167 insertions, 26 deletions
@@ -476,9 +476,9 @@ match val { // Destructuring Enums match shape { - Shape::Circle(r) => println "Radius: {r}", - Shape::Rect(w, h) => println "Area: {w*h}", - Shape::Point => println "Point" + Shape::Circle(r) => { println "Radius: {r}" }, + Shape::Rect(w, h) => { println "Area: {w*h}" }, + Shape::Point => { println "Point" }, } ``` diff --git a/README_ES.md b/README_ES.md index 956436d..be8e47e 100644 --- a/README_ES.md +++ b/README_ES.md @@ -475,9 +475,9 @@ match val { // Desestructuración de Enums match shape { - Shape::Circle(r) => println "Radio: {r}", - Shape::Rect(w, h) => println "Área: {w*h}", - Shape::Point => println "Punto" + Shape::Circle(r) => { println "Radio: {r}" }, + Shape::Rect(w, h) => { println "Área: {w*h}" }, + Shape::Point => { println "Punto" }, } ``` diff --git a/README_IT.md b/README_IT.md index 5b9e3ab..3d70a65 100644 --- a/README_IT.md +++ b/README_IT.md @@ -477,9 +477,9 @@ match val { // Destrutturazione degli Enums match forma { - Forma::Cerchio(r) => println "Raggio: {r}", - Forma::Rettangolo(w, h) => println "Area: {w*h}", - Forma::Punto => println "Punto" + Forma::Cerchio(r) => { println "Raggio: {r}" }, + Forma::Rettangolo(w, h) => { println "Area: {w*h}" }, + Forma::Punto => { println "Punto" }, } ``` diff --git a/README_ZH_CN.md b/README_ZH_CN.md index 926eb9f..e5f8f54 100644 --- a/README_ZH_CN.md +++ b/README_ZH_CN.md @@ -475,9 +475,9 @@ match val { // 解构枚举 match shape { - Shape::Circle(r) => println "半径: {r}", - Shape::Rect(w, h) => println "面积: {w*h}", - Shape::Point => println "点" + Shape::Circle(r) => { println "半径: {r}" }, + Shape::Rect(w, h) => { println "面积: {w*h}" }, + Shape::Point => { println "点" }, } ``` diff --git a/README_ZH_TW.md b/README_ZH_TW.md index df6a320..2f32656 100644 --- a/README_ZH_TW.md +++ b/README_ZH_TW.md @@ -475,9 +475,9 @@ match val { // 解構枚舉 match shape { - Shape::Circle(r) => println "半徑: {r}", - Shape::Rect(w, h) => println "面積: {w*h}", - Shape::Point => println "點" + Shape::Circle(r) => { println "半徑: {r}" }, + Shape::Rect(w, h) => { println "面積: {w*h}" }, + Shape::Point => { println "點" }, } ``` diff --git a/src/ast/ast.c b/src/ast/ast.c index 1b35500..28fe678 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -101,6 +101,9 @@ int is_integer_type(Type *t) t->kind == TYPE_ISIZE || t->kind == TYPE_BYTE || t->kind == TYPE_RUNE || t->kind == TYPE_UINT || t->kind == TYPE_I128 || t->kind == TYPE_U128 || t->kind == TYPE_BITINT || t->kind == TYPE_UBITINT || + t->kind == TYPE_C_INT || t->kind == TYPE_C_UINT || t->kind == TYPE_C_LONG || + t->kind == TYPE_C_ULONG || t->kind == TYPE_C_SHORT || t->kind == TYPE_C_USHORT || + t->kind == TYPE_C_CHAR || t->kind == TYPE_C_UCHAR || (t->kind == TYPE_STRUCT && t->name && (0 == strcmp(t->name, "int8_t") || 0 == strcmp(t->name, "uint8_t") || 0 == strcmp(t->name, "int16_t") || 0 == strcmp(t->name, "uint16_t") || diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c index 5bf0089..f27e2c3 100644 --- a/src/parser/parser_expr.c +++ b/src/parser/parser_expr.c @@ -370,8 +370,7 @@ static void check_format_string(ASTNode *call, Token t) if (spec == 'd' || spec == 'i' || spec == 'u' || spec == 'x' || spec == 'X' || spec == 'o') { - if (vt && vt->kind != TYPE_INT && vt->kind != TYPE_I64 && !type_is_unsigned(vt) && - vt->kind != TYPE_CHAR) + if (vt && !is_integer_type(vt)) { warn_format_string(t, arg_num, "integer", got_type); } @@ -4116,6 +4115,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) break; } ASTNode *node = ast_create(NODE_EXPR_MEMBER); + node->token = field; node->member.target = lhs; node->member.field = token_strdup(field); node->member.is_pointer_access = 1; @@ -4169,6 +4169,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) break; } ASTNode *node = ast_create(NODE_EXPR_MEMBER); + node->token = field; node->member.target = lhs; node->member.field = token_strdup(field); node->member.is_pointer_access = 2; @@ -4350,6 +4351,52 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) if (sig) { + // Check if this is a static method being called with dot operator + // Static methods don't have 'self' as first parameter + int is_static_method = 0; + if (sig->total_args == 0) + { + // No arguments at all - definitely static + is_static_method = 1; + } + else if (sig->arg_types[0]) + { + // Check if first parameter is a pointer to the struct type + // Instance methods have: fn method(self) where self is StructType* + // Static methods have: fn method(x: int, y: int) etc. + Type *first_param = sig->arg_types[0]; + + // If first param is not a pointer, it's likely static + // OR if it's a pointer but not to this struct type + if (first_param->kind != TYPE_POINTER) + { + is_static_method = 1; + } + else if (first_param->inner) + { + // Check if the inner type matches the struct + char *inner_name = NULL; + if (first_param->inner->kind == TYPE_STRUCT) + { + inner_name = first_param->inner->name; + } + + if (!inner_name || strcmp(inner_name, struct_name) != 0) + { + is_static_method = 1; + } + } + } + + if (is_static_method) + { + zpanic_at(lhs->token, + "Cannot call static method '%s' with dot operator\n" + " = help: Use '%s::%s(...)' instead of instance.%s(...)", + lhs->member.field, struct_name, lhs->member.field, + lhs->member.field); + } + resolved_name = xstrdup(mangled); resolved_sig = sig; @@ -4772,6 +4819,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) break; } ASTNode *node = ast_create(NODE_EXPR_MEMBER); + node->token = field; node->member.target = lhs; node->member.field = token_strdup(field); node->member.is_pointer_access = 0; diff --git a/src/parser/parser_struct.c b/src/parser/parser_struct.c index c89ad34..0c984a6 100644 --- a/src/parser/parser_struct.c +++ b/src/parser/parser_struct.c @@ -315,6 +315,16 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) register_generic(ctx, target_gen_param); } + // Check for common error: swapped Struct and Trait + // impl MyStruct for MyTrait (Wrong) vs impl MyTrait for MyStruct (Correct) + if (!is_trait(name1) && is_trait(name2)) + { + zpanic_at(t1, + "Incorrect usage of impl. Did you mean 'impl %s for %s'? Syntax is 'impl " + "<Trait> for <Struct>'", + name2, name1); + } + // Auto-import std/mem.zc if implementing Drop, Copy, or Clone traits if (strcmp(name1, "Drop") == 0 || strcmp(name1, "Copy") == 0 || strcmp(name1, "Clone") == 0) { diff --git a/std/thread.zc b/std/thread.zc index 78d2547..0722b60 100644 --- a/std/thread.zc +++ b/std/thread.zc @@ -25,9 +25,13 @@ raw { z_closure_T *closure = (z_closure_T*)c; void (*f)(void*) = (void(*)(void*))closure->func; f(closure->ctx); - free(c); + free(c); return NULL; } + + static int _z_thread_equal(void* handle1, void* handle2) { + return pthread_equal((pthread_t)handle1, (pthread_t)handle2); + } static int _z_thread_spawn(void *ctx_copy, size_t *out_handle) { pthread_t pt; @@ -41,6 +45,14 @@ raw { static int _z_thread_join(void *handle) { return (int)pthread_join((pthread_t)handle, NULL); } + + static int _z_thread_detach(void* handle) { + return pthread_detach((pthread_t)handle); + } + + static int _z_thread_cancel(void* handle) { + return pthread_cancel((pthread_t)handle); + } static void _z_mutex_init(void *ptr) { pthread_mutex_init((pthread_mutex_t*)ptr, NULL); @@ -63,8 +75,11 @@ raw { } } +extern fn _z_thread_equal(handle1: void*, handle2: void*) -> c_int; extern fn _z_thread_spawn(ctx: void*, out: usize*) -> c_int; extern fn _z_thread_join(handle: void*) -> c_int; +extern fn _z_thread_detach(handle: void*) -> c_int; +extern fn _z_thread_cancel(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*); @@ -74,10 +89,17 @@ extern fn _z_usleep(micros: c_int); struct Thread { - handle: void*; + handle: void*; } impl Thread { + fn eq(self, other: const Thread) -> bool { + return _z_thread_equal(self.handle, other.handle); + } + fn neq(self, other: const Thread) -> bool { + return !(self == other); + } + fn spawn(func: fn()) -> Result<Thread> { let out_handle: usize = 0; @@ -87,9 +109,8 @@ impl Thread { memcpy(ctx, &func, 16); let ret = _z_thread_spawn(ctx, &out_handle); - let zero: c_int = 0; - if (ret != zero) { - // Failed to spawn + + if ret != 0 { free(ctx); return Result<Thread>::Err("Failed to create thread"); } @@ -98,9 +119,26 @@ impl Thread { } fn join(self) -> Result<bool> { - let ret = _z_thread_join(self.handle); - let zero: c_int = 0; - if (ret != zero) return Result<bool>::Err("Join failed"); + let err = _z_thread_join(self.handle); + if err { + return Result<bool>::Err("Join failed"); + } + return Result<bool>::Ok(true); + } + + fn detach(self) -> Result<bool> { + let err = _z_thread_detach(self.handle); + if err { + return Result<bool>::Err("Detach failed"); + } + return Result<bool>::Ok(true); + } + + fn cancel(self) -> Result<bool> { + let err = _z_thread_cancel(self.handle); + if err { + return Result<bool>::Err("Cancel failed"); + } return Result<bool>::Ok(true); } } @@ -125,7 +163,7 @@ impl Mutex { } fn free(self) { - if (self.handle) { + if self.handle { _z_mutex_destroy(self.handle); free(self.handle); self.handle = NULL; diff --git a/tests/std/test_thread.zc b/tests/std/test_thread.zc new file mode 100644 index 0000000..42fa82e --- /dev/null +++ b/tests/std/test_thread.zc @@ -0,0 +1,42 @@ +import "std/thread.zc" + +test "Thread Spawn and Join" { + "Testing thread spawn and join"; + + let spawn_result = Thread::spawn(fn(){ + "Running on a separate thread"; + }); + assert(spawn_result.is_ok(), "Thread spawn has failed"); + + let thr = spawn_result.unwrap(); + let join_result = thr.join(); + assert(join_result.is_ok(), "Thread join has failed"); +} + +test "Thread Spawn and Detach" { + "Testing thread spawn and detach"; + + let spawn_result = Thread::spawn(fn(){ + "Detached thread, this line might print later."; + }); + assert(spawn_result.is_ok(), "Thread spawn has failed"); + + let thr = spawn_result.unwrap(); + let detach_result = thr.detach(); + assert(detach_result.is_ok(), "Thread detach has failed"); +} + +test "Thread Spawn and Cancel" { + "Testing thread spawn and cancel"; + + let spawn_result = Thread::spawn(fn(){ + "Thread running indefinitely..."; + while true { + } + }); + assert(spawn_result.is_ok(), "Thread spawn has failed"); + + let thr = spawn_result.unwrap(); + let cancel_result = thr.cancel(); + assert(cancel_result.is_ok(), "Thread cancel has failed"); +} |
