Skip to content

Commit 335c6e8

Browse files
committed
core: Allow traversal functions to take a single property name
1 parent 5b5e6e5 commit 335c6e8

File tree

4 files changed

+203
-103
lines changed

4 files changed

+203
-103
lines changed

core/src/cursor.rs

Lines changed: 155 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::{
55
};
66

77
use emacs::{defun, Result, Value, Env, GlobalRef, Vector, IntoLisp, FromLisp};
8-
use tree_sitter::{Tree, TreeCursor};
8+
use tree_sitter::{Tree, TreeCursor, Node};
99

1010
use crate::{
1111
types::{self, Shared, BytePos},
@@ -121,7 +121,7 @@ impl<'e> FromLisp<'e> for TreeOrNode<'e> {
121121
return Ok(Self::Tree(value));
122122
}
123123
if let Ok(value) = value.into_rust() {
124-
return Ok(Self::Node(value))
124+
return Ok(Self::Node(value));
125125
}
126126
value.env.signal(wrong_type_argument, (tree_or_node_p, value))
127127
}
@@ -231,20 +231,12 @@ struct DepthFirstIterator {
231231
// TODO: Provide a function to move backward.
232232
impl DepthFirstIterator {
233233
fn new(tree_or_node: TreeOrNode) -> Self {
234-
Self {
235-
cursor: tree_or_node.walk(),
236-
state: Start,
237-
depth: 0,
238-
}
234+
Self { cursor: tree_or_node.walk(), state: Start, depth: 0 }
239235
}
240236

241237
#[inline]
242238
fn item(&self) -> Option<(RNode, usize)> {
243-
Some((
244-
RNode::new(self.cursor.clone_tree(),
245-
|_| self.cursor.borrow().node()),
246-
self.depth,
247-
))
239+
Some((RNode::new(self.cursor.clone_tree(), |_| self.cursor.borrow().node()), self.depth))
248240
}
249241

250242
fn close(&mut self) {
@@ -282,7 +274,7 @@ impl Iterator for DepthFirstIterator {
282274
self.next()
283275
}
284276
}
285-
Done => None
277+
Done => None,
286278
}
287279
}
288280
}
@@ -308,130 +300,205 @@ fn _iter_close(iterator: &mut DepthFirstIterator) -> Result<()> {
308300
Ok(iterator.close())
309301
}
310302

311-
/// Retrieve properties of the node that ITERATOR is currently on.
303+
#[derive(Clone, Copy)]
304+
enum VectorOrKeyword<'e> {
305+
Vector(Vector<'e>),
306+
Keyword(Value<'e>),
307+
}
308+
309+
impl<'e> FromLisp<'e> for VectorOrKeyword<'e> {
310+
fn from_lisp(value: Value<'e>) -> Result<Self> {
311+
if let Ok(value) = value.into_rust::<Vector>() {
312+
Ok(Self::Vector(value))
313+
} else {
314+
// TODO: Verify that it's a valid node property
315+
Ok(Self::Keyword(value))
316+
}
317+
}
318+
}
319+
320+
/// Return the properties of ITERATOR's current node, or the node itself.
321+
///
322+
/// If PROPS is a vector of property names, return a vector containing the node's
323+
/// corresponding properties. If OUTPUT is also non-nil, it must be a vector of the
324+
/// same length, where the properties will be written into.
325+
///
326+
/// If PROPS is a single property name, return that property.
327+
///
328+
/// If PROPS is nil, return the node itself.
312329
///
313-
/// PROPS is a vector of property names to retrieve.
314-
/// OUTPUT is a vector where the properties will be written to.
330+
/// See `tsc-valid-node-props' for the list of available properties.
315331
#[defun]
316-
fn _iter_current_node(iterator: &mut DepthFirstIterator, props: Vector, output: Vector) -> Result<()> {
317-
let env = output.value().env;
332+
fn _iter_current_node<'e>(
333+
iterator: &mut DepthFirstIterator,
334+
props: Option<VectorOrKeyword<'e>>,
335+
output: Option<Vector<'e>>,
336+
env: &'e Env,
337+
) -> Result<Value<'e>> {
318338
let cursor = &iterator.cursor;
319-
let _ = _current_node(cursor, Some(props), Some(output), env)?;
320-
for (i, prop) in props.into_iter().enumerate() {
321-
if prop.eq(_depth.bind(env)) {
322-
output.set(i, iterator.depth)?;
339+
match props {
340+
Some(VectorOrKeyword::Keyword(prop)) if prop.eq(_depth.bind(env)) => {
341+
iterator.depth.into_lisp(env)
342+
}
343+
_ => {
344+
let result = _current_node(cursor, props, output, env)?;
345+
if let Some(VectorOrKeyword::Vector(props)) = props {
346+
if let Some(output) = output {
347+
for (i, prop) in props.into_iter().enumerate() {
348+
if prop.eq(_depth.bind(env)) {
349+
output.set(i, iterator.depth)?;
350+
}
351+
}
352+
} else {
353+
todo!()
354+
}
355+
}
356+
Ok(result)
323357
}
324358
}
325-
Ok(())
326359
}
327360

328-
/// Move ITERATOR to the next node, and retrieve its properties.
361+
/// Move ITERATOR to the next node, and retrieve its properties, or the node itself.
329362
///
330363
/// This a combination of `tsc--iter-next' and `tsc--iter-current-node'.
331364
#[defun]
332-
fn _iter_next_node(iterator: &mut DepthFirstIterator, props: Vector, output: Vector) -> Result<bool> {
365+
fn _iter_next_node<'e>(
366+
iterator: &mut DepthFirstIterator,
367+
props: Option<VectorOrKeyword<'e>>,
368+
output: Option<Vector<'e>>,
369+
env: &'e Env,
370+
) -> Result<Option<Value<'e>>> {
333371
if iterator.next().is_some() {
334-
_iter_current_node(iterator, props, output)?;
335-
Ok(true)
372+
Ok(Some(_iter_current_node(iterator, props, output, env)?))
336373
} else {
337-
Ok(false)
374+
Ok(None)
338375
}
339376
}
340377

341-
/// Return CURSOR's current node, if PROPS is nil.
342-
///
343-
/// If PROPS is a vector of property names, this function returns a vector
344-
/// containing the node's corresponding properties instead of the node itself. If
345-
/// OUTPUT is also a vector, this function overwrites its contents instead of
346-
/// creating a new vector.
347-
///
348-
/// See `tsc-valid-node-props' for the list of available properties.
349-
#[defun]
350-
fn _current_node<'e>(cursor: &RCursor, props: Option<Vector<'e>>, output: Option<Vector<'e>>, env: &'e Env) -> Result<Value<'e>> {
378+
fn get<'e>(prop: Value<'e>, node: Node, cursor: &RCursor) -> Result<Value<'e>> {
351379
macro_rules! sugar {
352380
($prop:ident, $env:ident) => {
353381
macro_rules! eq {
354-
($name:ident) => ($prop.eq($name.bind($env)))
382+
($name:ident) => {
383+
$prop.eq($name.bind($env))
384+
};
355385
}
356-
}
386+
};
387+
}
388+
let env = prop.env;
389+
sugar!(prop, env);
390+
if eq!(_type) {
391+
node.lisp_type().into_lisp(env)
392+
} else if eq!(_byte_range) {
393+
node.lisp_byte_range(env)
394+
} else if eq!(_start_byte) {
395+
node.lisp_start_byte().into_lisp(env)
396+
} else if eq!(_end_byte) {
397+
node.lisp_end_byte().into_lisp(env)
398+
} else if eq!(_field) {
399+
current_field(cursor)?.into_lisp(env)
400+
} else if eq!(_named_p) {
401+
node.is_named().into_lisp(env)
402+
} else if eq!(_extra_p) {
403+
node.is_extra().into_lisp(env)
404+
} else if eq!(_error_p) {
405+
node.is_error().into_lisp(env)
406+
} else if eq!(_missing_p) {
407+
node.is_missing().into_lisp(env)
408+
} else if eq!(_has_error_p) {
409+
node.has_error().into_lisp(env)
410+
} else if eq!(_start_point) {
411+
node.lisp_start_point().into_lisp(env)
412+
} else if eq!(_end_point) {
413+
node.lisp_end_point().into_lisp(env)
414+
} else if eq!(_range) {
415+
node.lisp_range().into_lisp(env)
416+
} else {
417+
().into_lisp(env)
357418
}
419+
}
420+
421+
/// Return the properties of CURSOR's current node, or the node itself.
422+
///
423+
/// If PROPS is a vector of property names, return a vector containing the node's
424+
/// corresponding properties. If OUTPUT is also non-nil, it must be a vector of the
425+
/// same length, where the properties will be written into.
426+
///
427+
/// If PROPS is a single property name, return that property.
428+
///
429+
/// If PROPS is nil, return the node itself.
430+
///
431+
/// See `tsc-valid-node-props' for the list of available properties.
432+
#[defun]
433+
fn _current_node<'e>(
434+
cursor: &RCursor,
435+
props: Option<VectorOrKeyword<'e>>,
436+
output: Option<Vector<'e>>,
437+
env: &'e Env,
438+
) -> Result<Value<'e>> {
358439
let node = cursor.borrow().node();
359440
match props {
360441
None => RNode::new(cursor.clone_tree(), |_| node).into_lisp(env),
361-
Some(props) => {
442+
Some(VectorOrKeyword::Vector(props)) => {
362443
let result = match output {
363444
None => env.make_vector(props.len(), ())?,
364445
Some(output) => output,
365446
};
366447
for (i, prop) in props.into_iter().enumerate() {
367-
sugar!(prop, env);
368-
if eq!(_type) {
369-
result.set(i, node.lisp_type())?;
370-
} else if eq!(_byte_range) {
371-
result.set(i, node.lisp_byte_range(env)?)?;
372-
} else if eq!(_start_byte) {
373-
result.set(i, node.lisp_start_byte())?;
374-
} else if eq!(_end_byte) {
375-
result.set(i, node.lisp_end_byte())?;
376-
} else if eq!(_field) {
377-
result.set(i, current_field(cursor)?)?;
378-
} else if eq!(_named_p) {
379-
result.set(i, node.is_named())?;
380-
} else if eq!(_extra_p) {
381-
result.set(i, node.is_extra())?;
382-
} else if eq!(_error_p) {
383-
result.set(i, node.is_error())?;
384-
} else if eq!(_missing_p) {
385-
result.set(i, node.is_missing())?;
386-
} else if eq!(_has_error_p) {
387-
result.set(i, node.has_error())?;
388-
} else if eq!(_start_point) {
389-
result.set(i, node.lisp_start_point())?;
390-
} else if eq!(_end_point) {
391-
result.set(i, node.lisp_end_point())?;
392-
} else if eq!(_range) {
393-
result.set(i, node.lisp_range())?;
394-
} else {
395-
result.set(i, ())?;
396-
}
448+
result.set(i, get(prop, node, cursor)?)?;
397449
}
398450
result.into_lisp(env)
399451
}
452+
Some(VectorOrKeyword::Keyword(prop)) => get(prop, node, cursor),
400453
}
401454
}
402455

403456
/// Actual logic of `tsc-traverse-mapc'. The wrapper is needed because
404457
/// `emacs-module-rs' doesn't currently support optional arguments.
405458
#[defun]
406-
fn _traverse_mapc(func: Value, tree_or_node: TreeOrNode, props: Option<Vector>) -> Result<()> {
459+
fn _traverse_mapc(
460+
func: Value,
461+
tree_or_node: TreeOrNode,
462+
props: Option<VectorOrKeyword>,
463+
) -> Result<()> {
407464
let mut iterator = DepthFirstIterator::new(tree_or_node);
408465
let env = func.env;
409-
let output = match props {
410-
None => None,
411-
Some(props) => Some(env.make_vector(props.len(), ())?),
412-
};
466+
let mut output = None;
413467
let mut depth_indexes = Vec::with_capacity(1);
414-
if let Some(props) = props {
415-
for (i, prop) in props.into_iter().enumerate() {
416-
if prop.eq(_depth.bind(env)) {
417-
depth_indexes.push(i)
468+
let mut depth = false;
469+
match props {
470+
Some(VectorOrKeyword::Vector(props)) => {
471+
output = Some(env.make_vector(props.len(), ())?);
472+
for (i, prop) in props.into_iter().enumerate() {
473+
if prop.eq(_depth.bind(env)) {
474+
depth_indexes.push(i)
475+
}
418476
}
419477
}
478+
Some(VectorOrKeyword::Keyword(prop)) if prop.eq(_depth.bind(env)) => {
479+
depth = true;
480+
}
481+
_ => {}
420482
}
421483
// Can't use a for loop because we need to access the cursor to process each item.
422484
let mut item: Option<(RNode, usize)> = iterator.next();
423485
while item.is_some() {
424-
let result = _current_node(&iterator.cursor, props, output, env)?;
425-
// let (_, depth) = item.unwrap();
426-
427-
if let Some(output) = output {
428-
for i in &depth_indexes {
429-
output.set(*i, iterator.depth)?;
486+
let result = if depth {
487+
iterator.depth.into_lisp(env)?
488+
} else {
489+
let result = _current_node(&iterator.cursor, props, output, env)?;
490+
if let Some(output) = output {
491+
for i in &depth_indexes {
492+
output.set(*i, iterator.depth)?;
493+
}
430494
}
431-
}
495+
result
496+
};
432497

433498
// Safety: the returned value is unused.
434-
unsafe { func.call_unprotected([result])?; }
499+
unsafe {
500+
func.call_unprotected([result])?;
501+
}
435502

436503
// // Safety: the returned value is unused.
437504
// unsafe { func.call_unprotected((result, depth))?; }

0 commit comments

Comments
 (0)