cpclib_asm/assembler/
list.rs

1use std::borrow::Borrow;
2
3use cpclib_common::itertools::Itertools;
4use cpclib_common::smol_str::SmolStr;
5use cpclib_tokens::ExprResult;
6use substring::Substring;
7
8use crate::error::{AssemblerError, ExpressionError};
9
10pub fn fix_string<S: Borrow<str>>(s: S) -> SmolStr {
11    s.borrow().replace("\\n", "\n").into()
12}
13
14/// Create a new list
15pub fn list_new(count: usize, value: ExprResult) -> ExprResult {
16    ExprResult::List(vec![value; count])
17}
18
19/// Create a new string
20pub fn string_new(count: usize, value: ExprResult) -> Result<ExprResult, AssemblerError> {
21    let value = value.char()?;
22    let s = (0..count).map(|_| value).collect::<SmolStr>();
23    Ok(ExprResult::String(fix_string(s)))
24}
25
26/// Modify a list or a string
27pub fn list_set(
28    mut list: ExprResult,
29    index: usize,
30    value: ExprResult
31) -> Result<ExprResult, crate::AssemblerError> {
32    match list {
33        ExprResult::String(s) => {
34            if index >= s.len() {
35                return Err(AssemblerError::ExpressionError(
36                    ExpressionError::InvalidSize(s.len(), index)
37                ));
38            }
39            let c = value.int()? as u8 as char;
40            let c = format!("{}", c);
41            let mut s = s.to_string();
42            s.replace_range(index..index + 1, &c);
43            Ok(ExprResult::String(fix_string(s)))
44        },
45        ExprResult::List(_) => {
46            if index >= list.list_len() {
47                return Err(AssemblerError::ExpressionError(
48                    ExpressionError::InvalidSize(list.list_len(), index)
49                ));
50            }
51            list.list_set(index, value);
52            Ok(list)
53        },
54
55        _ => {
56            Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
57                Box::new(AssemblerError::AssemblingError {
58                    msg: format!("{} is not a list", list)
59                })
60            )))
61        },
62    }
63}
64
65/// Get an item in a list of string
66pub fn list_get(list: &ExprResult, index: usize) -> Result<ExprResult, crate::AssemblerError> {
67    match list {
68        ExprResult::String(s) => {
69            if index >= s.len() {
70                return Err(AssemblerError::ExpressionError(
71                    ExpressionError::InvalidSize(s.len(), index)
72                ));
73            }
74            Ok(ExprResult::Value(s.chars().nth(index).unwrap() as _))
75        },
76        ExprResult::List(_) => {
77            if index >= list.list_len() {
78                return Err(AssemblerError::ExpressionError(
79                    ExpressionError::InvalidSize(list.list_len(), index)
80                ));
81            }
82            Ok(list.list_get(index).clone())
83        },
84
85        _ => {
86            Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
87                Box::new(AssemblerError::AssemblingError {
88                    msg: format!("{} is not a list", list)
89                })
90            )))
91        },
92    }
93}
94
95/// Get a sublist  a list of string
96pub fn list_sublist(
97    list: &ExprResult,
98    start: usize,
99    end: usize // not included
100) -> Result<ExprResult, crate::AssemblerError> {
101    match list {
102        ExprResult::String(s) => {
103            if start >= s.len() {
104                return Err(AssemblerError::ExpressionError(
105                    ExpressionError::InvalidSize(s.len(), start)
106                ));
107            }
108            if end > s.len() {
109                return Err(AssemblerError::ExpressionError(
110                    ExpressionError::InvalidSize(s.len(), end)
111                ));
112            }
113            Ok(ExprResult::String(s.substring(start, end).into()))
114        },
115        ExprResult::List(l) => {
116            if start >= l.len() {
117                return Err(AssemblerError::ExpressionError(
118                    ExpressionError::InvalidSize(l.len(), start)
119                ));
120            }
121            if end > l.len() {
122                return Err(AssemblerError::ExpressionError(
123                    ExpressionError::InvalidSize(l.len(), end)
124                ));
125            }
126            Ok(ExprResult::List(l[start..end].to_vec()))
127        },
128
129        _ => {
130            Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
131                Box::new(AssemblerError::AssemblingError {
132                    msg: format!("{} is not a list", list)
133                })
134            )))
135        },
136    }
137}
138
139pub fn list_len(list: &ExprResult) -> Result<ExprResult, crate::AssemblerError> {
140    match list {
141        ExprResult::List(l) => Ok(l.len().into()),
142        ExprResult::String(s) => Ok(s.len().into()),
143        _ => {
144            Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
145                Box::new(AssemblerError::AssemblingError {
146                    msg: format!("{} is not a list", list)
147                })
148            )))
149        },
150    }
151}
152
153pub fn list_push(list: ExprResult, elem: ExprResult) -> Result<ExprResult, crate::AssemblerError> {
154    match list {
155        ExprResult::List(mut l) => {
156            l.push(elem);
157            Ok(ExprResult::List(l))
158        },
159        _ => {
160            Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
161                Box::new(AssemblerError::AssemblingError {
162                    msg: format!("{} is not a list", list)
163                })
164            )))
165        },
166    }
167}
168
169pub fn list_extend(
170    list1: ExprResult,
171    list2: ExprResult
172) -> Result<ExprResult, crate::AssemblerError> {
173    match list1 {
174        ExprResult::List(mut l) => {
175            match list2 {
176                ExprResult::List(l2) => {
177                    for item in l2 {
178                        l.push(item);
179                    }
180                    Ok(ExprResult::List(l))
181                },
182                _ => {
183                    Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
184                        Box::new(AssemblerError::AssemblingError {
185                            msg: format!("{} is not a list", list2)
186                        })
187                    )))
188                },
189            }
190        },
191        _ => {
192            Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
193                Box::new(AssemblerError::AssemblingError {
194                    msg: format!("{} is not a list", list1)
195                })
196            )))
197        },
198    }
199}
200
201pub fn list_sort(list: ExprResult) -> Result<ExprResult, crate::AssemblerError> {
202    match list {
203        ExprResult::List(mut l) => {
204            l.sort();
205            Ok(ExprResult::List(l))
206        },
207        _ => {
208            Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
209                Box::new(AssemblerError::AssemblingError {
210                    msg: format!("{} is not a list", list)
211                })
212            )))
213        },
214    }
215}
216
217pub fn list_argsort(list: &ExprResult) -> Result<ExprResult, crate::AssemblerError> {
218    match list {
219        ExprResult::List(l) => {
220            // https://stackoverflow.com/questions/69764050/how-to-get-the-indices-that-would-sort-a-vector-in-rust
221            fn argsort<T: Ord>(data: &[T]) -> Vec<ExprResult> {
222                let mut indices = (0..data.len()).map(ExprResult::from).collect_vec();
223                indices.sort_by_key(|i| &data[i.int().unwrap() as usize]);
224                indices
225            }
226
227            let l = argsort(l);
228            Ok(ExprResult::List(l))
229        },
230        _ => {
231            Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
232                Box::new(AssemblerError::AssemblingError {
233                    msg: format!("{} is not a list", list)
234                })
235            )))
236        },
237    }
238}
239
240/// BUG bytes must be enced in utf8
241pub fn string_from_list(s1: ExprResult) -> Result<ExprResult, crate::AssemblerError> {
242    match s1 {
243        ExprResult::List(l1) => {
244            let bytes = l1
245                .iter()
246                .enumerate()
247                .map(|(idx, v)| {
248                    let v = v.int()?;
249                    if !(0..=255).contains(&v) {
250                        Err(AssemblerError::AssemblingError {
251                            msg: format!("{} at {} is not a valid byte value", v, idx)
252                        })
253                    }
254                    else {
255                        Ok(v as u8)
256                    }
257                })
258                .collect::<Result<Vec<u8>, AssemblerError>>()?;
259
260            String::from_utf8(bytes)
261                .map_err(|e| {
262                    AssemblerError::AssemblingError {
263                        msg: format!("Error when generating a string. {e}")
264                    }
265                })
266                .map(|s| s.into())
267        },
268
269        _ => {
270            Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
271                Box::new(AssemblerError::AssemblingError {
272                    msg: "string_from_list must take a list as an argument".to_string()
273                })
274            )))
275        },
276    }
277}
278
279pub fn string_push(s1: ExprResult, s2: ExprResult) -> Result<ExprResult, crate::AssemblerError> {
280    match (&s1, &s2) {
281        (ExprResult::Char(s1), ExprResult::Char(s2)) => {
282            let s1 = format!("{}{}", *s1 as char, *s2 as char);
283            Ok(ExprResult::String(s1.into()))
284        },
285
286        (ExprResult::String(s1), ExprResult::Char(s2)) => {
287            let s1 = format!("{}{}", s1, *s2 as char);
288            Ok(ExprResult::String(s1.into()))
289        },
290
291        (ExprResult::String(s1), ExprResult::String(s2)) => {
292            let s1 = s1.to_string() + fix_string(s2.clone()).as_str();
293            Ok(ExprResult::String(s1.into()))
294        },
295        (ExprResult::String(s1), ExprResult::List(l)) => {
296            let mut s1 = s1.to_string() + "[";
297
298            for (i, e) in l.iter().cloned().enumerate() {
299                if i != 0 {
300                    s1 += ","
301                }
302
303                s1 = string_push(s1.into(), e)?.string().unwrap().to_string();
304            }
305
306            s1 += "]";
307            Ok(ExprResult::String(s1.into()))
308        },
309
310        (ExprResult::String(s1), ExprResult::Float(s2)) => {
311            let mut s1 = s1.to_string();
312            s1 += &s2.into_inner().to_string();
313            Ok(ExprResult::String(s1.into()))
314        },
315
316        (ExprResult::String(s1), ExprResult::Value(s2)) => {
317            let mut s1 = s1.to_string();
318
319            s1 += &s2.to_string();
320            Ok(ExprResult::String(s1.into()))
321        },
322
323        (ExprResult::String(s1), ExprResult::Bool(s2)) => {
324            let mut s1 = s1.to_string();
325
326            s1 += &s2.to_string();
327            Ok(ExprResult::String(s1.into()))
328        },
329
330        _ => {
331            Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
332                Box::new(AssemblerError::AssemblingError {
333                    msg: format!("string_push called with wrong types {:?} {:?}", s1, s2)
334                })
335            )))
336        },
337    }
338}