diff --git a/cli/src/lib.rs b/cli/src/lib.rs index d36417c2..d52b516a 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -14,3 +14,7 @@ pub mod wasm; #[cfg(test)] mod tests; + +// To run compile fail tests +#[cfg(doctest)] +mod tests; diff --git a/cli/src/tests/language_test.rs b/cli/src/tests/language_test.rs index f8a4653f..5dd04c46 100644 --- a/cli/src/tests/language_test.rs +++ b/cli/src/tests/language_test.rs @@ -27,7 +27,7 @@ fn test_lookahead_iterator() { assert_ne!(cursor.node().grammar_id(), cursor.node().kind_id()); let expected_symbols = ["identifier", "block_comment", "line_comment"]; - let lookahead = language.lookahead_iterator(next_state).unwrap(); + let mut lookahead = language.lookahead_iterator(next_state).unwrap(); assert_eq!(lookahead.language(), language); assert!(lookahead.iter_names().eq(expected_symbols)); @@ -39,3 +39,57 @@ fn test_lookahead_iterator() { .map(|s| language.node_kind_for_id(s).unwrap()) .eq(expected_symbols)); } + +#[test] +fn test_lookahead_iterator_modifiable_only_by_mut() { + let mut parser = Parser::new(); + let language = get_language("rust"); + parser.set_language(language).unwrap(); + + let tree = parser.parse("struct Stuff {}", None).unwrap(); + + let mut cursor = tree.walk(); + + assert!(cursor.goto_first_child()); // struct + assert!(cursor.goto_first_child()); // struct keyword + + let next_state = cursor.node().next_parse_state(); + assert_ne!(next_state, 0); + + let mut lookahead = language.lookahead_iterator(next_state).unwrap(); + let _ = lookahead.next(); + + let mut names = lookahead.iter_names(); + let _ = names.next(); +} + +/// It doesn't allowed to use lookahead iterator by shared ref: +/// error[E0596]: cannot borrow `lookahead` as mutable, as it is not declared as mutable +/// ```compile_fail +/// use tree_sitter::{Parser, Language}; +/// let mut parser = Parser::new(); +/// let language = unsafe { Language::from_raw(std::ptr::null()) }; +/// let tree = parser.parse("", None).unwrap(); +/// let mut cursor = tree.walk(); +/// let next_state = cursor.node().next_parse_state(); +/// let lookahead = language.lookahead_iterator(next_state).unwrap(); +/// let _ = lookahead.next(); +/// ``` + +/// It doesn't allowed to use lookahead names iterator by shared ref: +/// error[E0596]: cannot borrow `names` as mutable, as it is not declared as mutable +/// ```compile_fail +/// use tree_sitter::{Parser, Language}; +/// let mut parser = Parser::new(); +/// let language = unsafe { Language::from_raw(std::ptr::null()) }; +/// let tree = parser.parse("", None).unwrap(); +/// let mut cursor = tree.walk(); +/// let next_state = cursor.node().next_parse_state(); +/// if let Some(mut lookahead) = language.lookahead_iterator(next_state) { +/// let _ = lookahead.next(); +/// let names = lookahead.iter_names(); +/// let _ = names.next(); +/// } +/// ``` + +fn _dummy() {} diff --git a/lib/binding_rust/lib.rs b/lib/binding_rust/lib.rs index 8e6b091a..ad20507e 100644 --- a/lib/binding_rust/lib.rs +++ b/lib/binding_rust/lib.rs @@ -90,6 +90,7 @@ pub struct Parser(NonNull); /// A stateful object that is used to look up symbols valid in a specific parse state #[doc(alias = "TSLookaheadIterator")] pub struct LookaheadIterator(NonNull); +struct LookaheadNamesIterator<'a>(&'a mut LookaheadIterator); /// A type of log message. #[derive(Debug, PartialEq, Eq)] @@ -1525,7 +1526,7 @@ impl LookaheadIterator { /// This returns `true` if the language was set successfully and `false` /// otherwise. #[doc(alias = "ts_lookahead_iterator_reset")] - pub fn reset(&self, language: Language, state: u16) -> bool { + pub fn reset(&mut self, language: Language, state: u16) -> bool { unsafe { ffi::ts_lookahead_iterator_reset(self.0.as_ptr(), language.0, state) } } @@ -1534,19 +1535,17 @@ impl LookaheadIterator { /// This returns `true` if the iterator was reset to the given state and `false` /// otherwise. #[doc(alias = "ts_lookahead_iterator_reset_state")] - pub fn reset_state(&self, state: u16) -> bool { + pub fn reset_state(&mut self, state: u16) -> bool { unsafe { ffi::ts_lookahead_iterator_reset_state(self.0.as_ptr(), state) } } /// Iterate symbol names. - pub fn iter_names<'a>(&'a self) -> impl Iterator + 'a { - NameLookaheadIterator(&self) + pub fn iter_names(&mut self) -> impl Iterator + '_ { + LookaheadNamesIterator(self) } } -struct NameLookaheadIterator<'a>(&'a LookaheadIterator); - -impl<'a> Iterator for NameLookaheadIterator<'a> { +impl Iterator for LookaheadNamesIterator<'_> { type Item = &'static str; #[doc(alias = "ts_lookahead_iterator_advance")] @@ -2647,6 +2646,12 @@ unsafe impl Sync for Language {} unsafe impl Send for Node<'_> {} unsafe impl Sync for Node<'_> {} +unsafe impl Send for LookaheadIterator {} +unsafe impl Sync for LookaheadIterator {} + +unsafe impl Send for LookaheadNamesIterator<'_> {} +unsafe impl Sync for LookaheadNamesIterator<'_> {} + unsafe impl Send for Parser {} unsafe impl Sync for Parser {}