moduforge-rules-template 0.5.0

moduforge 模板规则
Documentation
use std::iter::Peekable;
use std::rc::Rc;
use std::slice::Iter;

use crate::error::TemplateRenderError;
use crate::parser::Node;
use mf_expression::variable::Variable;
use mf_expression::Isolate;

#[derive(Debug, PartialEq)]
pub(crate) enum InterpreterResult<'a> {
    String(&'a str),
    Variable(Variable),
}

#[derive(Debug)]
pub(crate) struct Interpreter<'source, 'nodes> {
    cursor: Peekable<Iter<'nodes, Node<'source>>>,
    isolate: Isolate<'source>,
    results: Vec<InterpreterResult<'source>>,
}

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

        Self { cursor, isolate: Isolate::new(), results: Default::default() }
    }
}

impl<'source, 'nodes> Interpreter<'source, 'nodes> {
    pub(crate) fn collect_for(
        mut self,
        context: Variable,
    ) -> Result<Variable, TemplateRenderError> {
        self.isolate.set_environment(context);

        while let Some(node) = self.cursor.next() {
            match node {
                Node::Text(data) => self.text(data),
                Node::Expression(data) => self.expression(data)?,
            }
        }

        match self.results.len() {
            0 => Ok(Variable::Null),
            1 => {
                let item = self.results.remove(0);
                match item {
                    InterpreterResult::Variable(val) => Ok(val),
                    InterpreterResult::String(str) => {
                        Ok(Variable::String(Rc::from(str)))
                    },
                }
            },
            _ => {
                let string_data = self
                    .results
                    .into_iter()
                    .map(|item| match item {
                        InterpreterResult::String(str) => str.to_string(),
                        InterpreterResult::Variable(value) => {
                            var_to_string(value)
                        },
                    })
                    .collect::<String>();

                Ok(Variable::String(Rc::from(string_data.as_str())))
            },
        }
    }

    fn text(
        &mut self,
        data: &'source str,
    ) {
        self.results.push(InterpreterResult::String(data));
    }

    fn expression(
        &mut self,
        data: &'source str,
    ) -> Result<(), TemplateRenderError> {
        let result = self.isolate.run_standard(data)?;
        self.results.push(InterpreterResult::Variable(result));
        Ok(())
    }
}

fn var_to_string(var: Variable) -> String {
    match var {
        Variable::String(s) => s.to_string(),
        _ => var.to_string(),
    }
}