1use super::config::ConfigBlock;
2use super::error::{CodePosition, Error, ErrorType, Result};
3use super::lexer;
4use super::lexer::{Token, TokenType};
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<dyn Iterator<Item = lexer::Token>>,
24 last_token: Option<Token>,
25 force_next: Option<Token>,
26 done: bool,
27}
28
29impl CodePosition 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<dyn 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(
50 state: &mut ParseState,
51 inner: bool,
52 name: String,
53 options: Vec<String>,
54) -> Result<ConfigBlock> {
55 let mut return_value = ConfigBlock::new(name, options, vec![]);
56 loop {
57 let token = if inner {
58 expect_token!(state)
59 } else {
60 match next(state) {
61 Some(t) => t,
62 None => return Ok(return_value),
63 }
64 };
65 match token.clone().token_type {
66 TokenType::RawLiteral(option_name) => {
67 let params = parse_params(state)?;
68 let t = expect_token!(state);
69 match t.token_type {
70 TokenType::OpenBrace => {
71 return_value.add_block(parse_block(state, true, option_name, params)?);
73 }
74 _ => {
75 return_value.add_block(ConfigBlock::new(option_name, params, vec![]))
79 }
80 }
81 }
82 TokenType::CloseBrace if inner => break,
83 TokenType::Semicolon => {}
84 _ => {
85 return fail(
86 state,
87 ErrorType::Unexpected(token.clone()),
88 if inner { "option or }" } else { "option" },
89 )
90 }
91 }
92 }
93 Ok(return_value)
94}
95
96fn parse_params(state: &mut ParseState) -> Result<Vec<String>> {
97 let mut return_value = vec![];
98 loop {
99 match lookahead(state) {
100 Some(t) => match t.token_type {
101 TokenType::StringLiteral(s) => {
102 return_value.push(s);
103 pop(state);
104 }
105 TokenType::RawLiteral(s) => {
106 return_value.push(s);
107 pop(state);
108 }
109 TokenType::OpenBrace => break,
110 TokenType::Semicolon => break,
111 TokenType::LineEnd => break,
112 TokenType::Colon => {
113 pop(state);
114 }
115 _ => {
116 if cfg!(feature = "nonstrict") {
117 break;
118 } else {
119 println!("Errored params");
120 return fail(state, ErrorType::Unexpected(t), "; or {");
121 }
122 }
123 },
124 None => return fail(&state, ErrorType::UnexpectedEOF, "}"),
125 }
126 }
127 Ok(return_value)
128}
129
130fn next(state: &mut ParseState) -> Option<lexer::Token> {
131 let v = match &state.force_next {
132 &Some(ref t) => Some(t.clone()),
133 &None => state.tokens.next(),
134 };
135 state.force_next = None;
136 match v.clone() {
137 Some(_) => {}
138 None => {
139 if state.done {
140 unreachable!("Tried to get another token after end of stream");
141 } else {
142 state.done = true;
143 }
144 }
145 }
146 v
147}
148
149fn pop(state: &mut ParseState) {
150 if state.force_next.is_some() {
151 state.force_next = None;
152 } else {
153 state.tokens.next();
154 }
155}
156
157fn lookahead(state: &mut ParseState) -> Option<lexer::Token> {
158 match state.force_next.clone() {
159 Some(t) => Some(t),
160 None => {
161 let t = state.tokens.next();
162 state.force_next = t.clone();
163 t
164 }
165 }
166}
167
168fn fail<T>(state: &ParseState, error_type: ErrorType, expected: &'static str) -> Result<T> {
169 Err(Error::from_state(state, error_type, Some(expected)))
170}
171
172#[cfg(test)]
173mod test {
174 use super::super::config::ConfigBlock;
175 use super::super::lexer::{Token, TokenType};
176 use super::*;
177
178 #[test]
179 fn test_it_parsing_the_most_basic_option() {
180 assert_eq!(
181 run(Box::new(
182 vec![
183 tok(TokenType::RawLiteral(String::from("test"))),
184 tok(TokenType::Semicolon)
185 ]
186 .into_iter()
187 )),
188 Ok(ConfigBlock::new(
189 String::new(),
190 vec![],
191 vec![ConfigBlock::new(String::from("test"), vec![], vec![])]
192 ))
193 );
194 }
195
196 #[test]
197 fn test_it_parsing_a_typical_example() {
198 assert_eq!(
199 run(Box::new(
200 vec![
201 tok(TokenType::RawLiteral(String::from("option"))),
202 tok(TokenType::RawLiteral(String::from("param1"))),
203 tok(TokenType::OpenBrace),
204 tok(TokenType::RawLiteral(String::from("inner"))),
205 tok(TokenType::StringLiteral(String::from("value"))),
206 tok(TokenType::Semicolon),
207 tok(TokenType::CloseBrace),
208 ]
209 .into_iter()
210 )),
211 Ok(ConfigBlock::new(
212 String::new(),
213 vec![],
214 vec![ConfigBlock::new(
215 String::from("option"),
216 vec![String::from("param1")],
217 vec![ConfigBlock::new(
218 String::from("inner"),
219 vec![String::from("value")],
220 vec![]
221 )]
222 )]
223 ))
224 );
225 }
226
227 fn tok(ty: TokenType) -> Token {
228 Token::new(0, 0, ty)
229 }
230}