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