use egglog_lib as egglog;
#[derive(Debug, Clone)]
pub struct EgglogResult {
pub canonical_prop: String,
pub graph_json: String,
}
const SCHEMA: &str = include_str!("egglog_schema.egg");
const RULES: &str = include_str!("egglog_rules.egg");
pub fn run_egglog_analysis(
text_id: i64,
texticules: &[crate::jbo_prop::Texticule],
) -> Result<EgglogResult, String> {
let mut egraph = egglog::EGraph::default();
egraph
.parse_and_run_program(None, SCHEMA)
.map_err(|e| format!("egglog schema error: {e}"))?;
let facts = crate::egglog_lower::lower_text(text_id, texticules);
if !facts.trim().is_empty() {
egraph
.parse_and_run_program(None, &facts)
.map_err(|e| format!("egglog facts error: {e}\nfacts:\n{facts}"))?;
}
let run_program = format!("{RULES}\n(run 1000)");
egraph
.parse_and_run_program(None, &run_program)
.map_err(|e| format!("egglog rules error: {e}"))?;
let canonical_prop = extract_canonical_prop(&mut egraph, text_id);
let graph_json = serialize_egraph(&egraph);
Ok(EgglogResult {
canonical_prop,
graph_json,
})
}
fn extract_canonical_prop(egraph: &mut egglog::EGraph, text_id: i64) -> String {
let extract_program = format!(
"(extract (TexticuleProp (Eet)))\n"
);
let _ = text_id;
match egraph.parse_and_run_program(None, &extract_program) {
Ok(outputs) => {
for out in &outputs {
let s = format!("{out}");
if !s.trim().is_empty() {
return s.trim().to_string();
}
}
"(Eet)".to_string()
}
Err(_) => "(Eet)".to_string(),
}
}
fn serialize_egraph(egraph: &egglog::EGraph) -> String {
let config = egglog::SerializeConfig {
max_functions: Some(256),
max_calls_per_function: Some(1024),
include_temporary_functions: false,
root_eclasses: vec![],
};
let output = egraph.serialize(config);
match serde_json::to_string(&output.egraph) {
Ok(json) => json,
Err(e) => format!("{{\"error\":\"serialization failed: {}\"}}", e),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_text_runs_without_error() {
let result = run_egglog_analysis(0, &[]);
assert!(result.is_ok(), "empty text failed: {:?}", result.err());
}
}