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
use nodes::{ Parser, Parse }; use nodes::body::Body; use nodes::expr::Expr; use tokens::{ TokenRef, TokenValueRef }; use Expect; use error::{ TemplateResult, TemplateError }; impl<'c> Parse<'c> for Body<'c> { type Output = Body<'c>; fn parse<'r>(parser: &mut Parser<'r, 'c>) -> TemplateResult<Body<'c>> { trace!("Body::parse"); subparse(parser, |_| None) } } pub struct BlockEnd { pub drop_needle: bool, } pub fn subparse<'p, 'c, D>(parser: &mut Parser<'p, 'c>, test: D) -> TemplateResult<Body<'c>> where D: Fn(&TokenRef<'c>) -> Option<BlockEnd> { let mut maybe_line = None; let mut rv = Vec::new(); while let Some(token) = try!(parser.maybe_current()) { if let None = maybe_line { maybe_line = Some(token.line); } match token.value { TokenValueRef::Text(t) => { try!(parser.next()); rv.push(Body::Text { value: t, line: token.line }) }, TokenValueRef::VarStart => { try!(parser.next()); let expr = try!(Expr::parse(parser)); try!(parser.expect(TokenValueRef::VarEnd)); rv.push(Body::Print { expr: Box::new(expr), line: token.line }); }, TokenValueRef::BlockStart => { try!(parser.next()); let token = try!(parser.current()); let tag_name = match token.value { TokenValueRef::Name(n) => n, _ => return Err(TemplateError::MustStartWithTagName.at(token.line)), }; if let Some(end) = test(&token) { if end.drop_needle { try!(parser.next()); } return if 1 == rv.len() { Ok(rv.remove(0)) } else { Ok(Body::List { items: rv }) } } let subparser = match parser.env.handlers.get(tag_name) { Some(sp) => sp, None => { unreachable!("errors when subparser not found not implemented") } }; try!(parser.next()); let maybe_node = try!(subparser.parse(parser, token)); if let Some(node) = maybe_node { rv.push(node); } }, tv => { panic!("not implemented {:?}", tv) }, }; } if rv.len() == 1 { Ok(rv.remove(0)) } else { Ok(Body::List { items: rv }) } }