1use derive_more::{Display, Error};
5
6use crate::interpreter::environment::Environment;
7use crate::interpreter::value::*;
8use crate::interpreter::Interpreter;
9use crate::parser::ast::{Arg, Expr};
10
11#[derive(Debug, Display, Error)]
15pub enum IndexingError {
16 #[display("can't mix positive and negative subscripts")]
17 MixedSubscripts,
18
19 #[display("invalid index type")]
20 InvalidIndexType,
21
22 #[display("object is not subsettable")]
23 NotSubsettable,
24
25 #[display("incorrect number of dimensions")]
26 IncorrectDimensions,
27
28 #[display("subscript out of bounds (no dimnames to match against)")]
29 NoDimnames,
30
31 #[display("subscript out of bounds: '{}'", name)]
32 SubscriptOutOfBounds { name: String },
33
34 #[display("invalid subscript type")]
35 InvalidSubscriptType,
36
37 #[display("undefined row selected: '{}'", name)]
38 UndefinedRow { name: String },
39}
40
41impl From<IndexingError> for RError {
42 fn from(e: IndexingError) -> Self {
43 RError::from_source(RErrorKind::Index, e)
44 }
45}
46
47impl From<IndexingError> for RFlow {
48 fn from(e: IndexingError) -> Self {
49 RFlow::Error(RError::from(e))
50 }
51}
52
53impl Interpreter {
56 pub(super) fn eval_index(
57 &self,
58 object: &Expr,
59 indices: &[Arg],
60 env: &Environment,
61 ) -> Result<RValue, RFlow> {
62 eval_index(self, object, indices, env)
63 }
64
65 #[cfg(feature = "random")]
66 pub(crate) fn index_by_integer(
67 &self,
68 v: &Vector,
69 indices: &[Option<i64>],
70 ) -> Result<RValue, RFlow> {
71 index_by_integer(self, v, indices)
72 }
73
74 pub(super) fn eval_index_double(
75 &self,
76 object: &Expr,
77 indices: &[Arg],
78 env: &Environment,
79 ) -> Result<RValue, RFlow> {
80 eval_index_double(self, object, indices, env)
81 }
82
83 pub(super) fn eval_dollar(
84 &self,
85 object: &Expr,
86 member: &str,
87 env: &Environment,
88 ) -> Result<RValue, RFlow> {
89 eval_dollar(self, object, member, env)
90 }
91}
92
93pub(super) fn eval_index(
94 interp: &Interpreter,
95 object: &Expr,
96 indices: &[Arg],
97 env: &Environment,
98) -> Result<RValue, RFlow> {
99 let obj = interp.eval_in(object, env)?;
100
101 if indices.is_empty() {
102 return Ok(obj);
103 }
104
105 if indices.len() >= 2 {
106 return eval_matrix_index(interp, &obj, indices, env);
107 }
108
109 let idx_val = if let Some(val_expr) = &indices[0].value {
110 interp.eval_in(val_expr, env)?
111 } else {
112 return Ok(obj);
113 };
114
115 match &obj {
116 RValue::Vector(v) => match &idx_val {
117 RValue::Vector(idx_vec) => {
118 if let Vector::Logical(mask) = &idx_vec.inner {
119 return index_by_logical(interp, v, mask);
120 }
121
122 if let Vector::Character(idx_names) = &idx_vec.inner {
124 let names_attr = v.get_attr("names").and_then(|a| a.as_vector());
125 let name_strs: Vec<Option<String>> =
126 names_attr.map(|nv| nv.to_characters()).unwrap_or_default();
127 let positions: Vec<Option<i64>> = idx_names
128 .iter()
129 .map(|idx_name| {
130 idx_name.as_ref().and_then(|name| {
131 name_strs
132 .iter()
133 .position(|n| n.as_deref() == Some(name.as_str()))
134 .and_then(|p| i64::try_from(p + 1).ok())
135 })
136 })
137 .collect();
138 return index_by_integer(interp, v, &positions);
139 }
140
141 let indices = idx_vec.to_integers();
142 let nonzero: Vec<Option<i64>> = indices
144 .iter()
145 .filter(|x| !matches!(x, Some(0)))
146 .copied()
147 .collect();
148 let has_pos = nonzero.iter().any(|x| x.map(|i| i > 0).unwrap_or(false));
149 let has_neg = nonzero.iter().any(|x| x.map(|i| i < 0).unwrap_or(false));
150 if has_pos && has_neg {
151 return Err(IndexingError::MixedSubscripts.into());
152 }
153 if has_neg {
154 return index_by_negative(interp, v, &nonzero);
155 }
156 index_by_integer(interp, v, &nonzero)
157 }
158 RValue::Null => Ok(obj.clone()),
159 _ => Err(IndexingError::InvalidIndexType.into()),
160 },
161 RValue::List(list) => match &idx_val {
162 RValue::Vector(idx_vec) => {
163 if let Vector::Character(names) = &idx_vec.inner {
164 let mut result = Vec::new();
165 for name in names.iter().flatten() {
166 let found = list
167 .values
168 .iter()
169 .find(|(n, _)| n.as_ref() == Some(name))
170 .map(|(n, v)| (n.clone(), v.clone()));
171 if let Some(item) = found {
172 result.push(item);
173 }
174 }
175 return Ok(RValue::List(RList::new(result)));
176 }
177
178 let indices = idx_vec.to_integers();
179 let nonzero: Vec<Option<i64>> = indices
181 .iter()
182 .filter(|x| !matches!(x, Some(0)))
183 .copied()
184 .collect();
185 let has_pos = nonzero.iter().any(|x| x.map(|i| i > 0).unwrap_or(false));
186 let has_neg = nonzero.iter().any(|x| x.map(|i| i < 0).unwrap_or(false));
187 if has_pos && has_neg {
188 return Err(IndexingError::MixedSubscripts.into());
189 }
190 if has_neg {
191 let exclude: Vec<usize> = nonzero
193 .iter()
194 .filter_map(|x| x.and_then(|i| usize::try_from(-i).ok()))
195 .collect();
196 let result: Vec<_> = list
197 .values
198 .iter()
199 .enumerate()
200 .filter(|(i, _)| !exclude.contains(&(i + 1)))
201 .map(|(_, v)| v.clone())
202 .collect();
203 return Ok(RValue::List(RList::new(result)));
204 }
205 let mut result = Vec::new();
206 for i in nonzero.iter().flatten() {
207 let i = usize::try_from(*i).unwrap_or(0);
208 if i > 0 && i <= list.values.len() {
209 result.push(list.values[i - 1].clone());
210 }
211 }
212 Ok(RValue::List(RList::new(result)))
213 }
214 _ => Err(IndexingError::InvalidIndexType.into()),
215 },
216 RValue::Environment(target_env) => {
217 match &idx_val {
219 RValue::Vector(idx_vec) => {
220 if let Vector::Character(names) = &idx_vec.inner {
221 let mut result = Vec::new();
222 for name in names.iter().flatten() {
223 let val = target_env.get(name).unwrap_or(RValue::Null);
224 result.push((Some(name.clone()), val));
225 }
226 return Ok(RValue::List(RList::new(result)));
227 }
228 Err(IndexingError::InvalidIndexType.into())
229 }
230 RValue::Null => Ok(RValue::List(RList::new(Vec::new()))),
231 _ => Err(IndexingError::InvalidIndexType.into()),
232 }
233 }
234 RValue::Null => Ok(RValue::Null),
236 _ => Err(IndexingError::NotSubsettable.into()),
237 }
238}
239
240fn eval_matrix_index(
241 interp: &Interpreter,
242 obj: &RValue,
243 indices: &[Arg],
244 env: &Environment,
245) -> Result<RValue, RFlow> {
246 let (data, dim_attr) = match obj {
247 RValue::Vector(rv) => (&rv.inner, rv.get_attr("dim")),
248 RValue::List(list) => {
249 return eval_list_2d_index(interp, list, indices, env);
250 }
251 _ => {
252 return Err(IndexingError::IncorrectDimensions.into());
253 }
254 };
255
256 let dims: Vec<Option<i64>> = match dim_attr {
257 Some(RValue::Vector(rv)) => match &rv.inner {
258 Vector::Integer(d) => d.iter_opt().collect(),
259 _ => {
260 return Err(IndexingError::IncorrectDimensions.into());
261 }
262 },
263 _ => {
264 return Err(IndexingError::IncorrectDimensions.into());
265 }
266 };
267
268 if dims.len() < 2 {
269 return Err(IndexingError::IncorrectDimensions.into());
270 }
271 let nrow = usize::try_from(dims[0].unwrap_or(0)).unwrap_or(0);
272 let ncol = usize::try_from(dims[1].unwrap_or(0)).unwrap_or(0);
273
274 let row_idx = if let Some(val_expr) = &indices[0].value {
275 Some(interp.eval_in(val_expr, env)?)
276 } else {
277 None
278 };
279
280 let col_idx = if let Some(val_expr) = &indices[1].value {
281 Some(interp.eval_in(val_expr, env)?)
282 } else {
283 None
284 };
285
286 let dimnames = match obj {
288 RValue::Vector(rv) => rv.get_attr("dimnames"),
289 _ => None,
290 };
291 let row_names = extract_dim_names(dimnames, 0);
292 let col_names = extract_dim_names(dimnames, 1);
293
294 let rows: Vec<usize> = resolve_dim_index(&row_idx, nrow, &row_names)?;
295 let cols: Vec<usize> = resolve_dim_index(&col_idx, ncol, &col_names)?;
296
297 let flat_indices: Vec<usize> = cols
299 .iter()
300 .flat_map(|&j| rows.iter().map(move |&i| j * nrow + i))
301 .collect();
302
303 let result = data.select_indices(&flat_indices);
304
305 if rows.len() == 1 && cols.len() == 1 {
306 return Ok(RValue::vec(result));
307 }
308
309 let mut rv = RVector::from(result);
310 if rows.len() > 1 || cols.len() > 1 {
311 rv.set_attr(
312 "dim".to_string(),
313 RValue::vec(Vector::Integer(
314 vec![
315 Some(i64::try_from(rows.len())?),
316 Some(i64::try_from(cols.len())?),
317 ]
318 .into(),
319 )),
320 );
321 }
322 Ok(RValue::Vector(rv))
323}
324
325fn eval_list_2d_index(
326 interp: &Interpreter,
327 list: &RList,
328 indices: &[Arg],
329 env: &Environment,
330) -> Result<RValue, RFlow> {
331 let is_df = if let Some(RValue::Vector(rv)) = list.get_attr("class") {
332 if let Vector::Character(cls) = &rv.inner {
333 cls.iter().any(|c| c.as_deref() == Some("data.frame"))
334 } else {
335 false
336 }
337 } else {
338 false
339 };
340 if !is_df {
341 if let Some(val_expr) = &indices[0].value {
342 let idx_val = interp.eval_in(val_expr, env)?;
343 return match &idx_val {
344 RValue::Vector(iv) => {
345 let i = usize::try_from(iv.as_integer_scalar().unwrap_or(0)).unwrap_or(0);
346 if i > 0 && i <= list.values.len() {
347 Ok(list.values[i - 1].1.clone())
348 } else {
349 Ok(RValue::Null)
350 }
351 }
352 _ => Ok(RValue::Null),
353 };
354 }
355 return Ok(RValue::Null);
356 }
357
358 let drop = extract_drop_arg(interp, indices, env)?;
360
361 let col_idx = if let Some(val_expr) = &indices[1].value {
362 Some(interp.eval_in(val_expr, env)?)
363 } else {
364 None
365 };
366
367 let selected_cols: Vec<(Option<String>, RValue)> = match &col_idx {
368 None => list.values.clone(),
369 Some(RValue::Vector(rv)) if matches!(rv.inner, Vector::Character(_)) => {
370 let Vector::Character(names) = &rv.inner else {
371 unreachable!()
372 };
373 names
374 .iter()
375 .filter_map(|n| {
376 n.as_ref().and_then(|name| {
377 list.values
378 .iter()
379 .find(|(k, _)| k.as_ref() == Some(name))
380 .cloned()
381 })
382 })
383 .collect()
384 }
385 Some(RValue::Vector(rv)) => {
386 let idxs = rv.to_integers();
387 idxs.iter()
388 .filter_map(|i| {
389 i.and_then(|i| {
390 let i = usize::try_from(i - 1).ok()?;
391 list.values.get(i).cloned()
392 })
393 })
394 .collect()
395 }
396 _ => list.values.clone(),
397 };
398
399 let row_idx = if let Some(val_expr) = &indices[0].value {
400 Some(interp.eval_in(val_expr, env)?)
401 } else {
402 None
403 };
404
405 let nrows = selected_cols.first().map(|(_, v)| v.length()).unwrap_or(0);
407
408 if row_idx.is_none() {
409 if drop && col_idx.is_some() && selected_cols.len() == 1 {
411 return Ok(selected_cols
412 .into_iter()
413 .next()
414 .expect("selected_cols.len() == 1 guarantees an element")
415 .1);
416 }
417
418 let col_names: Vec<Option<String>> = selected_cols.iter().map(|(n, _)| n.clone()).collect();
419 let mut result = RList::new(selected_cols);
420 result.set_attr(
421 "class".to_string(),
422 RValue::vec(Vector::Character(
423 vec![Some("data.frame".to_string())].into(),
424 )),
425 );
426 result.set_attr(
427 "names".to_string(),
428 RValue::vec(Vector::Character(col_names.into())),
429 );
430 let row_names_attr = subset_row_names(
431 list,
432 &(1..=i64::try_from(nrows).unwrap_or(0))
433 .map(Some)
434 .collect::<Vec<_>>(),
435 );
436 result.set_attr("row.names".to_string(), row_names_attr);
437 return Ok(RValue::List(result));
438 }
439
440 let int_rows: Vec<Option<i64>> = resolve_df_row_index(&row_idx, nrows, list)?;
441
442 if drop && selected_cols.len() == 1 {
444 if let RValue::Vector(rv) = &selected_cols[0].1 {
445 return index_by_integer(interp, &rv.inner, &int_rows);
446 }
447 return Ok(selected_cols[0].1.clone());
448 }
449
450 let mut result_cols = Vec::new();
451 for (name, col_val) in &selected_cols {
452 if let RValue::Vector(rv) = col_val {
453 let indexed = index_by_integer(interp, &rv.inner, &int_rows)?;
454 result_cols.push((name.clone(), indexed));
455 } else {
456 result_cols.push((name.clone(), col_val.clone()));
457 }
458 }
459 let col_names: Vec<Option<String>> = result_cols.iter().map(|(n, _)| n.clone()).collect();
460 let mut result = RList::new(result_cols);
461 result.set_attr(
462 "class".to_string(),
463 RValue::vec(Vector::Character(
464 vec![Some("data.frame".to_string())].into(),
465 )),
466 );
467 result.set_attr(
468 "names".to_string(),
469 RValue::vec(Vector::Character(col_names.into())),
470 );
471 let row_names_attr = subset_row_names(list, &int_rows);
473 result.set_attr("row.names".to_string(), row_names_attr);
474 Ok(RValue::List(result))
475}
476
477fn extract_drop_arg(
480 interp: &Interpreter,
481 indices: &[Arg],
482 env: &Environment,
483) -> Result<bool, RFlow> {
484 for arg in indices.iter().skip(2) {
485 if arg.name.as_deref() == Some("drop") {
486 if let Some(val_expr) = &arg.value {
487 let val = interp.eval_in(val_expr, env)?;
488 if let Some(rv) = val.as_vector() {
489 if let Some(b) = rv.as_logical_scalar() {
490 return Ok(b);
491 }
492 }
493 }
494 return Ok(true);
495 }
496 }
497 Ok(true) }
499
500fn resolve_df_row_index(
503 row_idx: &Option<RValue>,
504 nrows: usize,
505 list: &RList,
506) -> Result<Vec<Option<i64>>, RFlow> {
507 match row_idx {
508 None => Ok((1..=i64::try_from(nrows).unwrap_or(0)).map(Some).collect()),
509 Some(RValue::Vector(rv)) => {
510 match &rv.inner {
511 Vector::Logical(lv) => Ok(lv
513 .iter()
514 .enumerate()
515 .filter(|(_, v)| v.unwrap_or(false))
516 .filter_map(|(i, _)| i64::try_from(i).ok().map(|i| Some(i + 1)))
517 .collect()),
518 Vector::Character(names) => {
520 let row_names = get_row_names_vec(list);
521 let mut result = Vec::new();
522 for name in names.iter() {
523 match name {
524 Some(n) => {
525 let pos = row_names
526 .iter()
527 .position(|rn| rn.as_deref() == Some(n.as_str()));
528 match pos {
529 Some(p) => result.push(Some(i64::try_from(p + 1)?)),
530 None => {
531 return Err(IndexingError::UndefinedRow {
532 name: n.clone(),
533 }
534 .into());
535 }
536 }
537 }
538 None => result.push(None),
539 }
540 }
541 Ok(result)
542 }
543 _ => {
545 let ints = rv.to_integers();
546 let nonzero: Vec<Option<i64>> = ints
548 .iter()
549 .filter(|x| !matches!(x, Some(0)))
550 .copied()
551 .collect();
552 let has_pos = nonzero.iter().any(|x| x.map(|i| i > 0).unwrap_or(false));
553 let has_neg = nonzero.iter().any(|x| x.map(|i| i < 0).unwrap_or(false));
554 if has_pos && has_neg {
555 return Err(IndexingError::MixedSubscripts.into());
556 }
557 if has_neg {
558 let exclude: Vec<usize> = nonzero
560 .iter()
561 .filter_map(|x| x.and_then(|i| usize::try_from(-i).ok()))
562 .collect();
563 Ok((1..=nrows)
564 .filter(|i| !exclude.contains(i))
565 .filter_map(|i| i64::try_from(i).ok().map(Some))
566 .collect())
567 } else {
568 Ok(nonzero)
569 }
570 }
571 }
572 }
573 _ => Ok(vec![]),
574 }
575}
576
577fn get_row_names_vec(list: &RList) -> Vec<Option<String>> {
579 if let Some(rn_attr) = list.get_attr("row.names") {
580 if let Some(rn_vec) = rn_attr.as_vector() {
581 return rn_vec.to_characters();
582 }
583 }
584 vec![]
585}
586
587pub(crate) fn index_by_integer(
588 _interp: &Interpreter,
589 v: &Vector,
590 indices: &[Option<i64>],
591) -> Result<RValue, RFlow> {
592 macro_rules! index_vec_option {
593 ($vals:expr, $variant:ident) => {{
594 let result: Vec<_> = indices
595 .iter()
596 .map(|idx| {
597 idx.and_then(|i| {
598 let i = usize::try_from(i).unwrap_or(0);
599 if i > 0 && i <= $vals.len() {
600 $vals[i - 1].clone().into()
601 } else {
602 None
603 }
604 })
605 })
606 .collect();
607 Ok(RValue::vec(Vector::$variant(result.into())))
608 }};
609 }
610
611 macro_rules! index_vec_buffer {
612 ($vals:expr, $variant:ident) => {{
613 let result: Vec<_> = indices
614 .iter()
615 .map(|idx| {
616 idx.and_then(|i| {
617 let i = usize::try_from(i).unwrap_or(0);
618 if i > 0 && i <= $vals.len() {
619 $vals.get_opt(i - 1)
620 } else {
621 None
622 }
623 })
624 })
625 .collect();
626 Ok(RValue::vec(Vector::$variant(result.into())))
627 }};
628 }
629
630 match v {
631 Vector::Raw(vals) => {
632 let result: Vec<u8> = indices
633 .iter()
634 .map(|idx| {
635 idx.and_then(|i| {
636 let i = usize::try_from(i).unwrap_or(0);
637 if i > 0 && i <= vals.len() {
638 Some(vals[i - 1])
639 } else {
640 Some(0u8)
641 }
642 })
643 .unwrap_or(0u8)
644 })
645 .collect();
646 Ok(RValue::vec(Vector::Raw(result)))
647 }
648 Vector::Double(vals) => index_vec_buffer!(vals, Double),
649 Vector::Integer(vals) => index_vec_buffer!(vals, Integer),
650 Vector::Logical(vals) => index_vec_option!(vals, Logical),
651 Vector::Complex(vals) => index_vec_option!(vals, Complex),
652 Vector::Character(vals) => index_vec_option!(vals, Character),
653 }
654}
655
656fn index_by_negative(
657 _interp: &Interpreter,
658 v: &Vector,
659 indices: &[Option<i64>],
660) -> Result<RValue, RFlow> {
661 let exclude: Vec<usize> = indices
662 .iter()
663 .filter_map(|x| x.and_then(|i| usize::try_from(-i).ok()))
664 .collect();
665
666 macro_rules! filter_vec_option {
667 ($vals:expr, $variant:ident) => {{
668 let result: Vec<_> = $vals
669 .iter()
670 .enumerate()
671 .filter(|(i, _)| !exclude.contains(&(i + 1)))
672 .map(|(_, v)| v.clone())
673 .collect();
674 Ok(RValue::vec(Vector::$variant(result.into())))
675 }};
676 }
677
678 macro_rules! filter_vec_buffer {
679 ($vals:expr, $variant:ident) => {{
680 let result: Vec<_> = $vals
681 .iter()
682 .enumerate()
683 .filter(|(i, _)| !exclude.contains(&(i + 1)))
684 .map(|(_, v)| v)
685 .collect();
686 Ok(RValue::vec(Vector::$variant(result.into())))
687 }};
688 }
689
690 match v {
691 Vector::Raw(vals) => {
692 let result: Vec<u8> = vals
693 .iter()
694 .enumerate()
695 .filter(|(i, _)| !exclude.contains(&(i + 1)))
696 .map(|(_, &v)| v)
697 .collect();
698 Ok(RValue::vec(Vector::Raw(result)))
699 }
700 Vector::Double(vals) => filter_vec_buffer!(vals, Double),
701 Vector::Integer(vals) => filter_vec_buffer!(vals, Integer),
702 Vector::Logical(vals) => filter_vec_option!(vals, Logical),
703 Vector::Complex(vals) => filter_vec_option!(vals, Complex),
704 Vector::Character(vals) => filter_vec_option!(vals, Character),
705 }
706}
707
708fn index_by_logical(
709 _interp: &Interpreter,
710 v: &Vector,
711 mask: &[Option<bool>],
712) -> Result<RValue, RFlow> {
713 let vlen = v.len();
714 if mask.is_empty() {
715 return Ok(RValue::vec(v.select_indices(&[])));
717 }
718
719 let recycled_mask = |i: usize| -> Option<bool> { mask[i % mask.len()] };
723
724 macro_rules! mask_vec_option {
725 ($vals:expr, $variant:ident) => {{
726 let result: Vec<_> = (0..vlen)
727 .filter_map(|i| match recycled_mask(i) {
728 Some(true) => Some($vals.get(i).cloned().unwrap_or(None)),
729 Some(false) => None,
730 None => Some(None), })
732 .collect();
733 Ok(RValue::vec(Vector::$variant(result.into())))
734 }};
735 }
736
737 macro_rules! mask_vec_buffer {
738 ($vals:expr, $variant:ident) => {{
739 let result: Vec<Option<_>> = (0..vlen)
740 .filter_map(|i| match recycled_mask(i) {
741 Some(true) => Some($vals.get_opt(i)),
742 Some(false) => None,
743 None => Some(None), })
745 .collect();
746 Ok(RValue::vec(Vector::$variant(result.into())))
747 }};
748 }
749
750 match v {
751 Vector::Raw(vals) => {
752 let result: Vec<u8> = (0..vlen)
753 .filter_map(|i| match recycled_mask(i) {
754 Some(true) => Some(vals.get(i).copied().unwrap_or(0)),
755 Some(false) => None,
756 None => Some(0u8), })
758 .collect();
759 Ok(RValue::vec(Vector::Raw(result)))
760 }
761 Vector::Double(vals) => mask_vec_buffer!(vals, Double),
762 Vector::Integer(vals) => mask_vec_buffer!(vals, Integer),
763 Vector::Logical(vals) => mask_vec_option!(vals, Logical),
764 Vector::Complex(vals) => mask_vec_option!(vals, Complex),
765 Vector::Character(vals) => mask_vec_option!(vals, Character),
766 }
767}
768
769fn resolve_dim_index(
772 idx: &Option<RValue>,
773 dim_size: usize,
774 dim_names: &Option<Vec<String>>,
775) -> Result<Vec<usize>, RFlow> {
776 match idx {
777 None => Ok((0..dim_size).collect()),
778 Some(RValue::Vector(rv)) => {
779 if let Vector::Logical(mask) = &rv.inner {
781 let result: Vec<usize> = (0..dim_size)
782 .filter(|&i| {
783 if mask.is_empty() {
784 false
785 } else {
786 mask[i % mask.len()].unwrap_or(false)
787 }
788 })
789 .collect();
790 return Ok(result);
791 }
792 if matches!(rv.inner, Vector::Character(_)) {
794 let names = dim_names.as_ref().ok_or(IndexingError::NoDimnames)?;
795 let chars = rv.inner.to_characters();
796 let mut result = Vec::new();
797 for ch in chars.into_iter().flatten() {
798 let pos = names
799 .iter()
800 .position(|n| n == &ch)
801 .ok_or_else(|| IndexingError::SubscriptOutOfBounds { name: ch.clone() })?;
802 result.push(pos);
803 }
804 return Ok(result);
805 }
806 let ints = rv.to_integers();
808 let nonzero: Vec<Option<i64>> = ints
809 .iter()
810 .filter(|x| !matches!(x, Some(0)))
811 .copied()
812 .collect();
813 let has_neg = nonzero.iter().any(|x| x.map(|i| i < 0).unwrap_or(false));
814 if has_neg {
815 let exclude: Vec<usize> = nonzero
816 .iter()
817 .filter_map(|x| x.and_then(|i| usize::try_from(-i).ok()))
818 .collect();
819 return Ok((0..dim_size)
820 .filter(|i| !exclude.contains(&(i + 1)))
821 .collect());
822 }
823 Ok(nonzero
824 .iter()
825 .filter_map(|x| x.and_then(|i| usize::try_from(i - 1).ok()))
826 .collect())
827 }
828 _ => Err(IndexingError::InvalidSubscriptType.into()),
829 }
830}
831
832fn subset_row_names(list: &RList, int_rows: &[Option<i64>]) -> RValue {
836 if let Some(rn_attr) = list.get_attr("row.names") {
837 if let Some(rn_vec) = rn_attr.as_vector() {
838 let orig = rn_vec.to_characters();
839 let selected: Vec<Option<String>> = int_rows
840 .iter()
841 .map(|idx| {
842 idx.and_then(|i| {
843 let i = usize::try_from(i - 1).ok()?;
844 orig.get(i).cloned().flatten()
845 })
846 })
847 .collect();
848 return RValue::vec(Vector::Character(selected.into()));
849 }
850 }
851 let row_names: Vec<Option<i64>> = (1..=i64::try_from(int_rows.len()).unwrap_or(0))
853 .map(Some)
854 .collect();
855 RValue::vec(Vector::Integer(row_names.into()))
856}
857
858fn extract_dim_names(dimnames: Option<&RValue>, dim: usize) -> Option<Vec<String>> {
860 let RValue::List(list) = dimnames? else {
861 return None;
862 };
863 let (_, val) = list.values.get(dim)?;
864 let vec = val.as_vector()?;
865 let chars = vec.to_characters();
866 let names: Vec<String> = chars.into_iter().flatten().collect();
867 if names.is_empty() {
868 None
869 } else {
870 Some(names)
871 }
872}
873
874pub(super) fn eval_index_double(
875 interp: &Interpreter,
876 object: &Expr,
877 indices: &[Arg],
878 env: &Environment,
879) -> Result<RValue, RFlow> {
880 let obj = interp.eval_in(object, env)?;
881 if indices.is_empty() {
882 return Ok(obj);
883 }
884
885 let idx_val = if let Some(val_expr) = &indices[0].value {
886 interp.eval_in(val_expr, env)?
887 } else {
888 return Ok(obj);
889 };
890
891 match &obj {
892 RValue::List(list) => match &idx_val {
893 RValue::Vector(rv) if matches!(rv.inner, Vector::Character(_)) => {
894 let Vector::Character(names) = &rv.inner else {
895 unreachable!()
896 };
897 if let Some(Some(name)) = names.first() {
898 for (n, v) in &list.values {
899 if n.as_ref() == Some(name) {
900 return Ok(v.clone());
901 }
902 }
903 }
904 Ok(RValue::Null)
905 }
906 RValue::Vector(v) => {
907 let i = usize::try_from(v.as_integer_scalar().unwrap_or(0)).unwrap_or(0);
908 if i > 0 && i <= list.values.len() {
909 Ok(list.values[i - 1].1.clone())
910 } else {
911 Ok(RValue::Null)
912 }
913 }
914 _ => Ok(RValue::Null),
915 },
916 RValue::Vector(v) => {
917 if let RValue::Vector(iv) = &idx_val {
919 if let Vector::Character(idx_names) = &iv.inner {
920 if let Some(Some(name)) = idx_names.first() {
921 if let Some(names_attr) = v.get_attr("names") {
922 if let Some(names_vec) = names_attr.as_vector() {
923 let name_strs = names_vec.to_characters();
924 for (j, n) in name_strs.iter().enumerate() {
925 if n.as_deref() == Some(name.as_str()) && j < v.len() {
926 return Ok(extract_vector_element(v, j));
927 }
928 }
929 }
930 }
931 return Ok(RValue::Null);
932 }
933 }
934 }
935 let i = match &idx_val {
936 RValue::Vector(iv) => {
937 usize::try_from(iv.as_integer_scalar().unwrap_or(0)).unwrap_or(0)
938 }
939 _ => 0,
940 };
941 if i > 0 && i <= v.len() {
942 Ok(extract_vector_element(v, i - 1))
943 } else {
944 Ok(RValue::Null)
945 }
946 }
947 RValue::Language(lang) => {
948 let i = match &idx_val {
949 RValue::Vector(iv) => {
950 usize::try_from(iv.as_integer_scalar().unwrap_or(0)).unwrap_or(0)
951 }
952 _ => 0,
953 };
954 lang.language_element(i).ok_or_else(|| {
955 RFlow::Error(RError::new(
956 RErrorKind::Index,
957 format!(
958 "subscript out of bounds: index {} into language object of length {}",
959 i,
960 lang.language_length()
961 ),
962 ))
963 })
964 }
965 RValue::Environment(target_env) => {
966 if let Some(name) = idx_val.as_vector().and_then(|v| v.as_character_scalar()) {
968 Ok(target_env.get(&name).unwrap_or(RValue::Null))
969 } else {
970 Ok(RValue::Null)
971 }
972 }
973 RValue::Null => Ok(RValue::Null),
975 _ => Err(IndexingError::NotSubsettable.into()),
976 }
977}
978
979pub fn extract_vector_element(v: &RVector, idx: usize) -> RValue {
981 match &v.inner {
982 Vector::Raw(vals) => RValue::vec(Vector::Raw(vec![vals[idx]])),
983 Vector::Double(vals) => RValue::vec(Vector::Double(vec![vals.get_opt(idx)].into())),
984 Vector::Integer(vals) => RValue::vec(Vector::Integer(vec![vals.get_opt(idx)].into())),
985 Vector::Logical(vals) => RValue::vec(Vector::Logical(vec![vals[idx]].into())),
986 Vector::Complex(vals) => RValue::vec(Vector::Complex(vec![vals[idx]].into())),
987 Vector::Character(vals) => RValue::vec(Vector::Character(vec![vals[idx].clone()].into())),
988 }
989}
990
991pub(super) fn eval_dollar(
992 interp: &Interpreter,
993 object: &Expr,
994 member: &str,
995 env: &Environment,
996) -> Result<RValue, RFlow> {
997 let obj = interp.eval_in(object, env)?;
998 match &obj {
999 RValue::List(list) => {
1000 for (name, val) in &list.values {
1001 if name.as_deref() == Some(member) {
1002 return Ok(val.clone());
1003 }
1004 }
1005 Ok(RValue::Null)
1006 }
1007 RValue::Environment(e) => e
1008 .get(member)
1009 .ok_or_else(|| RError::new(RErrorKind::Name, member.to_string()).into()),
1010 _ => Ok(RValue::Null),
1011 }
1012}