1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::fmt;

use abc::*;
use incrust::Context;
use types::abc::Writer;
use container::expression::*;
use container::template::*;

use super::evaluator::eval_expr;


pub fn text<'a>(context: &'a Context) -> RenderResult<String> {
    let mut buffer: String = Default::default();
    render_text(&mut buffer, context, context.template().root.as_slice())?;
    Ok(buffer)
}


pub fn render_text<'a, W: fmt::Write>(writer: &mut W, context: &'a Context, nodes: &'a[Node]) -> RenderResult<()> {
    for x in nodes {
        match *x {
            Node::Text(ref txt) => write!(writer, "{}", txt)?,
            Node::Mustache(ref mus) => render_mustache(writer, context, mus)?,
            Node::For(ref stmt) => render_for(writer, context, stmt)?,
            Node::If(ref stmt) => render_if(writer, context, stmt)?,
            Node::Block(ref stmt) => render_block(writer, context, stmt)?,
            Node::Include(ref expr) => render_include(writer, context, expr)?,
        }
    }
    Ok(())
}


pub fn render_mustache<W: fmt::Write>(writer: &mut W, context: &Context, mus: &Mustache) -> RenderResult<()> {
    render_expression(writer, context, &mus.expr)
}


pub fn render_expression<W: fmt::Write>(writer: &mut W, context: &Context, expr: &FullExpression) -> RenderResult<()> {
    let mut acc = eval_expr(context, &expr.expr)?;
    for filter in expr.filters.iter() {
        acc = match *filter {
            FilterItem::Simple(ref id) => context.env().filter(id, context, acc)?,
        };
    }
    match acc {
        None => write!(writer, "#None")?,
        Some(acc) => acc.as_ref().render(&mut Writer(writer))?,
    }
    Ok(())
}


pub fn render_for<W: fmt::Write>(writer: &mut W, context: &Context, stmt: &ForStatement) -> RenderResult<()> {
    #![cfg_attr(feature = "clippy", allow(used_underscore_binding))]

    // FIXME implement instead: expression(&stmt.begin.expression, context)
    if let Some(value) = eval_expr(context, &stmt.expression.expr)? {
        if let Some(iterable) = value.try_as_iterable() {
            for (index, v) in iterable.ivalues().enumerate() {
                let local_scope: Args = hashmap! {
                    stmt.value_var.as_str().into() => v,
                    "index0".into() => ex(index as i64),
                    "index".into() => ex(index as i64 + 1),
                    "first".into() => ex(index == 0),
                    "last".into() => ex(false), // TODO the "last" marker in a loop
                };
                render_text(writer, &context.nested_scope(&local_scope), &stmt.block)?;
            }
        }
    };
    Ok(())
}


pub fn render_if<W: fmt::Write>(writer: &mut W, context: &Context, stmt: &IfStatement) -> RenderResult<()> {
    for branch in &stmt.if_branches {
        // FIXME implement instead: expression(&branch.begin.expression, context)
        if let Some(res) = eval_expr(context, &branch.expr.expr)? {
            if res.to_bool() {
                render_text(writer, context, &branch.block)?;
                return Ok(());
            }
        }
    }
    if let Some(ref branch) = stmt.else_branch {
        render_text(writer, context, &branch)?;
    }
    Ok(())
}


pub fn render_block<W: fmt::Write>(writer: &mut W, context: &Context, name: &str) -> RenderResult<()> {
    for template in context.global().stack() {
        match template.blocks.get(name) {
            Some(block) => {
                render_text(writer, context, &block)?;
                break;
            },
            None => {},
        };
    }
    Ok(())
}


pub fn render_include<W: fmt::Write>(writer: &mut W, context: &Context, expr: &FullExpression) -> RenderResult<()> {
    let name = eval_expr(context, &expr.expr)?
        .ok_or(LoadError::BadName("Can't evaluate name (None result)".into()))?;
    let name = name.try_as_string()
        .ok_or(LoadError::BadName("Name is not string".into()))?;
    let args = Args::default();
    let env = context.global().env();
    let template = env.parse(&env.load(&name)?)?;
    let global = env.create_global_context(&template, &args)?;
    render_text(writer, &global.top_scope(), template.root.as_slice())
}