rl_lang/interpreter/stdlib/string/format.rs
1use crate::interpreter::evaluator::Evaluator;
2use crate::interpreter::values::Value;
3use crate::utils::errors::Error;
4use crate::utils::span::Span;
5
6pub fn std_format(eval: &mut Evaluator, args: Vec<Value>, span: Span) -> Result<Value, Error> {
7 // checks for incorrect usage
8 if args.is_empty() {
9 return Err(eval.err("expected arguments".to_string(), span));
10 }
11
12 // making mutable empty string for the transformation
13 let mut result = String::new();
14 // transforming the values to string and collecting to Vec<String>
15 let args: Vec<String> = args.iter().map(|s| s.to_string()).collect();
16 // assigning the first value as the to be transformed value
17 let text = &args[0];
18 // assiging the rest of Vec<String> as replacement items
19 let mut rest_args = args[1..].iter();
20 // making the to be transformed value as characters to detect '{' and '}'
21 // this is better for escape codes
22 let mut chars = text.chars().peekable();
23 // check for unused args
24 let mut used = 0;
25 // check for missing args
26 let mut missing = 0;
27
28 // loop through the characters of to be transforming value
29 while let Some(c) = chars.next() {
30 // detect for "{}" while "{\}" or similiar doesnt work
31 // better than split on "{}"
32 if c == '{' && chars.peek() == Some(&'}') {
33 // consume the next '}'
34 chars.next();
35 // replace current "{}" with value from replacements
36 match rest_args.next() {
37 Some(v) => {
38 // add the replacement value
39 result.push_str(v);
40 used += 1;
41 }
42 None => {
43 // push "{}" to continue checking for how many is missing
44 result.push_str("{}");
45 missing += 1;
46 }
47 }
48 } else {
49 // push the character if not '{' that has '}' after
50 result.push(c);
51 }
52 }
53
54 // check for missing value that wasnt replaced
55 if missing > 0 {
56 return Err(eval.err(
57 format!(
58 "format() has {} placeholder(s) with no matching argument",
59 missing
60 ),
61 span,
62 ));
63 }
64
65 // check for additional values that is not used
66 if used < args.len() - 1 {
67 return Err(eval.err(
68 format!(
69 "format() received {} argument(s) but only {} placeholder(s) were used",
70 args.len() - 1,
71 used
72 ),
73 span,
74 ));
75 }
76
77 // returns the final transformed value
78 Ok(Value::String(result))
79}