#![allow(dead_code)] #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] include!("./bindings.rs"); extern "C" { pub(crate) fn dup(fd: std::os::raw::c_int) -> std::os::raw::c_int; } use crate::{ predicate_error, Language, Node, Parser, Query, QueryCursor, QueryError, QueryPredicate, QueryPredicateArg, TextPredicate, Tree, TreeCursor, }; use std::{marker::PhantomData, mem::ManuallyDrop, ptr::NonNull, slice, str}; impl Language { /// Reconstructs a [Language] from a raw pointer. /// /// # Safety /// /// `ptr` must be non-null. pub unsafe fn from_raw(ptr: *mut TSLanguage) -> Language { Language(ptr) } /// Consumes the [Language], returning a raw pointer to the underlying C structure. pub fn into_raw(self) -> *const TSLanguage { ManuallyDrop::new(self).0 } } impl Parser { /// Reconstructs a [Parser] from a raw pointer. /// /// # Safety /// /// `ptr` must be non-null. pub unsafe fn from_raw(ptr: *mut TSParser) -> Parser { Parser(NonNull::new_unchecked(ptr)) } /// Consumes the [Parser], returning a raw pointer to the underlying C structure. pub fn into_raw(mut self) -> *mut TSParser { self.stop_printing_dot_graphs(); self.set_logger(None); ManuallyDrop::new(self).0.as_ptr() } } impl Tree { /// Reconstructs a [Tree] from a raw pointer. /// /// # Safety /// /// `ptr` must be non-null. pub unsafe fn from_raw(ptr: *mut TSTree) -> Tree { Tree(NonNull::new_unchecked(ptr)) } /// Consumes the [Tree], returning a raw pointer to the underlying C structure. pub fn into_raw(self) -> *mut TSTree { ManuallyDrop::new(self).0.as_ptr() } } impl<'tree> Node<'tree> { /// Reconstructs a [Node] from a raw pointer. /// /// # Safety /// /// `ptr` must be non-null. pub unsafe fn from_raw(ptr: *mut TSNode) -> Node<'tree> { Node(*ptr, PhantomData) } /// Consumes the [Node], returning a raw pointer to the underlying C structure. pub fn into_raw(self) -> *mut TSNode { &mut ManuallyDrop::new(self).0 } } impl<'a> TreeCursor<'a> { /// Reconstructs a [TreeCursor] from a raw pointer. /// /// # Safety /// /// `ptr` must be non-null. pub unsafe fn from_raw(ptr: *mut TSTreeCursor) -> TreeCursor<'a> { TreeCursor(*ptr, PhantomData) } /// Consumes the [TreeCursor], returning a raw pointer to the underlying C structure. pub fn into_raw(self) -> *mut TSTreeCursor { &mut ManuallyDrop::new(self).0 } } impl Query { /// Reconstructs a [Query] from a raw pointer. /// /// # Safety /// /// `ptr` must be non-null. pub unsafe fn from_raw(ptr: *mut TSQuery, source: &str) -> Result { let string_count = unsafe { ts_query_string_count(ptr) }; let capture_count = unsafe { ts_query_capture_count(ptr) }; let pattern_count = unsafe { ts_query_pattern_count(ptr) as usize }; let mut result = Query { ptr: unsafe { NonNull::new_unchecked(ptr) }, capture_names: Vec::with_capacity(capture_count as usize), capture_quantifiers: Vec::with_capacity(pattern_count as usize), text_predicates: Vec::with_capacity(pattern_count), property_predicates: Vec::with_capacity(pattern_count), property_settings: Vec::with_capacity(pattern_count), general_predicates: Vec::with_capacity(pattern_count), }; // Build a vector of strings to store the capture names. for i in 0..capture_count { unsafe { let mut length = 0u32; let name = ts_query_capture_name_for_id(ptr, i, &mut length as *mut u32) as *const u8; let name = slice::from_raw_parts(name, length as usize); let name = str::from_utf8_unchecked(name); result.capture_names.push(name.to_string()); } } // Build a vector to store capture qunatifiers. for i in 0..pattern_count { let mut capture_quantifiers = Vec::with_capacity(capture_count as usize); for j in 0..capture_count { unsafe { let quantifier = ts_query_capture_quantifier_for_id(ptr, i as u32, j); capture_quantifiers.push(quantifier.into()); } } result.capture_quantifiers.push(capture_quantifiers); } // Build a vector of strings to represent literal values used in predicates. let string_values = (0..string_count) .map(|i| unsafe { let mut length = 0u32; let value = ts_query_string_value_for_id(ptr, i as u32, &mut length as *mut u32) as *const u8; let value = slice::from_raw_parts(value, length as usize); let value = str::from_utf8_unchecked(value); value.to_string() }) .collect::>(); // Build a vector of predicates for each pattern. for i in 0..pattern_count { let predicate_steps = unsafe { let mut length = 0u32; let raw_predicates = ts_query_predicates_for_pattern(ptr, i as u32, &mut length as *mut u32); if length > 0 { slice::from_raw_parts(raw_predicates, length as usize) } else { &[] } }; let byte_offset = unsafe { ts_query_start_byte_for_pattern(ptr, i as u32) }; let row = source .char_indices() .take_while(|(i, _)| *i < byte_offset as usize) .filter(|(_, c)| *c == '\n') .count(); let type_done = TSQueryPredicateStepType_TSQueryPredicateStepTypeDone; let type_capture = TSQueryPredicateStepType_TSQueryPredicateStepTypeCapture; let type_string = TSQueryPredicateStepType_TSQueryPredicateStepTypeString; let mut text_predicates = Vec::new(); let mut property_predicates = Vec::new(); let mut property_settings = Vec::new(); let mut general_predicates = Vec::new(); for p in predicate_steps.split(|s| s.type_ == type_done) { if p.is_empty() { continue; } if p[0].type_ != type_string { return Err(predicate_error( row, format!( "Expected predicate to start with a function name. Got @{}.", result.capture_names[p[0].value_id as usize], ), )); } // Build a predicate for each of the known predicate function names. let operator_name = &string_values[p[0].value_id as usize]; match operator_name.as_str() { "eq?" | "not-eq?" => { if p.len() != 3 { return Err(predicate_error( row, format!( "Wrong number of arguments to #eq? predicate. Expected 2, got {}.", p.len() - 1 ), )); } if p[1].type_ != type_capture { return Err(predicate_error(row, format!( "First argument to #eq? predicate must be a capture name. Got literal \"{}\".", string_values[p[1].value_id as usize], ))); } let is_positive = operator_name == "eq?"; text_predicates.push(if p[2].type_ == type_capture { TextPredicate::CaptureEqCapture( p[1].value_id, p[2].value_id, is_positive, ) } else { TextPredicate::CaptureEqString( p[1].value_id, string_values[p[2].value_id as usize].clone(), is_positive, ) }); } "match?" | "not-match?" => { if p.len() != 3 { return Err(predicate_error(row, format!( "Wrong number of arguments to #match? predicate. Expected 2, got {}.", p.len() - 1 ))); } if p[1].type_ != type_capture { return Err(predicate_error(row, format!( "First argument to #match? predicate must be a capture name. Got literal \"{}\".", string_values[p[1].value_id as usize], ))); } if p[2].type_ == type_capture { return Err(predicate_error(row, format!( "Second argument to #match? predicate must be a literal. Got capture @{}.", result.capture_names[p[2].value_id as usize], ))); } let is_positive = operator_name == "match?"; let regex = &string_values[p[2].value_id as usize]; text_predicates.push(TextPredicate::CaptureMatchString( p[1].value_id, regex::bytes::Regex::new(regex).map_err(|_| { predicate_error(row, format!("Invalid regex '{}'", regex)) })?, is_positive, )); } "set!" => property_settings.push(Self::parse_property( row, &operator_name, &result.capture_names, &string_values, &p[1..], )?), "is?" | "is-not?" => property_predicates.push(( Self::parse_property( row, &operator_name, &result.capture_names, &string_values, &p[1..], )?, operator_name == "is?", )), _ => general_predicates.push(QueryPredicate { operator: operator_name.clone().into_boxed_str(), args: p[1..] .iter() .map(|a| { if a.type_ == type_capture { QueryPredicateArg::Capture(a.value_id) } else { QueryPredicateArg::String( string_values[a.value_id as usize].clone().into_boxed_str(), ) } }) .collect(), }), } } result .text_predicates .push(text_predicates.into_boxed_slice()); result .property_predicates .push(property_predicates.into_boxed_slice()); result .property_settings .push(property_settings.into_boxed_slice()); result .general_predicates .push(general_predicates.into_boxed_slice()); } Ok(result) } /// Consumes the [Query], returning a raw pointer to the underlying C structure. pub fn into_raw(self) -> *mut TSQuery { ManuallyDrop::new(self).ptr.as_ptr() } } impl QueryCursor { /// Reconstructs a [QueryCursor] from a raw pointer. /// /// # Safety /// /// `ptr` must be non-null. pub unsafe fn from_raw(ptr: *mut TSQueryCursor) -> QueryCursor { QueryCursor { ptr: NonNull::new_unchecked(ptr), } } /// Consumes the [QueryCursor], returning a raw pointer to the underlying C structure. pub fn into_raw(self) -> *mut TSQueryCursor { ManuallyDrop::new(self).ptr.as_ptr() } }