Skip to content

Commit 913563e

Browse files
committed
start moving core to formality-core
1 parent c0e0691 commit 913563e

File tree

11 files changed

+1907
-1
lines changed

11 files changed

+1907
-1
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/formality-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ env_logger = "*"
1111
tracing = "0.1"
1212
tracing-subscriber = {version = "0.3", default-features = false, features = ["env-filter", "fmt"]}
1313
tracing-tree = { version = "0.2" }
14+
formality-macros = { path = "../formality-macros" }

crates/formality-core/src/binder.rs

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
//! Manages binders so that the main rules can be nice and simple.
2+
3+
use std::sync::atomic::{AtomicUsize, Ordering};
4+
5+
use anyhow::bail;
6+
use lazy_static::lazy_static;
7+
8+
use crate::{
9+
cast::{Downcast, DowncastFrom, DowncastTo, To, Upcast, UpcastFrom},
10+
fold::Fold,
11+
fold::SubstitutionFn,
12+
grammar::VarIndex,
13+
visit::Visit,
14+
};
15+
16+
use super::{BoundVar, DebruijnIndex, Fallible, Parameter, ParameterKind, Substitution, Variable};
17+
18+
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
19+
pub struct Binder<T> {
20+
kinds: Vec<ParameterKind>,
21+
term: T,
22+
}
23+
24+
impl<T: Fold> Binder<T> {
25+
/// Accesses the contents of the binder.
26+
///
27+
/// The variables inside will be renamed to fresh var indices
28+
/// that do not alias any other indices seen during this computation.
29+
///
30+
/// The expectation is that you will create a term and use `Binder::new`.
31+
pub fn open(&self) -> (Vec<BoundVar>, T) {
32+
let (bound_vars, substitution): (Vec<BoundVar>, Substitution) = self
33+
.kinds
34+
.iter()
35+
.zip(0..)
36+
.map(|(kind, index)| {
37+
let old_bound_var = BoundVar {
38+
debruijn: Some(DebruijnIndex::INNERMOST),
39+
var_index: VarIndex { index },
40+
kind: *kind,
41+
};
42+
let new_bound_var = fresh_bound_var(*kind);
43+
(new_bound_var, (old_bound_var, new_bound_var))
44+
})
45+
.unzip();
46+
47+
(bound_vars, substitution.apply(&self.term))
48+
}
49+
50+
pub fn dummy(term: T) -> Self {
51+
let v: Vec<Variable> = vec![];
52+
Self::new(v, term)
53+
}
54+
55+
/// Given a set of variables (X, Y, Z) and a term referecing some subset of them,
56+
/// create a binder where exactly those variables are bound (even the ones not used).
57+
pub fn new(variables: impl Upcast<Vec<Variable>>, term: T) -> Self {
58+
let variables: Vec<Variable> = variables.upcast();
59+
let (kinds, substitution): (Vec<ParameterKind>, Substitution) = variables
60+
.iter()
61+
.zip(0..)
62+
.map(|(old_bound_var, index)| {
63+
let old_bound_var: Variable = old_bound_var.upcast();
64+
assert!(old_bound_var.is_free());
65+
let new_bound_var: Parameter = BoundVar {
66+
debruijn: Some(DebruijnIndex::INNERMOST),
67+
var_index: VarIndex { index },
68+
kind: old_bound_var.kind(),
69+
}
70+
.upcast();
71+
(old_bound_var.kind(), (old_bound_var, new_bound_var))
72+
})
73+
.unzip();
74+
75+
let term = substitution.apply(&term);
76+
Binder { kinds, term }
77+
}
78+
79+
/// Given a set of variables (X, Y, Z) and a term referecing some subset of them,
80+
/// create a binder for just those variables that are mentioned.
81+
pub fn mentioned(variables: impl Upcast<Vec<Variable>>, term: T) -> Self {
82+
let mut variables: Vec<Variable> = variables.upcast();
83+
let fv = term.free_variables();
84+
variables.retain(|v| fv.contains(v));
85+
let variables: Vec<Variable> = variables.into_iter().collect();
86+
Binder::new(variables, term)
87+
}
88+
89+
pub fn into<U>(self) -> Binder<U>
90+
where
91+
T: Into<U>,
92+
{
93+
Binder {
94+
kinds: self.kinds,
95+
term: self.term.into(),
96+
}
97+
}
98+
99+
/// Number of variables bound by this binder
100+
pub fn len(&self) -> usize {
101+
self.kinds.len()
102+
}
103+
104+
pub fn is_empty(&self) -> bool {
105+
self.kinds.is_empty()
106+
}
107+
108+
/// Instantiate the binder with the given parameters, returning an err if the parameters
109+
/// are the wrong number or ill-kinded.
110+
pub fn instantiate_with(&self, parameters: &[impl Upcast<Parameter>]) -> Fallible<T> {
111+
if parameters.len() != self.kinds.len() {
112+
bail!("wrong number of parameters");
113+
}
114+
115+
for ((p, k), i) in parameters.iter().zip(&self.kinds).zip(0..) {
116+
let p: Parameter = p.upcast();
117+
if p.kind() != *k {
118+
bail!(
119+
"parameter {i} has kind {:?} but should have kind {:?}",
120+
p.kind(),
121+
k
122+
);
123+
}
124+
}
125+
126+
Ok(self.instantiate(|_kind, index| parameters[index.index].to()))
127+
}
128+
129+
/// Instantiate the term, replacing each bound variable with `op(i)`.
130+
pub fn instantiate(&self, mut op: impl FnMut(ParameterKind, VarIndex) -> Parameter) -> T {
131+
let substitution: Vec<Parameter> = self
132+
.kinds
133+
.iter()
134+
.zip(0..)
135+
.map(|(&kind, index)| op(kind, VarIndex { index }))
136+
.collect();
137+
138+
self.term.substitute(&mut |var| match var {
139+
Variable::BoundVar(BoundVar {
140+
debruijn: Some(DebruijnIndex::INNERMOST),
141+
var_index,
142+
kind: _,
143+
}) => Some(substitution[var_index.index].clone()),
144+
145+
_ => None,
146+
})
147+
}
148+
149+
/// Accesses the data inside the binder. Use this for simple tests that extract data
150+
/// that is independent of the bound variables. If that's not the case, use `open`.
151+
pub fn peek(&self) -> &T {
152+
&self.term
153+
}
154+
155+
/// Returns the kinds of each variable bound by this binder
156+
pub fn kinds(&self) -> &[ParameterKind] {
157+
&self.kinds
158+
}
159+
160+
pub fn map<U: Fold>(&self, op: impl FnOnce(T) -> U) -> Binder<U> {
161+
let (vars, t) = self.open();
162+
let u = op(t);
163+
Binder::new(vars, u)
164+
}
165+
}
166+
167+
/// Creates a fresh bound var of the given kind that is not yet part of a binder.
168+
/// You can put this into a term and then use `Binder::new`.
169+
pub fn fresh_bound_var(kind: ParameterKind) -> BoundVar {
170+
lazy_static! {
171+
static ref COUNTER: AtomicUsize = AtomicUsize::new(0);
172+
}
173+
174+
let index = COUNTER.fetch_add(1, Ordering::SeqCst);
175+
let var_index = VarIndex { index };
176+
BoundVar {
177+
debruijn: None,
178+
var_index,
179+
kind,
180+
}
181+
}
182+
183+
impl<T: Visit> Visit for Binder<T> {
184+
fn free_variables(&self) -> Vec<Variable> {
185+
self.term.free_variables()
186+
}
187+
188+
fn size(&self) -> usize {
189+
self.term.size()
190+
}
191+
192+
fn assert_valid(&self) {
193+
self.term.assert_valid();
194+
}
195+
}
196+
197+
impl<T: Fold> Fold for Binder<T> {
198+
fn substitute(&self, substitution_fn: SubstitutionFn<'_>) -> Self {
199+
let term = self.term.substitute(&mut |v| {
200+
// Shift this variable out through the binder. If that fails,
201+
// it's a variable bound by this binder, so the substitution can't
202+
// affect it, and we can just return None.
203+
let v1 = v.shift_out()?;
204+
205+
// Get the result of the subst (if any).
206+
let parameter = substitution_fn(v1)?;
207+
208+
// Shift that result in to account for this binder.
209+
Some(parameter.shift_in())
210+
});
211+
212+
Binder {
213+
kinds: self.kinds.clone(),
214+
term,
215+
}
216+
}
217+
218+
fn shift_in(&self) -> Self {
219+
let term = self.term.shift_in();
220+
Binder {
221+
kinds: self.kinds.clone(),
222+
term,
223+
}
224+
}
225+
}
226+
227+
impl<T, U> UpcastFrom<Binder<T>> for Binder<U>
228+
where
229+
T: Clone,
230+
U: Clone,
231+
T: Upcast<U>,
232+
{
233+
fn upcast_from(term: Binder<T>) -> Self {
234+
let Binder { kinds, term } = term;
235+
Binder {
236+
kinds,
237+
term: term.upcast(),
238+
}
239+
}
240+
}
241+
242+
impl<T, U> DowncastTo<Binder<T>> for Binder<U>
243+
where
244+
T: DowncastFrom<U>,
245+
{
246+
fn downcast_to(&self) -> Option<Binder<T>> {
247+
let Binder { kinds, term } = self;
248+
let term = term.downcast()?;
249+
Some(Binder {
250+
kinds: kinds.clone(),
251+
term,
252+
})
253+
}
254+
}
255+
256+
impl<T> std::fmt::Debug for Binder<T>
257+
where
258+
T: std::fmt::Debug,
259+
{
260+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
261+
write!(f, "<")?;
262+
for (kind, i) in self.kinds.iter().zip(0..) {
263+
if i > 0 {
264+
write!(f, ", ")?;
265+
}
266+
write!(f, "{:?}", kind)?;
267+
}
268+
write!(f, "> ")?;
269+
write!(f, "{:?}", &self.term)?;
270+
Ok(())
271+
}
272+
}

0 commit comments

Comments
 (0)