steel decimal crate with a proper setup, needs so much work to be done to be finished

This commit is contained in:
filipriec
2025-07-04 11:56:21 +02:00
parent 93c67ffa14
commit f4a23be1a2
13 changed files with 1260 additions and 264 deletions

176
steel_decimal/src/parser.rs Normal file
View File

@@ -0,0 +1,176 @@
// src/parser.rs
use regex::Regex;
use std::collections::HashSet;
pub struct ScriptParser {
math_operators: Vec<(Regex, &'static str)>,
number_literal_re: Regex,
variable_re: Regex,
}
impl ScriptParser {
pub fn new() -> Self {
let math_operators = vec![
// Basic arithmetic
(Regex::new(r"\(\s*\+\s+").unwrap(), "(decimal-add "),
(Regex::new(r"\(\s*-\s+").unwrap(), "(decimal-sub "),
(Regex::new(r"\(\s*\*\s+").unwrap(), "(decimal-mul "),
(Regex::new(r"\(\s*/\s+").unwrap(), "(decimal-div "),
// Power and advanced operations
(Regex::new(r"\(\s*\^\s+").unwrap(), "(decimal-pow "),
(Regex::new(r"\(\s*\*\*\s+").unwrap(), "(decimal-pow "),
(Regex::new(r"\(\s*pow\s+").unwrap(), "(decimal-pow "),
(Regex::new(r"\(\s*sqrt\s+").unwrap(), "(decimal-sqrt "),
// Logarithmic functions
(Regex::new(r"\(\s*ln\s+").unwrap(), "(decimal-ln "),
(Regex::new(r"\(\s*log\s+").unwrap(), "(decimal-ln "),
(Regex::new(r"\(\s*log10\s+").unwrap(), "(decimal-log10 "),
(Regex::new(r"\(\s*exp\s+").unwrap(), "(decimal-exp "),
// Trigonometric functions
(Regex::new(r"\(\s*sin\s+").unwrap(), "(decimal-sin "),
(Regex::new(r"\(\s*cos\s+").unwrap(), "(decimal-cos "),
(Regex::new(r"\(\s*tan\s+").unwrap(), "(decimal-tan "),
// Comparison operators
(Regex::new(r"\(\s*>\s+").unwrap(), "(decimal-gt "),
(Regex::new(r"\(\s*<\s+").unwrap(), "(decimal-lt "),
(Regex::new(r"\(\s*=\s+").unwrap(), "(decimal-eq "),
(Regex::new(r"\(\s*>=\s+").unwrap(), "(decimal-gte "),
(Regex::new(r"\(\s*<=\s+").unwrap(), "(decimal-lte "),
// Utility functions
(Regex::new(r"\(\s*abs\s+").unwrap(), "(decimal-abs "),
(Regex::new(r"\(\s*min\s+").unwrap(), "(decimal-min "),
(Regex::new(r"\(\s*max\s+").unwrap(), "(decimal-max "),
(Regex::new(r"\(\s*round\s+").unwrap(), "(decimal-round "),
];
ScriptParser {
math_operators,
number_literal_re: Regex::new(r#"(?<!")(-?\d+\.?\d*(?:[eE][+-]?\d+)?)(?!")"#).unwrap(),
variable_re: Regex::new(r"\$(\w+)").unwrap(),
}
}
/// Transform a script by converting math operations and numbers to decimal functions
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
transformed = self.replace_math_functions(&transformed);
// Step 3: Replace variable references
transformed = self.replace_variable_references(&transformed);
transformed
}
/// Convert all unquoted numeric literals to quoted strings
fn convert_numbers_to_strings(&self, script: &str) -> String {
self.number_literal_re.replace_all(script, |caps: &regex::Captures| {
format!("\"{}\"", &caps[1])
}).to_string()
}
/// Replace math function calls with decimal equivalents
fn replace_math_functions(&self, script: &str) -> String {
let mut result = script.to_string();
for (pattern, replacement) in &self.math_operators {
result = pattern.replace_all(&result, *replacement).to_string();
}
result
}
/// Replace variable references ($var) with function calls
fn replace_variable_references(&self, script: &str) -> String {
self.variable_re.replace_all(script, |caps: &regex::Captures| {
format!("(get-var \"{}\")", &caps[1])
}).to_string()
}
/// Extract dependencies from script (useful for analysis)
pub fn extract_dependencies(&self, script: &str) -> HashSet<String> {
let mut dependencies = HashSet::new();
// Extract variable dependencies
for cap in self.variable_re.captures_iter(script) {
dependencies.insert(cap[1].to_string());
}
dependencies
}
}
impl Default for ScriptParser {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_math_transformation() {
let parser = ScriptParser::new();
let input = "(+ 1.5 2.3)";
let expected = "(decimal-add \"1.5\" \"2.3\")";
let result = parser.transform(input);
assert_eq!(result, expected);
}
#[test]
fn test_complex_expression() {
let parser = ScriptParser::new();
let input = "(+ (* 2 3) (/ 10 2))";
let expected = "(decimal-add (decimal-mul \"2\" \"3\") (decimal-div \"10\" \"2\"))";
let result = parser.transform(input);
assert_eq!(result, expected);
}
#[test]
fn test_variable_replacement() {
let parser = ScriptParser::new();
let input = "(+ $x $y)";
let expected = "(decimal-add (get-var \"x\") (get-var \"y\"))";
let result = parser.transform(input);
assert_eq!(result, expected);
}
#[test]
fn test_negative_numbers() {
let parser = ScriptParser::new();
let input = "(+ -1.5 2.3)";
let expected = "(decimal-add \"-1.5\" \"2.3\")";
let result = parser.transform(input);
assert_eq!(result, expected);
}
#[test]
fn test_scientific_notation() {
let parser = ScriptParser::new();
let input = "(+ 1.5e2 2.3E-1)";
let expected = "(decimal-add \"1.5e2\" \"2.3E-1\")";
let result = parser.transform(input);
assert_eq!(result, expected);
}
}