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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
use alloc::vec::Vec;
use crate::{ParseError, ParsedItem, Parser, TreeNode};
/// Parses into a tree of `TreeNode`.
///
/// # Example
///
/// ```
/// use sise::sise_tree;
///
/// let data = "(test (1 2 3))";
/// let mut parser = sise::Parser::new(data);
/// let root_node = sise::parse_tree(&mut parser).unwrap();
/// // Do not forget calling `finish` on the parser.
/// parser.finish().unwrap();
/// let expected_result = sise_tree!(["test", ["1", "2", "3"]]);
/// assert_eq!(root_node, expected_result);
/// ```
///
/// It does not consume the parser, so it can also be used to parse
/// a sub-tree:
///
/// ```
/// use sise::sise_tree;
///
/// let data = "(head (1 2 3) tail)";
/// let mut parser = sise::Parser::new(data);
///
/// // Parse the head
/// assert_eq!(parser.next_item().unwrap(), sise::ParsedItem::ListStart(0));
/// assert_eq!(
/// parser.next_item().unwrap(),
/// sise::ParsedItem::Atom("head", 1),
/// );
///
/// // Parse the subtree
/// let root_node = sise::parse_tree(&mut parser).unwrap();
/// let expected_result = sise_tree!(["1", "2", "3"]);
/// assert_eq!(root_node, expected_result);
///
/// // Parse the tail
/// assert_eq!(
/// parser.next_item().unwrap(),
/// sise::ParsedItem::Atom("tail", 14)
/// );
/// assert_eq!(parser.next_item().unwrap(), sise::ParsedItem::ListEnd(18));
/// parser.finish().unwrap();
/// ```
pub fn parse_tree(parser: &mut Parser<'_>) -> Result<TreeNode, ParseError> {
struct StackItem {
list_items: Vec<TreeNode>,
}
enum State {
Beginning,
Parsing {
stack: Vec<StackItem>,
current: StackItem,
},
Finished(TreeNode),
}
let mut state = State::Beginning;
loop {
match state {
State::Beginning => match parser.next_item()? {
ParsedItem::Atom(atom, _) => {
let root_node = TreeNode::Atom(atom.into());
state = State::Finished(root_node);
}
ParsedItem::ListStart(_) => {
state = State::Parsing {
stack: Vec::new(),
current: StackItem {
list_items: Vec::new(),
},
};
}
ParsedItem::ListEnd(_) => unreachable!(),
},
State::Parsing {
ref mut stack,
ref mut current,
} => match parser.next_item()? {
ParsedItem::Atom(atom, _) => {
current.list_items.push(TreeNode::Atom(atom.into()));
}
ParsedItem::ListStart(_) => {
let new_current = StackItem {
list_items: Vec::new(),
};
stack.push(core::mem::replace(current, new_current));
}
ParsedItem::ListEnd(_) => {
if let Some(previous) = stack.pop() {
let old_current = core::mem::replace(current, previous);
current
.list_items
.push(TreeNode::List(old_current.list_items));
} else {
let root_node = TreeNode::List(core::mem::take(&mut current.list_items));
state = State::Finished(root_node);
}
}
},
State::Finished(root_node) => return Ok(root_node),
}
}
}