diff --git a/lang/src/fmt.rs b/lang/src/fmt.rs index 773561b..caad9ec 100644 --- a/lang/src/fmt.rs +++ b/lang/src/fmt.rs @@ -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(); diff --git a/lang/src/fs.rs b/lang/src/fs.rs index da9c3ce..a0498d0 100644 --- a/lang/src/fs.rs +++ b/lang/src/fs.rs @@ -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 { + pub fn from_args(args: &[&str], out: &mut Vec) -> std::io::Result { if args.contains(&"--help") || args.contains(&"-h") { - log::error!("Usage: hbc [OPTIONS...] "); - log::error!(include_str!("../command-help.txt")); + writeln!(out, "Usage: hbc [OPTIONS...] ")?; + 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::().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) -> 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) -> 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); diff --git a/lang/src/main.rs b/lang/src/main.rs index a1f6906..407600d 100644 --- a/lang/src/main.rs +++ b/lang/src/main.rs @@ -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) -> std::io::Result<()> { + let args = std::env::args().collect::>(); + let args = args.iter().map(String::as_str).collect::>(); - let args = std::env::args().collect::>(); - let args = args.iter().map(String::as_str).collect::>(); + 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(), + } } diff --git a/lang/src/parser.rs b/lang/src/parser.rs index d9bd81f..4074166 100644 --- a/lang/src/parser.rs +++ b/lang/src/parser.rs @@ -282,6 +282,14 @@ impl<'a, 'b> Parser<'a, 'b> { fn unit_expr(&mut self) -> Option> { 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; diff --git a/lang/src/son.rs b/lang/src/son.rs index 6e86225..5e78c55 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -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, ret: Option, task_base: usize, inline_var_base: usize, @@ -2195,27 +2196,9 @@ impl CodegenCtx { } } -pub struct Errors<'a>(&'a RefCell); - -impl Deref for Errors<'_> { - type Target = RefCell; - - 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, 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 { + fn raw_expr_ctx(&mut self, expr: &Expr, ctx: Ctx) -> Option { + 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 { // ordered by complexity of the expression match *expr { Expr::Null { pos } => { diff --git a/test.hb b/test.hb new file mode 100644 index 0000000..358d6f5 --- /dev/null +++ b/test.hb @@ -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 + } +}