config_parser/
parser.rs

1use super::lexer;
2use super::lexer::{TokenType, Token};
3use super::config::ConfigBlock;
4use super::error::{Result, ErrorType, Error, CodePos};
5
6macro_rules! expect_token {
7    ($state:expr) => {
8        match next($state) {
9            Some(t) => t,
10            None => return fail($state, ErrorType::UnexpectedEOF, "token")
11        }
12    };
13    ($state:expr, $ty:expr) => {
14        match next($state) {
15            Some(Token {token_type: $ty(..), ..} @ t) => t,
16            Some(t) => return fail($state, ErrorType::Unexpected(t), stringify!($ty)) 
17            None => return fail($state, ErrorType::UnexpectedEOF, stringify!($ty))
18        }
19    }
20}
21
22struct ParseState {
23    tokens: Box<Iterator<Item=lexer::Token>>,
24    last_token: Option<Token>,
25    force_next: Option<Token>,
26    done: bool
27}
28
29impl CodePos for ParseState {
30    fn location(&self) -> (u32, u16) {
31        match self.last_token {
32            Some(ref t) => (t.line, t.col),
33            None => (0, 0)
34        }
35    }
36}
37
38pub fn run(tokens: Box<Iterator<Item=lexer::Token>>) -> Result<ConfigBlock> {
39    let mut state = ParseState {
40        tokens: tokens,
41        last_token: None,
42        force_next: None,
43        done: false
44    };
45
46    parse_block(&mut state, false, String::from(""), vec![])
47}
48
49fn parse_block(state: &mut ParseState, inner: bool, name: String, options: Vec<String>) -> Result<ConfigBlock> {
50    let mut ret = ConfigBlock::new(name, options, vec![]);
51    loop {
52        let tok = if inner {
53            expect_token!(state)
54        } else {
55            match next(state) {
56                Some(t) => t,
57                None => return Ok(ret)
58            }
59        };
60        match tok.clone().token_type {
61            TokenType::RawLiteral(option_name) => {
62                let params = try!(parse_params(state));
63                let t = expect_token!(state);
64                match t.token_type {
65                    TokenType::OpenBrace => {
66                        // Block follows
67                        ret.add_block(try!(parse_block(state, true, option_name, params)));
68                    },
69                    _ => {
70                        // No block. In strict mode this will only ever execute for 
71                        // TokenType::Semicolon as parse_params() will already have
72                        // returned an error for other types
73                        ret.add_block(ConfigBlock::new(option_name, params, vec![]))
74                    }
75                }
76            },
77            TokenType::CloseBrace if inner => break,
78            TokenType::Semicolon => {}
79            _ => return fail(state, ErrorType::Unexpected(tok.clone()), if inner { "option or }" } else { "option" })
80        }
81    }
82    Ok(ret)
83}
84
85fn parse_params(state: &mut ParseState) -> Result<Vec<String>> {
86    let mut ret = vec![];
87    println!("Parsing params");
88    loop {
89        let opt_t = lookahead(state);
90        match opt_t {
91            Some(t) => {
92                match t.token_type {
93                    TokenType::StringLiteral(s) => {
94                        ret.push(s);
95                        pop(state);
96                    },
97                    TokenType::RawLiteral(s) => {
98                        ret.push(s);
99                        pop(state);
100                    },
101                    TokenType::OpenBrace => break,
102                    TokenType::Semicolon => break,
103                    _ => {
104                        if cfg!(feature = "nonstrict") {
105                            break;
106                        } else {
107                            println!("Errored params");
108                            return fail(state, ErrorType::Unexpected(t), "; or {") 
109                        }
110                    }
111                }
112            },
113            None => return fail(&state, ErrorType::UnexpectedEOF, "}")
114        }
115    }
116    println!("Exited params");
117    Ok(ret)
118}
119
120fn next(state: &mut ParseState) -> Option<lexer::Token> {
121    let v = match &state.force_next {
122        &Some(ref t) => Some(t.clone()),
123        &None => state.tokens.next()
124    };
125    state.force_next = None;
126    println!("Token {:?}", &v);
127    match v.clone() {
128        Some(_) => {},
129        None => {
130            if state.done {
131                unreachable!("Tried to get another token after end of stream");
132            } else {
133                state.done = true;
134            }
135        }
136    }
137    v
138}
139
140fn pop(state: &mut ParseState) {
141    println!("popping...");
142    if state.force_next.is_some() {
143        state.force_next = None;
144    } else {
145        state.tokens.next();
146    }
147}
148
149fn lookahead(state: &mut ParseState) -> Option<lexer::Token> {
150    let r = match state.force_next.clone() {
151        Some(t) => Some(t),
152        None => {
153            let t = state.tokens.next();
154            state.force_next = t.clone();
155            t
156        }
157    };
158    println!("Lookahead Token {:?}", &r);
159    r
160}
161
162fn fail<T>(state: &ParseState, error_type: ErrorType, expected: &'static str) -> Result<T> {
163    Err(Error::from_state(state, error_type, Some(expected)))
164}
165
166#[cfg(test)]
167mod test {
168    use super::*;
169    use super::super::lexer::{Token, TokenType};
170    use super::super::config::ConfigBlock;
171
172    #[test] 
173    fn test_it_parsing_the_most_basic_option() {
174        assert_eq!(
175            run(Box::new(vec![
176                tok(TokenType::RawLiteral(String::from("test"))),
177                tok(TokenType::Semicolon)
178            ].into_iter())),
179                Ok(ConfigBlock::new(
180                    String::new(),
181                    vec![],
182                    vec![
183                        ConfigBlock::new(
184                            String::from("test"),
185                            vec![],
186                            vec![]
187                        )
188                    ]
189            )));
190    }
191
192    #[test]
193    fn test_it_parsing_a_typical_example() {
194        assert_eq!(
195            run(Box::new(vec![
196                tok(TokenType::RawLiteral(String::from("option"))),
197                tok(TokenType::RawLiteral(String::from("param1"))),
198                tok(TokenType::OpenBrace),
199                tok(TokenType::RawLiteral(String::from("inner"))),
200                tok(TokenType::StringLiteral(String::from("value"))),
201                tok(TokenType::Semicolon),
202                tok(TokenType::CloseBrace),
203            ].into_iter())),
204                Ok(ConfigBlock::new(
205                String::new(),
206                vec![],
207                vec![
208                    ConfigBlock::new(
209                        String::from("option"),
210                        vec![String::from("param1")],
211                        vec![
212                            ConfigBlock::new(
213                                String::from("inner"),
214                                vec![String::from("value")],
215                                vec![]
216                            )
217                        ]
218                    )
219                ]
220            )));
221    }
222
223    fn tok(ty: TokenType) -> Token {
224        Token::new(0, 0, ty)
225    }
226}