| 185 | } |
| 186 | |
| 187 | fn format_string(template: &str, args: &[Value]) -> Result<String, VmError> { |
| 188 | let mut result = String::new(); |
| 189 | let mut chars = template.chars().peekable(); |
| 190 | let mut arg_index = 0; |
| 191 | |
| 192 | while let Some(c) = chars.next() { |
| 193 | if c == '{' { |
| 194 | if chars.next_if_eq(&'{').is_some() { |
| 195 | result.push('{'); |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | // Collect format spec |
| 200 | let mut spec = String::new(); |
| 201 | let mut nested = 1; |
| 202 | |
| 203 | for c in chars.by_ref() { |
| 204 | match c { |
| 205 | '{' => nested += 1, |
| 206 | '}' => { |
| 207 | nested -= 1; |
| 208 | if nested == 0 { |
| 209 | break; |
| 210 | } |
| 211 | } |
| 212 | _ => {} |
| 213 | } |
| 214 | spec.push(c); |
| 215 | } |
| 216 | |
| 217 | if nested != 0 { |
| 218 | return Err(VmError::RuntimeError( |
| 219 | "Unmatched brace in format string.".into(), |
| 220 | )); |
| 221 | } |
| 222 | |
| 223 | let format_spec = FormatSpec::parse(&spec)?; |
| 224 | |
| 225 | if arg_index >= args.len() { |
| 226 | return Err(VmError::RuntimeError( |
| 227 | "Not enough arguments for format string.".into(), |
| 228 | )); |
| 229 | } |
| 230 | |
| 231 | let formatted = format_spec.format(&args[arg_index])?; |
| 232 | write!(result, "{}", formatted).map_err(|e| VmError::RuntimeError(e.to_string()))?; |
| 233 | |
| 234 | arg_index += 1; |
| 235 | } else if c == '}' { |
| 236 | if chars.next_if_eq(&'}').is_some() { |
| 237 | result.push('}'); |
| 238 | } else { |
| 239 | return Err(VmError::RuntimeError( |
| 240 | "Single '}' encountered in format string.".into(), |
| 241 | )); |
| 242 | } |
| 243 | } else { |
| 244 | result.push(c); |