blob: 9dd4a7d7bbc0f3792c5dd3a646504b138a322d5e [file] [log] [blame]
David Tolnay3be0e1f2020-10-31 20:53:00 -07001use crate::gen::builtin::Builtins;
David Tolnay9c68b1a2020-03-06 11:12:55 -08002use crate::gen::include::Includes;
David Tolnayb560a0f2020-10-30 21:28:45 -07003use crate::syntax::Types;
David Tolnay7ece56f2020-03-29 21:21:38 -07004use std::cell::RefCell;
David Tolnay7db73692019-10-20 14:51:12 -04005use std::fmt::{self, Arguments, Write};
6
David Tolnayb560a0f2020-10-30 21:28:45 -07007pub(crate) struct OutFile<'a> {
David Tolnay7db73692019-10-20 14:51:12 -04008 pub header: bool,
David Tolnayb560a0f2020-10-30 21:28:45 -07009 pub types: &'a Types<'a>,
David Tolnay9c68b1a2020-03-06 11:12:55 -080010 pub include: Includes,
David Tolnay3be0e1f2020-10-31 20:53:00 -070011 pub builtin: Builtins,
David Tolnay54702b92020-07-31 11:50:09 -070012 pub front: Content,
David Tolnay7ece56f2020-03-29 21:21:38 -070013 content: RefCell<Content>,
14}
15
David Tolnay54702b92020-07-31 11:50:09 -070016pub struct Content {
David Tolnaydab7e802020-08-28 18:54:48 -070017 bytes: String,
David Tolnay7db73692019-10-20 14:51:12 -040018 section_pending: bool,
David Tolnay9ad1fbc2020-03-01 14:01:24 -080019 blocks_pending: Vec<&'static str>,
David Tolnay7db73692019-10-20 14:51:12 -040020}
21
David Tolnayb560a0f2020-10-30 21:28:45 -070022impl<'a> OutFile<'a> {
23 pub fn new(header: bool, types: &'a Types) -> Self {
David Tolnay7db73692019-10-20 14:51:12 -040024 OutFile {
David Tolnay7db73692019-10-20 14:51:12 -040025 header,
David Tolnayb560a0f2020-10-30 21:28:45 -070026 types,
David Tolnay9c68b1a2020-03-06 11:12:55 -080027 include: Includes::new(),
David Tolnay3be0e1f2020-10-31 20:53:00 -070028 builtin: Builtins::new(),
David Tolnay54702b92020-07-31 11:50:09 -070029 front: Content::new(),
30 content: RefCell::new(Content::new()),
David Tolnay7db73692019-10-20 14:51:12 -040031 }
32 }
33
34 // Write a blank line if the preceding section had any contents.
35 pub fn next_section(&mut self) {
David Tolnaycb2189f2020-10-31 21:23:08 -070036 self.content.get_mut().next_section();
David Tolnay7db73692019-10-20 14:51:12 -040037 }
38
39 pub fn begin_block(&mut self, block: &'static str) {
David Tolnaycb2189f2020-10-31 21:23:08 -070040 self.content.get_mut().begin_block(block);
David Tolnay7db73692019-10-20 14:51:12 -040041 }
42
David Tolnay9ad1fbc2020-03-01 14:01:24 -080043 pub fn end_block(&mut self, block: &'static str) {
David Tolnaycb2189f2020-10-31 21:23:08 -070044 self.content.get_mut().end_block(block);
David Tolnay7db73692019-10-20 14:51:12 -040045 }
46
David Tolnay7ece56f2020-03-29 21:21:38 -070047 pub fn write_fmt(&self, args: Arguments) {
48 let content = &mut *self.content.borrow_mut();
49 Write::write_fmt(content, args).unwrap();
50 }
51
52 pub fn content(&self) -> Vec<u8> {
David Tolnay54702b92020-07-31 11:50:09 -070053 let front = &self.front.bytes;
54 let content = &self.content.borrow().bytes;
David Tolnay91489ec2020-09-03 12:48:46 -070055 let len = front.len() + content.len() + 1;
David Tolnaydab7e802020-08-28 18:54:48 -070056 let mut out = String::with_capacity(len);
57 out.push_str(front);
David Tolnay91489ec2020-09-03 12:48:46 -070058 if !front.is_empty() && !content.is_empty() {
David Tolnaydab7e802020-08-28 18:54:48 -070059 out.push('\n');
David Tolnay54702b92020-07-31 11:50:09 -070060 }
David Tolnaydab7e802020-08-28 18:54:48 -070061 out.push_str(content);
David Tolnay91489ec2020-09-03 12:48:46 -070062 if out.is_empty() {
63 out.push_str("// empty\n");
64 }
David Tolnaydab7e802020-08-28 18:54:48 -070065 out.into_bytes()
David Tolnay7db73692019-10-20 14:51:12 -040066 }
67}
68
David Tolnay7ece56f2020-03-29 21:21:38 -070069impl Write for Content {
David Tolnay7db73692019-10-20 14:51:12 -040070 fn write_str(&mut self, s: &str) -> fmt::Result {
David Tolnaydab7e802020-08-28 18:54:48 -070071 self.write(s);
David Tolnayf4632de2020-07-31 10:46:55 -070072 Ok(())
73 }
74}
75
76impl Content {
David Tolnay54702b92020-07-31 11:50:09 -070077 fn new() -> Self {
78 Content {
David Tolnaydab7e802020-08-28 18:54:48 -070079 bytes: String::new(),
David Tolnay54702b92020-07-31 11:50:09 -070080 section_pending: false,
81 blocks_pending: Vec::new(),
82 }
83 }
84
David Tolnaycb2189f2020-10-31 21:23:08 -070085 pub fn next_section(&mut self) {
86 self.section_pending = true;
87 }
88
89 pub fn begin_block(&mut self, block: &'static str) {
90 self.blocks_pending.push(block);
91 }
92
93 pub fn end_block(&mut self, block: &'static str) {
94 if self.blocks_pending.pop().is_none() {
95 self.bytes.push_str("} // ");
96 self.bytes.push_str(block);
97 self.bytes.push('\n');
98 self.section_pending = true;
99 }
100 }
101
102 pub fn write_fmt(&mut self, args: Arguments) {
103 Write::write_fmt(self, args).unwrap();
104 }
105
David Tolnaydab7e802020-08-28 18:54:48 -0700106 fn write(&mut self, b: &str) {
David Tolnayf4632de2020-07-31 10:46:55 -0700107 if !b.is_empty() {
David Tolnay9ad1fbc2020-03-01 14:01:24 -0800108 if !self.blocks_pending.is_empty() {
David Tolnay7ece56f2020-03-29 21:21:38 -0700109 if !self.bytes.is_empty() {
David Tolnaydab7e802020-08-28 18:54:48 -0700110 self.bytes.push('\n');
David Tolnay3577d452020-03-17 21:48:13 -0700111 }
David Tolnay9ad1fbc2020-03-01 14:01:24 -0800112 for block in self.blocks_pending.drain(..) {
David Tolnaydab7e802020-08-28 18:54:48 -0700113 self.bytes.push_str(block);
114 self.bytes.push_str(" {\n");
David Tolnayb92e66f2020-03-01 13:36:55 -0800115 }
David Tolnay7db73692019-10-20 14:51:12 -0400116 self.section_pending = false;
117 } else if self.section_pending {
David Tolnay7ece56f2020-03-29 21:21:38 -0700118 if !self.bytes.is_empty() {
David Tolnaydab7e802020-08-28 18:54:48 -0700119 self.bytes.push('\n');
David Tolnay3577d452020-03-17 21:48:13 -0700120 }
David Tolnay7db73692019-10-20 14:51:12 -0400121 self.section_pending = false;
122 }
David Tolnaydab7e802020-08-28 18:54:48 -0700123 self.bytes.push_str(b);
David Tolnay7db73692019-10-20 14:51:12 -0400124 }
David Tolnay7db73692019-10-20 14:51:12 -0400125 }
126}