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 118 119 120 121 122 123 124 125 126 127 128 129 130
use std::borrow::Cow; use abc::*; use incrust::Incrust; use container::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>, } pub enum ParentScope<'a> { Global(&'a GlobalContext<'a>), Local(&'a Context<'a>), } impl <'a> From<&'a GlobalContext<'a>> for ParentScope<'a> { fn from(x: &'a GlobalContext<'a>) -> Self { ParentScope::Global(x) } } impl <'a> From<&'a Context<'a>> for ParentScope<'a> { fn from(x: &'a Context<'a>) -> Self { ParentScope::Local(x) } } 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().as_ref().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<PS: Into<ParentScope<'a>>>(parent_scope: PS, args: &'a Args<'a>) -> Self { let (global, parent) = match parent_scope.into() { ParentScope::Global(global) => (global, None), ParentScope::Local(local) => (local.global(), Some(local)), }; Context { global: global, parent: parent, 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(&self, id: &str) -> Option<&BType> { self.args.get(id) .or_else(|| self.parent .and_then(|p| p.get(id)) .or_else(|| self.global.env().top_context().get(id)) ) } }