use rowan::GreenNode;
use crate::parser::grammar;
use crate::parser::lexer::lex;
use crate::parser::tree_builder::build_tree;
use crate::syntax::SyntaxNode;
#[derive(Debug, Clone)]
pub struct Parse {
pub green: GreenNode,
pub errors: Vec<SyntaxError>,
}
impl Parse {
pub fn syntax(&self) -> SyntaxNode {
SyntaxNode::new_root(self.green.clone())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SyntaxError {
pub message: String,
pub start: usize,
pub end: usize,
}
pub fn parse(input: &str) -> Parse {
let tokens = lex(input);
let (events, errors) = grammar::parse(&tokens);
let green = build_tree(&tokens, &events);
Parse { green, errors }
}
pub fn reconstruct(input: &str) -> String {
parse(input).syntax().to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reconstruct_is_identity() {
let input = "\\section{Hi}\n\nbody $x^2$ % c\n";
assert_eq!(reconstruct(input), input);
}
#[test]
fn command_wraps_its_argument_group() {
use crate::syntax::SyntaxKind;
let parse = parse(r"\a{b}");
let command = parse
.syntax()
.descendants()
.find(|n| n.kind() == SyntaxKind::COMMAND)
.expect("a COMMAND node");
assert!(
command.children().any(|n| n.kind() == SyntaxKind::GROUP),
"the argument should be a nested GROUP node"
);
assert!(parse.errors.is_empty());
}
}