1use std::borrow::Cow;
2
3use ftml_ontology::terms::{ApplicationTerm, Argument, ComponentVar, Term, helpers::IntoTerm};
4use ftml_uris::SymbolUri;
5
6use crate::{
7 Checker,
8 impls::solving::{Solutions, Solvable},
9 split::SplitStrategy,
10};
11
12#[derive(Debug, Clone)]
13pub struct HOASSymbols {
14 pub judgment: Option<SymbolUri>,
15 pub lambda: SymbolUri,
16 pub pi: SymbolUri,
17 pub any: SymbolUri,
18 pub apply: Option<SymbolUri>,
19 }
21impl HOASSymbols {
22 pub fn apply<'t, Split: SplitStrategy>(
23 &self,
24 checker: &Checker<Split>,
25 head: &'t Term,
26 arguments: impl Iterator<Item = Option<Term>>,
27 ) -> (Cow<'t, Term>, Solutions) {
28 let mut ret = Solutions::default();
29 if let Some(app) = self.apply.as_ref() {
30 (
31 arguments.fold(Cow::Borrowed(head), |h, a| {
32 Cow::Owned(app.clone().apply_tms([
33 h.into_owned(),
34 a.unwrap_or_else(|| {
35 let name = checker.new_solvable();
36 ret.0
37 .insert(Solvable::new(name.clone(), std::iter::empty()));
38 name.into()
39 }),
40 ]))
41 }),
42 ret,
43 )
44 } else {
45 let args = arguments
46 .map(|t| {
47 Argument::Simple(t.unwrap_or_else(|| {
48 let name = checker.new_solvable();
49 ret.0
50 .insert(Solvable::new(name.clone(), std::iter::empty()));
51 name.into()
52 }))
53 })
54 .collect::<Box<[_]>>();
55 (
56 if args.is_empty() {
57 Cow::Borrowed(head)
58 } else {
59 Cow::Owned(Term::Application(ApplicationTerm::new(
60 head.clone(),
61 args,
62 None,
63 )))
64 },
65 ret,
66 )
67 }
68 }
69
70 pub fn get<Split: SplitStrategy>(checker: &Checker<Split>) -> Option<Self> {
71 let judgment = checker.rules.marker().iter().rev().find_map(|rl| {
72 rl.as_any()
73 .downcast_ref::<super::rules::IsJudgmentRule>()
74 .map(|rl| rl.0.clone())
75 });
76 let any = checker.rules.marker().iter().rev().find_map(|rl| {
77 rl.as_any()
78 .downcast_ref::<super::rules::operators::universe::AnyRule>()
79 .map(|rl| rl.0.clone())
80 })?;
81 let (lambda, pi, apply) = checker.rules.marker().iter().rev().find_map(|rl| {
82 rl.as_any()
83 .downcast_ref::<super::rules::HOASRule>()
84 .map(|rl| (rl.lambda.clone(), rl.pi.clone(), rl.apply.clone()))
85 })?;
86 Some(Self {
87 judgment,
88 lambda,
89 pi,
90 any,
91 apply, })
93 }
94
95 pub fn wrap_vars<'c>(
96 &self,
97 args: impl DoubleEndedIterator<Item = ComponentVar>,
98 ret: &'c Term,
99 ) -> Cow<'c, Term> {
100 args.rev().fold(Cow::Borrowed(ret), |c, v| {
101 Cow::Owned(
103 self.pi
104 .clone()
105 .simple_bind(v.var, v.tp, v.df, c.into_owned()),
106 )
107 })
108 }
109
110 pub fn wrap_types<'c>(&self, args: &[Term], ret: &'c Term) -> Cow<'c, Term> {
111 let ret = self.wrap_judg(ret);
112 args.iter().rev().fold(ret, |c, p| {
113 let premise = self.wrap_judg(p).into_owned();
114 Cow::Owned(self.pi.clone().simple_bind(
115 crate::DUMMY.clone().into(),
116 Some(premise),
117 None,
118 c.into_owned(),
119 ))
120 })
121 }
122
123 #[inline]
124 pub fn let_in(var: ComponentVar, body: Term) -> Term {
125 ftml_uris::metatheory::LET_IN
126 .clone()
127 .simple_bind(var.var, var.tp, var.df, body)
128 }
129
130 #[inline]
131 pub fn lambda(&self, var: ComponentVar, body: Term) -> Term {
132 self.lambda
133 .clone()
134 .simple_bind(var.var, var.tp, var.df, body)
135 }
136
137 #[inline]
138 pub fn pi(&self, var: ComponentVar, body: Term) -> Term {
139 self.pi.clone().simple_bind(var.var, var.tp, var.df, body)
140 }
141
142 pub fn wrap_judg<'c>(&self, ret: &'c Term) -> Cow<'c, Term> {
143 self.judgment.as_ref().map_or_else(
144 || Cow::Borrowed(ret),
145 |j| {
146 Cow::Owned(self.apply.as_ref().map_or_else(
147 || j.clone().apply_tms([ret.clone()]),
148 |app| app.clone().apply_tms([j.clone().into(), ret.clone()]),
149 ))
150 },
151 )
152 }
153}