1#![allow(clippy::large_enum_variant)]
2
3pub mod checking;
4pub mod documents;
5pub mod notations;
6pub mod paragraphs;
7pub mod problems;
8pub mod sections;
9pub mod variables;
10
11use std::marker::PhantomData;
12
13use documents::Document;
14use flams_utils::prelude::InnerArc;
15use notations::Notation;
16use paragraphs::LogicalParagraph;
17use problems::{CognitiveDimension, Problem};
18use sections::{Section, SectionLevel};
19use variables::Variable;
20
21use crate::{
22 content::{
23 declarations::{
24 morphisms::Morphism,
25 structures::{Extension, MathStructure},
26 symbols::Symbol,
27 },
28 terms::Term,
29 },
30 uris::{DocumentElementURI, DocumentURI, Name, NameStep, SymbolURI},
31 Checked, CheckingState, DocumentRange, Unchecked,
32};
33
34#[derive(Debug, Copy, Clone)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
37#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
38#[cfg_attr(feature = "serde", serde(tag = "type"))]
39pub enum LOKind {
40 Definition,
41 Example,
42 Problem(CognitiveDimension),
43 SubProblem(CognitiveDimension),
44}
45
46#[derive(Debug, Clone)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48pub struct LazyDocRef<T> {
49 pub start: usize,
50 pub end: usize,
51 pub in_doc: DocumentURI,
52 phantom_data: PhantomData<T>,
53}
54impl<T> LazyDocRef<T> {
55 #[inline]
56 #[must_use]
57 pub const fn new(start: usize, end: usize, in_doc: DocumentURI) -> Self {
58 Self {
59 start,
60 end,
61 in_doc,
62 phantom_data: PhantomData,
63 }
64 }
65}
66
67pub trait NarrationTrait {
68 fn from_element(e: &DocumentElement<Checked>) -> Option<&Self>
69 where
70 Self: Sized;
71 fn children(&self) -> &[DocumentElement<Checked>];
72
73 fn find<T: NarrationTrait>(&self, steps: &[NameStep]) -> Option<&T> {
74 enum I<'a> {
75 One(std::slice::Iter<'a, DocumentElement<Checked>>),
76 Mul(
77 std::slice::Iter<'a, DocumentElement<Checked>>,
78 Vec<std::slice::Iter<'a, DocumentElement<Checked>>>,
79 ),
80 }
81 impl<'a> I<'a> {
82 fn push(&mut self, es: &'a [DocumentElement<Checked>]) {
83 match self {
84 Self::One(_) => {
85 let new = Self::Mul(es.iter(), Vec::with_capacity(1));
86 let Self::One(s) = std::mem::replace(self, new) else {
87 unreachable!()
88 };
89 let Self::Mul(_, v) = self else {
90 unreachable!()
91 };
92 v.push(s);
93 }
94 Self::Mul(f, r) => {
95 let of = std::mem::replace(f, es.iter());
96 r.push(of);
97 }
98 }
99 }
100 }
101 impl<'a> Iterator for I<'a> {
102 type Item = &'a DocumentElement<Checked>;
103 #[allow(clippy::option_if_let_else)]
104 fn next(&mut self) -> Option<Self::Item> {
105 match self {
106 Self::One(s) => s.next(),
107 Self::Mul(f, r) => loop {
108 if let Some(n) = f.next() {
109 return Some(n);
110 }
111 let Some(mut n) = r.pop() else { unreachable!() };
112 if r.is_empty() {
113 let r = n.next();
114 *self = Self::One(n);
115 return r;
116 }
117 *f = n;
118 },
119 }
120 }
121 }
122 let mut steps = steps;
123 let mut curr = I::One(self.children().iter());
124 'outer: while !steps.is_empty() {
125 let step = &steps[0];
126 steps = &steps[1..];
127 while let Some(c) = curr.next() {
128 match c {
129 DocumentElement::Section(Section { uri, children, .. })
130 | DocumentElement::Paragraph(LogicalParagraph { uri, children, .. })
131 | DocumentElement::Problem(Problem { uri, children, .. })
132 if uri.name().last_name() == step =>
133 {
134 if steps.is_empty() {
135 return T::from_element(c);
136 }
137 curr = I::One(children.iter());
138 continue 'outer;
139 }
140 DocumentElement::Slide { uri, .. }
141 if uri.name().last_name() == step && steps.is_empty() =>
142 {
143 return T::from_element(c);
144 }
145 DocumentElement::Module { children, .. }
146 | DocumentElement::Morphism { children, .. }
147 | DocumentElement::MathStructure { children, .. }
148 | DocumentElement::Slide { children, .. }
149 | DocumentElement::Extension { children, .. } => curr.push(children),
150 DocumentElement::Notation { id: uri, .. }
151 | DocumentElement::VariableNotation { id: uri, .. }
152 | DocumentElement::Variable(Variable { uri, .. })
153 | DocumentElement::TopTerm { uri, .. }
154 if uri.name().last_name() == step =>
155 {
156 if steps.is_empty() {
157 return T::from_element(c);
158 }
159 return None;
160 }
161 DocumentElement::Section(_)
162 | DocumentElement::Paragraph(_)
163 | DocumentElement::Problem(_)
164 | DocumentElement::SetSectionLevel(_)
165 | DocumentElement::SymbolDeclaration(_)
166 | DocumentElement::UseModule(_)
167 | DocumentElement::ImportModule(_)
168 | DocumentElement::SkipSection(_)
169 | DocumentElement::Variable(_)
170 | DocumentElement::Definiendum { .. }
171 | DocumentElement::SymbolReference { .. }
172 | DocumentElement::VariableReference { .. }
173 | DocumentElement::DocumentReference { .. }
174 | DocumentElement::Notation { .. }
175 | DocumentElement::VariableNotation { .. }
176 | DocumentElement::TopTerm { .. } => (),
177 }
178 }
179 }
180 None
181 }
182}
183
184pub struct NarrativeReference<T: NarrationTrait>(InnerArc<Document, T>);
185
186impl<T: NarrationTrait> NarrativeReference<T> {
187 #[must_use]
188 pub fn new(d: &Document, name: &Name) -> Option<Self> {
189 unsafe {
190 InnerArc::new(d, |d| &d.0, |d| d.find(name.steps()).ok_or(()))
191 .ok()
192 .map(Self)
193 }
194 }
195 #[must_use]
196 #[inline]
197 pub const fn top(&self) -> &Document {
198 self.0.outer()
199 }
200}
201
202impl<T: NarrationTrait> AsRef<T> for NarrativeReference<T> {
203 #[inline]
204 fn as_ref(&self) -> &T {
205 self.0.as_ref()
206 }
207}
208
209impl<T: NarrationTrait + std::fmt::Debug> std::fmt::Debug for NarrativeReference<T> {
210 #[inline]
211 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212 std::fmt::Debug::fmt(self.as_ref(), f)
213 }
214}
215
216pub enum DocumentElement<State: CheckingState> {
218 SetSectionLevel(SectionLevel),
219 Section(Section<State>),
220 Slide {
221 range: DocumentRange,
222 uri: DocumentElementURI,
223 children: State::Seq<DocumentElement<State>>,
224 },
225 Module {
226 range: DocumentRange,
227 module: State::ModuleLike,
228 children: State::Seq<DocumentElement<State>>,
229 },
230 Morphism {
231 range: DocumentRange,
232 morphism: State::Decl<Morphism<Checked>>,
233 children: State::Seq<DocumentElement<State>>,
234 },
235 MathStructure {
236 range: DocumentRange,
237 structure: State::Decl<MathStructure<Checked>>,
238 children: State::Seq<DocumentElement<State>>,
239 },
240 Extension {
241 range: DocumentRange,
242 extension: State::Decl<Extension<Checked>>,
243 target: State::Decl<MathStructure<Checked>>,
244 children: State::Seq<DocumentElement<State>>,
245 },
246 DocumentReference {
247 id: DocumentElementURI,
248 range: DocumentRange,
249 target: State::Doc,
250 },
251 SymbolDeclaration(State::Decl<Symbol>),
252 Notation {
253 symbol: SymbolURI,
254 id: DocumentElementURI,
255 notation: LazyDocRef<Notation>,
256 },
257 VariableNotation {
258 variable: DocumentElementURI,
259 id: DocumentElementURI,
260 notation: LazyDocRef<Notation>,
261 },
262 Variable(Variable),
263 Definiendum {
264 range: DocumentRange,
265 uri: SymbolURI,
266 },
267 SymbolReference {
268 range: DocumentRange,
269 uri: SymbolURI,
270 notation: Option<NameStep>,
271 },
272 VariableReference {
273 range: DocumentRange,
274 uri: DocumentElementURI,
275 notation: Option<NameStep>,
276 },
277 TopTerm {
278 uri: DocumentElementURI,
279 term: Term,
280 },
281 UseModule(State::ModuleLike),
282 ImportModule(State::ModuleLike),
283 Paragraph(LogicalParagraph<State>),
284 Problem(Problem<State>),
285 SkipSection(State::Seq<DocumentElement<State>>),
286}
287
288crate::serde_impl! {
289 enum DocumentElement {
290 {0 = SetSectionLevel(l)}
291 {1 = Section(s)}
292 {2 = Module{range,module,children}}
293 {3 = Morphism{range,morphism,children}}
294 {4 = MathStructure{range,structure,children}}
295 {5 = Extension{range,extension,target,children}}
296 {6 = DocumentReference { id, range, target }}
297 {7 = SymbolDeclaration(s)}
298 {8 = Notation{symbol,id,notation}}
299 {9 = VariableNotation { variable, id, notation }}
300 {10 = Variable(v)}
301 {11 = Definiendum { range, uri }}
302 {12 = SymbolReference { range, uri, notation }}
303 {13 = VariableReference { range, uri, notation }}
304 {14 = TopTerm { uri, term }}
305 {15 = UseModule(m)}
306 {16 = ImportModule(m)}
307 {17 = Paragraph(p)}
308 {18 = Problem(e)}
309 {19 = SkipSection(children)}
310 {20 = Slide{ uri, range, children}}
311 }
312}
313
314impl NarrationTrait for DocumentElement<Checked> {
315 #[inline]
316 fn from_element(e: &DocumentElement<Checked>) -> Option<&Self>
317 where
318 Self: Sized,
319 {
320 Some(e)
321 }
322 fn children(&self) -> &[DocumentElement<Checked>] {
323 match self {
324 Self::Section(s) => s.children(),
325 Self::Paragraph(p) => p.children(),
326 Self::Problem(e) => e.children(),
327 Self::Module { children, .. }
328 | Self::Morphism { children, .. }
329 | Self::MathStructure { children, .. }
330 | Self::Extension { children, .. }
331 | Self::SkipSection(children)
332 | Self::Slide { children, .. } => children,
333 _ => &[],
334 }
335 }
336}
337
338impl<State: CheckingState> std::fmt::Debug for DocumentElement<State> {
339 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
340 match self {
341 Self::SetSectionLevel(level) => f.debug_tuple("SetSectionLevel").field(level).finish(),
342 Self::Section(section) => f.debug_tuple("Section").field(section).finish(),
343 Self::Module {
344 range,
345 module,
346 children,
347 } => f
348 .debug_struct("Module")
349 .field("range", range)
350 .field("module", module)
351 .field("children", children)
352 .finish(),
353 Self::Morphism {
354 range,
355 morphism,
356 children,
357 } => f
358 .debug_struct("Morphism")
359 .field("range", range)
360 .field("morphism", morphism)
361 .field("children", children)
362 .finish(),
363 Self::MathStructure {
364 range,
365 structure,
366 children,
367 } => f
368 .debug_struct("MathStructure")
369 .field("range", range)
370 .field("structure", structure)
371 .field("children", children)
372 .finish(),
373 Self::Extension {
374 range,
375 extension,
376 target,
377 children,
378 } => f
379 .debug_struct("Extension")
380 .field("range", range)
381 .field("extension", extension)
382 .field("target", target)
383 .field("children", children)
384 .finish(),
385 Self::DocumentReference { id, range, target } => f
386 .debug_struct("DocumentReference")
387 .field("id", id)
388 .field("range", range)
389 .field("target", target)
390 .finish(),
391 Self::SymbolDeclaration(symbol) => {
392 f.debug_tuple("SymbolDeclaration").field(symbol).finish()
393 }
394 Self::Notation {
395 symbol,
396 id,
397 notation,
398 } => f
399 .debug_struct("Notation")
400 .field("symbol", symbol)
401 .field("id", id)
402 .field("notation", notation)
403 .finish(),
404 Self::VariableNotation {
405 variable,
406 id,
407 notation,
408 } => f
409 .debug_struct("VariableNotation")
410 .field("variable", variable)
411 .field("id", id)
412 .field("notation", notation)
413 .finish(),
414 Self::Variable(variable) => f.debug_tuple("Variable").field(variable).finish(),
415 Self::Definiendum { range, uri } => f
416 .debug_struct("Definiendum")
417 .field("range", range)
418 .field("uri", uri)
419 .finish(),
420 Self::SymbolReference {
421 range,
422 uri,
423 notation,
424 } => f
425 .debug_struct("SymbolReference")
426 .field("range", range)
427 .field("uri", uri)
428 .field("notation", notation)
429 .finish(),
430 Self::VariableReference {
431 range,
432 uri,
433 notation,
434 } => f
435 .debug_struct("VariableReference")
436 .field("range", range)
437 .field("uri", uri)
438 .field("notation", notation)
439 .finish(),
440 Self::TopTerm { uri, term } => f
441 .debug_struct("TopTerm")
442 .field("uri", uri)
443 .field("term", term)
444 .finish(),
445 Self::UseModule(module) => f.debug_tuple("UseModule").field(module).finish(),
446 Self::ImportModule(module) => f.debug_tuple("ImportModule").field(module).finish(),
447 Self::Paragraph(paragraph) => f.debug_tuple("Paragraph").field(paragraph).finish(),
448 Self::Problem(problem) => f.debug_tuple("Problem").field(problem).finish(),
449 Self::SkipSection(children) => f.debug_tuple("SkipSection").field(children).finish(),
450 Self::Slide {
451 uri,
452 range,
453 children,
454 } => f
455 .debug_struct("Slide")
456 .field("uri", uri)
457 .field("range", range)
458 .field("children", children)
459 .finish(),
460 }
461 }
462}
463
464impl DocumentElement<Unchecked> {
465 #[allow(clippy::missing_errors_doc)]
466 pub fn set_children(&mut self, new_children: Vec<Self>) -> Result<(), ElementHasNoChildren> {
467 match self {
468 Self::Section(s) => s.children = new_children,
469 Self::Paragraph(p) => p.children = new_children,
470 Self::Problem(e) => e.children = new_children,
471 Self::Module { children, .. }
472 | Self::Morphism { children, .. }
473 | Self::MathStructure { children, .. }
474 | Self::SkipSection(children)
475 | Self::Slide { children, .. } => *children = new_children,
476 _ => return Err(ElementHasNoChildren),
477 }
478 Ok(())
479 }
480}
481
482pub struct ElementHasNoChildren;