use alloc::string::String;
use crate::repeat_char;
use crate::{
Keyword::{self, *},
Punct::{self, *},
};
use crate::{Flexible, FlexibleList};
#[derive(Debug, Default)]
pub struct Generator {
code: String,
}
impl Generator {
#[must_use]
pub fn new() -> Self {
Self {
code: String::new(),
}
}
pub fn clear(&mut self) -> &mut Self {
self.code.clear();
self
}
#[must_use]
pub fn code(&self) -> &String {
&self.code
}
#[must_use]
pub fn code_mut(&mut self) -> &mut String {
&mut self.code
}
#[must_use]
pub fn into_code(self) -> String {
self.code
}
pub fn out(&mut self, s: &str) -> &mut Self {
self.code.push_str(s);
self
}
pub fn outc(&mut self, c: char) -> &mut Self {
self.code.push(c);
self
}
}
impl Generator {
pub fn space(&mut self) -> &mut Self {
self.outc(' ')
}
pub fn line(&mut self) -> &mut Self {
self.outc('\n')
}
pub fn lines(&mut self, n: usize) -> &mut Self {
self.out(&repeat_char('\n', n))
}
pub fn punct(&mut self, p: Punct) -> &mut Self {
self.outc(p as u8 as _)
}
pub fn keyword(&mut self, kw: Keyword) -> &mut Self {
self.out(kw.as_str())
}
pub fn ident(&mut self, i: &str) -> &mut Self {
self.out(i)
}
}
impl Generator {
impl_punct!(semi, Semi);
impl_punct!(dot, Dot);
impl_punct!(comma, Comma);
impl_punct!(colon, Colon);
impl_punct!(hash, Hash);
impl_punct!(star, Star);
impl_punct!(l_paren, LParen);
impl_punct!(r_paren, RParen);
impl_punct!(l_brace, LBrace);
impl_punct!(r_brace, RBrace);
impl_punct!(l_curly, LCurly);
impl_punct!(r_curly, RCurly);
impl_punct!(quote, Quote);
impl_punct!(single_quote, SingleQuote);
impl_punct!(equal, Equal);
}
impl Generator {
impl_keyword!(public, Pub);
impl_keyword!(not_safe, Unsafe);
impl_keyword!(func, Fn);
impl_keyword!(mutable, Mut);
impl_keyword!(implement, Impl);
impl_keyword!(variable, Let);
impl_keyword!(constant, Const);
}
impl Generator {
impl_alias!(deref, star);
}
impl Generator {
pub fn quoted<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
let mut g = Generator::new();
expr.call(&mut g);
self.quote();
self.out(g.code());
self.quote()
}
pub fn parenthesized<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
let mut g = Generator::new();
expr.call(&mut g);
self.l_paren();
self.out(g.code());
self.r_paren()
}
pub fn braced<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
let mut g = Generator::new();
expr.call(&mut g);
self.l_brace();
self.out(g.code());
self.r_brace()
}
pub fn curlied<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
let mut g = Generator::new();
expr.call(&mut g);
self.l_curly();
self.out(g.code());
self.r_curly()
}
}
impl Generator {
pub fn str<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
self.quoted(expr)
}
pub fn block<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
self.curlied(expr)
}
pub fn unsafe_block<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
self.keyword(Unsafe);
self.block(expr)
}
}
impl Generator {
pub fn declare_const<Name, Ty, Val>(&mut self, name: Name, ty: Ty, val: Val) -> &mut Self
where
Name: Flexible,
Ty: Flexible,
Val: Flexible,
{
self.constant();
self.space();
let mut g = Generator::new();
name.call(&mut g);
self.ident(g.code());
self.colon();
g.clear();
ty.call(&mut g);
self.out(g.code());
g.equal();
g.clear();
val.call(&mut g);
self.out(g.code());
self.semi()
}
}
macro_rules! impl_punct {
($fn:ident, $var:ident) => {
pub fn $fn(&mut self) -> &mut Self {
self.punct($var)
}
};
}
macro_rules! impl_keyword {
($fn:ident, $var:ident) => {
pub fn $fn(&mut self) -> &mut Self {
self.keyword($var)
}
};
}
macro_rules! impl_alias {
($fn:ident, $alias:ident) => {
pub fn $fn(&mut self) -> &mut Self {
self.$alias()
}
};
}
use {impl_alias, impl_keyword, impl_punct};