Rust · 5250 bytes Raw Blame History
1 use rush_parser::ast::BraceExpansion;
2
3 /// Expand a brace expansion pattern into a list of strings
4 pub fn expand_brace(brace: &BraceExpansion) -> Vec<String> {
5 match brace {
6 BraceExpansion::List(items) => items.clone(),
7 BraceExpansion::Sequence { start, end, increment } => {
8 expand_sequence(start, end, increment.unwrap_or(1))
9 }
10 }
11 }
12
13 /// Expand a sequence like {1..10} or {a..z}
14 fn expand_sequence(start: &str, end: &str, increment: i32) -> Vec<String> {
15 // Try numeric sequence first
16 if let (Ok(start_num), Ok(end_num)) = (start.parse::<i32>(), end.parse::<i32>()) {
17 expand_numeric_sequence(start_num, end_num, increment, start.len())
18 } else if start.len() == 1 && end.len() == 1 {
19 // Try character sequence
20 let start_char = start.chars().next().unwrap();
21 let end_char = end.chars().next().unwrap();
22 expand_char_sequence(start_char, end_char, increment)
23 } else {
24 // Invalid sequence, return empty
25 vec![]
26 }
27 }
28
29 /// Expand a numeric sequence: {1..10} or {01..05}
30 fn expand_numeric_sequence(start: i32, end: i32, increment: i32, width: usize) -> Vec<String> {
31 let mut result = Vec::new();
32
33 if increment == 0 {
34 return result;
35 }
36
37 // Check if we should use zero-padding
38 let use_padding = width > 1;
39
40 if start <= end && increment > 0 {
41 // Ascending
42 let mut current = start;
43 while current <= end {
44 if use_padding {
45 result.push(format!("{:0width$}", current, width = width));
46 } else {
47 result.push(current.to_string());
48 }
49 current += increment;
50 }
51 } else if start >= end && increment < 0 {
52 // Descending
53 let mut current = start;
54 while current >= end {
55 if use_padding {
56 result.push(format!("{:0width$}", current, width = width));
57 } else {
58 result.push(current.to_string());
59 }
60 current += increment;
61 }
62 } else if start > end && increment > 0 {
63 // Descending with positive increment (use negative)
64 let mut current = start;
65 while current >= end {
66 if use_padding {
67 result.push(format!("{:0width$}", current, width = width));
68 } else {
69 result.push(current.to_string());
70 }
71 current -= increment;
72 }
73 }
74
75 result
76 }
77
78 /// Expand a character sequence: {a..z} or {Z..A}
79 fn expand_char_sequence(start: char, end: char, increment: i32) -> Vec<String> {
80 let mut result = Vec::new();
81
82 if increment == 0 {
83 return result;
84 }
85
86 let start_code = start as i32;
87 let end_code = end as i32;
88
89 if start_code <= end_code && increment > 0 {
90 // Ascending
91 let mut current = start_code;
92 while current <= end_code {
93 if let Some(ch) = char::from_u32(current as u32) {
94 result.push(ch.to_string());
95 }
96 current += increment;
97 }
98 } else if start_code >= end_code && increment < 0 {
99 // Descending
100 let mut current = start_code;
101 while current >= end_code {
102 if let Some(ch) = char::from_u32(current as u32) {
103 result.push(ch.to_string());
104 }
105 current += increment;
106 }
107 } else if start_code > end_code && increment > 0 {
108 // Descending with positive increment
109 let mut current = start_code;
110 while current >= end_code {
111 if let Some(ch) = char::from_u32(current as u32) {
112 result.push(ch.to_string());
113 }
114 current -= increment;
115 }
116 }
117
118 result
119 }
120
121 #[cfg(test)]
122 mod tests {
123 use super::*;
124 use rush_parser::ast::BraceExpansion;
125
126 #[test]
127 fn test_list_expansion() {
128 let brace = BraceExpansion::List(vec![
129 "a".to_string(),
130 "b".to_string(),
131 "c".to_string(),
132 ]);
133 assert_eq!(expand_brace(&brace), vec!["a", "b", "c"]);
134 }
135
136 #[test]
137 fn test_numeric_sequence() {
138 let brace = BraceExpansion::Sequence {
139 start: "1".to_string(),
140 end: "5".to_string(),
141 increment: None,
142 };
143 assert_eq!(expand_brace(&brace), vec!["1", "2", "3", "4", "5"]);
144 }
145
146 #[test]
147 fn test_numeric_sequence_descending() {
148 let brace = BraceExpansion::Sequence {
149 start: "5".to_string(),
150 end: "1".to_string(),
151 increment: None,
152 };
153 assert_eq!(expand_brace(&brace), vec!["5", "4", "3", "2", "1"]);
154 }
155
156 #[test]
157 fn test_char_sequence() {
158 let brace = BraceExpansion::Sequence {
159 start: "a".to_string(),
160 end: "d".to_string(),
161 increment: None,
162 };
163 assert_eq!(expand_brace(&brace), vec!["a", "b", "c", "d"]);
164 }
165
166 #[test]
167 fn test_padded_numbers() {
168 let brace = BraceExpansion::Sequence {
169 start: "01".to_string(),
170 end: "05".to_string(),
171 increment: None,
172 };
173 assert_eq!(expand_brace(&brace), vec!["01", "02", "03", "04", "05"]);
174 }
175 }
176