blob: 2733c32dc814c63770c0a3e19f874cc7cd6a69fd [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 Tolnaye3b39822020-11-01 15:55:21 -080021 blocks: Vec<BlockBoundary<'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 Tolnaye3b39822020-11-01 15:55:21 -080026#[derive(Copy, Clone, PartialEq, Debug)]
27enum BlockBoundary<'a> {
28 Begin(Block<'a>),
29 End(Block<'a>),
30}
31
David Tolnayb560a0f2020-10-30 21:28:45 -070032impl<'a> OutFile<'a> {
David Tolnaye1476af2020-11-01 13:47:25 -080033 pub fn new(header: bool, opt: &'a Opt, types: &'a Types) -> Self {
David Tolnay7db73692019-10-20 14:51:12 -040034 OutFile {
David Tolnay7db73692019-10-20 14:51:12 -040035 header,
David Tolnaye1476af2020-11-01 13:47:25 -080036 opt,
David Tolnayb560a0f2020-10-30 21:28:45 -070037 types,
David Tolnay9c68b1a2020-03-06 11:12:55 -080038 include: Includes::new(),
David Tolnay3be0e1f2020-10-31 20:53:00 -070039 builtin: Builtins::new(),
David Tolnay54702b92020-07-31 11:50:09 -070040 content: RefCell::new(Content::new()),
David Tolnay7db73692019-10-20 14:51:12 -040041 }
42 }
43
44 // Write a blank line if the preceding section had any contents.
45 pub fn next_section(&mut self) {
David Tolnaycb2189f2020-10-31 21:23:08 -070046 self.content.get_mut().next_section();
David Tolnay7db73692019-10-20 14:51:12 -040047 }
48
David Tolnay97c5b862020-11-01 14:59:01 -080049 pub fn begin_block(&mut self, block: Block<'a>) {
David Tolnaycb2189f2020-10-31 21:23:08 -070050 self.content.get_mut().begin_block(block);
David Tolnay7db73692019-10-20 14:51:12 -040051 }
52
David Tolnay97c5b862020-11-01 14:59:01 -080053 pub fn end_block(&mut self, block: Block<'a>) {
David Tolnaycb2189f2020-10-31 21:23:08 -070054 self.content.get_mut().end_block(block);
David Tolnay7db73692019-10-20 14:51:12 -040055 }
56
David Tolnay7ece56f2020-03-29 21:21:38 -070057 pub fn write_fmt(&self, args: Arguments) {
58 let content = &mut *self.content.borrow_mut();
59 Write::write_fmt(content, args).unwrap();
60 }
61
David Tolnaye3b39822020-11-01 15:55:21 -080062 pub fn content(&mut self) -> Vec<u8> {
63 self.flush();
David Tolnay8810a542020-10-31 21:39:22 -070064 let include = &self.include.content.bytes;
David Tolnay8c14d9a2020-10-31 21:52:38 -070065 let builtin = &self.builtin.content.bytes;
David Tolnaye3b39822020-11-01 15:55:21 -080066 let content = &self.content.get_mut().bytes;
David Tolnay8c14d9a2020-10-31 21:52:38 -070067 let len = include.len() + builtin.len() + content.len() + 2;
David Tolnaydab7e802020-08-28 18:54:48 -070068 let mut out = String::with_capacity(len);
David Tolnay8810a542020-10-31 21:39:22 -070069 out.push_str(include);
David Tolnay8c14d9a2020-10-31 21:52:38 -070070 if !out.is_empty() && !builtin.is_empty() {
71 out.push('\n');
72 }
73 out.push_str(builtin);
74 if !out.is_empty() && !content.is_empty() {
David Tolnaydab7e802020-08-28 18:54:48 -070075 out.push('\n');
David Tolnay54702b92020-07-31 11:50:09 -070076 }
David Tolnaydab7e802020-08-28 18:54:48 -070077 out.push_str(content);
David Tolnay91489ec2020-09-03 12:48:46 -070078 if out.is_empty() {
79 out.push_str("// empty\n");
80 }
David Tolnaydab7e802020-08-28 18:54:48 -070081 out.into_bytes()
David Tolnay7db73692019-10-20 14:51:12 -040082 }
David Tolnaye3b39822020-11-01 15:55:21 -080083
84 fn flush(&mut self) {
85 self.include.content.flush();
86 self.builtin.content.flush();
87 self.content.get_mut().flush();
88 }
David Tolnay7db73692019-10-20 14:51:12 -040089}
90
David Tolnay97c5b862020-11-01 14:59:01 -080091impl<'a> Write for Content<'a> {
David Tolnay7db73692019-10-20 14:51:12 -040092 fn write_str(&mut self, s: &str) -> fmt::Result {
David Tolnaydab7e802020-08-28 18:54:48 -070093 self.write(s);
David Tolnayf4632de2020-07-31 10:46:55 -070094 Ok(())
95 }
96}
97
David Tolnay97c5b862020-11-01 14:59:01 -080098impl<'a> PartialEq for Content<'a> {
David Tolnay8810a542020-10-31 21:39:22 -070099 fn eq(&self, _other: &Content) -> bool {
100 true
101 }
102}
103
David Tolnay97c5b862020-11-01 14:59:01 -0800104impl<'a> Content<'a> {
David Tolnay54702b92020-07-31 11:50:09 -0700105 fn new() -> Self {
David Tolnay8810a542020-10-31 21:39:22 -0700106 Content::default()
David Tolnay54702b92020-07-31 11:50:09 -0700107 }
108
David Tolnaycb2189f2020-10-31 21:23:08 -0700109 pub fn next_section(&mut self) {
110 self.section_pending = true;
111 }
112
David Tolnay97c5b862020-11-01 14:59:01 -0800113 pub fn begin_block(&mut self, block: Block<'a>) {
David Tolnaye3b39822020-11-01 15:55:21 -0800114 self.push_block_boundary(BlockBoundary::Begin(block));
David Tolnaycb2189f2020-10-31 21:23:08 -0700115 }
116
David Tolnay97c5b862020-11-01 14:59:01 -0800117 pub fn end_block(&mut self, block: Block<'a>) {
David Tolnaye3b39822020-11-01 15:55:21 -0800118 self.push_block_boundary(BlockBoundary::End(block));
David Tolnaycb2189f2020-10-31 21:23:08 -0700119 }
120
121 pub fn write_fmt(&mut self, args: Arguments) {
122 Write::write_fmt(self, args).unwrap();
123 }
124
David Tolnaydab7e802020-08-28 18:54:48 -0700125 fn write(&mut self, b: &str) {
David Tolnayf4632de2020-07-31 10:46:55 -0700126 if !b.is_empty() {
David Tolnayf02146e2020-11-01 15:35:42 -0800127 if self.blocks_pending > 0 {
David Tolnaye3b39822020-11-01 15:55:21 -0800128 self.flush_blocks();
129 }
130 if self.section_pending && !self.bytes.is_empty() {
David Tolnayf02146e2020-11-01 15:35:42 -0800131 self.bytes.push('\n');
David Tolnay7db73692019-10-20 14:51:12 -0400132 }
David Tolnaydab7e802020-08-28 18:54:48 -0700133 self.bytes.push_str(b);
David Tolnayf02146e2020-11-01 15:35:42 -0800134 self.section_pending = false;
135 self.blocks_pending = 0;
David Tolnay7db73692019-10-20 14:51:12 -0400136 }
David Tolnay7db73692019-10-20 14:51:12 -0400137 }
David Tolnaye3b39822020-11-01 15:55:21 -0800138
139 fn push_block_boundary(&mut self, boundary: BlockBoundary<'a>) {
140 if self.blocks_pending > 0 && boundary == self.blocks.last().unwrap().rev() {
141 self.blocks.pop();
142 self.blocks_pending -= 1;
143 } else {
144 self.blocks.push(boundary);
145 self.blocks_pending += 1;
146 }
147 }
148
149 fn flush(&mut self) {
150 if self.blocks_pending > 0 {
151 self.flush_blocks();
152 }
153 }
154
155 fn flush_blocks(&mut self) {
156 self.section_pending = !self.bytes.is_empty();
157 let mut read = self.blocks.len() - self.blocks_pending;
158 let mut write = read;
159
160 while read < self.blocks.len() {
161 match self.blocks[read] {
162 BlockBoundary::Begin(begin_block) => {
163 if self.section_pending {
164 self.bytes.push('\n');
165 self.section_pending = false;
166 }
167 Block::write_begin(begin_block, &mut self.bytes);
168 self.blocks[write] = BlockBoundary::Begin(begin_block);
169 write += 1;
170 }
171 BlockBoundary::End(end_block) => {
172 write = write.checked_sub(1).unwrap();
173 let begin_block = self.blocks[write];
174 assert_eq!(begin_block, BlockBoundary::Begin(end_block));
175 Block::write_end(end_block, &mut self.bytes);
176 self.section_pending = true;
177 }
178 }
179 read += 1;
180 }
181
182 self.blocks.truncate(write);
183 }
184}
185
186impl<'a> BlockBoundary<'a> {
187 fn rev(self) -> BlockBoundary<'a> {
188 match self {
189 BlockBoundary::Begin(block) => BlockBoundary::End(block),
190 BlockBoundary::End(block) => BlockBoundary::Begin(block),
191 }
192 }
David Tolnay7db73692019-10-20 14:51:12 -0400193}