Compare commits

...

2 Commits

Author SHA1 Message Date
aea9ce911a std json parser 2026-07-05 15:22:50 +02:00
873aa3e1cc normal destructuring with one line changed 2026-07-01 17:01:47 +02:00
19 changed files with 291 additions and 102 deletions

View File

@@ -52,7 +52,7 @@ func CHIP8.free[c: CHIP8] : void
c->keyboard->free() c->keyboard->free()
c->display->free() c->display->free()
c->keyboard_map->free() c->keyboard_map->free()
mem.free(c) (c as ptr)->free()
func CHIP8.disassemble[c: CHIP8, ins_count: i64] : void func CHIP8.disassemble[c: CHIP8, ins_count: i64] : void
for i in 0..ins_count for i in 0..ins_count
@@ -291,7 +291,7 @@ func main[argc: i64, argv: ptr] : i64
c := new CHIP8 c := new CHIP8
c->init() c->init()
~buffer, ok := io.read_binary_file(path) buffer, ok := io.read_binary_file(path)
if !ok if !ok
panic("failed to read file") panic("failed to read file")

View File

@@ -12,7 +12,7 @@ func main[argc: i64, argv: ptr] : i64
io.println("ERROR: invalid url (Did you forget \"http://\"?)") io.println("ERROR: invalid url (Did you forget \"http://\"?)")
return 1 return 1
if !url->substr(0, 7)->equal("http://") if !url->substr_n(0, 7)->equal("http://")
io.println("ERROR: only http scheme is supported") io.println("ERROR: only http scheme is supported")
return 1 return 1
@@ -24,23 +24,19 @@ func main[argc: i64, argv: ptr] : i64
break break
i += 1 i += 1
host := url->substr(host_start, i - host_start) host := url->substr_n(host_start, i - host_start)
path := "/" path := "/"
if i < url_len if i < url_len
path = url->substr(i, url_len - i) path = url->substr_n(i, url_len - i)
~s, ok := net.connect(host, 80) s, ok := net.connect(host, 80)
if !ok if !ok
panic("failed to connect") panic("failed to connect")
req := new str.Builder // seems reasonable
req->append("GET ") req := _stackalloc(4096)
req->append(path) req_size := str.format_into(req as str, 4096, "GET %s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\n\r\n", path, host)
req->append(" HTTP/1.0\r\nHost: ") net.send(s, req, req_size)
req->append(host)
req->append("\r\nConnection: close\r\n\r\n")
net.send(s, req->data, req->size)
req->destroy()
header_buf := mem.alloc(8192) as str header_buf := mem.alloc(8192) as str
header_size := 0 header_size := 0

View File

@@ -2,4 +2,4 @@ include "std/io.zr"
func main[] : i64 func main[] : i64
n := 37107287533 + 46376937677 + 74324986199 + 91942213363 + 23067588207 + 89261670696 + 28112879812 + 44274228917 + 47451445736 + 70386486105 + 62176457141 + 64906352462 + 92575867718 + 58203565325 + 80181199384 + 35398664372 + 86515506006 + 71693888707 + 54370070576 + 53282654108 + 36123272525 + 45876576172 + 17423706905 + 81142660418 + 51934325451 + 62467221648 + 15732444386 + 55037687525 + 18336384825 + 80386287592 + 78182833757 + 16726320100 + 48403098129 + 87086987551 + 59959406895 + 69793950679 + 41052684708 + 65378607361 + 35829035317 + 94953759765 + 88902802571 + 25267680276 + 36270218540 + 24074486908 + 91430288197 + 34413065578 + 23053081172 + 11487696932 + 63783299490 + 67720186971 + 95548255300 + 76085327132 + 37774242535 + 23701913275 + 29798860272 + 18495701454 + 38298203783 + 34829543829 + 40957953066 + 29746152185 + 41698116222 + 62467957194 + 23189706772 + 86188088225 + 11306739708 + 82959174767 + 97623331044 + 42846280183 + 55121603546 + 32238195734 + 75506164965 + 62177842752 + 32924185707 + 99518671430 + 73267460800 + 76841822524 + 97142617910 + 87783646182 + 10848802521 + 71329612474 + 62184073572 + 66627891981 + 60661826293 + 85786944089 + 66024396409 + 64913982680 + 16730939319 + 94809377245 + 78639167021 + 15368713711 + 40789923115 + 44889911501 + 41503128880 + 81234880673 + 82616570773 + 22918802058 + 77158542502 + 72107838435 + 20849603980 + 53503534226 n := 37107287533 + 46376937677 + 74324986199 + 91942213363 + 23067588207 + 89261670696 + 28112879812 + 44274228917 + 47451445736 + 70386486105 + 62176457141 + 64906352462 + 92575867718 + 58203565325 + 80181199384 + 35398664372 + 86515506006 + 71693888707 + 54370070576 + 53282654108 + 36123272525 + 45876576172 + 17423706905 + 81142660418 + 51934325451 + 62467221648 + 15732444386 + 55037687525 + 18336384825 + 80386287592 + 78182833757 + 16726320100 + 48403098129 + 87086987551 + 59959406895 + 69793950679 + 41052684708 + 65378607361 + 35829035317 + 94953759765 + 88902802571 + 25267680276 + 36270218540 + 24074486908 + 91430288197 + 34413065578 + 23053081172 + 11487696932 + 63783299490 + 67720186971 + 95548255300 + 76085327132 + 37774242535 + 23701913275 + 29798860272 + 18495701454 + 38298203783 + 34829543829 + 40957953066 + 29746152185 + 41698116222 + 62467957194 + 23189706772 + 86188088225 + 11306739708 + 82959174767 + 97623331044 + 42846280183 + 55121603546 + 32238195734 + 75506164965 + 62177842752 + 32924185707 + 99518671430 + 73267460800 + 76841822524 + 97142617910 + 87783646182 + 10848802521 + 71329612474 + 62184073572 + 66627891981 + 60661826293 + 85786944089 + 66024396409 + 64913982680 + 16730939319 + 94809377245 + 78639167021 + 15368713711 + 40789923115 + 44889911501 + 41503128880 + 81234880673 + 82616570773 + 22918802058 + 77158542502 + 72107838435 + 20849603980 + 53503534226
io.println(n->to_str()->substr(0, 10)) io.println(n->to_str()->substr_n(0, 10))

View File

@@ -1,4 +0,0 @@
include "std/io.zr"
func main[] : i64
io.println("Hello, World!")

View File

@@ -1,18 +0,0 @@
include "std/io.zr"
include "std/os.zr"
func main[] : i64
arr := []
for i in 0..10
arr->push(os.urandom_i64()->abs() % 1000)
for i in 0..arr->size
io.println_i64(arr->nth(i))
io.println("------------")
arr->quicksort()
for i in 0..arr->size
io.println_i64(arr->nth(i))
arr->free()

View File

@@ -2,7 +2,7 @@ include "std/io.zr"
include "std/net.zr" include "std/net.zr"
func main[] : i64 func main[] : i64
~s, ok := net.listen("127.0.0.1", 8000) s, ok := net.listen("127.0.0.1", 8000)
if !ok if !ok
panic("failed to listen") panic("failed to listen")

View File

@@ -2,7 +2,7 @@ include "std/io.zr"
include "std/net.zr" include "std/net.zr"
func main[] : i64 func main[] : i64
~s, ok := net.create_udp_server("127.0.0.1", 8000) s, ok := net.create_udp_server("127.0.0.1", 8000)
if !ok if !ok
panic("net.create_udp_server failed") panic("net.create_udp_server failed")

View File

@@ -812,7 +812,6 @@ _builtin_environ:
if *use_heap { if *use_heap {
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");
emit!(&mut self.output, " push rax");
} else { } else {
let aligned_size = (memory_size + 15) & !15; let aligned_size = (memory_size + 15) & !15;
emit!(&mut self.output, " sub rsp, {}", aligned_size); emit!(&mut self.output, " sub rsp, {}", aligned_size);

View File

@@ -342,7 +342,7 @@ impl Parser {
Ok(Stmt::Break) Ok(Stmt::Break)
} else if self.match_token(&[TokenType::KeywordContinue]) { } else if self.match_token(&[TokenType::KeywordContinue]) {
Ok(Stmt::Continue) Ok(Stmt::Continue)
} else if self.match_token(&[TokenType::Tilde]) { } else if self.check(&TokenType::Identifier) && self.check_ahead(&TokenType::Comma) {
let mut targets = vec![]; let mut targets = vec![];
loop { loop {
targets.push(self.consume(Identifier, "expected an identifier")?); targets.push(self.consume(Identifier, "expected an identifier")?);

View File

@@ -30,7 +30,6 @@ pub enum TokenType {
ShiftLeft, ShiftLeft,
ShiftRight, ShiftRight,
Arrow, Arrow,
Tilde,
Equal, Equal,
DoubleEqual, DoubleEqual,
@@ -179,7 +178,6 @@ impl<'a> Tokenizer<'a> {
'%' => self.add_token(TokenType::Mod)?, '%' => self.add_token(TokenType::Mod)?,
'^' => self.add_token(TokenType::Xor)?, '^' => self.add_token(TokenType::Xor)?,
':' => self.add_token(TokenType::Colon)?, ':' => self.add_token(TokenType::Colon)?,
'~' => self.add_token(TokenType::Tilde)?,
'-' => { '-' => {
if self.match_char('=') { if self.match_char('=') {
self.add_token(TokenType::MinusEqual)? self.add_token(TokenType::MinusEqual)?

View File

@@ -596,6 +596,15 @@ impl<'a> TypeChecker<'a> {
match &func_type.params { match &func_type.params {
FnParams::Normal(params) => { FnParams::Normal(params) => {
if params.is_empty() || params[0] != receiver_type {
return error!(
method.loc,
format!(
"first parameter of the method must be of type {}",
receiver_type
)
);
}
if params.len() != args.len() + 1 { if params.len() != args.len() + 1 {
return error!( return error!(
method.loc, method.loc,
@@ -606,15 +615,6 @@ impl<'a> TypeChecker<'a> {
) )
); );
} }
if params[0] != receiver_type {
return error!(
method.loc,
format!(
"first parameter of the method must be of type {}",
receiver_type
)
);
}
for (i, arg) in args.iter().enumerate() { for (i, arg) in args.iter().enumerate() {
expect_type!(self.typecheck_expr(env, arg)?, params[i + 1], method.loc); expect_type!(self.typecheck_expr(env, arg)?, params[i + 1], method.loc);
} }

View File

@@ -38,14 +38,14 @@ func Array.push[xs: Array, x: any] : void
func Array.free[xs: Array] : void func Array.free[xs: Array] : void
if xs->data != 0 if xs->data != 0
xs->data->free() xs->data->free()
mem.free(xs) (xs as ptr)->free()
func Array.free_with_items[xs: Array] : void func Array.free_with_items[xs: Array] : void
if xs->data != 0 if xs->data != 0
for i in 0..xs->size for i in 0..xs->size
mem.free(xs->nth(i)) (xs->nth(i) as ptr)->free()
xs->data->free() xs->data->free()
mem.free(xs) (xs as ptr)->free()
func Array.pop[xs: Array] : any func Array.pop[xs: Array] : any
if xs->size == 0 if xs->size == 0
@@ -137,7 +137,7 @@ func str.split[haystack: str, needle: str]: Array
return result return result
else else
for i in 0..haystack_len for i in 0..haystack_len
result->push(haystack->substr(i, 1)) result->push(haystack->substr_n(i, 1))
return result return result
start := 0 start := 0
@@ -150,13 +150,13 @@ func str.split[haystack: str, needle: str]: Array
match = false match = false
break break
if match if match
result->push(haystack->substr(start, i - start)) result->push(haystack->substr_n(start, i - start))
start = i + needle_len start = i + needle_len
i += needle_len i += needle_len
continue continue
i += 1 i += 1
result->push(haystack->substr(start, haystack_len - start)) result->push(haystack->substr_n(start, haystack_len - start))
return result return result
const HashMap._TABLE_SIZE = 100 const HashMap._TABLE_SIZE = 100
@@ -214,27 +214,36 @@ func HashMap.delete[map: HashMap, key: str] : void
map->table->set(index, current->next) map->table->set(index, current->next)
current->key->free() current->key->free()
mem.free(current) (current as ptr)->free()
return return
prev = current prev = current
current = current->next current = current->next
func HashMap.keys[map: HashMap] : Array
out := []
for i in 0..HashMap._TABLE_SIZE
current : HashMap._Node = map->table->nth(i)
while current as ptr
out->push(current->key)
current = current->next
return out
func HashMap.free_with_keys[map: HashMap] : void
for i in 0..HashMap._TABLE_SIZE
current : HashMap._Node = map->table->nth(i)
while current as ptr
tmp := current
current = current->next
tmp->key->free()
(tmp as ptr)->free()
map->table->free()
(map as ptr)->free()
func HashMap._djb2[key: str] : i64 func HashMap._djb2[key: str] : i64
hash := 5381 hash := 5381
for i in 0..key->len() for i in 0..key->len()
hash = ((hash << 5) + hash) + key[i] hash = ((hash << 5) + hash) + key[i]
hash = (hash & 0x7fffffffffffffff) // prevent negative hash = (hash & 0x7fffffffffffffff) // prevent negative
return hash % HashMap._TABLE_SIZE return hash % HashMap._TABLE_SIZE
func HashMap.free[map: HashMap] : void
for i in 0..HashMap._TABLE_SIZE
current : HashMap._Node = map->table->nth(i)
while current as ptr
tmp := current
current = current->next
tmp->key->free()
mem.free(tmp)
map->table->free()
mem.free(map)

View File

@@ -85,9 +85,7 @@ func io.read_line[] : str
if c == '\n' if c == '\n'
break break
b->append_char(c) b->append_char(c)
s := b->build() return b->build_and_free_buffer()
b->destroy()
return s
func io.read_text_file[path: str] : str, bool func io.read_text_file[path: str] : str, bool
fd := _builtin_syscall(SYS_openat, AT_FDCWD, path, O_RDONLY, 0) fd := _builtin_syscall(SYS_openat, AT_FDCWD, path, O_RDONLY, 0)

200
std/json.zr Normal file
View File

@@ -0,0 +1,200 @@
include "std/containers.zr"
const JSON_OBJECT = 0
const JSON_ARRAY = 1
const JSON_STRING = 2
const JSON_NUMBER = 3
const JSON_NULL = 4
const JSON_BOOL = 5
struct json.Value
type: i64
value: any
func json.Value.dump[v: json.Value] : str
s := new str.Builder
if v->type == JSON_OBJECT
map := v->value as HashMap
keys := map->keys()
s->append_char('{')
for i in 0..keys->size
if i > 0
s->append_char(',')
s->append_char('"')
s->append(keys->nth(i) as str)
s->append_char('"')
s->append_char(':')
value, _ := map->get(keys->nth(i) as str)
s->append((value as json.Value)->dump())
s->append_char('}')
keys->free()
else if v->type == JSON_ARRAY
arr := v->value as Array
s->append_char('[')
for i in 0..arr->size
if i > 0
s->append_char(',')
s->append((arr->nth(i) as json.Value)->dump())
s->append_char(']')
else if v->type == JSON_STRING
// TODO: escape sequences
s->append_char('"')
s->append(v->value as str)
s->append_char('"')
else if v->type == JSON_NUMBER
s->append((v->value as i64)->to_str())
else if v->type == JSON_NULL
s->append("null")
else if v->type == JSON_BOOL
if v->value as bool
s->append("true")
else
s->append("false")
else
panic("json.Value.dump: unknown value type")
return s->build_and_free_buffer()
func json.Value.free[v: json.Value] : void
if v->type == JSON_OBJECT
map := v->value as HashMap
keys := map->keys()
for i in 0..keys->size
value, _ := map->get(keys->nth(i) as str)
(value as json.Value)->free()
keys->free()
map->free_with_keys()
else if v->type == JSON_ARRAY
arr := v->value as Array
for i in 0..arr->size
(arr->nth(i) as json.Value)->free()
arr->free()
else if v->type == JSON_STRING
(v->value as str)->free()
(v as ptr)->free()
func json.parse[s: str] : json.Value
i := 0
return json._parse_value(s, ^i)
func json._parse_value[s: str, i: ptr] : json.Value
out := new* json.Value
json._skip_whitespace(s, i)
if s[mem.read64(i)] == 0
panic("json.parse: unexpected EOF")
if s[mem.read64(i)] == '{'
mem.write64(i, mem.read64(i) + 1)
json._skip_whitespace(s, i)
out->type = JSON_OBJECT
out->value = HashMap.new()
if s[mem.read64(i)] != '}'
while true
json._skip_whitespace(s, i)
key := json._parse_string(s, i)
json._skip_whitespace(s, i)
if s[mem.read64(i)] != ':'
panic("json.parse: expected ':'")
mem.write64(i, mem.read64(i) + 1)
json._skip_whitespace(s, i)
value := json._parse_value(s, i)
(out->value as HashMap)->insert(key, value)
key->free()
json._skip_whitespace(s, i)
if s[mem.read64(i)] == ','
mem.write64(i, mem.read64(i) + 1)
else
break
json._skip_whitespace(s, i)
if s[mem.read64(i)] != '}'
panic("json.parse: expected '}'")
mem.write64(i, mem.read64(i) + 1)
else if s[mem.read64(i)] == '['
mem.write64(i, mem.read64(i) + 1)
json._skip_whitespace(s, i)
out->type = JSON_ARRAY
out->value = []
while s[mem.read64(i)] != ']'
json._skip_whitespace(s, i)
(out->value as Array)->push(json._parse_value(s, i))
json._skip_whitespace(s, i)
if s[mem.read64(i)] == ','
mem.write64(i, mem.read64(i) + 1)
else
break
json._skip_whitespace(s, i)
if s[mem.read64(i)] != ']'
panic("json.parse: expected ']'")
mem.write64(i, mem.read64(i) + 1)
else if s[mem.read64(i)] == '"'
out->type = JSON_STRING
out->value = json._parse_string(s, i)
else if s[mem.read64(i)]->is_digit() || s[mem.read64(i)] == '-'
start := mem.read64(i)
if s[mem.read64(i)] == '-'
mem.write64(i, mem.read64(i) + 1)
while s[mem.read64(i)]->is_digit()
mem.write64(i, mem.read64(i) + 1)
// TODO: float support once str.parse_f64 is a thing
if s[mem.read64(i)] == '.'
panic("json.parse: parsing floats not implemented yet")
len := mem.read64(i) - start
num_str := s->substr_n(start, len)
out->type = JSON_NUMBER
out->value = num_str->parse_i64()
num_str->free()
else if s[mem.read64(i)] == 'n' && s[mem.read64(i)+1] == 'u' && s[mem.read64(i)+2] == 'l' && s[mem.read64(i)+3] == 'l'
out->type = JSON_NULL
mem.write64(i, mem.read64(i) + 4)
else if s[mem.read64(i)] == 't' && s[mem.read64(i)+1] == 'r' && s[mem.read64(i)+2] == 'u' && s[mem.read64(i)+3] == 'e'
out->type = JSON_BOOL
out->value = true
mem.write64(i, mem.read64(i) + 4)
else if s[mem.read64(i)] == 'f' && s[mem.read64(i)+1] == 'a' && s[mem.read64(i)+2] == 'l' && s[mem.read64(i)+3] == 's' && s[mem.read64(i)+4] == 'e'
out->type = JSON_BOOL
out->value = false
mem.write64(i, mem.read64(i) + 5)
else
panic("json.parse: unexpected character")
return out
func json._parse_string[s: str, i: ptr] : str
if s[mem.read64(i)] != '"'
panic("json.parse: expected '\"'")
mem.write64(i, mem.read64(i) + 1)
start := mem.read64(i)
// TODO: escape sequences
while s[mem.read64(i)] != '"'
if s[mem.read64(i)] == 0
panic("json.parse: unexpected EOF")
mem.write64(i, mem.read64(i) + 1)
len := mem.read64(i) - start
mem.write64(i, mem.read64(i) + 1)
return s->substr_n(start, len)
func json._skip_whitespace[s: str, i: ptr] : void
while s[mem.read64(i)]->is_whitespace()
mem.write64(i, mem.read64(i) + 1)

View File

@@ -72,9 +72,6 @@ func mem.alloc[size: i64] : ptr
return blk as ptr + MEM_BLOCK_SIZE return blk as ptr + MEM_BLOCK_SIZE
func mem.free[x: any] : void
ptr.free(x as ptr)
func ptr.free[x: ptr] : void func ptr.free[x: ptr] : void
if x == 0 if x == 0
return return
@@ -237,4 +234,4 @@ func Blob.alloc[size: i64] : Blob
func Blob.free[buf: Blob] : void func Blob.free[buf: Blob] : void
buf->data->free() buf->data->free()
mem.free(buf) (buf as ptr)->free()

View File

@@ -22,7 +22,7 @@ func net.listen[host: str, port: i64] : i64, bool
_builtin_syscall(SYS_close, s) _builtin_syscall(SYS_close, s)
return -1, false return -1, false
~packed_host, ok := net.resolve(host) packed_host, ok := net.resolve(host)
if !ok if !ok
return -1, false return -1, false
@@ -44,7 +44,7 @@ func net.connect[host: str, port: i64] : i64, bool
if s < 0 if s < 0
return -1, false return -1, false
~packed_host, ok := net.resolve(host) packed_host, ok := net.resolve(host)
if !ok if !ok
return -1, false return -1, false
@@ -101,18 +101,18 @@ func net.UDPSocket.receive[s: net.UDPSocket, size: i64] : net.UDPPacket
func net.UDPSocket.close_and_free[s: net.UDPSocket] : void func net.UDPSocket.close_and_free[s: net.UDPSocket] : void
_builtin_syscall(SYS_close, s->fd) _builtin_syscall(SYS_close, s->fd)
s->addr->free() s->addr->free()
mem.free(s) (s as ptr)->free()
func net.create_udp_client[host: str, port: i64] : net.UDPSocket, bool func net.create_udp_client[host: str, port: i64] : net.UDPSocket, bool
s := new* net.UDPSocket s := new* net.UDPSocket
~packed_host, ok := net.resolve(host) packed_host, ok := net.resolve(host)
if !ok if !ok
return 0 as net.UDPSocket, false return 0 as net.UDPSocket, false
s->fd = _builtin_syscall(SYS_socket, AF_INET, SOCK_DGRAM, 0) s->fd = _builtin_syscall(SYS_socket, AF_INET, SOCK_DGRAM, 0)
if s->fd < 0 if s->fd < 0
mem.free(s) (s as ptr)->free()
return 0 as net.UDPSocket, false return 0 as net.UDPSocket, false
s->addr = mem.alloc(16) s->addr = mem.alloc(16)
@@ -120,7 +120,7 @@ func net.create_udp_client[host: str, port: i64] : net.UDPSocket, bool
return s, true return s, true
func net.create_udp_server[host: str, port: i64] : net.UDPSocket, bool func net.create_udp_server[host: str, port: i64] : net.UDPSocket, bool
~s, ok := net.create_udp_client(host, port) s, ok := net.create_udp_client(host, port)
if !ok if !ok
return 0 as net.UDPSocket, false return 0 as net.UDPSocket, false
@@ -141,7 +141,7 @@ struct net.UDPPacket
func net.UDPPacket.free[pkt: net.UDPPacket] : void func net.UDPPacket.free[pkt: net.UDPPacket] : void
pkt->data->free() pkt->data->free()
pkt->source_addr->free() pkt->source_addr->free()
mem.free(pkt) (pkt as ptr)->free()
func net.resolve[domain: str] : i64, bool func net.resolve[domain: str] : i64, bool
// if domain is already an ip, skip dns resolution // if domain is already an ip, skip dns resolution
@@ -172,7 +172,7 @@ func net.resolve[domain: str] : i64, bool
query := net.build_dns_query(domain, DNS_TYPE_A) query := net.build_dns_query(domain, DNS_TYPE_A)
// TODO: this probably shouldnt be hardcoded // TODO: this probably shouldnt be hardcoded
~s, ok := net.create_udp_client("1.1.1.1", 53) s, ok := net.create_udp_client("1.1.1.1", 53)
if !ok if !ok
query->free() query->free()
return -1, false return -1, false

View File

@@ -9,7 +9,7 @@ func os.exit[code: i64] : void
func os.getpid[] : i64 func os.getpid[] : i64
return _builtin_syscall(SYS_getpid) return _builtin_syscall(SYS_getpid)
func os.getenv[name: str] : str func os.getenv[name: str] : str, bool
name_len := name->len() name_len := name->len()
i := 0 i := 0
while true while true
@@ -17,15 +17,24 @@ func os.getenv[name: str] : str
if entry as ptr == 0 if entry as ptr == 0
break break
if entry->equal_n(name, name_len) && entry[name_len] == '=' if entry->equal_n(name, name_len) && entry[name_len] == '='
return (entry as ptr + name_len + 1) as str return (entry as ptr + name_len + 1) as str, true
i += 1 i += 1
return "" return 0 as str, false
func os.basename[path: str] : str func os.basename[path: str] : str
i := path->len() - 1 len := path->len()
end := len
while end > 0 && path[end - 1] == '/'
end -= 1
if end == 0
return "/"
i := end - 1
while i >= 0 && path[i] != '/' while i >= 0 && path[i] != '/'
i -= 1 i -= 1
return path->substr(i + 1, path->len() - i - 1)
return path->substr_n(i + 1, end - i - 1)
struct os.Timespec struct os.Timespec
tv_sec: i64 tv_sec: i64

View File

@@ -29,7 +29,7 @@ func u8.to_str[c: u8] : str
return s return s
func str.free[s: str] : void func str.free[s: str] : void
mem.free(s) (s as ptr)->free()
func str.len[s: str] : i64 func str.len[s: str] : i64
i := 0 i := 0
@@ -103,7 +103,7 @@ func str.format_into[..] : i64
n += 1 n += 1
i += 1 i += 1
else if s[0] == 'f' else if s[0] == 'f'
// TODO: fix when we implement f64 params // TODO: use arrow when we implement f64 params
f64.to_str_buf(_var_arg(i), tmp as ptr) f64.to_str_buf(_var_arg(i), tmp as ptr)
tmp_len := tmp->len() tmp_len := tmp->len()
remaining := size - n - 1 remaining := size - n - 1
@@ -166,7 +166,7 @@ func str.find[haystack: str, needle: str] : i64
return i return i
return -1 return -1
func str.substr[s: str, start: i64, length: i64] : str func str.substr_n[s: str, start: i64, length: i64] : str
out := mem.alloc(length + 1) as str out := mem.alloc(length + 1) as str
mem.copy(s as ptr + start, out as ptr, length) mem.copy(s as ptr + start, out as ptr, length)
out[length] = 0 out[length] = 0
@@ -188,7 +188,7 @@ func str.trim[s: str] : str
while end >= start && s[end]->is_whitespace() while end >= start && s[end]->is_whitespace()
end -= 1 end -= 1
return s->substr(start, end - start + 1) return s->substr_n(start, end - start + 1)
func str.reverse[s: str] : str func str.reverse[s: str] : str
len := s->len() len := s->len()
@@ -286,7 +286,12 @@ func str.Builder.build[b: str.Builder] : str
s[b->size] = 0 s[b->size] = 0
return s return s
func str.Builder.destroy[b: str.Builder] : void func str.Builder.build_and_free_buffer[b: str.Builder] : str
s := b->build()
b->free_buffer()
return s
func str.Builder.free_buffer[b: str.Builder] : void
if b->data != 0 if b->data != 0
b->data->free() b->data->free()
b->size = 0 b->size = 0

12
test.zr
View File

@@ -8,7 +8,7 @@ struct TestRunner
custom_run_args: HashMap custom_run_args: HashMap
func TestRunner.run_directory[tr: TestRunner, dir: str] : void func TestRunner.run_directory[tr: TestRunner, dir: str] : void
~files, ok := os.list_directory(dir) files, ok := os.list_directory(dir)
if !ok if !ok
panic("failed to open test directory") panic("failed to open test directory")
for i in 0..files->size for i in 0..files->size
@@ -28,12 +28,12 @@ func TestRunner.run_test[tr: TestRunner, x: str] : void
io.printf("Building %s...\n", x) io.printf("Building %s...\n", x)
build_cmd := "./target/release/zern "->concat(x) build_cmd := "./target/release/zern "->concat(x)
~custom_build_flags, ok := tr->custom_build_flags->get(name) custom_build_flags, ok := tr->custom_build_flags->get(name)
if ok if ok
build_cmd = build_cmd->concat(" ")->concat(custom_build_flags) build_cmd = build_cmd->concat(" ")->concat(custom_build_flags)
build_start_time := os.time() build_start_time := os.time()
~status, ok := os.run_shell_command(build_cmd) status, ok := os.run_shell_command(build_cmd)
if !ok || status != 0 if !ok || status != 0
os.exit(1) os.exit(1)
build_end_time := os.time() build_end_time := os.time()
@@ -47,12 +47,12 @@ func TestRunner.run_test[tr: TestRunner, x: str] : void
io.printf("Running %s...\n", x) io.printf("Running %s...\n", x)
run_cmd := "./out" run_cmd := "./out"
~custom_run_args, ok := tr->custom_run_args->get(name) custom_run_args, ok := tr->custom_run_args->get(name)
if ok if ok
run_cmd = run_cmd->concat(" ")->concat(custom_run_args) run_cmd = run_cmd->concat(" ")->concat(custom_run_args)
run_start_time := os.time() run_start_time := os.time()
~status, ok := os.run_shell_command(run_cmd) status, ok := os.run_shell_command(run_cmd)
if !ok || status != 0 if !ok || status != 0
io.println("Test failed.") io.println("Test failed.")
os.exit(1) os.exit(1)
@@ -61,7 +61,7 @@ func TestRunner.run_test[tr: TestRunner, x: str] : void
io.printf("Running %s took %dms\n", x, run_end_time - run_start_time) io.printf("Running %s took %dms\n", x, run_end_time - run_start_time)
func main[] : i64 func main[] : i64
~status, ok := os.run_shell_command("cargo build --release") status, ok := os.run_shell_command("cargo build --release")
if !ok || status != 0 if !ok || status != 0
os.exit(1) os.exit(1)