use crate::ast::{Arm, Attribute, Block, Element, ForLoop, If, Let, Match, Node, Template};
use syn::{
Expr, ExprLit, Ident, Lit, LitStr, Pat, PatType, Token, Type, braced, parenthesized,
parse::{self, Parse},
token,
};
impl Parse for Template {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut nodes = Vec::new();
while !input.is_empty() {
nodes.push(Node::parse(input)?);
}
Ok(Self { nodes })
}
}
impl Parse for Node {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
if input.peek(Token![if]) {
If::parse(input).map(Self::If)
} else if input.peek(Token![match]) {
Match::parse(input).map(Self::Match)
} else if input.peek(Token![for]) {
ForLoop::parse(input).map(Self::ForLoop)
} else if input.peek(Token![let]) {
Let::parse(input).map(Self::Let)
} else if input.peek(token::Paren) {
let content;
parenthesized!(content in input);
Expr::parse(&content).map(Self::Expr)
} else if input.peek(token::Brace) {
Block::parse(input).map(Self::Block)
} else if let Ok(s) = input.parse::<LitStr>() {
Ok(Self::Expr(Expr::Lit(ExprLit {
attrs: Vec::new(),
lit: Lit::Str(s),
})))
} else {
Element::parse(input).map(Self::Element)
}
}
}
impl Parse for Element {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let name = Ident::parse(input)?;
let mut attr_list = Vec::new();
while input.peek(Ident) || input.peek(Token![@]) || input.peek(Token![.]) {
attr_list.push(Attribute::parse(input)?);
}
let body = if input.peek(Token![;]) {
<Token![;]>::parse(input)?;
None
} else if input.peek(token::Brace) {
Some(Block::parse(input)?)
} else {
Err(input.error("expected curly braces or SEMICOLON"))?
};
Ok(Self {
name,
attr_list,
body,
})
}
}
impl Parse for Attribute {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
if <Token![@]>::parse(input).is_ok() {
let id = parse_attribute_value(input)?;
Ok(Self::Id(id))
} else if <Token![.]>::parse(input).is_ok() {
let class = parse_attribute_value(input)?;
Ok(Self::Class(class))
} else if let Ok(key) = Ident::parse(input) {
let value = if <Token![:]>::parse(input).is_ok() {
Some(parse_attribute_value(input)?)
} else {
None
};
Ok(Self::KeyValue { key, value })
} else {
Err(syn::Error::new(input.span(), "todo"))
}
}
}
impl Parse for Block {
fn parse(input: parse::ParseStream) -> syn::Result<Self> {
let content;
braced!(content in input);
let mut nodes = Vec::new();
while !content.is_empty() {
nodes.push(Node::parse(&content)?);
}
Ok(Self { nodes })
}
}
impl Parse for If {
fn parse(input: parse::ParseStream) -> syn::Result<Self> {
<Token![if]>::parse(input)?;
let cond = Expr::parse_without_eager_brace(input)?;
let then_branch = Block::parse(input)?;
let else_branch = if <Token![else]>::parse(input).is_ok() {
if input.peek(Token![if]) {
Some(Box::new(Node::If(Self::parse(input)?)))
} else {
Some(Box::new(Node::Block(Block::parse(input)?)))
}
} else {
None
};
Ok(Self {
cond,
then_branch,
else_branch,
})
}
}
impl Parse for Match {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
input.parse::<Token![match]>()?;
let expr = Expr::parse_without_eager_brace(input)?;
let content;
braced!(content in input);
let mut arms = Vec::new();
while !content.is_empty() {
arms.push(Arm::parse(&content)?);
}
Ok(Self { expr, arms })
}
}
impl Parse for Arm {
fn parse(input: parse::ParseStream) -> syn::Result<Self> {
let pat = Pat::parse_multi_with_leading_vert(input)?;
let guard = input
.parse::<Token![if]>()
.map(|_| Expr::parse(input))
.ok()
.transpose()?;
<Token![=>]>::parse(input)?;
let body = Node::parse(input)?;
if body.ends_with_eager_brace() || input.is_empty() {
_ = <Token![,]>::parse(input)
} else {
<Token![,]>::parse(input)?;
}
Ok(Self { pat, guard, body })
}
}
impl Parse for ForLoop {
fn parse(input: parse::ParseStream) -> syn::Result<Self> {
<Token![for]>::parse(input)?;
let pat = Pat::parse_multi_with_leading_vert(input)?;
<Token![in]>::parse(input)?;
let expr = Expr::parse_without_eager_brace(input)?;
let body = Block::parse(input)?;
Ok(Self { pat, expr, body })
}
}
impl Parse for Let {
fn parse(input: parse::ParseStream) -> syn::Result<Self> {
<Token![let]>::parse(input)?;
let mut pat = Pat::parse_single(input)?;
if input.peek(Token![:]) {
let colon_token = <Token![:]>::parse(input)?;
let ty = Type::parse(input)?;
pat = Pat::Type(PatType {
attrs: Vec::new(),
pat: Box::new(pat),
colon_token,
ty: Box::new(ty),
});
}
<Token![=]>::parse(input)?;
let expr = Expr::parse(input)?;
<Token![;]>::parse(input)?;
Ok(Self { pat, expr })
}
}
fn parse_attribute_value(input: syn::parse::ParseStream) -> syn::Result<Expr> {
<LitStr as Parse>::parse(input)
.map(|s| {
Expr::Lit(ExprLit {
attrs: Vec::new(),
lit: Lit::Str(s),
})
})
.or_else(|_| {
let content;
parenthesized!(content in input);
Expr::parse(&content)
})
}