blob: bf880cc8ba3bcf4c5bba9082b0b020e00d89b4f5 [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 Tolnay078c90f2020-11-01 13:31:08 -08005use crate::syntax::namespace::Namespace;
David Tolnayb560a0f2020-10-30 21:28:45 -07006use crate::syntax::Types;
David Tolnay7ece56f2020-03-29 21:21:38 -07007use std::cell::RefCell;
David Tolnay7db73692019-10-20 14:51:12 -04008use std::fmt::{self, Arguments, Write};
9
David Tolnayb560a0f2020-10-30 21:28:45 -070010pub(crate) struct OutFile<'a> {
David Tolnay7db73692019-10-20 14:51:12 -040011 pub header: bool,
David Tolnaye1476af2020-11-01 13:47:25 -080012 pub opt: &'a Opt,
David Tolnayb560a0f2020-10-30 21:28:45 -070013 pub types: &'a Types<'a>,
David Tolnay97c5b862020-11-01 14:59:01 -080014 pub include: Includes<'a>,
15 pub builtin: Builtins<'a>,
16 content: RefCell<Content<'a>>,
David Tolnay7ece56f2020-03-29 21:21:38 -070017}
18
David Tolnay8810a542020-10-31 21:39:22 -070019#[derive(Default)]
David Tolnay97c5b862020-11-01 14:59:01 -080020pub struct Content<'a> {
David Tolnaydab7e802020-08-28 18:54:48 -070021 bytes: String,
David Tolnay078c90f2020-11-01 13:31:08 -080022 namespace: &'a Namespace,
David Tolnaye3b39822020-11-01 15:55:21 -080023 blocks: Vec<BlockBoundary<'a>>,
David Tolnay7db73692019-10-20 14:51:12 -040024 section_pending: bool,
David Tolnayf02146e2020-11-01 15:35:42 -080025 blocks_pending: usize,
David Tolnay7db73692019-10-20 14:51:12 -040026}
27
David Tolnaye3b39822020-11-01 15:55:21 -080028#[derive(Copy, Clone, PartialEq, Debug)]
29enum BlockBoundary<'a> {
30 Begin(Block<'a>),
31 End(Block<'a>),
32}
33
David Tolnayb560a0f2020-10-30 21:28:45 -070034impl<'a> OutFile<'a> {
David Tolnaye1476af2020-11-01 13:47:25 -080035 pub fn new(header: bool, opt: &'a Opt, types: &'a Types) -> Self {
David Tolnay7db73692019-10-20 14:51:12 -040036 OutFile {
David Tolnay7db73692019-10-20 14:51:12 -040037 header,
David Tolnaye1476af2020-11-01 13:47:25 -080038 opt,
David Tolnayb560a0f2020-10-30 21:28:45 -070039 types,
David Tolnay9c68b1a2020-03-06 11:12:55 -080040 include: Includes::new(),
David Tolnay3be0e1f2020-10-31 20:53:00 -070041 builtin: Builtins::new(),
David Tolnay54702b92020-07-31 11:50:09 -070042 content: RefCell::new(Content::new()),
David Tolnay7db73692019-10-20 14:51:12 -040043 }
44 }
45
46 // Write a blank line if the preceding section had any contents.
47 pub fn next_section(&mut self) {
David Tolnaycb2189f2020-10-31 21:23:08 -070048 self.content.get_mut().next_section();
David Tolnay7db73692019-10-20 14:51:12 -040049 }
50
David Tolnay97c5b862020-11-01 14:59:01 -080051 pub fn begin_block(&mut self, block: Block<'a>) {
David Tolnaycb2189f2020-10-31 21:23:08 -070052 self.content.get_mut().begin_block(block);
David Tolnay7db73692019-10-20 14:51:12 -040053 }
54
David Tolnay97c5b862020-11-01 14:59:01 -080055 pub fn end_block(&mut self, block: Block<'a>) {
David Tolnaycb2189f2020-10-31 21:23:08 -070056 self.content.get_mut().end_block(block);
David Tolnay7db73692019-10-20 14:51:12 -040057 }
58
David Tolnay078c90f2020-11-01 13:31:08 -080059 pub fn set_namespace(&mut self, namespace: &'a Namespace) {
60 self.content.get_mut().set_namespace(namespace);
61 }
62
David Tolnay7ece56f2020-03-29 21:21:38 -070063 pub fn write_fmt(&self, args: Arguments) {
64 let content = &mut *self.content.borrow_mut();
65 Write::write_fmt(content, args).unwrap();
66 }
67
David Tolnaye3b39822020-11-01 15:55:21 -080068 pub fn content(&mut self) -> Vec<u8> {
69 self.flush();
David Tolnay8810a542020-10-31 21:39:22 -070070 let include = &self.include.content.bytes;
David Tolnay8c14d9a2020-10-31 21:52:38 -070071 let builtin = &self.builtin.content.bytes;
David Tolnaye3b39822020-11-01 15:55:21 -080072 let content = &self.content.get_mut().bytes;
David Tolnay8c14d9a2020-10-31 21:52:38 -070073 let len = include.len() + builtin.len() + content.len() + 2;
David Tolnaydab7e802020-08-28 18:54:48 -070074 let mut out = String::with_capacity(len);
David Tolnay8810a542020-10-31 21:39:22 -070075 out.push_str(include);
David Tolnay8c14d9a2020-10-31 21:52:38 -070076 if !out.is_empty() && !builtin.is_empty() {
77 out.push('\n');
78 }
79 out.push_str(builtin);
80 if !out.is_empty() && !content.is_empty() {
David Tolnaydab7e802020-08-28 18:54:48 -070081 out.push('\n');
David Tolnay54702b92020-07-31 11:50:09 -070082 }
David Tolnaydab7e802020-08-28 18:54:48 -070083 out.push_str(content);
David Tolnay91489ec2020-09-03 12:48:46 -070084 if out.is_empty() {
85 out.push_str("// empty\n");
86 }
David Tolnaydab7e802020-08-28 18:54:48 -070087 out.into_bytes()
David Tolnay7db73692019-10-20 14:51:12 -040088 }
David Tolnaye3b39822020-11-01 15:55:21 -080089
90 fn flush(&mut self) {
91 self.include.content.flush();
92 self.builtin.content.flush();
93 self.content.get_mut().flush();
94 }
David Tolnay7db73692019-10-20 14:51:12 -040095}
96
David Tolnay97c5b862020-11-01 14:59:01 -080097impl<'a> Write for Content<'a> {
David Tolnay7db73692019-10-20 14:51:12 -040098 fn write_str(&mut self, s: &str) -> fmt::Result {
David Tolnaydab7e802020-08-28 18:54:48 -070099 self.write(s);
David Tolnayf4632de2020-07-31 10:46:55 -0700100 Ok(())
101 }
102}
103
David Tolnay97c5b862020-11-01 14:59:01 -0800104impl<'a> PartialEq for Content<'a> {
David Tolnay8810a542020-10-31 21:39:22 -0700105 fn eq(&self, _other: &Content) -> bool {
106 true
107 }
108}
109
David Tolnay97c5b862020-11-01 14:59:01 -0800110impl<'a> Content<'a> {
David Tolnay54702b92020-07-31 11:50:09 -0700111 fn new() -> Self {
David Tolnay8810a542020-10-31 21:39:22 -0700112 Content::default()
David Tolnay54702b92020-07-31 11:50:09 -0700113 }
114
David Tolnaycb2189f2020-10-31 21:23:08 -0700115 pub fn next_section(&mut self) {
116 self.section_pending = true;
117 }
118
David Tolnay97c5b862020-11-01 14:59:01 -0800119 pub fn begin_block(&mut self, block: Block<'a>) {
David Tolnaye3b39822020-11-01 15:55:21 -0800120 self.push_block_boundary(BlockBoundary::Begin(block));
David Tolnaycb2189f2020-10-31 21:23:08 -0700121 }
122
David Tolnay97c5b862020-11-01 14:59:01 -0800123 pub fn end_block(&mut self, block: Block<'a>) {
David Tolnaye3b39822020-11-01 15:55:21 -0800124 self.push_block_boundary(BlockBoundary::End(block));
David Tolnaycb2189f2020-10-31 21:23:08 -0700125 }
126
David Tolnay078c90f2020-11-01 13:31:08 -0800127 pub fn set_namespace(&mut self, namespace: &'a Namespace) {
128 for name in self.namespace.iter().rev() {
129 self.end_block(Block::UserDefinedNamespace(name));
130 }
131 for name in namespace {
132 self.begin_block(Block::UserDefinedNamespace(name));
133 }
134 self.namespace = namespace;
135 }
136
David Tolnaycb2189f2020-10-31 21:23:08 -0700137 pub fn write_fmt(&mut self, args: Arguments) {
138 Write::write_fmt(self, args).unwrap();
139 }
140
David Tolnaydab7e802020-08-28 18:54:48 -0700141 fn write(&mut self, b: &str) {
David Tolnayf4632de2020-07-31 10:46:55 -0700142 if !b.is_empty() {
David Tolnayf02146e2020-11-01 15:35:42 -0800143 if self.blocks_pending > 0 {
David Tolnaye3b39822020-11-01 15:55:21 -0800144 self.flush_blocks();
145 }
146 if self.section_pending && !self.bytes.is_empty() {
David Tolnayf02146e2020-11-01 15:35:42 -0800147 self.bytes.push('\n');
David Tolnay7db73692019-10-20 14:51:12 -0400148 }
David Tolnaydab7e802020-08-28 18:54:48 -0700149 self.bytes.push_str(b);
David Tolnayf02146e2020-11-01 15:35:42 -0800150 self.section_pending = false;
151 self.blocks_pending = 0;
David Tolnay7db73692019-10-20 14:51:12 -0400152 }
David Tolnay7db73692019-10-20 14:51:12 -0400153 }
David Tolnaye3b39822020-11-01 15:55:21 -0800154
155 fn push_block_boundary(&mut self, boundary: BlockBoundary<'a>) {
156 if self.blocks_pending > 0 && boundary == self.blocks.last().unwrap().rev() {
157 self.blocks.pop();
158 self.blocks_pending -= 1;
159 } else {
160 self.blocks.push(boundary);
161 self.blocks_pending += 1;
162 }
163 }
164
165 fn flush(&mut self) {
David Tolnay078c90f2020-11-01 13:31:08 -0800166 self.set_namespace(Default::default());
David Tolnaye3b39822020-11-01 15:55:21 -0800167 if self.blocks_pending > 0 {
168 self.flush_blocks();
169 }
170 }
171
172 fn flush_blocks(&mut self) {
173 self.section_pending = !self.bytes.is_empty();
174 let mut read = self.blocks.len() - self.blocks_pending;
175 let mut write = read;
176
177 while read < self.blocks.len() {
178 match self.blocks[read] {
179 BlockBoundary::Begin(begin_block) => {
180 if self.section_pending {
181 self.bytes.push('\n');
182 self.section_pending = false;
183 }
184 Block::write_begin(begin_block, &mut self.bytes);
185 self.blocks[write] = BlockBoundary::Begin(begin_block);
186 write += 1;
187 }
188 BlockBoundary::End(end_block) => {
189 write = write.checked_sub(1).unwrap();
190 let begin_block = self.blocks[write];
191 assert_eq!(begin_block, BlockBoundary::Begin(end_block));
192 Block::write_end(end_block, &mut self.bytes);
193 self.section_pending = true;
194 }
195 }
196 read += 1;
197 }
198
199 self.blocks.truncate(write);
200 }
201}
202
203impl<'a> BlockBoundary<'a> {
204 fn rev(self) -> BlockBoundary<'a> {
205 match self {
206 BlockBoundary::Begin(block) => BlockBoundary::End(block),
207 BlockBoundary::End(block) => BlockBoundary::Begin(block),
208 }
209 }
David Tolnay7db73692019-10-20 14:51:12 -0400210}