Skip to content

Commit

Permalink
Share code for parse function between comments.rs and `tree_sitte…
Browse files Browse the repository at this point in the history
…r.rs`
  • Loading branch information
nbacquey committed Dec 11, 2024
1 parent b30cd81 commit 48483fb
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 71 deletions.
3 changes: 2 additions & 1 deletion topiary-core/src/atom_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use std::{
use topiary_tree_sitter_facade::Node;

use crate::{
tree_sitter::NodeExt, Atom, FormatterError, FormatterResult, ScopeCondition, ScopeInformation,
tree_sitter::NodeExt,
Atom, FormatterError, FormatterResult, ScopeCondition, ScopeInformation,
};

/// A struct that holds sets of node IDs that have line breaks before or after them.
Expand Down
25 changes: 9 additions & 16 deletions topiary-core/src/comments.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use topiary_tree_sitter_facade::{InputEdit, Language, Node, Parser, Tree};
use topiary_tree_sitter_facade::{InputEdit, Language, Node, Tree};

use crate::{
common::{parse, Diff, InputSection, Position},
error::FormatterError,
types::{Diff, InputSection, Position},
FormatterResult,
};

Expand Down Expand Up @@ -222,19 +222,6 @@ fn previous_non_comment_leaf<'tree>(starting_node: Node<'tree>) -> Option<Node<'
}
}

fn reparse(
old_tree: Tree,
content: &str,
grammar: &topiary_tree_sitter_facade::Language,
) -> FormatterResult<Tree> {
let mut parser = Parser::new()?;
parser.set_language(grammar)?;
let tree = parser
.parse(content, Some(&old_tree))?
.ok_or_else(|| FormatterError::Internal("Could not parse input".into(), None))?;
Ok(tree)
}

// Use the following heuristics to find a comment's anchor:
// If the comment is only prefixed by blank symbols on its line, then the anchor is the
// next non-comment sibling node.
Expand Down Expand Up @@ -298,6 +285,7 @@ pub fn extract_comments<'a>(
tree: &'a Tree,
input: &'a str,
grammar: &Language,
tolerate_parsing_errors: bool,
) -> FormatterResult<SeparatedInput> {
let mut anchors: Vec<(Node, AnchoredComment)> = Vec::new();
let mut anchored_comments: Vec<AnchoredComment> = Vec::new();
Expand Down Expand Up @@ -351,7 +339,12 @@ pub fn extract_comments<'a>(
for edit in edits {
new_tree.edit(&edit);
}
new_tree = reparse(new_tree, new_input.as_str(), grammar)?;
new_tree = parse(
new_input.as_str(),
grammar,
tolerate_parsing_errors,
Some(&new_tree),
)?;
Ok(SeparatedInput {
input_tree: new_tree,
input_string: new_input,
Expand Down
51 changes: 49 additions & 2 deletions topiary-core/src/types.rs → topiary-core/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::{cmp::Ord, fmt::Display};

use serde::Serialize;
use topiary_tree_sitter_facade::{Node, Point};
use topiary_tree_sitter_facade::{Node, Parser, Point, Tree};

/// A module for common, low-level types in the topiary-core crate
use crate::{error::FormatterError, FormatterResult};

/// A module for common, low-level types and functions in the topiary-core crate
/// Refers to a position within the code. Used for error reporting, and for
/// comparing input with formatted output. The numbers are 1-based, because that
Expand Down Expand Up @@ -55,3 +57,48 @@ pub trait Diff<T> {

fn subtract(self: &mut Self, other: T) -> Result<(), Self::ErrorType>;
}

/// Parses some string into a syntax tree, given a tree-sitter grammar.
pub fn parse(
content: &str,
grammar: &topiary_tree_sitter_facade::Language,
tolerate_parsing_errors: bool,
old_tree: Option<&Tree>,
) -> FormatterResult<Tree> {
let mut parser = Parser::new()?;
parser.set_language(grammar).map_err(|_| {
FormatterError::Internal("Could not apply Tree-sitter grammar".into(), None)
})?;

let tree = parser
.parse(content, old_tree)?
.ok_or_else(|| FormatterError::Internal("Could not parse input".into(), None))?;

// Fail parsing if we don't get a complete syntax tree.
if !tolerate_parsing_errors {
check_for_error_nodes(&tree.root_node())?;
}

Ok(tree)
}

fn check_for_error_nodes(node: &Node) -> FormatterResult<()> {
if node.kind() == "ERROR" {
let start = node.start_position();
let end = node.end_position();

// Report 1-based lines and columns.
return Err(FormatterError::Parsing {
start_line: start.row() + 1,
start_column: start.column() + 1,
end_line: end.row() + 1,
end_column: end.column() + 1,
});
}

for child in node.children(&mut node.walk()) {
check_for_error_nodes(&child)?;
}

Ok(())
}
6 changes: 3 additions & 3 deletions topiary-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ use itertools::Itertools;
use pretty_assertions::StrComparison;

pub use crate::{
common::{parse, Position},
error::{FormatterError, IoError},
language::Language,
tree_sitter::{apply_query, CoverageData, SyntaxNode, TopiaryQuery, Visualisation},
types::Position,
};

mod atom_collection;
pub mod comments;
pub mod common;
mod error;
mod graphviz;
mod language;
mod pretty;
pub mod tree_sitter;
pub mod types;

#[doc(hidden)]
pub mod test_utils;
Expand Down Expand Up @@ -264,7 +264,7 @@ pub fn formatter(
}

Operation::Visualise { output_format } => {
let tree = tree_sitter::parse(&content, &language.grammar, false)?;
let tree = parse(&content, &language.grammar, false, None)?;
let root: SyntaxNode = tree.root_node().into();

match output_format {
Expand Down
54 changes: 5 additions & 49 deletions topiary-core/src/tree_sitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ use std::{collections::HashSet, fmt::Display};
use serde::Serialize;

use topiary_tree_sitter_facade::{
Node, Parser, Point, Query, QueryCapture, QueryCursor, QueryMatch, QueryPredicate, Tree,
Node, Point, Query, QueryCapture, QueryCursor, QueryMatch, QueryPredicate,
};

use streaming_iterator::StreamingIterator;

use crate::{
atom_collection::{AtomCollection, QueryPredicates},
comments::{extract_comments, AnchoredComment, SeparatedInput},
common::{parse, Position},
error::FormatterError,
types::Position,
FormatterResult,
};

Expand Down Expand Up @@ -211,14 +211,14 @@ pub fn apply_query(
grammar: &topiary_tree_sitter_facade::Language,
tolerate_parsing_errors: bool,
) -> FormatterResult<AtomCollection> {
let tree = parse(input_content, grammar, tolerate_parsing_errors)?;
let tree = parse(input_content, grammar, tolerate_parsing_errors, None)?;

// Remove comments in a separate stream before applying queries
let SeparatedInput {
input_string,
input_tree,
comments,
} = extract_comments(&tree, input_content, grammar)?;
} = extract_comments(&tree, input_content, grammar, tolerate_parsing_errors)?;
let source = input_string.as_bytes();
let root = input_tree.root_node();

Expand Down Expand Up @@ -325,50 +325,6 @@ pub fn apply_query(
Ok(atoms)
}

/// Parses some string into a syntax tree, given a tree-sitter grammar.
pub fn parse(
content: &str,
grammar: &topiary_tree_sitter_facade::Language,
tolerate_parsing_errors: bool,
) -> FormatterResult<Tree> {
let mut parser = Parser::new()?;
parser.set_language(grammar).map_err(|_| {
FormatterError::Internal("Could not apply Tree-sitter grammar".into(), None)
})?;

let tree = parser
.parse(content, None)?
.ok_or_else(|| FormatterError::Internal("Could not parse input".into(), None))?;

// Fail parsing if we don't get a complete syntax tree.
if !tolerate_parsing_errors {
check_for_error_nodes(&tree.root_node())?;
}

Ok(tree)
}

fn check_for_error_nodes(node: &Node) -> FormatterResult<()> {
if node.kind() == "ERROR" {
let start = node.start_position();
let end = node.end_position();

// Report 1-based lines and columns.
return Err(FormatterError::Parsing {
start_line: start.row() + 1,
start_column: start.column() + 1,
end_line: end.row() + 1,
end_column: end.column() + 1,
});
}

for child in node.children(&mut node.walk()) {
check_for_error_nodes(&child)?;
}

Ok(())
}

/// Collects the IDs of all leaf nodes in a set of query matches.
///
/// This function takes a slice of `LocalQueryMatch` and a slice of capture names,
Expand Down Expand Up @@ -519,7 +475,7 @@ pub fn check_query_coverage(
original_query: &TopiaryQuery,
grammar: &topiary_tree_sitter_facade::Language,
) -> FormatterResult<CoverageData> {
let tree = parse(input_content, grammar, false)?;
let tree = parse(input_content, grammar, false, None)?;
let root = tree.root_node();
let source = input_content.as_bytes();
let mut missing_patterns = Vec::new();
Expand Down

0 comments on commit 48483fb

Please sign in to comment.