use std::ops::{Deref, DerefMut};
use cssparser::{ParserInput, Token};
use less_allocator::Vec;
use super::variable::VariableReference;
use crate::{
printer::{Printer, PrinterError},
properties::resolve_and_evaluate_variable,
rules::variable::VariableValue,
};
#[derive(Debug, Clone)]
pub enum TokenOrVariable<'i> {
Token(Token<'i>),
Variable(VariableReference<'i>),
}
#[derive(Debug)]
pub struct TokenList<'i>(Vec<'i, TokenOrVariable<'i>>);
impl<'i> Deref for TokenList<'i> {
type Target = Vec<'i, TokenOrVariable<'i>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'i> DerefMut for TokenList<'i> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'i> TokenList<'i> {
pub fn parse_raw_until_before(
allocator: &'i less_allocator::Allocator,
input: &'i str,
delimiter: cssparser::Delimiters,
) -> Result<Self, cssparser::ParseError<'i, crate::error::ParserError<'i>>> {
let mut input = ParserInput::new(input);
let mut parser = cssparser::Parser::new(&mut input);
Self::parse_until_before(allocator, &mut parser, delimiter)
}
pub fn parse_until_before(
allocator: &'i less_allocator::Allocator,
input: &mut cssparser::Parser<'i, '_>,
delimiter: cssparser::Delimiters,
) -> Result<Self, cssparser::ParseError<'i, crate::error::ParserError<'i>>> {
let mut tokens = Vec::new_in(allocator);
input.parse_until_before(delimiter, |input| {
loop {
match input.next() {
Ok(Token::AtKeyword(v)) => {
tokens.push(TokenOrVariable::Variable(VariableReference(v.clone())))
}
Ok(t @ Token::Function(_)) => {
tokens.push(TokenOrVariable::Token(t.clone()));
input.parse_nested_block(|input| {
let token = Self::parse_until_before(allocator, input, delimiter)?;
tokens.extend(token.0.into_iter());
Ok(())
})?;
tokens.push(TokenOrVariable::Token(Token::CloseParenthesis));
}
Ok(t) => tokens.push(TokenOrVariable::Token(t.clone())),
Err(cssparser::BasicParseError {
kind: cssparser::BasicParseErrorKind::EndOfInput,
..
}) => return Ok(()),
Err(_) => unreachable!(),
}
}
})?;
Ok(Self(tokens))
}
pub fn evaluate<W: std::fmt::Write>(
&self,
dest: &mut Printer<'_, 'i, W>,
) -> Result<EvaluatedTokens<'i>, PrinterError<'i>> {
let mut evaluated_tokens: Vec<Token<'i>> = Vec::new_in(dest.allocator);
for token in self.0.iter() {
match token {
TokenOrVariable::Token(token) => evaluated_tokens.push(token.clone()),
TokenOrVariable::Variable(var) => {
let variable = resolve_and_evaluate_variable(var, dest)?;
let evaluted = match &*variable.value.borrow() {
VariableValue::Unparsed(_) => unreachable!(),
VariableValue::Parsed(token_list) => token_list.evaluate(dest)?,
};
variable.evaluating.set(false);
evaluated_tokens.extend(evaluted.0);
}
}
}
Ok(EvaluatedTokens(evaluated_tokens))
}
}
#[derive(Debug)]
pub struct EvaluatedTokens<'i>(Vec<'i, Token<'i>>);
impl<'i> Deref for EvaluatedTokens<'i> {
type Target = Vec<'i, Token<'i>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}