use super::*;
impl EngineState {
pub fn expressions_json(&self) -> String {
self.history.expressions()
}
pub fn set_expressions(&mut self, expressions: &str) -> String {
self.history.set_expressions(expressions);
self.rerun_history()
}
pub fn configurator_json(&self) -> String {
self.history.configurator().to_string()
}
pub fn expression_variables_json(&self) -> String {
let vars = parse_expression_variables(&self.history.expressions());
serde_json::to_string(&vars).unwrap_or_else(|_| "[]".to_string())
}
}
fn parse_expression_variables(source: &str) -> Vec<serde_json::Value> {
let mut cleaned = String::with_capacity(source.len());
for line in source.lines() {
let code = match line.find("//") {
Some(idx) => &line[..idx],
None => line,
};
cleaned.push_str(code);
cleaned.push('\n');
}
let mut out = Vec::new();
for stmt in cleaned.split(';') {
let stmt = stmt.trim();
if stmt.is_empty() {
continue;
}
let Some(eq) = stmt.find('=') else {
continue;
};
let name = stmt[..eq].trim();
let expr = stmt[eq + 1..].trim();
if name.is_empty() || expr.is_empty() || !is_identifier(name) {
continue;
}
out.push(serde_json::json!({ "name": name, "expr": expr }));
}
out
}
fn is_identifier(s: &str) -> bool {
let mut chars = s.chars();
match chars.next() {
Some(c) if c.is_ascii_alphabetic() || c == '_' || c == '$' => {}
_ => return false,
}
chars.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '$')
}