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
use std::borrow::Cow;

use abc::*;
use {Args, Arg, Incrust, Template};


pub type TemplateStack<'a> = Vec<&'a Template>;


pub struct GlobalContext<'a> {
    env: &'a Incrust,
    stack: Vec<Cow<'a, Template>>,
    args: &'a Args<'a>,
}


pub struct Context<'a> {
    global: &'a GlobalContext<'a>,
    parent: Option<&'a Context<'a>>,
    args: &'a Args<'a>,
}


impl <'a> GlobalContext<'a> {
    pub fn new(env: &'a Incrust, template: &'a Template, args: &'a Args<'a>) -> RenderResult<Self> {
        use ::renderer::evaluator::eval_expr;

        let mut context = GlobalContext {
            env: env,
            stack: vec![Cow::Borrowed(template)],
            args: args,
        };

        loop {
            if let Some(parent) = context.template().extends.clone() {
                let template = {
                    let local = context.top_scope();
                    let name = eval_expr(&local, &parent.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()))?;
                    Cow::Owned(env.parse(&env.load(&name)?)?)
                };
                context.stack.push(template);
            } else {
                break;
            }
        }

        Ok(context)
    }

    pub fn top_scope(&'a self) -> Context<'a> {
         Context::new(self, self.args)
    }

    pub fn template(&'a self) -> &'a Template {
        self.stack.last().unwrap()
    }

    pub fn stack(&'a self) -> &'a [Cow<'a, Template>] {
        &self.stack
    }

    pub fn env(&self) -> &'a Incrust {
        self.env
    }
}


impl <'a> Context<'a> {
    pub fn new(global: &'a GlobalContext<'a>, args: &'a Args<'a>) -> Self {
        Context {
            global: global,
            parent: None,
            args: args
        }
    }

    pub fn nested_scope(&'a self, args: &'a Args<'a>) -> Self {
        Context {
            global: self.global,
            parent: Some(self),
            args: args
        }
    }

    pub fn template(&self) -> &'a Template {
        self.global.template()
    }

    pub fn global(&self) -> &'a GlobalContext<'a> {
        self.global
    }

    pub fn env(&self) -> &'a Incrust {
        self.global.env()
    }

    pub fn get(&'a self, id: &str) -> Option<Arg<'a>> {
        self.args.get(id).map(Arg::from)
            .or_else(|| self.parent
                .and_then(|p| p.get(id))
                .or_else(|| self.global.env().top_context().get(id).map(Arg::from))
            )
    }
}