use std::rc::Rc;
use syn::{
ext::IdentExt as _,
parse::{Parse, ParseStream},
*,
};
pub enum StmtSyn {
Layout(LayoutTempl),
Use(UseTempl),
Render(RenderTempl),
Yield(YieldTempl),
Block(BlockTempl),
If(IfTempl),
Else(ElseTempl),
For(ForTempl),
Endblock(kw::endblock),
EndIf(kw::endif),
EndFor(kw::endfor),
Item(Rc<ItemTempl>),
Expr(Rc<Expr>),
}
pub struct LayoutTempl {
pub layout_token: kw::layout,
pub path: LitStr,
}
pub struct UseTempl {
pub use_token: Token![use],
pub path: LitStr,
pub as_token: Token![as],
pub ident: Ident,
}
pub struct RenderTempl {
pub render_token: kw::render,
pub value: RenderValue,
pub block: Option<(kw::block,Ident)>
}
pub enum RenderValue {
Ident(Ident),
Path(LitStr),
}
pub struct YieldTempl {
pub yield_token: Token![yield],
pub block: Option<(kw::block, Ident)>
}
pub struct BlockTempl {
pub pub_token: Option<Token![pub]>,
pub static_token: Option<Token![static]>,
pub block_token: kw::block,
pub name: Ident,
}
pub struct IfTempl {
pub if_token: Token![if],
pub cond: Rc<Expr>,
}
pub struct ElseTempl {
pub else_token: Token![else],
pub elif_branch: Option<(Token![if],Rc<Expr>)>
}
pub struct ForTempl {
pub for_token: Token![for],
pub pat: Rc<Pat>,
pub in_token: Token![in],
pub expr: Rc<Expr>,
}
pub enum ItemTempl {
Use(ItemUse),
Const(ItemConst),
}
impl Parse for StmtSyn {
fn parse(input: ParseStream) -> Result<Self> {
match () {
_ if input.peek(kw::layout) => input.parse().map(Self::Layout),
_ if input.peek(kw::extends) => input.parse().map(Self::Layout),
_ if UseTempl::peek(input) => input.parse().map(Self::Use),
_ if input.peek(kw::render) => input.parse().map(Self::Render),
_ if input.peek(Token![yield]) => input.parse().map(Self::Yield),
_ if BlockTempl::peek(input) => input.parse().map(Self::Block),
_ if input.peek(Token![if]) => input.parse().map(Self::If),
_ if input.peek(Token![else]) => input.parse().map(Self::Else),
_ if input.peek(Token![for]) => input.parse().map(Self::For),
_ if input.peek(kw::endblock) => input.parse().map(Self::Endblock),
_ if input.peek(kw::endif) => input.parse().map(Self::EndIf),
_ if input.peek(kw::endfor) => input.parse().map(Self::EndFor),
_ if ItemTempl::peek(input) => input.parse().map(Rc::new).map(Self::Item),
_ => input.parse().map(Rc::new).map(Self::Expr),
}
}
}
impl UseTempl {
pub fn peek(input: ParseStream) -> bool {
input.peek(Token![use]) && input.peek2(LitStr)
}
}
impl BlockTempl {
pub fn peek(input: ParseStream) -> bool {
(input.peek(Token![pub]) && input.peek2(Token![static]) && input.peek3(kw::block)) ||
(input.peek(Token![pub]) && input.peek2(kw::block)) ||
(input.peek(Token![static]) && input.peek2(kw::block)) ||
input.peek(kw::block)
}
}
impl ItemTempl {
pub fn peek(input: ParseStream) -> bool {
input.peek(Token![use]) ||
input.peek(Token![const])
}
}
impl Parse for LayoutTempl {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
layout_token: match () {
_ if input.peek(kw::layout) => input.parse()?,
_ if input.peek(kw::extends) => kw::layout(input.parse::<kw::extends>()?.span),
_ => unreachable!()
},
path: input.parse()?,
})
}
}
impl Parse for UseTempl {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
use_token: input.parse()?,
path: input.parse()?,
as_token: input.parse()?,
ident: input.call(Ident::parse_any)?,
})
}
}
impl Parse for RenderTempl {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
render_token: input.parse()?,
value: input.parse()?,
block: if input.peek(kw::block) {
Some((input.parse()?,input.call(Ident::parse_any)?))
} else {
None
},
})
}
}
impl Parse for RenderValue {
fn parse(input: ParseStream) -> Result<Self> {
let look = input.lookahead1();
match () {
_ if look.peek(LitStr) => input.parse().map(Self::Path),
_ if look.peek(Ident::peek_any) => input.call(Ident::parse_any).map(Self::Ident),
_ => Err(look.error()),
}
}
}
impl Parse for YieldTempl {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
yield_token: input.parse()?,
block: if input.peek(kw::block) {
Some((input.parse()?,input.call(Ident::parse_any)?))
} else {
None
},
})
}
}
impl Parse for BlockTempl {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
pub_token: input.parse()?,
static_token: input.parse()?,
block_token: input.parse()?,
name: input.call(Ident::parse_any)?,
})
}
}
impl Parse for IfTempl {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
if_token: input.parse()?,
cond: Rc::new(input.parse()?),
})
}
}
impl Parse for ElseTempl {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
else_token: input.parse()?,
elif_branch: if input.peek(Token![if]) {
Some((input.parse()?,Rc::new(input.parse()?)))
} else {
None
},
})
}
}
impl Parse for ForTempl {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
for_token: input.parse()?,
pat: Rc::new(Pat::parse_multi_with_leading_vert(input)?),
in_token: input.parse()?,
expr: Rc::new(input.parse()?),
})
}
}
impl Parse for ItemTempl {
fn parse(input: ParseStream) -> Result<Self> {
let look = input.lookahead1();
match () {
_ if look.peek(Token![use]) => input.parse().map(Self::Use),
_ if look.peek(Token![const]) => input.parse().map(Self::Const),
_ => Err(look.error()),
}
}
}
mod kw {
syn::custom_keyword!(layout);
syn::custom_keyword!(extends);
syn::custom_keyword!(block);
syn::custom_keyword!(render);
syn::custom_keyword!(endblock);
syn::custom_keyword!(endif);
syn::custom_keyword!(endfor);
}