From 06e30529bf7a8804bf74532e05f934bcfa85a0cf Mon Sep 17 00:00:00 2001 From: mlokr Date: Sun, 12 May 2024 23:19:45 +0200 Subject: [PATCH] added better error reports --- hblang/src/codegen.rs | 118 ++++++++++++++++++++++++++++-------------- hblang/src/lexer.rs | 28 +++++----- hblang/src/parser.rs | 47 +++++++++++++---- 3 files changed, 130 insertions(+), 63 deletions(-) diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index c1c83118..ab7fc446 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -306,6 +306,7 @@ impl<'a> std::fmt::Display for TypeDisplay<'a> { pub struct Codegen<'a> { path: &'a std::path::Path, + input: &'a [u8], ret: Type, gpa: RegAlloc, code: Func, @@ -324,6 +325,7 @@ impl<'a> Codegen<'a> { pub fn new() -> Self { Self { path: std::path::Path::new(""), + input: &[], ret: bt::VOID, gpa: Default::default(), code: Default::default(), @@ -342,10 +344,22 @@ impl<'a> Codegen<'a> { pub fn file( &mut self, path: &'a std::path::Path, + input: &'a [u8], exprs: &'a [parser::Expr<'a>], ) -> std::fmt::Result { self.path = path; + self.input = input; + for expr in exprs { + let E::BinOp { + left: E::Ident { .. }, + op: T::Decl, + .. + } = expr + else { + self.report(expr.pos(), format_args!("expected declaration")); + }; + self.expr(expr, None); } Ok(()) @@ -393,9 +407,12 @@ impl<'a> Codegen<'a> { TypeDisplay::new(self, ty) } - fn offset_of(&self, ty: Type, field: &str) -> (u64, Type) { + fn offset_of(&self, pos: parser::Pos, ty: Type, field: &str) -> (u64, Type) { let TypeKind::Struct(idx) = TypeKind::from_ty(ty) else { - panic!("expected struct, got {}", self.display_ty(ty)); + self.report( + pos, + format_args!("expected struct, got {}", self.display_ty(ty)), + ); }; let record = &self.records[idx as usize]; let mut offset = 0; @@ -407,7 +424,7 @@ impl<'a> Codegen<'a> { offset = (offset + align - 1) & !(align - 1); offset += self.size_of(*ty); } - panic!("field not found: {:?}", field); + self.report(pos, format_args!("field not found: {}", field)); } fn loc_to_reg(&mut self, loc: Loc) -> LinReg { @@ -481,11 +498,9 @@ impl<'a> Codegen<'a> { self.alloc_pointer(ty) } E::Ident { id, name, .. } => { - let index = self - .records - .iter() - .position(|r| r.id == id) - .unwrap_or_else(|| panic!("type not found: {name}")); + let Some(index) = self.records.iter().position(|r| r.id == id) else { + self.report(expr.pos(), format_args!("unknown type: {}", name)) + }; TypeKind::Struct(index as Type).encode() } expr => unimplemented!("type: {:#?}", expr), @@ -501,7 +516,10 @@ impl<'a> Codegen<'a> { E::Ctor { ty, fields } => { let ty = self.ty(&ty); let TypeKind::Struct(idx) = TypeKind::from_ty(ty) else { - panic!("expected struct, got {}", self.display_ty(ty)); + self.report( + expr.pos(), + format_args!("expected struct, got {}", self.display_ty(ty)), + ); }; let mut field_values = fields @@ -514,17 +532,20 @@ impl<'a> Codegen<'a> { let decl_fields = self.records[idx as usize].fields.clone(); let mut offset = 0; - for (name, ty) in decl_fields.as_ref() { + for &(ref name, ty) in decl_fields.as_ref() { let index = field_values .iter() .position(|(n, _)| *n == name.as_ref()) .unwrap(); let (_, value) = field_values.remove(index); - if value.ty != *ty { - panic!( - "expected {}, got {}", - self.display_ty(*ty), - self.display_ty(value.ty) + if value.ty != ty { + self.report( + expr.pos(), + format_args!( + "expected {}, got {}", + self.display_ty(ty), + self.display_ty(value.ty) + ), ); } log::dbg!("ctor: {} {} {:?}", stack, offset, value.loc); @@ -535,7 +556,7 @@ impl<'a> Codegen<'a> { }, value, ); - offset += self.size_of(*ty); + offset += self.size_of(ty); } Some(Value { ty, @@ -543,10 +564,10 @@ impl<'a> Codegen<'a> { }) } E::Field { target, field } => { - let mut target = self.expr(target, None)?; - if let TypeKind::Pointer(ty) = TypeKind::from_ty(target.ty) { - target.ty = self.pointers[ty as usize]; - target.loc = match target.loc { + let mut tal = self.expr(target, None)?; + if let TypeKind::Pointer(ty) = TypeKind::from_ty(tal.ty) { + tal.ty = self.pointers[ty as usize]; + tal.loc = match tal.loc { Loc::Reg(r) => Loc::Deref(r, 0), Loc::RegRef(r) => Loc::DerefRef(r, 0), Loc::StackRef(stack) | Loc::Stack(stack) => { @@ -554,11 +575,11 @@ impl<'a> Codegen<'a> { self.load_stack(reg.0, stack, 8); Loc::Deref(reg, 0) } - l => panic!("cant get field of {:?}", l), + l => todo!("cant get field of {:?}", l), }; } - let (offset, ty) = self.offset_of(target.ty, field); - let loc = match target.loc { + let (offset, ty) = self.offset_of(target.pos(), tal.ty, field); + let loc = match tal.loc { Loc::Deref(r, off) => Loc::Deref(r, off + offset), Loc::DerefRef(r, off) => Loc::DerefRef(r, off + offset), Loc::Stack(stack) => Loc::Stack(stack + offset), @@ -584,7 +605,9 @@ impl<'a> Codegen<'a> { Some(Value::VOID) } E::UnOp { - op: T::Amp, val, .. + op: T::Amp, + val, + pos, } => { let val = self.expr(val, None)?; match val.loc { @@ -596,11 +619,16 @@ impl<'a> Codegen<'a> { loc: Loc::Reg(reg), }) } - l => panic!("cant take pointer of {} ({:?})", self.display_ty(val.ty), l), + l => self.report( + pos, + format_args!("cant take pointer of {} ({:?})", self.display_ty(val.ty), l), + ), } } E::UnOp { - op: T::Star, val, .. + op: T::Star, + val, + pos, } => { let val = self.expr(val, None)?; let reg = self.loc_to_reg(val.loc); @@ -609,7 +637,10 @@ impl<'a> Codegen<'a> { ty: self.pointers[ty as usize], loc: Loc::Deref(reg, 0), }), - _ => panic!("cant deref {}", self.display_ty(val.ty)), + _ => self.report( + pos, + format_args!("expected pointer, got {}", self.display_ty(val.ty)), + ), } } E::BinOp { @@ -641,7 +672,7 @@ impl<'a> Codegen<'a> { log::dbg!("fn-body"); if self.expr(body, None).is_some() { - panic!("expected all paths in the fucntion {name} to return"); + self.report(body.pos(), "expected all paths in the fucntion to return"); } self.vars.clear(); @@ -689,24 +720,25 @@ impl<'a> Codegen<'a> { }) } E::Ident { name, id, .. } => { - let var = self - .vars - .iter() - .find(|v| v.id == id) - .unwrap_or_else(|| panic!("variable not found: {name}")); + let Some(var) = self.vars.iter().find(|v| v.id == id) else { + self.report(expr.pos(), format_args!("unknown variable: {}", name)) + }; Some(Value { ty: var.value.ty, loc: var.value.loc.take_ref(), }) } - E::Return { val, .. } => { + E::Return { val, pos } => { if let Some(val) = val { let val = self.expr(val, Some(self.ret))?; if val.ty != self.ret { - panic!( - "expected {}, got {}", - self.display_ty(self.ret), - self.display_ty(val.ty) + self.report( + pos, + format_args!( + "expected {}, got {}", + self.display_ty(self.ret), + self.display_ty(val.ty) + ), ); } self.assign( @@ -1055,7 +1087,7 @@ impl<'a> Codegen<'a> { if size > 16 { let (Loc::Stack(stack) | Loc::StackRef(stack)) = value.loc else { - panic!("expected stack location, got {:?}", value.loc); + todo!("expected stack location, got {:?}", value.loc); }; self.code.encode(instrs::addi64(p, STACK_PTR, stack)); } @@ -1129,6 +1161,12 @@ impl<'a> Codegen<'a> { l => l, } } + + fn report(&self, pos: parser::Pos, msg: impl std::fmt::Display) -> ! { + let (line, col) = lexer::line_col(self.input, pos); + println!("{}:{}:{}: {}", self.path.display(), line, col, msg); + unreachable!(); + } } pub struct Value { @@ -1239,7 +1277,7 @@ mod tests { let mut parser = super::parser::Parser::new(input, path, &arena); let exprs = parser.file(); let mut codegen = super::Codegen::new(); - codegen.file(path, &exprs).unwrap(); + codegen.file(path, input.as_bytes(), &exprs).unwrap(); let mut out = Vec::new(); codegen.dump(&mut out).unwrap(); diff --git a/hblang/src/lexer.rs b/hblang/src/lexer.rs index 46d629bc..321c87eb 100644 --- a/hblang/src/lexer.rs +++ b/hblang/src/lexer.rs @@ -165,21 +165,25 @@ impl<'a> Lexer<'a> { } } - pub fn line_col(&self, mut start: u32) -> (usize, usize) { - self.bytes - .split(|&b| b == b'\n') - .enumerate() - .find_map(|(i, line)| { - if start < line.len() as u32 { - return Some((i + 1, start as usize + 1)); - } - start -= line.len() as u32 + 1; - None - }) - .unwrap_or((1, 1)) + pub fn line_col(&self, pos: u32) -> (usize, usize) { + line_col(self.bytes, pos) } } +pub fn line_col(bytes: &[u8], mut start: u32) -> (usize, usize) { + bytes + .split(|&b| b == b'\n') + .enumerate() + .find_map(|(i, line)| { + if start < line.len() as u32 { + return Some((i + 1, start as usize + 1)); + } + start -= line.len() as u32 + 1; + None + }) + .unwrap_or((1, 1)) +} + impl<'a> Iterator for Lexer<'a> { type Item = Token; diff --git a/hblang/src/parser.rs b/hblang/src/parser.rs index 4f729037..ce51d95b 100644 --- a/hblang/src/parser.rs +++ b/hblang/src/parser.rs @@ -6,6 +6,8 @@ use crate::{ lexer::{Lexer, Token, TokenKind}, }; +pub type Pos = u32; + struct ScopeIdent<'a> { ident: Ident, declared: bool, @@ -341,13 +343,13 @@ pub struct Arg<'a> { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Expr<'a> { Break { - pos: u32, + pos: Pos, }, Continue { - pos: u32, + pos: Pos, }, Closure { - pos: u32, + pos: Pos, args: &'a [Arg<'a>], ret: &'a Self, body: &'a Self, @@ -357,7 +359,7 @@ pub enum Expr<'a> { args: &'a [Self], }, Return { - pos: u32, + pos: Pos, val: Option<&'a Self>, }, Ident { @@ -366,11 +368,11 @@ pub enum Expr<'a> { last: Option<&'a Cell>, }, Block { - pos: u32, + pos: Pos, stmts: &'a [Self], }, Number { - pos: u32, + pos: Pos, value: u64, }, BinOp { @@ -379,22 +381,22 @@ pub enum Expr<'a> { right: &'a Self, }, If { - pos: u32, + pos: Pos, cond: &'a Self, then: &'a Self, else_: Option<&'a Self>, }, Loop { - pos: u32, + pos: Pos, body: &'a Self, }, UnOp { - pos: u32, + pos: Pos, op: TokenKind, val: &'a Self, }, Struct { - pos: u32, + pos: Pos, fields: &'a [(&'a str, Self)], }, Ctor { @@ -406,11 +408,34 @@ pub enum Expr<'a> { field: &'a str, }, Bool { - pos: u32, + pos: Pos, value: bool, }, } +impl<'a> Expr<'a> { + pub fn pos(&self) -> Pos { + match self { + Self::Break { pos } => *pos, + Self::Continue { pos } => *pos, + Self::Closure { pos, .. } => *pos, + Self::Call { func, .. } => func.pos(), + Self::Return { pos, .. } => *pos, + Self::Ident { id, .. } => ident::pos(*id), + Self::Block { pos, .. } => *pos, + Self::Number { pos, .. } => *pos, + Self::BinOp { left, .. } => left.pos(), + Self::If { pos, .. } => *pos, + Self::Loop { pos, .. } => *pos, + Self::UnOp { pos, .. } => *pos, + Self::Struct { pos, .. } => *pos, + Self::Ctor { ty, .. } => ty.pos(), + Self::Field { target, .. } => target.pos(), + Self::Bool { pos, .. } => *pos, + } + } +} + impl<'a> std::fmt::Display for Expr<'a> { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { thread_local! {