cg2 0.3.6

Rust code generator.
Documentation
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 add_code(&mut self, s: &str) -> &mut Self {
    self.code.push_str(s);
    self
  }

  pub fn out<S>(&mut self, s: S) -> &mut Self
  where
    S: Flexible,
  {
    let mut g = Generator::new();

    s.call(&mut g);

    self.add_code(g.code())
  }

  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<I>(&mut self, i: I) -> &mut Self
  where
    I: Flexible,
  {
    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,
  {
    self.quote();
    self.out(expr);
    self.quote()
  }

  pub fn parenthesized<E>(&mut self, expr: E) -> &mut Self
  where
    E: Flexible,
  {
    self.l_paren();
    self.out(expr);
    self.r_paren()
  }

  pub fn braced<E>(&mut self, expr: E) -> &mut Self
  where
    E: Flexible,
  {
    self.l_brace();
    self.out(expr);
    self.r_brace()
  }

  pub fn curlied<E>(&mut self, expr: E) -> &mut Self
  where
    E: Flexible,
  {
    self.l_curly();
    self.out(expr);
    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();
    self.ident(name);
    self.colon();
    self.out(ty);
    self.equal();
    self.out(val);
    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};