adding better error reporting when compiler crashes errors are now sent trough out buffer

This commit is contained in:
Jakub Doka 2024-11-08 08:36:00 +01:00
parent 0374848b28
commit 455f70db6e
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
6 changed files with 76 additions and 68 deletions

View file

@ -482,15 +482,6 @@ pub mod test {
let mut ctx = Ctx::default(); let mut ctx = Ctx::default();
let ast = parser::Ast::new(ident, minned, &mut ctx, &mut parser::no_loader); let ast = parser::Ast::new(ident, minned, &mut ctx, &mut parser::no_loader);
//log::error!(
// "{} / {} = {} | {} / {} = {}",
// ast.mem.size(),
// input.len(),
// ast.mem.size() as f32 / input.len() as f32,
// ast.mem.size(),
// ast.file.len(),
// ast.mem.size() as f32 / ast.file.len() as f32
//);
let mut output = String::new(); let mut output = String::new();
write!(output, "{ast}").unwrap(); write!(output, "{ast}").unwrap();

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
parser::{self, Ast, Ctx, FileKind}, parser::{Ast, Ctx, FileKind},
son::{self, hbvm::HbvmBackend}, son::{self, hbvm::HbvmBackend},
}, },
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
@ -42,10 +42,10 @@ pub struct Options {
} }
impl Options { impl Options {
pub fn from_args(args: &[&str]) -> std::io::Result<Self> { pub fn from_args(args: &[&str], out: &mut Vec<u8>) -> std::io::Result<Self> {
if args.contains(&"--help") || args.contains(&"-h") { if args.contains(&"--help") || args.contains(&"-h") {
log::error!("Usage: hbc [OPTIONS...] <FILE>"); writeln!(out, "Usage: hbc [OPTIONS...] <FILE>")?;
log::error!(include_str!("../command-help.txt")); writeln!(out, include_str!("../command-help.txt"))?;
return Err(std::io::ErrorKind::Other.into()); return Err(std::io::ErrorKind::Other.into());
} }
@ -58,7 +58,9 @@ impl Options {
.position(|&a| a == "--threads") .position(|&a| a == "--threads")
.map(|i| { .map(|i| {
args[i + 1].parse::<NonZeroUsize>().map_err(|e| { args[i + 1].parse::<NonZeroUsize>().map_err(|e| {
std::io::Error::other(format!("--threads expects non zero integer: {e}")) writeln!(out, "--threads expects non zero integer: {e}")
.err()
.unwrap_or(std::io::ErrorKind::Other.into())
}) })
}) })
.transpose()? .transpose()?
@ -71,32 +73,22 @@ impl Options {
pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std::io::Result<()> { pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std::io::Result<()> {
let parsed = parse_from_fs(options.extra_threads, root_file)?; let parsed = parse_from_fs(options.extra_threads, root_file)?;
fn format_ast(ast: parser::Ast) -> std::io::Result<()> { if (options.fmt || options.fmt_stdout) && !parsed.errors.is_empty() {
let mut output = String::new(); *out = parsed.errors.into_bytes();
write!(output, "{ast}").unwrap(); return Err(std::io::Error::other("fmt fialed (errors are in out)"));
if ast.file.deref().trim() != output.as_str().trim() {
std::fs::write(&*ast.path, output)?;
}
Ok(())
} }
if options.fmt { if options.fmt {
if !parsed.errors.is_empty() { let mut output = String::new();
*out = parsed.errors.into_bytes(); for ast in parsed.ast {
return Err(std::io::Error::other("parsing fialed")); write!(output, "{ast}").unwrap();
} if ast.file.deref().trim() != output.as_str().trim() {
std::fs::write(&*ast.path, &output)?;
for parsed in parsed.ast { }
format_ast(parsed)?; output.clear();
} }
} else if options.fmt_stdout { } else if options.fmt_stdout {
if !parsed.errors.is_empty() { write!(out, "{}", &parsed.ast[0])?;
*out = parsed.errors.into_bytes();
return Err(std::io::Error::other("parsing fialed"));
}
let ast = parsed.ast.into_iter().next().unwrap();
write!(out, "{ast}").unwrap();
} else { } else {
let mut backend = HbvmBackend::default(); let mut backend = HbvmBackend::default();
let mut ctx = crate::son::CodegenCtx::default(); let mut ctx = crate::son::CodegenCtx::default();
@ -107,8 +99,9 @@ pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std
codegen.generate(0); codegen.generate(0);
if !codegen.errors.borrow().is_empty() { if !codegen.errors.borrow().is_empty() {
log::error!("{}", codegen.errors.borrow()); drop(codegen);
return Err(std::io::Error::other("compilation faoled")); *out = ctx.parser.errors.into_inner().into_bytes();
return Err(std::io::Error::other("compilation faoled (errors are in out)"));
} }
codegen.assemble(out); codegen.assemble(out);

View file

@ -1,17 +1,20 @@
#[cfg(feature = "std")] #[cfg(feature = "std")]
fn main() -> std::io::Result<()> { fn main() {
use std::io::Write; use std::io::Write;
log::set_logger(&hblang::Logger).unwrap(); fn run(out: &mut Vec<u8>) -> std::io::Result<()> {
log::set_max_level(log::LevelFilter::Info); let args = std::env::args().collect::<Vec<_>>();
let args = args.iter().map(String::as_str).collect::<Vec<_>>();
let args = std::env::args().collect::<Vec<_>>(); let opts = hblang::Options::from_args(&args, out)?;
let args = args.iter().map(String::as_str).collect::<Vec<_>>(); let file = args.iter().filter(|a| !a.starts_with('-')).nth(1).copied().unwrap_or("main.hb");
let opts = hblang::Options::from_args(&args)?; hblang::run_compiler(file, opts, out)
let file = args.iter().filter(|a| !a.starts_with('-')).nth(1).copied().unwrap_or("main.hb"); }
let mut out = Vec::new(); let mut out = Vec::new();
hblang::run_compiler(file, opts, &mut out)?; match run(&mut out) {
std::io::stdout().write_all(&out) Ok(_) => std::io::stdout().write_all(&out).unwrap(),
Err(_) => std::io::stderr().write_all(&out).unwrap(),
}
} }

View file

@ -282,6 +282,14 @@ impl<'a, 'b> Parser<'a, 'b> {
fn unit_expr(&mut self) -> Option<Expr<'a>> { fn unit_expr(&mut self) -> Option<Expr<'a>> {
use {Expr as E, TokenKind as T}; use {Expr as E, TokenKind as T};
if matches!(
self.token.kind,
T::RParen | T::RBrace | T::RBrack | T::Comma | T::Semi | T::Else
) {
self.report(self.token.start, "expected expression")?;
}
let frame = self.ctx.idents.len(); let frame = self.ctx.idents.len();
let token @ Token { start: pos, .. } = self.next(); let token @ Token { start: pos, .. } = self.next();
let prev_boundary = self.ns_bound; let prev_boundary = self.ns_bound;

View file

@ -17,7 +17,7 @@ use {
CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef, CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef,
SymKey, TypeParser, Types, SymKey, TypeParser, Types,
}, },
alloc::{string::String, vec::Vec}, alloc::{rc::Rc, string::String, vec::Vec},
core::{ core::{
assert_matches::debug_assert_matches, assert_matches::debug_assert_matches,
cell::{Cell, RefCell}, cell::{Cell, RefCell},
@ -2017,6 +2017,7 @@ impl Scope {
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct ItemCtx { pub struct ItemCtx {
file: FileId, file: FileId,
pos: Vec<Pos>,
ret: Option<ty::Id>, ret: Option<ty::Id>,
task_base: usize, task_base: usize,
inline_var_base: usize, inline_var_base: usize,
@ -2195,27 +2196,9 @@ impl CodegenCtx {
} }
} }
pub struct Errors<'a>(&'a RefCell<String>);
impl Deref for Errors<'_> {
type Target = RefCell<String>;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl Drop for Errors<'_> {
fn drop(&mut self) {
if debug::panicking() && !self.0.borrow().is_empty() {
log::error!("{}", self.0.borrow());
}
}
}
pub struct Codegen<'a> { pub struct Codegen<'a> {
pub files: &'a [parser::Ast], pub files: &'a [parser::Ast],
pub errors: Errors<'a>, pub errors: &'a RefCell<String>,
tys: &'a mut Types, tys: &'a mut Types,
ci: ItemCtx, ci: ItemCtx,
pool: &'a mut Pool, pool: &'a mut Pool,
@ -2224,6 +2207,20 @@ pub struct Codegen<'a> {
backend: &'a mut dyn Backend, backend: &'a mut dyn Backend,
} }
impl Drop for Codegen<'_> {
fn drop(&mut self) {
if debug::panicking() {
if let Some(&pos) = self.ci.pos.last() {
self.report(pos, "panic occured here");
}
if !self.errors.borrow().is_empty() {
log::error!("{}", self.errors.borrow());
}
}
}
}
impl<'a> Codegen<'a> { impl<'a> Codegen<'a> {
pub fn new( pub fn new(
backend: &'a mut dyn Backend, backend: &'a mut dyn Backend,
@ -2232,7 +2229,7 @@ impl<'a> Codegen<'a> {
) -> Self { ) -> Self {
Self { Self {
files, files,
errors: Errors(&ctx.parser.errors), errors: &ctx.parser.errors,
tys: &mut ctx.tys, tys: &mut ctx.tys,
ci: Default::default(), ci: Default::default(),
pool: &mut ctx.pool, pool: &mut ctx.pool,
@ -2427,7 +2424,14 @@ impl<'a> Codegen<'a> {
self.raw_expr_ctx(expr, Ctx::default()) self.raw_expr_ctx(expr, Ctx::default())
} }
fn raw_expr_ctx(&mut self, expr: &Expr, mut ctx: Ctx) -> Option<Value> { fn raw_expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option<Value> {
self.ci.pos.push(expr.pos());
let res = self.raw_expr_ctx_low(expr, ctx);
self.ci.pos.pop().unwrap();
res
}
fn raw_expr_ctx_low(&mut self, expr: &Expr, mut ctx: Ctx) -> Option<Value> {
// ordered by complexity of the expression // ordered by complexity of the expression
match *expr { match *expr {
Expr::Null { pos } => { Expr::Null { pos } => {

9
test.hb Normal file
View file

@ -0,0 +1,9 @@
signum := fn($Expr: type, x: Expr): int {
if x > @as(Expr, @intcast(0)) {
return 1
} else if x < @as(Expr, @intcast(0)) {
return -
} else {
return 0
}
}