adding better error reporting when compiler crashes errors are now sent trough out buffer
This commit is contained in:
parent
0374848b28
commit
455f70db6e
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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)?;
|
||||||
}
|
}
|
||||||
|
output.clear();
|
||||||
for parsed in parsed.ast {
|
|
||||||
format_ast(parsed)?;
|
|
||||||
}
|
}
|
||||||
} 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);
|
||||||
|
|
|
@ -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 = std::env::args().collect::<Vec<_>>();
|
||||||
let args = args.iter().map(String::as_str).collect::<Vec<_>>();
|
let args = args.iter().map(String::as_str).collect::<Vec<_>>();
|
||||||
|
|
||||||
let opts = hblang::Options::from_args(&args)?;
|
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 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();
|
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(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 } => {
|
||||||
|
|
Loading…
Reference in a new issue