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