1use crate::expansion::attr::AttrChar;
36use crate::expansion::attr::Origin;
37use std::iter::FusedIterator;
38use std::ops::Add;
39use std::ops::AddAssign;
40use yash_env::variable::IFS;
41use yash_env::variable::Value;
42use yash_env::variable::VariableSet;
43
44#[derive(Clone, Debug, Eq)]
48pub enum Phrase {
49 Char(AttrChar),
54 Field(Vec<AttrChar>),
58 Full(Vec<Vec<AttrChar>>),
60}
61
62use Phrase::*;
63
64impl PartialEq for Phrase {
65 fn eq(&self, other: &Phrase) -> bool {
66 match (self, other) {
67 (Char(left), Char(right)) => left == right,
68 (Field(left), Field(right)) => left == right,
69 (Full(left), Full(right)) => left == right,
70 (Char(c), Field(f)) | (Field(f), Char(c)) => [*c].as_slice() == f.as_slice(),
71 (Char(c), Full(v)) | (Full(v), Char(c)) => {
72 matches!(v.as_slice(), [f] if [*c].as_slice() == f.as_slice())
73 }
74 (Field(f), Full(v)) | (Full(v), Field(f)) => {
75 matches!(v.as_slice(), [fv] if f == fv)
76 }
77 }
78 }
79}
80
81impl Phrase {
82 #[inline]
86 #[must_use]
87 pub fn zero_fields() -> Self {
88 Full(Vec::new())
89 }
90
91 #[inline]
95 #[must_use]
96 pub fn one_empty_field() -> Self {
97 Field(Vec::new())
98 }
99
100 #[must_use]
102 pub fn is_zero_fields(&self) -> bool {
103 matches!(self, Full(fields) if fields.is_empty())
104 }
105
106 #[must_use]
108 pub fn field_count(&self) -> usize {
109 match self {
110 Char(_) | Field(_) => 1,
111 Full(fields) => fields.len(),
112 }
113 }
114
115 pub fn append(&mut self, other: &mut Phrase) {
194 match (&mut *self, &mut *other) {
195 (Char(left), Char(right)) => {
196 *self = Field(vec![*left, *right]);
197 *other = Phrase::zero_fields();
198 }
199 (Char(left), Field(right)) => {
200 right.insert(0, *left);
201 *self = std::mem::replace(other, Phrase::zero_fields());
202 }
203 (Field(left), Char(right)) => {
204 left.push(*right);
205 *other = Phrase::zero_fields();
206 }
207 (Field(left), Field(right)) => {
208 left.append(right);
209 *other = Phrase::zero_fields();
210 }
211 (left, Full(right)) => {
212 if let Some(right_first) = right.first_mut() {
213 match left {
214 Char(left) => {
215 right_first.insert(0, *left);
216 *self = std::mem::replace(other, Phrase::zero_fields());
217 }
218 Field(left) => {
219 left.append(right_first);
220 std::mem::swap(left, right_first);
221 *self = std::mem::replace(other, Phrase::zero_fields());
222 }
223 Full(left) => {
224 if let Some(left_last) = left.last_mut() {
225 left_last.append(right_first);
226 left.extend(right.drain(1..));
227 right.clear();
228 } else {
229 std::mem::swap(left, right);
230 }
231 }
232 }
233 } else {
234 }
236 }
237 (Full(left), right) => {
238 if let Some(left_last) = left.last_mut() {
239 match right {
240 Char(right) => left_last.push(*right),
241 Field(right) => left_last.append(right),
242 Full(_right) => unreachable!(),
243 }
244 *other = Phrase::zero_fields();
245 } else {
246 std::mem::swap(self, other);
247 }
248 }
249 }
250 }
251
252 pub fn ifs_join(self, vars: &VariableSet) -> Vec<AttrChar> {
259 match self {
260 Char(c) => vec![c],
261 Field(field) => field,
262 Full(mut fields) => match fields.len() {
263 0 => vec![],
264 1 => fields.swap_remove(0),
265 _ => {
266 let separator = match vars.get(IFS).and_then(|v| v.value.as_ref()) {
267 Some(Value::Scalar(value)) => value.chars().next(),
268 Some(Value::Array(values)) => {
269 values.first().and_then(|value| value.chars().next())
270 }
271 None => Some(' '),
272 }
273 .map(|c| AttrChar {
274 value: c,
275 origin: Origin::SoftExpansion,
276 is_quoted: false,
277 is_quoting: false,
278 });
279
280 let mut i = fields.into_iter();
281 let mut result = i.next().unwrap();
282 result.reserve_exact(
283 i.as_slice().iter().map(|field| field.len()).sum::<usize>()
284 + i.as_slice().len(),
285 );
286 for field in i {
287 if let Some(separator) = separator {
288 result.push(separator);
289 }
290 result.extend(field);
291 }
292 result
293 }
294 },
295 }
296 }
297
298 pub fn for_each_char_mut<F>(&mut self, mut f: F)
300 where
301 F: FnMut(&mut AttrChar),
302 {
303 match self {
304 Char(c) => f(c),
305 Field(field) => field.iter_mut().for_each(f),
306 Full(fields) => fields.iter_mut().flatten().for_each(f),
307 }
308 }
309}
310
311impl From<AttrChar> for Phrase {
312 #[inline]
313 fn from(c: AttrChar) -> Self {
314 Char(c)
315 }
316}
317
318impl From<Vec<AttrChar>> for Phrase {
319 #[inline]
320 fn from(chars: Vec<AttrChar>) -> Self {
321 Field(chars)
322 }
323}
324
325impl From<Vec<Vec<AttrChar>>> for Phrase {
326 #[inline]
327 fn from(fields: Vec<Vec<AttrChar>>) -> Self {
328 Full(fields)
329 }
330}
331
332impl From<Phrase> for Vec<Vec<AttrChar>> {
333 fn from(phrase: Phrase) -> Self {
334 match phrase {
335 Char(c) => vec![vec![c]],
336 Field(f) => vec![f],
337 Full(v) => v,
338 }
339 }
340}
341
342#[derive(Clone, Debug)]
344enum IntoIterState {
345 None,
346 Char(AttrChar),
347 Field(Vec<AttrChar>),
348 Full(std::vec::IntoIter<Vec<AttrChar>>),
349}
350
351#[derive(Clone, Debug)]
356pub struct IntoIter(IntoIterState);
357
358impl Iterator for IntoIter {
359 type Item = Vec<AttrChar>;
360 fn next(&mut self) -> Option<Vec<AttrChar>> {
361 match &mut self.0 {
362 IntoIterState::None => None,
363 IntoIterState::Char(c) => {
364 let f = vec![*c];
365 self.0 = IntoIterState::None;
366 Some(f)
367 }
368 IntoIterState::Field(f) => {
369 let f = std::mem::take(f);
370 self.0 = IntoIterState::None;
371 Some(f)
372 }
373 IntoIterState::Full(i) => i.next(),
374 }
375 }
376
377 fn size_hint(&self) -> (usize, Option<usize>) {
378 match &self.0 {
379 IntoIterState::None => (0, Some(0)),
380 IntoIterState::Char(_) | IntoIterState::Field(_) => (1, Some(1)),
381 IntoIterState::Full(i) => i.size_hint(),
382 }
383 }
384
385 #[inline]
386 fn count(self) -> usize {
387 self.len()
388 }
389}
390
391impl DoubleEndedIterator for IntoIter {
392 fn next_back(&mut self) -> Option<Vec<AttrChar>> {
393 match &mut self.0 {
394 IntoIterState::None => None,
395 IntoIterState::Char(c) => {
396 let f = vec![*c];
397 self.0 = IntoIterState::None;
398 Some(f)
399 }
400 IntoIterState::Field(f) => {
401 let f = std::mem::take(f);
402 self.0 = IntoIterState::None;
403 Some(f)
404 }
405 IntoIterState::Full(i) => i.next_back(),
406 }
407 }
408}
409
410impl ExactSizeIterator for IntoIter {}
411
412impl FusedIterator for IntoIter {}
413
414impl IntoIterator for Phrase {
415 type Item = Vec<AttrChar>;
416 type IntoIter = IntoIter;
417 fn into_iter(self) -> IntoIter {
418 IntoIter(match self {
419 Char(c) => IntoIterState::Char(c),
420 Field(f) => IntoIterState::Field(f),
421 Full(f) => IntoIterState::Full(f.into_iter()),
422 })
423 }
424}
425
426impl AddAssign for Phrase {
432 fn add_assign(&mut self, mut other: Phrase) {
433 self.append(&mut other)
434 }
435}
436
437impl Add for Phrase {
439 type Output = Phrase;
440 #[inline]
441 fn add(mut self, other: Phrase) -> Self {
442 self.add_assign(other);
443 self
444 }
445}
446
447#[cfg(test)]
451mod tests {
452 use super::*;
453 use yash_env::variable::Scope;
454
455 #[test]
456 fn partial_eq() {
457 let c1 = AttrChar {
458 value: 'a',
459 origin: Origin::Literal,
460 is_quoted: false,
461 is_quoting: false,
462 };
463 let c2 = AttrChar { value: 'b', ..c1 };
464 let f0 = vec![];
465 let f1 = vec![c1];
466 let f2 = vec![c2];
467 let f3 = vec![c1, c2];
468 let ve = vec![];
469 let v0 = vec![f0.clone()];
470 let v1 = vec![f1.clone()];
471 let v2 = vec![f2.clone()];
472 let v3 = vec![f3.clone()];
473 let v4 = vec![f1.clone(), f2.clone()];
474
475 let c1 = Char(c1);
476 let c2 = Char(c2);
477 let f0 = Field(f0);
478 let f1 = Field(f1);
479 let f2 = Field(f2);
480 let f3 = Field(f3);
481 let ve = Full(ve);
482 let v0 = Full(v0);
483 let v1 = Full(v1);
484 let v2 = Full(v2);
485 let v3 = Full(v3);
486 let v4 = Full(v4);
487
488 assert_eq!(c1, c1);
489 assert_eq!(c2, c2);
490 assert_ne!(c1, c2);
491 assert_ne!(c2, c1);
492
493 assert_eq!(f0, f0);
494 assert_eq!(f1, f1);
495 assert_eq!(f3, f3);
496 assert_ne!(f0, f1);
497 assert_ne!(f1, f2);
498 assert_ne!(f2, f3);
499 assert_ne!(f3, f0);
500
501 assert_eq!(ve, ve);
502 assert_eq!(v2, v2);
503 assert_eq!(v4, v4);
504 assert_ne!(ve, v0);
505 assert_ne!(v0, v1);
506 assert_ne!(v1, v2);
507 assert_ne!(v2, v3);
508 assert_ne!(v3, v4);
509 assert_ne!(v4, ve);
510
511 assert_eq!(c1, f1);
512 assert_eq!(c2, f2);
513 assert_ne!(c1, f2);
514 assert_ne!(c2, f3);
515 assert_ne!(c2, f0);
516
517 assert_eq!(f1, c1);
518 assert_eq!(f2, c2);
519 assert_ne!(f2, c1);
520 assert_ne!(f3, c2);
521 assert_ne!(f0, c2);
522
523 assert_eq!(c1, v1);
524 assert_eq!(c2, v2);
525 assert_ne!(c1, v2);
526 assert_ne!(c2, v3);
527 assert_ne!(c1, v4);
528 assert_ne!(c2, ve);
529
530 assert_eq!(v1, c1);
531 assert_eq!(v2, c2);
532 assert_ne!(v2, c1);
533 assert_ne!(v3, c2);
534 assert_ne!(v4, c1);
535 assert_ne!(ve, c2);
536
537 assert_eq!(f0, v0);
538 assert_eq!(f1, v1);
539 assert_eq!(f2, v2);
540 assert_eq!(f3, v3);
541 assert_ne!(f0, ve);
542 assert_ne!(f1, v0);
543 assert_ne!(f2, v1);
544 assert_ne!(f3, v2);
545 assert_ne!(f3, v4);
546
547 assert_eq!(v0, f0);
548 assert_eq!(v1, f1);
549 assert_eq!(v2, f2);
550 assert_eq!(v3, f3);
551 assert_ne!(ve, f0);
552 assert_ne!(v0, f1);
553 assert_ne!(v1, f2);
554 assert_ne!(v2, f3);
555 assert_ne!(v4, f3);
556 }
557
558 #[test]
559 fn is_zero_fields() {
560 let c = AttrChar {
561 value: 'a',
562 origin: Origin::Literal,
563 is_quoted: false,
564 is_quoting: false,
565 };
566
567 assert!(Full(vec![]).is_zero_fields());
568
569 assert!(!Char(c).is_zero_fields());
570 assert!(!Field(vec![]).is_zero_fields());
571 assert!(!Field(vec![c]).is_zero_fields());
572 assert!(!Field(vec![c, c]).is_zero_fields());
573 assert!(!Full(vec![vec![]]).is_zero_fields());
574 assert!(!Full(vec![vec![c]]).is_zero_fields());
575 assert!(!Full(vec![vec![], vec![]]).is_zero_fields());
576 }
577
578 #[test]
579 fn field_count() {
580 let c = AttrChar {
581 value: 'a',
582 origin: Origin::Literal,
583 is_quoted: false,
584 is_quoting: false,
585 };
586 assert_eq!(Char(c).field_count(), 1);
587 assert_eq!(Field(vec![c]).field_count(), 1);
588 assert_eq!(Phrase::zero_fields().field_count(), 0);
589 assert_eq!(Phrase::one_empty_field().field_count(), 1);
590 assert_eq!(Full(vec![vec![c]]).field_count(), 1);
591 assert_eq!(Full(vec![vec![c, c]]).field_count(), 1);
592 assert_eq!(Full(vec![vec![c], vec![c]]).field_count(), 2);
593 }
594
595 #[test]
596 fn into_iter_size_hint() {
597 let c = AttrChar {
598 value: 'x',
599 origin: Origin::Literal,
600 is_quoted: false,
601 is_quoting: false,
602 };
603
604 let mut i = Char(c).into_iter();
605 assert_eq!(i.size_hint(), (1, Some(1)));
606 i.next();
607 assert_eq!(i.size_hint(), (0, Some(0)));
608
609 let mut i = Field(vec![c, c]).into_iter();
610 assert_eq!(i.size_hint(), (1, Some(1)));
611 i.next();
612 assert_eq!(i.size_hint(), (0, Some(0)));
613
614 let mut i = Full(vec![vec![c], vec![c, c, c], vec![c, c]]).into_iter();
615 assert_eq!(i.size_hint(), (3, Some(3)));
616 i.next();
617 assert_eq!(i.size_hint(), (2, Some(2)));
618 i.next();
619 assert_eq!(i.size_hint(), (1, Some(1)));
620 i.next();
621 assert_eq!(i.size_hint(), (0, Some(0)));
622 }
623
624 #[test]
625 fn into_iter_count() {
626 let c = AttrChar {
627 value: 'x',
628 origin: Origin::Literal,
629 is_quoted: false,
630 is_quoting: false,
631 };
632
633 let i = Char(c).into_iter();
634 assert_eq!(i.count(), 1);
635
636 let mut i = Char(c).into_iter();
637 i.next();
638 assert_eq!(i.count(), 0);
639
640 let i = Field(vec![c, c]).into_iter();
641 assert_eq!(i.count(), 1);
642
643 let mut i = Field(vec![c, c]).into_iter();
644 i.next();
645 assert_eq!(i.count(), 0);
646
647 let mut i = Full(vec![vec![c], vec![c, c, c], vec![c, c]]).into_iter();
648 i.next();
649 assert_eq!(i.count(), 2);
650
651 let mut i = Full(vec![vec![c], vec![c, c, c], vec![c, c]]).into_iter();
652 i.next();
653 i.next();
654 i.next();
655 assert_eq!(i.count(), 0);
656 }
657
658 #[test]
659 fn into_iter_fused() {
660 let c = AttrChar {
661 value: 'x',
662 origin: Origin::Literal,
663 is_quoted: false,
664 is_quoting: false,
665 };
666
667 let mut i = Char(c).into_iter();
668 assert_eq!(i.next(), Some(vec![c]));
669 assert_eq!(i.next(), None);
670 assert_eq!(i.next(), None);
671
672 let mut i = Field(vec![c, c]).into_iter();
673 assert_eq!(i.next(), Some(vec![c, c]));
674 assert_eq!(i.next(), None);
675 assert_eq!(i.next(), None);
676
677 let mut i = Full(vec![vec![c], vec![c, c, c], vec![c, c]]).into_iter();
678 assert_eq!(i.next(), Some(vec![c]));
679 assert_eq!(i.next(), Some(vec![c, c, c]));
680 assert_eq!(i.next(), Some(vec![c, c]));
681 assert_eq!(i.next(), None);
682 assert_eq!(i.next(), None);
683 }
684
685 #[test]
686 fn into_iter_back_fused() {
687 let c = AttrChar {
688 value: 'x',
689 origin: Origin::Literal,
690 is_quoted: false,
691 is_quoting: false,
692 };
693
694 let mut i = Char(c).into_iter();
695 assert_eq!(i.next_back(), Some(vec![c]));
696 assert_eq!(i.next_back(), None);
697 assert_eq!(i.next_back(), None);
698
699 let mut i = Field(vec![c, c]).into_iter();
700 assert_eq!(i.next_back(), Some(vec![c, c]));
701 assert_eq!(i.next_back(), None);
702 assert_eq!(i.next_back(), None);
703
704 let mut i = Full(vec![vec![c], vec![c, c, c], vec![c, c]]).into_iter();
705 assert_eq!(i.next_back(), Some(vec![c, c]));
706 assert_eq!(i.next_back(), Some(vec![c, c, c]));
707 assert_eq!(i.next_back(), Some(vec![c]));
708 assert_eq!(i.next_back(), None);
709 assert_eq!(i.next_back(), None);
710 }
711
712 #[test]
713 fn append_empty_empty() {
714 let mut left = Phrase::zero_fields();
715 let mut right = Phrase::zero_fields();
716 left.append(&mut right);
717 assert_eq!(left, Phrase::zero_fields());
718 assert_eq!(right, Phrase::zero_fields());
719
720 let mut left = Phrase::one_empty_field();
721 let mut right = Phrase::zero_fields();
722 left.append(&mut right);
723 assert_eq!(left, Phrase::one_empty_field());
724 assert_eq!(right, Phrase::zero_fields());
725
726 let mut left = Phrase::zero_fields();
727 let mut right = Phrase::one_empty_field();
728 left.append(&mut right);
729 assert_eq!(left, Phrase::one_empty_field());
730 assert_eq!(right, Phrase::zero_fields());
731
732 }
734
735 #[test]
736 fn append_empty_char() {
737 let phrase = Char(AttrChar {
738 value: 'a',
739 origin: Origin::Literal,
740 is_quoted: false,
741 is_quoting: false,
742 });
743 for mut left in [
744 Phrase::zero_fields(),
745 Phrase::one_empty_field(),
746 Full(vec![]),
747 Full(vec![vec![]]),
748 ] {
749 let mut right = phrase.clone();
750 left.append(&mut right);
751 assert_eq!(left, phrase);
752 assert_eq!(right, Phrase::zero_fields());
753 }
754 }
755
756 #[test]
757 fn append_char_empty() {
758 let phrase = Char(AttrChar {
759 value: 'a',
760 origin: Origin::Literal,
761 is_quoted: false,
762 is_quoting: false,
763 });
764 for mut right in [
765 Phrase::zero_fields(),
766 Phrase::one_empty_field(),
767 Full(vec![]),
768 Full(vec![vec![]]),
769 ] {
770 let mut left = phrase.clone();
771 left.append(&mut right);
772 assert_eq!(left, phrase);
773 assert_eq!(right, Phrase::zero_fields());
774 }
775 }
776
777 #[test]
782 fn append_empty_field() {
783 let a = AttrChar {
784 value: 'a',
785 origin: Origin::Literal,
786 is_quoted: false,
787 is_quoting: false,
788 };
789 let b = AttrChar { value: 'b', ..a };
790 let c = AttrChar { value: 'c', ..a };
791 let phrase = Field(vec![a, b, c]);
792 for mut left in [
793 Phrase::zero_fields(),
794 Phrase::one_empty_field(),
795 Full(vec![]),
796 Full(vec![vec![]]),
797 ] {
798 let mut right = phrase.clone();
799 left.append(&mut right);
800 assert_eq!(left, phrase);
801 assert_eq!(right, Phrase::zero_fields());
802 }
803 }
804
805 #[test]
806 fn append_field_empty() {
807 let a = AttrChar {
808 value: 'a',
809 origin: Origin::Literal,
810 is_quoted: false,
811 is_quoting: false,
812 };
813 let b = AttrChar { value: 'b', ..a };
814 let c = AttrChar { value: 'c', ..a };
815 let phrase = Field(vec![a, b, c]);
816 for mut right in [
817 Phrase::zero_fields(),
818 Phrase::one_empty_field(),
819 Full(vec![]),
820 Full(vec![vec![]]),
821 ] {
822 let mut left = phrase.clone();
823 left.append(&mut right);
824 assert_eq!(left, phrase);
825 assert_eq!(right, Phrase::zero_fields());
826 }
827 }
828
829 #[test]
830 fn append_char_field() {
831 let a = AttrChar {
832 value: 'a',
833 origin: Origin::Literal,
834 is_quoted: false,
835 is_quoting: false,
836 };
837 let b = AttrChar { value: 'b', ..a };
838 let c = AttrChar { value: 'c', ..a };
839 let mut left = Char(a);
840 let mut right = Field(vec![b, c]);
841 left.append(&mut right);
842 assert_eq!(left, Field(vec![a, b, c]));
843 assert_eq!(right, Phrase::zero_fields());
844 }
845
846 #[test]
847 fn append_field_char() {
848 let a = AttrChar {
849 value: 'a',
850 origin: Origin::Literal,
851 is_quoted: false,
852 is_quoting: false,
853 };
854 let b = AttrChar { value: 'b', ..a };
855 let c = AttrChar { value: 'c', ..a };
856 let mut left = Field(vec![a, b]);
857 let mut right = Char(c);
858 left.append(&mut right);
859 assert_eq!(left, Field(vec![a, b, c]));
860 assert_eq!(right, Phrase::zero_fields());
861 }
862
863 #[test]
868 fn append_empty_full() {
869 let a = AttrChar {
870 value: 'a',
871 origin: Origin::Literal,
872 is_quoted: false,
873 is_quoting: false,
874 };
875 let b = AttrChar { value: 'b', ..a };
876 let c = AttrChar { value: 'c', ..a };
877 let phrase = Full(vec![vec![a], vec![b], vec![c]]);
878 for mut left in [
879 Phrase::zero_fields(),
880 Phrase::one_empty_field(),
881 Full(vec![]),
882 Full(vec![vec![]]),
883 ] {
884 let mut right = phrase.clone();
885 left.append(&mut right);
886 assert_eq!(left, phrase);
887 assert_eq!(right, Phrase::zero_fields());
888 }
889 }
890
891 #[test]
892 fn append_full_empty() {
893 let a = AttrChar {
894 value: 'a',
895 origin: Origin::Literal,
896 is_quoted: false,
897 is_quoting: false,
898 };
899 let b = AttrChar { value: 'b', ..a };
900 let c = AttrChar { value: 'c', ..a };
901 let phrase = Full(vec![vec![a], vec![b], vec![c]]);
902 for mut right in [
903 Phrase::zero_fields(),
904 Phrase::one_empty_field(),
905 Full(vec![]),
906 Full(vec![vec![]]),
907 ] {
908 let mut left = phrase.clone();
909 left.append(&mut right);
910 assert_eq!(left, phrase);
911 assert_eq!(right, Phrase::zero_fields());
912 }
913 }
914
915 #[test]
916 fn append_char_full() {
917 let a = AttrChar {
918 value: 'a',
919 origin: Origin::Literal,
920 is_quoted: false,
921 is_quoting: false,
922 };
923 let b = AttrChar { value: 'b', ..a };
924 let c = AttrChar { value: 'c', ..a };
925 let mut left = Char(a);
926 let mut right = Full(vec![vec![b], vec![c]]);
927 left.append(&mut right);
928 assert_eq!(left, Full(vec![vec![a, b], vec![c]]));
929 assert_eq!(right, Phrase::zero_fields());
930 }
931
932 #[test]
933 fn append_full_char() {
934 let a = AttrChar {
935 value: 'a',
936 origin: Origin::Literal,
937 is_quoted: false,
938 is_quoting: false,
939 };
940 let b = AttrChar { value: 'b', ..a };
941 let c = AttrChar { value: 'c', ..a };
942 let mut left = Full(vec![vec![a], vec![b]]);
943 let mut right = Char(c);
944 left.append(&mut right);
945 assert_eq!(left, Full(vec![vec![a], vec![b, c]]));
946 assert_eq!(right, Phrase::zero_fields());
947 }
948
949 #[test]
950 fn append_field_full() {
951 let a = AttrChar {
952 value: 'a',
953 origin: Origin::Literal,
954 is_quoted: false,
955 is_quoting: false,
956 };
957 let b = AttrChar { value: 'b', ..a };
958 let c = AttrChar { value: 'c', ..a };
959 let mut left = Field(vec![a]);
960 let mut right = Full(vec![vec![b], vec![c]]);
961 left.append(&mut right);
962 assert_eq!(left, Full(vec![vec![a, b], vec![c]]));
963 assert_eq!(right, Phrase::zero_fields());
964 }
965
966 #[test]
967 fn append_full_field() {
968 let a = AttrChar {
969 value: 'a',
970 origin: Origin::Literal,
971 is_quoted: false,
972 is_quoting: false,
973 };
974 let b = AttrChar { value: 'b', ..a };
975 let c = AttrChar { value: 'c', ..a };
976 let mut left = Full(vec![vec![a], vec![b]]);
977 let mut right = Field(vec![c]);
978 left.append(&mut right);
979 assert_eq!(left, Full(vec![vec![a], vec![b, c]]));
980 assert_eq!(right, Phrase::zero_fields());
981 }
982
983 fn dummy_field(chars: &str) -> Vec<AttrChar> {
988 chars
989 .chars()
990 .map(|c| AttrChar {
991 value: c,
992 origin: Origin::SoftExpansion,
993 is_quoted: false,
994 is_quoting: false,
995 })
996 .collect()
997 }
998
999 #[test]
1000 fn ifs_join_char() {
1001 let a = AttrChar {
1002 value: 'a',
1003 origin: Origin::Literal,
1004 is_quoted: false,
1005 is_quoting: false,
1006 };
1007 let phrase = Char(a);
1008 let field = phrase.ifs_join(&VariableSet::new());
1009 assert_eq!(field, [a]);
1010 }
1011
1012 #[test]
1013 fn ifs_join_field() {
1014 let field_in = dummy_field("abc");
1015 let phrase = Field(field_in.clone());
1016 let field_out = phrase.ifs_join(&VariableSet::new());
1017 assert_eq!(field_out, field_in);
1018 }
1019
1020 #[test]
1021 fn ifs_join_full_empty() {
1022 let phrase = Full(vec![]);
1023 let field = phrase.ifs_join(&VariableSet::new());
1024 assert_eq!(field, []);
1025 }
1026
1027 #[test]
1028 fn ifs_join_full_one() {
1029 let field_in = dummy_field("foo");
1030 let phrase = Full(vec![field_in.clone()]);
1031 let field_out = phrase.ifs_join(&VariableSet::new());
1032 assert_eq!(field_out, field_in);
1033 }
1034
1035 #[test]
1036 fn ifs_join_full_unset_ifs() {
1037 let phrase = Full(vec![vec![], vec![]]);
1038 let field = phrase.ifs_join(&VariableSet::new());
1039 assert_eq!(field, dummy_field(" "));
1040
1041 let phrase = Full(vec![
1042 dummy_field("foo"),
1043 dummy_field("bar"),
1044 dummy_field("baz"),
1045 ]);
1046 let field = phrase.ifs_join(&VariableSet::new());
1047 assert_eq!(field, dummy_field("foo bar baz"));
1048 }
1049
1050 #[test]
1051 fn ifs_join_full_unassigned_ifs() {
1052 let mut vars = VariableSet::new();
1053 vars.get_or_new(IFS, Scope::Global);
1054 let phrase = Full(vec![
1055 dummy_field("foo"),
1056 dummy_field("bar"),
1057 dummy_field("baz"),
1058 ]);
1059 let field = phrase.ifs_join(&vars);
1060 assert_eq!(field, dummy_field("foo bar baz"));
1061 }
1062
1063 #[test]
1064 fn ifs_join_full_scalar_ifs() {
1065 let mut vars = VariableSet::new();
1066 vars.get_or_new(IFS, Scope::Global)
1067 .assign("!?", None)
1068 .unwrap();
1069 let phrase = Full(vec![
1070 dummy_field("foo"),
1071 dummy_field("bar"),
1072 dummy_field("baz"),
1073 ]);
1074 let field = phrase.ifs_join(&vars);
1075 assert_eq!(field, dummy_field("foo!bar!baz"));
1076 }
1077
1078 #[test]
1079 fn ifs_join_full_array_ifs() {
1080 let mut vars = VariableSet::new();
1081 vars.get_or_new(IFS, Scope::Global)
1082 .assign(Value::array(["-+", "abc"]), None)
1083 .unwrap();
1084 let phrase = Full(vec![
1085 dummy_field("foo"),
1086 dummy_field("bar"),
1087 dummy_field("baz"),
1088 ]);
1089 let field = phrase.ifs_join(&vars);
1090 assert_eq!(field, dummy_field("foo-bar-baz"));
1091 }
1092
1093 #[test]
1094 fn ifs_join_full_empty_scalar_ifs() {
1095 let mut vars = VariableSet::new();
1096 vars.get_or_new(IFS, Scope::Global)
1097 .assign("", None)
1098 .unwrap();
1099 let phrase = Full(vec![
1100 dummy_field("foo"),
1101 dummy_field("bar"),
1102 dummy_field("baz"),
1103 ]);
1104 let field = phrase.ifs_join(&vars);
1105 assert_eq!(field, dummy_field("foobarbaz"));
1106 }
1107
1108 #[test]
1109 fn ifs_join_full_empty_array_ifs() {
1110 let mut vars = VariableSet::new();
1111 vars.get_or_new(IFS, Scope::Global)
1112 .assign(Value::Array(vec![]), None)
1113 .unwrap();
1114 let phrase = Full(vec![
1115 dummy_field("foo"),
1116 dummy_field("bar"),
1117 dummy_field("baz"),
1118 ]);
1119 let field = phrase.ifs_join(&vars);
1120 assert_eq!(field, dummy_field("foobarbaz"));
1121
1122 vars.get_or_new(IFS, Scope::Global)
1123 .assign(Value::array(["", "abc"]), None)
1124 .unwrap();
1125 let phrase = Full(vec![
1126 dummy_field("foo"),
1127 dummy_field("bar"),
1128 dummy_field("baz"),
1129 ]);
1130 let field = phrase.ifs_join(&vars);
1131 assert_eq!(field, dummy_field("foobarbaz"));
1132 }
1133}