diff --git a/README.md b/README.md index 0ed1f4a..27427fc 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A very cool language * Growing [standard library](https://github.com/antpiasecki/zern/tree/main/src/std) * Produces tiny static executables (11KB for `hello.zr`) * No libc required! -* Has the pipe operator +* Has the pipe operator, dynamic arrays, hashmaps ## Syntax ```rust diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 3442f02..1c30b41 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -732,7 +732,6 @@ _builtin_environ: Expr::New(struct_name) => { let struct_fields = &self.symbol_table.structs[&struct_name.lexeme]; - // TODO: panic on mem.alloc error let memory_size = struct_fields.len() * 8; emit!(&mut self.output, " mov rdi, {}", memory_size); emit!(&mut self.output, " call mem.alloc"); diff --git a/src/std/std.zr b/src/std/std.zr index 0865455..1dea503 100644 --- a/src/std/std.zr +++ b/src/std/std.zr @@ -5,6 +5,7 @@ const ERR_READ_FAILED = 3 const ERR_WRITE_FAILED = 4 const ERR_ALLOC_FAILED = 5 const ERR_CONNECTION_FAILED = 6 +const ERR_KEY_ERROR = 7 func err.code[] : i64 return mem.read64(_builtin_err_code()) @@ -846,6 +847,89 @@ func array.concat[a: Array, b: Array] : Array array.set(new_array, a->size + i, array.nth(b, i)) return new_array +const HashMap._TABLE_SIZE = 100 + +struct HashMap + table: Array + +struct HashMap._Node + key: str + value: any + next: HashMap._Node + +func HashMap.new[] : HashMap + let map: HashMap = new HashMap + map->table = array.new_preallocated_and_zeroed(HashMap._TABLE_SIZE) + return map + +func HashMap.insert[map: HashMap, key: str, value: any] : void + let index: i64 = HashMap._djb2(key) + let current: HashMap._Node = array.nth(map->table, index) + + while current as ptr + if str.equal(current->key, key) + current->value = value + return 0 + current = current->next + + let new_node: HashMap._Node = new HashMap._Node + new_node->key = str.make_copy(key) + new_node->value = value + new_node->next = array.nth(map->table, index) + array.set(map->table, index, new_node) + +func HashMap.get?[map: HashMap, key: str] : any + err.clear() + let index: i64 = HashMap._djb2(key) + let current: HashMap._Node = array.nth(map->table, index) + + while current as ptr + if str.equal(current->key, key) + return current->value + current = current->next + + err.set(ERR_KEY_ERROR, "key not found") + return 0 + +func HashMap.delete[map: HashMap, key: str] : void + let index: i64 = HashMap._djb2(key) + let current: HashMap._Node = array.nth(map->table, index) + let prev: HashMap._Node = 0 as HashMap._Node + + while current as ptr + if str.equal(current->key, key) + if prev as ptr + prev->next = current->next + else + array.set(map->table, index, current->next) + + mem.free(current->key) + mem.free(current) + return 0 + + prev = current + current = current->next + +func HashMap._djb2[key: str] : i64 + let hash: i64 = 5381 + let key_len: i64 = str.len(key) + for i in 0..key_len + hash = ((hash << 5) + hash) + key[i] + hash = (hash & 0x7fffffffffffffff) // prevent negative + return hash % HashMap._TABLE_SIZE + +func HashMap.free[map: HashMap] : void + for i in 0..HashMap._TABLE_SIZE + let current: HashMap._Node = array.nth(map->table, i) + while current as ptr + let tmp: HashMap._Node = current + current = current->next + mem.free(tmp->key) + mem.free(tmp) + + array.free(map->table) + mem.free(map) + func alg.quicksort[arr: Array] : void alg._do_quicksort(arr, 0, arr->size - 1) diff --git a/src/symbol_table.rs b/src/symbol_table.rs index f7ec70b..f38d10b 100644 --- a/src/symbol_table.rs +++ b/src/symbol_table.rs @@ -66,10 +66,7 @@ impl SymbolTable { match stmt { Stmt::Const { name, value } => { if self.is_name_defined(&name.lexeme) { - return error!( - name.loc, - format!("tried to redefine constant '{}'", name.lexeme) - ); + return error!(name.loc, format!("tried to redefine '{}'", name.lexeme)); } if value.lexeme.starts_with("0x") { self.constants.insert( diff --git a/src/typechecker.rs b/src/typechecker.rs index 11d6983..ce9b358 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -166,8 +166,29 @@ impl<'a> TypeChecker<'a> { body, exported: _, } => { - if name.lexeme == "main" && return_type.lexeme != "i64" { - return error!(&name.loc, "main must return i64"); + if name.lexeme == "main" { + if return_type.lexeme != "i64" { + return error!(&name.loc, "main function must return i64"); + } + + if !params.is_empty() && params.len() != 2 { + return error!(&name.loc, "main function must accept 0 or 2 parameters"); + } + + if params.len() == 2 { + if params[0].var_type.lexeme != "i64" { + return error!( + &name.loc, + "first parameter of the main function must be a i64" + ); + } + if params[1].var_type.lexeme != "ptr" { + return error!( + &name.loc, + "second parameter of the main function must be a ptr" + ); + } + } } if !self.is_valid_type_name(&return_type.lexeme) {