use alloc::string::String;
use crate::{fns, 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 spaces(&mut self, n: usize) -> &mut Self {
self.out(repeat_char(' ', n))
}
pub fn line(&mut self) -> &mut Self {
self.outc('\n')
}
impl_simple_alias!(ln, line);
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())
}
impl_alias!(
pub fn(&mut self, kw: Keyword) -> &mut Self {
self.keyword(kw)
},
[kw]
);
pub fn ident<I>(&mut self, i: I) -> &mut Self
where
I: Flexible,
{
self.out(i)
}
impl_alias!(
pub fn [I](&mut self, i: I) -> &mut Self
where
[I: Flexible]
{
self.out(i)
},
[id]
);
}
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_punct!(slash, Slash);
impl_punct!(minus, Minus);
impl_punct!(less_than, LessThan);
impl_punct!(greater_than, GreaterThan);
impl_simple_alias!(semicolon, semi);
impl_simple_alias!(period, dot);
impl_simple_alias!(pound, hash);
impl_simple_alias!(deref, star);
impl_simple_alias!(l_bracket, l_paren);
impl_simple_alias!(r_bracket, r_paren);
impl_simple_alias!(l_square_brace, l_brace);
impl_simple_alias!(r_square_brace, r_brace);
impl_simple_alias!(divide, slash);
impl_simple_alias!(sub, minus);
impl_simple_alias!(lt, less_than);
impl_simple_alias!(gt, greater_than);
}
impl Generator {
impl_keyword!(pub_, Pub);
impl_keyword!(unsafe_, Unsafe);
impl_keyword!(fn_, Fn);
impl_keyword!(mut_, Mut);
impl_keyword!(if_, If);
impl_keyword!(else_, Else);
impl_keyword!(enum_, Enum);
impl_keyword!(impl_, Impl);
impl_keyword!(struct_, Struct);
impl_keyword!(union_, Union);
impl_keyword!(let_, Let);
impl_keyword!(const_, Const);
impl_keyword!(self_, Self_);
impl_keyword!(self_ty, SelfTy);
impl_keyword!(match_, Match);
impl_keyword!(for_, For);
impl_keyword!(type_, Type);
impl_keyword!(use_, Use);
impl_keyword!(as_, As);
impl_simple_alias!(public, pub_);
impl_simple_alias!(not_safe, unsafe_);
impl_simple_alias!(function, fn_);
impl_simple_alias!(func, fn_);
impl_simple_alias!(fun, fn_);
impl_simple_alias!(mutable, mut_);
impl_simple_alias!(enumeration, enum_);
impl_simple_alias!(implementation, impl_);
impl_simple_alias!(implement, impl_);
impl_simple_alias!(structure, struct_);
impl_simple_alias!(variable, let_);
impl_simple_alias!(var, let_);
impl_simple_alias!(constant, const_);
impl_simple_alias!(this, self_);
impl_simple_alias!(this_type, self_ty);
impl_simple_alias!(this_ty, self_ty);
impl_simple_alias!(myself, self_ty);
impl_simple_alias!(ty, type_);
impl_simple_alias!(using, use_);
}
impl Generator {
pub fn comma_sep<I>(&mut self, items: I) -> &mut Self
where
I: FlexibleList,
{
let items = items.call();
for (i, item) in items.iter().enumerate() {
if i > 0 {
self.comma();
}
self.out(item);
}
self
}
pub fn quoted<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
self.quote().out(expr).quote()
}
impl_alias!(
pub fn [E](&mut self, expr: E) -> &mut Self
where
[E: Flexible]
{
self.quoted(expr)
},
[string, str]
);
pub fn parenthesized<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
self.l_paren().out(expr).r_paren()
}
impl_alias!(
pub fn [E](&mut self, expr: E) -> &mut Self
where
[E: Flexible]
{
self.parenthesized(expr)
},
[bracketed]
);
pub fn braced<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
self.l_brace().out(expr).r_brace()
}
impl_alias!(
pub fn [E](&mut self, expr: E) -> &mut Self
where
[E: Flexible]
{
self.braced(expr)
},
[square_braced]
);
pub fn curlied<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
self.l_curly().out(expr).r_curly()
}
impl_alias!(
pub fn [E](&mut self, expr: E) -> &mut Self
where
[E: Flexible]
{
self.curlied(expr)
},
[curly_braced, block]
);
pub fn unsafe_block<E>(&mut self, expr: E) -> &mut Self
where
E: Flexible,
{
self.keyword(Unsafe).block(expr)
}
}
impl Generator {
pub fn comment<C>(&mut self, comment: C) -> &mut Self
where
C: Flexible,
{
self.slash().slash().out(comment).line()
}
impl_alias!(
pub fn [C](&mut self, comment: C) -> &mut Self
where
[C: Flexible]
{
self.comment(comment)
},
[cmt]
);
pub fn doc_line(&mut self) -> &mut Self {
self.slash().slash().slash().line()
}
impl_simple_alias!(docline, doc_line);
pub fn doc_comment<C>(&mut self, comment: C) -> &mut Self
where
C: Flexible,
{
self.slash().slash().slash().out(comment).line()
}
impl_alias!(
pub fn [C](&mut self, comment: C) -> &mut Self
where
[C: Flexible]
{
self.doc_comment(comment)
},
[doc]
);
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
.const_()
.space()
.ident(name)
.colon()
.out(ty)
.equal()
.out(val)
.semi()
}
pub fn declare_fn<Name, Params, Ret, Body>(
&mut self,
name: Name,
params: Params,
ret: Ret,
body: Body,
) -> &mut Self
where
Name: Flexible,
Params: FlexibleList,
Ret: Flexible,
Body: FlexibleList,
{
self
.fn_()
.space()
.out(name)
.parenthesized(fns::comma_sep(params));
let mut ret_g = Generator::new();
ret.call(&mut ret_g);
if !ret_g.code().is_empty() {
self.minus().greater_than().out(ret_g);
}
self.block(|g: &mut Generator| {
for i in body.call() {
g.out(i);
}
});
self
}
}
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_simple_alias {
($fn:ident, $alias:ident) => {
pub fn $fn(&mut self) -> &mut Self {
self.$alias()
}
};
}
macro_rules! impl_alias {
(
$vis:vis fn $([ $($gen:tt)* ])? ($($args:tt)*) -> $ret:ty
$(where [$($where:tt)*])?
{
$($forward:tt)*
},
[$($alias:ident),* $(,)?]
) => {
impl_alias! {
@repeat-for-each-alias
[$($alias),*],
{
$vis fn $([ $($gen)* ])? ($($args)*) -> $ret
$(where [$($where)*])?
{
$($forward)*
}
}
}
};
(
@repeat-for-each-alias
[$($alias:ident),*],
$fn:tt
) => {
$(
impl_alias! {
@impl-alias
$alias,
$fn
}
)*
};
(
@impl-alias
$alias:ident,
{
$vis:vis fn $([ $($gen:tt)* ])? ($($args:tt)*) -> $ret:ty
$(where [$($where:tt)*])?
{
$($forward:tt)*
}
}
) => {
$vis fn $alias $(< $($gen)* >)? ($($args)*) -> $ret
$(where $($where)*)?
{
$($forward)*
}
};
}
use {impl_alias, impl_keyword, impl_punct, impl_simple_alias};