Skip to content

Commit 670984a

Browse files
committed
[function-grep]
working to remove panicking code (specifically in language instantiation plus a bit of cleanup
1 parent a9a6c18 commit 670984a

File tree

8 files changed

+138
-116
lines changed

8 files changed

+138
-116
lines changed

function-grep/examples/main.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
#![deny(missing_debug_implementations, clippy::missing_panics_doc)]
44
#![warn(clippy::pedantic, clippy::nursery, clippy::cargo)]
55
#![deny(clippy::use_self, rust_2018_idioms)]
6-
use function_grep::supported_languages::InstantiateMap;
6+
use function_grep::supported_languages::{InstantiateMap, InstantiationError};
77
use function_grep::{supported_languages::predefined_languages, ParsedFile};
88

99
use clap::Parser;
1010
use std::{fs::File, io::Read, path::PathBuf};
11-
use tree_sitter::QueryError;
1211
#[derive(Parser, Debug)]
1312
#[command(version, about)]
1413
pub struct Args {
@@ -23,7 +22,7 @@ pub enum Error {
2322
CouldNotOpenFile(std::io::Error),
2423
CouldNotReadFile(std::io::Error),
2524
LibraryError(function_grep::Error),
26-
QueryError(QueryError),
25+
InstatantiationError(InstantiationError),
2726
}
2827

2928
///
@@ -38,7 +37,7 @@ pub fn main() -> Result<(), Error> {
3837
let mut code = String::new();
3938
let languages = predefined_languages()
4039
.instantiate_map(&args.name)
41-
.map_err(Error::QueryError)?;
40+
.map_err(Error::InstatantiationError)?;
4241
file.read_to_string(&mut code)
4342
.map_err(Error::CouldNotReadFile)?;
4443
let file_name = &args.file.to_string_lossy();

function-grep/src/filter.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ pub trait HasFilterInformation {
117117
fn supports(&self) -> Self::Supports;
118118

119119
fn attributes(&self) -> Attributes;
120-
// TODO: have filter creation informaton about types and fields for uis
121120
fn filter_info(&self) -> FilterInformation<Self::Supports> {
122121
FilterInformation {
123122
filter_name: self.filter_name(),

function-grep/src/filter/filter_parsers.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,9 @@ pub fn string<'a>(
3737
position: &str,
3838
filter: &str,
3939
) -> Result<String, String> {
40-
substring.next().map(ToOwned::to_owned).ok_or_else(||format! ("invalid options for function_with_parameter filter\nexpected {format}\n missing {position} [number]"))
40+
substring.next().map(ToOwned::to_owned).ok_or_else(|| {
41+
format!(
42+
"invalid options for {filter} filter\nexpected {format}\n missing {position} [string]"
43+
)
44+
})
4145
}

function-grep/src/filter/general_filters.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl Filter for FunctionWithParameterRust {
171171
cursor.matches(&query, *node, text_provider).any(|c| {
172172
c.captures
173173
.iter()
174-
.any(|c| c.node.utf8_text(text_provider).unwrap() == name)
174+
.any(|c| c.node.utf8_text(text_provider).unwrap_or("") == name)
175175
})
176176
}))
177177
}
@@ -198,7 +198,7 @@ impl HasFilterInformation for FunctionWithParameterPython {
198198
}
199199

200200
impl Filter for FunctionWithParameterPython {
201-
fn parse_filter(&self, s: &str) -> Result<FilterFunction, String> {
201+
fn parse_filter(&self, _s: &str) -> Result<FilterFunction, String> {
202202
todo!()
203203
}
204204
}

function-grep/src/supported_languages.rs

Lines changed: 94 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ pub struct InstantiatedLanguage<'a> {
1414
run_query: QueryFunction,
1515
}
1616

17+
#[derive(Debug)]
18+
pub enum InstantiationError {
19+
NoMatchingField(String),
20+
Query(QueryError),
21+
Tags(tree_sitter_tags::Error),
22+
}
1723
pub trait HasLanguageInformation {
1824
/// The name of this language
1925
fn language_name(&self) -> &'static str;
@@ -88,49 +94,59 @@ pub struct TreeSitter;
8894
pub struct Tags;
8995
// TODO: hide in docs?
9096
trait InstantiateHelper<Type> {
91-
fn instantiate(&self, search: Box<str>) -> QueryFunction;
97+
fn instantiate(&self, search: Box<str>) -> Result<QueryFunction, InstantiationError>;
9298
}
9399

94100
// TODO: hide in docs?
95101
pub trait Assoc {
96102
type Type;
97103
}
98104
impl<T: IdentifierQuery> InstantiateHelper<Identifier> for T {
99-
fn instantiate(&self, search: Box<str>) -> QueryFunction {
100-
let query = Query::new(&self.language(), &self.query_string().to_string()).unwrap();
101-
let method_field = query
102-
.capture_index_for_name(&self.query_name().to_string())
103-
.unwrap();
104-
Box::new(move |node, code| {
105-
let name = &*search;
106-
let mut query_cursor = tree_sitter::QueryCursor::new();
107-
let matches = query_cursor.matches(&query, node, code);
108-
let ranges = matches
109-
.filter(move |m| {
110-
m.captures
111-
.iter()
112-
.any(|c| c.index == method_field && c.node.utf8_text(code).unwrap() == name)
113-
})
114-
.map(|m| m.captures[0].node.range());
115-
116-
ranges.collect()
117-
})
105+
fn instantiate(&self, search: Box<str>) -> Result<QueryFunction, InstantiationError> {
106+
Query::new(&self.language(), &self.query_string().to_string())
107+
.map_err(InstantiationError::Query)
108+
.and_then(|query: Query| {
109+
query
110+
.capture_index_for_name(&self.query_name().to_string())
111+
.ok_or_else(|| {
112+
InstantiationError::NoMatchingField(self.query_name().to_string())
113+
})
114+
.map(|method_field| -> QueryFunction {
115+
Box::new(move |node, code| {
116+
let name = &*search;
117+
let mut query_cursor = tree_sitter::QueryCursor::new();
118+
let matches = query_cursor.matches(&query, node, code);
119+
let ranges = matches
120+
.filter(move |m| {
121+
m.captures.iter().any(|c| {
122+
c.index == method_field
123+
&& c.node.utf8_text(code).unwrap_or("") == name
124+
})
125+
})
126+
.map(|m| m.captures[0].node.range());
127+
128+
ranges.collect()
129+
})
130+
})
131+
})
118132
}
119133
}
120134
impl<T: TreeSitterQuery> InstantiateHelper<TreeSitter> for T {
121-
fn instantiate(&self, search: Box<str>) -> QueryFunction {
122-
let query = Query::new(
135+
fn instantiate(&self, search: Box<str>) -> Result<QueryFunction, InstantiationError> {
136+
Query::new(
123137
&self.language(),
124138
&self.query_string_function(search.as_ref()),
125139
)
126-
.unwrap();
127-
Box::new(move |node, code| {
128-
let mut query_cursor = tree_sitter::QueryCursor::new();
129-
let matches = query_cursor.matches(&query, node, code);
130-
131-
let ranges = matches.map(|m| m.captures[0].node.range());
132-
ranges.collect()
140+
.map(|query| -> QueryFunction {
141+
Box::new(move |node, code| {
142+
let mut query_cursor = tree_sitter::QueryCursor::new();
143+
let matches = query_cursor.matches(&query, node, code);
144+
145+
let ranges = matches.map(|m| m.captures[0].node.range());
146+
ranges.collect()
147+
})
133148
})
149+
.map_err(InstantiationError::Query)
134150
}
135151
}
136152
struct TagsConfigurationThreadSafe(TagsConfiguration);
@@ -156,64 +172,75 @@ impl TagsConfigurationThreadSafe {
156172
}
157173
}
158174
impl<T: TreeSitterTags> InstantiateHelper<Tags> for T {
159-
fn instantiate(&self, search: Box<str>) -> QueryFunction {
160-
let tag_config = TagsConfigurationThreadSafe(
161-
TagsConfiguration::new(self.language(), &self.tag_query().to_string(), "").unwrap(),
162-
);
163-
Box::new(move |node, code| {
164-
let mut tag_context = TagsContext::new();
165-
let name = &*search;
166-
// TODO: don't double parse
167-
let tags = tag_config
168-
.generate_tags(&mut tag_context, code, None)
169-
.unwrap()
170-
.0;
171-
let ranges = tags
172-
.filter_map(Result::ok)
173-
.filter(|tag| {
174-
["method", "function"]
175-
.contains(&tag_config.syntax_type_name(tag.syntax_type_id))
176-
&& str::from_utf8(&code[tag.name_range.clone()]).unwrap_or("") == name
175+
fn instantiate(&self, search: Box<str>) -> Result<QueryFunction, InstantiationError> {
176+
TagsConfiguration::new(self.language(), &self.tag_query().to_string(), "")
177+
.map_err(InstantiationError::Tags)
178+
.map(|tag_config| -> QueryFunction {
179+
let tag_config = TagsConfigurationThreadSafe(tag_config);
180+
Box::new(move |node, code| {
181+
let mut tag_context = TagsContext::new();
182+
let name = &*search;
183+
// TODO: don't double parse
184+
tag_config
185+
.generate_tags(&mut tag_context, code, None)
186+
.map(|tags| {
187+
let ranges = tags
188+
.0
189+
.filter_map(Result::ok)
190+
.filter(|tag| {
191+
["method", "function"]
192+
.contains(&tag_config.syntax_type_name(tag.syntax_type_id))
193+
&& str::from_utf8(&code[tag.name_range.clone()])
194+
.unwrap_or("")
195+
== name
196+
})
197+
.filter_map(|tag| {
198+
node.descendant_for_byte_range(tag.range.start, tag.range.end)
199+
.map(|node| node.range())
200+
});
201+
ranges.collect()
202+
})
203+
.unwrap_or_else(|_| vec![].into_boxed_slice())
177204
})
178-
.filter_map(|tag| {
179-
node.descendant_for_byte_range(tag.range.start, tag.range.end)
180-
.map(|node| node.range())
181-
});
182-
ranges.collect()
183-
})
205+
})
184206
}
185207
}
208+
186209
impl<T: Assoc + InstantiateHelper<T::Type> + HasLanguageInformation> SupportedLanguage for T {
187-
fn instantiate(&self, search: Box<str>) -> QueryFunction {
210+
fn instantiate(&self, search: Box<str>) -> Result<QueryFunction, InstantiationError> {
188211
self.instantiate(search)
189212
}
190213
}
214+
// TODO: maybe make this fallable
191215
type QueryFunction = Box<dyn for<'x, 'y> Fn(Node<'x>, &'y [u8]) -> Box<[Range]> + Send + Sync>;
192216

193217
pub trait SupportedLanguage: HasLanguageInformation {
194-
fn instantiate(&self, search: Box<str>) -> QueryFunction;
195-
fn to_language<'a>(&self, search: &'a str) -> InstantiatedLanguage<'a> {
196-
InstantiatedLanguage::new(
197-
search,
198-
self.language_info(),
199-
self.instantiate(search.into()),
200-
)
218+
fn instantiate(&self, search: Box<str>) -> Result<QueryFunction, InstantiationError>;
219+
fn to_language<'a>(
220+
&self,
221+
search: &'a str,
222+
) -> Result<InstantiatedLanguage<'a>, InstantiationError> {
223+
self.instantiate(search.into())
224+
.map(|f| InstantiatedLanguage::new(search, self.language_info(), f))
201225
}
202226
}
203227

204228
pub trait InstantiateMap<'a> {
205-
fn instantiate_map(self, name: &'a str) -> Result<Vec<InstantiatedLanguage<'a>>, QueryError>;
229+
fn instantiate_map(
230+
self,
231+
name: &'a str,
232+
) -> Result<Vec<InstantiatedLanguage<'a>>, InstantiationError>;
206233
}
207234
impl<'a, T, U> InstantiateMap<'a> for T
208235
where
209236
T: IntoIterator<Item = U>,
210237
U: Deref<Target = &'a dyn SupportedLanguage>,
211238
{
212-
fn instantiate_map(self, name: &'a str) -> Result<Vec<InstantiatedLanguage<'a>>, QueryError> {
213-
Ok(self
214-
.into_iter()
215-
.map(|l| InstantiatedLanguage::new(name, l.language_info(), l.instantiate(name.into())))
216-
.collect())
239+
fn instantiate_map(
240+
self,
241+
name: &'a str,
242+
) -> Result<Vec<InstantiatedLanguage<'a>>, InstantiationError> {
243+
self.into_iter().map(|l| l.to_language(name)).collect()
217244
}
218245
}
219246
impl<'a> InstantiatedLanguage<'a> {

0 commit comments

Comments
 (0)