added better error reports

This commit is contained in:
mlokr 2024-05-12 23:19:45 +02:00
parent 4ec635dc56
commit 06e30529bf
3 changed files with 130 additions and 63 deletions

View file

@ -306,6 +306,7 @@ impl<'a> std::fmt::Display for TypeDisplay<'a> {
pub struct Codegen<'a> { pub struct Codegen<'a> {
path: &'a std::path::Path, path: &'a std::path::Path,
input: &'a [u8],
ret: Type, ret: Type,
gpa: RegAlloc, gpa: RegAlloc,
code: Func, code: Func,
@ -324,6 +325,7 @@ impl<'a> Codegen<'a> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
path: std::path::Path::new(""), path: std::path::Path::new(""),
input: &[],
ret: bt::VOID, ret: bt::VOID,
gpa: Default::default(), gpa: Default::default(),
code: Default::default(), code: Default::default(),
@ -342,10 +344,22 @@ impl<'a> Codegen<'a> {
pub fn file( pub fn file(
&mut self, &mut self,
path: &'a std::path::Path, path: &'a std::path::Path,
input: &'a [u8],
exprs: &'a [parser::Expr<'a>], exprs: &'a [parser::Expr<'a>],
) -> std::fmt::Result { ) -> std::fmt::Result {
self.path = path; self.path = path;
self.input = input;
for expr in exprs { 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); self.expr(expr, None);
} }
Ok(()) Ok(())
@ -393,9 +407,12 @@ impl<'a> Codegen<'a> {
TypeDisplay::new(self, ty) 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 { 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 record = &self.records[idx as usize];
let mut offset = 0; let mut offset = 0;
@ -407,7 +424,7 @@ impl<'a> Codegen<'a> {
offset = (offset + align - 1) & !(align - 1); offset = (offset + align - 1) & !(align - 1);
offset += self.size_of(*ty); 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 { fn loc_to_reg(&mut self, loc: Loc) -> LinReg {
@ -481,11 +498,9 @@ impl<'a> Codegen<'a> {
self.alloc_pointer(ty) self.alloc_pointer(ty)
} }
E::Ident { id, name, .. } => { E::Ident { id, name, .. } => {
let index = self let Some(index) = self.records.iter().position(|r| r.id == id) else {
.records self.report(expr.pos(), format_args!("unknown type: {}", name))
.iter() };
.position(|r| r.id == id)
.unwrap_or_else(|| panic!("type not found: {name}"));
TypeKind::Struct(index as Type).encode() TypeKind::Struct(index as Type).encode()
} }
expr => unimplemented!("type: {:#?}", expr), expr => unimplemented!("type: {:#?}", expr),
@ -501,7 +516,10 @@ impl<'a> Codegen<'a> {
E::Ctor { ty, fields } => { E::Ctor { ty, fields } => {
let ty = self.ty(&ty); let ty = self.ty(&ty);
let TypeKind::Struct(idx) = TypeKind::from_ty(ty) else { 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 let mut field_values = fields
@ -514,17 +532,20 @@ impl<'a> Codegen<'a> {
let decl_fields = self.records[idx as usize].fields.clone(); let decl_fields = self.records[idx as usize].fields.clone();
let mut offset = 0; 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 let index = field_values
.iter() .iter()
.position(|(n, _)| *n == name.as_ref()) .position(|(n, _)| *n == name.as_ref())
.unwrap(); .unwrap();
let (_, value) = field_values.remove(index); let (_, value) = field_values.remove(index);
if value.ty != *ty { if value.ty != ty {
panic!( self.report(
"expected {}, got {}", expr.pos(),
self.display_ty(*ty), format_args!(
self.display_ty(value.ty) "expected {}, got {}",
self.display_ty(ty),
self.display_ty(value.ty)
),
); );
} }
log::dbg!("ctor: {} {} {:?}", stack, offset, value.loc); log::dbg!("ctor: {} {} {:?}", stack, offset, value.loc);
@ -535,7 +556,7 @@ impl<'a> Codegen<'a> {
}, },
value, value,
); );
offset += self.size_of(*ty); offset += self.size_of(ty);
} }
Some(Value { Some(Value {
ty, ty,
@ -543,10 +564,10 @@ impl<'a> Codegen<'a> {
}) })
} }
E::Field { target, field } => { E::Field { target, field } => {
let mut target = self.expr(target, None)?; let mut tal = self.expr(target, None)?;
if let TypeKind::Pointer(ty) = TypeKind::from_ty(target.ty) { if let TypeKind::Pointer(ty) = TypeKind::from_ty(tal.ty) {
target.ty = self.pointers[ty as usize]; tal.ty = self.pointers[ty as usize];
target.loc = match target.loc { tal.loc = match tal.loc {
Loc::Reg(r) => Loc::Deref(r, 0), Loc::Reg(r) => Loc::Deref(r, 0),
Loc::RegRef(r) => Loc::DerefRef(r, 0), Loc::RegRef(r) => Loc::DerefRef(r, 0),
Loc::StackRef(stack) | Loc::Stack(stack) => { Loc::StackRef(stack) | Loc::Stack(stack) => {
@ -554,11 +575,11 @@ impl<'a> Codegen<'a> {
self.load_stack(reg.0, stack, 8); self.load_stack(reg.0, stack, 8);
Loc::Deref(reg, 0) 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 (offset, ty) = self.offset_of(target.pos(), tal.ty, field);
let loc = match target.loc { let loc = match tal.loc {
Loc::Deref(r, off) => Loc::Deref(r, off + offset), Loc::Deref(r, off) => Loc::Deref(r, off + offset),
Loc::DerefRef(r, off) => Loc::DerefRef(r, off + offset), Loc::DerefRef(r, off) => Loc::DerefRef(r, off + offset),
Loc::Stack(stack) => Loc::Stack(stack + offset), Loc::Stack(stack) => Loc::Stack(stack + offset),
@ -584,7 +605,9 @@ impl<'a> Codegen<'a> {
Some(Value::VOID) Some(Value::VOID)
} }
E::UnOp { E::UnOp {
op: T::Amp, val, .. op: T::Amp,
val,
pos,
} => { } => {
let val = self.expr(val, None)?; let val = self.expr(val, None)?;
match val.loc { match val.loc {
@ -596,11 +619,16 @@ impl<'a> Codegen<'a> {
loc: Loc::Reg(reg), 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 { E::UnOp {
op: T::Star, val, .. op: T::Star,
val,
pos,
} => { } => {
let val = self.expr(val, None)?; let val = self.expr(val, None)?;
let reg = self.loc_to_reg(val.loc); let reg = self.loc_to_reg(val.loc);
@ -609,7 +637,10 @@ impl<'a> Codegen<'a> {
ty: self.pointers[ty as usize], ty: self.pointers[ty as usize],
loc: Loc::Deref(reg, 0), 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 { E::BinOp {
@ -641,7 +672,7 @@ impl<'a> Codegen<'a> {
log::dbg!("fn-body"); log::dbg!("fn-body");
if self.expr(body, None).is_some() { 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(); self.vars.clear();
@ -689,24 +720,25 @@ impl<'a> Codegen<'a> {
}) })
} }
E::Ident { name, id, .. } => { E::Ident { name, id, .. } => {
let var = self let Some(var) = self.vars.iter().find(|v| v.id == id) else {
.vars self.report(expr.pos(), format_args!("unknown variable: {}", name))
.iter() };
.find(|v| v.id == id)
.unwrap_or_else(|| panic!("variable not found: {name}"));
Some(Value { Some(Value {
ty: var.value.ty, ty: var.value.ty,
loc: var.value.loc.take_ref(), loc: var.value.loc.take_ref(),
}) })
} }
E::Return { val, .. } => { E::Return { val, pos } => {
if let Some(val) = val { if let Some(val) = val {
let val = self.expr(val, Some(self.ret))?; let val = self.expr(val, Some(self.ret))?;
if val.ty != self.ret { if val.ty != self.ret {
panic!( self.report(
"expected {}, got {}", pos,
self.display_ty(self.ret), format_args!(
self.display_ty(val.ty) "expected {}, got {}",
self.display_ty(self.ret),
self.display_ty(val.ty)
),
); );
} }
self.assign( self.assign(
@ -1055,7 +1087,7 @@ impl<'a> Codegen<'a> {
if size > 16 { if size > 16 {
let (Loc::Stack(stack) | Loc::StackRef(stack)) = value.loc else { 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)); self.code.encode(instrs::addi64(p, STACK_PTR, stack));
} }
@ -1129,6 +1161,12 @@ impl<'a> Codegen<'a> {
l => l, 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 { pub struct Value {
@ -1239,7 +1277,7 @@ mod tests {
let mut parser = super::parser::Parser::new(input, path, &arena); let mut parser = super::parser::Parser::new(input, path, &arena);
let exprs = parser.file(); let exprs = parser.file();
let mut codegen = super::Codegen::new(); let mut codegen = super::Codegen::new();
codegen.file(path, &exprs).unwrap(); codegen.file(path, input.as_bytes(), &exprs).unwrap();
let mut out = Vec::new(); let mut out = Vec::new();
codegen.dump(&mut out).unwrap(); codegen.dump(&mut out).unwrap();

View file

@ -165,21 +165,25 @@ impl<'a> Lexer<'a> {
} }
} }
pub fn line_col(&self, mut start: u32) -> (usize, usize) { pub fn line_col(&self, pos: u32) -> (usize, usize) {
self.bytes line_col(self.bytes, pos)
.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(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> { impl<'a> Iterator for Lexer<'a> {
type Item = Token; type Item = Token;

View file

@ -6,6 +6,8 @@ use crate::{
lexer::{Lexer, Token, TokenKind}, lexer::{Lexer, Token, TokenKind},
}; };
pub type Pos = u32;
struct ScopeIdent<'a> { struct ScopeIdent<'a> {
ident: Ident, ident: Ident,
declared: bool, declared: bool,
@ -341,13 +343,13 @@ pub struct Arg<'a> {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Expr<'a> { pub enum Expr<'a> {
Break { Break {
pos: u32, pos: Pos,
}, },
Continue { Continue {
pos: u32, pos: Pos,
}, },
Closure { Closure {
pos: u32, pos: Pos,
args: &'a [Arg<'a>], args: &'a [Arg<'a>],
ret: &'a Self, ret: &'a Self,
body: &'a Self, body: &'a Self,
@ -357,7 +359,7 @@ pub enum Expr<'a> {
args: &'a [Self], args: &'a [Self],
}, },
Return { Return {
pos: u32, pos: Pos,
val: Option<&'a Self>, val: Option<&'a Self>,
}, },
Ident { Ident {
@ -366,11 +368,11 @@ pub enum Expr<'a> {
last: Option<&'a Cell<bool>>, last: Option<&'a Cell<bool>>,
}, },
Block { Block {
pos: u32, pos: Pos,
stmts: &'a [Self], stmts: &'a [Self],
}, },
Number { Number {
pos: u32, pos: Pos,
value: u64, value: u64,
}, },
BinOp { BinOp {
@ -379,22 +381,22 @@ pub enum Expr<'a> {
right: &'a Self, right: &'a Self,
}, },
If { If {
pos: u32, pos: Pos,
cond: &'a Self, cond: &'a Self,
then: &'a Self, then: &'a Self,
else_: Option<&'a Self>, else_: Option<&'a Self>,
}, },
Loop { Loop {
pos: u32, pos: Pos,
body: &'a Self, body: &'a Self,
}, },
UnOp { UnOp {
pos: u32, pos: Pos,
op: TokenKind, op: TokenKind,
val: &'a Self, val: &'a Self,
}, },
Struct { Struct {
pos: u32, pos: Pos,
fields: &'a [(&'a str, Self)], fields: &'a [(&'a str, Self)],
}, },
Ctor { Ctor {
@ -406,11 +408,34 @@ pub enum Expr<'a> {
field: &'a str, field: &'a str,
}, },
Bool { Bool {
pos: u32, pos: Pos,
value: bool, 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> { impl<'a> std::fmt::Display for Expr<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
thread_local! { thread_local! {