blob: 0f12e89f05e439224056403ae5eb5f4527ea3b46 [file] [log] [blame]
David Tolnay0c033e32020-11-01 15:15:48 -08001use crate::gen::block::Block;
David Tolnay3be0e1f2020-10-31 20:53:00 -07002use crate::gen::builtin::Builtins;
David Tolnay9c68b1a2020-03-06 11:12:55 -08003use crate::gen::include::Includes;
David Tolnaye1476af2020-11-01 13:47:25 -08004use crate::gen::Opt;
David Tolnayb560a0f2020-10-30 21:28:45 -07005use crate::syntax::Types;
David Tolnay7ece56f2020-03-29 21:21:38 -07006use std::cell::RefCell;
David Tolnay7db73692019-10-20 14:51:12 -04007use std::fmt::{self, Arguments, Write};
8
David Tolnayb560a0f2020-10-30 21:28:45 -07009pub(crate) struct OutFile<'a> {
David Tolnay7db73692019-10-20 14:51:12 -040010 pub header: bool,
David Tolnaye1476af2020-11-01 13:47:25 -080011 pub opt: &'a Opt,
David Tolnayb560a0f2020-10-30 21:28:45 -070012 pub types: &'a Types<'a>,
David Tolnay97c5b862020-11-01 14:59:01 -080013 pub include: Includes<'a>,
14 pub builtin: Builtins<'a>,
15 content: RefCell<Content<'a>>,
David Tolnay7ece56f2020-03-29 21:21:38 -070016}
17
David Tolnay8810a542020-10-31 21:39:22 -070018#[derive(Default)]
David Tolnay97c5b862020-11-01 14:59:01 -080019pub struct Content<'a> {
David Tolnaydab7e802020-08-28 18:54:48 -070020 bytes: String,
David Tolnayf02146e2020-11-01 15:35:42 -080021 blocks: Vec<Block<'a>>,
David Tolnay7db73692019-10-20 14:51:12 -040022 section_pending: bool,
David Tolnayf02146e2020-11-01 15:35:42 -080023 blocks_pending: usize,
David Tolnay7db73692019-10-20 14:51:12 -040024}
25
David Tolnayb560a0f2020-10-30 21:28:45 -070026impl<'a> OutFile<'a> {
David Tolnaye1476af2020-11-01 13:47:25 -080027 pub fn new(header: bool, opt: &'a Opt, types: &'a Types) -> Self {
David Tolnay7db73692019-10-20 14:51:12 -040028 OutFile {
David Tolnay7db73692019-10-20 14:51:12 -040029 header,
David Tolnaye1476af2020-11-01 13:47:25 -080030 opt,
David Tolnayb560a0f2020-10-30 21:28:45 -070031 types,
David Tolnay9c68b1a2020-03-06 11:12:55 -080032 include: Includes::new(),
David Tolnay3be0e1f2020-10-31 20:53:00 -070033 builtin: Builtins::new(),
David Tolnay54702b92020-07-31 11:50:09 -070034 content: RefCell::new(Content::new()),
David Tolnay7db73692019-10-20 14:51:12 -040035 }
36 }
37
38 // Write a blank line if the preceding section had any contents.
39 pub fn next_section(&mut self) {
David Tolnaycb2189f2020-10-31 21:23:08 -070040 self.content.get_mut().next_section();
David Tolnay7db73692019-10-20 14:51:12 -040041 }
42
David Tolnay97c5b862020-11-01 14:59:01 -080043 pub fn begin_block(&mut self, block: Block<'a>) {
David Tolnaycb2189f2020-10-31 21:23:08 -070044 self.content.get_mut().begin_block(block);
David Tolnay7db73692019-10-20 14:51:12 -040045 }
46
David Tolnay97c5b862020-11-01 14:59:01 -080047 pub fn end_block(&mut self, block: Block<'a>) {
David Tolnaycb2189f2020-10-31 21:23:08 -070048 self.content.get_mut().end_block(block);
David Tolnay7db73692019-10-20 14:51:12 -040049 }
50
David Tolnay7ece56f2020-03-29 21:21:38 -070051 pub fn write_fmt(&self, args: Arguments) {
52 let content = &mut *self.content.borrow_mut();
53 Write::write_fmt(content, args).unwrap();
54 }
55
56 pub fn content(&self) -> Vec<u8> {
David Tolnay8810a542020-10-31 21:39:22 -070057 let include = &self.include.content.bytes;
David Tolnay8c14d9a2020-10-31 21:52:38 -070058 let builtin = &self.builtin.content.bytes;
David Tolnay54702b92020-07-31 11:50:09 -070059 let content = &self.content.borrow().bytes;
David Tolnay8c14d9a2020-10-31 21:52:38 -070060 let len = include.len() + builtin.len() + content.len() + 2;
David Tolnaydab7e802020-08-28 18:54:48 -070061 let mut out = String::with_capacity(len);
David Tolnay8810a542020-10-31 21:39:22 -070062 out.push_str(include);
David Tolnay8c14d9a2020-10-31 21:52:38 -070063 if !out.is_empty() && !builtin.is_empty() {
64 out.push('\n');
65 }
66 out.push_str(builtin);
67 if !out.is_empty() && !content.is_empty() {
David Tolnaydab7e802020-08-28 18:54:48 -070068 out.push('\n');
David Tolnay54702b92020-07-31 11:50:09 -070069 }
David Tolnaydab7e802020-08-28 18:54:48 -070070 out.push_str(content);
David Tolnay91489ec2020-09-03 12:48:46 -070071 if out.is_empty() {
72 out.push_str("// empty\n");
73 }
David Tolnaydab7e802020-08-28 18:54:48 -070074 out.into_bytes()
David Tolnay7db73692019-10-20 14:51:12 -040075 }
76}
77
David Tolnay97c5b862020-11-01 14:59:01 -080078impl<'a> Write for Content<'a> {
David Tolnay7db73692019-10-20 14:51:12 -040079 fn write_str(&mut self, s: &str) -> fmt::Result {
David Tolnaydab7e802020-08-28 18:54:48 -070080 self.write(s);
David Tolnayf4632de2020-07-31 10:46:55 -070081 Ok(())
82 }
83}
84
David Tolnay97c5b862020-11-01 14:59:01 -080085impl<'a> PartialEq for Content<'a> {
David Tolnay8810a542020-10-31 21:39:22 -070086 fn eq(&self, _other: &Content) -> bool {
87 true
88 }
89}
90
David Tolnay97c5b862020-11-01 14:59:01 -080091impl<'a> Content<'a> {
David Tolnay54702b92020-07-31 11:50:09 -070092 fn new() -> Self {
David Tolnay8810a542020-10-31 21:39:22 -070093 Content::default()
David Tolnay54702b92020-07-31 11:50:09 -070094 }
95
David Tolnaycb2189f2020-10-31 21:23:08 -070096 pub fn next_section(&mut self) {
97 self.section_pending = true;
98 }
99
David Tolnay97c5b862020-11-01 14:59:01 -0800100 pub fn begin_block(&mut self, block: Block<'a>) {
David Tolnayf02146e2020-11-01 15:35:42 -0800101 self.blocks.push(block);
102 self.blocks_pending += 1;
David Tolnaycb2189f2020-10-31 21:23:08 -0700103 }
104
David Tolnay97c5b862020-11-01 14:59:01 -0800105 pub fn end_block(&mut self, block: Block<'a>) {
David Tolnayf02146e2020-11-01 15:35:42 -0800106 let begin_block = self.blocks.pop().unwrap();
107 let end_block = block;
108 assert_eq!(begin_block, end_block);
109
110 if self.blocks_pending > 0 {
111 self.blocks_pending -= 1;
112 } else {
David Tolnay2a160e42020-11-01 15:40:20 -0800113 Block::write_end(block, &mut self.bytes);
David Tolnaycb2189f2020-10-31 21:23:08 -0700114 self.section_pending = true;
115 }
116 }
117
118 pub fn write_fmt(&mut self, args: Arguments) {
119 Write::write_fmt(self, args).unwrap();
120 }
121
David Tolnaydab7e802020-08-28 18:54:48 -0700122 fn write(&mut self, b: &str) {
David Tolnayf4632de2020-07-31 10:46:55 -0700123 if !b.is_empty() {
David Tolnayf02146e2020-11-01 15:35:42 -0800124 if self.blocks_pending > 0 {
David Tolnay7ece56f2020-03-29 21:21:38 -0700125 if !self.bytes.is_empty() {
David Tolnaydab7e802020-08-28 18:54:48 -0700126 self.bytes.push('\n');
David Tolnay3577d452020-03-17 21:48:13 -0700127 }
David Tolnayf02146e2020-11-01 15:35:42 -0800128 let pending = self.blocks.len() - self.blocks_pending..;
129 for block in &self.blocks[pending] {
130 Block::write_begin(*block, &mut self.bytes);
David Tolnayb92e66f2020-03-01 13:36:55 -0800131 }
David Tolnayf02146e2020-11-01 15:35:42 -0800132 } else if self.section_pending && !self.bytes.is_empty() {
133 self.bytes.push('\n');
David Tolnay7db73692019-10-20 14:51:12 -0400134 }
David Tolnaydab7e802020-08-28 18:54:48 -0700135 self.bytes.push_str(b);
David Tolnayf02146e2020-11-01 15:35:42 -0800136 self.section_pending = false;
137 self.blocks_pending = 0;
David Tolnay7db73692019-10-20 14:51:12 -0400138 }
David Tolnay7db73692019-10-20 14:51:12 -0400139 }
140}