1use all_the_same::all_the_same;
11use derivative::Derivative;
12use derive_more::{Constructor, From, TryInto};
13use std::{fmt, rc::Rc};
14
15use super::prelude::*;
16use crate::dbl::{discrete, modal, model::PrintableDblModel, theory::DblTheory};
17use crate::one::QualifiedPath;
18use crate::stdlib::theories;
19use crate::zero::{QualifiedName, name};
20
21#[derive(Constructor, Clone, Derivative)]
26#[derivative(PartialEq, Eq)]
27pub struct Theory {
28 pub name: QualifiedName,
30 #[derivative(PartialEq = "ignore")]
32 pub definition: TheoryDef,
33}
34
35impl fmt::Display for Theory {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 write!(f, "{}", self.name)
38 }
39}
40
41#[derive(Clone, From)]
43pub enum TheoryDef {
44 Discrete(Rc<discrete::DiscreteDblTheory>),
46 Modal(Rc<modal::ModalDblTheory>),
48}
49
50impl TheoryDef {
51 pub fn discrete(theory: discrete::DiscreteDblTheory) -> Self {
53 TheoryDef::Discrete(Rc::new(theory))
54 }
55
56 pub fn modal(theory: modal::ModalDblTheory) -> Self {
58 TheoryDef::Modal(Rc::new(theory))
59 }
60
61 pub fn basic_ob_type(&self, name: QualifiedName) -> Option<ObType> {
63 let ob_type = match self {
64 TheoryDef::Discrete(_) => ObType::Discrete(name),
65 TheoryDef::Modal(_) => ObType::Modal(modal::ModeApp::new(name)),
66 };
67 all_the_same!(match self {
68 TheoryDef::[Discrete, Modal](th) => {
69 if th.has_ob_type((&ob_type).try_into().unwrap()) {
70 Some(ob_type)
71 } else {
72 None
73 }
74 }
75 })
76 }
77
78 pub fn basic_mor_type(&self, name: QualifiedName) -> Option<MorType> {
80 let mor_type = match self {
81 TheoryDef::Discrete(_) => MorType::Discrete(name.into()),
82 TheoryDef::Modal(_) => MorType::Modal(modal::ModeApp::new(name).into()),
83 };
84 all_the_same!(match self {
85 TheoryDef::[Discrete, Modal](th) => {
86 if th.has_mor_type((&mor_type).try_into().unwrap()) {
87 Some(mor_type)
88 } else {
89 None
90 }
91 }
92 })
93 }
94
95 pub fn basic_ob_op(&self, name: QualifiedName) -> Option<ObOp> {
97 match self {
98 TheoryDef::Discrete(_) => None,
99 TheoryDef::Modal(th) => {
100 let op = modal::ModalObOp::generator(name);
101 if th.has_ob_op(&op) {
102 Some(ObOp::Modal(op))
103 } else {
104 None
105 }
106 }
107 }
108 }
109
110 pub fn src_type(&self, mor_type: &MorType) -> ObType {
112 all_the_same!(match self {
113 TheoryDef::[Discrete, Modal](th) => {
114 th.src_type(mor_type.try_into().unwrap()).into()
115 }
116 })
117 }
118
119 pub fn tgt_type(&self, mor_type: &MorType) -> ObType {
121 all_the_same!(match self {
122 TheoryDef::[Discrete, Modal](th) => {
123 th.tgt_type(mor_type.try_into().unwrap()).into()
124 }
125 })
126 }
127
128 pub fn hom_type(&self, ob_type: ObType) -> MorType {
130 all_the_same!(match self {
131 TheoryDef::[Discrete, Modal](th) => {
132 th.hom_type(ob_type.try_into().unwrap()).into()
133 }
134 })
135 }
136
137 pub fn compose_types2(&self, mt1: MorType, mt2: MorType) -> Option<MorType> {
139 all_the_same!(match self {
140 TheoryDef::[Discrete, Modal](th) => {
141 let path = Path::pair(mt1.try_into().unwrap(), mt2.try_into().unwrap());
142 th.compose_types(path).map(|mt| mt.into())
143 }
144 })
145 }
146
147 pub fn ob_op_dom(&self, ob_op: &ObOp) -> ObType {
149 all_the_same!(match self {
150 TheoryDef::[Discrete, Modal](th) => {
151 th.ob_op_dom(ob_op.try_into().unwrap()).into()
152 }
153 })
154 }
155
156 pub fn ob_op_cod(&self, ob_op: &ObOp) -> ObType {
158 all_the_same!(match self {
159 TheoryDef::[Discrete, Modal](th) => {
160 th.ob_op_cod(ob_op.try_into().unwrap()).into()
161 }
162 })
163 }
164}
165
166#[derive(Clone, Debug, From, TryInto, PartialEq, Eq)]
168#[try_into(owned, ref)]
169pub enum ObType {
170 Discrete(QualifiedName),
172 Modal(modal::ModalObType),
174}
175
176impl ObType {
177 pub fn mode_app(self) -> Option<(modal::Modality, ObType)> {
179 match self {
180 ObType::Discrete(_) => None,
181 ObType::Modal(ob_type) => {
182 let (maybe_modality, ob_type) = ob_type.pop_app();
183 maybe_modality.map(|modality| (modality, ob_type.into()))
184 }
185 }
186 }
187
188 pub fn list_arg(self) -> Option<ObType> {
190 self.mode_app().and_then(|(modality, ob_type)| match modality {
191 modal::Modality::List(_) => Some(ob_type),
192 _ => None,
193 })
194 }
195}
196
197impl ToDoc for ObType {
198 fn to_doc<'a>(&self) -> D<'a> {
199 match self {
200 ObType::Discrete(name) => discrete::DiscreteDblModel::ob_type_to_doc(name),
201 ObType::Modal(ob_type) => modal::ModalDblModel::ob_type_to_doc(ob_type),
202 }
203 }
204}
205
206impl fmt::Display for ObType {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 write!(f, "{}", self.to_doc().group().pretty())
209 }
210}
211
212#[derive(Clone, Debug, From, TryInto, PartialEq, Eq)]
214#[try_into(owned, ref)]
215pub enum MorType {
216 Discrete(QualifiedPath),
218 Modal(modal::ModalMorType),
220}
221
222impl ToDoc for MorType {
223 fn to_doc<'a>(&self) -> D<'a> {
224 match self {
225 MorType::Discrete(path) => discrete::DiscreteDblModel::mor_type_to_doc(path),
226 MorType::Modal(mor_type) => modal::ModalDblModel::mor_type_to_doc(mor_type),
227 }
228 }
229}
230
231impl fmt::Display for MorType {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 write!(f, "{}", self.to_doc().group().pretty())
234 }
235}
236
237#[derive(Clone, Debug, TryInto)]
239#[try_into(owned, ref)]
240pub enum ObOp {
241 Discrete(QualifiedName),
243 Modal(modal::ModalObOp),
245}
246
247pub fn std_theories() -> HashMap<QualifiedName, Theory> {
249 [
250 (name("ThSchema"), TheoryDef::discrete(theories::th_schema())),
251 (name("ThCategory"), TheoryDef::discrete(theories::th_category())),
252 (name("ThSignedCategory"), TheoryDef::discrete(theories::th_signed_category())),
253 (name("ThMulticategory"), TheoryDef::modal(theories::th_multicategory())),
254 (
255 name("ThSymMonoidalCategory"),
256 TheoryDef::modal(theories::th_sym_monoidal_category()),
257 ),
258 ]
259 .into_iter()
260 .map(|(name, def)| (name.clone(), Theory::new(name, def)))
261 .collect()
262}