i did actually pattern matching holy crap
This commit is contained in:
parent
6a39bf6bac
commit
6e00f260a8
1 changed files with 68 additions and 30 deletions
98
src/main.rs
98
src/main.rs
|
@ -1,6 +1,6 @@
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::{HashMap, HashSet},
|
||||||
env,
|
env,
|
||||||
io::{self, Read},
|
io::{self, Read},
|
||||||
iter,
|
iter,
|
||||||
|
@ -436,6 +436,23 @@ impl Rule {
|
||||||
rhs: to.clone(),
|
rhs: to.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn concrete_with_matches(&self, matches: &Matches<'_>) -> Rule {
|
||||||
|
match self {
|
||||||
|
Rule::Forall { vars, .. } => {
|
||||||
|
let mut out = self.clone();
|
||||||
|
|
||||||
|
for var in vars {
|
||||||
|
let expr = matches.get(var).copied().cloned().unwrap_or_else(Sexp::nil);
|
||||||
|
out = out.concrify(&expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
Rule::Concrete { .. } => self.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Rule {
|
impl fmt::Display for Rule {
|
||||||
|
@ -473,45 +490,76 @@ fn could_match(vars: Option<&[Symbol]>, lhs: &Sexp, expr: &Sexp) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// type Matches<'src> = HashMap<Symbol, HashSet<&'src Sexp>>;
|
type Matches<'src> = HashMap<Symbol, &'src Sexp>;
|
||||||
|
|
||||||
// TODO: there. can. be. at most. one. match.
|
// DONE?: there. can. be. at most. one. match.
|
||||||
// i'm happy that this is faster, but it might be worth going back to the per-variable thing
|
// i'm happy that this is faster, but it might be worth going back to the per-variable thing
|
||||||
fn matches<'src>(vars: &HashSet<Symbol>, lhs: &Sexp, expr: &'src Sexp) -> HashSet<&'src Sexp> {
|
fn matches<'src>(vars: &[Symbol], lhs: &Sexp, expr: &'src Sexp) -> Option<Matches<'src>> {
|
||||||
match (lhs, expr) {
|
match (lhs, expr) {
|
||||||
(Sexp::Atom(a), Sexp::Atom(b)) => {
|
(Sexp::Atom(a), Sexp::Atom(b)) => {
|
||||||
if a == b || vars.contains(a) {
|
if a == b {
|
||||||
let mut out = HashSet::with_capacity(1);
|
Some(HashMap::with_capacity(0))
|
||||||
out.insert(expr);
|
} else if vars.contains(a) {
|
||||||
out
|
let mut out = HashMap::with_capacity(1);
|
||||||
|
out.insert(*a, expr);
|
||||||
|
Some(out)
|
||||||
} else {
|
} else {
|
||||||
HashSet::with_capacity(0)
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Sexp::Atom(a), Sexp::List(_)) => {
|
(Sexp::Atom(a), Sexp::List(_)) => {
|
||||||
if vars.contains(a) {
|
if vars.contains(a) {
|
||||||
let mut out = HashSet::with_capacity(1);
|
let mut out = HashMap::with_capacity(1);
|
||||||
out.insert(expr);
|
out.insert(*a, expr);
|
||||||
out
|
Some(out)
|
||||||
} else {
|
} else {
|
||||||
HashSet::with_capacity(0)
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Sexp::List(_), Sexp::Atom(_)) => HashSet::with_capacity(0),
|
(Sexp::List(_), Sexp::Atom(_)) => None,
|
||||||
(Sexp::List(xs), Sexp::List(ys)) => {
|
(Sexp::List(xs), Sexp::List(ys)) => {
|
||||||
if xs.len() == ys.len() {
|
if xs.len() == ys.len() {
|
||||||
xs.iter()
|
xs.iter()
|
||||||
.zip(ys)
|
.zip(ys)
|
||||||
.map(|(lhs, expr)| matches(vars, lhs, expr))
|
.map(|(lhs, expr)| matches(vars, lhs, expr))
|
||||||
.reduce(|a, b| a.union(&b).copied().collect())
|
.reduce(|a, b| match (a, b) {
|
||||||
.unwrap_or(HashSet::with_capacity(0))
|
(None, _) => None,
|
||||||
|
(_, None) => None,
|
||||||
|
(Some(a), Some(b)) => merge_matches(vars, a, b),
|
||||||
|
})
|
||||||
|
.unwrap_or(None)
|
||||||
} else {
|
} else {
|
||||||
HashSet::with_capacity(0)
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn merge_matches<'src>(
|
||||||
|
vars: &[Symbol],
|
||||||
|
a: Matches<'src>,
|
||||||
|
b: Matches<'src>,
|
||||||
|
) -> Option<Matches<'src>> {
|
||||||
|
let mut out = HashMap::with_capacity(vars.len());
|
||||||
|
|
||||||
|
for var in vars {
|
||||||
|
match (a.get(var), b.get(var)) {
|
||||||
|
(None, None) => {}
|
||||||
|
(Some(m), None) | (None, Some(m)) => {
|
||||||
|
out.insert(*var, *m);
|
||||||
|
}
|
||||||
|
(Some(a), Some(b)) => {
|
||||||
|
if a != b {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
out.insert(*var, *a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(out)
|
||||||
|
}
|
||||||
|
|
||||||
// fn absorb_matches<'src>(from: Matches<'src>, into: &mut Matches<'src>) {
|
// fn absorb_matches<'src>(from: Matches<'src>, into: &mut Matches<'src>) {
|
||||||
// for (var, matches) in from {
|
// for (var, matches) in from {
|
||||||
// let insert_into = into.entry(var).or_default();
|
// let insert_into = into.entry(var).or_default();
|
||||||
|
@ -527,19 +575,9 @@ fn rw(rule: &Rule, sexp: &Sexp) -> Sexp {
|
||||||
}
|
}
|
||||||
|
|
||||||
match rule {
|
match rule {
|
||||||
rule @ Rule::Forall { vars, lhs, .. } => {
|
Rule::Forall { vars, lhs, .. } => {
|
||||||
if could_match(Some(vars), lhs, sexp) {
|
if let Some(matc) = matches(vars, lhs, sexp) {
|
||||||
// let targets = sexp.concretion_targets();
|
rule.concrete_with_matches(&matc).rw(sexp)
|
||||||
let targets = matches(&vars.iter().copied().collect(), lhs, sexp);
|
|
||||||
let mut out = sexp.clone();
|
|
||||||
for rule in rule.concretions(&targets) {
|
|
||||||
let rwed = rw(&rule, &out);
|
|
||||||
if rwed != out {
|
|
||||||
out = rwed;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out
|
|
||||||
} else {
|
} else {
|
||||||
match sexp {
|
match sexp {
|
||||||
Sexp::Atom(_) => sexp.clone(),
|
Sexp::Atom(_) => sexp.clone(),
|
||||||
|
|
Loading…
Reference in a new issue