1use crate::{
2 CheckRef,
3 impls::solving::Solutions,
4 rules::implicits::{ImplicitExtApp, ImplicitExtBound, ImplicitExtTerm},
5 split::SplitStrategy,
6};
7use either::Either;
8use ftml_ontology::{
9 domain::{
10 SharedDeclaration,
11 declarations::{morphisms::Morphism, symbols::Symbol},
12 },
13 narrative::{SharedDocumentElement, elements::VariableDeclaration},
14 terms::{
15 ApplicationTerm, Argument, BindingTerm, BoundArgument, ComponentVar, IsTerm, MaybeSequence,
16 Term, Variable, helpers::IntoTerm, sequences::Sequence, termpaths::TermPath,
17 },
18};
19
20impl<Split: SplitStrategy> CheckRef<'_, '_, Split> {
21 #[inline]
22 #[must_use]
23 pub const fn rules(&self) -> &crate::rules::RuleSet<Split> {
24 &self.top.rules
25 }
26
27 pub(crate) fn prepare(&self, t: Term, path: Option<&mut TermPath>) -> (Solutions, Term) {
28 let mut cp = self.copied();
29 let mut ncp = cp.get_ref();
30 let old = ncp.context.take();
31 let r = ncp.prepare_i(t, path.map(|p| (p.inner_mut(), 0)));
32 ncp.context.set(old);
33 drop(ncp);
34 let sols = std::mem::take(&mut cp.solutions);
35 (sols, r)
36 }
37
38 pub(crate) fn revert_prepare(&self, t: Term) -> Term {
39 tracing::trace!("reverting preparation {:?}", t.debug_short());
40 let mut cp = self.copied();
41 let mut ncp = cp.get_ref();
42 let old = ncp.context.take();
43 let r = ncp.revert_i(t);
44 ncp.context.set(old);
45 r
46 }
47
48 pub fn get_head(
115 &self,
116 t: &Term,
117 ) -> Option<Either<SharedDeclaration<Symbol>, SharedDocumentElement<VariableDeclaration>>> {
118 let head = t.head()?;
119 Some(match head {
120 Either::Left(uri) => Either::Left(self.get_symbol(uri).ok()?),
121 Either::Right(Variable::Ref { declaration, .. }) => {
122 Either::Right(self.get_variable(declaration).ok()?)
123 }
124 either::Right(Variable::Name { .. }) => return None,
125 })
126 }
127
128 fn push_down_implicits(term: Term) -> Term {
129 if let Term::Application(ref app) = term
130 && app.head.is(&*ftml_uris::metatheory::APPLY_IMPLICIT)
131 && let [
132 Argument::Simple(f @ (Term::Application(_) | Term::Bound(_))),
133 Argument::Sequence(MaybeSequence::Seq(args)),
134 ] = &*app.arguments
135 {
136 let mut iter = args.iter();
137 let next = if let Term::Application(fapp) = f {
138 let napp = fapp
139 .head
140 .clone()
141 .apply_implicits(args.len(), |_| iter.next().expect("bug").clone());
142 Term::Application(ApplicationTerm::new(
143 napp,
144 fapp.arguments.clone(),
145 fapp.presentation.clone(),
146 ))
147 } else if let Term::Bound(fapp) = f {
148 let napp = fapp
149 .head
150 .clone()
151 .apply_implicits(args.len(), |_| iter.next().expect("bug").clone());
152 Term::Bound(BindingTerm::new(
153 napp,
154 fapp.arguments.clone(),
155 fapp.presentation.clone(),
156 ))
157 } else {
158 unreachable!("bug");
159 };
160 Self::push_down_implicits(next)
161 } else {
162 term
163 }
164 }
165
166 fn prepare_i(
167 &mut self,
168 mut t: Term,
169 mut path: Option<(&mut smallvec::SmallVec<u8, 16>, usize)>,
170 ) -> Term {
171 tracing::trace!("preparing {:?}", t.debug_short());
172 if t.unapply_implicits().is_some() {
175 return t;
176 }
177 match &t {
178 Term::Symbol { uri, presentation } => {
179 return if let Ok(sym) = self.get_symbol(uri)
180 && sym.data.tp.has_checked()
181 {
182 sym.data
183 .tp
184 .with_checked(|t| {
185 let (_, vars) = t.get_bound_implicits()?;
186 Some(
187 Term::Symbol {
188 uri: uri.clone(),
189 presentation: presentation.clone(),
190 }
191 .apply_implicits(vars.len(), |_| self.new_solvable()),
192 )
193 })
194 .flatten()
195 .unwrap_or(t)
196 } else {
197 t
198 };
199 }
200 Term::Var { .. } => return t,
201 _ => (),
202 }
203
204 for rl in self.top.rules.preparation() {
205 if !rl.applicable(self, &t) {
206 continue;
207 }
208 let path = match &mut path {
209 Some((p, t)) => Some((&mut **p, *t)),
210 _ => None,
211 };
212 match rl.apply(self, t, path) {
213 std::ops::ControlFlow::Break(t) => return t,
214 std::ops::ControlFlow::Continue(tm) => {
215 t = tm;
216 }
217 }
218 tracing::trace!("Rule {rl:?} applied; result: {:?}", t.debug_short());
219 }
220 self.prepare_recurse(t, |s, t, p| s.prepare_i(t, p), path)
221 }
222
223 fn revert_i(&mut self, t: Term) -> Term {
224 match &t {
225 Term::Application(b) if b.head.unapply_implicits().is_some() => {
226 let (t, args) = unsafe { b.head.unapply_implicits().unwrap_unchecked() };
228 {
229 return self.revert_i(
230 Term::Application(ApplicationTerm::new(
231 t.clone(),
232 b.arguments.clone(),
233 b.presentation.clone(),
234 ))
235 .apply_implicits(args.len(), |i| args[i].clone()),
236 );
237 }
238 }
239 Term::Bound(b) if b.head.unapply_implicits().is_some() => {
240 let (t, args) = unsafe { b.head.unapply_implicits().unwrap_unchecked() };
242 {
243 return self.revert_i(
244 Term::Bound(BindingTerm::new(
245 t.clone(),
246 b.arguments.clone(),
247 b.presentation.clone(),
248 ))
249 .apply_implicits(args.len(), |i| args[i].clone()),
250 );
251 }
252 }
253
254 Term::Application(a) if a.unapply_implicits().is_some() => {
255 let (t, _) = unsafe { a.unapply_implicits().unwrap_unchecked() };
257 return t.clone();
258 }
259 Term::Symbol { .. } | Term::Var { .. } => return t,
260 _ => (),
261 }
262
263 let mut tm = t;
264
265 for rl in self.top.rules.preparation().iter().rev() {
266 if !rl.applicable_revert(self, &tm) {
268 continue;
269 }
270 tm = match rl.revert(self, tm) {
271 std::ops::ControlFlow::Break(t) => return t,
272 std::ops::ControlFlow::Continue(t) => t,
273 };
274 tracing::trace!("Rule {rl:?} applied; result: {:?}", tm.debug_short());
275 }
276 self.prepare_recurse(tm, |s, t, _| s.revert_i(t), None)
277 }
278
279 fn prepare_recurse(
280 &mut self,
281 term: Term,
282 then: fn(
283 &mut CheckRef<'_, '_, Split>,
284 Term,
285 Option<(&mut smallvec::SmallVec<u8, 16>, usize)>,
286 ) -> Term,
287 mut path: Option<(&mut smallvec::SmallVec<u8, 16>, usize)>,
288 ) -> Term {
289 tracing::trace!("Recursing {:?}", term.debug_short());
290 match term {
291 Term::Application(a) => {
292 if let Term::Symbol { uri, .. } = &a.head
293 && let Ok(m) = self.get_declaration::<Morphism>(uri)
294 {
295 }
297 Term::Application(ApplicationTerm::new(
298 then(self, a.head.clone(), get_path(&mut path, 0)),
299 {
300 let mut idx = 0;
301 a.arguments
302 .iter()
303 .map(|arg| match arg {
304 Argument::Simple(t) => Argument::Simple(then(
305 self,
306 t.clone(),
307 get_path(&mut path, {
308 idx += 1;
309 idx
310 }),
311 )),
312 Argument::Sequence(MaybeSequence::One(t)) => {
313 Argument::Sequence(MaybeSequence::One(then(
314 self,
315 t.clone(),
316 get_path(&mut path, {
317 idx += 1;
318 idx
319 }),
320 )))
321 }
322 Argument::Sequence(MaybeSequence::Seq(ts)) => {
323 idx += 1;
324 let mut npath = get_path(&mut path, idx);
325 Argument::Sequence(MaybeSequence::Seq(
326 ts.iter()
327 .cloned()
328 .enumerate()
329 .map(|(i, t)| then(self, t, get_path(&mut npath, i)))
330 .collect(),
331 ))
332 }
333 })
334 .collect()
335 },
336 a.presentation.clone(),
337 ))
338 }
339 Term::Bound(b) => Term::Bound(BindingTerm::new(
340 then(self, b.head.clone(), get_path(&mut path, 0)),
341 self.scoped(|slf| {
342 let mut idx = 0;
343 b.arguments
344 .iter()
345 .map(|arg| match arg {
346 BoundArgument::Simple(t) => BoundArgument::Simple(then(
347 slf,
348 t.clone(),
349 get_path(&mut path, {
350 idx += 1;
351 idx
352 }),
353 )),
354 BoundArgument::Sequence(MaybeSequence::One(t)) => {
355 BoundArgument::Sequence(MaybeSequence::One(then(
356 slf,
357 t.clone(),
358 get_path(&mut path, {
359 idx += 1;
360 idx
361 }),
362 )))
363 }
364 BoundArgument::Sequence(MaybeSequence::Seq(ts)) => {
365 idx += 1;
366 let mut npath = get_path(&mut path, idx);
367 BoundArgument::Sequence(MaybeSequence::Seq(
368 ts.iter()
369 .cloned()
370 .enumerate()
371 .map(|(i, t)| then(slf, t, get_path(&mut npath, i)))
372 .collect(),
373 ))
374 }
375 BoundArgument::Bound(cv) => BoundArgument::Bound(slf.prepare_cv(
376 cv,
377 then,
378 get_path(&mut path, {
379 idx += 1;
380 idx
381 }),
382 )),
383 BoundArgument::BoundSeq(MaybeSequence::One(cv)) => {
384 BoundArgument::BoundSeq(MaybeSequence::One(slf.prepare_cv(
385 cv,
386 then,
387 get_path(&mut path, {
388 idx += 1;
389 idx
390 }),
391 )))
392 }
393 BoundArgument::BoundSeq(MaybeSequence::Seq(vars)) => {
394 idx += 1;
395 let mut npath = get_path(&mut path, idx);
396 BoundArgument::BoundSeq(MaybeSequence::Seq(
397 vars.iter()
398 .enumerate()
399 .map(|(i, cv)| {
400 slf.prepare_cv(cv, then, get_path(&mut npath, i))
401 })
402 .collect(),
403 ))
404 }
405 })
406 .collect()
407 }),
408 b.presentation.clone(),
409 )),
410 t => t,
411 }
412 }
413
414 #[allow(clippy::single_match_else)]
415 fn prepare_cv(
416 &mut self,
417 cv: &ComponentVar,
418 then: fn(&mut Self, Term, Option<(&mut smallvec::SmallVec<u8, 16>, usize)>) -> Term,
419 mut path: Option<(&mut smallvec::SmallVec<u8, 16>, usize)>,
420 ) -> ComponentVar {
421 tracing::trace!("preparing bound variable {}", cv.var.name());
422 let mut next = 0;
423 let tp = match &cv.tp {
424 Some(t) => {
425 next += 1;
426 Some(then(self, t.clone(), get_path(&mut path, 0)))
427 }
428 None => {
429 let r = self.infer_var_type_i(&cv.var);
430 if r.is_some()
431 && let Some((p, i)) = &mut path
432 && let Some(i) = p.get_mut(*i)
433 {
434 *i += 1;
435 next += 1;
436 }
437 r
438 }
439 };
440 let df = match &cv.df {
441 Some(t) => Some(then(self, t.clone(), get_path(&mut path, next))),
442 None => {
443 let r = self.get_var_definiens(&cv.var);
444 if r.is_some()
445 && let Some((p, i)) = &mut path
446 && let Some(i) = p.get_mut(*i)
447 {
448 *i += 1;
449 next += 1;
450 }
451 r
452 }
453 };
454 let cv = ComponentVar {
455 var: cv.var.clone(),
456 tp,
457 df,
458 };
459 tracing::trace!("Extending context");
460 self.extend_context(cv.clone());
461 tracing::trace!("Done");
462 cv
463 }
464}
465
466fn get_path<'a, 'b>(
467 op: &'a mut Option<(&'b mut smallvec::SmallVec<u8, 16>, usize)>,
468 idx: usize,
469) -> Option<(&'a mut smallvec::SmallVec<u8, 16>, usize)> {
470 op.as_mut().and_then(|(s, i)| {
471 if s.get(*i).copied() == Some(idx as u8) {
472 Some((&mut **s, *i + 1))
473 } else {
474 None
475 }
476 })
477}