Skip to main content

yog_codegen/
writer.rs

1//! An indenting writer for a language with blocks.
2
3use std::marker::PhantomData;
4
5use crate::syntax::{Blocks, Comments, Literals};
6
7/// Generated code of language `L`, written a line at a time at the current depth.
8pub struct Code<L> {
9    out: String,
10    depth: usize,
11    lang: PhantomData<L>,
12}
13
14impl<L: Blocks + Comments + Literals> Code<L> {
15    /// An empty file.
16    pub fn new() -> Self {
17        Self::starting(String::new())
18    }
19
20    /// A file starting with `text` (its header, say) as written.
21    pub fn starting(text: impl Into<String>) -> Self {
22        Self {
23            out: text.into(),
24            depth: 0,
25            lang: PhantomData,
26        }
27    }
28
29    /// A string literal of the language.
30    pub fn str(&self, text: &str) -> String {
31        L::string(text)
32    }
33
34    /// One line at the current depth.
35    pub fn line(&mut self, text: impl AsRef<str>) -> &mut Self {
36        for _ in 0..self.depth {
37            self.out.push_str(L::INDENT);
38        }
39        self.out.push_str(text.as_ref());
40        self.out.push('\n');
41        self
42    }
43
44    /// An empty line.
45    pub fn blank(&mut self) -> &mut Self {
46        self.out.push('\n');
47        self
48    }
49
50    /// A doc comment on what follows.
51    pub fn doc(&mut self, text: impl AsRef<str>) -> &mut Self {
52        self.line(L::doc(text.as_ref()))
53    }
54
55    /// A block after `head`, and what follows one level deeper.
56    pub fn open(&mut self, head: impl AsRef<str>) -> &mut Self {
57        self.line(L::open(head.as_ref()));
58        self.depth += 1;
59        self
60    }
61
62    /// The innermost block closed, then `tail`.
63    pub fn close(&mut self, tail: &str) -> &mut Self {
64        self.depth = self.depth.saturating_sub(1);
65        self.line(L::close(tail))
66    }
67
68    /// The code written.
69    pub fn finish(self) -> String {
70        self.out
71    }
72}
73
74impl<L: Blocks + Comments + Literals> Default for Code<L> {
75    fn default() -> Self {
76        Self::new()
77    }
78}
79
80#[cfg(test)]
81mod tests;