summaryrefslogtreecommitdiff
path: root/std
diff options
context:
space:
mode:
authorZuhaitz <zuhaitz.zechhub@gmail.com>2026-01-31 17:22:17 +0000
committerGitHub <noreply@github.com>2026-01-31 17:22:17 +0000
commit962d659c61212b1a23acfe56dda7cb92b721feda (patch)
treeba1637d3885213095b312f81a477c33b1ebca6aa /std
parente521ee7d175393ef37579ebd61ccb7e8d56a397f (diff)
parent91ed9fdd65e09bd6cd32e44dd07c390f2cf79c22 (diff)
Merge branch 'main' into main
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.zc90
-rw-r--r--std/io.zc49
-rw-r--r--std/json.zc72
-rw-r--r--std/map.zc29
-rw-r--r--std/mem.zc23
-rw-r--r--std/net.zc46
-rw-r--r--std/process.zc136
-rw-r--r--std/set.zc20
-rw-r--r--std/slice.zc40
-rw-r--r--std/string.zc22
-rw-r--r--std/thread.zc14
-rw-r--r--std/time.zc29
15 files changed, 450 insertions, 157 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 c19f9f1..a00993b 100644
--- a/std/fs.zc
+++ b/std/fs.zc
@@ -2,22 +2,32 @@ import "./core.zc"
import "./result.zc"
import "./string.zc"
import "./vec.zc"
+import "./mem.zc"
def Z_SEEK_SET = 0;
def Z_SEEK_END = 2;
def Z_F_OK = 0;
-
-// TODO: restructure this tomorrow.
+include <dirent.h>
+include <sys/stat.h>
+include <unistd.h>
+include <stdlib.h>
+include <stdio.h>
+
+// 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 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 {
- #include <dirent.h>
- #include <sys/stat.h>
- #include <unistd.h>
-
- // typedef needed for Vec<DirEntry*> generation if inferred
typedef struct DirEntry* DirEntryPtr;
- 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);
}
@@ -40,20 +50,9 @@ raw {
int64_t _z_fs_ftell(void* stream) {
return (int64_t)ftell((FILE*)stream);
}
-
- 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);
- }
-
- 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);
}
@@ -61,15 +60,8 @@ raw {
return closedir((DIR*)dir);
}
- void* _z_fs_malloc(size_t size) {
- return malloc(size);
- }
-
- void _z_fs_free(void* ptr) {
- free(ptr);
- }
-
- 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;
@@ -78,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;
@@ -87,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
@@ -96,22 +90,18 @@ raw {
}
}
-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_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_fopen(path: char*, mode: char*) -> void*;
+extern fn _z_fs_fopen(path: const char*, mode: const char*) -> void*;
extern fn _z_fs_fclose(stream: void*) -> 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: long, whence: int) -> int;
-extern fn _z_fs_ftell(stream: void*) -> long;
-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: char*) -> void*;
+extern fn _z_fs_fseek(stream: void*, offset: I64, whence: int) -> 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_malloc(size: usize) -> void*;
-extern fn _z_fs_free(ptr: void*);
+
struct File {
handle: void*;
@@ -153,7 +143,7 @@ impl File {
let size = _z_fs_ftell(self.handle);
_z_fs_fseek(self.handle, 0, Z_SEEK_SET);
- let buffer: char* = _z_fs_malloc((usize)size + 1);
+ let buffer: char* = malloc((usize)size + 1);
if (buffer == NULL) {
return Result<String>::Err("Out of memory");
}
@@ -162,7 +152,7 @@ impl File {
buffer[read] = 0;
let s = String::new(buffer);
- _z_fs_free(buffer);
+ free(buffer);
let res = Result<String>::Ok(s);
s.forget();
@@ -201,7 +191,7 @@ impl File {
}
fn exists(path: char*) -> bool {
- return _z_fs_access(path, Z_F_OK) == 0;
+ return access(path, Z_F_OK) == 0;
}
fn metadata(path: char*) -> Result<Metadata> {
@@ -228,14 +218,14 @@ impl File {
}
fn remove_file(path: char*) -> Result<bool> {
- if (_z_fs_unlink(path) != 0) {
+ if (unlink(path) != 0) {
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) {
+ if (rmdir(path) != 0) {
return Result<bool>::Err("Failed to remove directory");
}
return Result<bool>::Ok(true);
@@ -248,7 +238,7 @@ impl File {
}
let entries = Vec<DirEntry>::new();
- let name_buf: char* = _z_fs_malloc(256);
+ let name_buf: char* = malloc(256);
if (name_buf == NULL) {
_z_fs_closedir(dir);
@@ -277,7 +267,7 @@ impl File {
ent.name.forget();
}
- _z_fs_free(name_buf);
+ free(name_buf);
_z_fs_closedir(dir);
let res = Result< Vec<DirEntry> >::Ok(entries);
diff --git a/std/io.zc b/std/io.zc
index 2793ecf..a5a7359 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) -> 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;
+
+// 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*) -> 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 {
let ap: va_list;
va_start(ap, fmt);
+
let ret = _z_vsnprintf(buffer, size, fmt, ap);
va_end(ap);
+
return ret;
}
@@ -42,15 +56,17 @@ 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 {
let ap: va_list;
va_start(ap, fmt);
- let ret = _z_vprintf(fmt, ap);
+ let ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
@@ -58,7 +74,7 @@ fn print(fmt: char*, ...) -> int {
fn println(fmt: char*, ...) -> 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;
@@ -72,11 +88,10 @@ fn readln() -> char* {
let 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 == Z_EOF) break;
if (c == 10) break; // '\n'
if (len + 1 >= cap) {
@@ -93,7 +108,7 @@ fn readln() -> char* {
len = len + 1;
}
- if (len == 0 && c == eof_val) {
+ if (len == 0 && c == Z_EOF) {
free(line);
return NULL;
}
diff --git a/std/json.zc b/std/json.zc
index e6a15cd..9f5cf73 100644
--- a/std/json.zc
+++ b/std/json.zc
@@ -5,6 +5,7 @@ import "./map.zc"
import "./string.zc"
import "./result.zc"
import "./option.zc"
+import "./mem.zc"
@derive(Eq)
enum JsonType {
@@ -450,3 +451,74 @@ impl JsonValue {
}
}
}
+
+impl Drop for JsonValue {
+ fn drop(self) {
+ 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 8e58cdc..8376da2 100644
--- a/std/map.zc
+++ b/std/map.zc
@@ -1,17 +1,22 @@
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> {
@@ -248,3 +253,9 @@ impl Map<V> {
};
}
}
+
+impl Drop for Map<V> {
+ fn drop(self) {
+ self.free();
+ }
+}
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 72c3fcb..d410a4d 100644
--- a/std/net.zc
+++ b/std/net.zc
@@ -8,12 +8,22 @@ include <errno.h>
import "./core.zc"
import "./result.zc"
import "./string.zc"
+import "./mem.zc"
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;
+
+// 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);
@@ -27,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);
@@ -36,28 +46,20 @@ raw {
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) return -2;
return 0;
}
-
+
static int _z_net_accept(int fd) {
return accept(fd, NULL, NULL);
}
- static ssize_t _z_net_read(int fd, char* buf, size_t n) {
- return read(fd, (void*)buf, n);
- }
-
- 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 _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_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_read(fd: int, buf: char*, n: usize) -> isize;
-extern fn _z_net_write(fd: int, buf: char*, n: usize) -> isize;
+extern fn _z_net_write(fd: int, buf: const char*, n: usize) -> isize;
struct TcpStream {
@@ -66,7 +68,7 @@ struct TcpStream {
impl TcpStream {
fn read(self, buf: char*, len: usize) -> Result<usize> {
- let n = _z_net_read(self.fd, buf, len);
+ let n = read(self.fd, (void*)buf, len);
if (n < 0) return Result<usize>::Err("Read failed");
return Result<usize>::Ok((usize)n);
}
@@ -96,6 +98,12 @@ impl TcpStream {
}
}
+impl Drop for TcpStream {
+ fn drop(self) {
+ self.close();
+ }
+}
+
struct TcpListener {
fd: int;
}
@@ -126,3 +134,9 @@ impl TcpListener {
}
}
}
+
+impl Drop for TcpListener {
+ fn drop(self) {
+ self.close();
+ }
+}
diff --git a/std/process.zc b/std/process.zc
new file mode 100644
index 0000000..3ce43b6
--- /dev/null
+++ b/std/process.zc
@@ -0,0 +1,136 @@
+
+import "./core.zc";
+import "./vec.zc";
+import "./mem.zc";
+import "./string.zc";
+import "./option.zc";
+
+include <stdio.h>
+include <stdlib.h>
+
+// system() can be externed directly with const char*
+extern fn system(command: const char*) -> 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);
+ }
+
+ int _z_pclose(void *stream) {
+ return pclose((FILE *)stream);
+ }
+
+ char *_z_fgets(char *s, int size, void *stream) {
+ return fgets(s, size, (FILE *)stream);
+ }
+}
+
+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*;
+
+struct Output {
+ stdout: String;
+ exit_code: int;
+}
+
+struct Command {
+ program: String;
+ args: Vec<String>;
+}
+
+impl Command {
+ fn new(program: char*) -> Command {
+ return Command {
+ program: String::from(program),
+ args: Vec<String>::new()
+ };
+ }
+
+ fn arg(self, arg: char*) -> Command* {
+ self.args.push(String::from(arg));
+ return self;
+ }
+
+ fn _build_cmd(self) -> String {
+ let cmd_str = self.program.substring(0, self.program.length());
+
+ for arg in &self.args {
+ let space = String::from(" ");
+ cmd_str.append(&space);
+ space.free();
+
+ cmd_str.append(arg);
+ }
+
+ return cmd_str;
+ }
+
+ fn output(self) -> Output {
+ let cmd_str = self._build_cmd();
+ let cmd_c = cmd_str.c_str();
+
+ let fp = _z_popen(cmd_c, "r");
+
+ if (fp == 0) {
+ cmd_str.free();
+ // TODO: Better error handling...
+ return Output {
+ stdout: String::from(""),
+ exit_code: -1
+ };
+ }
+
+ let out = String::from("");
+ let buf_size: usize = 1024;
+ let buf = (char*)malloc(buf_size);
+
+ while (true) {
+ let res = _z_fgets(buf, (int)buf_size, fp);
+ if (res == 0) break;
+
+ let chunk = String::from(buf);
+ out.append(&chunk);
+ chunk.free();
+ }
+
+ let code = _z_pclose(fp);
+ free(buf);
+ cmd_str.free();
+
+ return Output {
+ stdout: out,
+ exit_code: code
+ };
+ }
+
+ fn status(self) -> int {
+ let cmd_str = self._build_cmd();
+ let code = system(cmd_str.c_str());
+ cmd_str.free();
+ return code;
+ }
+
+ fn free(self) {
+ self.program.free();
+
+ for s in &self.args {
+ s.free();
+ }
+ self.args.free();
+ }
+}
+
+impl Drop for Command {
+ fn drop(self) {
+ self.free();
+ }
+}
+
+impl Drop for Output {
+ fn drop(self) {
+ self.stdout.free();
+ }
+}
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..0bc9539 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);
diff --git a/std/thread.zc b/std/thread.zc
index e90943b..16f3ca1 100644
--- a/std/thread.zc
+++ b/std/thread.zc
@@ -5,7 +5,13 @@ include <unistd.h>
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*);
@@ -120,11 +126,17 @@ impl Mutex {
if (self.handle) {
_z_mutex_destroy(self.handle);
free(self.handle);
+ self.handle = NULL;
}
}
}
+impl Drop for Mutex {
+ fn drop(self) {
+ self.free();
+ }
+}
+
fn sleep_ms(ms: int) {
_z_usleep(ms * 1000);
}
-
diff --git a/std/time.zc b/std/time.zc
index 1191821..fa764ed 100644
--- a/std/time.zc
+++ b/std/time.zc
@@ -1,18 +1,31 @@
-
import "./core.zc"
+include <time.h>
+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 {
- #include <time.h>
- #include <unistd.h>
- #include <sys/time.h>
-
static uint64_t _time_now_impl(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)(tv.tv_sec) * 1000 + (uint64_t)(tv.tv_usec) / 1000;
}
+
+ static int64_t _z_time_time(void) {
+ return (int64_t)time(NULL);
+ }
}
+extern fn srand(seed: U32);
+extern fn rand() -> int;
+extern fn usleep(micros: U32) -> int;
+extern fn _time_now_impl() -> U64;
+extern fn _z_time_time() -> I64;
+
struct Duration {
millis: U64;
}
@@ -33,10 +46,8 @@ extern size_t __zen_hash_seed;
impl Time {
fn randomize_hash() {
- raw {
- srand(time(NULL));
- __zen_hash_seed ^= (size_t)rand();
- }
+ srand((U32)_z_time_time());
+ __zen_hash_seed ^= (size_t)rand();
}
fn now() -> U64 {