diff --git a/examples/chip8.zr b/examples/chip8.zr index 11e65e3..0677b8e 100644 --- a/examples/chip8.zr +++ b/examples/chip8.zr @@ -290,7 +290,7 @@ func main[argc: i64, argv: ptr] : i64 c := chip8_create() - buffer : io.Buffer = must(io.read_binary_file?(path)) + buffer : Blob = must(io.read_binary_file?(path)) for i in 0..buffer->size c->memory[0x200 + i] = buffer->data[i] diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 1405c47..9fd690a 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -236,6 +236,45 @@ _builtin_environ: let offset = env.define_var(name.lexeme.clone(), var_type); emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); } + Stmt::Assign { left, op, value } => { + self.compile_expr(env, value)?; + + match &left.kind { + ExprKind::Variable(name) => { + // already ensured by the typechecker + let var = env.get_var(&name.lexeme).unwrap(); + emit!( + &mut self.output, + " mov QWORD [rbp-{}], rax", + var.stack_offset, + ); + } + ExprKind::Index { + expr, + bracket: _, + index, + } => { + emit!(&mut self.output, " push rax"); + self.compile_expr(env, expr)?; + emit!(&mut self.output, " push rax"); + self.compile_expr(env, index)?; + emit!(&mut self.output, " pop rbx"); + emit!(&mut self.output, " add rbx, rax"); + emit!(&mut self.output, " pop rax"); + emit!(&mut self.output, " mov BYTE [rbx], al"); + } + ExprKind::MemberAccess { left, field } => { + emit!(&mut self.output, " push rax"); + + let offset = self.get_field_offset(left, field)?; + + self.compile_expr(env, left)?; + emit!(&mut self.output, " pop rbx"); + emit!(&mut self.output, " mov QWORD [rax+{}], rbx", offset); + } + _ => return error!(&op.loc, "invalid assignment target"), + }; + } Stmt::Const { name: _, value: _ } => { // handled in SymbolTable } @@ -573,45 +612,6 @@ _builtin_environ: ); } } - ExprKind::Assign { left, op, value } => { - self.compile_expr(env, value)?; - - match &left.kind { - ExprKind::Variable(name) => { - // already ensured by the typechecker - let var = env.get_var(&name.lexeme).unwrap(); - emit!( - &mut self.output, - " mov QWORD [rbp-{}], rax", - var.stack_offset, - ); - } - ExprKind::Index { - expr, - bracket: _, - index, - } => { - emit!(&mut self.output, " push rax"); - self.compile_expr(env, expr)?; - emit!(&mut self.output, " push rax"); - self.compile_expr(env, index)?; - emit!(&mut self.output, " pop rbx"); - emit!(&mut self.output, " add rbx, rax"); - emit!(&mut self.output, " pop rax"); - emit!(&mut self.output, " mov BYTE [rbx], al"); - } - ExprKind::MemberAccess { left, field } => { - emit!(&mut self.output, " push rax"); - - let offset = self.get_field_offset(left, field)?; - - self.compile_expr(env, left)?; - emit!(&mut self.output, " pop rbx"); - emit!(&mut self.output, " mov QWORD [rax+{}], rbx", offset); - } - _ => return error!(&op.loc, "invalid assignment target"), - }; - } ExprKind::Call { callee, paren: _, diff --git a/src/parser.rs b/src/parser.rs index ad13782..1bb82fb 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -22,6 +22,11 @@ pub enum Stmt { var_type: Option, initializer: Expr, }, + Assign { + left: Expr, + op: Token, + value: Expr, + }, Const { name: Token, value: Token, @@ -101,11 +106,6 @@ pub enum ExprKind { right: Box, }, Variable(Token), - Assign { - left: Box, - op: Token, - value: Box, - }, Call { callee: Box, paren: Token, @@ -312,7 +312,18 @@ impl Parser { } else if self.match_token(&[TokenType::KeywordContinue]) { Ok(Stmt::Continue) } else { - Ok(Stmt::Expression(self.expression()?)) + let expr = self.expression()?; + if self.match_token(&[TokenType::Equal]) { + let op = self.previous().clone(); + let value = self.expression()?; + Ok(Stmt::Assign { + left: expr, + op, + value, + }) + } else { + Ok(Stmt::Expression(expr)) + } } } @@ -365,24 +376,7 @@ impl Parser { } fn expression(&mut self) -> Result { - self.assignment() - } - - fn assignment(&mut self) -> Result { - let expr = self.pipe()?; - - if self.match_token(&[TokenType::Equal]) { - let equals = self.previous().clone(); - let value = self.assignment()?; - - return Ok(Expr::new(ExprKind::Assign { - left: Box::new(expr), - op: equals, - value: Box::new(value), - })); - } - - Ok(expr) + self.pipe() } fn pipe(&mut self) -> Result { diff --git a/src/std/net.zr b/src/std/net.zr index 9aeeab5..72ddccb 100644 --- a/src/std/net.zr +++ b/src/std/net.zr @@ -156,9 +156,9 @@ const DNS_TYPE_A = 1 const DNS_CLASS_IN = 1 const DNS_RECURSION_DESIRED = 256 -func net.encode_dns_name[domain: str] : io.Buffer +func net.encode_dns_name[domain: str] : Blob domain_len := str.len(domain) - buf : io.Buffer = must(io.Buffer.alloc?(domain_len + 2)) + buf : Blob = must(Blob.alloc?(domain_len + 2)) out_pos := 0 part_start := 0 i := 0 @@ -175,9 +175,9 @@ func net.encode_dns_name[domain: str] : io.Buffer buf->data[out_pos] = 0 return buf -func net.build_dns_query[domain_name: str, record_type: i64] : io.Buffer +func net.build_dns_query[domain_name: str, record_type: i64] : Blob name := net.encode_dns_name(domain_name) - out : io.Buffer = must(io.Buffer.alloc?(12 + name->size + 4)) + out : Blob = must(Blob.alloc?(12 + name->size + 4)) // header id := math.abs(os.urandom_i64() % 65536) @@ -193,7 +193,7 @@ func net.build_dns_query[domain_name: str, record_type: i64] : io.Buffer mem.write16be(out->data + 12 + name->size, record_type) mem.write16be(out->data + 12 + name->size + 2, DNS_CLASS_IN) - io.Buffer.free(name) + Blob.free(name) return out // TODO: dont resolve if its already an IP @@ -207,7 +207,7 @@ func net.resolve?[domain: str] : i64 return -1 net.udp_send_to(s, s->addr, query->data, query->size) - io.Buffer.free(query) + Blob.free(query) pkt := net.udp_receive(s, 1024) net.UDPSocket.close_and_free(s) diff --git a/src/std/std.zr b/src/std/std.zr index 1f498ee..35c7b59 100644 --- a/src/std/std.zr +++ b/src/std/std.zr @@ -333,21 +333,21 @@ func io.read_line[]: str buffer = must(mem.realloc?(buffer as ptr, n + 1)) return buffer -struct io.Buffer +struct Blob data: ptr size: i64 -func io.Buffer.alloc?[size: i64] : io.Buffer +func Blob.alloc?[size: i64] : Blob err.clear() - buffer := new* io.Buffer + buffer := new* Blob buffer->size = size buffer->data = mem.alloc?(size) if err.check() mem.free(buffer) - return 0 as io.Buffer + return 0 as Blob return buffer -func io.Buffer.free[buf: io.Buffer] : void +func Blob.free[buf: Blob] : void mem.free(buf->data) mem.free(buf) @@ -396,30 +396,30 @@ func io.read_text_file?[path: str] : str buffer[n] = 0 return buffer -func io.read_binary_file?[path: str] : io.Buffer +func io.read_binary_file?[path: str] : Blob err.clear() fd := _builtin_syscall(SYS_openat, -100, path, 0, 0) if fd < 0 err.set(ERR_OPEN_FAILED, "io.read_binary_file?: failed to open file") - return 0 as io.Buffer + return 0 as Blob - buf := new* io.Buffer + buf := new* Blob buf->size = _builtin_syscall(SYS_lseek, fd, 0, 2) _builtin_syscall(SYS_lseek, fd, 0, 0) buf->data = mem.alloc?(buf->size) if err.check() - io.Buffer.free(buf) + Blob.free(buf) _builtin_syscall(SYS_close, fd) - return 0 as io.Buffer + return 0 as Blob n := _builtin_syscall(SYS_read, fd, buf->data, buf->size) _builtin_syscall(SYS_close, fd) if n != buf->size - io.Buffer.free(buf) + Blob.free(buf) err.set(ERR_READ_FAILED, "io.read_binary_file?: failed to read file") - return 0 as io.Buffer + return 0 as Blob return buf diff --git a/src/typechecker.rs b/src/typechecker.rs index 19a4aa4..3fa34a4 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -111,6 +111,59 @@ impl<'a> TypeChecker<'a> { env.define_var(name.lexeme.clone(), actual_type); } + Stmt::Assign { left, op, value } => { + let value_type = self.typecheck_expr(env, value)?; + + match &left.kind { + ExprKind::Variable(name) => { + let existing_var_type = match env.get_var_type(&name.lexeme) { + Some(x) => x, + None => { + return error!( + name.loc, + format!("undefined variable: {}", &name.lexeme) + ); + } + }; + expect_type!(value_type.clone(), *existing_var_type, name.loc); + } + ExprKind::Index { + expr, + bracket, + index, + } => { + expect_types!(self.typecheck_expr(env, expr)?, ["ptr", "str"], bracket.loc); + expect_types!(self.typecheck_expr(env, index)?, ["i64", "u8"], bracket.loc); + expect_types!(value_type.clone(), ["u8", "i64"], bracket.loc); + } + ExprKind::MemberAccess { left, field } => { + let left_type = self.typecheck_expr(env, left)?; + + let fields = match self.symbol_table.structs.get(&left_type) { + Some(f) => f, + None => { + return error!( + &field.loc, + format!("unknown struct type: {}", left_type) + ); + } + }; + + let f = match fields.get(&field.lexeme) { + Some(o) => o, + None => { + return error!( + &field.loc, + format!("unknown field: {}", &field.lexeme) + ); + } + }; + + expect_type!(value_type.clone(), f.field_type, field.loc); + } + _ => return error!(&op.loc, "invalid assignment target"), + } + } Stmt::Const { name: _, value: _ } => { // handled in SymbolTable } @@ -354,60 +407,6 @@ impl<'a> TypeChecker<'a> { } } } - ExprKind::Assign { left, op, value } => { - let value_type = self.typecheck_expr(env, value)?; - - match &left.kind { - ExprKind::Variable(name) => { - let existing_var_type = match env.get_var_type(&name.lexeme) { - Some(x) => x, - None => { - return error!( - name.loc, - format!("undefined variable: {}", &name.lexeme) - ); - } - }; - expect_type!(value_type.clone(), *existing_var_type, name.loc); - } - ExprKind::Index { - expr, - bracket, - index, - } => { - expect_types!(self.typecheck_expr(env, expr)?, ["ptr", "str"], bracket.loc); - expect_types!(self.typecheck_expr(env, index)?, ["i64", "u8"], bracket.loc); - expect_types!(value_type.clone(), ["u8", "i64"], bracket.loc); - } - ExprKind::MemberAccess { left, field } => { - let left_type = self.typecheck_expr(env, left)?; - - let fields = match self.symbol_table.structs.get(&left_type) { - Some(f) => f, - None => { - return error!( - &field.loc, - format!("unknown struct type: {}", left_type) - ); - } - }; - - let f = match fields.get(&field.lexeme) { - Some(o) => o, - None => { - return error!( - &field.loc, - format!("unknown field: {}", &field.lexeme) - ); - } - }; - - expect_type!(value_type.clone(), f.field_type, field.loc); - } - _ => return error!(&op.loc, "invalid assignment target"), - } - Ok(value_type) - } ExprKind::Call { callee, paren,