Skip to main content

mumustring/partial/
slice.rs

1use mumu::parser::types::Value;
2use crate::common::{is_placeholder, make_three_arg_partial};
3
4pub fn string_slice_bridge(_interp: &mut mumu::parser::interpreter::Interpreter, args: Vec<Value>) -> Result<Value, String> {
5    match args.len() {
6        0 => Ok(make_three_arg_partial(string_slice_finalize, None, None, None)),
7        1 => Ok(make_three_arg_partial(string_slice_finalize, Some(args[0].clone()), None, None)),
8        2 => Ok(make_three_arg_partial(string_slice_finalize, Some(args[0].clone()), Some(args[1].clone()), None)),
9        3 => {
10            let s = &args[0];
11            let start = &args[1];
12            let end = &args[2];
13            let s_pl = is_placeholder(s);
14            let start_pl = is_placeholder(start);
15            let end_pl = is_placeholder(end);
16            if !s_pl && !start_pl && !end_pl {
17                string_slice_finalize(vec![s.clone(), start.clone(), end.clone()])
18            } else {
19                Ok(make_three_arg_partial(
20                    string_slice_finalize,
21                    if s_pl { None } else { Some(s.clone()) },
22                    if start_pl { None } else { Some(start.clone()) },
23                    if end_pl { None } else { Some(end.clone()) },
24                ))
25            }
26        }
27        n => Err(format!("string:slice => expected up to 3 arguments, got {}", n)),
28    }
29}
30
31fn string_slice_finalize(mut args: Vec<Value>) -> Result<Value, String> {
32    if args.len() != 3 {
33        return Err(format!("string:slice => finalize => expected 3 real args, got {}", args.len()));
34    }
35    let s_val = args.remove(0);
36    let start_val = args.remove(0);
37    let end_val = args.remove(0);
38    let s = match s_val {
39        Value::SingleString(s) => s,
40        Value::StrArray(ss) if ss.len() == 1 => ss[0].clone(),
41        other => return Err(format!("string:slice => first arg must be a string, got {:?}", other)),
42    };
43    let start = match start_val {
44        Value::Int(i) => i,
45        other => return Err(format!("string:slice => start must be int, got {:?}", other)),
46    };
47    let end = match end_val {
48        Value::Int(i) => i,
49        other => return Err(format!("string:slice => end must be int, got {:?}", other)),
50    };
51    let len = s.chars().count() as i32;
52    let start = if start < 0 { len + start } else { start };
53    let end = if end < 0 { len + end } else { end };
54    let start = start.max(0).min(len);
55    let end = end.max(0).min(len);
56    let res: String = s.chars().skip(start as usize).take((end - start).max(0) as usize).collect();
57    Ok(Value::SingleString(res))
58}