hashmaps, enforce main function type
This commit is contained in:
@@ -8,7 +8,7 @@ A very cool language
|
|||||||
* Growing [standard library](https://github.com/antpiasecki/zern/tree/main/src/std)
|
* Growing [standard library](https://github.com/antpiasecki/zern/tree/main/src/std)
|
||||||
* Produces tiny static executables (11KB for `hello.zr`)
|
* Produces tiny static executables (11KB for `hello.zr`)
|
||||||
* No libc required!
|
* No libc required!
|
||||||
* Has the pipe operator
|
* Has the pipe operator, dynamic arrays, hashmaps
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
```rust
|
```rust
|
||||||
|
|||||||
@@ -732,7 +732,6 @@ _builtin_environ:
|
|||||||
Expr::New(struct_name) => {
|
Expr::New(struct_name) => {
|
||||||
let struct_fields = &self.symbol_table.structs[&struct_name.lexeme];
|
let struct_fields = &self.symbol_table.structs[&struct_name.lexeme];
|
||||||
|
|
||||||
// TODO: panic on mem.alloc error
|
|
||||||
let memory_size = struct_fields.len() * 8;
|
let memory_size = struct_fields.len() * 8;
|
||||||
emit!(&mut self.output, " mov rdi, {}", memory_size);
|
emit!(&mut self.output, " mov rdi, {}", memory_size);
|
||||||
emit!(&mut self.output, " call mem.alloc");
|
emit!(&mut self.output, " call mem.alloc");
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const ERR_READ_FAILED = 3
|
|||||||
const ERR_WRITE_FAILED = 4
|
const ERR_WRITE_FAILED = 4
|
||||||
const ERR_ALLOC_FAILED = 5
|
const ERR_ALLOC_FAILED = 5
|
||||||
const ERR_CONNECTION_FAILED = 6
|
const ERR_CONNECTION_FAILED = 6
|
||||||
|
const ERR_KEY_ERROR = 7
|
||||||
|
|
||||||
func err.code[] : i64
|
func err.code[] : i64
|
||||||
return mem.read64(_builtin_err_code())
|
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))
|
array.set(new_array, a->size + i, array.nth(b, i))
|
||||||
return new_array
|
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
|
func alg.quicksort[arr: Array] : void
|
||||||
alg._do_quicksort(arr, 0, arr->size - 1)
|
alg._do_quicksort(arr, 0, arr->size - 1)
|
||||||
|
|
||||||
|
|||||||
@@ -66,10 +66,7 @@ impl SymbolTable {
|
|||||||
match stmt {
|
match stmt {
|
||||||
Stmt::Const { name, value } => {
|
Stmt::Const { name, value } => {
|
||||||
if self.is_name_defined(&name.lexeme) {
|
if self.is_name_defined(&name.lexeme) {
|
||||||
return error!(
|
return error!(name.loc, format!("tried to redefine '{}'", name.lexeme));
|
||||||
name.loc,
|
|
||||||
format!("tried to redefine constant '{}'", name.lexeme)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if value.lexeme.starts_with("0x") {
|
if value.lexeme.starts_with("0x") {
|
||||||
self.constants.insert(
|
self.constants.insert(
|
||||||
|
|||||||
@@ -166,8 +166,29 @@ impl<'a> TypeChecker<'a> {
|
|||||||
body,
|
body,
|
||||||
exported: _,
|
exported: _,
|
||||||
} => {
|
} => {
|
||||||
if name.lexeme == "main" && return_type.lexeme != "i64" {
|
if name.lexeme == "main" {
|
||||||
return error!(&name.loc, "main must return i64");
|
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) {
|
if !self.is_valid_type_name(&return_type.lexeme) {
|
||||||
|
|||||||
Reference in New Issue
Block a user