ream/
parser.rs

1use crate::error::*;
2use crate::object::*;
3use crate::scanner::*;
4
5use std::collections::{BTreeMap, HashMap, VecDeque};
6
7#[derive(Debug)]
8pub struct Parser<'source> {
9    pub scanner: Scanner<'source>,
10    pub current_level: usize,
11    pub class_history: Vec<String>,
12    pub schemas: HashMap<String, EntrySchema>,
13
14    upstream: HashMap<String, VariableMap>,
15    downstream: HashMap<String, Vec<VariableMap>>,
16    parse_direction: Direction,
17    ref_keys_buffer: Vec<String>,
18}
19
20#[derive(Debug, PartialEq, Eq)]
21enum Direction {
22    Down,
23    Up,
24}
25
26impl<'source> Parser<'source> {
27    pub fn new(source: &'source str) -> Self {
28        Parser {
29            scanner: Scanner::new(source),
30            current_level: 0,
31            class_history: vec!["_root_".to_string()],
32            schemas: HashMap::new(),
33
34            upstream: HashMap::new(),
35            downstream: HashMap::new(),
36            parse_direction: Direction::Down,
37            ref_keys_buffer: Vec::new(),
38        }
39    }
40
41    pub fn push_ref_key(&mut self, key: String) {
42        self.ref_keys_buffer.push(key);
43    }
44
45    pub fn get_schema(&self, class: String) -> Result<EntrySchema, ReamError> {
46        match self.schemas.get(&class) {
47            Some(v) => Ok((*v).clone()), // TODO: clone!
48            None => Err(ReamError::SchemaError(SchemaErrorType::IncorrectSchema)),
49        }
50    }
51
52    pub fn parent_class(&self) -> Option<String> {
53        let level = self.current_level;
54        match level {
55            1 => None,                                        // root node
56            _ => Some(self.class_history[level - 2].clone()), // TODO: clone!
57        }
58    }
59
60    pub fn push_class(&mut self, new_class: String) {
61        self.class_history.push(new_class);
62    }
63
64    pub fn pop_class(&mut self) {
65        self.class_history.pop();
66    }
67
68    // pub fn current_class(&self) -> &String {
69    //     match self.class_history.last() {
70    //         Some(c) => c,
71    //         None => unreachable!(),
72    //     }
73    // }
74
75    pub fn parse_header(&mut self) -> Result<usize, ReamError> {
76        let level = match self.scanner.take_token()? {
77            Some(Token(TokenType::Header(n), _, _)) => n,
78            _ => return Err(ReamError::ParseError(ParseErrorType::MissingHeaderLevel)),
79        };
80
81        Ok(level)
82    }
83
84    pub fn parse_identifier(&mut self) -> Result<String, ReamError> {
85        let identifier = match self.scanner.take_token()? {
86            Some(Token(TokenType::Class(c), _, _)) | Some(Token(TokenType::Key(c), _, _)) => c,
87            _ => return Err(ReamError::ParseError(ParseErrorType::MissingIdentifier)),
88        };
89
90        Ok(identifier)
91    }
92
93    pub fn parse_entry(&mut self) -> Result<Option<Entry>, ReamError> {
94
95        // find entry level
96        let level = self.parse_header()?;
97        self.current_level = level;
98
99        // find entry class
100        let class = self.parse_identifier()?;
101        self.push_class(class.clone()); // TODO: clone!
102
103        // init entry
104        let mut entry = Entry::new(class, level, self.parent_class());
105
106        // loop for variables
107        while let Some(Token(TokenType::Dash, _, _)) = self.scanner.peek_token()? {
108            self.scanner.take_token()?; // consume Dash
109            let (key, val) = self.parse_variable()?;
110            entry.push_key(key.clone());
111            entry.insert_variable(key, val)?;
112        }
113
114        // check schema
115        let mut entry = self.check_schema(entry)?;
116
117        // update upstream
118        self.upstream.insert(entry.class(), entry.variable_map());
119
120        // move unresolved ref keys from parser to entry
121        entry.set_ref_key(self.ref_keys_buffer.clone()); // TODO: clone!
122        self.ref_keys_buffer = Vec::new();
123
124        // loop for subentries
125        while let Some(Token(TokenType::Header(next_level), _, _)) = self.scanner.peek_token()? {
126            if next_level.to_owned() == self.current_level + 1 {
127                // child entry
128                self.parse_direction = Direction::Down;
129                let subentry = match self.parse_entry()? {
130                    Some(sub) => sub,
131                    None => return Err(ReamError::ParseError(ParseErrorType::MissingSubentry)),
132                };
133                entry.push_subentry(subentry);
134            } else if next_level.to_owned() <= self.current_level {
135                // return to parent entry
136                self.parse_direction = Direction::Up;
137                self.current_level -= 1;
138                break;
139            } else {
140                // wrong level for subentry
141                return Err(ReamError::ParseError(ParseErrorType::WrongHeaderLevel));
142            }
143        }
144
145        // downstream reference
146        entry.resolve_downstream_ref(&self.downstream)?;
147
148        // cleanup
149
150        // pop current class
151        self.pop_class();
152
153        // move current entry from upstream to downstream
154        let variable_map = match self.upstream.get(&entry.class()) {
155            Some(map) => map.clone(),
156            None => return Err(ReamError::Placeholder),
157        };
158        self.upstream.remove(&entry.class());
159        self.insert_downstream(entry.class().clone(), variable_map.clone());
160
161
162        Ok(Some(entry))
163    }
164
165    pub fn insert_downstream(&mut self, class: String, variable_map: VariableMap) {
166        if let Some(x) = self.downstream.get_mut(&class) {
167            x.push(variable_map);
168        } else {
169            self.downstream.insert(class.clone(), vec![variable_map]);
170        }
171    }
172
173    pub fn check_schema(&mut self, entry: Entry) -> Result<Entry, ReamError> {
174        if self.schemas.contains_key(&entry.class()) {
175            // schema exist -> check
176            self.check_schema_inner(entry)
177        } else {
178            // schema does not exist -> init
179            self.init_schema(entry)
180        }
181    }
182
183    pub fn init_schema(&mut self, entry: Entry) -> Result<Entry, ReamError> {
184        let entry_keys = entry.keys();
185        let entry_parent_class = entry.get_parent_class();
186        let entry_schema = EntrySchema::new(entry_keys, entry_parent_class);
187
188        let entry_class = entry.class().clone(); // TODO: clone!
189        self.schemas.insert(entry_class, entry_schema);
190
191        Ok(entry)
192    }
193
194    pub fn check_schema_inner(&self, entry: Entry) -> Result<Entry, ReamError> {
195        let entry_schema = entry.get_schema();
196        let parser_schema = self.get_schema(entry.class())?;
197
198        if entry_schema == parser_schema {
199            Ok(entry)
200        } else {
201            Err(ReamError::SchemaError(SchemaErrorType::IncorrectKeys))
202        }
203    }
204
205    pub fn parse_variable(&mut self) -> Result<(String, Value), ReamError> {
206        let key = self.parse_identifier()?;
207        let typ = self.parse_type()?;
208        self.parse_colon()?;
209        let value = self.parse_value(&key, typ)?;
210
211        Ok((key, value))
212    }
213
214    pub fn parse_value(&mut self, key: &String, typ: ValueType) -> Result<Value, ReamError> {
215        let tok_value = self.scanner.take_token()?;
216        let (value_base, typ) = match tok_value {
217            Some(Token(TokenType::Value(v), _, _)) => {
218                match typ {
219                    // if value is a reference, get the reference
220                    ValueType::Ref => {
221                        let (value_base, typ) = self.get_ref(v)?;
222                        match value_base {
223                            // unresolved reference will be pushed to ref_key_buffer
224                            // and checked for downstream reference
225                            ValueBase::Ref(c, k) => {
226                                self.push_ref_key(key.clone());
227                                (ValueBase::new_ref(c, k), typ)
228                            },
229                            _ => (value_base, typ),
230                        }
231                    },
232                    _ => ValueBase::new(v, typ)?,
233                }
234            }
235            Some(Token(TokenType::Star, _, _)) => self.parse_list_items(&key, typ)?,
236            _ => return Err(ReamError::ParseError(ParseErrorType::MissingValue)),
237        };
238
239        let annotation = self.parse_annotation()?;
240
241        let value = Value::new(value_base, annotation, typ);
242
243        Ok(value)
244    }
245
246    pub fn get_ref(&self, value: String) -> Result<(ValueBase, ValueType), ReamError> {
247        let v: Vec<&str> = value.split('$').collect();
248
249        if let [class, key] = &v[..] {
250            match self.upstream.get(*class) {
251                Some(variable_map) => match variable_map.get(&key.to_string()) {
252                    Some(s) => Ok(s.get_base_and_typ()),
253                    None => Err(ReamError::ReferenceError(
254                        ReferenceErrorType::VariableKeyNotFound,
255                    )),
256                },
257                None => match self.parse_direction {
258                    Direction::Down => Ok((
259                            ValueBase::new_ref(
260                                (*class).to_string(),
261                                (*key).to_string(),
262                            ),
263                            ValueType::Ref,
264                    )),
265                    Direction::Up => Err(ReamError::ReferenceError(
266                        ReferenceErrorType::EntryClassNotFound,
267                    )),
268                }
269            }
270        } else {
271            return Err(ReamError::ReferenceError(
272                ReferenceErrorType::InvalidReference,
273            ));
274        }
275    }
276
277    pub fn parse_list_items(
278        &mut self,
279        key: &String,
280        typ: ValueType,
281    ) -> Result<(ValueBase, ValueType), ReamError> {
282        // unwrap list type
283        let typ = match typ {
284            ValueType::List(t) => *t,
285            ValueType::Unknown => ValueType::Unknown,
286            _ => return Err(ReamError::TypeError(TypeErrorType::UnknownType)),
287        };
288
289        // parse first item
290        let first_item = self.parse_value(&key, typ.clone())?;
291
292        // init list
293        let item_typ = first_item.typ().clone(); // get the updated type
294        let mut list = List::new(item_typ.clone(), first_item);
295
296        // loop through list items
297        loop {
298            match self.scanner.peek_token()? {
299                Some(Token(TokenType::Star, _, _)) => {
300                    self.scanner.take_token()?; // consume star
301                    let new_item = self.parse_value(&key, typ.clone())?;
302                    // check new item type
303                    if new_item.typ() == list.item_type() {
304                        list.push_item(new_item);
305                    } else {
306                        return Err(ReamError::TypeError(TypeErrorType::HeterogeneousList));
307                    }
308                }
309                _ => break,
310            }
311        }
312
313        let value_base = ValueBase::new_item(list);
314        let typ = ValueType::List(Box::new(item_typ.clone()));
315        Ok((value_base, typ))
316    }
317
318    pub fn parse_annotation(&mut self) -> Result<Option<String>, ReamError> {
319        match self.scanner.peek_token()? {
320            Some(Token(TokenType::Block(_), _, _)) => {
321                self.scanner.take_token()?; // consume Block
322                match self.scanner.take_token()? {
323                    Some(Token(TokenType::Annotation(s), _, _)) => Ok(Some(s)),
324                    _ => return Err(ReamError::Placeholder),
325                }
326            }
327            _ => Ok(None),
328        }
329    }
330
331    pub fn parse_type(&mut self) -> Result<ValueType, ReamError> {
332        let typ = match self.scanner.peek_token()? {
333            // value type is specified
334            Some(Token(TokenType::ValueType(_), _, _)) => {
335                let t = match self.scanner.take_token()? {
336                    Some(Token(TokenType::ValueType(t), _, _)) => t,
337                    _ => return Err(ReamError::Placeholder),
338                };
339                t
340            }
341            // value type not specified
342            Some(Token(TokenType::Colon, _, _)) => ValueType::Unknown,
343            // maybe unreachable?
344            _ => return Err(ReamError::ParseError(ParseErrorType::MissingColon)),
345        };
346
347        Ok(typ)
348    }
349
350    pub fn parse_colon(&mut self) -> Result<(), ReamError> {
351        match self.scanner.take_token()? {
352            Some(Token(TokenType::Colon, _, _)) => Ok(()),
353            _ => return Err(ReamError::ParseError(ParseErrorType::MissingColon)),
354        }
355    }
356}
357
358#[cfg(test)]
359mod tests {
360
361    use super::*;
362
363    // #[test]
364    // fn header_line() {
365    //     let text = "# Title";
366    //     let mut parser = Parser::new(&text);
367    //     let entry_test = parser.parse_entry().unwrap().unwrap();
368    //     let entry_ans = Entry::new("Title".to_string(), 1);
369    //     assert_eq!(entry_test, entry_ans);
370    // }
371
372    // #[test]
373    // fn variable_line_string() {
374    //     let text = "# Title\n- key: value\n> annotation";
375    //     let mut parser = Parser::new(&text);
376    //     let entry_test = parser.parse_entry().unwrap().unwrap();
377    //     let mut entry_ans = Entry::new("Title".to_string(), 1);
378    //     let var = ReamVariable::new(
379    //         String::from("key"),
380    //         ReamValue::Str("value".to_string()),
381    //         String::from("annotation"),
382    //     );
383    //     entry_ans.push_variable(var);
384    //     assert_eq!(entry_test, entry_ans);
385    // }
386}