133d722a9Sopenharmony_ciuse crate::gen::block::Block; 233d722a9Sopenharmony_ciuse crate::gen::builtin::Builtins; 333d722a9Sopenharmony_ciuse crate::gen::include::Includes; 433d722a9Sopenharmony_ciuse crate::gen::Opt; 533d722a9Sopenharmony_ciuse crate::syntax::namespace::Namespace; 633d722a9Sopenharmony_ciuse crate::syntax::Types; 733d722a9Sopenharmony_ciuse std::cell::RefCell; 833d722a9Sopenharmony_ciuse std::fmt::{self, Arguments, Write}; 933d722a9Sopenharmony_ci 1033d722a9Sopenharmony_cipub(crate) struct OutFile<'a> { 1133d722a9Sopenharmony_ci pub header: bool, 1233d722a9Sopenharmony_ci pub opt: &'a Opt, 1333d722a9Sopenharmony_ci pub types: &'a Types<'a>, 1433d722a9Sopenharmony_ci pub include: Includes<'a>, 1533d722a9Sopenharmony_ci pub builtin: Builtins<'a>, 1633d722a9Sopenharmony_ci content: RefCell<Content<'a>>, 1733d722a9Sopenharmony_ci} 1833d722a9Sopenharmony_ci 1933d722a9Sopenharmony_ci#[derive(Default)] 2033d722a9Sopenharmony_cipub struct Content<'a> { 2133d722a9Sopenharmony_ci bytes: String, 2233d722a9Sopenharmony_ci namespace: &'a Namespace, 2333d722a9Sopenharmony_ci blocks: Vec<BlockBoundary<'a>>, 2433d722a9Sopenharmony_ci section_pending: bool, 2533d722a9Sopenharmony_ci blocks_pending: usize, 2633d722a9Sopenharmony_ci} 2733d722a9Sopenharmony_ci 2833d722a9Sopenharmony_ci#[derive(Copy, Clone, PartialEq, Debug)] 2933d722a9Sopenharmony_cienum BlockBoundary<'a> { 3033d722a9Sopenharmony_ci Begin(Block<'a>), 3133d722a9Sopenharmony_ci End(Block<'a>), 3233d722a9Sopenharmony_ci} 3333d722a9Sopenharmony_ci 3433d722a9Sopenharmony_ciimpl<'a> OutFile<'a> { 3533d722a9Sopenharmony_ci pub fn new(header: bool, opt: &'a Opt, types: &'a Types) -> Self { 3633d722a9Sopenharmony_ci OutFile { 3733d722a9Sopenharmony_ci header, 3833d722a9Sopenharmony_ci opt, 3933d722a9Sopenharmony_ci types, 4033d722a9Sopenharmony_ci include: Includes::new(), 4133d722a9Sopenharmony_ci builtin: Builtins::new(), 4233d722a9Sopenharmony_ci content: RefCell::new(Content::new()), 4333d722a9Sopenharmony_ci } 4433d722a9Sopenharmony_ci } 4533d722a9Sopenharmony_ci 4633d722a9Sopenharmony_ci // Write a blank line if the preceding section had any contents. 4733d722a9Sopenharmony_ci pub fn next_section(&mut self) { 4833d722a9Sopenharmony_ci self.content.get_mut().next_section(); 4933d722a9Sopenharmony_ci } 5033d722a9Sopenharmony_ci 5133d722a9Sopenharmony_ci pub fn begin_block(&mut self, block: Block<'a>) { 5233d722a9Sopenharmony_ci self.content.get_mut().begin_block(block); 5333d722a9Sopenharmony_ci } 5433d722a9Sopenharmony_ci 5533d722a9Sopenharmony_ci pub fn end_block(&mut self, block: Block<'a>) { 5633d722a9Sopenharmony_ci self.content.get_mut().end_block(block); 5733d722a9Sopenharmony_ci } 5833d722a9Sopenharmony_ci 5933d722a9Sopenharmony_ci pub fn set_namespace(&mut self, namespace: &'a Namespace) { 6033d722a9Sopenharmony_ci self.content.get_mut().set_namespace(namespace); 6133d722a9Sopenharmony_ci } 6233d722a9Sopenharmony_ci 6333d722a9Sopenharmony_ci pub fn write_fmt(&self, args: Arguments) { 6433d722a9Sopenharmony_ci let content = &mut *self.content.borrow_mut(); 6533d722a9Sopenharmony_ci Write::write_fmt(content, args).unwrap(); 6633d722a9Sopenharmony_ci } 6733d722a9Sopenharmony_ci 6833d722a9Sopenharmony_ci pub fn content(&mut self) -> Vec<u8> { 6933d722a9Sopenharmony_ci self.flush(); 7033d722a9Sopenharmony_ci let include = &self.include.content.bytes; 7133d722a9Sopenharmony_ci let builtin = &self.builtin.content.bytes; 7233d722a9Sopenharmony_ci let content = &self.content.get_mut().bytes; 7333d722a9Sopenharmony_ci let len = include.len() + builtin.len() + content.len() + 2; 7433d722a9Sopenharmony_ci let mut out = String::with_capacity(len); 7533d722a9Sopenharmony_ci out.push_str(include); 7633d722a9Sopenharmony_ci if !out.is_empty() && !builtin.is_empty() { 7733d722a9Sopenharmony_ci out.push('\n'); 7833d722a9Sopenharmony_ci } 7933d722a9Sopenharmony_ci out.push_str(builtin); 8033d722a9Sopenharmony_ci if !out.is_empty() && !content.is_empty() { 8133d722a9Sopenharmony_ci out.push('\n'); 8233d722a9Sopenharmony_ci } 8333d722a9Sopenharmony_ci out.push_str(content); 8433d722a9Sopenharmony_ci if out.is_empty() { 8533d722a9Sopenharmony_ci out.push_str("// empty\n"); 8633d722a9Sopenharmony_ci } 8733d722a9Sopenharmony_ci out.into_bytes() 8833d722a9Sopenharmony_ci } 8933d722a9Sopenharmony_ci 9033d722a9Sopenharmony_ci fn flush(&mut self) { 9133d722a9Sopenharmony_ci self.include.content.flush(); 9233d722a9Sopenharmony_ci self.builtin.content.flush(); 9333d722a9Sopenharmony_ci self.content.get_mut().flush(); 9433d722a9Sopenharmony_ci } 9533d722a9Sopenharmony_ci} 9633d722a9Sopenharmony_ci 9733d722a9Sopenharmony_ciimpl<'a> Write for Content<'a> { 9833d722a9Sopenharmony_ci fn write_str(&mut self, s: &str) -> fmt::Result { 9933d722a9Sopenharmony_ci self.write(s); 10033d722a9Sopenharmony_ci Ok(()) 10133d722a9Sopenharmony_ci } 10233d722a9Sopenharmony_ci} 10333d722a9Sopenharmony_ci 10433d722a9Sopenharmony_ciimpl<'a> PartialEq for Content<'a> { 10533d722a9Sopenharmony_ci fn eq(&self, _other: &Self) -> bool { 10633d722a9Sopenharmony_ci true 10733d722a9Sopenharmony_ci } 10833d722a9Sopenharmony_ci} 10933d722a9Sopenharmony_ci 11033d722a9Sopenharmony_ciimpl<'a> Content<'a> { 11133d722a9Sopenharmony_ci fn new() -> Self { 11233d722a9Sopenharmony_ci Content::default() 11333d722a9Sopenharmony_ci } 11433d722a9Sopenharmony_ci 11533d722a9Sopenharmony_ci pub fn next_section(&mut self) { 11633d722a9Sopenharmony_ci self.section_pending = true; 11733d722a9Sopenharmony_ci } 11833d722a9Sopenharmony_ci 11933d722a9Sopenharmony_ci pub fn begin_block(&mut self, block: Block<'a>) { 12033d722a9Sopenharmony_ci self.push_block_boundary(BlockBoundary::Begin(block)); 12133d722a9Sopenharmony_ci } 12233d722a9Sopenharmony_ci 12333d722a9Sopenharmony_ci pub fn end_block(&mut self, block: Block<'a>) { 12433d722a9Sopenharmony_ci self.push_block_boundary(BlockBoundary::End(block)); 12533d722a9Sopenharmony_ci } 12633d722a9Sopenharmony_ci 12733d722a9Sopenharmony_ci pub fn set_namespace(&mut self, namespace: &'a Namespace) { 12833d722a9Sopenharmony_ci for name in self.namespace.iter().rev() { 12933d722a9Sopenharmony_ci self.end_block(Block::UserDefinedNamespace(name)); 13033d722a9Sopenharmony_ci } 13133d722a9Sopenharmony_ci for name in namespace { 13233d722a9Sopenharmony_ci self.begin_block(Block::UserDefinedNamespace(name)); 13333d722a9Sopenharmony_ci } 13433d722a9Sopenharmony_ci self.namespace = namespace; 13533d722a9Sopenharmony_ci } 13633d722a9Sopenharmony_ci 13733d722a9Sopenharmony_ci pub fn write_fmt(&mut self, args: Arguments) { 13833d722a9Sopenharmony_ci Write::write_fmt(self, args).unwrap(); 13933d722a9Sopenharmony_ci } 14033d722a9Sopenharmony_ci 14133d722a9Sopenharmony_ci fn write(&mut self, b: &str) { 14233d722a9Sopenharmony_ci if !b.is_empty() { 14333d722a9Sopenharmony_ci if self.blocks_pending > 0 { 14433d722a9Sopenharmony_ci self.flush_blocks(); 14533d722a9Sopenharmony_ci } 14633d722a9Sopenharmony_ci if self.section_pending && !self.bytes.is_empty() { 14733d722a9Sopenharmony_ci self.bytes.push('\n'); 14833d722a9Sopenharmony_ci } 14933d722a9Sopenharmony_ci self.bytes.push_str(b); 15033d722a9Sopenharmony_ci self.section_pending = false; 15133d722a9Sopenharmony_ci self.blocks_pending = 0; 15233d722a9Sopenharmony_ci } 15333d722a9Sopenharmony_ci } 15433d722a9Sopenharmony_ci 15533d722a9Sopenharmony_ci fn push_block_boundary(&mut self, boundary: BlockBoundary<'a>) { 15633d722a9Sopenharmony_ci if self.blocks_pending > 0 && boundary == self.blocks.last().unwrap().rev() { 15733d722a9Sopenharmony_ci self.blocks.pop(); 15833d722a9Sopenharmony_ci self.blocks_pending -= 1; 15933d722a9Sopenharmony_ci } else { 16033d722a9Sopenharmony_ci self.blocks.push(boundary); 16133d722a9Sopenharmony_ci self.blocks_pending += 1; 16233d722a9Sopenharmony_ci } 16333d722a9Sopenharmony_ci } 16433d722a9Sopenharmony_ci 16533d722a9Sopenharmony_ci fn flush(&mut self) { 16633d722a9Sopenharmony_ci self.set_namespace(Default::default()); 16733d722a9Sopenharmony_ci if self.blocks_pending > 0 { 16833d722a9Sopenharmony_ci self.flush_blocks(); 16933d722a9Sopenharmony_ci } 17033d722a9Sopenharmony_ci } 17133d722a9Sopenharmony_ci 17233d722a9Sopenharmony_ci fn flush_blocks(&mut self) { 17333d722a9Sopenharmony_ci self.section_pending = !self.bytes.is_empty(); 17433d722a9Sopenharmony_ci let mut read = self.blocks.len() - self.blocks_pending; 17533d722a9Sopenharmony_ci let mut write = read; 17633d722a9Sopenharmony_ci 17733d722a9Sopenharmony_ci while read < self.blocks.len() { 17833d722a9Sopenharmony_ci match self.blocks[read] { 17933d722a9Sopenharmony_ci BlockBoundary::Begin(begin_block) => { 18033d722a9Sopenharmony_ci if self.section_pending { 18133d722a9Sopenharmony_ci self.bytes.push('\n'); 18233d722a9Sopenharmony_ci self.section_pending = false; 18333d722a9Sopenharmony_ci } 18433d722a9Sopenharmony_ci Block::write_begin(begin_block, &mut self.bytes); 18533d722a9Sopenharmony_ci self.blocks[write] = BlockBoundary::Begin(begin_block); 18633d722a9Sopenharmony_ci write += 1; 18733d722a9Sopenharmony_ci } 18833d722a9Sopenharmony_ci BlockBoundary::End(end_block) => { 18933d722a9Sopenharmony_ci write = write.checked_sub(1).unwrap(); 19033d722a9Sopenharmony_ci let begin_block = self.blocks[write]; 19133d722a9Sopenharmony_ci assert_eq!(begin_block, BlockBoundary::Begin(end_block)); 19233d722a9Sopenharmony_ci Block::write_end(end_block, &mut self.bytes); 19333d722a9Sopenharmony_ci self.section_pending = true; 19433d722a9Sopenharmony_ci } 19533d722a9Sopenharmony_ci } 19633d722a9Sopenharmony_ci read += 1; 19733d722a9Sopenharmony_ci } 19833d722a9Sopenharmony_ci 19933d722a9Sopenharmony_ci self.blocks.truncate(write); 20033d722a9Sopenharmony_ci } 20133d722a9Sopenharmony_ci} 20233d722a9Sopenharmony_ci 20333d722a9Sopenharmony_ciimpl<'a> BlockBoundary<'a> { 20433d722a9Sopenharmony_ci fn rev(self) -> BlockBoundary<'a> { 20533d722a9Sopenharmony_ci match self { 20633d722a9Sopenharmony_ci BlockBoundary::Begin(block) => BlockBoundary::End(block), 20733d722a9Sopenharmony_ci BlockBoundary::End(block) => BlockBoundary::Begin(block), 20833d722a9Sopenharmony_ci } 20933d722a9Sopenharmony_ci } 21033d722a9Sopenharmony_ci} 211