Skip to main content

ftml_solver/impls/
preparation.rs

1use crate::{
2    CheckRef,
3    impls::{records::Record, 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        OpaqueTerm, 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    /*
49    pub(crate) fn bind_implicits(&mut self, nt: Term) -> Term {
50        tracing::trace!("Binding implicits for {:?}", nt.debug_short());
51        let mut allvars = nt
52            .free_variables()
53            .into_iter()
54            .cloned()
55            .collect::<SmallVec<_, 4>>();
56        let mut curr_idx = 0;
57        if allvars.is_empty() {
58            return nt;
59        }
60        while curr_idx < allvars.len() {
61            if let Variable::Ref { declaration, .. } = &allvars[curr_idx]
62                && let Ok(v) = self.get_variable(declaration)
63                && let Some((tp, _)) = v.data.tp.checked_or_parsed()
64            {
65                let vars = tp.free_variables();
66                let mut changed = false;
67                for v in vars {
68                    if !allvars[..curr_idx].contains(v) {
69                        allvars.insert(curr_idx, v.clone());
70                        changed = true;
71                    }
72                }
73                if changed {
74                    continue;
75                }
76            }
77            curr_idx += 1;
78        }
79        tracing::trace!("All variables: {allvars:?}");
80
81        let mut ctx = smallvec::SmallVec::<_, 4>::new();
82        for v in allvars {
83            if !ctx.iter().any(|(var, _)| *var == v) {
84                let name = self.new_solvable();
85                let Variable::Name { name: id, .. } = &name else {
86                    // SAFETY: new_solvable always returns Variable::Name
87                    unsafe { unreachable_unchecked() }
88                };
89                let tp = self.infer_var_type_i(&v);
90                if let Some(tp) = tp {
91                    self.comment(format!("Solving type of {id}"));
92                    self.solve_type(id.clone(), tp / ctx.as_slice());
93                }
94
95                ctx.push((
96                    v,
97                    Term::Var {
98                        variable: name,
99                        presentation: None,
100                    },
101                ));
102            }
103        }
104        if ctx.is_empty() {
105            return nt;
106        }
107        tracing::trace!("New context: {ctx:?}");
108        let n = nt / ctx.as_slice();
109        tracing::trace!("Implicitified: {:?}", n.debug_short());
110        n
111    }
112     */
113
114    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    /*
129    fn push_down_implicits(term: Term) -> Term {
130        if let Term::Application(ref app) = term
131            && app.head.is(&*ftml_uris::metatheory::APPLY_IMPLICIT)
132            && let [
133                Argument::Simple(f @ (Term::Application(_) | Term::Bound(_))),
134                Argument::Sequence(MaybeSequence::Seq(args)),
135            ] = &*app.arguments
136        {
137            let mut iter = args.iter();
138            let next = if let Term::Application(fapp) = f {
139                let napp = fapp
140                    .head
141                    .clone()
142                    .apply_implicits(args.len(), |_| iter.next().expect("bug").clone());
143                Term::Application(ApplicationTerm::new(
144                    napp,
145                    fapp.arguments.clone(),
146                    fapp.presentation.clone(),
147                ))
148            } else if let Term::Bound(fapp) = f {
149                let napp = fapp
150                    .head
151                    .clone()
152                    .apply_implicits(args.len(), |_| iter.next().expect("bug").clone());
153                Term::Bound(BindingTerm::new(
154                    napp,
155                    fapp.arguments.clone(),
156                    fapp.presentation.clone(),
157                ))
158            } else {
159                unreachable!("bug");
160            };
161            Self::push_down_implicits(next)
162        } else {
163            term
164        }
165    }
166     */
167
168    fn prepare_i(
169        &mut self,
170        mut t: Term,
171        mut path: Option<(&mut smallvec::SmallVec<u8, 16>, usize)>,
172    ) -> Term {
173        tracing::trace!("preparing {:?}", t.debug_short());
174        //let mut t = Self::prepare_seqs(t);
175        //let mut t = Self::push_down_implicits(t);
176        if t.unapply_implicits(false).is_some() {
177            return t;
178        }
179        match &t {
180            Term::Field(f) => {
181                if let Some(r) = self.scoped(|slf| {
182                    if let Ok(r) = Record::from_term(&f.record, f.record_type.as_ref(), slf)
183                    && let Some(sym) = r.get_type().get_symbol(&f.key)
184                    //&& sym.data.tp.has_checked()
185                    && let Some(Some(vars)) = sym
186                        .data
187                        .tp
188                        .with_checked(|t| Some(t.get_bound_implicits()?.1.len()))
189                    {
190                        Some(t.clone().apply_implicits(vars, |_| slf.new_solvable()))
191                    } else {
192                        None
193                    }
194                }) {
195                    return r;
196                }
197            }
198            Term::Symbol { uri, presentation } => {
199                return if let Ok(sym) = self.get_symbol(uri)
200                    && sym.data.tp.has_checked()
201                {
202                    sym.data
203                        .tp
204                        .with_checked(|t| {
205                            let (_, vars) = t.get_bound_implicits()?;
206                            Some(
207                                Term::Symbol {
208                                    uri: uri.clone(),
209                                    presentation: presentation.clone(),
210                                }
211                                .apply_implicits(vars.len(), |_| self.new_solvable()),
212                            )
213                        })
214                        .flatten()
215                        .unwrap_or(t)
216                } else {
217                    t
218                };
219            }
220            Term::Var { .. } => return t,
221            _ => (),
222        }
223
224        for rl in self.top.rules.preparation() {
225            if !rl.applicable(self, &t) {
226                continue;
227            }
228            let path = match &mut path {
229                Some((p, t)) => Some((&mut **p, *t)),
230                _ => None,
231            };
232            match rl.apply(self, t, path) {
233                std::ops::ControlFlow::Break(t) => return t,
234                std::ops::ControlFlow::Continue(tm) => {
235                    t = tm;
236                }
237            }
238            tracing::trace!("Rule {rl:?} applied; result: {:?}", t.debug_short());
239        }
240        self.prepare_recurse(t, |s, t, p| s.prepare_i(t, p), path)
241    }
242
243    fn revert_i(&mut self, t: Term) -> Term {
244        match &t {
245            Term::Application(b) if b.head.unapply_implicits(true).is_some() => {
246                // SAFETY: pattern match
247                let (t, args) = unsafe { b.head.unapply_implicits(true).unwrap_unchecked() };
248                {
249                    return self.revert_i(
250                        Term::Application(ApplicationTerm::new(
251                            t.clone(),
252                            b.arguments.clone(),
253                            b.presentation.clone(),
254                        ))
255                        .apply_implicits(args.len(), |i| args[i].clone()),
256                    );
257                }
258            }
259            Term::Bound(b) if b.head.unapply_implicits(true).is_some() => {
260                // SAFETY: pattern match
261                let (t, args) = unsafe { b.head.unapply_implicits(true).unwrap_unchecked() };
262                {
263                    return self.revert_i(
264                        Term::Bound(BindingTerm::new(
265                            t.clone(),
266                            b.arguments.clone(),
267                            b.presentation.clone(),
268                        ))
269                        .apply_implicits(args.len(), |i| args[i].clone()),
270                    );
271                }
272            }
273
274            Term::Application(a) if a.unapply_implicits(true).is_some() => {
275                // SAFETY: pattern match
276                let (t, _) = unsafe { a.unapply_implicits(true).unwrap_unchecked() };
277                return t.clone();
278            }
279            Term::Symbol { .. } | Term::Var { .. } => return t,
280            _ => (),
281        }
282
283        let mut tm = t;
284
285        for rl in self.top.rules.preparation().iter().rev() {
286            // SAFETY: not yet replaced
287            if !rl.applicable_revert(self, &tm) {
288                continue;
289            }
290            tm = match rl.revert(self, tm) {
291                std::ops::ControlFlow::Break(t) => return t,
292                std::ops::ControlFlow::Continue(t) => t,
293            };
294            tracing::trace!("Rule {rl:?} applied; result: {:?}", tm.debug_short());
295        }
296        self.prepare_recurse(tm, |s, t, _| s.revert_i(t), None)
297    }
298
299    fn prepare_recurse(
300        &mut self,
301        term: Term,
302        then: fn(
303            &mut CheckRef<'_, '_, Split>,
304            Term,
305            Option<(&mut smallvec::SmallVec<u8, 16>, usize)>,
306        ) -> Term,
307        mut path: Option<(&mut smallvec::SmallVec<u8, 16>, usize)>,
308    ) -> Term {
309        tracing::trace!("Recursing {:?}", term.debug_short());
310        match term {
311            Term::Opaque(ot) => Term::Opaque(OpaqueTerm::new(
312                ot.node.clone(),
313                ot.terms
314                    .iter()
315                    .enumerate()
316                    .map(|(i, t)| then(self, t.clone(), get_path(&mut path, i)))
317                    .collect(),
318            )),
319            Term::Application(a) => Term::Application(ApplicationTerm::new(
320                then(self, a.head.clone(), get_path(&mut path, 0)),
321                {
322                    let mut idx = 0;
323                    a.arguments
324                        .iter()
325                        .map(|arg| match arg {
326                            Argument::Simple(t) => Argument::Simple(then(
327                                self,
328                                t.clone(),
329                                get_path(&mut path, {
330                                    idx += 1;
331                                    idx
332                                }),
333                            )),
334                            Argument::Sequence(MaybeSequence::One(t)) => {
335                                Argument::Sequence(MaybeSequence::One(then(
336                                    self,
337                                    t.clone(),
338                                    get_path(&mut path, {
339                                        idx += 1;
340                                        idx
341                                    }),
342                                )))
343                            }
344                            Argument::Sequence(MaybeSequence::Seq(ts)) => {
345                                idx += 1;
346                                let mut npath = get_path(&mut path, idx);
347                                Argument::Sequence(MaybeSequence::Seq(
348                                    ts.iter()
349                                        .cloned()
350                                        .enumerate()
351                                        .map(|(i, t)| then(self, t, get_path(&mut npath, i)))
352                                        .collect(),
353                                ))
354                            }
355                        })
356                        .collect()
357                },
358                a.presentation.clone(),
359            )),
360            Term::Bound(b) => Term::Bound(BindingTerm::new(
361                then(self, b.head.clone(), get_path(&mut path, 0)),
362                self.scoped(|slf| {
363                    let mut idx = 0;
364                    b.arguments
365                        .iter()
366                        .map(|arg| match arg {
367                            BoundArgument::Simple(t) => BoundArgument::Simple(then(
368                                slf,
369                                t.clone(),
370                                get_path(&mut path, {
371                                    idx += 1;
372                                    idx
373                                }),
374                            )),
375                            BoundArgument::Sequence(MaybeSequence::One(t)) => {
376                                BoundArgument::Sequence(MaybeSequence::One(then(
377                                    slf,
378                                    t.clone(),
379                                    get_path(&mut path, {
380                                        idx += 1;
381                                        idx
382                                    }),
383                                )))
384                            }
385                            BoundArgument::Sequence(MaybeSequence::Seq(ts)) => {
386                                idx += 1;
387                                let mut npath = get_path(&mut path, idx);
388                                BoundArgument::Sequence(MaybeSequence::Seq(
389                                    ts.iter()
390                                        .cloned()
391                                        .enumerate()
392                                        .map(|(i, t)| then(slf, t, get_path(&mut npath, i)))
393                                        .collect(),
394                                ))
395                            }
396                            BoundArgument::Bound(cv) => BoundArgument::Bound(slf.prepare_cv(
397                                cv,
398                                then,
399                                get_path(&mut path, {
400                                    idx += 1;
401                                    idx
402                                }),
403                            )),
404                            BoundArgument::BoundSeq(MaybeSequence::One(cv)) => {
405                                BoundArgument::BoundSeq(MaybeSequence::One(slf.prepare_cv(
406                                    cv,
407                                    then,
408                                    get_path(&mut path, {
409                                        idx += 1;
410                                        idx
411                                    }),
412                                )))
413                            }
414                            BoundArgument::BoundSeq(MaybeSequence::Seq(vars)) => {
415                                idx += 1;
416                                let mut npath = get_path(&mut path, idx);
417                                BoundArgument::BoundSeq(MaybeSequence::Seq(
418                                    vars.iter()
419                                        .enumerate()
420                                        .map(|(i, cv)| {
421                                            slf.prepare_cv(cv, then, get_path(&mut npath, i))
422                                        })
423                                        .collect(),
424                                ))
425                            }
426                        })
427                        .collect()
428                }),
429                b.presentation.clone(),
430            )),
431            t => t,
432        }
433    }
434
435    #[allow(clippy::single_match_else)]
436    fn prepare_cv(
437        &mut self,
438        cv: &ComponentVar,
439        then: fn(&mut Self, Term, Option<(&mut smallvec::SmallVec<u8, 16>, usize)>) -> Term,
440        mut path: Option<(&mut smallvec::SmallVec<u8, 16>, usize)>,
441    ) -> ComponentVar {
442        tracing::trace!("preparing bound variable {}", cv.var.name());
443        let mut next = 0;
444        let tp = match &cv.tp {
445            Some(t) => {
446                next += 1;
447                Some(then(self, t.clone(), get_path(&mut path, 0)))
448            }
449            None => {
450                let r = self.infer_var_type_i(&cv.var);
451                if r.is_some()
452                    && let Some((p, i)) = &mut path
453                    && let Some(i) = p.get_mut(*i)
454                {
455                    *i += 1;
456                    next += 1;
457                }
458                r
459            }
460        };
461        let df = match &cv.df {
462            Some(t) => Some(then(self, t.clone(), get_path(&mut path, next))),
463            None => {
464                let r = self.get_var_definiens(&cv.var);
465                if r.is_some()
466                    && let Some((p, i)) = &mut path
467                    && let Some(i) = p.get_mut(*i)
468                {
469                    *i += 1;
470                    next += 1;
471                }
472                r
473            }
474        };
475        let cv = ComponentVar {
476            var: cv.var.clone(),
477            tp,
478            df,
479        };
480        tracing::trace!("Extending context");
481        self.extend_context(cv.clone());
482        tracing::trace!("Done");
483        cv
484    }
485}
486
487fn get_path<'a, 'b>(
488    op: &'a mut Option<(&'b mut smallvec::SmallVec<u8, 16>, usize)>,
489    idx: usize,
490) -> Option<(&'a mut smallvec::SmallVec<u8, 16>, usize)> {
491    op.as_mut().and_then(|(s, i)| {
492        if s.get(*i).copied() == Some(idx as u8) {
493            Some((&mut **s, *i + 1))
494        } else {
495            None
496        }
497    })
498}