use syn::{parse::{Parse, ParseStream}, ext::IdentExt, token::{Paren, Brace}};
use crate::*;
impl Parse for CSS {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut rules = Vec::new();
while !input.is_empty() {
rules.push(input.parse()?);
}
Ok(Self(rules))
}
}
impl Parse for Rule {
fn parse(input: ParseStream) -> syn::Result<Self> {
let selector = input.parse()?;
let group: Group = input.parse()?;
let declarations = syn::parse2(group.stream())?;
Ok(Self {
selector,
group,
declarations,
})
}
}
fn selector_simple(input: ParseStream) -> syn::Result<Selector> {
let look = input.lookahead1();
if look.peek(Token![:]) {
let colon = input.parse()?;
let ident = input.parse()?;
let arg = if input.peek(Paren) {
let group: Group = input.parse()?;
let arg = syn::parse2(group.stream())?;
Some((group, arg))
} else {
None
};
Ok(Selector::Colon {
colon,
ident,
arg,
})
} else if look.peek(Token![*]) {
input.parse().map(Selector::Any)
} else if look.peek(Ident::peek_any) || look.peek(Token![.]) || look.peek(Token![#]) {
let ident = if input.peek(Ident::peek_any) { Some(input.parse()?) } else { None };
let class = if input.peek(Token![.]) {
Some((input.parse()?, input.parse()?))
} else {
None
};
let id = if input.peek(Token![#]) {
Some((input.parse()?, input.parse()?))
} else {
None
};
if let (&None, &None, &None) = (&ident, &class, &id) {
todo!("Error");
}
Ok(Selector::Simple {
ident,
class,
id,
})
} else {
Err(look.error())
}
}
fn selector_sub(input: ParseStream) -> syn::Result<Selector> {
let mut left = selector_simple(input)?;
while input.peek(Ident::peek_any) || input.peek(Token![.]) || input.peek(Token![#]) || input.peek(Token![:]) {
left = Selector::Sub {
left: Box::new(left),
right: Box::new(selector_simple(input)?),
};
}
Ok(left)
}
fn selector_plus(input: ParseStream) -> syn::Result<Selector> {
let mut left = selector_sub(input)?;
while input.peek(Token![+]) {
left = Selector::Plus {
left: Box::new(left),
plus: input.parse()?,
right: Box::new(selector_sub(input)?),
};
}
Ok(left)
}
fn selector_comma(input: ParseStream) -> syn::Result<Selector> {
let mut left = selector_plus(input)?;
while input.peek(Token![,]) {
left = Selector::Comma {
left: Box::new(left),
comma: input.parse()?,
right: Box::new(selector_plus(input)?),
};
}
Ok(left)
}
impl Parse for Selector {
fn parse(input: ParseStream) -> syn::Result<Self> {
selector_comma(input)
}
}
impl Parse for Declarations {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut decls = Vec::new();
while !input.is_empty() {
decls.push(input.parse()?);
}
Ok(Self(decls))
}
}
impl Parse for Declaration {
fn parse(input: ParseStream) -> syn::Result<Self> {
let ident = input.parse()?;
let colon = input.parse()?;
let mut value = vec![input.parse()?];
while !input.peek(Token![;]) {
value.push(input.parse()?);
}
Ok(Self {
ident,
colon,
value,
semicolon: input.parse()?,
})
}
}
impl Parse for Value {
fn parse(input: ParseStream) -> syn::Result<Self> {
let look = input.lookahead1();
if look.peek(Token![#]) {
Ok(Self::ColorCode {
pound: input.parse()?,
value: input.parse()?,
})
} else if look.peek(LitInt) {
let int = input.parse()?;
if input.peek(Token![%]) {
Ok(Self::IntPerc(int, input.parse()?))
} else {
Ok(Self::Int(int))
}
} else if look.peek(LitFloat) {
let f = input.parse()?;
if input.peek(Token![%]) {
Ok(Self::FloatPerc(f, input.parse()?))
} else {
Ok(Self::Float(f))
}
} else if look.peek(Ident::peek_any) || look.peek(Token![-]) {
let ident = input.parse()?;
if input.peek(Paren) {
let group: Group = input.parse()?;
let args = syn::parse2(group.stream())?;
Ok(Self::Function { ident, group, args })
} else {
Ok(Self::Ident(ident))
}
} else if look.peek(Brace) {
input.parse().map(Self::Block)
} else {
Err(look.error())
}
}
}
impl Parse for Args {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut values = vec![input.parse()?];
while input.peek(Token![,]) {
input.parse::<Token![,]>()?;
values.push(input.parse()?);
}
Ok(Self(values))
}
}
impl Parse for CSSIdent {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut segments = Vec::new();
while input.peek(Token![-]) {
segments.push(CSSIdentSegment::Minus(input.parse()?));
}
segments.push(CSSIdentSegment::Ident(Ident::parse_any(input)?));
while input.peek(Token![-]) {
while input.peek(Token![-]) {
segments.push(CSSIdentSegment::Minus(input.parse()?));
}
segments.push(CSSIdentSegment::Ident(Ident::parse_any(input)?));
}
Ok(Self(segments))
}
}