virtual_rust/interpreter/
format.rs1use crate::interpreter::error::RuntimeError;
4use crate::interpreter::value::Value;
5
6pub fn format_string(fmt: &str, args: &[Value]) -> Result<String, RuntimeError> {
15 let mut result = String::new();
16 let mut arg_index = 0;
17 let mut chars = fmt.chars().peekable();
18
19 while let Some(c) = chars.next() {
20 match c {
21 '{' => format_placeholder(&mut chars, &mut result, args, &mut arg_index),
22 '}' if chars.peek() == Some(&'}') => {
23 chars.next();
24 result.push('}');
25 }
26 _ => result.push(c),
27 }
28 }
29
30 Ok(result)
31}
32
33fn format_placeholder(
35 chars: &mut std::iter::Peekable<std::str::Chars<'_>>,
36 result: &mut String,
37 args: &[Value],
38 arg_index: &mut usize,
39) {
40 if chars.peek() == Some(&'{') {
41 chars.next();
43 result.push('{');
44 return;
45 }
46
47 if chars.peek() == Some(&'}') {
48 chars.next();
50 if *arg_index < args.len() {
51 result.push_str(&format!("{}", args[*arg_index]));
52 *arg_index += 1;
53 } else {
54 result.push_str("{}");
55 }
56 return;
57 }
58
59 let mut placeholder = String::new();
61 while let Some(&c) = chars.peek() {
62 if c == '}' {
63 chars.next();
64 break;
65 }
66 placeholder.push(c);
67 chars.next();
68 }
69
70 if let Some(spec) = placeholder.strip_prefix(':') {
71 format_with_spec(spec, result, args, arg_index);
73 } else if let Ok(idx) = placeholder.parse::<usize>() {
74 if idx < args.len() {
76 result.push_str(&format!("{}", args[idx]));
77 }
78 } else {
79 if *arg_index < args.len() {
81 result.push_str(&format!("{}", args[*arg_index]));
82 *arg_index += 1;
83 } else {
84 result.push('{');
85 result.push_str(&placeholder);
86 result.push('}');
87 }
88 }
89}
90
91fn format_with_spec(spec: &str, result: &mut String, args: &[Value], arg_index: &mut usize) {
93 if *arg_index >= args.len() {
94 return;
95 }
96
97 let arg = &args[*arg_index];
98 *arg_index += 1;
99
100 if spec == "?" {
101 result.push_str(&arg.debug_fmt());
103 } else if let Some(prec_str) = spec.strip_prefix('.') {
104 if let Ok(precision) = prec_str.parse::<usize>() {
106 if let Value::Float(n) = arg {
107 result.push_str(&format!("{n:.prec$}", prec = precision));
108 } else {
109 result.push_str(&format!("{arg}"));
110 }
111 } else {
112 result.push_str(&format!("{arg}"));
113 }
114 } else {
115 result.push_str(&format!("{arg}"));
116 }
117}