Skip to main content

flams_stex/quickparse/stex/
structs.rs

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