use crate::desktop::{Desktop, ParseError, PositionedParseError};
use rowan::ast::AstNode;
use rowan::{GreenNode, SyntaxNode};
use std::marker::PhantomData;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Parse<T> {
green: GreenNode,
errors: Vec<String>,
positioned_errors: Vec<PositionedParseError>,
_ty: PhantomData<T>,
}
impl<T> Parse<T> {
pub fn new(green: GreenNode, errors: Vec<String>) -> Self {
Parse {
green,
errors,
positioned_errors: Vec::new(),
_ty: PhantomData,
}
}
pub fn new_with_positioned_errors(
green: GreenNode,
errors: Vec<String>,
positioned_errors: Vec<PositionedParseError>,
) -> Self {
Parse {
green,
errors,
positioned_errors,
_ty: PhantomData,
}
}
pub fn green(&self) -> &GreenNode {
&self.green
}
pub fn errors(&self) -> &[String] {
&self.errors
}
pub fn positioned_errors(&self) -> &[PositionedParseError] {
&self.positioned_errors
}
pub fn error_messages(&self) -> Vec<String> {
self.positioned_errors
.iter()
.map(|e| e.message.clone())
.collect()
}
pub fn ok(&self) -> bool {
self.errors.is_empty()
}
pub fn to_result(self) -> Result<T, ParseError>
where
T: AstNode<Language = crate::desktop::Lang>,
{
if self.errors.is_empty() {
let node = SyntaxNode::new_root_mut(self.green);
Ok(T::cast(node).expect("root node has wrong type"))
} else {
Err(ParseError(self.errors))
}
}
pub fn tree(&self) -> T
where
T: AstNode<Language = crate::desktop::Lang>,
{
assert!(
self.errors.is_empty(),
"tried to get tree with errors: {:?}",
self.errors
);
let node = SyntaxNode::new_root_mut(self.green.clone());
T::cast(node).expect("root node has wrong type")
}
pub fn syntax_node(&self) -> SyntaxNode<crate::desktop::Lang> {
SyntaxNode::new_root_mut(self.green.clone())
}
}
unsafe impl<T> Send for Parse<T> {}
unsafe impl<T> Sync for Parse<T> {}
impl Parse<Desktop> {
pub fn parse_desktop(text: &str) -> Self {
let parsed = crate::desktop::parse(text);
Parse::new_with_positioned_errors(
parsed.green_node,
parsed.errors,
parsed.positioned_errors,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_success() {
let input = "[Desktop Entry]\nName=Example\n";
let parsed = Parse::<Desktop>::parse_desktop(input);
assert!(parsed.ok());
assert!(parsed.errors().is_empty());
let desktop = parsed.tree();
assert_eq!(desktop.groups().count(), 1);
}
#[test]
fn test_parse_with_errors() {
let input = "Invalid line without section\n[Desktop Entry]\n";
let parsed = Parse::<Desktop>::parse_desktop(input);
assert!(!parsed.ok());
assert!(!parsed.errors().is_empty());
}
}