added better error reports
This commit is contained in:
parent
4ec635dc56
commit
06e30529bf
|
@ -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(
|
||||||
|
expr.pos(),
|
||||||
|
format_args!(
|
||||||
"expected {}, got {}",
|
"expected {}, got {}",
|
||||||
self.display_ty(*ty),
|
self.display_ty(ty),
|
||||||
self.display_ty(value.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(
|
||||||
|
pos,
|
||||||
|
format_args!(
|
||||||
"expected {}, got {}",
|
"expected {}, got {}",
|
||||||
self.display_ty(self.ret),
|
self.display_ty(self.ret),
|
||||||
self.display_ty(val.ty)
|
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();
|
||||||
|
|
||||||
|
|
|
@ -165,8 +165,13 @@ 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn line_col(bytes: &[u8], mut start: u32) -> (usize, usize) {
|
||||||
|
bytes
|
||||||
.split(|&b| b == b'\n')
|
.split(|&b| b == b'\n')
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map(|(i, line)| {
|
.find_map(|(i, line)| {
|
||||||
|
@ -178,7 +183,6 @@ impl<'a> Lexer<'a> {
|
||||||
})
|
})
|
||||||
.unwrap_or((1, 1))
|
.unwrap_or((1, 1))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for Lexer<'a> {
|
impl<'a> Iterator for Lexer<'a> {
|
||||||
type Item = Token;
|
type Item = Token;
|
||||||
|
|
|
@ -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! {
|
||||||
|
|
Loading…
Reference in a new issue