summaryrefslogtreecommitdiff
path: root/std
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-02-02 00:48:12 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-02-02 00:48:12 +0000
commit6bbcd9536522386a53cd2f87ece7aa6cf423829f (patch)
tree55d6dc2b4e2a9d84c09a67acb36f1ab4131e290c /std
parentec140e5e1823ed72e1ac8ab4af121dbe1b3f85d7 (diff)
parentdadabf8b9d11d099777acc261068a3ed8ca06f24 (diff)
Merge branch 'main' of https://github.com/z-libs/Zen-C into patch-1
Diffstat (limited to 'std')
-rw-r--r--std/core.zc6
-rw-r--r--std/cuda.zc2
-rw-r--r--std/env.zc29
-rw-r--r--std/fs.zc99
-rw-r--r--std/io.zc62
-rw-r--r--std/json.zc65
-rw-r--r--std/map.zc22
-rw-r--r--std/mem.zc23
-rw-r--r--std/net.zc113
-rw-r--r--std/process.zc27
-rw-r--r--std/regex.zc198
-rw-r--r--std/set.zc20
-rw-r--r--std/slice.zc40
-rw-r--r--std/string.zc31
-rw-r--r--std/thread.zc84
-rw-r--r--std/time.zc3
16 files changed, 614 insertions, 210 deletions
diff --git a/std/core.zc b/std/core.zc
index f450517..7379db4 100644
--- a/std/core.zc
+++ b/std/core.zc
@@ -7,11 +7,11 @@ include <stdarg.h>
let __zen_hash_seed: usize = 14695981039346656037;
-raw {
-void _zen_panic(const char* file, int line, const char* func, const char* msg) {
+extern fn exit(code: int);
+
+fn _zen_panic(file: const char*, line: int, func: const char*, msg: const char*) {
fprintf(stderr, "%s:%d (%s): Panic: %s\n", file, line, func, msg);
exit(1);
}
-}
#define panic(msg) _zen_panic(__FILE__, __LINE__, __func__, msg) \ No newline at end of file
diff --git a/std/cuda.zc b/std/cuda.zc
index c6a9403..8fc6545 100644
--- a/std/cuda.zc
+++ b/std/cuda.zc
@@ -101,6 +101,8 @@ fn cuda_ok() -> bool {
}
+// Minimal raw block: required for cudaDeviceProp struct field access
+// The cudaDeviceProp struct cannot be declared in Zen-C without type conflicts
raw {
void _z_cuda_get_props(int dev, char* name, size_t* total_mem, int* sm_count, int* major, int* minor, int* max_threads, int* warp_size) {
struct cudaDeviceProp prop;
diff --git a/std/env.zc b/std/env.zc
index 959784f..c63fd3d 100644
--- a/std/env.zc
+++ b/std/env.zc
@@ -2,23 +2,12 @@ import "./core.zc"
import "./option.zc"
import "./string.zc"
-raw {
- char *_z_env_get(char *name) {
- return getenv(name);
- }
-
- int _z_env_set(char *name, char *value, int overwrite) {
- return setenv(name, value, overwrite);
- }
-
- int _z_env_unset(char *name) {
- return unsetenv(name);
- }
-}
+include <stdlib.h>
-extern fn _z_env_get(name: char*) -> char*;
-extern fn _z_env_set(name: char*, value: char*, overwrite: int) -> int;
-extern fn _z_env_unset(name: char*) -> int;
+// Direct externs with const char* to match C stdlib declarations
+extern fn getenv(name: const char*) -> char*;
+extern fn setenv(name: const char*, value: const char*, overwrite: int) -> int;
+extern fn unsetenv(name: const char*) -> int;
@derive(Eq)
enum EnvRes {
@@ -30,7 +19,7 @@ struct Env {}
impl Env {
fn get(name: string) -> Option<string> {
- let value: string = _z_env_get(name);
+ let value: string = getenv(name);
if (value == NULL) {
return Option<string>::None();
}
@@ -39,7 +28,7 @@ impl Env {
}
fn get_dup(name: string) -> Option<String> {
- let value: string = _z_env_get(name);
+ let value: string = getenv(name);
if (value == NULL) {
return Option<String>::None();
}
@@ -52,13 +41,13 @@ impl Env {
}
fn set(name: string, value: string) -> EnvRes {
- let ret: int = _z_env_set(name, value, 1);
+ let ret: int = setenv(name, value, 1);
return (ret == 0) ? EnvRes::OK() : EnvRes::ERR();
}
fn unset(name: string) -> EnvRes {
- let ret: int = _z_env_unset(name);
+ let ret: int = unsetenv(name);
return (ret == 0) ? EnvRes::OK() : EnvRes::ERR();
}
diff --git a/std/fs.zc b/std/fs.zc
index 4547b30..5b2cb21 100644
--- a/std/fs.zc
+++ b/std/fs.zc
@@ -14,12 +14,20 @@ include <unistd.h>
include <stdlib.h>
include <stdio.h>
-// TODO: restructure this tomorrow (lol).
+// Direct externs for simple functions with const char* parameters
+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*);
+
+// Minimal raw block: required for opaque FILE*/DIR* types and C struct access
+// These cannot be expressed in Zen-C extern declarations without type conflicts
raw {
typedef struct DirEntry* DirEntryPtr;
- // Wrappers for FILE* handling due to opaque pointer casting
- void* _z_fs_fopen(char* path, char* mode) {
+ // FILE* wrappers - fopen/fclose/etc use FILE* which conflicts with void*
+ void* _z_fs_fopen(const char* path, const char* mode) {
return fopen(path, mode);
}
@@ -43,22 +51,8 @@ raw {
return (int64_t)ftell((FILE*)stream);
}
- // Wrappers needed because C headers declare these with 'const char*'
- // but Zen C externs generate 'char*', leading to conflicting types.
- int _z_fs_access(char* pathname, int mode) {
- return access(pathname, mode);
- }
-
- int _z_fs_unlink(char* pathname) {
- return unlink(pathname);
- }
-
- int _z_fs_rmdir(char* pathname) {
- return rmdir(pathname);
- }
-
- // Wrappers for DIR* handling
- void* _z_fs_opendir(char* name) {
+ // DIR* wrappers - opendir/closedir/readdir use DIR* which conflicts with void*
+ void* _z_fs_opendir(const char* name) {
return opendir(name);
}
@@ -66,8 +60,8 @@ raw {
return closedir((DIR*)dir);
}
- // struct stat / struct dirent helpers
- int _z_fs_get_metadata(char* path, uint64_t* size, int* is_dir, int* is_file) {
+ // struct stat access - cannot define matching Zen-C struct for stat
+ int _z_fs_get_metadata(const char* path, uint64_t* size, int* is_dir, int* is_file) {
struct stat st;
if (stat(path, &st) != 0) return -1;
*size = st.st_size;
@@ -76,6 +70,7 @@ raw {
return 0;
}
+ // struct dirent access - readdir returns struct dirent*
int _z_fs_read_entry(void* dir, char* out_name, int buf_size, int* is_dir) {
struct dirent* ent = readdir((DIR*)dir);
if (!ent) return 0;
@@ -85,7 +80,8 @@ raw {
return 1;
}
- int _z_fs_mkdir(char* path) {
+ // mkdir has different signatures on Windows vs POSIX
+ int _z_fs_mkdir(const char* path) {
#ifdef _WIN32
return mkdir(path);
#else
@@ -94,25 +90,17 @@ raw {
}
}
-// Direct externs
-extern fn malloc(size: usize) -> void*;
-extern fn free(ptr: void*);
-
-extern fn _z_fs_mkdir(path: char*) -> int;
-extern fn _z_fs_get_metadata(path: 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_fopen(path: char*, mode: char*) -> void*;
-extern fn _z_fs_fclose(stream: void*) -> 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*) -> 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: char*) -> void*;
-extern fn _z_fs_closedir(dir: void*) -> int;
-
-extern fn _z_fs_access(pathname: char*, mode: int) -> int;
-extern fn _z_fs_unlink(pathname: char*) -> int;
-extern fn _z_fs_rmdir(pathname: char*) -> int;
+extern fn _z_fs_opendir(name: const char*) -> void*;
+extern fn _z_fs_closedir(dir: void*) -> c_int;
struct File {
@@ -203,41 +191,50 @@ impl File {
}
fn exists(path: char*) -> bool {
- return _z_fs_access(path, Z_F_OK) == 0;
+ let zero: c_int = 0;
+ return access(path, Z_F_OK) == zero;
}
fn metadata(path: char*) -> Result<Metadata> {
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<Metadata>::Err("Failed to get metadata");
}
return Result<Metadata>::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<bool> {
- if (_z_fs_mkdir(path) != 0) {
+ let res = _z_fs_mkdir(path);
+ let zero: c_int = 0;
+ if (res != zero) {
return Result<bool>::Err("Failed to create directory");
}
return Result<bool>::Ok(true);
}
fn remove_file(path: char*) -> Result<bool> {
- if (_z_fs_unlink(path) != 0) {
+ let res = unlink(path);
+ let zero: c_int = 0;
+ if (res != zero) {
return Result<bool>::Err("Failed to remove file");
}
return Result<bool>::Ok(true);
}
fn remove_dir(path: char*) -> Result<bool> {
- if (_z_fs_rmdir(path) != 0) {
+ let res = rmdir(path);
+ let zero: c_int = 0;
+ if (res != zero) {
return Result<bool>::Err("Failed to remove directory");
}
return Result<bool>::Ok(true);
@@ -257,17 +254,19 @@ impl File {
return Result< Vec<DirEntry> >::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 2793ecf..d9829dd 100644
--- a/std/io.zc
+++ b/std/io.zc
@@ -2,37 +2,51 @@
import "./core.zc"
import "./string.zc"
-raw {
- int _z_vprintf(char* fmt, va_list ap) {
- return vprintf((const char*)fmt, ap);
- }
-
- int _z_vsnprintf(char* str, size_t size, char* fmt, va_list ap) {
- return vsnprintf(str, size, (const char*)fmt, ap);
- }
+include <stdio.h>
+include <stdarg.h>
- void* _z_get_stdin() { return stdin; }
- int _z_get_eof() { return EOF; }
+// These work directly with const char* in extern declarations
+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) -> c_int;
+
+// EOF is typically -1, but we define it for portability
+def Z_EOF = -1;
+
+// Minimal raw block: only for truly opaque FILE* types that can't be
+// represented in Zen-C extern declarations without type conflicts.
+// These wrappers use void* to avoid FILE* declaration conflicts.
+raw {
+ void* _z_get_stdin(void) { return stdin; }
int _z_fgetc(void* stream) { return fgetc((FILE*)stream); }
+ int _z_vsnprintf(char* str, size_t size, const char* fmt, va_list ap) {
+ return vsnprintf(str, size, fmt, ap);
+ }
}
-extern fn _z_vprintf(fmt: char*, ap: va_list) -> int;
-extern fn _z_vsnprintf(str: char*, size: usize, fmt: char*, ap: va_list) -> int;
+extern fn _z_get_stdin() -> void*;
+extern fn _z_fgetc(stream: void*) -> c_int;
fn format(fmt: char*, ...) -> char* {
static let buffer: char[1024];
let ap: va_list;
va_start(ap, fmt);
+
_z_vsnprintf(buffer, 1024, fmt, ap);
va_end(ap);
+
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);
+
let ret = _z_vsnprintf(buffer, size, fmt, ap);
va_end(ap);
+
return ret;
}
@@ -42,23 +56,25 @@ fn format_new(fmt: char*, ...) -> char* {
let ap: va_list;
va_start(ap, fmt);
+
_z_vsnprintf(buffer, 1024, fmt, ap);
va_end(ap);
+
return buffer;
}
-fn print(fmt: char*, ...) -> int {
+fn print(fmt: char*, ...) -> c_int {
let ap: va_list;
va_start(ap, fmt);
- let ret = _z_vprintf(fmt, ap);
+ let ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
-fn println(fmt: char*, ...) -> int {
+fn println(fmt: char*, ...) -> c_int {
let ap: va_list;
va_start(ap, fmt);
- let ret = _z_vprintf(fmt, ap);
+ let ret = vprintf(fmt, ap);
va_end(ap);
puts("");
return ret + 1;
@@ -70,14 +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();
- let eof_val = _z_get_eof();
while (true) {
c = _z_fgetc(std_in);
- if (c == eof_val) 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;
@@ -93,7 +110,8 @@ fn readln() -> char* {
len = len + 1;
}
- if (len == 0 && c == eof_val) {
+ let eof_final: c_int = Z_EOF;
+ if (len == 0 && c == eof_final) {
free(line);
return NULL;
}
diff --git a/std/json.zc b/std/json.zc
index d373ab9..9f5cf73 100644
--- a/std/json.zc
+++ b/std/json.zc
@@ -457,3 +457,68 @@ impl Drop for JsonValue {
self.free();
}
}
+
+impl JsonValue {
+ fn to_string(self) -> String {
+ let s = String::new("");
+ self.stringify(&s);
+ return s;
+ }
+
+ fn stringify(self, buf: String*) {
+ if (self.kind.tag == JsonType::JSON_NULL().tag) {
+ buf.append_c_ptr("null");
+ } else if (self.kind.tag == JsonType::JSON_BOOL().tag) {
+ if (self.bool_val) { buf.append_c_ptr("true"); } else { buf.append_c_ptr("false"); }
+ } else if (self.kind.tag == JsonType::JSON_NUMBER().tag) {
+ let tmp: char[64];
+ sprintf((char*)tmp, "%.15g", self.number_val); // Use %.15g for precision
+ buf.append_c_ptr((char*)tmp);
+ } else if (self.kind.tag == JsonType::JSON_STRING().tag) {
+ buf.append_c_ptr("\"");
+ let p = self.string_val;
+ let len = strlen(p);
+ for (let i = 0; i < len; i = i + 1) {
+ let c = p[i];
+ if (c == '"') buf.append_c_ptr("\\\"");
+ else if (c == '\\') buf.append_c_ptr("\\\\");
+ else if (c == '\n') buf.append_c_ptr("\\n");
+ else if (c == '\t') buf.append_c_ptr("\\t");
+ else if (c == '\r') buf.append_c_ptr("\\r");
+ else if (c == '\b') buf.append_c_ptr("\\b");
+ else if (c == '\f') buf.append_c_ptr("\\f");
+ else {
+ let tmp: char[2]; tmp[0] = c; tmp[1] = 0;
+ buf.append_c_ptr((char*)tmp);
+ }
+ }
+ buf.append_c_ptr("\"");
+ } else if (self.kind.tag == JsonType::JSON_ARRAY().tag) {
+ buf.append_c_ptr("[");
+ let v = self.array_val;
+ for (let i: usize = 0; i < v.length(); i = i + 1) {
+ if (i > 0) buf.append_c_ptr(",");
+ let item = v.get(i);
+ (*item).stringify(buf);
+ }
+ buf.append_c_ptr("]");
+ } else if (self.kind.tag == JsonType::JSON_OBJECT().tag) {
+ buf.append_c_ptr("{{");
+ let m = self.object_val;
+ let first = true;
+ for (let i: usize = 0; i < m.capacity(); i = i + 1) {
+ if (m.is_slot_occupied(i)) {
+ if (!first) buf.append_c_ptr(",");
+ first = false;
+ let key = m.key_at(i);
+ buf.append_c_ptr("\"");
+ buf.append_c_ptr(key); // Assuming keys are simple for now, but really should escape them too
+ buf.append_c_ptr("\":");
+ let val = m.val_at(i);
+ val.stringify(buf);
+ }
+ }
+ buf.append_c_ptr("}");
+ }
+ }
+}
diff --git a/std/map.zc b/std/map.zc
index 70d6ad2..8376da2 100644
--- a/std/map.zc
+++ b/std/map.zc
@@ -3,16 +3,20 @@ import "./core.zc"
import "./option.zc"
import "./mem.zc"
-raw {
- extern size_t __zen_hash_seed;
- size_t _map_hash_str(const char* str) {
- size_t hash = __zen_hash_seed;
- while (*str) {
- hash ^= (unsigned char)*str++;
- hash *= 1099511628211UL;
- }
- return hash;
+// Pure Zen-C string hash using FNV-1a algorithm
+fn _map_hash_str(str: const char*) -> usize {
+ let hash = __zen_hash_seed;
+ let i: usize = 0;
+
+ while (str[i] != 0) {
+ // Cast char to U8 for unsigned byte value
+ let b: U8 = (U8)str[i];
+ hash = hash ^ (usize)b;
+ hash = hash * (usize)1099511628211;
+ i = i + 1;
}
+
+ return hash;
}
struct Map<V> {
diff --git a/std/mem.zc b/std/mem.zc
index 6ee96e8..f1a5f5a 100644
--- a/std/mem.zc
+++ b/std/mem.zc
@@ -49,28 +49,7 @@ impl Box<T> {
}
}
-struct Slice<T> {
- data: T*;
- len: usize;
-}
-
-impl Slice<T> {
- fn new(data: T*, len: usize) -> Self {
- return Self { data: data, len: len };
- }
-
- fn get(self, i: usize) -> T {
- return self.data[i];
- }
-
- fn set(self, i: usize, val: T) {
- self.data[i] = val;
- }
-
- fn is_empty(self) -> bool {
- return self.len == 0;
- }
-}
+// Note: Slice<T> is defined in std/slice.zc with iteration support
fn mem_zero<T>(ptr: T*, count: usize) {
memset(ptr, 0, sizeof(T) * count);
diff --git a/std/net.zc b/std/net.zc
index dd10642..dce1a01 100644
--- a/std/net.zc
+++ b/std/net.zc
@@ -13,8 +13,17 @@ import "./mem.zc"
def Z_AF_INET = 2;
def Z_SOCK_STREAM = 1;
+// Direct externs for simple socket functions
+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
+// cannot be declared in Zen-C without type conflicts with C headers.
+// Also includes inet_pton, htons, bind, connect, listen, accept wrappers.
raw {
- static int _z_net_bind(int fd, char *host, int port) {
+ static int _z_net_bind(int fd, const char *host, int port) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
@@ -28,7 +37,7 @@ raw {
return 0;
}
- static int _z_net_connect(int fd, char *host, int port) {
+ static int _z_net_connect(int fd, const char *host, int port) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
@@ -42,54 +51,68 @@ raw {
return accept(fd, NULL, NULL);
}
- static ssize_t _z_net_write(int fd, char* buf, size_t n) {
+ static ssize_t _z_net_write(int fd, const char* buf, size_t n) {
return write(fd, (const void*)buf, n);
}
}
-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 _z_net_bind(fd: int, host: char*, port: int) -> int;
-extern fn _z_net_connect(fd: int, host: char*, port: int) -> int;
-extern fn _z_net_accept(fd: int) -> int;
-extern fn _z_net_write(fd: int, buf: 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 {
- fd: int;
+ handle: c_int;
}
+extern fn strerror(errnum: c_int) -> char*;
+
impl TcpStream {
fn read(self, buf: char*, len: usize) -> Result<usize> {
- let n = read(self.fd, (void*)buf, len);
- if (n < 0) return Result<usize>::Err("Read failed");
+ let n = read(self.handle - 1, (void*)buf, len);
+ let zero: c_int = 0;
+ if (n < (isize)zero) return Result<usize>::Err(strerror(errno));
return Result<usize>::Ok((usize)n);
}
- fn write(self, buf: char*, len: usize) -> Result<usize> {
- let n = _z_net_write(self.fd, buf, len);
- if (n < 0) return Result<usize>::Err("Write failed");
+ fn write(self, buf: u8*, len: usize) -> Result<usize> {
+ 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<usize>::Err("Write failed");
return Result<usize>::Ok((usize)n);
}
fn close(self) {
- if (self.fd >= 0) {
- close(self.fd);
- self.fd = -1;
+ 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<TcpStream> {
- let fd = socket(Z_AF_INET, Z_SOCK_STREAM, 0);
- if (fd < 0) return Result<TcpStream>::Err("Failed to create socket");
+ fn connect(host: char*, port: c_int) -> Result<TcpStream> {
+ let zero: c_int = 0;
+ let fd = socket(Z_AF_INET, Z_SOCK_STREAM, zero);
+ if (fd < zero) return Result<TcpStream>::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<TcpStream>::Err("Invalid address"); }
- if (res == -2) { close(fd); return Result<TcpStream>::Err("Connection failed"); }
+ if (res == neg_one) { close(fd); return Result<TcpStream>::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<TcpStream>::Err("Connection failed"); }
- return Result<TcpStream>::Ok(TcpStream { fd: fd });
+ let one: c_int = 1;
+ return Result<TcpStream>::Ok(TcpStream { handle: fd + one });
}
}
@@ -100,32 +123,42 @@ impl Drop for TcpStream {
}
struct TcpListener {
- fd: int;
+ handle: c_int;
}
impl TcpListener {
- fn bind(host: char*, port: int) -> Result<TcpListener> {
- let fd = socket(Z_AF_INET, Z_SOCK_STREAM, 0);
- if (fd < 0) return Result<TcpListener>::Err("Failed to create socket");
+ fn bind(host: char*, port: c_int) -> Result<TcpListener> {
+ let zero: c_int = 0;
+ let fd = socket(Z_AF_INET, Z_SOCK_STREAM, zero);
+ if (fd < zero) return Result<TcpListener>::Err("Failed to create socket");
let res = _z_net_bind(fd, host, port);
- if (res == -1) { close(fd); return Result<TcpListener>::Err("Invalid address"); }
- if (res == -2) { close(fd); return Result<TcpListener>::Err("Bind failed"); }
- if (res == -3) { close(fd); return Result<TcpListener>::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<TcpListener>::Err("Invalid address"); }
+ if (res == neg_two) { close(fd); return Result<TcpListener>::Err("Bind failed"); }
+ if (res == neg_three) { close(fd); return Result<TcpListener>::Err("Listen failed"); }
- return Result<TcpListener>::Ok(TcpListener { fd: fd });
+ let one: c_int = 1;
+ return Result<TcpListener>::Ok(TcpListener { handle: fd + one });
}
fn accept(self) -> Result<TcpStream> {
- let client_fd = _z_net_accept(self.fd);
- if (client_fd < 0) return Result<TcpStream>::Err("Accept failed");
- return Result<TcpStream>::Ok(TcpStream { fd: client_fd });
+ 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<TcpStream>::Err("Accept failed");
+ return Result<TcpStream>::Ok(TcpStream { handle: client_fd + one });
}
fn close(self) {
- if (self.fd >= 0) {
- close(self.fd);
- self.fd = -1;
+ 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 d0b09a9..9f432c0 100644
--- a/std/process.zc
+++ b/std/process.zc
@@ -5,8 +5,16 @@ import "./mem.zc";
import "./string.zc";
import "./option.zc";
-raw {
- void *_z_popen(char *command, char *type) {
+include <stdio.h>
+include <stdlib.h>
+
+// system() can be externed directly with const char*
+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*
+raw {
+ void *_z_popen(const char *command, const char *type) {
return (void *)popen(command, type);
}
@@ -17,16 +25,11 @@ raw {
char *_z_fgets(char *s, int size, void *stream) {
return fgets(s, size, (FILE *)stream);
}
-
- int _z_system(char *command) {
- return system(command);
- }
}
-extern fn _z_popen(command: char*, type: char*) -> void*;
-extern fn _z_pclose(stream: void*) -> int;
-extern fn _z_fgets(s: char*, size: int, stream: void*) -> char*;
-extern fn _z_system(command: char*) -> int;
+extern fn _z_popen(command: const char*, type: const char*) -> void*;
+extern fn _z_pclose(stream: void*) -> c_int;
+extern fn _z_fgets(s: char*, size: c_int, stream: void*) -> char*;
struct Output {
stdout: String;
@@ -85,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);
@@ -105,7 +108,7 @@ impl Command {
fn status(self) -> int {
let cmd_str = self._build_cmd();
- let code = _z_system(cmd_str.c_str());
+ let code = system(cmd_str.c_str());
cmd_str.free();
return code;
}
diff --git a/std/regex.zc b/std/regex.zc
new file mode 100644
index 0000000..f64b36e
--- /dev/null
+++ b/std/regex.zc
@@ -0,0 +1,198 @@
+include <regex.h>
+
+import "./core.zc"
+import "./string.zc"
+import "./vec.zc"
+import "./option.zc"
+
+struct Match {
+ text: char*;
+ start: int;
+ len: int;
+}
+
+impl Match {
+ fn new(text: char*, start: int, len: int) -> Match {
+ return Match { text: text, start: start, len: len };
+ }
+
+ fn as_string(self) -> char* {
+ return self.text;
+ }
+
+ fn end(self) -> int {
+ return self.start + self.len;
+ }
+}
+
+struct Regex {
+ preg: void*;
+ pattern: char*;
+ flags: int;
+}
+
+impl Regex {
+ fn compile(pattern: char*) -> Regex {
+ return Regex::compile_with_flags(pattern, 1 | 2);
+ }
+
+ fn compile_with_flags(pattern: char*, flags: int) -> Regex {
+ let preg = malloc(1024);
+ let status = regcomp(preg, pattern, flags);
+ if (status != 0) {
+ free(preg);
+ return Regex { preg: 0, pattern: 0, flags: flags };
+ }
+ return Regex { preg: preg, pattern: pattern, flags: flags };
+ }
+
+ fn is_valid(self) -> bool {
+ return self.preg != 0;
+ }
+
+ fn match(self, text: char*) -> bool {
+ if (self.preg == 0) { return false; }
+ return regexec(self.preg, text, 0, 0, 0) == 0;
+ }
+
+ fn match_full(self, text: char*) -> bool {
+ return self.match(text);
+ }
+
+ fn match_at(self, text: char*, offset: int) -> bool {
+ if (self.preg == 0) { return false; }
+ let len = strlen(text);
+ if (offset < 0 || offset > len) { return false; }
+ return regexec(self.preg, text + offset, 0, 0, 0) == 0;
+ }
+
+ fn is_match(self, text: char*) -> bool {
+ return self.match(text);
+ }
+
+ fn find(self, text: char*) -> Option<Match> {
+ if (self.preg == 0) { return Option<Match>::None(); }
+ let t_len = strlen(text);
+ for (let i = 0; i <= t_len; i = i + 1) {
+ let sub = text + i;
+ if (regexec(self.preg, sub, 0, 0, 0) == 0) {
+ let j = 0;
+ while (text[i + j] != 0 && regexec(self.preg, sub, 0, 0, 0) == 0) {
+ j = j + 1;
+ sub = text + i + j;
+ }
+ return Option<Match>::Some(Match::new(text + i, i, j));
+ }
+ }
+ return Option<Match>::None();
+ }
+
+ fn find_at(self, text: char*, start: int) -> Option<Match> {
+ let len = strlen(text);
+ if (start < 0 || start >= len) {
+ return Option<Match>::None();
+ }
+ return self.find(text + start);
+ }
+
+ fn count(self, text: char*) -> int {
+ if (self.preg == 0) { return 0; }
+ let count = 0;
+ let pos = 0;
+ let t_len = strlen(text);
+ while (pos < t_len) {
+ let sub = text + pos;
+ if (regexec(self.preg, sub, 0, 0, 0) == 0) {
+ count = count + 1;
+ pos = pos + 1;
+ } else {
+ break;
+ }
+ }
+ return count;
+ }
+
+ fn split(self, text: char*) -> Vec<String> {
+ let parts = Vec<String>::new();
+ if (self.preg == 0) {
+ parts.push(String::from(text));
+ return parts;
+ }
+ let t_len = strlen(text);
+ let last_pos = 0;
+ let pos = 0;
+ while (pos < t_len) {
+ let sub = text + pos;
+ if (regexec(self.preg, sub, 0, 0, 0) == 0) {
+ if (pos > last_pos) {
+ let before = text + last_pos;
+ let part_len = pos - last_pos;
+ let v = Vec<char>::new();
+ for (let i = 0; i < part_len; i = i + 1) {
+ v.push(before[i]);
+ }
+ v.push(0);
+ parts.push(String { vec: v });
+ }
+ last_pos = pos + 1;
+ pos = pos + 1;
+ } else {
+ pos = pos + 1;
+ }
+ }
+ if (last_pos < t_len) {
+ parts.push(String::from(text + last_pos));
+ }
+ return parts;
+ }
+
+ fn pattern(self) -> char* {
+ return self.pattern;
+ }
+
+ fn flags(self) -> int {
+ return self.flags;
+ }
+
+ fn is_valid_pattern(pattern: char*) -> bool {
+ let test_regex = Regex::compile(pattern);
+ let valid = test_regex.is_valid();
+ test_regex.destroy();
+ return valid;
+ }
+
+ fn destroy(self) {
+ if (self.preg != 0) {
+ regfree(self.preg);
+ free(self.preg);
+ }
+ }
+}
+
+fn regex_match(pattern: char*, text: char*) -> bool {
+ let re = Regex::compile(pattern);
+ let result = re.match(text);
+ re.destroy();
+ return result;
+}
+
+fn regex_find(pattern: char*, text: char*) -> Option<Match> {
+ let re = Regex::compile(pattern);
+ let result = re.find(text);
+ re.destroy();
+ return result;
+}
+
+fn regex_count(pattern: char*, text: char*) -> int {
+ let re = Regex::compile(pattern);
+ let count = re.count(text);
+ re.destroy();
+ return count;
+}
+
+fn regex_split(pattern: char*, text: char*) -> Vec<String> {
+ let re = Regex::compile(pattern);
+ let parts = re.split(text);
+ re.destroy();
+ return parts;
+}
diff --git a/std/set.zc b/std/set.zc
index ba6c93f..e1faab3 100644
--- a/std/set.zc
+++ b/std/set.zc
@@ -2,17 +2,17 @@
import "./core.zc"
import "./option.zc"
-raw {
- extern size_t __zen_hash_seed;
- size_t _set_hash(const void* data, size_t len) {
- size_t hash = __zen_hash_seed;
- const unsigned char* bytes = (const unsigned char*)data;
- for (size_t i = 0; i < len; i++) {
- hash ^= bytes[i];
- hash *= 1099511628211UL;
- }
- return hash;
+// Pure Zen-C generic hash using FNV-1a algorithm
+fn _set_hash(data: const void*, len: usize) -> usize {
+ let hash = __zen_hash_seed;
+ let bytes: U8* = (U8*)data;
+
+ for (let i: usize = 0; i < len; i = i + 1) {
+ hash = hash ^ (usize)bytes[i];
+ hash = hash * (usize)1099511628211;
}
+
+ return hash;
}
struct Set<T> {
diff --git a/std/slice.zc b/std/slice.zc
index 778c6ed..c757fbd 100644
--- a/std/slice.zc
+++ b/std/slice.zc
@@ -1,10 +1,50 @@
+import "./option.zc"
+
struct Slice<T> {
data: T*;
len: usize;
}
+struct SliceIter<T> {
+ data: T*;
+ count: usize;
+ idx: usize;
+}
+
+impl SliceIter<T> {
+ fn next(self) -> Option<T> {
+ if (self.idx < self.count) {
+ let item = self.data[self.idx];
+ self.idx = self.idx + 1;
+ return Option<T>::Some(item);
+ }
+ return Option<T>::None();
+ }
+
+ fn iterator(self) -> SliceIter<T> {
+ return *self;
+ }
+}
+
impl Slice<T> {
+ fn from_array(ptr: T*, len: usize) -> Slice<T> {
+ return Slice<T> { data: ptr, len: len };
+ }
+
+ // Alias for backwards compatibility with std/mem.zc
+ fn new(data: T*, len: usize) -> Slice<T> {
+ return Slice<T> { data: data, len: len };
+ }
+
+ fn iterator(self) -> SliceIter<T> {
+ return SliceIter<T> {
+ data: self.data,
+ count: self.len,
+ idx: 0
+ };
+ }
+
fn length(self) -> usize {
return self.len;
}
diff --git a/std/string.zc b/std/string.zc
index fe5b0ad..54f11b2 100644
--- a/std/string.zc
+++ b/std/string.zc
@@ -55,6 +55,28 @@ impl String {
}
}
+ fn append_c(self, s: char*) {
+ if (self.vec.len > 0) {
+ self.vec.len = self.vec.len - 1;
+ }
+ let len = strlen(s);
+ for (let i = 0; i < len; i = i + 1) {
+ self.vec.push(s[i]);
+ }
+ self.vec.push(0);
+ }
+
+ fn append_c_ptr(ptr: String*, s: char*) {
+ if (ptr.vec.len > 0) {
+ ptr.vec.len = ptr.vec.len - 1;
+ }
+ let len = strlen(s);
+ for (let i = 0; i < len; i = i + 1) {
+ ptr.vec.push(s[i]);
+ }
+ ptr.vec.push(0);
+ }
+
fn add(self, other: String*) -> String {
let new_s = String::from(self.c_str());
new_s.append(other);
@@ -68,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 {
@@ -124,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 {
@@ -132,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 98f080e..0722b60 100644
--- a/std/thread.zc
+++ b/std/thread.zc
@@ -7,6 +7,11 @@ import "./core.zc"
import "./result.zc"
import "./mem.zc"
+// Essential raw block: required for pthread operations and closure trampolining
+// This block cannot be eliminated because:
+// 1. z_closure_T is an internal compiler type for Zen-C closures
+// 2. pthread_t, pthread_mutex_t are opaque types that can't be extern'd with void*
+// 3. The trampoline function needs to cast and execute Zen-C closures
raw {
typedef void (*ZenThreadFunc)(void*);
@@ -20,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;
@@ -30,11 +39,19 @@ 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 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) {
@@ -58,42 +75,70 @@ raw {
}
}
-extern fn _z_thread_spawn(ctx: void*, out: usize*) -> int;
-extern fn _z_thread_join(handle: void*) -> int;
+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*);
extern fn _z_mutex_destroy(ptr: void*);
-extern fn _z_usleep(micros: int);
+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 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<Thread>::Err("OOM");
+ let ctx = malloc(16); // z_closure_T is 16 bytes
+ if (ctx == NULL) return Result<Thread>::Err("OOM");
- memcpy(ctx_copy, &func, 16);
+ memcpy(ctx, &func, 16);
- let ret = _z_thread_spawn(ctx_copy, &t);
+ let ret = _z_thread_spawn(ctx, &out_handle);
- if (ret != 0) {
- free(ctx_copy);
+ if ret != 0 {
+ free(ctx);
return Result<Thread>::Err("Failed to create thread");
}
- return Result<Thread>::Ok(Thread { handle: (void*)t });
+ return Result<Thread>::Ok(Thread { handle: (void*)out_handle });
}
fn join(self) -> Result<bool> {
- let ret = _z_thread_join(self.handle);
- if (ret != 0) 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);
}
}
@@ -118,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;
@@ -133,5 +178,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/std/time.zc b/std/time.zc
index 865dd6d..fa764ed 100644
--- a/std/time.zc
+++ b/std/time.zc
@@ -5,6 +5,9 @@ include <unistd.h>
include <sys/time.h>
include <stdlib.h>
+// Minimal raw block: required because gettimeofday() uses struct timeval
+// which can't be declared in Zen-C without type conflicts, and time()
+// has conflicting type signature (time_t* vs void*)
raw {
static uint64_t _time_now_impl(void) {
struct timeval tv;