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 })
    }
}