use tree_sitter::Node;
use tree_sitter::Tree;
#[derive(Debug)]
pub enum ParseError<'tree> {
Missing(Node<'tree>),
Unexpected(Node<'tree>),
}
impl<'tree> ParseError<'tree> {
pub fn first(tree: &Tree) -> Option<ParseError> {
let mut errors = Vec::new();
find_errors(tree, &mut errors, true);
errors.into_iter().next()
}
pub fn into_first(tree: Tree) -> TreeWithParseErrorOption {
TreeWithParseErrorOption::into_first(tree)
}
pub fn all(tree: &'tree Tree) -> Vec<ParseError> {
let mut errors = Vec::new();
find_errors(tree, &mut errors, false);
errors
}
pub fn into_all(tree: Tree) -> TreeWithParseErrorVec {
TreeWithParseErrorVec::into_all(tree)
}
}
impl<'tree> ParseError<'tree> {
pub fn node(&self) -> &Node<'tree> {
match self {
Self::Missing(node) => node,
Self::Unexpected(node) => node,
}
}
pub fn display(&self, source: &'tree str, verbose: bool) -> ParseErrorDisplay {
ParseErrorDisplay {
error: self,
source,
verbose,
}
}
}
pub struct ParseErrorDisplay<'tree> {
error: &'tree ParseError<'tree>,
source: &'tree str,
verbose: bool,
}
impl std::fmt::Display for ParseErrorDisplay<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let node = match self.error {
ParseError::Missing(node) => {
write!(f, "Missing syntax")?;
node
}
ParseError::Unexpected(node) => {
write!(f, "Unexpected syntax")?;
node
}
};
let line = node.start_position().row;
let start_column = node.start_position().column;
if node.byte_range().is_empty() {
writeln!(f, "")?;
} else {
let (end_column, end_byte) = self.source[node.byte_range()]
.chars()
.take_while(|c| *c != '\n')
.fold(
(node.start_position().column, node.start_byte()),
|(column, byte), c| (column + 1, byte + c.len_utf8()),
);
if !self.verbose {
let text = &self.source[node.start_byte()..end_byte];
write!(f, ": {}", text)?;
} else {
let text = self.source.lines().nth(line).unwrap();
writeln!(f, ":")?;
writeln!(f, "")?;
writeln!(f, "| {}", text)?;
write!(
f,
" {}{}",
" ".repeat(start_column),
"^".repeat(end_column - start_column)
)?;
if node.end_position().row == line {
writeln!(f, "")?;
} else {
writeln!(f, "...")?;
}
}
}
Ok(())
}
}
fn find_errors<'tree>(tree: &'tree Tree, errors: &mut Vec<ParseError<'tree>>, first_only: bool) {
if !tree.root_node().has_error() {
return;
}
let mut cursor = tree.walk();
let mut did_visit_children = false;
loop {
let node = cursor.node();
if node.is_error() {
errors.push(ParseError::Unexpected(node));
if first_only {
break;
}
did_visit_children = true;
} else if node.is_missing() {
errors.push(ParseError::Missing(node));
if first_only {
break;
}
did_visit_children = true;
}
if did_visit_children {
if cursor.goto_next_sibling() {
did_visit_children = false;
} else if cursor.goto_parent() {
did_visit_children = true;
} else {
break;
}
} else {
if cursor.goto_first_child() {
did_visit_children = false;
} else {
did_visit_children = true;
}
}
}
cursor.reset(tree.root_node());
}
pub struct TreeWithParseError {
tree: Tree,
error: ParseError<'static>,
}
impl TreeWithParseError {
pub fn tree(&self) -> &Tree {
&self.tree
}
pub fn into_tree(self) -> Tree {
self.tree
}
pub fn error(&self) -> &ParseError {
&self.error
}
}
impl std::fmt::Debug for TreeWithParseError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self.error)
}
}
unsafe impl Send for TreeWithParseError {}
unsafe impl Sync for TreeWithParseError {}
pub struct TreeWithParseErrorOption {
tree: Tree,
error: Option<ParseError<'static>>,
}
impl TreeWithParseErrorOption {
fn into_first(tree: Tree) -> TreeWithParseErrorOption {
let mut errors = Vec::new();
find_errors(&tree, &mut errors, true);
Self {
error: unsafe { std::mem::transmute(errors.into_iter().next()) },
tree: tree,
}
}
}
impl TreeWithParseErrorOption {
pub fn tree(&self) -> &Tree {
&self.tree
}
pub fn into_tree(self) -> Tree {
self.tree
}
pub fn error(&self) -> &Option<ParseError> {
&self.error
}
pub fn into_option(self) -> Option<TreeWithParseError> {
match self.error {
None => None,
Some(error) => Some(TreeWithParseError {
tree: self.tree,
error,
}),
}
}
}
impl std::fmt::Debug for TreeWithParseErrorOption {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self.error)
}
}
unsafe impl Send for TreeWithParseErrorOption {}
unsafe impl Sync for TreeWithParseErrorOption {}
pub struct TreeWithParseErrorVec {
tree: Tree,
errors: Vec<ParseError<'static>>,
}
impl TreeWithParseErrorVec {
fn into_all(tree: Tree) -> TreeWithParseErrorVec {
let mut errors = Vec::new();
find_errors(&tree, &mut errors, false);
TreeWithParseErrorVec {
errors: unsafe { std::mem::transmute(errors) },
tree: tree,
}
}
}
impl TreeWithParseErrorVec {
pub fn tree(&self) -> &Tree {
&self.tree
}
pub fn into_tree(self) -> Tree {
self.tree
}
pub fn errors(&self) -> &Vec<ParseError> {
&self.errors
}
}
impl std::fmt::Debug for TreeWithParseErrorVec {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self.errors)
}
}
unsafe impl Send for TreeWithParseErrorVec {}
unsafe impl Sync for TreeWithParseErrorVec {}