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 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();
write!(output, "{ast}").unwrap();

View file

@ -1,6 +1,6 @@
use {
crate::{
parser::{self, Ast, Ctx, FileKind},
parser::{Ast, Ctx, FileKind},
son::{self, hbvm::HbvmBackend},
},
alloc::{string::String, vec::Vec},
@ -42,10 +42,10 @@ pub struct 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") {
log::error!("Usage: hbc [OPTIONS...] <FILE>");
log::error!(include_str!("../command-help.txt"));
writeln!(out, "Usage: hbc [OPTIONS...] <FILE>")?;
writeln!(out, include_str!("../command-help.txt"))?;
return Err(std::io::ErrorKind::Other.into());
}
@ -58,7 +58,9 @@ impl Options {
.position(|&a| a == "--threads")
.map(|i| {
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()?
@ -71,32 +73,22 @@ impl Options {
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)?;
fn format_ast(ast: parser::Ast) -> std::io::Result<()> {
let mut output = String::new();
write!(output, "{ast}").unwrap();
if ast.file.deref().trim() != output.as_str().trim() {
std::fs::write(&*ast.path, output)?;
}
Ok(())
if (options.fmt || options.fmt_stdout) && !parsed.errors.is_empty() {
*out = parsed.errors.into_bytes();
return Err(std::io::Error::other("fmt fialed (errors are in out)"));
}
if options.fmt {
if !parsed.errors.is_empty() {
*out = parsed.errors.into_bytes();
return Err(std::io::Error::other("parsing fialed"));
}
for parsed in parsed.ast {
format_ast(parsed)?;
let mut output = String::new();
for ast in parsed.ast {
write!(output, "{ast}").unwrap();
if ast.file.deref().trim() != output.as_str().trim() {
std::fs::write(&*ast.path, &output)?;
}
output.clear();
}
} else if options.fmt_stdout {
if !parsed.errors.is_empty() {
*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();
write!(out, "{}", &parsed.ast[0])?;
} else {
let mut backend = HbvmBackend::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);
if !codegen.errors.borrow().is_empty() {
log::error!("{}", codegen.errors.borrow());
return Err(std::io::Error::other("compilation faoled"));
drop(codegen);
*out = ctx.parser.errors.into_inner().into_bytes();
return Err(std::io::Error::other("compilation faoled (errors are in out)"));
}
codegen.assemble(out);

View file

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

View file

@ -17,7 +17,7 @@ use {
CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef,
SymKey, TypeParser, Types,
},
alloc::{string::String, vec::Vec},
alloc::{rc::Rc, string::String, vec::Vec},
core::{
assert_matches::debug_assert_matches,
cell::{Cell, RefCell},
@ -2017,6 +2017,7 @@ impl Scope {
#[derive(Default, Clone)]
pub struct ItemCtx {
file: FileId,
pos: Vec<Pos>,
ret: Option<ty::Id>,
task_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 files: &'a [parser::Ast],
pub errors: Errors<'a>,
pub errors: &'a RefCell<String>,
tys: &'a mut Types,
ci: ItemCtx,
pool: &'a mut Pool,
@ -2224,6 +2207,20 @@ pub struct Codegen<'a> {
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> {
pub fn new(
backend: &'a mut dyn Backend,
@ -2232,7 +2229,7 @@ impl<'a> Codegen<'a> {
) -> Self {
Self {
files,
errors: Errors(&ctx.parser.errors),
errors: &ctx.parser.errors,
tys: &mut ctx.tys,
ci: Default::default(),
pool: &mut ctx.pool,
@ -2427,7 +2424,14 @@ impl<'a> Codegen<'a> {
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
match *expr {
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
}
}