diff --git a/steel_decimal/src/parser.rs b/steel_decimal/src/parser.rs index 288dddb..62e8cd9 100644 --- a/steel_decimal/src/parser.rs +++ b/steel_decimal/src/parser.rs @@ -4,7 +4,7 @@ use std::collections::HashSet; pub struct ScriptParser { math_operators: Vec<(Regex, &'static str)>, - number_literal_re: Regex, + number_re: Regex, variable_re: Regex, } @@ -50,8 +50,10 @@ impl ScriptParser { ScriptParser { math_operators, - // Simple regex that matches numbers - we'll handle context in the replacement - number_literal_re: Regex::new(r"\b(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\b").unwrap(), + // VALID REGEX: + // This captures the preceding delimiter (group 1) and the number (group 2) separately. + // This avoids lookarounds and allows us to reconstruct the string correctly. + number_re: Regex::new(r"(^|[\s\(])(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)").unwrap(), variable_re: Regex::new(r"\$(\w+)").unwrap(), } } @@ -60,40 +62,40 @@ impl ScriptParser { pub fn transform(&self, script: &str) -> String { let mut transformed = script.to_string(); - // Step 1: Convert numeric literals to strings - transformed = self.convert_numbers_to_strings(&transformed); - - // Step 2: Replace math function calls with decimal equivalents + // CORRECT ORDER: Functions first, then variables, then numbers. transformed = self.replace_math_functions(&transformed); - - // Step 3: Replace variable references transformed = self.replace_variable_references(&transformed); + transformed = self.convert_numbers_to_strings(&transformed); transformed } /// Convert all unquoted numeric literals to quoted strings fn convert_numbers_to_strings(&self, script: &str) -> String { - // Simple approach: split on quotes and only process unquoted sections let parts: Vec<&str> = script.split('"').collect(); let mut result = String::new(); - + for (i, part) in parts.iter().enumerate() { if i % 2 == 0 { // Even indices are outside quotes - process them - let processed = self.number_literal_re.replace_all(part, "\"$1\""); + let processed = self.number_re.replace_all(part, |caps: ®ex::Captures| { + // Reconstruct the string: + // caps[1] is the delimiter (space, '(', or start of string) + // caps[2] is the number itself + // We put the delimiter back and wrap the number in quotes. + format!("{}\"{}\"", &caps[1], &caps[2]) + }); result.push_str(&processed); } else { // Odd indices are inside quotes - keep as is result.push_str(part); } - - // Add back the quote if not the last part + if i < parts.len() - 1 { result.push('"'); } } - + result } @@ -119,7 +121,6 @@ impl ScriptParser { pub fn extract_dependencies(&self, script: &str) -> HashSet { let mut dependencies = HashSet::new(); - // Extract variable dependencies for cap in self.variable_re.captures_iter(script) { dependencies.insert(cap[1].to_string()); }