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 ret.add_block(try!(parse_block(state, true, option_name, params)));
68 },
69 _ => {
70 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}