Skip to main content

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}