From 3efbb3ecd1b2da01bcc629e5ca9a7527af7f7ab1 Mon Sep 17 00:00:00 2001 From: Toni Date: Fri, 20 Mar 2026 15:35:35 +0100 Subject: [PATCH] io.is_a_directory, octal literal constants --- examples/chip8.zr | 20 ++++++------- examples/curl.zr | 2 +- examples/puzzles/aoc2024_04.zr | 2 +- examples/puzzles/aoc2025_03.zr | 2 +- examples/raylib.zr | 2 +- examples/sqlite_todo.zr | 2 +- src/main.rs | 24 ++++++++++------ src/std/net.zr | 10 +++---- src/std/std.zr | 52 ++++++++++++++++++++++------------ src/symbol_table.rs | 22 ++++++++++---- 10 files changed, 86 insertions(+), 52 deletions(-) diff --git a/examples/chip8.zr b/examples/chip8.zr index e1c1dc4..e27ebbd 100644 --- a/examples/chip8.zr +++ b/examples/chip8.zr @@ -1,4 +1,4 @@ -// needs to be compiled with -m -C="-lraylib" +// needs to be compiled with -m -C "-lraylib" extern InitWindow extern SetTargetFPS extern WindowShouldClose @@ -45,6 +45,15 @@ func chip8_create[] : CHIP8 return c +func chip8_free[c: CHIP8] : void + mem.free(c->memory) + array.free(c->stack) + mem.free(c->reg) + array.free(c->keyboard) + mem.free(c->display) + array.free(c->keyboard_map) + mem.free(c) + func chip8_disassemble[c: CHIP8, ins_count: i64] : void for i in 0..ins_count io.printf("0x%x: ", c->pc) @@ -264,15 +273,6 @@ func chip8_step[c: CHIP8] : void for i in 0..x+1 c->reg[i] = c->memory[c->I + i] -func chip8_free[c: CHIP8] : void - mem.free(c->memory) - array.free(c->stack) - mem.free(c->reg) - array.free(c->keyboard) - mem.free(c->display) - array.free(c->keyboard_map) - mem.free(c) - func main[argc: i64, argv: ptr] : i64 let path: str = 0 as str let disassemble: bool = false diff --git a/examples/curl.zr b/examples/curl.zr index 2f7540f..a9d09cc 100644 --- a/examples/curl.zr +++ b/examples/curl.zr @@ -39,7 +39,7 @@ func main[argc: i64, argv: ptr] : i64 net.send(s, req as ptr, str.len(req)) mem.free(req) - let header_buf: str = mem.alloc(8192) + let header_buf: str = mem.alloc(8192) as str let header_size = 0 let found: bool = false let end_index: i64 = -1 diff --git a/examples/puzzles/aoc2024_04.zr b/examples/puzzles/aoc2024_04.zr index 73578da..e987a32 100644 --- a/examples/puzzles/aoc2024_04.zr +++ b/examples/puzzles/aoc2024_04.zr @@ -43,7 +43,7 @@ func part2[lines: Array] : void for x in 1..lines->size-1 for y in 1..str.len(array.nth(lines, x))-1 if array.nth(lines, x)[y] == 'A' - let s: str = mem.alloc(5) + let s: str = mem.alloc(5) as str s[0] = array.nth(lines, x - 1)[y - 1] s[1] = array.nth(lines, x + 1)[y - 1] s[2] = array.nth(lines, x + 1)[y + 1] diff --git a/examples/puzzles/aoc2025_03.zr b/examples/puzzles/aoc2025_03.zr index 61cc246..8272e16 100644 --- a/examples/puzzles/aoc2025_03.zr +++ b/examples/puzzles/aoc2025_03.zr @@ -7,7 +7,7 @@ func part1[lines: Array] : void let largest = 0 for j in 0..str.len(line) for k in (j+1)..str.len(line) - let s: str = mem.alloc(3) + let s: str = mem.alloc(3) as str s[0] = line[j] s[1] = line[k] s[2] = 0 diff --git a/examples/raylib.zr b/examples/raylib.zr index 58de9ce..30af271 100644 --- a/examples/raylib.zr +++ b/examples/raylib.zr @@ -1,4 +1,4 @@ -// needs to be compiled with -m -C="-lraylib" +// needs to be compiled with -m -C "-lraylib" extern InitWindow extern SetTargetFPS extern WindowShouldClose diff --git a/examples/sqlite_todo.zr b/examples/sqlite_todo.zr index 4ce2f44..0e79e15 100644 --- a/examples/sqlite_todo.zr +++ b/examples/sqlite_todo.zr @@ -1,4 +1,4 @@ -// needs to be compiled with -m -C="-lsqlite3" +// needs to be compiled with -m -C "-lsqlite3" extern sqlite3_open extern sqlite3_exec extern sqlite3_prepare_v2 diff --git a/src/main.rs b/src/main.rs index 107bc3b..24c969c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,7 +132,7 @@ impl Args { match args.next() { Some(s) => out.out = Some(s), None => { - eprintln!("-o option requires a name"); + eprintln!("\x1b[91mERROR\x1b[0m: -o option requires a name"); process::exit(1); } } @@ -146,7 +146,7 @@ impl Args { match args.next() { Some(s) => out.cflags = s, None => { - eprintln!("-C option requires a name"); + eprintln!("\x1b[91mERROR\x1b[0m: -C option requires a name"); process::exit(1); } } @@ -154,16 +154,27 @@ impl Args { println!("Usage: zern [-o path] [-S] [-r] [-m] [-C cflags] path"); process::exit(0); } else if arg.starts_with('-') { - eprintln!("unrecognized option: {}", arg); + eprintln!("\x1b[91mERROR\x1b[0m: unrecognized option: {}", arg); process::exit(1); } else if out.path.is_empty() { out.path = arg } else { - eprintln!("unrecognized argument: {}", arg); + eprintln!("\x1b[91mERROR\x1b[0m: unrecognized argument: {}", arg); process::exit(1); } } + if out.path.is_empty() { + eprintln!("\x1b[91mERROR\x1b[0m: you must provide a path"); + process::exit(1); + } + + if !out.use_gcc && !out.cflags.is_empty() { + // no "ERROR:" since its not an error + eprintln!("You can't set CFLAGS if you're not using gcc. Add the -m flag."); + process::exit(1); + } + out } } @@ -173,11 +184,6 @@ fn main() { _ = raw_args.next(); let args = Args::parse(raw_args); - if !args.use_gcc && !args.cflags.is_empty() { - eprintln!("You can't set CFLAGS if you're not using gcc. Add the -m flag."); - process::exit(1); - } - if let Err(err) = compile_file(args) { eprintln!("{}", err); process::exit(1); diff --git a/src/std/net.zr b/src/std/net.zr index 61bdfde..e4c4250 100644 --- a/src/std/net.zr +++ b/src/std/net.zr @@ -137,7 +137,7 @@ func net.udp_receive[s: net.UDPSocket, size: i64] : net.UDPPacket pkt->source_addr = mem.alloc(16) mem.zero(pkt->source_addr, 16) - let addrlen: i64 = 16 + let addrlen = 16 pkt->size = _builtin_syscall(SYS_recvfrom, s->fd, pkt->data, size, 0, pkt->source_addr, ^addrlen) return pkt @@ -158,9 +158,9 @@ const DNS_RECURSION_DESIRED = 256 func net.encode_dns_name[domain: str] : io.Buffer let domain_len: i64 = str.len(domain) let buf: io.Buffer = must(io.Buffer.alloc?(domain_len + 2)) - let out_pos: i64 = 0 - let part_start: i64 = 0 - let i: i64 = 0 + let out_pos = 0 + let part_start = 0 + let i = 0 while i <= domain_len if i == domain_len || domain[i] == '.' let part_len: i64 = i - part_start @@ -212,7 +212,7 @@ func net.resolve?[domain: str] : i64 // TODO: do actual parsing - let pos: i64 = 12 // skip header (12 bytes) + let pos = 12 // skip header (12 bytes) while pkt->data[pos] != 0 pos = pos + pkt->data[pos] + 1 // skip question diff --git a/src/std/std.zr b/src/std/std.zr index 45651f9..0865455 100644 --- a/src/std/std.zr +++ b/src/std/std.zr @@ -90,11 +90,11 @@ func mem._request_space?[size: i64] : mem.Block mem.write64(_builtin_heap_tail(), blk) return blk -func mem.alloc?[size: i64] : any +func mem.alloc?[size: i64] : ptr err.clear() if size <= 0 err.set(ERR_ALLOC_FAILED, "mem.alloc? called with non-positive size") - return 0 + return 0 as ptr size = mem._align(size) @@ -108,7 +108,7 @@ func mem.alloc?[size: i64] : any let blk: mem.Block = mem._request_space?(size) if err.check() - return 0 + return 0 as ptr if !mem.read64(_builtin_heap_head()) mem.write64(_builtin_heap_head(), blk) @@ -117,7 +117,7 @@ func mem.alloc?[size: i64] : any return blk as ptr + MEM_BLOCK_SIZE -func mem.alloc[size: i64] : any +func mem.alloc[size: i64] : ptr return must(mem.alloc?(size)) func mem.free[x: any] : void @@ -330,7 +330,7 @@ func io.read_char[] : u8 func io.read_line[]: str let MAX_SIZE = 60000 - let buffer: str = mem.alloc(MAX_SIZE + 1) + let buffer: str = mem.alloc(MAX_SIZE + 1) as str let n: i64 = _builtin_syscall(SYS_read, 0, buffer, MAX_SIZE) if n < 0 n = 0 @@ -359,6 +359,22 @@ func io.Buffer.free[buf: io.Buffer] : void func io.file_exists[path: str] : bool return _builtin_syscall(SYS_faccessat, -100, path, 0, 0) == 0 +const S_IFDIR = 0o040000 +const S_IFMT = 0o170000 + +func io.is_a_directory[path: str] : bool + let st: ptr = mem.alloc(256) // it has 21 mixed-size fields so `ptr` must do for now + + let rc: i64 = _builtin_syscall(SYS_newfstatat, -100, path, st, 0) + if rc != 0 + mem.free(st) + return false + + let out: bool = (mem.read32(st + 24) & S_IFMT) == S_IFDIR + + mem.free(st) + return out + func io.read_text_file?[path: str] : str err.clear() let fd: i64 = _builtin_syscall(SYS_openat, -100, path, 0, 0) @@ -436,7 +452,7 @@ func str.len[s: str] : i64 func str.make_copy[s: str] : str let size: i64 = str.len(s) + 1 - let dup: str = mem.alloc(size) + let dup: str = mem.alloc(size) as str mem.copy(s as ptr, dup as ptr, size) return dup @@ -472,7 +488,7 @@ func str.is_alphanumeric[x: u8] : bool func str.concat[a: str, b: str] : str let a_len: i64 = str.len(a) let b_len: i64 = str.len(b) - let out: str = mem.alloc(a_len + b_len + 1) + let out: str = mem.alloc(a_len + b_len + 1) as str mem.copy(a as ptr, out as ptr, a_len) mem.copy(b as ptr, out as ptr + a_len, b_len) out[a_len + b_len] = 0 @@ -505,7 +521,7 @@ func str.substr[s: str, start: i64, length: i64] : str if start < 0 || length < 0 || start + length > str.len(s) panic("str.substr out of bounds") - let out: str = mem.alloc(length + 1) + let out: str = mem.alloc(length + 1) as str mem.copy(s as ptr + start, out as ptr, length) out[length] = 0 return out @@ -513,7 +529,7 @@ func str.substr[s: str, start: i64, length: i64] : str func str.trim[s: str] : str let len: i64 = str.len(s) if len == 0 - let out: str = mem.alloc(1) + let out: str = mem.alloc(1) as str out[0] = 0 return out @@ -562,7 +578,7 @@ func str.split[haystack: str, needle: str]: Array func str.reverse[s: str] : str let len: i64 = str.len(s) - let out: str = mem.alloc(len + 1) + let out: str = mem.alloc(len + 1) as str for i in 0..len out[i] = s[len - i - 1] @@ -571,7 +587,7 @@ func str.reverse[s: str] : str func str.from_i64[n: i64] : str if n == 0 - let out: str = mem.alloc(2) + let out: str = mem.alloc(2) as str out[0] = '0' out[1] = 0 return out @@ -582,7 +598,7 @@ func str.from_i64[n: i64] : str if n == -9223372036854775808 return str.make_copy("-9223372036854775808") n = -n - let buf: str = mem.alloc(21) // enough to fit -MAX_I64 + let buf: str = mem.alloc(21) as str // enough to fit -MAX_I64 let end = 20 buf[end] = 0 end = end - 1 @@ -601,13 +617,13 @@ func str.hex_from_i64[n: i64] : str let hex_chars: str = "0123456789abcdef" if n == 0 - let out: str = mem.alloc(2) + let out: str = mem.alloc(2) as str out[0] = '0' out[1] = 0 return out let mask: i64 = (1 << 60) - 1 - let buf: str = mem.alloc(17) + let buf: str = mem.alloc(17) as str let len = 0 while n != 0 @@ -615,7 +631,7 @@ func str.hex_from_i64[n: i64] : str n = (n >> 4) & mask len = len + 1 - let out: str = mem.alloc(len + 1) + let out: str = mem.alloc(len + 1) as str let j = 0 while j < len out[j] = buf[len - 1 - j] @@ -626,7 +642,7 @@ func str.hex_from_i64[n: i64] : str return out func str.from_char[c: u8] : str - let s: str = mem.alloc(2) + let s: str = mem.alloc(2) as str s[0] = c s[1] = 0 return s @@ -652,7 +668,7 @@ func str.parse_i64[s: str] : i64 func str.hex_encode[s: str, s_len: i64] : str let hex_chars: str = "0123456789abcdef" let j = 0 - let out: str = mem.alloc(s_len * 2 + 1) + let out: str = mem.alloc(s_len * 2 + 1) as str for i in 0..s_len let high: u8 = (s[i] >> 4) & 15 @@ -678,7 +694,7 @@ func str.hex_decode[s: str] : str let i = 0 let j = 0 - let out: str = mem.alloc(s_len / 2 + 1) + let out: str = mem.alloc(s_len / 2 + 1) as str while i < s_len out[j] = str._hex_digit_to_int(s[i]) * 16 + str._hex_digit_to_int(s[i + 1]) diff --git a/src/symbol_table.rs b/src/symbol_table.rs index 8b0b9c7..f7ec70b 100644 --- a/src/symbol_table.rs +++ b/src/symbol_table.rs @@ -65,9 +65,7 @@ impl SymbolTable { pub fn register_declaration(&mut self, stmt: &Stmt) -> Result<(), ZernError> { match stmt { Stmt::Const { name, value } => { - if self.constants.contains_key(&name.lexeme) - || self.functions.contains_key(&name.lexeme) - { + if self.is_name_defined(&name.lexeme) { return error!( name.loc, format!("tried to redefine constant '{}'", name.lexeme) @@ -78,13 +76,18 @@ impl SymbolTable { name.lexeme.clone(), u64::from_str_radix(&value.lexeme[2..], 16).unwrap(), ); + } else if value.lexeme.starts_with("0o") { + self.constants.insert( + name.lexeme.clone(), + u64::from_str_radix(&value.lexeme[2..], 8).unwrap(), + ); } else { self.constants .insert(name.lexeme.clone(), value.lexeme.parse().unwrap()); } } Stmt::Extern(name) => { - if self.functions.contains_key(&name.lexeme) { + if self.is_name_defined(&name.lexeme) { return error!(name.loc, format!("tried to redefine '{}'", name.lexeme)); } self.functions @@ -97,7 +100,7 @@ impl SymbolTable { body: _, exported: _, } => { - if self.functions.contains_key(&name.lexeme) { + if self.is_name_defined(&name.lexeme) { return error!(name.loc, format!("tried to redefine '{}'", name.lexeme)); } self.functions.insert( @@ -109,6 +112,9 @@ impl SymbolTable { ); } Stmt::Struct { name, fields } => { + if self.is_name_defined(&name.lexeme) { + return error!(name.loc, format!("tried to redefine '{}'", name.lexeme)); + } let mut fields_map: HashMap = HashMap::new(); let mut offset: usize = 0; @@ -129,4 +135,10 @@ impl SymbolTable { } Ok(()) } + + fn is_name_defined(&self, s: &str) -> bool { + self.functions.contains_key(s) + || self.constants.contains_key(s) + || self.structs.contains_key(s) + } }