flams_stex/quickparse/stex/
structs.rs

1use super::{
2    rules::{
3        MathStructureArg, NotationArg, ParagraphArg, ProblemArg, SModuleArg, SymdeclArg, SymdefArg,
4        TextSymdeclArg, VardefArg,
5    },
6    DiagnosticLevel, STeXParseData,
7};
8use crate::quickparse::{
9    latex::{
10        rules::{AnyEnv, AnyMacro, DynMacro},
11        Environment, FromLaTeXToken, Group, GroupState, Groups, LaTeXParser, Macro, ParserState,
12    },
13    stex::rules::{IncludeProblemArg, MHGraphicsArg},
14};
15use flams_math_archives::{
16    backend::{AnyBackend, LocalBackend},
17    MathArchive,
18};
19use flams_utils::{
20    id_counters::IdCounter,
21    impossible,
22    parsing::ParseStr,
23    prelude::HMap,
24    sourcerefs::{LSPLineCol, SourcePos, SourceRange},
25    vecmap::{VecMap, VecSet},
26};
27use ftml_ontology::narrative::elements::{paragraphs::ParagraphKind, problems::CognitiveDimension};
28use ftml_uris::{
29    ArchiveId, ArchiveUri, DocumentUri, DomainUri, IsDomainUri, Language, ModuleUri, PathUri,
30    SymbolUri, UriName, UriPath, UriWithArchive, UriWithPath,
31};
32use smallvec::SmallVec;
33use std::{
34    borrow::Cow,
35    collections::hash_map::Entry,
36    path::{Path, PathBuf},
37};
38
39#[allow(clippy::large_enum_variant)]
40#[derive(Debug, serde::Serialize)]
41pub enum STeXToken<Pos: SourcePos> {
42    ImportModule {
43        archive_range: Option<SourceRange<Pos>>,
44        path_range: SourceRange<Pos>,
45        module: ModuleReference,
46        full_range: SourceRange<Pos>,
47        token_range: SourceRange<Pos>,
48    },
49    UseModule {
50        archive_range: Option<SourceRange<Pos>>,
51        path_range: SourceRange<Pos>,
52        module: ModuleReference,
53        full_range: SourceRange<Pos>,
54        token_range: SourceRange<Pos>,
55    },
56    UseStructure {
57        structure: SymbolReference<Pos>,
58        structure_range: SourceRange<Pos>,
59        full_range: SourceRange<Pos>,
60        token_range: SourceRange<Pos>,
61    },
62    SetMetatheory {
63        archive_range: Option<SourceRange<Pos>>,
64        path_range: SourceRange<Pos>,
65        module: ModuleReference,
66        full_range: SourceRange<Pos>,
67        token_range: SourceRange<Pos>,
68    },
69    Inputref {
70        archive: Option<(ArchiveId, SourceRange<Pos>)>,
71        filepath: (std::sync::Arc<str>, SourceRange<Pos>),
72        full_range: SourceRange<Pos>,
73        token_range: SourceRange<Pos>,
74    },
75    IncludeProblem {
76        filepath: (std::sync::Arc<str>, SourceRange<Pos>),
77        archive: Option<(ArchiveId, SourceRange<Pos>)>,
78        full_range: SourceRange<Pos>,
79        token_range: SourceRange<Pos>,
80        args: Vec<IncludeProblemArg<Pos>>,
81    },
82    MHGraphics {
83        filepath: (std::sync::Arc<str>, SourceRange<Pos>),
84        archive: Option<(ArchiveId, SourceRange<Pos>)>,
85        full_range: SourceRange<Pos>,
86        token_range: SourceRange<Pos>,
87        args: Vec<MHGraphicsArg<Pos>>,
88    },
89    MHInput {
90        archive: Option<(ArchiveId, SourceRange<Pos>)>,
91        filepath: (std::sync::Arc<str>, SourceRange<Pos>),
92        full_range: SourceRange<Pos>,
93        token_range: SourceRange<Pos>,
94    },
95    Module {
96        uri: ModuleUri,
97        rules: ModuleRules<Pos>,
98        name_range: SourceRange<Pos>,
99        opts: Vec<SModuleArg<Pos, Self>>,
100        sig: Option<Language>,
101        meta_theory: Option<ModuleReference>,
102        full_range: SourceRange<Pos>,
103        children: Vec<STeXToken<Pos>>,
104        smodule_range: SourceRange<Pos>,
105    },
106    MathStructure {
107        uri: SymbolReference<Pos>,
108        extends: Vec<(SymbolReference<Pos>, SourceRange<Pos>)>,
109        name_range: SourceRange<Pos>,
110        opts: Vec<MathStructureArg<Pos, Self>>,
111        full_range: SourceRange<Pos>,
112        children: Vec<STeXToken<Pos>>,
113        mathstructure_range: SourceRange<Pos>,
114    },
115    ConservativeExt {
116        uri: SymbolReference<Pos>,
117        ext_range: SourceRange<Pos>,
118        full_range: SourceRange<Pos>,
119        children: Vec<STeXToken<Pos>>,
120        extstructure_range: SourceRange<Pos>,
121    },
122    MorphismEnv {
123        full_range: SourceRange<Pos>,
124        env_range: SourceRange<Pos>,
125        name_range: SourceRange<Pos>,
126        uri: SymbolUri,
127        star: bool,
128        domain: ModuleOrStruct<Pos>,
129        domain_range: SourceRange<Pos>,
130        kind: MorphismKind,
131        children: Vec<STeXToken<Pos>>,
132    },
133    InlineMorphism {
134        full_range: SourceRange<Pos>,
135        token_range: SourceRange<Pos>,
136        name_range: SourceRange<Pos>,
137        uri: SymbolUri,
138        star: bool,
139        domain: ModuleOrStruct<Pos>,
140        domain_range: SourceRange<Pos>,
141        kind: MorphismKind,
142        assignments: Vec<InlineMorphAssign<Pos, Self>>,
143    },
144    Paragraph {
145        kind: ParagraphKind,
146        full_range: SourceRange<Pos>,
147        name_range: SourceRange<Pos>,
148        symbol: Option<SymbolReference<Pos>>,
149        parsed_args: Vec<ParagraphArg<Pos, STeXToken<Pos>>>,
150        children: Vec<STeXToken<Pos>>,
151    },
152    Problem {
153        sub: bool,
154        full_range: SourceRange<Pos>,
155        name_range: SourceRange<Pos>,
156        parsed_args: Vec<ProblemArg<Pos, STeXToken<Pos>>>,
157        children: Vec<STeXToken<Pos>>,
158    },
159    InlineParagraph {
160        kind: ParagraphKind,
161        full_range: SourceRange<Pos>,
162        token_range: SourceRange<Pos>,
163        symbol: Option<SymbolReference<Pos>>,
164        parsed_args: Vec<ParagraphArg<Pos, STeXToken<Pos>>>,
165        children: Vec<STeXToken<Pos>>,
166        children_range: SourceRange<Pos>,
167    },
168    #[allow(clippy::type_complexity)]
169    Symdecl {
170        uri: SymbolReference<Pos>,
171        main_name_range: SourceRange<Pos>,
172        full_range: SourceRange<Pos>,
173        parsed_args: Vec<SymdeclArg<Pos, Self>>,
174        token_range: SourceRange<Pos>,
175    },
176    #[allow(clippy::type_complexity)]
177    TextSymdecl {
178        uri: SymbolReference<Pos>,
179        main_name_range: SourceRange<Pos>,
180        full_range: SourceRange<Pos>,
181        parsed_args: Vec<TextSymdeclArg<Pos, Self>>,
182        token_range: SourceRange<Pos>,
183    },
184    Notation {
185        uri: SmallVec<SymbolReference<Pos>, 1>,
186        token_range: SourceRange<Pos>,
187        name_range: SourceRange<Pos>,
188        notation_args: Vec<NotationArg<Pos, Self>>,
189        full_range: SourceRange<Pos>,
190    },
191    RenameDecl {
192        uri: SymbolReference<Pos>,
193        token_range: SourceRange<Pos>,
194        orig_range: SourceRange<Pos>,
195        name_range: Option<SourceRange<Pos>>,
196        macroname_range: SourceRange<Pos>,
197        full_range: SourceRange<Pos>,
198    },
199    Assign {
200        uri: SymbolReference<Pos>,
201        token_range: SourceRange<Pos>,
202        orig_range: SourceRange<Pos>,
203        full_range: SourceRange<Pos>,
204    },
205    #[allow(clippy::type_complexity)]
206    Symdef {
207        uri: SymbolReference<Pos>,
208        main_name_range: SourceRange<Pos>,
209        full_range: SourceRange<Pos>,
210        parsed_args: Vec<SymdefArg<Pos, Self>>,
211        token_range: SourceRange<Pos>,
212    },
213    #[allow(clippy::type_complexity)]
214    Vardef {
215        name: UriName,
216        main_name_range: SourceRange<Pos>,
217        full_range: SourceRange<Pos>,
218        parsed_args: Vec<VardefArg<Pos, Self>>,
219        token_range: SourceRange<Pos>,
220    },
221    #[allow(clippy::type_complexity)]
222    Varseq {
223        name: UriName,
224        main_name_range: SourceRange<Pos>,
225        full_range: SourceRange<Pos>,
226        parsed_args: Vec<VardefArg<Pos, Self>>,
227        token_range: SourceRange<Pos>,
228    },
229    SemanticMacro {
230        uri: SymbolReference<Pos>,
231        argnum: u8,
232        full_range: SourceRange<Pos>,
233        token_range: SourceRange<Pos>,
234    },
235    VariableMacro {
236        name: UriName,
237        orig: SourceRange<Pos>,
238        argnum: u8,
239        sequence: bool,
240        full_range: SourceRange<Pos>,
241        token_range: SourceRange<Pos>,
242    },
243    SymName {
244        uri: SmallVec<SymbolReference<Pos>, 1>,
245        full_range: SourceRange<Pos>,
246        token_range: SourceRange<Pos>,
247        name_range: SourceRange<Pos>,
248        mode: SymnameMode<Pos>,
249    },
250    Symuse {
251        uri: SmallVec<SymbolReference<Pos>, 1>,
252        full_range: SourceRange<Pos>,
253        token_range: SourceRange<Pos>,
254        name_range: SourceRange<Pos>,
255    },
256    Definiens {
257        uri: SmallVec<SymbolReference<Pos>, 1>,
258        full_range: SourceRange<Pos>,
259        token_range: SourceRange<Pos>,
260        name_range: Option<SourceRange<Pos>>,
261    },
262    Defnotation {
263        full_range: SourceRange<Pos>,
264    },
265    Svar {
266        name: UriName,
267        full_range: SourceRange<Pos>,
268        token_range: SourceRange<Pos>,
269        name_range: Option<SourceRange<Pos>>,
270        arg_range: SourceRange<Pos>,
271    },
272    Symref {
273        uri: SmallVec<SymbolReference<Pos>, 1>,
274        full_range: SourceRange<Pos>,
275        token_range: SourceRange<Pos>,
276        name_range: SourceRange<Pos>,
277        text: (SourceRange<Pos>, Vec<STeXToken<Pos>>),
278    },
279    Precondition {
280        uri: SmallVec<SymbolReference<Pos>, 1>,
281        full_range: SourceRange<Pos>,
282        token_range: SourceRange<Pos>,
283        dim_range: SourceRange<Pos>,
284        symbol_range: SourceRange<Pos>,
285        dim: CognitiveDimension,
286    },
287    Objective {
288        uri: SmallVec<SymbolReference<Pos>, 1>,
289        full_range: SourceRange<Pos>,
290        token_range: SourceRange<Pos>,
291        dim_range: SourceRange<Pos>,
292        symbol_range: SourceRange<Pos>,
293        dim: CognitiveDimension,
294    },
295    Vec(Vec<STeXToken<Pos>>),
296}
297
298impl<'a, P: SourcePos> FromLaTeXToken<'a, P, &'a str> for STeXToken<P> {
299    fn from_comment(_: SourceRange<P>) -> Option<Self> {
300        None
301    }
302    fn from_group(_: SourceRange<P>, v: Vec<Self>) -> Option<Self> {
303        Some(Self::Vec(v))
304    }
305    fn from_math(_: bool, _: SourceRange<P>, v: Vec<Self>) -> Option<Self> {
306        Some(Self::Vec(v))
307    }
308    fn from_control_sequence(_: P, _: &'a str) -> Option<Self> {
309        None
310    }
311    fn from_text(_: SourceRange<P>, _: &'a str) -> Option<Self> {
312        None
313    }
314    fn from_macro_application(_: Macro<'a, P, &'a str>) -> Option<Self> {
315        None
316    }
317    fn from_environment(e: Environment<'a, P, &'a str, Self>) -> Option<Self> {
318        Some(Self::Vec(e.children))
319    }
320}
321
322#[derive(Copy, Clone, Debug, serde::Serialize)]
323pub enum MorphismKind {
324    CopyModule,
325    InterpretModule,
326}
327
328#[derive(Debug, Clone, serde::Serialize)]
329pub enum SymnameMode<Pos: SourcePos> {
330    Cap {
331        post: Option<(SourceRange<Pos>, SourceRange<Pos>, String)>,
332    },
333    PostS {
334        pre: Option<(SourceRange<Pos>, SourceRange<Pos>, String)>,
335    },
336    CapAndPostS,
337    PrePost {
338        pre: Option<(SourceRange<Pos>, SourceRange<Pos>, String)>,
339        post: Option<(SourceRange<Pos>, SourceRange<Pos>, String)>,
340    },
341}
342
343#[derive(Debug, Clone, serde::Serialize)]
344pub struct InlineMorphAssign<Pos: SourcePos, T> {
345    pub symbol: SymbolReference<Pos>,
346    pub symbol_range: SourceRange<Pos>,
347    pub first: Option<(Pos, InlineMorphAssKind<Pos, T>)>,
348    pub second: Option<(Pos, InlineMorphAssKind<Pos, T>)>,
349}
350
351impl<Pos: SourcePos, T1> InlineMorphAssign<Pos, T1> {
352    pub fn into_other<T2>(
353        self,
354        mut cont: impl FnMut(Vec<T1>) -> Vec<T2>,
355    ) -> InlineMorphAssign<Pos, T2> {
356        let Self {
357            symbol,
358            symbol_range,
359            first,
360            second,
361        } = self;
362        InlineMorphAssign {
363            symbol,
364            symbol_range,
365            first: first.map(|(p, k)| {
366                (
367                    p,
368                    match k {
369                        InlineMorphAssKind::Rename(a, b, c) => InlineMorphAssKind::Rename(a, b, c),
370                        InlineMorphAssKind::Df(v) => InlineMorphAssKind::Df(cont(v)),
371                    },
372                )
373            }),
374            second: second.map(|(p, k)| {
375                (
376                    p,
377                    match k {
378                        InlineMorphAssKind::Rename(a, b, c) => InlineMorphAssKind::Rename(a, b, c),
379                        InlineMorphAssKind::Df(v) => InlineMorphAssKind::Df(cont(v)),
380                    },
381                )
382            }),
383        }
384    }
385}
386
387pub struct InlineMorphAssIter<'a, Pos: SourcePos, T>(
388    std::slice::Iter<'a, InlineMorphAssign<Pos, T>>,
389    Option<std::slice::Iter<'a, T>>,
390);
391impl<'a, Pos: SourcePos, T> InlineMorphAssIter<'a, Pos, T> {
392    pub fn new(v: &'a [InlineMorphAssign<Pos, T>]) -> Self {
393        Self(v.iter(), None)
394    }
395}
396impl<'a, Pos: SourcePos, T> Iterator for InlineMorphAssIter<'a, Pos, T> {
397    type Item = &'a T;
398    fn next(&mut self) -> Option<Self::Item> {
399        loop {
400            if let Some(n) = &mut self.1 {
401                if let Some(n) = n.next() {
402                    return Some(n);
403                }
404            }
405            if let Some(a) = self.0.next() {
406                if let Some((_, InlineMorphAssKind::Df(v))) = &a.first {
407                    self.1 = Some(v.iter());
408                    continue;
409                }
410                if let Some((_, InlineMorphAssKind::Df(v))) = &a.second {
411                    self.1 = Some(v.iter());
412                }
413            } else {
414                return None;
415            }
416        }
417    }
418}
419
420#[derive(Debug, Clone, serde::Serialize)]
421pub enum InlineMorphAssKind<Pos: SourcePos, T> {
422    Df(Vec<T>),
423    Rename(
424        Option<(UriName, SourceRange<Pos>)>,
425        Box<str>,
426        SourceRange<Pos>,
427    ),
428}
429
430#[derive(Debug, Clone, serde::Serialize)]
431pub struct SymbolReference<Pos: SourcePos> {
432    pub uri: SymbolUri,
433    pub filepath: Option<std::sync::Arc<Path>>,
434    pub range: SourceRange<Pos>,
435}
436
437#[derive(Debug, Clone, serde::Serialize)]
438pub struct ModuleReference {
439    pub uri: ModuleUri,
440    pub in_doc: DocumentUri,
441    pub rel_path: Option<std::sync::Arc<str>>,
442    pub full_path: Option<std::sync::Arc<Path>>,
443}
444impl ModuleReference {
445    /*
446    #[must_use]
447    pub fn doc_uri(&self) -> Option<DocumentUri> {
448      let rel_path = &**self.rel_path.as_ref()?;
449      let (path,name) = rel_path.rsplit_once('/').map_or_else(
450        || (None,rel_path),
451        |(path,name)| (Some(path),name)
452      );
453      let path = path.map_or_else(
454        || Ok(self.uri.archive_uri().owned().into()),
455        |path| self.uri.archive_uri().owned() % path
456      ).ok()?;
457      let (name,language) = name.rsplit_once('.')
458        .map_or((name,Language::default()), |(name,l)| (name,l.parse().unwrap_or_default()));
459      let name = if name.ends_with(Into::<&str>::into(language)) && name.len() > 3 {
460        &name[..name.len() - 3]
461      } else {name};
462      (path & (name,language)).ok()
463    }
464     */
465}
466
467pub enum GetModuleError {
468    NotFound(ModuleUri),
469    Cycle(Vec<DocumentUri>),
470}
471impl std::fmt::Display for GetModuleError {
472    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
473        match self {
474            Self::NotFound(uri) => write!(f, "module not found: {uri}"),
475            Self::Cycle(cycle) => write!(
476                f,
477                "cycle in module dependencies: {}",
478                cycle
479                    .iter()
480                    .map(DocumentUri::to_string)
481                    .collect::<Vec<_>>()
482                    .join(" -> ")
483            ),
484        }
485    }
486}
487
488pub trait STeXModuleStore {
489    const FULL: bool;
490    /// # Errors
491    fn get_module(
492        &mut self,
493        module: &ModuleReference,
494        in_path: Option<&std::sync::Arc<Path>>,
495    ) -> Result<STeXParseData, GetModuleError>;
496}
497impl STeXModuleStore for () {
498    const FULL: bool = false;
499    #[inline]
500    fn get_module(
501        &mut self,
502        r: &ModuleReference,
503        _: Option<&std::sync::Arc<Path>>,
504    ) -> Result<STeXParseData, GetModuleError> {
505        Err(GetModuleError::NotFound(r.uri.clone()))
506    }
507}
508
509#[derive(Debug, serde::Serialize)]
510pub enum ModuleRule<Pos: SourcePos> {
511    Import(ModuleReference),
512    Symbol(SymbolRule<Pos>),
513    Structure {
514        symbol: SymbolRule<Pos>,
515        //reference:ModuleReference,
516        rules: ModuleRules<Pos>,
517    },
518    ConservativeExt(SymbolReference<Pos>, ModuleRules<Pos>),
519    StructureImport(SymbolReference<Pos>),
520}
521
522#[derive(Debug, Clone, serde::Serialize)]
523pub struct SymbolRule<Pos: SourcePos> {
524    pub uri: SymbolReference<Pos>,
525    pub macroname: Option<std::sync::Arc<str>>,
526    pub has_tp: bool,
527    pub has_df: bool,
528    pub argnum: u8,
529}
530impl<Pos: SourcePos> SymbolRule<Pos> {
531    fn as_rule<'a, MS: STeXModuleStore, Err: FnMut(String, SourceRange<Pos>, DiagnosticLevel)>(
532        &self,
533    ) -> Option<(
534        Cow<'a, str>,
535        AnyMacro<'a, ParseStr<'a, Pos>, STeXToken<Pos>, Err, STeXParseState<'a, Pos, MS>>,
536    )> {
537        self.macroname.as_ref().map(|m| {
538            (
539                m.to_string().into(),
540                AnyMacro::Ext(DynMacro {
541                    ptr: super::rules::semantic_macro as _,
542                    arg: MacroArg::Symbol(self.uri.clone(), self.argnum),
543                }),
544            )
545        })
546    }
547}
548impl<Pos: SourcePos> Eq for SymbolReference<Pos> {}
549impl<Pos: SourcePos> PartialEq for SymbolReference<Pos> {
550    #[inline]
551    fn eq(&self, other: &Self) -> bool {
552        self.uri == other.uri
553    }
554}
555
556#[derive(Debug, Clone, serde::Serialize)]
557pub struct ModuleRules<Pos: SourcePos> {
558    pub rules: std::sync::Arc<[ModuleRule<Pos>]>,
559}
560impl<Pos: SourcePos> Default for ModuleRules<Pos> {
561    #[inline]
562    fn default() -> Self {
563        Self {
564            rules: std::sync::Arc::new([]),
565        }
566    }
567}
568
569pub struct STeXParseState<'a, Pos: SourcePos, MS: STeXModuleStore> {
570    pub(super) archive: Option<&'a ArchiveUri>,
571    pub(super) in_path: Option<std::sync::Arc<Path>>,
572    pub(super) doc_uri: &'a DocumentUri,
573    pub(super) backend: &'a AnyBackend,
574    pub(super) language: Language,
575    pub(super) dependencies: Vec<std::sync::Arc<Path>>,
576    pub(super) modules: SmallVec<(ModuleUri, ModuleRules<Pos>), 1>,
577    module_store: MS,
578    name_counter: IdCounter,
579}
580impl<'a, MS: STeXModuleStore> STeXParseState<'a, LSPLineCol, MS> {
581    fn load_module(
582        &mut self,
583        module: &ModuleReference,
584    ) -> Result<ModuleRules<LSPLineCol>, GetModuleError> {
585        for (uri, m) in &self.modules {
586            if *uri == module.uri {
587                return Ok(m.clone());
588            }
589        }
590        /*if let Some(fp) = &module.full_path {
591          self.dependencies.push(fp.clone());
592        }*/
593        match self.module_store.get_module(module, self.in_path.as_ref()) {
594            Ok(d) => {
595                for (uri, m) in &d.lock().modules {
596                    if *uri == module.uri {
597                        return Ok(m.clone());
598                    }
599                }
600                Err(GetModuleError::NotFound(module.uri.clone()))
601            }
602            Err(e) => Err(e),
603        }
604    }
605
606    fn load_rules<'b, Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
607        mod_ref: ModuleReference,
608        irules: ModuleRules<LSPLineCol>,
609        prev: &[STeXGroup<'a, MS, LSPLineCol, Err>],
610        current: &mut HMap<
611            Cow<'a, str>,
612            AnyMacro<'a, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
613        >,
614        changes: &mut HMap<
615            Cow<'a, str>,
616            Option<AnyMacro<'a, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>>,
617        >,
618        semantic_rules: &mut Vec<SemanticRule<LSPLineCol>>,
619        f: &mut impl FnMut(&ModuleReference) -> Option<ModuleRules<LSPLineCol>>,
620        cycles_count: u16,
621    ) -> Result<(), ()> {
622        if cycles_count >= 500 {
623            return Err(());
624        }
625        if Self::has_module(prev, semantic_rules, &mod_ref) {
626            return Ok(());
627        }
628        for rule in irules.rules.iter() {
629            match rule {
630                ModuleRule::Import(m) => {
631                    if let Some(rls) = f(m) {
632                        Self::load_rules(
633                            m.clone(),
634                            rls.clone(),
635                            prev,
636                            current,
637                            changes,
638                            semantic_rules,
639                            f,
640                            cycles_count + 1,
641                        )?;
642                    }
643                }
644                ModuleRule::Symbol(rule) if MS::FULL => {
645                    //symbols.push(rule.clone());
646                    if let Some((name, rule)) = rule.as_rule() {
647                        let old = current.insert(name.clone(), rule);
648                        if let Entry::Vacant(e) = changes.entry(name) {
649                            e.insert(old);
650                        }
651                    }
652                }
653                ModuleRule::Structure { symbol, rules } => {
654                    semantic_rules.push(SemanticRule::Structure {
655                        symbol: symbol.clone(),
656                        rules: rules.clone(),
657                    });
658                    if MS::FULL {
659                        if let Some((name, rule)) = symbol.as_rule() {
660                            let old = current.insert(name.clone(), rule);
661                            if let Entry::Vacant(e) = changes.entry(name) {
662                                e.insert(old);
663                            }
664                        }
665                    }
666                }
667                ModuleRule::ConservativeExt(s, rls) => {
668                    semantic_rules.push(SemanticRule::ConservativeExt(s.clone(), rls.clone()));
669                }
670                _ => (),
671            }
672        }
673        semantic_rules.push(SemanticRule::Module(mod_ref, irules));
674        Ok(())
675    }
676
677    fn has_module<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
678        prev: &[STeXGroup<'a, MS, LSPLineCol, Err>],
679        current: &Vec<SemanticRule<LSPLineCol>>,
680        mod_ref: &ModuleReference,
681    ) -> bool {
682        if current
683            .iter()
684            .any(|e| matches!(e,SemanticRule::Module(r,_) if r.uri == mod_ref.uri))
685        {
686            return true;
687        }
688        for p in prev.iter().rev() {
689            if matches!(&p.kind,GroupKind::Module { uri, .. } if *uri == mod_ref.uri) {
690                return true;
691            }
692            if p.semantic_rules
693                .iter()
694                .any(|e| matches!(e,SemanticRule::Module(r,_) if r.uri == mod_ref.uri))
695            {
696                return true;
697            }
698        }
699        false
700    }
701
702    /// # Panics
703    #[allow(clippy::needless_pass_by_value)]
704    pub fn add_use<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
705        &mut self,
706        module: &ModuleReference,
707        groups: Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
708        range: SourceRange<LSPLineCol>,
709    ) {
710        let groups_ls = &mut **groups.groups;
711        assert!(!groups_ls.is_empty());
712        let i = groups_ls.len() - 1;
713        let (prev, after) = groups_ls.split_at_mut(i);
714        let prev = &*prev;
715        let g = &mut after[0];
716        match self.load_module(module) {
717            Ok(irules) => {
718                if Self::load_rules(
719                    module.clone(),
720                    irules,
721                    prev,
722                    groups.rules,
723                    &mut g.inner.macro_rule_changes,
724                    &mut g.semantic_rules,
725                    &mut |m| match self.load_module(m) {
726                        Ok(r) => Some(r),
727                        Err(e) => {
728                            groups
729                                .tokenizer
730                                .problem(range.start, e, DiagnosticLevel::Error);
731                            None
732                        }
733                    },
734                    0,
735                )
736                .is_err()
737                {
738                    groups
739                        .tokenizer
740                        .problem(range.start, "Import cycle", DiagnosticLevel::Error);
741                }
742            }
743            Err(e) => groups
744                .tokenizer
745                .problem(range.start, e, DiagnosticLevel::Error),
746        }
747    }
748
749    fn has_structure<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
750        prev: &[STeXGroup<'a, MS, LSPLineCol, Err>],
751        current: &Vec<SemanticRule<LSPLineCol>>,
752        sym_ref: &SymbolReference<LSPLineCol>,
753    ) -> bool {
754        if current
755            .iter()
756            .any(|e| matches!(e,SemanticRule::StructureImport(r,_) if r.uri == sym_ref.uri))
757        {
758            return true;
759        }
760        for p in prev.iter().rev() {
761            if p.semantic_rules
762                .iter()
763                .any(|e| matches!(e,SemanticRule::StructureImport(r,_) if r.uri == sym_ref.uri))
764            {
765                return true;
766            }
767        }
768        false
769    }
770    fn load_structure<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
771        symbol: &SymbolReference<LSPLineCol>,
772        prev: &[STeXGroup<'a, MS, LSPLineCol, Err>],
773        semantic_rules: &Vec<SemanticRule<LSPLineCol>>,
774    ) -> Option<ModuleRules<LSPLineCol>> {
775        for r in semantic_rules.iter().rev() {
776            match r {
777                SemanticRule::Structure {
778                    symbol: isymbol,
779                    rules,
780                    ..
781                } if isymbol.uri.uri == symbol.uri => return Some(rules.clone()),
782                _ => (),
783            }
784        }
785        for g in prev.iter().rev() {
786            for r in g.semantic_rules.iter().rev() {
787                match r {
788                    SemanticRule::Structure {
789                        symbol: isymbol,
790                        rules,
791                        ..
792                    } if isymbol.uri.uri == symbol.uri => return Some(rules.clone()),
793                    _ => (),
794                }
795            }
796        }
797        None
798    }
799
800    fn load_structure_rules<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
801        symbol: SymbolReference<LSPLineCol>,
802        irules: ModuleRules<LSPLineCol>,
803        prev: &[STeXGroup<'a, MS, LSPLineCol, Err>],
804        current: &mut HMap<
805            Cow<'a, str>,
806            AnyMacro<'a, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
807        >,
808        changes: &mut HMap<
809            Cow<'a, str>,
810            Option<AnyMacro<'a, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>>,
811        >,
812        semantic_rules: &mut Vec<SemanticRule<LSPLineCol>>,
813    ) {
814        macro_rules! do_rule {
815            ($rule:ident) => {
816                match $rule {
817                    ModuleRule::StructureImport(m)
818                        if !Self::has_structure(prev, semantic_rules, &symbol) =>
819                    {
820                        if let Some(rls) = Self::load_structure(m, prev, semantic_rules) {
821                            Self::load_structure_rules(
822                                m.clone(),
823                                rls,
824                                prev,
825                                current,
826                                changes,
827                                semantic_rules,
828                            );
829                        }
830                    }
831                    ModuleRule::Symbol(rule) if MS::FULL => {
832                        //symbols.push(rule.clone());
833                        if let Some((name, rule)) = rule.as_rule() {
834                            let old = current.insert(name.clone(), rule);
835                            if let Entry::Vacant(e) = changes.entry(name) {
836                                e.insert(old);
837                            }
838                        }
839                    }
840                    ModuleRule::Structure { symbol, rules } => {
841                        semantic_rules.push(SemanticRule::Structure {
842                            symbol: symbol.clone(),
843                            rules: rules.clone(),
844                        });
845                        if MS::FULL {
846                            if let Some((name, rule)) = symbol.as_rule() {
847                                let old = current.insert(name.clone(), rule);
848                                if let Entry::Vacant(e) = changes.entry(name) {
849                                    e.insert(old);
850                                }
851                            }
852                        }
853                    }
854                    _ => (),
855                }
856            };
857        }
858        for rule in irules.rules.iter() {
859            do_rule!(rule);
860        }
861        for g in prev.iter().rev() {
862            for rule in g.semantic_rules.iter().rev() {
863                if let SemanticRule::ConservativeExt(s, rls) = rule {
864                    //tracing::info!("Checking {} vs {}",s.uri,symbol.uri);
865                    if s.uri == symbol.uri {
866                        for rule in rls.rules.iter() {
867                            do_rule!(rule);
868                        }
869                    }
870                }
871            }
872        }
873        semantic_rules.push(SemanticRule::StructureImport(symbol, irules));
874    }
875
876    pub fn import_structure<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
877        &mut self,
878        symbol: &SymbolReference<LSPLineCol>,
879        srules: &ModuleRules<LSPLineCol>,
880        groups: &mut Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
881        range: SourceRange<LSPLineCol>,
882    ) {
883        let groups_ls = &mut **groups.groups;
884        let Some(i) = groups_ls.iter().enumerate().rev().find_map(|(i, g)| {
885            if matches!(
886                &g.kind,
887                GroupKind::Module { .. } | GroupKind::MathStructure { .. }
888            ) {
889                Some(i)
890            } else {
891                None
892            }
893        }) else {
894            groups.tokenizer.problem(
895                range.start,
896                "\\importmodule is only allowed in a module".to_string(),
897                DiagnosticLevel::Error,
898            );
899            return;
900        };
901        let (prev, after) = groups_ls.split_at_mut(i);
902        let prev = &*prev;
903        let g = &mut after[0];
904        let (GroupKind::Module { rules, .. } | GroupKind::MathStructure { rules, .. }) =
905            &mut g.kind
906        else {
907            impossible!()
908        };
909        if rules
910            .iter()
911            .any(|r| matches!(r,ModuleRule::StructureImport(s) if s.uri == symbol.uri))
912        {
913            return;
914        }
915        rules.push(ModuleRule::StructureImport(symbol.clone()));
916        if !Self::has_structure(prev, &g.semantic_rules, &symbol) {
917            // if MS::FULL {
918            Self::load_structure_rules(
919                symbol.clone(),
920                srules.clone(),
921                prev,
922                groups.rules,
923                &mut g.inner.macro_rule_changes,
924                &mut g.semantic_rules,
925            );
926            // }
927        }
928    }
929
930    pub fn use_structure<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
931        &mut self,
932        symbol: &SymbolReference<LSPLineCol>,
933        srules: &ModuleRules<LSPLineCol>,
934        groups: &mut Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
935        _range: SourceRange<LSPLineCol>,
936    ) {
937        let groups_ls = &mut **groups.groups;
938        let i = groups_ls.len() - 1;
939        let (prev, after) = groups_ls.split_at_mut(i);
940        let prev = &*prev;
941        let g = &mut after[0];
942        if !Self::has_structure(prev, &g.semantic_rules, &symbol) {
943            // if MS::FULL {
944            Self::load_structure_rules(
945                symbol.clone(),
946                srules.clone(),
947                prev,
948                groups.rules,
949                &mut g.inner.macro_rule_changes,
950                &mut g.semantic_rules,
951            );
952            // }
953        }
954    }
955
956    #[allow(clippy::needless_pass_by_value)]
957    pub fn add_import<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
958        &mut self,
959        module: &ModuleReference,
960        groups: Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
961        range: SourceRange<LSPLineCol>,
962    ) {
963        let groups_ls = &mut **groups.groups;
964        let Some(i) = groups_ls.iter().enumerate().rev().find_map(|(i, g)| {
965            if matches!(
966                &g.kind,
967                GroupKind::Module { .. } | GroupKind::MathStructure { .. }
968            ) {
969                Some(i)
970            } else {
971                None
972            }
973        }) else {
974            groups.tokenizer.problem(
975                range.start,
976                "\\importmodule is only allowed in a module".to_string(),
977                DiagnosticLevel::Error,
978            );
979            return;
980        };
981        let (prev, after) = groups_ls.split_at_mut(i);
982        let prev = &*prev;
983        let g = &mut after[0];
984        let (GroupKind::Module { rules, .. } | GroupKind::MathStructure { rules, .. }) =
985            &mut g.kind
986        else {
987            unreachable!()
988        };
989        if rules
990            .iter()
991            .any(|r| matches!(r,ModuleRule::Import(m) if m.uri == module.uri))
992        {
993            return;
994        }
995        rules.push(ModuleRule::Import(module.clone()));
996        match self.load_module(module) {
997            Ok(irules) => {
998                if Self::load_rules(
999                    module.clone(),
1000                    irules,
1001                    prev,
1002                    groups.rules,
1003                    &mut g.inner.macro_rule_changes,
1004                    &mut g.semantic_rules,
1005                    &mut |m| match self.load_module(m) {
1006                        Ok(r) => Some(r),
1007                        Err(e) => {
1008                            groups
1009                                .tokenizer
1010                                .problem(range.start, e, DiagnosticLevel::Error);
1011                            None
1012                        }
1013                    },
1014                    0,
1015                )
1016                .is_err()
1017                {
1018                    groups
1019                        .tokenizer
1020                        .problem(range.start, "Import cycle", DiagnosticLevel::Error);
1021                }
1022            }
1023            Err(e) => groups
1024                .tokenizer
1025                .problem(range.start, e, DiagnosticLevel::Error),
1026        }
1027    }
1028
1029    #[allow(clippy::unused_self)]
1030    fn get_symbol_macro_or_name<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
1031        &self,
1032        groups: &Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
1033        namestr: &str,
1034    ) -> Option<SmallVec<SymbolReference<LSPLineCol>, 1>> {
1035        let mut ret = SmallVec::new();
1036        for g in groups.groups.iter().rev() {
1037            for r in g.semantic_rules.iter().rev() {
1038                match r {
1039                    SemanticRule::Symbol(r) | SemanticRule::Structure { symbol: r, .. } => {
1040                        if r.macroname.as_ref().is_some_and(|n| &**n == namestr) {
1041                            if !ret.contains(&r.uri) {
1042                                ret.push(r.uri.clone());
1043                            }
1044                            continue;
1045                        }
1046                        if r.uri.uri.name().last() == namestr {
1047                            if !ret.contains(&r.uri) {
1048                                ret.push(r.uri.clone());
1049                            }
1050                        }
1051                    }
1052                    SemanticRule::Module(_, r) | SemanticRule::StructureImport(_, r) => {
1053                        for r in r.rules.iter().rev() {
1054                            match r {
1055                                ModuleRule::Symbol(r) | ModuleRule::Structure { symbol: r, .. } => {
1056                                    if r.macroname.as_ref().is_some_and(|n| &**n == namestr) {
1057                                        if !ret.contains(&r.uri) {
1058                                            ret.push(r.uri.clone());
1059                                        }
1060                                        continue;
1061                                    }
1062                                    if r.uri.uri.name().last() == namestr {
1063                                        if !ret.contains(&r.uri) {
1064                                            ret.push(r.uri.clone());
1065                                        }
1066                                    }
1067                                }
1068                                _ => (),
1069                            }
1070                        }
1071                    }
1072                    SemanticRule::ConservativeExt(s, rls)
1073                        if Self::has_structure(&groups.groups, &Vec::new(), s) =>
1074                    {
1075                        for r in rls.rules.iter().rev() {
1076                            match r {
1077                                ModuleRule::Symbol(r) | ModuleRule::Structure { symbol: r, .. } => {
1078                                    if r.macroname.as_ref().is_some_and(|n| &**n == namestr) {
1079                                        if !ret.contains(&r.uri) {
1080                                            ret.push(r.uri.clone());
1081                                        }
1082                                        continue;
1083                                    }
1084                                    if r.uri.uri.name().last() == namestr {
1085                                        if !ret.contains(&r.uri) {
1086                                            ret.push(r.uri.clone());
1087                                        }
1088                                    }
1089                                }
1090                                _ => (),
1091                            }
1092                        }
1093                    }
1094                    SemanticRule::ConservativeExt(..) => (),
1095                }
1096            }
1097        }
1098        if ret.is_empty() {
1099            None
1100        } else {
1101            Some(ret)
1102        }
1103    }
1104
1105    #[allow(clippy::unused_self)]
1106    fn get_structure_macro_or_name<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
1107        &self,
1108        groups: &Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
1109        namestr: &str,
1110    ) -> Option<(SymbolReference<LSPLineCol>, ModuleRules<LSPLineCol>)> {
1111        for g in groups.groups.iter().rev() {
1112            for r in g.semantic_rules.iter().rev() {
1113                match r {
1114                    SemanticRule::Structure { symbol, rules, .. } => {
1115                        if symbol.macroname.as_ref().is_some_and(|n| &**n == namestr) {
1116                            return Some((symbol.uri.clone(), rules.clone()));
1117                        }
1118                        if symbol.uri.uri.name().last() == namestr {
1119                            return Some((symbol.uri.clone(), rules.clone()));
1120                        }
1121                    }
1122                    SemanticRule::Module(_, r) => {
1123                        for r in r.rules.iter().rev() {
1124                            match r {
1125                                ModuleRule::Structure { symbol, rules, .. } => {
1126                                    if symbol.macroname.as_ref().is_some_and(|n| &**n == namestr) {
1127                                        return Some((symbol.uri.clone(), rules.clone()));
1128                                    }
1129                                    if symbol.uri.uri.name().last() == namestr {
1130                                        return Some((symbol.uri.clone(), rules.clone()));
1131                                    }
1132                                }
1133                                _ => (),
1134                            }
1135                        }
1136                    }
1137                    _ => (),
1138                }
1139            }
1140        }
1141        None
1142    }
1143
1144    fn compare(symbol: &str, module: &str, path: Option<&str>, uri: &SymbolUri) -> bool {
1145        fn compare_names(n1: &str, n2: &UriName) -> Option<bool> {
1146            let mut symbol_steps = n1.split('/').rev();
1147            let mut uri_steps = n2.steps().rev();
1148            loop {
1149                let Some(sym) = symbol_steps.next() else {
1150                    return if uri_steps.next().is_some() {
1151                        None
1152                    } else {
1153                        Some(true)
1154                    };
1155                };
1156                let Some(uristep) = uri_steps.next() else {
1157                    return Some(false);
1158                };
1159                if sym != uristep {
1160                    if symbol_steps.next().is_none() && uristep.ends_with(sym) {
1161                        return None;
1162                    }
1163                    return Some(false);
1164                }
1165            }
1166        }
1167        if compare_names(symbol, uri.name()) != Some(true) {
1168            return false;
1169        }
1170        match compare_names(module, uri.module_name()) {
1171            None | Some(true) if path.is_none() => return true,
1172            Some(false) | None => return false,
1173            Some(true) => (),
1174        }
1175        let Some(mut path) = path else { unreachable!() };
1176        if let Some(uri_path) = uri.path() {
1177            for step in uri_path.steps().rev() {
1178                if path.is_empty() {
1179                    return true;
1180                }
1181                if let Some(p) = path.strip_suffix(step) {
1182                    if let Some(p) = p.strip_suffix('/') {
1183                        path = p;
1184                    } else {
1185                        if p.is_empty() {
1186                            return true;
1187                        }
1188                    }
1189                } else {
1190                    return false;
1191                }
1192            }
1193        }
1194        let id = uri.archive_id();
1195        return id.as_ref().ends_with(path);
1196    }
1197
1198    #[allow(clippy::unused_self)]
1199    fn get_symbol_complex<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
1200        &self,
1201        groups: &Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
1202        symbol: &str,
1203        module: &str,
1204        path: Option<&str>,
1205    ) -> Option<SmallVec<SymbolReference<LSPLineCol>, 1>> {
1206        let mut ret = SmallVec::new();
1207        for g in groups.groups.iter().rev() {
1208            for r in g.semantic_rules.iter().rev() {
1209                match r {
1210                    SemanticRule::Symbol(r) | SemanticRule::Structure { symbol: r, .. }
1211                        if Self::compare(symbol, module, path, &r.uri.uri) =>
1212                    {
1213                        if !ret.contains(&r.uri) {
1214                            ret.push(r.uri.clone());
1215                        }
1216                    }
1217                    SemanticRule::Module(_, r) | SemanticRule::StructureImport(_, r) => {
1218                        for r in r.rules.iter().rev() {
1219                            match r {
1220                                ModuleRule::Symbol(r) | ModuleRule::Structure { symbol: r, .. }
1221                                    if Self::compare(symbol, module, path, &r.uri.uri) =>
1222                                {
1223                                    if !ret.contains(&r.uri) {
1224                                        ret.push(r.uri.clone());
1225                                    }
1226                                }
1227                                _ => (),
1228                            }
1229                        }
1230                    }
1231                    SemanticRule::ConservativeExt(s, rls)
1232                        if Self::has_structure(&groups.groups, &Vec::new(), s) =>
1233                    {
1234                        for r in rls.rules.iter().rev() {
1235                            match r {
1236                                ModuleRule::Symbol(r) | ModuleRule::Structure { symbol: r, .. }
1237                                    if Self::compare(symbol, module, path, &r.uri.uri) =>
1238                                {
1239                                    if !ret.contains(&r.uri) {
1240                                        ret.push(r.uri.clone());
1241                                    }
1242                                }
1243                                _ => (),
1244                            }
1245                        }
1246                    }
1247                    _ => (),
1248                }
1249            }
1250        }
1251        if ret.is_empty() {
1252            None
1253        } else {
1254            Some(ret)
1255        }
1256    }
1257
1258    #[allow(clippy::unused_self)]
1259    fn get_structure_uri<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
1260        &self,
1261        groups: &Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
1262        uri: &SymbolReference<LSPLineCol>,
1263    ) -> Option<ModuleRules<LSPLineCol>> {
1264        for g in groups.groups.iter().rev() {
1265            for r in g.semantic_rules.iter().rev() {
1266                match r {
1267                    SemanticRule::Structure { symbol, rules, .. } if symbol.uri.uri == uri.uri => {
1268                        return Some(rules.clone())
1269                    }
1270                    SemanticRule::Module(_, r) => {
1271                        for r in r.rules.iter().rev() {
1272                            match r {
1273                                ModuleRule::Structure { symbol, rules, .. }
1274                                    if symbol.uri.uri == uri.uri =>
1275                                {
1276                                    return Some(rules.clone())
1277                                }
1278                                _ => (),
1279                            }
1280                        }
1281                    }
1282                    _ => (),
1283                }
1284            }
1285        }
1286        None
1287    }
1288
1289    #[allow(clippy::unused_self)]
1290    fn get_structure_complex<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
1291        &self,
1292        groups: &Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
1293        namestr: &str,
1294        module: &str,
1295        path: Option<&str>,
1296    ) -> Option<(SymbolReference<LSPLineCol>, ModuleRules<LSPLineCol>)> {
1297        for g in groups.groups.iter().rev() {
1298            for r in g.semantic_rules.iter().rev() {
1299                match r {
1300                    SemanticRule::Structure { symbol, rules, .. }
1301                        if Self::compare(namestr, module, path, &symbol.uri.uri) =>
1302                    {
1303                        return Some((symbol.uri.clone(), rules.clone()))
1304                    }
1305                    SemanticRule::Module(_, r) => {
1306                        for r in r.rules.iter().rev() {
1307                            match r {
1308                                ModuleRule::Structure { symbol, rules, .. }
1309                                    if Self::compare(namestr, module, path, &symbol.uri.uri) =>
1310                                {
1311                                    return Some((symbol.uri.clone(), rules.clone()))
1312                                }
1313                                _ => (),
1314                            }
1315                        }
1316                    }
1317                    _ => (),
1318                }
1319            }
1320        }
1321        None
1322    }
1323
1324    pub fn get_symbol<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
1325        &self,
1326        start: LSPLineCol,
1327        groups: &mut Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
1328        namestr: &str,
1329    ) -> Option<SmallVec<SymbolReference<LSPLineCol>, 1>> {
1330        //let realname = namestr.trim().split_ascii_whitespace().collect::<Vec<_>>().join(" ");
1331        let mut steps = namestr.split('?').rev(); //realname.split('?').rev();
1332        let name = steps.next()?;
1333
1334        let module = if let Some(module) = steps.next() {
1335            module
1336        } else {
1337            if !name.contains('/') {
1338                //return self.get_symbol_macro_or_name(groups,name);
1339                let r = self.get_symbol_macro_or_name(groups, name)?;
1340                if r.len() > 1 {
1341                    groups.tokenizer.problem(
1342                        start,
1343                        format!("Ambiguous symbol reference: {namestr}"),
1344                        DiagnosticLevel::Warning,
1345                    );
1346                }
1347                return Some(r);
1348            }
1349            ""
1350        };
1351        let path = if steps.next().is_none() {
1352            None
1353        } else {
1354            let i = namestr.len() - (name.len() + 1 + module.len() + 1);
1355            Some(&namestr[..i])
1356        };
1357        let r = self.get_symbol_complex(groups, name, module, path)?;
1358        if r.len() > 1 {
1359            groups.tokenizer.problem(
1360                start,
1361                format!("Ambiguous symbol reference: {namestr}"),
1362                DiagnosticLevel::Warning,
1363            );
1364        }
1365        Some(r)
1366    }
1367
1368    pub fn get_structure<Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel)>(
1369        &self,
1370        groups: &Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
1371        namestr: &str,
1372    ) -> Option<(SymbolReference<LSPLineCol>, ModuleRules<LSPLineCol>)> {
1373        //let realname = namestr.trim().split_ascii_whitespace().collect::<Vec<_>>().join(" ");
1374        let mut steps = namestr.split('?').rev(); //realname.split('?').rev();
1375        let name = steps.next()?;
1376
1377        let Some(module) = steps.next() else {
1378            return self.get_structure_macro_or_name(groups, name);
1379        };
1380        let path = if steps.next().is_none() {
1381            None
1382        } else {
1383            let i = namestr.len() - (name.len() + 1 + module.len() + 1);
1384            Some(&namestr[..i])
1385        };
1386        self.get_structure_complex(groups, name, module, path)
1387    }
1388
1389    #[allow(clippy::too_many_lines)]
1390    pub(super) fn resolve_module_or_struct<
1391        Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel),
1392    >(
1393        &mut self,
1394        groups: &Groups<'a, '_, ParseStr<'a, LSPLineCol>, STeXToken<LSPLineCol>, Err, Self>,
1395        module_or_struct: &str,
1396        archive: Option<ArchiveId>,
1397    ) -> Option<(ModuleOrStruct<LSPLineCol>, Vec<ModuleRules<LSPLineCol>>)> {
1398        fn mmatch<
1399            'a,
1400            MS: STeXModuleStore,
1401            Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel),
1402        >(
1403            slf: &mut STeXParseState<'a, LSPLineCol, MS>,
1404            groups: &Groups<
1405                'a,
1406                '_,
1407                ParseStr<'a, LSPLineCol>,
1408                STeXToken<LSPLineCol>,
1409                Err,
1410                STeXParseState<'a, LSPLineCol, MS>,
1411            >,
1412            rules: &ModuleRules<LSPLineCol>,
1413            dones: &mut Vec<DomainUri>,
1414            target: &mut Vec<ModuleRules<LSPLineCol>>,
1415        ) -> Option<()> {
1416            for r in rules.rules.iter() {
1417                match r {
1418                    ModuleRule::Import(m)
1419                        if !dones
1420                            .iter()
1421                            .any(|u| matches!(u,DomainUri::Module(u) if *u == m.uri)) =>
1422                    {
1423                        load_module(slf, groups, m, dones, target)?;
1424                    }
1425                    ModuleRule::StructureImport(s)
1426                        if !dones
1427                            .iter()
1428                            .any(|u| matches!(u,DomainUri::Symbol(u) if *u == s.uri)) =>
1429                    {
1430                        load_structure(slf, groups, s, dones, target)?;
1431                    }
1432                    _ => (),
1433                }
1434            }
1435            Some(())
1436        }
1437        fn load_module<
1438            'a,
1439            MS: STeXModuleStore,
1440            Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel),
1441        >(
1442            slf: &mut STeXParseState<'a, LSPLineCol, MS>,
1443            groups: &Groups<
1444                'a,
1445                '_,
1446                ParseStr<'a, LSPLineCol>,
1447                STeXToken<LSPLineCol>,
1448                Err,
1449                STeXParseState<'a, LSPLineCol, MS>,
1450            >,
1451            module: &ModuleReference,
1452            dones: &mut Vec<DomainUri>,
1453            target: &mut Vec<ModuleRules<LSPLineCol>>,
1454        ) -> Option<()> {
1455            dones.push(module.uri.clone().into());
1456            let rls = slf.load_module(module).ok()?;
1457            mmatch(slf, groups, &rls, dones, target)?;
1458            target.push(rls);
1459            Some(())
1460        }
1461        fn load_structure<
1462            'a,
1463            MS: STeXModuleStore,
1464            Err: FnMut(String, SourceRange<LSPLineCol>, DiagnosticLevel),
1465        >(
1466            slf: &mut STeXParseState<'a, LSPLineCol, MS>,
1467            groups: &Groups<
1468                'a,
1469                '_,
1470                ParseStr<'a, LSPLineCol>,
1471                STeXToken<LSPLineCol>,
1472                Err,
1473                STeXParseState<'a, LSPLineCol, MS>,
1474            >,
1475            structure: &SymbolReference<LSPLineCol>,
1476            dones: &mut Vec<DomainUri>,
1477            target: &mut Vec<ModuleRules<LSPLineCol>>,
1478        ) -> Option<()> {
1479            dones.push(structure.uri.clone().into());
1480            let rls = slf.get_structure_uri(groups, structure)?;
1481            mmatch(slf, groups, &rls, dones, target)?;
1482            target.push(rls);
1483            Some(())
1484        }
1485        let mut dones = Vec::new();
1486        if archive.is_none() {
1487            if let Some((m, rls)) = self.find_module(module_or_struct) {
1488                let mut ret = Vec::new();
1489                let rls = rls.clone();
1490                let rf = ModuleOrStruct::Module(ModuleReference {
1491                    uri: m.clone(),
1492                    in_doc: self.doc_uri.clone(),
1493                    rel_path: None,
1494                    full_path: self.in_path.clone(),
1495                });
1496                mmatch(self, groups, &rls, &mut dones, &mut ret)?;
1497                ret.push(rls);
1498                return Some((rf, ret));
1499            }
1500            if let Some((s, r)) = self.get_structure(groups, module_or_struct) {
1501                let mut ret = Vec::new();
1502                mmatch(self, groups, &r, &mut dones, &mut ret)?;
1503                ret.push(r);
1504                return Some((ModuleOrStruct::Struct(s), ret));
1505            }
1506        }
1507        if let Some(m) = self.resolve_module(module_or_struct, archive) {
1508            let mut ret = Vec::new();
1509            load_module(self, groups, &m, &mut dones, &mut ret)?;
1510            Some((ModuleOrStruct::Module(m), ret))
1511        } else {
1512            None
1513        }
1514    }
1515}
1516
1517impl<'a, Pos: SourcePos, MS: STeXModuleStore> STeXParseState<'a, Pos, MS> {
1518    #[inline]
1519    #[must_use]
1520    pub fn new(
1521        archive: Option<&'a ArchiveUri>,
1522        in_path: Option<&'a Path>,
1523        uri: &'a DocumentUri,
1524        backend: &'a AnyBackend,
1525        on_module: MS,
1526    ) -> Self {
1527        let language = in_path.map(Language::from).unwrap_or_default();
1528        Self {
1529            archive,
1530            in_path: in_path.map(Into::into),
1531            doc_uri: uri,
1532            language,
1533            backend,
1534            modules: SmallVec::new(),
1535            module_store: on_module,
1536            name_counter: IdCounter::default(),
1537            dependencies: Vec::new(),
1538        }
1539    }
1540
1541    pub fn set_structure<Err: FnMut(String, SourceRange<Pos>, DiagnosticLevel)>(
1542        &mut self,
1543        groups: &mut Groups<'a, '_, ParseStr<'a, Pos>, STeXToken<Pos>, Err, Self>,
1544        rules: ModuleRules<Pos>,
1545        range: SourceRange<Pos>,
1546    ) {
1547        for g in groups.groups.iter_mut().rev() {
1548            match &mut g.kind {
1549                GroupKind::Module { rules: rls, .. } => match rls.last_mut() {
1550                    Some(ModuleRule::Structure {
1551                        symbol,
1552                        rules: rls1,
1553                        ..
1554                    }) => {
1555                        for sr in g.semantic_rules.iter_mut().rev() {
1556                            match sr {
1557                                SemanticRule::Structure {
1558                                    symbol: symbol2,
1559                                    rules: rls2,
1560                                    ..
1561                                } if symbol.uri.uri == symbol2.uri.uri => {
1562                                    *rls2 = rules.clone();
1563                                    break;
1564                                }
1565                                _ => (),
1566                            }
1567                        }
1568                        *rls1 = rules;
1569                        return;
1570                    }
1571                    Some(ModuleRule::ConservativeExt(_, rls1)) => {
1572                        for sr in g.semantic_rules.iter_mut().rev() {
1573                            match sr {
1574                                SemanticRule::ConservativeExt(_, rls2) => {
1575                                    *rls2 = rules.clone();
1576                                    break;
1577                                }
1578                                _ => (),
1579                            }
1580                        }
1581                        *rls1 = rules;
1582                        return;
1583                    }
1584                    _ => {
1585                        groups.tokenizer.problem(
1586                            range.start,
1587                            "mathstructure ended unexpectedly".to_string(),
1588                            DiagnosticLevel::Error,
1589                        );
1590                        return;
1591                    }
1592                },
1593                _ => (),
1594            }
1595        }
1596        groups.tokenizer.problem(
1597            range.start,
1598            "mathstructure is only allowed in a module".to_string(),
1599            DiagnosticLevel::Error,
1600        );
1601    }
1602
1603    pub fn add_structure<Err: FnMut(String, SourceRange<Pos>, DiagnosticLevel)>(
1604        &mut self,
1605        groups: &mut Groups<'a, '_, ParseStr<'a, Pos>, STeXToken<Pos>, Err, Self>,
1606        name: UriName,
1607        macroname: Option<std::sync::Arc<str>>,
1608        range: SourceRange<Pos>,
1609    ) -> Option<SymbolReference<Pos>> {
1610        for g in groups.groups.iter_mut().rev() {
1611            match &mut g.kind {
1612                GroupKind::Module { uri, rules, .. } => {
1613                    let suri = uri.clone() | name;
1614                    let uri = SymbolReference {
1615                        uri: suri,
1616                        filepath: self.in_path.clone(),
1617                        range,
1618                    };
1619                    for r in &*rules {
1620                        match r {
1621                            ModuleRule::Symbol(s) | ModuleRule::Structure { symbol: s, .. }
1622                                if s.uri.uri == uri.uri =>
1623                            {
1624                                groups.tokenizer.problem(
1625                                    range.start,
1626                                    format!("symbol with name {} already exists", s.uri.uri),
1627                                    DiagnosticLevel::Warning,
1628                                );
1629                            }
1630                            _ => (),
1631                        }
1632                    }
1633                    let rule = SymbolRule {
1634                        uri,
1635                        macroname,
1636                        has_tp: false,
1637                        has_df: false,
1638                        argnum: 0,
1639                    };
1640                    if MS::FULL {
1641                        if let Some((name, rule)) = rule.as_rule() {
1642                            let old = groups.rules.insert(name.clone(), rule);
1643                            if let Entry::Vacant(e) = g.inner.macro_rule_changes.entry(name) {
1644                                e.insert(old);
1645                            }
1646                        }
1647                    }
1648                    g.semantic_rules.push(SemanticRule::Structure {
1649                        //module_uri: rule.uri.uri.clone().into_module(),
1650                        symbol: rule.clone(),
1651                        rules: ModuleRules::default(),
1652                    });
1653                    let uri = rule.uri.clone();
1654                    rules.push(ModuleRule::Structure {
1655                        symbol: rule,
1656                        rules: ModuleRules::default(),
1657                    });
1658                    return Some(uri);
1659                }
1660                _ => (),
1661            }
1662        }
1663        groups.tokenizer.problem(
1664            range.start,
1665            "mathstructure is only allowed in a module".to_string(),
1666            DiagnosticLevel::Error,
1667        );
1668        None
1669    }
1670
1671    #[inline]
1672    fn new_id(&mut self, prefix: Cow<'static, str>) -> Box<str> {
1673        self.name_counter.new_id(prefix)
1674    }
1675
1676    pub fn add_conservative_ext<Err: FnMut(String, SourceRange<Pos>, DiagnosticLevel)>(
1677        &mut self,
1678        groups: &mut Groups<'a, '_, ParseStr<'a, Pos>, STeXToken<Pos>, Err, Self>,
1679        orig: &SymbolReference<Pos>,
1680        range: SourceRange<Pos>,
1681    ) -> Option<ModuleUri> {
1682        for g in groups.groups.iter_mut().rev() {
1683            match &mut g.kind {
1684                GroupKind::Module { uri, rules, .. } => {
1685                    let name = self.new_id(Cow::Borrowed("EXTSTRUCT"));
1686                    let euri = uri.clone() / &name.parse().ok()?;
1687                    g.semantic_rules.push(SemanticRule::ConservativeExt(
1688                        orig.clone(),
1689                        ModuleRules::default(),
1690                    ));
1691                    rules.push(ModuleRule::ConservativeExt(
1692                        orig.clone(),
1693                        ModuleRules::default(),
1694                    ));
1695                    return Some(euri);
1696                }
1697                _ => (),
1698            }
1699        }
1700        groups.tokenizer.problem(
1701            range.start,
1702            "mathstructure is only allowed in a module".to_string(),
1703            DiagnosticLevel::Error,
1704        );
1705        None
1706    }
1707
1708    pub fn add_symbol<Err: FnMut(String, SourceRange<Pos>, DiagnosticLevel)>(
1709        &mut self,
1710        groups: &mut Groups<'a, '_, ParseStr<'a, Pos>, STeXToken<Pos>, Err, Self>,
1711        name: UriName,
1712        macroname: Option<std::sync::Arc<str>>,
1713        range: SourceRange<Pos>,
1714        has_tp: bool,
1715        has_df: bool,
1716        argnum: u8,
1717    ) -> Option<SymbolReference<Pos>> {
1718        for g in groups.groups.iter_mut().rev() {
1719            match &mut g.kind {
1720                GroupKind::Module { uri, rules, .. }
1721                | GroupKind::MathStructure { uri, rules }
1722                | GroupKind::ConservativeExt(uri, rules) => {
1723                    let suri = uri.clone() | name;
1724                    let uri = SymbolReference {
1725                        uri: suri,
1726                        filepath: self.in_path.clone(),
1727                        range,
1728                    };
1729                    for r in &*rules {
1730                        match r {
1731                            ModuleRule::Symbol(s) | ModuleRule::Structure { symbol: s, .. }
1732                                if s.uri.uri == uri.uri =>
1733                            {
1734                                groups.tokenizer.problem(
1735                                    range.start,
1736                                    format!("symbol with name {} already exists", s.uri.uri),
1737                                    DiagnosticLevel::Warning,
1738                                );
1739                            }
1740                            _ => (),
1741                        }
1742                    }
1743                    let rule = SymbolRule {
1744                        uri,
1745                        macroname,
1746                        has_tp,
1747                        has_df,
1748                        argnum,
1749                    };
1750                    if MS::FULL {
1751                        if let Some((name, rule)) = rule.as_rule() {
1752                            let old = groups.rules.insert(name.clone(), rule);
1753                            if let Entry::Vacant(e) = g.inner.macro_rule_changes.entry(name) {
1754                                e.insert(old);
1755                            }
1756                        }
1757                    }
1758                    g.semantic_rules.push(SemanticRule::Symbol(rule.clone()));
1759                    let uri = rule.uri.clone();
1760                    rules.push(ModuleRule::Symbol(rule));
1761                    //g.symbols.push(rule);
1762                    return Some(uri);
1763                }
1764                _ => (),
1765            }
1766        }
1767        groups.tokenizer.problem(
1768            range.start,
1769            "\\symdecl is only allowed in a module".to_string(),
1770            DiagnosticLevel::Error,
1771        );
1772        None
1773    }
1774
1775    #[allow(clippy::case_sensitive_file_extension_comparisons)]
1776    #[allow(clippy::needless_pass_by_value)]
1777    #[allow(clippy::too_many_lines)]
1778    pub(super) fn resolve_module(
1779        &self,
1780        module: &'a str,
1781        archive: Option<ArchiveId>,
1782    ) -> Option<ModuleReference> {
1783        if let Some((m, _)) = self.find_module(module) {
1784            return Some(ModuleReference {
1785                uri: m.clone(),
1786                in_doc: self.doc_uri.clone(),
1787                rel_path: None,
1788                full_path: self.in_path.clone(),
1789            });
1790        }
1791        let (mut basepath, archive) = archive.as_ref().map_or_else(
1792            || {
1793                self.archive.and_then(|a| {
1794                    self.in_path
1795                        .as_ref()
1796                        .and_then(|p| p.to_str())
1797                        .and_then(|s| {
1798                            s.find("source")
1799                                .map(|i| (PathBuf::from(&s[..i - 1]).join("source"), a.clone()))
1800                        })
1801                })
1802            },
1803            |a| {
1804                self.backend
1805                    .with_local_archive(a, |a| a.map(|a| (a.source_dir(), a.uri().clone())))
1806            },
1807        )?;
1808
1809        let (mut path, module) = if let Some((a, b)) = module.split_once('?') {
1810            (a.trim(), b)
1811        } else {
1812            ("", module)
1813        };
1814
1815        let top_module = if let Some((t, _)) = module.split_once('/') {
1816            t
1817        } else {
1818            module
1819        };
1820
1821        let last = if let Some((p, last)) = path.rsplit_once('/') {
1822            basepath = p.split('/').fold(basepath, |p, s| p.join(s));
1823            last
1824        } else {
1825            path
1826        };
1827
1828        let uri: ModuleUri = if path.trim().is_empty() {
1829            PathUri::from(archive) | module.parse().ok()?
1830        } else {
1831            (PathUri::from(archive) / path.trim().parse::<UriPath>().ok()?) | module.parse().ok()?
1832        };
1833
1834        let p = basepath
1835            .join(last)
1836            .join(format!("{top_module}.{}.tex", self.language));
1837        if p.exists() {
1838            let rel_path = if path.is_empty() {
1839                format!("{top_module}.{}.tex", self.language)
1840            } else {
1841                format!("{path}/{top_module}.{}.tex", self.language)
1842            };
1843            return Some(ModuleReference {
1844                rel_path: Some(rel_path.into()),
1845                in_doc: uri.path_uri().clone() & (top_module.parse().ok()?, self.language),
1846                full_path: Some(p.into()),
1847                uri,
1848            });
1849        }
1850
1851        let p = basepath.join(last).join(format!("{top_module}.en.tex"));
1852        if p.exists() {
1853            let rel_path = if path.is_empty() {
1854                format!("{top_module}.en.tex")
1855            } else {
1856                format!("{path}/{top_module}.en.tex")
1857            };
1858            return Some(ModuleReference {
1859                rel_path: Some(rel_path.into()),
1860                in_doc: uri.path_uri().clone() & (top_module.parse().ok()?, Language::English),
1861                full_path: Some(p.into()),
1862                uri,
1863            });
1864        }
1865
1866        let p = basepath.join(last).join(format!("{top_module}.tex"));
1867        if p.exists() {
1868            let rel_path = if path.is_empty() {
1869                format!("{top_module}.tex")
1870            } else {
1871                format!("{path}/{top_module}.tex")
1872            };
1873            return Some(ModuleReference {
1874                rel_path: Some(rel_path.into()),
1875                in_doc: uri.path_uri().clone() & (top_module.parse().ok()?, Language::English),
1876                full_path: Some(p.into()),
1877                uri,
1878            });
1879        }
1880
1881        let path_uri = uri.path_uri().clone().up();
1882
1883        let p = basepath.join(format!("{last}.{}.tex", self.language));
1884        if p.exists() {
1885            return Some(ModuleReference {
1886                uri,
1887                in_doc: path_uri & (last.parse().ok()?, self.language),
1888                rel_path: Some(format!("{path}.{}.tex", self.language).into()),
1889                full_path: Some(p.into()),
1890            });
1891        }
1892
1893        let p = basepath.join(format!("{last}.en.tex"));
1894        if p.exists() {
1895            return Some(ModuleReference {
1896                uri,
1897                in_doc: path_uri & (last.parse().ok()?, Language::English),
1898                rel_path: Some(format!("{path}.en.tex").into()),
1899                full_path: Some(p.into()),
1900            });
1901        }
1902
1903        let p = basepath.join(format!("{last}.tex"));
1904        if p.exists() {
1905            return Some(ModuleReference {
1906                uri,
1907                in_doc: path_uri & (last.parse().ok()?, Language::English),
1908                rel_path: Some(format!("{path}.tex").into()),
1909                full_path: Some(p.into()),
1910            });
1911        }
1912        None
1913    }
1914
1915    fn find_module(&self, m: &str) -> Option<(&ModuleUri, &ModuleRules<Pos>)> {
1916        'top: for (muri, rls) in &self.modules {
1917            let mut f_steps = m.split('/');
1918            let mut m_steps = muri.module_name().steps();
1919            loop {
1920                let Some(f) = f_steps.next() else {
1921                    if m_steps.next().is_none() {
1922                        return Some((muri, rls));
1923                    }
1924                    continue 'top;
1925                };
1926                let Some(m) = m_steps.next() else {
1927                    continue 'top;
1928                };
1929                if f != m {
1930                    continue 'top;
1931                }
1932            }
1933        }
1934        None
1935    }
1936}
1937
1938#[derive(Default)]
1939#[allow(clippy::large_enum_variant)]
1940pub enum GroupKind<Pos: SourcePos> {
1941    #[default]
1942    None,
1943    Problem,
1944    Module {
1945        uri: ModuleUri,
1946        rules: Vec<ModuleRule<Pos>>,
1947    },
1948    MathStructure {
1949        uri: ModuleUri,
1950        rules: Vec<ModuleRule<Pos>>,
1951    },
1952    ConservativeExt(ModuleUri, Vec<ModuleRule<Pos>>),
1953    DefPara(Vec<SymbolReference<Pos>>),
1954    Morphism {
1955        domain: ModuleOrStruct<Pos>,
1956        rules: Vec<ModuleRules<Pos>>,
1957        specs: VecMap<SymbolReference<Pos>, MorphismSpec<Pos>>,
1958    },
1959}
1960
1961#[derive(Clone, Debug, Default)]
1962pub struct MorphismSpec<Pos: SourcePos> {
1963    pub macroname: Option<Box<str>>,
1964    pub new_name: Option<UriName>,
1965    pub is_assigned_at: Option<SourceRange<Pos>>,
1966    pub decl_range: SourceRange<Pos>,
1967}
1968
1969#[derive(Debug, Clone, serde::Serialize)]
1970pub enum ModuleOrStruct<Pos: SourcePos> {
1971    Module(ModuleReference),
1972    Struct(SymbolReference<Pos>),
1973}
1974
1975#[non_exhaustive]
1976pub struct STeXGroup<
1977    'a,
1978    MS: STeXModuleStore,
1979    Pos: SourcePos + 'a,
1980    Err: FnMut(String, SourceRange<Pos>, DiagnosticLevel),
1981> {
1982    pub inner: Group<'a, ParseStr<'a, Pos>, STeXToken<Pos>, Err, STeXParseState<'a, Pos, MS>>,
1983    pub kind: GroupKind<Pos>,
1984    pub semantic_rules: Vec<SemanticRule<Pos>>,
1985    pub uses: VecSet<ModuleUri>,
1986}
1987
1988pub enum SemanticRule<Pos: SourcePos> {
1989    Symbol(SymbolRule<Pos>),
1990    Module(ModuleReference, ModuleRules<Pos>),
1991    Structure {
1992        symbol: SymbolRule<Pos>,
1993        //module_uri:ModuleUri,
1994        rules: ModuleRules<Pos>,
1995    },
1996    ConservativeExt(SymbolReference<Pos>, ModuleRules<Pos>),
1997    StructureImport(SymbolReference<Pos>, ModuleRules<Pos>),
1998}
1999
2000impl<
2001        'a,
2002        MS: STeXModuleStore,
2003        Pos: SourcePos + 'a,
2004        Err: FnMut(String, SourceRange<Pos>, DiagnosticLevel),
2005    > GroupState<'a, ParseStr<'a, Pos>, STeXToken<Pos>, Err, STeXParseState<'a, Pos, MS>>
2006    for STeXGroup<'a, MS, Pos, Err>
2007{
2008    #[inline]
2009    fn new(parent: Option<&mut Self>) -> Self {
2010        Self {
2011            inner: Group::new(parent.map(|p| &mut p.inner)),
2012            kind: GroupKind::None,
2013            semantic_rules: Vec::new(),
2014            uses: VecSet::default(),
2015        }
2016    }
2017
2018    #[inline]
2019    fn inner(
2020        &self,
2021    ) -> &Group<'a, ParseStr<'a, Pos>, STeXToken<Pos>, Err, STeXParseState<'a, Pos, MS>> {
2022        &self.inner
2023    }
2024    #[inline]
2025    fn inner_mut(
2026        &mut self,
2027    ) -> &mut Group<'a, ParseStr<'a, Pos>, STeXToken<Pos>, Err, STeXParseState<'a, Pos, MS>> {
2028        &mut self.inner
2029    }
2030    #[inline]
2031    fn close(
2032        self,
2033        parser: &mut LaTeXParser<
2034            'a,
2035            ParseStr<'a, Pos>,
2036            STeXToken<Pos>,
2037            Err,
2038            STeXParseState<'a, Pos, MS>,
2039        >,
2040    ) {
2041        self.inner.close(parser);
2042    }
2043    #[inline]
2044    fn add_macro_rule(
2045        &mut self,
2046        name: Cow<'a, str>,
2047        old: Option<
2048            AnyMacro<'a, ParseStr<'a, Pos>, STeXToken<Pos>, Err, STeXParseState<'a, Pos, MS>>,
2049        >,
2050    ) {
2051        self.inner.add_macro_rule(name, old);
2052    }
2053    #[inline]
2054    fn add_environment_rule(
2055        &mut self,
2056        name: Cow<'a, str>,
2057        old: Option<
2058            AnyEnv<'a, ParseStr<'a, Pos>, STeXToken<Pos>, Err, STeXParseState<'a, Pos, MS>>,
2059        >,
2060    ) {
2061        self.inner.add_environment_rule(name, old);
2062    }
2063    #[inline]
2064    fn letter_change(&mut self, old: &str) {
2065        self.inner.letter_change(old);
2066    }
2067}
2068
2069#[derive(Clone, Debug)]
2070pub enum MacroArg<Pos: SourcePos> {
2071    Symbol(SymbolReference<Pos>, u8),
2072    Variable(UriName, SourceRange<Pos>, bool, u8),
2073}
2074
2075impl<
2076        'a,
2077        MS: STeXModuleStore,
2078        Pos: SourcePos + 'a,
2079        Err: FnMut(String, SourceRange<Pos>, DiagnosticLevel),
2080    > ParserState<'a, ParseStr<'a, Pos>, STeXToken<Pos>, Err> for STeXParseState<'a, Pos, MS>
2081{
2082    type Group = STeXGroup<'a, MS, Pos, Err>;
2083    type MacroArg = MacroArg<Pos>;
2084}