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)]
271#[try_into(ref)]
272pub enum DblTheoryBox {
273 Discrete(Rc<theory::DiscreteDblTheory>),
275 DiscreteTab(Rc<theory::DiscreteTabTheory>),
277 Modal(Rc<theory::ModalDblTheory>),
279}
280
281#[wasm_bindgen]
283pub struct DblTheory(#[wasm_bindgen(skip)] pub DblTheoryBox);
284
285impl DblTheory {
286 pub fn discrete(&self) -> Result<&Rc<theory::DiscreteDblTheory>, String> {
288 (&self.0).try_into().map_err(|_| "Theory should be discrete".into())
289 }
290}
291
292#[wasm_bindgen]
293impl DblTheory {
294 #[wasm_bindgen]
296 pub fn src(&self, mor_type: MorType) -> Result<ObType, String> {
297 all_the_same!(match &self.0 {
298 DblTheoryBox::[Discrete, DiscreteTab, Modal](th) => {
299 let mor_type = Elaborator.elab(&mor_type)?;
300 Ok(Quoter.quote(&th.src_type(&mor_type)))
301 }
302 })
303 }
304
305 #[wasm_bindgen]
307 pub fn tgt(&self, mor_type: MorType) -> Result<ObType, String> {
308 all_the_same!(match &self.0 {
309 DblTheoryBox::[Discrete, DiscreteTab, Modal](th) => {
310 let mor_type = Elaborator.elab(&mor_type)?;
311 Ok(Quoter.quote(&th.tgt_type(&mor_type)))
312 }
313 })
314 }
315
316 #[wasm_bindgen]
318 pub fn dom(&self, op: ObOp) -> Result<ObType, String> {
319 all_the_same!(match &self.0 {
320 DblTheoryBox::[Discrete, DiscreteTab, Modal](th) => {
321 let op = Elaborator.elab(&op)?;
322 Ok(Quoter.quote(&th.ob_op_dom(&op)))
323 }
324 })
325 }
326
327 #[wasm_bindgen]
329 pub fn cod(&self, op: ObOp) -> Result<ObType, String> {
330 all_the_same!(match &self.0 {
331 DblTheoryBox::[Discrete, DiscreteTab, Modal](th) => {
332 let op = Elaborator.elab(&op)?;
333 Ok(Quoter.quote(&th.ob_op_cod(&op)))
334 }
335 })
336 }
337}
338
339#[wasm_bindgen]
344#[derive(Clone, Default)]
345pub struct ObTypeIndex(HashMap<ObType, usize>);
346
347#[wasm_bindgen]
348impl ObTypeIndex {
349 #[wasm_bindgen(constructor)]
351 pub fn new() -> Self {
352 Default::default()
353 }
354
355 #[wasm_bindgen(js_name = "has")]
357 pub fn contains_key(&self, x: &ObType) -> bool {
358 self.0.contains_key(x)
359 }
360
361 #[wasm_bindgen]
363 pub fn get(&self, x: &ObType) -> Option<usize> {
364 self.0.get(x).copied()
365 }
366
367 #[wasm_bindgen(js_name = "set")]
369 pub fn insert(&mut self, x: ObType, i: usize) {
370 self.0.insert(x, i);
371 }
372}
373
374#[wasm_bindgen]
379#[derive(Clone, Default)]
380pub struct MorTypeIndex(HashMap<MorType, usize>);
381
382#[wasm_bindgen]
383impl MorTypeIndex {
384 #[wasm_bindgen(constructor)]
386 pub fn new() -> Self {
387 Default::default()
388 }
389
390 #[wasm_bindgen(js_name = "has")]
392 pub fn contains_key(&self, m: &MorType) -> bool {
393 self.0.contains_key(m)
394 }
395
396 #[wasm_bindgen]
398 pub fn get(&self, m: &MorType) -> Option<usize> {
399 self.0.get(m).copied()
400 }
401
402 #[wasm_bindgen(js_name = "set")]
404 pub fn insert(&mut self, m: MorType, i: usize) {
405 self.0.insert(m, i);
406 }
407}