std json parser

This commit is contained in:
2026-07-05 15:22:50 +02:00
parent 873aa3e1cc
commit aea9ce911a
14 changed files with 275 additions and 84 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

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

@@ -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

@@ -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

@@ -101,7 +101,7 @@ 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
@@ -112,7 +112,7 @@ func net.create_udp_client[host: str, port: i64] : net.UDPSocket, bool
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)
@@ -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

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