use crate::lexer::{Lexer, Token, TokenType};
use anyhow::Result;
impl Lexer {
pub fn expand_string_interpolation(&self, tokens: Vec<Token>) -> Result<Vec<Token>> {
let mut result = Vec::new();
for token in tokens {
if token.token_type == TokenType::String && self.contains_interpolation(&token) {
result.extend(self.expand_interpolated_string(token)?);
} else {
result.push(token);
}
}
Ok(result)
}
fn contains_interpolation(&self, token: &Token) -> bool {
if let Some(text) = &token.text {
text.contains("${")
} else {
false
}
}
fn expand_interpolated_string(&self, token: Token) -> Result<Vec<Token>> {
let text = token.text.as_ref().unwrap();
let mut result = Vec::new();
let mut current_pos = 0;
while let Some(start_pos) = text[current_pos..].find("${") {
let actual_start = current_pos + start_pos;
if actual_start > current_pos {
let text_part = &text[current_pos..actual_start];
result.push(Token::with_text(TokenType::StringPart, text_part));
}
let expr_start = actual_start + 2; if let Some(end_pos) = self.find_matching_brace(text, expr_start) {
result.push(Token::simple(TokenType::InterpolationStart));
let expr_text = &text[expr_start..end_pos];
let expr_tokens = Self::tokenize(expr_text)?;
for expr_token in expr_tokens {
if expr_token.token_type != TokenType::Eof {
result.push(expr_token);
}
}
result.push(Token::simple(TokenType::InterpolationEnd));
current_pos = end_pos + 1; } else {
return Err(anyhow::anyhow!(
"Unclosed interpolation in string: missing '}}' after '${{' at position {}",
actual_start
));
}
}
if current_pos < text.len() {
let remaining = &text[current_pos..];
result.push(Token::with_text(TokenType::StringPart, remaining));
}
Ok(result)
}
fn find_matching_brace(&self, text: &str, start: usize) -> Option<usize> {
let chars: Vec<char> = text.chars().collect();
let mut brace_count = 1;
let mut in_string = false;
let mut escape_next = false;
for (i, &ch) in chars.iter().enumerate().skip(start) {
if escape_next {
escape_next = false;
continue;
}
match ch {
'\\' if in_string => escape_next = true,
'"' => in_string = !in_string,
'{' if !in_string => brace_count += 1,
'}' if !in_string => {
brace_count -= 1;
if brace_count == 0 {
return Some(i);
}
}
_ => {}
}
}
None }
}