mumustring/partial/
slice.rs1use 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}