From d293e02f62e6432382c59ac2664ad037bd1ca36b Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Tue, 1 Oct 2024 15:28:18 +0200 Subject: [PATCH] relaxing by optimizing the compiler --- Cargo.toml | 1 + hblang/src/codegen.rs | 83 ++++++++++-------- hblang/src/fs.rs | 9 +- hblang/src/lib.rs | 41 +++++---- hblang/src/parser.rs | 199 ++++++++++++++++++++++++++++++++---------- hblang/src/son.rs | 6 +- 6 files changed, 229 insertions(+), 110 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 66561e2..6b5f6ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = ["hbbytecode", "hbvm", "hbxrt", "xtask", "hblang", "hbjit"] [profile.release] lto = true +debug = true codegen-units = 1 panic = "abort" diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index 47aa551..396381b 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -10,8 +10,8 @@ use { ty, Field, Func, Global, LoggedMem, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey, TypedReloc, Types, }, - alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec}, - core::{fmt::Display, panic}, + alloc::{boxed::Box, string::String, vec::Vec}, + core::fmt::Display, }; type Offset = u32; @@ -171,9 +171,9 @@ mod reg { type Reg = u8; - #[cfg(feature = "std")] + #[cfg(all(debug_assertions, feature = "std"))] type Bt = std::backtrace::Backtrace; - #[cfg(not(feature = "std"))] + #[cfg(not(all(debug_assertions, feature = "std")))] type Bt = (); #[derive(Default, Debug)] @@ -209,15 +209,15 @@ mod reg { } } - #[cfg(feature = "std")] + #[cfg(all(debug_assertions, feature = "std"))] impl Drop for Id { fn drop(&mut self) { let is_panicking = { - #[cfg(feature = "std")] + #[cfg(all(debug_assertions, feature = "std"))] { std::thread::panicking() } - #[cfg(not(feature = "std"))] + #[cfg(not(all(debug_assertions, feature = "std")))] { false } @@ -246,9 +246,9 @@ mod reg { self.max_used = self.max_used.max(reg); Id( reg, - #[cfg(feature = "std")] + #[cfg(all(debug_assertions, feature = "std"))] Some(std::backtrace::Backtrace::capture()), - #[cfg(not(feature = "std"))] + #[cfg(not(all(debug_assertions, feature = "std")))] Some(()), ) } @@ -883,9 +883,8 @@ impl Codegen { self.assert_arg_count(expr.pos(), args.len(), cargs.len(), "inline function call"); if scope == self.ci.vars.len() { - for ((arg, ty), carg) in - args.iter().zip(sig.args.view(&self.tys.args).to_owned()).zip(cargs) - { + for ((arg, ti), carg) in args.iter().zip(sig.args.range()).zip(cargs) { + let ty = self.tys.args[ti]; let loc = self.expr_ctx(arg, Ctx::default().with_ty(ty))?.loc; self.ci.vars.push(Variable { id: carg.id, value: Value { ty, loc } }); } @@ -903,9 +902,11 @@ impl Codegen { self.ci.file = prev_file; self.ci.ret = prev_ret; - for var in self.ci.vars.drain(scope..).collect::>() { + let mut vars = std::mem::take(&mut self.ci.vars); + for var in vars.drain(scope..) { self.ci.free_loc(var.value.loc); } + self.ci.vars = vars; if let Some(last_ret) = self.ci.ret_relocs.last() && last_ret.offset as usize == self.ci.code.len() - 5 @@ -1796,26 +1797,32 @@ impl Codegen { id: self.ci.id, ret: self.ci.ret, task_base: self.ci.task_base, - loops: self.ci.loops.clone(), - vars: self - .ci - .vars - .iter() - .map(|v| Variable { - id: v.id, - value: Value { ty: v.value.ty, loc: v.value.loc.as_ref() }, - }) - .collect(), - stack_relocs: self.ci.stack_relocs.clone(), - ret_relocs: self.ci.ret_relocs.clone(), - loop_relocs: self.ci.loop_relocs.clone(), - ..Default::default() + ..self.pool.cis.pop().unwrap_or_default() }; + ci.loops.extend(self.ci.loops.iter()); + ci.vars.extend(self.ci.vars.iter().map(|v| Variable { + id: v.id, + value: Value { ty: v.value.ty, loc: v.value.loc.as_ref() }, + })); + ci.stack_relocs.extend(self.ci.stack_relocs.iter()); + ci.ret_relocs.extend(self.ci.ret_relocs.iter()); + ci.loop_relocs.extend(self.ci.loop_relocs.iter()); ci.regs.init(); + core::mem::swap(&mut self.ci, &mut ci); let value = self.expr(expr).unwrap(); self.ci.free_loc(value.loc); core::mem::swap(&mut self.ci, &mut ci); + + ci.loops.clear(); + ci.vars.clear(); + ci.stack_relocs.clear(); + ci.ret_relocs.clear(); + ci.loop_relocs.clear(); + ci.code.clear(); + ci.relocs.clear(); + self.pool.cis.push(ci); + value.ty } @@ -2118,9 +2125,11 @@ impl Codegen { self.report(body.pos(), "expected all paths in the fucntion to return"); } - for vars in self.ci.vars.drain(..).collect::>() { - self.ci.free_loc(vars.value.loc); + let mut vars = std::mem::take(&mut self.ci.vars); + for var in vars.drain(..) { + self.ci.free_loc(var.value.loc); } + self.ci.vars = vars; self.ci.finalize(); self.ci.emit(jala(ZERO, RET_ADDR, 0)); @@ -2570,8 +2579,8 @@ impl Codegen { let last_fn = self.tys.funcs.len(); self.tys.funcs.push(Default::default()); - self.tys.funcs[last_fn].code.append(&mut self.ci.code); - self.tys.funcs[last_fn].relocs.append(&mut self.ci.relocs); + self.tys.funcs[last_fn].code = std::mem::take(&mut self.ci.code); + self.tys.funcs[last_fn].relocs = std::mem::take(&mut self.ci.relocs); if is_on_stack { let size = @@ -2603,7 +2612,11 @@ impl Codegen { self.run_vm(); self.ct.vm.pc = prev_pc + self.ct.code.as_ptr() as usize; - self.tys.funcs.pop().unwrap(); + let func = self.tys.funcs.pop().unwrap(); + self.ci.code = func.code; + self.ci.code.clear(); + self.ci.relocs = func.relocs; + self.ci.relocs.clear(); } self.pool.cis.push(core::mem::replace(&mut self.ci, prev_ci)); @@ -2634,10 +2647,8 @@ impl Codegen { ty::Display::new(&self.tys, &self.files, ty) } - fn ast_display(&self, ast: &Expr) -> String { - let mut s = String::new(); - parser::Formatter::new(&self.cfile().file).fmt(ast, &mut s).unwrap(); - s + fn ast_display<'a>(&'a self, ast: &'a Expr<'a>) -> parser::Display<'a> { + parser::Display::new(&self.cfile().file, ast) } #[must_use] diff --git a/hblang/src/fs.rs b/hblang/src/fs.rs index 82047e4..c2a4ab2 100644 --- a/hblang/src/fs.rs +++ b/hblang/src/fs.rs @@ -1,7 +1,7 @@ use { crate::{ codegen, - parser::{self, Ast}, + parser::{self, Ast, StackAlloc}, }, alloc::{string::String, vec::Vec}, core::{fmt::Write, num::NonZeroUsize}, @@ -288,21 +288,22 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result> { Ok(id) }; - let execute_task = |(_, path): Task| { + let execute_task = |stack: &mut _, (_, path): Task| { let path = path.to_str().ok_or_else(|| { io::Error::new( io::ErrorKind::InvalidData, format!("path contains invalid characters: {}", display_rel_path(&path)), ) })?; - Ok(Ast::new(path, std::fs::read_to_string(path)?, &|path, from| { + Ok(Ast::new(path, std::fs::read_to_string(path)?, stack, &|path, from| { loader(path, from).map_err(|e| e.to_string()) })) }; let thread = || { + let mut stack = StackAlloc::default(); while let Some(task @ (indx, ..)) = tasks.pop() { - let res = execute_task(task); + let res = execute_task(&mut stack, task); let mut ast = ast.lock().unwrap(); let len = ast.len().max(indx as usize + 1); ast.resize_with(len, || Err(io::ErrorKind::InvalidData.into())); diff --git a/hblang/src/lib.rs b/hblang/src/lib.rs index 638d803..2e6e0ee 100644 --- a/hblang/src/lib.rs +++ b/hblang/src/lib.rs @@ -18,7 +18,8 @@ map_try_insert, extract_if, ptr_internals, - iter_intersperse + iter_intersperse, + slice_from_ptr_range )] #![warn(clippy::dbg_macro)] #![allow(stable_features, internal_features)] @@ -152,9 +153,9 @@ mod ty { Some(Self((pos << Self::LEN_BITS | len) as u32)) } - pub fn view(self, slice: &[Id]) -> &[Id] { - &slice[self.0 as usize >> Self::LEN_BITS..][..self.len()] - } + //pub fn view(self, slice: &[Id]) -> &[Id] { + // &slice[self.0 as usize >> Self::LEN_BITS..][..self.len()] + //} pub fn range(self) -> Range { let start = self.0 as usize >> Self::LEN_BITS; @@ -658,16 +659,19 @@ impl IdentInterner { #[derive(Default)] struct Types { syms: HashMap, - funcs: Vec, args: Vec, globals: Vec, structs: Vec, fields: Vec, - fields_tmp: Vec, field_names: IdentInterner, ptrs: Vec, arrays: Vec, + + fields_tmp: Vec, + frontier_tmp: Vec, + reachable_globals: Vec, + reachable_funcs: Vec, } const HEADER_SIZE: usize = core::mem::size_of::(); @@ -756,12 +760,12 @@ impl Types { } fn dump_reachable(&mut self, from: ty::Func, to: &mut Vec) -> AbleOsExecutableHeader { - let mut used_funcs = vec![]; - let mut used_globals = vec![]; + debug_assert!(self.frontier_tmp.is_empty()); + debug_assert!(self.reachable_funcs.is_empty()); + debug_assert!(self.reachable_globals.is_empty()); - let mut frontier = vec![ty::Kind::Func(from).compress()]; - - while let Some(itm) = frontier.pop() { + self.frontier_tmp.push(ty::Kind::Func(from).compress()); + while let Some(itm) = self.frontier_tmp.pop() { match itm.expand() { ty::Kind::Func(func) => { let fuc = &mut self.funcs[func as usize]; @@ -769,8 +773,8 @@ impl Types { continue; } fuc.offset = 0; - used_funcs.push(func); - frontier.extend(fuc.relocs.iter().map(|r| r.target)); + self.reachable_funcs.push(func); + self.frontier_tmp.extend(fuc.relocs.iter().map(|r| r.target)); } ty::Kind::Global(glob) => { let glb = &mut self.globals[glob as usize]; @@ -778,13 +782,13 @@ impl Types { continue; } glb.offset = 0; - used_globals.push(glob); + self.reachable_globals.push(glob); } _ => unreachable!(), } } - for &func in &used_funcs { + for &func in &self.reachable_funcs { let fuc = &mut self.funcs[func as usize]; fuc.offset = to.len() as _; to.extend(&fuc.code); @@ -792,7 +796,7 @@ impl Types { let code_length = to.len(); - for &global in &used_globals { + for global in self.reachable_globals.drain(..) { let global = &mut self.globals[global as usize]; global.offset = to.len() as _; to.extend(&global.data); @@ -800,7 +804,7 @@ impl Types { let data_length = to.len() - code_length; - for func in used_funcs { + for func in self.reachable_funcs.drain(..) { let fuc = &self.funcs[func as usize]; for rel in &fuc.relocs { let offset = match rel.target.expand() { @@ -1167,9 +1171,10 @@ fn test_parse_files(ident: &'static str, input: &'static str) -> Vec { path: &'b str, loader: Loader<'b>, - lexer: Lexer<'b>, + lexer: Lexer<'a>, arena: &'b Arena<'a>, token: Token, symbols: &'b mut Symbols, + stack: &'b mut StackAlloc, ns_bound: usize, trailing_sep: bool, packed: bool, @@ -70,7 +73,12 @@ pub struct Parser<'a, 'b> { } impl<'a, 'b> Parser<'a, 'b> { - pub fn new(arena: &'b Arena<'a>, symbols: &'b mut Symbols, loader: Loader<'b>) -> Self { + pub fn new( + arena: &'b Arena<'a>, + symbols: &'b mut Symbols, + stack: &'b mut StackAlloc, + loader: Loader<'b>, + ) -> Self { let mut lexer = Lexer::new(""); Self { loader, @@ -79,6 +87,7 @@ impl<'a, 'b> Parser<'a, 'b> { path: "", arena, symbols, + stack, ns_bound: 0, trailing_sep: false, packed: false, @@ -87,7 +96,7 @@ impl<'a, 'b> Parser<'a, 'b> { } } - pub fn file(&mut self, input: &'b str, path: &'b str) -> &'a [Expr<'a>] { + pub fn file(&mut self, input: &'a str, path: &'b str) -> &'a [Expr<'a>] { self.path = path; self.lexer = Lexer::new(input); self.token = self.lexer.next(); @@ -247,8 +256,8 @@ impl<'a, 'b> Parser<'a, 'b> { (id.ident, bl) } - fn move_str(&mut self, range: Token) -> &'a str { - self.arena.alloc_str(self.lexer.slice(range.range())) + fn tok_str(&mut self, range: Token) -> &'a str { + self.lexer.slice(range.range()) } fn unit_expr(&mut self) -> Expr<'a> { @@ -278,7 +287,7 @@ impl<'a, 'b> Parser<'a, 'b> { } T::Directive => E::Directive { pos: pos - 1, // need to undo the directive shift - name: self.move_str(token), + name: self.tok_str(token), args: { self.expect_advance(T::LParen); self.collect_list(T::Comma, T::RParen, Self::expr) @@ -287,7 +296,7 @@ impl<'a, 'b> Parser<'a, 'b> { T::True => E::Bool { pos, value: true }, T::False => E::Bool { pos, value: false }, T::Idk => E::Idk { pos }, - T::DQuote => E::String { pos, literal: self.move_str(token) }, + T::DQuote => E::String { pos, literal: self.tok_str(token) }, T::Packed => { self.packed = true; let expr = self.unit_expr(); @@ -308,13 +317,13 @@ impl<'a, 'b> Parser<'a, 'b> { self.collect_list(T::Comma, T::RBrace, |s| { let tok = s.token; if s.advance_if(T::Comment) { - CommentOr::Comment { literal: s.move_str(tok), pos: tok.start } + CommentOr::Comment { literal: s.tok_str(tok), pos: tok.start } } else { let name = s.expect_advance(T::Ident); s.expect_advance(T::Colon); CommentOr::Or(StructField { pos: name.start, - name: s.move_str(name), + name: s.tok_str(name), ty: s.expr(), }) } @@ -338,7 +347,7 @@ impl<'a, 'b> Parser<'a, 'b> { }, T::Ident | T::CtIdent => { let (id, is_first) = self.resolve_ident(token); - let name = self.move_str(token); + let name = self.tok_str(token); E::Ident { pos, is_ct: token.kind == T::CtIdent, name, id, is_first } } T::If => E::If { @@ -369,7 +378,7 @@ impl<'a, 'b> Parser<'a, 'b> { s.expect_advance(T::Colon); Arg { pos: name.start, - name: s.move_str(name), + name: s.tok_str(name), is_ct: name.kind == T::CtIdent, id, ty: s.expr(), @@ -426,7 +435,7 @@ impl<'a, 'b> Parser<'a, 'b> { self.expect_advance(T::RParen); expr } - T::Comment => Expr::Comment { pos, literal: self.move_str(token) }, + T::Comment => Expr::Comment { pos, literal: self.tok_str(token) }, tok => self.report(token.start, format_args!("unexpected token: {tok:?}")), }; @@ -457,7 +466,7 @@ impl<'a, 'b> Parser<'a, 'b> { pos: token.start, name: { let token = self.expect_advance(T::Ident); - self.move_str(token) + self.tok_str(token) }, }, _ => break, @@ -486,7 +495,7 @@ impl<'a, 'b> Parser<'a, 'b> { ty: ty.map(|ty| self.arena.alloc(ty)), fields: self.collect_list(TokenKind::Comma, TokenKind::RBrace, |s| { let name_tok = s.advance_ident(); - let name = s.move_str(name_tok); + let name = s.tok_str(name_tok); CtorField { pos: name_tok.start, name, @@ -538,19 +547,13 @@ impl<'a, 'b> Parser<'a, 'b> { end: TokenKind, mut f: impl FnMut(&mut Self) -> T, ) -> &'a [T] { - self.collect(|s| { - s.advance_if(end).not().then(|| { - let val = f(s); - s.trailing_sep = s.advance_if(delim); - val - }) - }) - } - - fn collect(&mut self, mut f: impl FnMut(&mut Self) -> Option) -> &'a [T] { - // TODO: avoid this allocation - let vec = core::iter::from_fn(|| f(self)).collect::>(); - self.arena.alloc_slice(&vec) + let mut view = self.stack.view(); + while !self.advance_if(end) { + let val = f(self); + self.trailing_sep = self.advance_if(delim); + unsafe { self.stack.push(&mut view, val) }; + } + self.arena.alloc_slice(unsafe { self.stack.finalize(view) }) } fn advance_if(&mut self, kind: TokenKind) -> bool { @@ -931,6 +934,22 @@ impl<'a, T: Copy> CommentOr<'a, T> { } } +pub struct Display<'a> { + source: &'a str, + expr: &'a Expr<'a>, +} +impl<'a> Display<'a> { + pub fn new(source: &'a str, expr: &'a Expr<'a>) -> Self { + Self { source, expr } + } +} + +impl core::fmt::Display for Display<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Formatter::new(self.source).fmt(self.expr, f) + } +} + pub struct Formatter<'a> { source: &'a str, depth: usize, @@ -942,14 +961,14 @@ impl<'a> Formatter<'a> { Self { source, depth: 0, disp_buff: Default::default() } } - fn fmt_list( + fn fmt_list( &mut self, - f: &mut String, + f: &mut F, trailing: bool, end: &str, sep: &str, list: &[T], - fmt: impl Fn(&mut Self, &T, &mut String) -> fmt::Result, + fmt: impl Fn(&mut Self, &T, &mut F) -> fmt::Result, ) -> fmt::Result { self.fmt_list_low(f, trailing, end, sep, list, |s, v, f| { fmt(s, v, f)?; @@ -957,14 +976,14 @@ impl<'a> Formatter<'a> { }) } - fn fmt_list_low( + fn fmt_list_low( &mut self, - f: &mut String, + f: &mut F, trailing: bool, end: &str, sep: &str, list: &[T], - fmt: impl Fn(&mut Self, &T, &mut String) -> Result, + fmt: impl Fn(&mut Self, &T, &mut F) -> Result, ) -> fmt::Result { if !trailing { let mut first = true; @@ -1013,10 +1032,10 @@ impl<'a> Formatter<'a> { res } - fn fmt_paren( + fn fmt_paren( &mut self, expr: &Expr, - f: &mut String, + f: &mut F, cond: impl FnOnce(&Expr) -> bool, ) -> fmt::Result { if cond(expr) { @@ -1028,7 +1047,7 @@ impl<'a> Formatter<'a> { } } - pub fn fmt(&mut self, expr: &Expr, f: &mut String) -> fmt::Result { + pub fn fmt(&mut self, expr: &Expr, f: &mut F) -> fmt::Result { macro_rules! impl_parenter { ($($name:ident => $pat:pat,)*) => { $( @@ -1259,11 +1278,13 @@ impl AstInner<[Symbol]> { .0 } - fn new(content: String, path: &str, loader: Loader) -> NonNull { + fn new(file: Box, path: &str, stack: &mut StackAlloc, loader: Loader) -> NonNull { let arena = Arena::default(); let mut syms = Vec::new(); - let mut parser = Parser::new(&arena, &mut syms, loader); - let exprs = parser.file(&content, path) as *const [Expr<'static>]; + let mut parser = Parser::new(&arena, &mut syms, stack, loader); + let exprs = + parser.file(unsafe { &*(&*file as *const _) }, path) as *const [Expr<'static>]; + drop(parser); syms.sort_unstable_by_key(|s| s.name); @@ -1278,7 +1299,7 @@ impl AstInner<[Symbol]> { mem: arena.chunk.into_inner(), exprs, path: path.into(), - file: content.into(), + file, symbols: (), }); core::ptr::addr_of_mut!((*inner).symbols) @@ -1320,8 +1341,8 @@ pub fn report_to( pub struct Ast(NonNull>); impl Ast { - pub fn new(path: &str, content: String, loader: Loader) -> Self { - Self(AstInner::new(content, path, loader)) + pub fn new(path: &str, content: String, stack: &mut StackAlloc, loader: Loader) -> Self { + Self(AstInner::new(content.into(), path, stack, loader)) } pub fn exprs(&self) -> &[Expr] { @@ -1346,7 +1367,7 @@ impl Ast { impl Default for Ast { fn default() -> Self { - Self(AstInner::new(String::new(), "", &no_loader)) + Self(AstInner::new("".into(), "", &mut StackAlloc::default(), &no_loader)) } } @@ -1392,7 +1413,10 @@ impl Drop for Ast { fn drop(&mut self) { let inner = unsafe { self.0.as_ref() }; if inner.ref_count.fetch_sub(1, core::sync::atomic::Ordering::Relaxed) == 1 { - let layout = AstInner::layout(inner.symbols.len()); + let inner = unsafe { self.0.as_mut() }; + let len = inner.symbols.len(); + unsafe { core::ptr::drop_in_place(inner) }; + let layout = AstInner::layout(len); unsafe { alloc::alloc::dealloc(self.0.as_ptr() as _, layout); } @@ -1408,6 +1432,84 @@ impl Deref for Ast { } } +pub struct StackAllocView { + prev: usize, + base: usize, + _ph: PhantomData, +} + +pub struct StackAlloc { + data: *mut u8, + len: usize, + cap: usize, +} + +impl StackAlloc { + const MAX_ALIGN: usize = 16; + + fn view(&mut self) -> StackAllocView { + let prev = self.len; + let align = core::mem::align_of::(); + assert!(align <= Self::MAX_ALIGN); + self.len = (self.len + align - 1) & !(align - 1); + StackAllocView { base: self.len, prev, _ph: PhantomData } + } + + unsafe fn push(&mut self, _view: &mut StackAllocView, value: T) { + if unlikely(self.len + core::mem::size_of::() > self.cap) { + let next_cap = self.cap.max(16 * 32).max(std::mem::size_of::()) * 2; + if self.cap == 0 { + let layout = + core::alloc::Layout::from_size_align_unchecked(next_cap, Self::MAX_ALIGN); + self.data = alloc::alloc::alloc(layout); + } else { + let old_layout = + core::alloc::Layout::from_size_align_unchecked(self.cap, Self::MAX_ALIGN); + self.data = alloc::alloc::realloc(self.data, old_layout, next_cap); + } + self.cap = next_cap; + } + + let dst = self.data.add(self.len) as *mut T; + debug_assert!( + dst.is_aligned(), + "{:?} {:?} {} {} {}", + dst, + std::mem::size_of::(), + std::mem::align_of::(), + self.len, + self.cap + ); + self.len += core::mem::size_of::(); + core::ptr::write(dst, value); + } + + unsafe fn finalize(&mut self, view: StackAllocView) -> &[T] { + if unlikely(self.cap == 0) { + return &[]; + } + let slice = core::slice::from_ptr_range( + self.data.add(view.base) as *const T..self.data.add(self.len) as *const T, + ); + self.len = view.prev; + slice + } +} + +impl Default for StackAlloc { + fn default() -> Self { + Self { data: core::ptr::null_mut(), len: 0, cap: 0 } + } +} + +impl Drop for StackAlloc { + fn drop(&mut self) { + let layout = + unsafe { core::alloc::Layout::from_size_align_unchecked(self.cap, Self::MAX_ALIGN) }; + unsafe { alloc::alloc::dealloc(self.data, layout) }; + } +} + #[derive(Default)] pub struct Arena<'a> { chunk: UnsafeCell, @@ -1529,10 +1631,11 @@ impl Drop for ArenaChunk { #[cfg(test)] pub mod test { - use {alloc::borrow::ToOwned, std::string::String}; + use {crate::parser::StackAlloc, alloc::borrow::ToOwned, std::string::String}; pub fn format(ident: &str, input: &str) { - let ast = super::Ast::new(ident, input.to_owned(), &|_, _| Ok(0)); + let ast = + super::Ast::new(ident, input.to_owned(), &mut StackAlloc::default(), &|_, _| Ok(0)); let mut output = String::new(); crate::fs::format_to(&ast, input, &mut output).unwrap(); diff --git a/hblang/src/son.rs b/hblang/src/son.rs index 9b17211..468af74 100644 --- a/hblang/src/son.rs +++ b/hblang/src/son.rs @@ -2107,10 +2107,8 @@ impl Codegen { ty::Display::new(&self.tys, &self.files, ty) } - fn ast_display(&self, ast: &Expr) -> String { - let mut s = String::new(); - parser::Formatter::new(&self.cfile().file).fmt(ast, &mut s).unwrap(); - s + fn ast_display<'a>(&'a self, ast: &'a Expr<'a>) -> parser::Display<'a> { + parser::Display::new(&self.cfile().file, ast) } #[must_use]