1use std::collections::HashMap;
4use std::rc::Rc;
5
6use all_the_same::all_the_same;
7use derive_more::{From, TryInto};
8use ustr::Ustr;
9
10use wasm_bindgen::prelude::*;
11
12use catlog::dbl::theory::{
13 self, DblTheory as _, ModalMorType, ModalObOp, ModalObType, ModalOp, ModeApp, TabMorType,
14 TabObOp, TabObType,
15};
16use catlog::one::{Path, QualifiedPath, ShortPath};
17use catlog::zero::{NameSegment, QualifiedName};
18use notebook_types::current::theory::*;
19
20use super::notation::*;
21
22impl CanElaborate<ObType, QualifiedName> for Elaborator {
24 fn elab(&self, ob_type: &ObType) -> Result<QualifiedName, String> {
25 match ob_type {
26 ObType::Basic(id) => Ok((*id).into()),
27 _ => Err(format!("Cannot use object type in discrete double theory: {ob_type:#?}")),
28 }
29 }
30}
31
32impl CanElaborate<MorType, QualifiedPath> for Elaborator {
34 fn elab(&self, mor_type: &MorType) -> Result<QualifiedPath, String> {
35 match mor_type {
36 MorType::Basic(id) => Ok(Path::single((*id).into())),
37 MorType::Composite(fs) => {
38 let fs: Result<Vec<_>, _> = fs.iter().map(|f| self.elab(f)).collect();
39 let path = Path::from_vec(fs?).ok_or("Composite should not be empty")?;
40 Ok(path.flatten())
41 }
42 MorType::Hom(ob_type) => Ok(Path::Id(self.elab(ob_type.as_ref())?)),
43 _ => Err(format!("Cannot use morphsim type in discrete double theory: {mor_type:#?}")),
44 }
45 }
46}
47
48impl CanElaborate<ObOp, QualifiedName> for Elaborator {
50 fn elab(&self, op: &ObOp) -> Result<QualifiedName, String> {
51 match op {
52 ObOp::Id(ObType::Basic(id)) => Ok((*id).into()),
53 _ => Err(format!("Cannot use operation in discrete double theory: {op:#?}")),
54 }
55 }
56}
57
58impl CanElaborate<ObType, TabObType> for Elaborator {
60 fn elab(&self, ob_type: &ObType) -> Result<TabObType, String> {
61 match ob_type {
62 ObType::Basic(id) => Ok(TabObType::Basic((*id).into())),
63 ObType::Tabulator(mor_type) => {
64 Ok(TabObType::Tabulator(Box::new(self.elab(mor_type.as_ref())?)))
65 }
66 _ => Err(format!("Cannot use object type in discrete tabulator theory: {ob_type:#?}")),
67 }
68 }
69}
70
71impl CanElaborate<MorType, TabMorType> for Elaborator {
73 fn elab(&self, mor_type: &MorType) -> Result<TabMorType, String> {
74 match mor_type {
75 MorType::Basic(id) => Ok(TabMorType::Basic((*id).into())),
76 MorType::Composite(_) => {
77 Err("Composites not yet implemented for tabulator theories".into())
78 }
79 MorType::Hom(ob_type) => Ok(TabMorType::Hom(Box::new(self.elab(ob_type.as_ref())?))),
80 _ => {
81 Err(format!("Cannot use morphism type in discrete tabulator theory: {mor_type:#?}"))
82 }
83 }
84 }
85}
86
87impl CanElaborate<ObOp, TabObOp> for Elaborator {
89 fn elab(&self, op: &ObOp) -> Result<TabObOp, String> {
90 match op {
91 ObOp::Id(ob_type) => Ok(Path::empty(self.elab(ob_type)?)),
92 _ => Err(format!("Cannot use operation in discrete tabulator theory: {op:#?}")),
93 }
94 }
95}
96
97impl CanElaborate<ObType, ModalObType> for Elaborator {
99 fn elab(&self, ob_type: &ObType) -> Result<ModalObType, String> {
100 match ob_type {
101 ObType::Basic(id) => Ok(ModeApp::new((*id).into())),
102 ObType::ModeApp { modality, ob_type } => Ok({
103 let ob_type: ModalObType = self.elab(ob_type.as_ref())?;
104 ob_type.apply(promote_modality(*modality))
105 }),
106 _ => Err(format!("Cannot use object type in modal theory: {ob_type:#?}")),
107 }
108 }
109}
110
111impl CanElaborate<MorType, ModalMorType> for Elaborator {
113 fn elab(&self, mor_type: &MorType) -> Result<ModalMorType, String> {
114 match mor_type {
115 MorType::Basic(id) => Ok(ModeApp::new((*id).into()).into()),
116 MorType::Hom(ob_type) => Ok(ShortPath::Zero(self.elab(ob_type.as_ref())?)),
117 MorType::ModeApp { modality, mor_type } => Ok({
118 let mor_type: ModalMorType = self.elab(mor_type.as_ref())?;
119 mor_type.apply(promote_modality(*modality))
120 }),
121 _ => Err(format!("Cannot use morphism type in modal theory: {mor_type:#?}")),
122 }
123 }
124}
125
126impl CanElaborate<ObOp, ModalObOp> for Elaborator {
128 fn elab(&self, op: &ObOp) -> Result<ModalObOp, String> {
129 match op {
130 ObOp::Basic(id) => Ok(ModeApp::new(ModalOp::Generator((*id).into())).into()),
131 ObOp::Id(ob_type) => Ok(Path::empty(self.elab(ob_type)?)),
132 ObOp::Composite(ops) => {
133 let ops: Result<Vec<_>, _> = ops.iter().map(|op| self.elab(op)).collect();
134 Ok(Path::from_vec(ops?).ok_or("Composite should be non-empty")?.flatten())
135 }
136 ObOp::ModeApp { modality, op } => Ok({
137 let op: ModalObOp = self.elab(op.as_ref())?;
138 op.apply(promote_modality(*modality))
139 }),
140 }
141 }
142}
143
144pub(crate) fn promote_modality(modality: Modality) -> theory::Modality {
145 match modality {
146 Modality::Discrete => theory::Modality::Discrete(),
147 Modality::Codiscrete => theory::Modality::Codiscrete(),
148 Modality::List => theory::Modality::List(theory::List::Plain),
149 Modality::SymmetricList => theory::Modality::List(theory::List::Symmetric),
150 Modality::ProductList => theory::Modality::List(theory::List::Product),
151 Modality::CoproductList => theory::Modality::List(theory::List::Coproduct),
152 Modality::BiproductList => theory::Modality::List(theory::List::Biproduct),
153 }
154}
155
156pub(crate) fn expect_single_name(name: &QualifiedName) -> Ustr {
157 match name.only() {
158 Some(NameSegment::Text(text)) => text,
159 _ => panic!("Only singleton names are currently supported in notebook types"),
160 }
161}
162
163impl CanQuote<QualifiedName, ObType> for Quoter {
165 fn quote(&self, name: &QualifiedName) -> ObType {
166 ObType::Basic(expect_single_name(name))
167 }
168}
169
170impl CanQuote<QualifiedPath, MorType> for Quoter {
172 fn quote(&self, path: &QualifiedPath) -> MorType {
173 match path {
174 Path::Id(v) => MorType::Hom(Box::new(ObType::Basic(expect_single_name(v)))),
175 Path::Seq(edges) => {
176 if edges.len() == 1 {
177 MorType::Basic(expect_single_name(&edges.head))
178 } else {
179 MorType::Composite(
180 edges.iter().map(|e| MorType::Basic(expect_single_name(e))).collect(),
181 )
182 }
183 }
184 }
185 }
186}
187
188impl CanQuote<QualifiedName, ObOp> for Quoter {
190 fn quote(&self, name: &QualifiedName) -> ObOp {
191 ObOp::Id(ObType::Basic(expect_single_name(name)))
192 }
193}
194
195impl CanQuote<TabObType, ObType> for Quoter {
197 fn quote(&self, ob_type: &TabObType) -> ObType {
198 match ob_type {
199 TabObType::Basic(name) => ObType::Basic(expect_single_name(name)),
200 TabObType::Tabulator(mor_type) => {
201 ObType::Tabulator(Box::new(self.quote(mor_type.as_ref())))
202 }
203 }
204 }
205}
206
207impl CanQuote<TabMorType, MorType> for Quoter {
209 fn quote(&self, mor_type: &TabMorType) -> MorType {
210 match mor_type {
211 TabMorType::Basic(name) => MorType::Basic(expect_single_name(name)),
212 TabMorType::Hom(ob_type) => MorType::Hom(Box::new(self.quote(ob_type.as_ref()))),
213 }
214 }
215}
216
217impl CanQuote<ModalObType, ObType> for Quoter {
219 fn quote(&self, app: &ModalObType) -> ObType {
220 let mut quoted = ObType::Basic(expect_single_name(&app.arg));
221 for modality in &app.modalities {
222 quoted = ObType::ModeApp {
223 modality: demote_modality(*modality),
224 ob_type: quoted.into(),
225 }
226 }
227 quoted
228 }
229}
230
231impl CanQuote<ModalMorType, MorType> for Quoter {
233 fn quote(&self, mor_type: &ModalMorType) -> MorType {
234 match mor_type {
235 ShortPath::Zero(ob_type) => MorType::Hom(Box::new(self.quote(ob_type))),
236 ShortPath::One(app) => {
237 let mut quoted = MorType::Basic(expect_single_name(&app.arg));
238 for modality in &app.modalities {
239 quoted = MorType::ModeApp {
240 modality: demote_modality(*modality),
241 mor_type: quoted.into(),
242 }
243 }
244 quoted
245 }
246 }
247 }
248}
249
250pub(crate) fn demote_modality(modality: theory::Modality) -> Modality {
251 match modality {
252 theory::Modality::Discrete() => Modality::Discrete,
253 theory::Modality::Codiscrete() => Modality::Codiscrete,
254 theory::Modality::List(list_type) => match list_type {
255 theory::List::Plain => Modality::List,
256 theory::List::Symmetric => Modality::SymmetricList,
257 theory::List::Product => Modality::ProductList,
258 theory::List::Coproduct => Modality::CoproductList,
259 theory::List::Biproduct => Modality::BiproductList,
260 },
261 }
262}
263
264#[derive(From, TryInto)]
272#[try_into(ref)]
273pub enum DblTheoryBox {
274 Discrete(Rc<theory::DiscreteDblTheory>),
276 DiscreteTab(Rc<theory::DiscreteTabTheory>),
278 Modal(Rc<theory::ModalDblTheory>),
280}
281
282#[wasm_bindgen]
284pub struct DblTheory(#[wasm_bindgen(skip)] pub DblTheoryBox);
285
286impl DblTheory {
287 pub fn discrete(&self) -> Result<&Rc<theory::DiscreteDblTheory>, String> {
289 (&self.0).try_into().map_err(|_| "Theory should be discrete".into())
290 }
291}
292
293#[wasm_bindgen]
294impl DblTheory {
295 #[wasm_bindgen]
297 pub fn src(&self, mor_type: MorType) -> Result<ObType, String> {
298 all_the_same!(match &self.0 {
299 DblTheoryBox::[Discrete, DiscreteTab, Modal](th) => {
300 let mor_type = Elaborator.elab(&mor_type)?;
301 Ok(Quoter.quote(&th.src_type(&mor_type)))
302 }
303 })
304 }
305
306 #[wasm_bindgen]
308 pub fn tgt(&self, mor_type: MorType) -> Result<ObType, String> {
309 all_the_same!(match &self.0 {
310 DblTheoryBox::[Discrete, DiscreteTab, Modal](th) => {
311 let mor_type = Elaborator.elab(&mor_type)?;
312 Ok(Quoter.quote(&th.tgt_type(&mor_type)))
313 }
314 })
315 }
316
317 #[wasm_bindgen]
319 pub fn dom(&self, op: ObOp) -> Result<ObType, String> {
320 all_the_same!(match &self.0 {
321 DblTheoryBox::[Discrete, DiscreteTab, Modal](th) => {
322 let op = Elaborator.elab(&op)?;
323 Ok(Quoter.quote(&th.ob_op_dom(&op)))
324 }
325 })
326 }
327
328 #[wasm_bindgen]
330 pub fn cod(&self, op: ObOp) -> Result<ObType, String> {
331 all_the_same!(match &self.0 {
332 DblTheoryBox::[Discrete, DiscreteTab, Modal](th) => {
333 let op = Elaborator.elab(&op)?;
334 Ok(Quoter.quote(&th.ob_op_cod(&op)))
335 }
336 })
337 }
338}
339
340#[wasm_bindgen]
346#[derive(Clone, Default)]
347pub struct ObTypeIndex(HashMap<ObType, usize>);
348
349#[wasm_bindgen]
350impl ObTypeIndex {
351 #[wasm_bindgen(constructor)]
353 pub fn new() -> Self {
354 Default::default()
355 }
356
357 #[wasm_bindgen]
359 pub fn get(&self, x: &ObType) -> Option<usize> {
360 self.0.get(x).copied()
361 }
362
363 #[wasm_bindgen]
365 pub fn set(&mut self, x: ObType, i: usize) {
366 self.0.insert(x, i);
367 }
368}
369
370#[wasm_bindgen]
376#[derive(Clone, Default)]
377pub struct MorTypeIndex(HashMap<MorType, usize>);
378
379#[wasm_bindgen]
380impl MorTypeIndex {
381 #[wasm_bindgen(constructor)]
383 pub fn new() -> Self {
384 Default::default()
385 }
386
387 #[wasm_bindgen]
389 pub fn get(&self, m: &MorType) -> Option<usize> {
390 self.0.get(m).copied()
391 }
392
393 #[wasm_bindgen]
395 pub fn set(&mut self, m: MorType, i: usize) {
396 self.0.insert(m, i);
397 }
398}