2023-04-11 19:16:04 -04:00
|
|
|
use crate::parser::Source;
|
|
|
|
|
2023-04-19 15:19:21 -04:00
|
|
|
use super::sexp::Token;
|
|
|
|
|
2023-04-11 19:16:04 -04:00
|
|
|
/// Check if the child string slice is a slice of the parent string slice.
|
|
|
|
fn is_slice_of(parent: &str, child: &str) -> bool {
|
|
|
|
let parent_start = parent.as_ptr() as usize;
|
|
|
|
let parent_end = parent_start + parent.len();
|
|
|
|
let child_start = child.as_ptr() as usize;
|
|
|
|
let child_end = child_start + child.len();
|
|
|
|
child_start >= parent_start && child_end <= parent_end
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the offset into source that the rust object exists at.
|
|
|
|
///
|
|
|
|
/// These offsets are zero-based unlike the elisp ones.
|
|
|
|
pub fn get_offsets<'s, S: Source<'s>>(source: &'s str, rust_object: &'s S) -> (usize, usize) {
|
|
|
|
let rust_object_source = rust_object.get_source();
|
|
|
|
assert!(is_slice_of(source, rust_object_source));
|
|
|
|
let offset = rust_object_source.as_ptr() as usize - source.as_ptr() as usize;
|
|
|
|
let end = offset + rust_object_source.len();
|
|
|
|
(offset, end)
|
|
|
|
}
|
2023-04-19 15:19:21 -04:00
|
|
|
|
|
|
|
pub fn assert_name<'s>(emacs: &'s Token<'s>, name: &str) -> Result<(), Box<dyn std::error::Error>> {
|
|
|
|
let children = emacs.as_list()?;
|
|
|
|
let first_child = children
|
|
|
|
.first()
|
|
|
|
.ok_or("Should have at least one child.")?
|
|
|
|
.as_atom()?;
|
|
|
|
if first_child != name {
|
|
|
|
Err(format!(
|
|
|
|
"Expected a {expected} cell, but found a {found} cell.",
|
|
|
|
expected = name,
|
|
|
|
found = first_child
|
|
|
|
))?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|