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