Compare commits

...

2 Commits

Author SHA1 Message Date
174dbfa740 make net examples print ip and data 2026-05-20 14:34:31 +02:00
48c58c0709 stack allocated structs 2026-05-20 13:59:08 +02:00
8 changed files with 68 additions and 35 deletions

View File

@@ -22,7 +22,7 @@ struct CHIP8
keyboard_map: Array keyboard_map: Array
func chip8_create[] : CHIP8 func chip8_create[] : CHIP8
let c = new CHIP8 let c = new* CHIP8
c->memory = mem.alloc(4096) c->memory = mem.alloc(4096)
mem.zero(c->memory, 4096) mem.zero(c->memory, 4096)
c->display = mem.alloc(64*32) c->display = mem.alloc(64*32)

View File

@@ -3,11 +3,17 @@ func main[] : i64
io.println("Listening on port 8000...") io.println("Listening on port 8000...")
let resp = mem.alloc(60000) let resp = mem.alloc(60000)
let addr = mem.alloc(16)
while true while true
let conn = net.accept(s) let conn = net.accept(s, addr)
if conn < 0 if conn < 0
continue continue
io.printf("%d.%d.%d.%d:%d\n", addr[4], addr[5], addr[6], addr[7], mem.read16be(addr + 2))
io.print_sized(resp, n)
io.println("")
let n = net.read(conn, resp, 60000) let n = net.read(conn, resp, 60000)
net.send(conn, resp, n) net.send(conn, resp, n)
net.close(conn) net.close(conn)

View File

@@ -8,5 +8,10 @@ func main[] : i64
net.UDPPacket.free(pkt) net.UDPPacket.free(pkt)
continue continue
io.printf("%d.%d.%d.%d:%d\n", pkt->source_addr[4], pkt->source_addr[5], pkt->source_addr[6], pkt->source_addr[7], mem.read16be(pkt->source_addr + 2))
io.print_sized(pkt->data, pkt->size)
io.println("")
net.udp_send_to(s, pkt->source_addr, pkt->data, pkt->size) net.udp_send_to(s, pkt->source_addr, pkt->data, pkt->size)
net.UDPPacket.free(pkt) net.UDPPacket.free(pkt)

View File

@@ -12,6 +12,8 @@ struct Var {
pub var_type: String, pub var_type: String,
} }
const STACK_SIZE: usize = 256; // TODO: eww
pub struct Env { pub struct Env {
scopes: Vec<HashMap<String, Var>>, scopes: Vec<HashMap<String, Var>>,
next_offset: usize, next_offset: usize,
@@ -300,7 +302,8 @@ _builtin_environ:
emit!(&mut self.output, "{}:", name.lexeme); emit!(&mut self.output, "{}:", name.lexeme);
emit!(&mut self.output, " push rbp"); emit!(&mut self.output, " push rbp");
emit!(&mut self.output, " mov rbp, rsp"); emit!(&mut self.output, " mov rbp, rsp");
emit!(&mut self.output, " sub rsp, 256"); // TODO: eww let stack_size = (STACK_SIZE + 15) & !15;
emit!(&mut self.output, " sub rsp, {}", stack_size);
match params { match params {
Params::Normal(params) => { Params::Normal(params) => {
@@ -730,16 +733,28 @@ _builtin_environ:
return error!(&op.loc, "can only take address of variables and functions"); return error!(&op.loc, "can only take address of variables and functions");
} }
}, },
ExprKind::New(struct_name) => { ExprKind::New {
struct_name,
use_heap,
} => {
let struct_fields = &self.symbol_table.structs[&struct_name.lexeme]; let struct_fields = &self.symbol_table.structs[&struct_name.lexeme];
let memory_size = struct_fields.len() * 8; let memory_size = struct_fields.len() * 8;
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"); emit!(&mut self.output, " push rax");
} else {
let aligned_size = (memory_size + 15) & !15;
emit!(&mut self.output, " sub rsp, {}", aligned_size);
emit!(&mut self.output, " mov rax, rsp");
}
emit!(&mut self.output, " push rax");
emit!(&mut self.output, " sub rsp, 8");
emit!(&mut self.output, " mov rdi, rax"); emit!(&mut self.output, " mov rdi, rax");
emit!(&mut self.output, " mov rsi, {}", memory_size); emit!(&mut self.output, " mov rsi, {}", memory_size);
emit!(&mut self.output, " call mem.zero"); emit!(&mut self.output, " call mem.zero");
emit!(&mut self.output, " add rsp, 8");
emit!(&mut self.output, " pop rax"); emit!(&mut self.output, " pop rax");
} }
ExprKind::MemberAccess { left, field } => { ExprKind::MemberAccess { left, field } => {

View File

@@ -121,7 +121,10 @@ pub enum ExprKind {
op: Token, op: Token,
expr: Box<Expr>, expr: Box<Expr>,
}, },
New(Token), New {
struct_name: Token,
use_heap: bool,
},
MemberAccess { MemberAccess {
left: Box<Expr>, left: Box<Expr>,
field: Token, field: Token,
@@ -621,9 +624,13 @@ impl Parser {
Ok(Expr::new(ExprKind::ArrayLiteral(xs))) Ok(Expr::new(ExprKind::ArrayLiteral(xs)))
} else if self.match_token(&[TokenType::KeywordNew]) { } else if self.match_token(&[TokenType::KeywordNew]) {
let use_heap = self.match_token(&[TokenType::Star]);
let struct_name = let struct_name =
self.consume(TokenType::Identifier, "expected struct name after 'new'")?; self.consume(TokenType::Identifier, "expected struct name after 'new'")?;
Ok(Expr::new(ExprKind::New(struct_name))) Ok(Expr::new(ExprKind::New {
struct_name,
use_heap,
}))
} else if self.match_token(&[TokenType::Identifier]) { } else if self.match_token(&[TokenType::Identifier]) {
Ok(Expr::new(ExprKind::Variable(self.previous().clone()))) Ok(Expr::new(ExprKind::Variable(self.previous().clone())))
} else { } else {

View File

@@ -69,8 +69,9 @@ func net.connect?[packed_host: i64, port: i64] : i64
mem.free(sa) mem.free(sa)
return s return s
func net.accept[s: i64] : i64 func net.accept[s: i64, addr: ptr] : i64
return _builtin_syscall(SYS_accept, s, 0, 0) let addrlen = 16
return _builtin_syscall(SYS_accept, s, addr, ^addrlen)
func net.send[s: i64, data: ptr, size: i64] : void func net.send[s: i64, data: ptr, size: i64] : void
_builtin_syscall(SYS_sendto, s, data, size, 0, 0, 0) _builtin_syscall(SYS_sendto, s, data, size, 0, 0, 0)
@@ -88,14 +89,9 @@ struct net.UDPSocket
fd: i64 fd: i64
addr: ptr addr: ptr
struct net.UDPPacket
data: ptr
source_addr: ptr
size: i64
func net.create_udp_client?[packed_host: i64, port: i64] : net.UDPSocket func net.create_udp_client?[packed_host: i64, port: i64] : net.UDPSocket
err.clear() err.clear()
let s = new net.UDPSocket let s = new* net.UDPSocket
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
@@ -131,8 +127,18 @@ func net.create_udp_server?[packed_host: i64, port: i64] : net.UDPSocket
func net.udp_send_to[s: net.UDPSocket, addr: ptr, data: ptr, size: i64] : void func net.udp_send_to[s: net.UDPSocket, addr: ptr, data: ptr, size: i64] : void
_builtin_syscall(SYS_sendto, s->fd, data, size, 0, addr, 16) _builtin_syscall(SYS_sendto, s->fd, data, size, 0, addr, 16)
struct net.UDPPacket
data: ptr
source_addr: ptr
size: i64
func net.UDPPacket.free[pkt: net.UDPPacket] : void
mem.free(pkt->data)
mem.free(pkt->source_addr)
mem.free(pkt)
func net.udp_receive[s: net.UDPSocket, size: i64] : net.UDPPacket func net.udp_receive[s: net.UDPSocket, size: i64] : net.UDPPacket
let pkt = new net.UDPPacket let pkt = new* net.UDPPacket
pkt->data = mem.alloc(size) pkt->data = mem.alloc(size)
pkt->source_addr = mem.alloc(16) pkt->source_addr = mem.alloc(16)
mem.zero(pkt->source_addr, 16) mem.zero(pkt->source_addr, 16)
@@ -146,11 +152,6 @@ func net.UDPSocket.close_and_free[s: net.UDPSocket] : void
mem.free(s->addr) mem.free(s->addr)
mem.free(s) mem.free(s)
func net.UDPPacket.free[pkt: net.UDPPacket] : void
mem.free(pkt->data)
mem.free(pkt->source_addr)
mem.free(pkt)
const DNS_TYPE_A = 1 const DNS_TYPE_A = 1
const DNS_CLASS_IN = 1 const DNS_CLASS_IN = 1
const DNS_RECURSION_DESIRED = 256 const DNS_RECURSION_DESIRED = 256
@@ -195,7 +196,7 @@ func net.build_dns_query[domain_name: str, record_type: i64] : io.Buffer
io.Buffer.free(name) io.Buffer.free(name)
return out return out
// TODO: dont resolve IPs // TODO: dont resolve if its already an IP
func net.resolve?[domain: str] : i64 func net.resolve?[domain: str] : i64
err.clear() err.clear()
let query = net.build_dns_query(domain, DNS_TYPE_A) let query = net.build_dns_query(domain, DNS_TYPE_A)

View File

@@ -339,7 +339,7 @@ struct io.Buffer
func io.Buffer.alloc?[size: i64] : io.Buffer func io.Buffer.alloc?[size: i64] : io.Buffer
err.clear() err.clear()
let buffer = new io.Buffer let buffer = new* io.Buffer
buffer->size = size buffer->size = size
buffer->data = mem.alloc?(size) buffer->data = mem.alloc?(size)
if err.check() if err.check()
@@ -403,7 +403,7 @@ func io.read_binary_file?[path: str] : io.Buffer
err.set(ERR_OPEN_FAILED, "io.read_binary_file?: failed to open file") err.set(ERR_OPEN_FAILED, "io.read_binary_file?: failed to open file")
return 0 as io.Buffer return 0 as io.Buffer
let buf = new io.Buffer let buf = new* io.Buffer
buf->size = _builtin_syscall(SYS_lseek, fd, 0, 2) buf->size = _builtin_syscall(SYS_lseek, fd, 0, 2)
_builtin_syscall(SYS_lseek, fd, 0, 0) _builtin_syscall(SYS_lseek, fd, 0, 0)
@@ -777,10 +777,10 @@ struct Array
capacity: i64 capacity: i64
func array.new[] : Array func array.new[] : Array
return new Array return new* Array
func array.new_preallocated_and_zeroed[size: i64] : Array func array.new_preallocated_and_zeroed[size: i64] : Array
let xs = new Array let xs = new* Array
if size > 0 if size > 0
xs->data = must(mem.realloc?(xs->data, size * 8)) as ptr xs->data = must(mem.realloc?(xs->data, size * 8)) as ptr
mem.zero(xs->data, size * 8) mem.zero(xs->data, size * 8)
@@ -849,7 +849,7 @@ struct HashMap._Node
next: HashMap._Node next: HashMap._Node
func HashMap.new[] : HashMap func HashMap.new[] : HashMap
let map = new HashMap let map = new* HashMap
map->table = array.new_preallocated_and_zeroed(HashMap._TABLE_SIZE) map->table = array.new_preallocated_and_zeroed(HashMap._TABLE_SIZE)
return map return map
@@ -863,7 +863,7 @@ func HashMap.insert[map: HashMap, key: str, value: any] : void
return 0 return 0
current = current->next current = current->next
let new_node = new HashMap._Node let new_node = new* HashMap._Node
new_node->key = str.make_copy(key) new_node->key = str.make_copy(key)
new_node->value = value new_node->value = value
new_node->next = array.nth(map->table, index) new_node->next = array.nth(map->table, index)
@@ -982,12 +982,10 @@ struct os.Timespec
func os.sleep[ms: i64] : void func os.sleep[ms: i64] : void
if ms < 0 if ms < 0
panic("negative time passed to os.sleep") panic("negative time passed to os.sleep")
// TODO: we really shouldnt need a heap allocation to sleep
let req = new os.Timespec let req = new os.Timespec
req->tv_sec = ms / 1000 req->tv_sec = ms / 1000
req->tv_nsec = (ms % 1000) * 1000000 req->tv_nsec = (ms % 1000) * 1000000
_builtin_syscall(SYS_nanosleep, req, 0) _builtin_syscall(SYS_nanosleep, req, 0)
mem.free(req)
func os.urandom?[n: i64]: ptr func os.urandom?[n: i64]: ptr
err.clear() err.clear()
@@ -1022,11 +1020,9 @@ struct os.Timeval
tv_usec: i64 tv_usec: i64
func os.time[] : i64 func os.time[] : i64
// TODO: we really shouldnt need a heap allocation to check the time
let tv = new os.Timeval let tv = new os.Timeval
_builtin_syscall(SYS_gettimeofday, tv, 0) _builtin_syscall(SYS_gettimeofday, tv, 0)
let out = tv->tv_sec * 1000 + tv->tv_usec / 1000 let out = tv->tv_sec * 1000 + tv->tv_usec / 1000
mem.free(tv)
return out return out
// voodoo magic // voodoo magic

View File

@@ -483,7 +483,10 @@ impl<'a> TypeChecker<'a> {
error!(&op.loc, "can only take address of variables and functions") error!(&op.loc, "can only take address of variables and functions")
} }
}, },
ExprKind::New(struct_name) => { ExprKind::New {
struct_name,
use_heap: _,
} => {
if !self.symbol_table.structs.contains_key(&struct_name.lexeme) { if !self.symbol_table.structs.contains_key(&struct_name.lexeme) {
return error!( return error!(
&struct_name.loc, &struct_name.loc,