diff options
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 132 |
1 files changed, 116 insertions, 16 deletions
diff --git a/src/main.rs b/src/main.rs index 911948d..aae5122 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,29 +1,129 @@ -use difx::sexpr::Parser; +use difx::def_rules::Rule; use difx::match_rules::{self, Bindings}; +use difx::simplify; +use difx::sexpr::{Expr, Parser}; +use rustyline::DefaultEditor; +use rustyline::error::ReadlineError; + +const MAX_REWRITE_ITERS: usize = 100; + +fn parse_expr(input: &str) -> Option<Expr> { + std::panic::catch_unwind(|| { + let mut parser = Parser::new(input); + parser.parse_one() + }) + .ok() +} + +fn rewrite_node(rules: &[Rule], expr: &Expr) -> Option<(usize, Expr)> { + for (idx, rule) in rules.iter().enumerate() { + let mut bindings = Bindings::default(); + if match_rules::matches(&rule.lhs, expr, &mut bindings) { + let rewritten = match_rules::substitute(&rule.rhs, &bindings); + return Some((idx, rewritten)); + } + } + + None +} + +fn rewrite_top_down_once(rules: &[Rule], expr: &Expr) -> Option<(usize, Expr)> { + if let Some(hit) = rewrite_node(rules, expr) { + return Some(hit); + } + + match expr { + Expr::Atom(_) => None, + Expr::Application(items) => { + for (idx, item) in items.iter().enumerate() { + if let Some((rule_idx, rewritten_child)) = rewrite_top_down_once(rules, item) { + let mut rewritten_items = items.clone(); + rewritten_items[idx] = rewritten_child; + return Some((rule_idx, Expr::Application(rewritten_items))); + } + } + + None + } + Expr::OrderedList(items) => { + for (idx, item) in items.iter().enumerate() { + if let Some((rule_idx, rewritten_child)) = rewrite_top_down_once(rules, item) { + let mut rewritten_items = items.clone(); + rewritten_items[idx] = rewritten_child; + return Some((rule_idx, Expr::OrderedList(rewritten_items))); + } + } + + None + } + } +} fn main() { - let input = include_str!("../test_rule"); + let input = include_str!("../base.rules"); let rules = difx::def_rules::parse_def_rules(input.to_string()); - // println!("{:#?}", rules); - let pat = rules[0].clone().lhs; - println!("{:?}", pat); + println!("Loaded {} rule(s) from base.rules", rules.len()); + + let mut rl = DefaultEditor::new().expect("failed to initialize line editor"); loop { - let mut input = String::new(); - std::io::stdin() - .read_line(&mut input) - .unwrap(); + let line = match rl.readline("> ") { + Ok(line) => line, + Err(ReadlineError::Interrupted) => { + println!("^C"); + continue; + } + Err(ReadlineError::Eof) => { + println!(); + break; + } + Err(err) => { + eprintln!("Readline error: {err}"); + break; + } + }; - let mut parser = Parser::new(&input); - let parsed = parser.parse_one(); + let line = line.trim(); + if line.is_empty() { + continue; + } - let mut bindings = Bindings::default(); + if let Err(err) = rl.add_history_entry(line) { + eprintln!("history error: {err}"); + } + + let Some(mut expr) = parse_expr(line) else { + println!("Parse error"); + continue; + }; - if match_rules::matches(&pat, &parsed, &mut bindings) { - println!("{:?}", &bindings); - println!("MATCH"); + let mut applied = 0usize; + while applied < MAX_REWRITE_ITERS { + let Some((idx, rewritten_expr)) = rewrite_top_down_once(&rules, &expr) else { + break; + }; + let next_expr = simplify::simplify(rewritten_expr); + + let rule = &rules[idx]; + println!("{}.", applied + 1); + println!("```lisp\n{} => {}\n```", rule.lhs, rule.rhs); + println!("> {}", next_expr); + + expr = next_expr; + applied += 1; + } + + if applied == 0 { + println!("NO MATCH"); + } else { + println!("final: {}", expr); + } + + let stopped = applied == MAX_REWRITE_ITERS; + if applied == MAX_REWRITE_ITERS { + let stop_msg = format!("Stopped after {} iterations (safety limit).", MAX_REWRITE_ITERS); + println!("{}", stop_msg); } } } - |
