zen-tmpl 0.54.0

Zen Template Language
Documentation
use crate::error::{ParserError, TemplateRenderError};
use crate::lexer::Token;
use std::iter::Peekable;
use std::slice::Iter;

#[derive(Debug, PartialOrd, PartialEq)]
pub(crate) enum Node<'a> {
    Text(&'a str),
    Expression(&'a str),
}

#[derive(Debug, PartialOrd, PartialEq)]
enum ParserState {
    Text,
    Expression,
}

pub(crate) struct Parser<'source, 'tokens> {
    cursor: Peekable<Iter<'tokens, Token<'source>>>,
    state: ParserState,
    nodes: Vec<Node<'source>>,
}

impl<'source, 'tokens, T> From<T> for Parser<'source, 'tokens>
where
    T: Into<&'tokens [Token<'source>]>,
{
    fn from(value: T) -> Self {
        let tokens = value.into();
        let cursor = tokens.iter().peekable();

        Self {
            cursor,
            nodes: Default::default(),
            state: ParserState::Text,
        }
    }
}

impl<'source, 'tokens> Parser<'source, 'tokens> {
    pub(crate) fn collect(mut self) -> Result<Vec<Node<'source>>, TemplateRenderError> {
        while let Some(token) = self.cursor.next() {
            match token {
                Token::Text(text) => self.text(text),
                Token::OpenBracket => self.open_bracket()?,
                Token::CloseBracket => self.close_bracket()?,
            }
        }

        Ok(self.nodes)
    }

    fn text(&mut self, data: &'source str) {
        match self.state {
            ParserState::Text => self.nodes.push(Node::Text(data)),
            ParserState::Expression => self.nodes.push(Node::Expression(data)),
        }
    }

    fn open_bracket(&mut self) -> Result<(), ParserError> {
        if self.state == ParserState::Expression {
            return Err(ParserError::OpenBracket);
        }

        self.state = ParserState::Expression;
        Ok(())
    }

    fn close_bracket(&mut self) -> Result<(), ParserError> {
        if self.state != ParserState::Expression {
            return Err(ParserError::CloseBracket);
        }

        self.state = ParserState::Text;
        Ok(())
    }
}