Skip to main content

flams_stex/quickparse/stex/
rules.rs

1#![allow(clippy::ref_option)]
2#![allow(clippy::case_sensitive_file_extension_comparisons)]
3#![allow(clippy::cast_possible_truncation)]
4#![allow(unused_variables)]
5#![allow(clippy::needless_pass_by_value)]
6
7use crate::{
8    quickparse::{
9        latex::{
10            Environment, KeyValKind, LaTeXParser, Macro, ParsedKeyValue,
11            rules::{
12                AnyMacro, DynMacro, EnvironmentResult, EnvironmentRule, MacroResult, MacroRule,
13            },
14        },
15        stex::structs::MorphismKind,
16        tokenizer::TeXTokenizer,
17    },
18    tex,
19};
20use flams_math_archives::{
21    MathArchive,
22    backend::{GlobalBackend, LocalBackend},
23};
24use flams_utils::parsing::SourceParser;
25use flams_utils::{
26    CondSerialize, impossible,
27    sourcerefs::{LSPLineCol, StringPosition, StringRange},
28    vecmap::VecMap,
29};
30use ftml_ontology::narrative::elements::paragraphs::ParagraphKind;
31use ftml_uris::{
32    ArchiveId, DocumentUri, IsNarrativeUri, Language, ModuleUri, SymbolUri, UriName,
33    UriWithArchive, UriWithPath,
34};
35use smallvec::SmallVec;
36use std::{borrow::Cow, path::Path};
37
38use super::{
39    DiagnosticLevel,
40    structs::{
41        GroupKind, InlineMorphAssKind, InlineMorphAssign, MacroArg, ModuleOrStruct,
42        ModuleReference, ModuleRule, ModuleRules, MorphismSpec, STeXGroup, STeXModuleStore,
43        STeXParseState, STeXToken, SymbolReference, SymbolRule,
44    },
45};
46
47#[must_use]
48#[allow(clippy::type_complexity)]
49pub fn all_rules<'a, MS: STeXModuleStore>() -> [(
50    &'static str,
51    MacroRule<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
52); 47] {
53    [
54        ("importmodule", importmodule as _),
55        ("setmetatheory", setmetatheory as _),
56        ("usemodule", usemodule as _),
57        ("requiremodule", usemodule as _),
58        ("usestructure", usestructure as _),
59        ("inputref", inputref as _),
60        ("includeproblem", includeproblem as _),
61        ("mhinput", mhinput as _),
62        ("mhgraphics", mhgraphics as _),
63        ("cmhgraphics", mhgraphics as _),
64        ("stexstyleassertion", stexstyleassertion as _),
65        ("stexstyledefinition", stexstyledefinition as _),
66        ("stexstyleparagraph", stexstyleparagraph as _),
67        ("symdecl", symdecl as _),
68        ("textsymdecl", textsymdecl as _),
69        ("symdef", symdef as _),
70        ("vardef", vardef as _),
71        ("newvar", newvar as _),
72        ("varseq", varseq as _),
73        ("newseq", newseq as _),
74        ("symref", symref as _),
75        ("sr", symref as _),
76        ("symname", symname as _),
77        ("sn", symname as _),
78        ("Symname", Symname as _),
79        ("Sn", Symname as _),
80        ("sns", symnames as _),
81        ("Sns", Symnames as _),
82        ("symuse", symuse as _),
83        ("svar", svar as _),
84        ("notation", notation as _),
85        ("definame", defi_only as _),
86        ("Definame", defi_only as _),
87        ("definames", defi_only as _),
88        ("Definames", defi_only as _),
89        ("definiendum", defi_only as _),
90        ("definiens", defi_only as _),
91        ("defnotation", defi_only as _),
92        ("inlinedef", inlinedef as _),
93        ("inlineass", inlineass as _),
94        ("inlinepara", inlinepara as _),
95        ("inlineex", inlineex as _),
96        ("copymod", copymod as _),
97        ("interpretmod", interpretmod as _),
98        ("precondition", precondition as _),
99        ("objective", objective as _),
100        ("sref", sref as _),
101    ]
102}
103
104#[must_use]
105#[allow(clippy::type_complexity)]
106pub fn declarative_rules<'a, MS: STeXModuleStore>() -> [(
107    &'static str,
108    MacroRule<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
109); 14] {
110    [
111        ("importmodule", importmodule as _),
112        ("setmetatheory", setmetatheory as _),
113        ("stexstyleassertion", stexstyleassertion as _),
114        ("stexstyledefinition", stexstyledefinition as _),
115        ("stexstyleparagraph", stexstyleparagraph as _),
116        ("symdecl", symdecl as _),
117        ("textsymdecl", textsymdecl as _),
118        ("symdef", symdef as _),
119        ("inlinedef", inlinedef as _),
120        ("inlineass", inlineass as _),
121        ("inlinepara", inlinepara as _),
122        ("inlineex", inlineex as _),
123        ("copymod", copymod as _),
124        ("interpretmod", interpretmod as _),
125    ]
126}
127
128#[must_use]
129#[allow(clippy::type_complexity)]
130pub fn all_env_rules<'a, MS: STeXModuleStore>() -> [(
131    &'static str,
132    EnvironmentRule<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
133); 16] {
134    [
135        ("smodule", (smodule_open as _, smodule_close as _)),
136        (
137            "mathstructure",
138            (mathstructure_open as _, mathstructure_close as _),
139        ),
140        (
141            "extstructure",
142            (extstructure_open as _, extstructure_close as _),
143        ),
144        (
145            "extstructure*",
146            (extstructure_ast_open as _, extstructure_ast_close as _),
147        ),
148        ("sassertion", (sassertion_open as _, sassertion_close as _)),
149        (
150            "sdefinition",
151            (sdefinition_open as _, sdefinition_close as _),
152        ),
153        ("sparagraph", (sparagraph_open as _, sparagraph_close as _)),
154        ("sexample", (sexample_open as _, sexample_close as _)),
155        (
156            "ndefinition",
157            (sdefinition_open as _, sdefinition_close as _),
158        ),
159        ("nparagraph", (sparagraph_open as _, sparagraph_close as _)),
160        ("copymodule", (copymodule_open as _, copymodule_close as _)),
161        (
162            "copymodule*",
163            (copymodule_ast_open as _, copymodule_ast_close as _),
164        ),
165        (
166            "interpretmodule",
167            (interpretmodule_open as _, interpretmodule_close as _),
168        ),
169        (
170            "interpretmodule*",
171            (
172                interpretmodule_ast_open as _,
173                interpretmodule_ast_close as _,
174            ),
175        ),
176        ("sproblem", (sproblem_open as _, sproblem_close as _)),
177        ("subproblem", (subproblem_open as _, subproblem_close as _)),
178    ]
179}
180
181#[must_use]
182#[allow(clippy::type_complexity)]
183pub fn declarative_env_rules<'a, MS: STeXModuleStore>() -> [(
184    &'static str,
185    EnvironmentRule<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
186); 12] {
187    [
188        ("smodule", (smodule_open as _, smodule_close as _)),
189        (
190            "mathstructure",
191            (mathstructure_open as _, mathstructure_close as _),
192        ),
193        (
194            "extstructure",
195            (extstructure_open as _, extstructure_close as _),
196        ),
197        (
198            "extstructure*",
199            (extstructure_ast_open as _, extstructure_ast_close as _),
200        ),
201        ("sassertion", (sassertion_open as _, sassertion_close as _)),
202        (
203            "sdefinition",
204            (sdefinition_open as _, sdefinition_close as _),
205        ),
206        ("sparagraph", (sparagraph_open as _, sparagraph_close as _)),
207        ("sexample", (sexample_open as _, sexample_close as _)),
208        ("copymodule", (copymodule_open as _, copymodule_close as _)),
209        (
210            "copymodule*",
211            (copymodule_ast_open as _, copymodule_ast_close as _),
212        ),
213        (
214            "interpretmodule",
215            (interpretmodule_open as _, interpretmodule_close as _),
216        ),
217        (
218            "interpretmodule*",
219            (
220                interpretmodule_ast_open as _,
221                interpretmodule_ast_close as _,
222            ),
223        ),
224    ]
225}
226
227macro_rules! stex {
228  ($p:ident => @begin $($stuff:tt)+) => {
229    tex!(<{'a,Pos:StringPosition,MS:STeXModuleStore} E{'a,Pos,STeXToken<Pos>} P{'a,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>} R{'a,Pos,STeXToken<Pos>}>
230      $p => @begin $($stuff)*
231    );
232  };
233  ($p:ident => $($stuff:tt)+) => {
234    tex!(<{'a,Pos:StringPosition,MS:STeXModuleStore} M{'a,Pos} P{'a,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>} R{'a,Pos,STeXToken<Pos>}>
235      $p => $($stuff)*
236    );
237  };
238  (LSP: $p:ident => @begin $($stuff:tt)+) => {
239    tex!(<{'a,MS:STeXModuleStore} E{'a,LSPLineCol,STeXToken<LSPLineCol>} P{'a,LSPLineCol,STeXToken<LSPLineCol>,STeXParseState<'a,LSPLineCol,MS>} R{'a,LSPLineCol,STeXToken<LSPLineCol>}>
240      $p => @begin $($stuff)*
241    );
242  };
243  (LSP: $p:ident => $($stuff:tt)+) => {
244    tex!(<{'a,MS:STeXModuleStore} M{'a,LSPLineCol} P{'a,LSPLineCol,STeXToken<LSPLineCol>,STeXParseState<'a,LSPLineCol,MS>} R{'a,LSPLineCol,STeXToken<LSPLineCol>}>
245      $p => $($stuff)*
246    );
247  };
248}
249
250fn parse_id<'a, P: StringPosition>(
251    id: &str,
252    pos: P,
253    tkn: &mut TeXTokenizer<'a, P>,
254) -> Option<ArchiveId> {
255    match ArchiveId::new(id) {
256        Ok(id) => Some(id),
257        Err(e) => {
258            tkn.problem(
259                pos,
260                format_args!("Invalid Archive Id {id}: {e}"),
261                DiagnosticLevel::Error,
262            );
263            None
264        }
265    }
266}
267
268stex!(LSP: p => importmodule[archive:str]{module:name} => {
269  let (archive,archive_range) = archive.map_or((None,None),|(a,r)| (
270      parse_id(a,importmodule.range.start,&mut p.tokenizer),
271      Some(r)
272  ));
273  if let Some(r) = p.state.resolve_module(module.0, archive) {
274    let path = p.state.in_path.as_ref().expect("this is a bug");
275    let (state,groups) = p.split();
276    state.add_import(&r, groups,importmodule.range);
277    MacroResult::Success(STeXToken::ImportModule {
278      archive_range, path_range:module.1,module:r,
279      full_range:importmodule.range, token_range:importmodule.token_range
280    })
281  } else {
282    p.tokenizer.problem(importmodule.range.start, format!("Module {} not found",module.0),DiagnosticLevel::Error);
283    MacroResult::Simple(importmodule)
284  }
285});
286
287stex!(p => importmodule_deps[archive:str]{module:name} => {
288    let (archive,archive_range) = archive.map_or((None,None),|(a,r)| (
289        parse_id(a,importmodule_deps.range.start,&mut p.tokenizer),
290        Some(r)
291    ));
292
293    if let Some(r) = p.state.resolve_module(module.0, archive) {
294      MacroResult::Success(STeXToken::ImportModule {
295        archive_range, path_range:module.1,module:r,
296        full_range:importmodule_deps.range, token_range:importmodule_deps.token_range
297      })
298    } else {
299      p.tokenizer.problem(importmodule_deps.range.start, format!("Module {} not found",module.0),DiagnosticLevel::Error);
300      MacroResult::Simple(importmodule_deps)
301    }
302});
303
304stex!(LSP:p => usemodule[archive:str]{module:name} => {
305    let (archive,archive_range) = archive.map_or((None,None),|(a,r)| (
306        parse_id(a,usemodule.range.start,&mut p.tokenizer),
307        Some(r)
308    ));
309      if let Some(r) = p.state.resolve_module(module.0, archive) {
310        let (state,groups) = p.split();
311        state.add_use(&r, groups,usemodule.range);
312        MacroResult::Success(STeXToken::UseModule {
313          archive_range, path_range:module.1,module:r,
314          full_range:usemodule.range, token_range:usemodule.token_range
315        })
316      } else {
317        p.tokenizer.problem(usemodule.range.start, format!("Module {} not found",module.0),DiagnosticLevel::Error);
318        MacroResult::Simple(usemodule)
319      }
320  }
321);
322
323stex!(LSP:p => usestructure{exts:!name} => {
324  let (state,mut groups) = p.split();
325  let Some((sym,rules)) = state.get_structure(&groups,&exts.0) else {
326    groups.tokenizer.problem(exts.1.start, format!("Unknown structure {}",exts.0),DiagnosticLevel::Error);
327    return MacroResult::Simple(usestructure)
328  };
329  state.use_structure(&sym,&rules,&mut groups,usestructure.range);
330  MacroResult::Success(STeXToken::UseStructure {
331    structure:sym,structure_range:exts.1,
332    full_range:usestructure.range, token_range:usestructure.token_range
333  })
334}
335);
336
337stex!(p => usemodule_deps[archive:str]{module:name} => {
338    let (archive,archive_range) = archive.map_or((None,None),|(a,r)| (
339        parse_id(a,usemodule_deps.range.start,&mut p.tokenizer),
340        Some(r)
341    ));
342      if let Some(r) = p.state.resolve_module(module.0, archive) {
343        MacroResult::Success(STeXToken::UseModule {
344          archive_range, path_range:module.1,module:r,
345          full_range:usemodule_deps.range,token_range:usemodule_deps.token_range
346        })
347      } else {
348        p.tokenizer.problem(usemodule_deps.range.start, format!("Module {} not found",module.0),DiagnosticLevel::Error);
349        MacroResult::Simple(usemodule_deps)
350      }
351  }
352);
353
354stex!(p => setmetatheory[archive:str]{module:name} => {
355    let (archive,archive_range) = archive.map_or((None,None),|(a,r)| (
356        parse_id(a,setmetatheory.range.start,&mut p.tokenizer),
357        Some(r)
358    ));
359      if let Some(r) = p.state.resolve_module(module.0, archive) {
360        MacroResult::Success(STeXToken::SetMetatheory {
361          archive_range, path_range:module.1,module:r,
362          full_range:setmetatheory.range, token_range:setmetatheory.token_range
363        })
364      } else {
365        p.tokenizer.problem(setmetatheory.range.start, format!("Module {} not found",module.0),DiagnosticLevel::Error);
366        MacroResult::Simple(setmetatheory)
367      }
368  }
369);
370
371stex!(p => stexstyleassertion[_]{_}{_}!);
372stex!(p => stexstyledefinition[_]{_}{_}!);
373stex!(p => stexstyleparagraph[_]{_}{_}!);
374
375stex!(p => inputref('*'?_s)[archive:str]{filepath:name} => {
376    let archive = archive.and_then(|(a,r)|
377        parse_id(a,inputref.range.start,&mut p.tokenizer).map(|a| (a,r))
378    );
379      let rel_path: std::sync::Arc<str> = if filepath.0.ends_with(".tex") {
380        filepath.0.into()
381      } else {
382        format!("{}.tex",filepath.0).into()
383      };
384      {
385          if let Some(id) = archive.as_ref().map_or_else(||
386              p.state.archive.as_ref().map(|a| a.archive_id()),
387              |(a,_)| Some(a)
388          ) {
389              p.state.backend.with_local_archive(id,|a|
390                  if let Some(a) = a {
391                      let path = a.source_dir();
392                      let path = rel_path.as_ref().split('/').fold(path,|p,s| p.join(s));
393                      if !path.exists() {
394                          p.tokenizer.problem(filepath.1.start,format!("File {} not found",path.display()),DiagnosticLevel::Error);
395                      }
396                  }
397              );
398          }
399      }
400      let filepath = (rel_path,filepath.1);
401      MacroResult::Success(STeXToken::Inputref {
402        archive, filepath,full_range:inputref.range,
403        token_range:inputref.token_range
404      })
405    }
406);
407
408stex!(p => mhinput[archive:str]{filepath:name} => {
409    let archive = archive.and_then(|(a,r)|
410        parse_id(a,mhinput.range.start,&mut p.tokenizer).map(|a| (a,r))
411    );
412      let rel_path: std::sync::Arc<str> = if filepath.0.ends_with(".tex") {
413        filepath.0.into()
414      } else {
415        format!("{}.tex",filepath.0).into()
416      };
417      {
418          if let Some(id) = archive.as_ref().map_or_else(||
419              p.state.archive.as_ref().map(|a| a.archive_id()),
420              |(a,_)| Some(a)
421          ) {
422              p.state.backend.with_local_archive(id,|a|
423                  if let Some(a) = a {
424                      let path = a.source_dir();
425                      let path = rel_path.as_ref().split('/').fold(path,|p,s| p.join(s));
426                      if !path.exists() {
427                          p.tokenizer.problem(filepath.1.start,format!("File {} not found",path.display()),DiagnosticLevel::Error);
428                      }
429                  }
430              );
431          }
432      }
433      let filepath = (rel_path,filepath.1);
434      MacroResult::Success(STeXToken::MHInput {
435        archive, filepath,full_range:mhinput.range,
436        token_range:mhinput.token_range
437      })
438    }
439);
440
441fn strip_comments(s: &str) -> Cow<'_, str> {
442    s.find('%').map_or(Cow::Borrowed(s), |i| {
443        let rest = &s[i..];
444        rest.find("\r\n")
445            .or_else(|| rest.find('\n'))
446            .or_else(|| rest.find('\r'))
447            .map_or_else(
448                || Cow::Borrowed(&s[..i]),
449                |j| {
450                    let r = strip_comments(&rest[j..]);
451                    if r.is_empty() {
452                        Cow::Borrowed(&s[..i])
453                    } else {
454                        Cow::Owned(format!("{}{}", &s[..i], r))
455                    }
456                },
457            )
458    })
459}
460
461macro_rules! optargtype {
462  ($parser:ident => $name:ident { $( {$fieldname:ident = $id:literal : $($tp:tt)+} )* $(_ = $default:ident)? }) => {
463    #[derive(serde::Serialize)]
464    pub enum $name<Pos:StringPosition> {
465      $(
466        $fieldname(ParsedKeyValue<Pos,optargtype!(@TYPE $($tp)*)>)
467      ),*
468      $(, $default(StringRange<Pos>,Box<str>))?
469    }
470    impl<Pos:StringPosition> std::fmt::Debug for $name<Pos> {
471      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
472        f.write_str(stringify!($name))
473      }
474    }
475    impl<Pos:StringPosition> Clone for $name<Pos> {
476      fn clone(&self) -> Self {
477        match self {
478          $(
479            Self::$fieldname(v) => Self::$fieldname(v.clone())
480          ),*
481        }
482      }
483    }
484    impl<'a,Pos:StringPosition,MS:STeXModuleStore>
485      KeyValKind<'a,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>> for $name<Pos> {
486        fn next_val(
487          $parser:&mut crate::quickparse::latex::KeyValParser<'a, '_,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>>,
488          key:&str
489        ) -> Option<Self> {
490          #[allow(unused_imports)]
491          use super::super::latex::KeyValParsable;
492          match key {
493            $(
494              $id => optargtype!(@PARSE $parser $fieldname $($tp)*),
495            )*
496            _ => optargtype!(@DEFAULT $($parser $default)?)
497          }
498        }
499    }
500  };
501  ($parser:ident => $name:ident <T> { $( {$fieldname:ident = $id:literal : $($tp:tt)+} )* $(_ = $default:ident)? } @ $iter:ident) => {
502    #[derive(serde::Serialize)]
503    pub enum $name<Pos:StringPosition,T:CondSerialize> {
504      $(
505        $fieldname(ParsedKeyValue<Pos,optargtype!(@TYPE T $($tp)*)>)
506      ),*
507      $(, $default(StringRange<Pos>,Box<str>))?
508    }
509    impl<Pos:StringPosition,T:CondSerialize> std::fmt::Debug for $name<Pos,T> {
510      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
511        f.write_str(stringify!($name))
512      }
513    }
514    impl<Pos:StringPosition,T:Clone+CondSerialize> Clone for $name<Pos,T> {
515      fn clone(&self) -> Self {
516        match self {
517          $(
518            Self::$fieldname(v) => Self::$fieldname(v.clone())
519          ),*
520          $(,
521            Self::$default(r,s) => Self::$default(*r,s.clone())
522          )?
523        }
524      }
525    }
526
527    impl<'a,Pos:StringPosition,MS:STeXModuleStore>
528      KeyValKind<'a,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>> for $name<Pos,STeXToken<Pos>> {
529        fn next_val(
530          $parser:&mut crate::quickparse::latex::KeyValParser<'a, '_,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>>,
531          key:&str
532        ) -> Option<Self> {
533            #[allow(unused_imports)]
534          use super::super::latex::KeyValParsable;
535          match key {
536            $(
537              $id => optargtype!(@PARSE+ $parser $fieldname $($tp)*),
538            )*
539            _ => optargtype!(@DEFAULT $($parser $default)?)
540          }
541        }
542    }
543
544    impl<Pos:StringPosition,T1:CondSerialize> $name<Pos,T1> {
545      pub fn into_other<T2:CondSerialize>(self,mut cont:impl FnMut(Vec<T1>) -> Vec<T2>) -> $name<Pos,T2> {
546        match self {
547          $(
548            $name::$fieldname(val) => optargtype!(@TRANSLATE val cont $name $fieldname $($tp)*)
549          ),*
550          $(, $name::$default(range,name) => $name::$default(range,name))?
551        }
552      }
553    }
554
555    pub struct $iter<'a,Pos:StringPosition,T:CondSerialize>{
556      current:Option<std::slice::Iter<'a,T>>,
557      nexts:std::slice::Iter<'a,$name<Pos,T>>
558    }
559    impl<'a,Pos:StringPosition,T:CondSerialize> $iter<'a,Pos,T> {
560      pub fn new(sn:&'a[$name<Pos,T>]) -> Self {
561        Self { current:None,nexts:sn.iter()}
562      }
563    }
564    impl<'a,Pos:StringPosition,T:CondSerialize> Iterator for $iter<'a,Pos,T> {
565      type Item = &'a T;
566      fn next(&mut self) -> Option<Self::Item> {
567          if let Some(c) = &mut self.current {
568            if let Some(n) = c.next() { return Some(n)}
569          }
570          loop {
571            let Some(n) = self.nexts.next() else {return None};
572            match n {
573              optargtype!(@DOITER e $name {} {$($fieldname $($tp)*; )*}) => {
574                let mut next = e.val.iter();
575                if let Some(n) = next.next() {
576                  self.current = Some(next);
577                  return Some(n)
578                }
579              }
580              _ => ()
581            }
582          }
583      }
584    }
585  };
586  (LSP $parser:ident => $name:ident <T> { $( {$fieldname:ident = $id:literal : $($tp:tt)+} )* $(_ = $default:ident)? } @ $iter:ident) => {
587
588    #[derive(serde::Serialize)]
589    pub enum $name<Pos:StringPosition,T:CondSerialize> {
590      $(
591        $fieldname(ParsedKeyValue<Pos,optargtype!(@TYPE T $($tp)*)>)
592      ),*
593      $(, $default(StringRange<Pos>,Box<str>))?
594    }
595    impl<Pos:StringPosition,T:CondSerialize> std::fmt::Debug for $name<Pos,T> {
596      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
597        f.write_str(stringify!($name))
598      }
599    }
600    impl<Pos:StringPosition,T:Clone+CondSerialize> Clone for $name<Pos,T> {
601      fn clone(&self) -> Self {
602        match self {
603          $(
604            Self::$fieldname(v) => Self::$fieldname(v.clone())
605          ),*
606          $(,
607            Self::$default(r,s) => Self::$default(*r,s.clone())
608          )?
609        }
610      }
611    }
612
613    impl<'a,MS:STeXModuleStore>
614      KeyValKind<'a,LSPLineCol,STeXToken<LSPLineCol>,STeXParseState<'a,LSPLineCol,MS>> for $name<LSPLineCol,STeXToken<LSPLineCol>> {
615        fn next_val(
616          $parser:&mut crate::quickparse::latex::KeyValParser<'a, '_,LSPLineCol,STeXToken<LSPLineCol>,STeXParseState<'a,LSPLineCol,MS>>,
617          key:&str
618        ) -> Option<Self> {
619            #[allow(unused_imports)]
620          use super::super::latex::KeyValParsable;
621          match key {
622            $(
623              $id => optargtype!(@PARSE+ $parser $fieldname $($tp)*),
624            )*
625            _ => optargtype!(@DEFAULT $($parser $default)?)
626          }
627        }
628    }
629
630    impl<T1:CondSerialize> $name<LSPLineCol,T1> {
631      pub fn into_other<T2:CondSerialize>(self,mut cont:impl FnMut(Vec<T1>) -> Vec<T2>) -> $name<LSPLineCol,T2> {
632        match self {
633          $(
634            $name::$fieldname(val) => optargtype!(@TRANSLATE val cont $name $fieldname $($tp)*)
635          ),*
636          $(, $name::$default(range,name) => $name::$default(range,name))?
637        }
638      }
639    }
640
641    pub struct $iter<'a,T:CondSerialize>{
642      current:Option<std::slice::Iter<'a,T>>,
643      nexts:std::slice::Iter<'a,$name<LSPLineCol,T>>
644    }
645    impl<'a,T:CondSerialize> $iter<'a,T> {
646      pub fn new(sn:&'a[$name<LSPLineCol,T>]) -> Self {
647        Self { current:None,nexts:sn.iter()}
648      }
649    }
650    impl<'a,T:CondSerialize> Iterator for $iter<'a,T> {
651      type Item = &'a T;
652      fn next(&mut self) -> Option<Self::Item> {
653          if let Some(c) = &mut self.current {
654            if let Some(n) = c.next() { return Some(n)}
655          }
656          loop {
657            let Some(n) = self.nexts.next() else {return None};
658            match n {
659              optargtype!(@DOITER e $name {} {$($fieldname $($tp)*; )*}) => {
660                let mut next = e.val.iter();
661                if let Some(n) = next.next() {
662                  self.current = Some(next);
663                  return Some(n)
664                }
665              }
666              _ => ()
667            }
668          }
669      }
670    }
671  };
672  (@DEFAULT ) => { None };
673  (@DEFAULT $parser:ident $default:ident) => {
674    if $parser.has_value {
675      $parser.skip_value();
676      $parser.problem("Invalid value",DiagnosticLevel::Error);
677      None
678    } else {
679      Some(Self::$default($parser.key_range,$parser.key.to_string().into()))
680    }
681  };
682
683  (@DOITER $e:ident $name:ident {$($tks:tt)*} {} ) => {$($tks)*};
684
685  (@TYPE $(T)? str) => {Box<str>};
686  (@PARSE $(+)? $parser:ident $fieldname:ident str ) => {$parser.parse().map(Self::$fieldname)};
687  (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident str) => {
688    $name::$fieldname($val)
689  };
690  (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident str; $($rest:tt)* }) => {
691    optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
692  };
693
694  (@TYPE $(T)? ()) => {()};
695  (@PARSE $(+)? $parser:ident $fieldname:ident () ) => {$parser.parse().map(Self::$fieldname)};
696  (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident ()) => {
697    $name::$fieldname($val)
698  };
699  (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident (); $($rest:tt)* }) => {
700    optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
701  };
702
703  (@TYPE $(T)? Language) => {Language};
704  (@PARSE $(+)? $parser:ident $fieldname:ident Language ) => {$parser.parse().map(Self::$fieldname)};
705  (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident Language) => {
706    $name::$fieldname($val)
707  };
708  (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident Language; $($rest:tt)* }) => {
709    optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
710  };
711
712  (@TYPE $(T)? f32) => {f32};
713  (@PARSE $(+)? $parser:ident $fieldname:ident f32 ) => {$parser.parse().map(Self::$fieldname)};
714  (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident f32) => {
715    $name::$fieldname($val)
716  };
717  (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident f32; $($rest:tt)* }) => {
718    optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
719  };
720
721  (@TYPE $(T)? bool?) => {bool};
722  (@PARSE $(+)? $parser:ident $fieldname:ident bool? ) => {
723    if $parser.has_value {$parser.parse().map(Self::$fieldname)} else { Some(Self::$fieldname(
724      ParsedKeyValue{key_range:$parser.key_range,val_range:StringRange{start:$parser.start,end:$parser.start},val:true}
725    )) }
726  };
727  (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident bool?) => {
728    $name::$fieldname($val)
729  };
730  (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident bool?; $($rest:tt)* }) => {
731    optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
732  };
733
734  (@TYPE $(T)? !) => {()};
735  (@PARSE $(+)? $parser:ident $fieldname:ident ! ) => {{
736    if $parser.has_value {
737      $parser.problem("Invalid value",DiagnosticLevel::Error);
738    }
739    $parser.parse().map(Self::$fieldname)
740  }};
741  (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident !) => {
742    $name::$fieldname($val)
743  };
744  (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident !; $($rest:tt)* }) => {
745    optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
746  };
747
748  (@TYPE T T*) => {Vec<T>};
749  (@PARSE+ $parser:ident $fieldname:ident T* ) => {$parser.parse().map(Self::$fieldname)};
750  (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident T*) => {
751    $name::$fieldname(ParsedKeyValue{key_range:$val.key_range,val_range:$val.val_range,val:$cont($val.val)})
752  };
753  (@DOITER $e:ident $name:ident {} {$fieldname:ident T*; $($rest:tt)* }) => {
754    optargtype!(@DOITER $e $name {$name::$fieldname($e)} { $($rest)* })
755  };
756  (@DOITER $e:ident $name:ident {$($tks:tt)+} {$fieldname:ident T*; $($rest:tt)* }) => {
757    optargtype!(@DOITER $e $name {$($tks)* | $name::$fieldname($e)} { $($rest)* })
758  };
759
760  (@TYPE $(T)? Args) => {u8};
761  (@PARSE $(+)? $parser:ident $fieldname:ident Args) => {{
762    let Some(s) = $parser.read_value_str_normalized() else {
763      $parser.problem("Missing value for args",DiagnosticLevel::Error);
764      return None
765    };
766    if s.bytes().all(|b| b.is_ascii_digit()) && s.len() == 1 {
767      let arg:u8 = s.parse().unwrap_or_else(|_| unreachable!());
768      Some(Self::Args($parser.to_key_value(arg)))
769    } else if s.bytes().all(|b| b == b'i' || b == b'a' || b == b'b' || b == b'B') {
770      if s.len() > 9 {
771        $parser.problem("Too many arguments",DiagnosticLevel::Error);
772        None
773      } else {
774        Some(Self::Args($parser.to_key_value(s.len() as u8)))
775      }
776    } else {
777      $parser.problem(format!("Invalid args value: >{s}<"),DiagnosticLevel::Error);
778      None
779    }
780  }};
781  (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident Args) => {
782    $name::$fieldname($val)
783  };
784  (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident Args; $($rest:tt)* }) => {
785    optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
786  };
787
788  (@TYPE $(T)? { $tp:ty => $($r:tt)*}) => {$tp};
789  (@PARSE $(+)? $parser:ident $fieldname:ident { $tp:ty => $($r:tt)*}) => {{$($r)*}};
790  (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident { $tp:ty => $($r:tt)*}) => {
791    $name::$fieldname($val)
792  };
793  (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident { $tp:ty => $($r:tt)*}; $($rest:tt)* }) => {
794    optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
795  };
796}
797
798optargtype! {parser =>
799    SRefOptsA<T> {
800        {Archive = "archive": str}
801        {File = "file": str}
802        {Fallback = "fallback": T*}
803        {Pre = "pre": ()}
804        {Post = "post": ()}
805    } @ SRefOptsAIter
806}
807optargtype! {parser =>
808    SRefOptsB<T> {
809        {Archive = "archive": str}
810        {File = "file": str}
811        {Title = "title": T*}
812    } @ SRefOptsBIter
813}
814
815stex!(p => sref[args_a:type SRefOptsA<Pos, STeXToken<Pos>>]{label:name}[args_b:type SRefOptsB<Pos, STeXToken<Pos>>] => {
816    let args_a = args_a.unwrap_or_default();
817    let args_b = args_b.unwrap_or_default();
818    let archive = args_a.iter().find_map(|p| if let SRefOptsA::Archive(a) = p {Some(a)} else {None})
819        .and_then(|pair|
820            parse_id(&pair.val,pair.key_range.start,&mut p.tokenizer)
821        );
822    let rel_path: Option<&str> = args_a.iter().find_map(|p|
823        if let SRefOptsA::File(f) = p {Some(&*f.val)} else {None}
824    );
825    let in_archive = args_b.iter().find_map(|p| if let SRefOptsB::Archive(a) = p {Some(a)} else {None})
826        .and_then(|pair|
827        parse_id(&pair.val,pair.key_range.start,&mut p.tokenizer)
828        );
829    let in_rel_path: Option<&str> = args_b.iter().find_map(|p|
830        if let SRefOptsB::File(f) = p {Some(&*f.val)} else {None}
831    );
832
833    let (doc_uri,target_path):(DocumentUri,std::sync::Arc<Path>) = if let Some(rp) = rel_path {
834        if let Some(uri) = parse_doc_ref(p,archive.as_ref(),&rp,sref.token_range.end) {
835            uri
836        } else {
837            return MacroResult::Simple(sref);
838        }
839    } else if let Some(rp) = &p.state.in_path{
840        (p.state.doc_uri.clone(),rp.clone())
841    } else {
842        p.tokenizer
843            .problem(sref.range.start, "file not found", DiagnosticLevel::Error);
844        return MacroResult::Simple(sref);
845    };
846    let target_uri = doc_uri & {
847        if let Ok(l) = label.0.parse::<UriName>() {
848            l
849        } else {
850            p.tokenizer.problem(sref.range.start, format_args!("invalid label name {}",label.0), DiagnosticLevel::Error);
851            return MacroResult::Simple(sref);
852        }
853    };
854    let in_doc_uri = if let Some(rp) = &in_rel_path {
855        if let Some(uri) = parse_doc_ref(p,in_archive.as_ref(),rp,label.1.end) {
856            Some(uri)
857        } else {
858            return MacroResult::Simple(sref);
859        }
860    } else {None};
861    MacroResult::Success(STeXToken::SRef {
862        full_range: sref.range,
863        token_range: sref.token_range,
864        opt_args: args_a,
865        label_range: label.1,
866        target_path,
867        in_opt_args: args_b,
868        target: target_uri,
869        in_doc: in_doc_uri
870    })
871});
872
873fn parse_doc_ref<'a, Pos: StringPosition, MS: STeXModuleStore>(
874    p: &mut crate::quickparse::latex::LaTeXParser<
875        'a,
876        Pos,
877        STeXToken<Pos>,
878        STeXParseState<'a, Pos, MS>,
879    >,
880    archive: Option<&ArchiveId>,
881    relpath: &str,
882    errpos: Pos,
883) -> Option<(DocumentUri, std::sync::Arc<Path>)> {
884    let (archive_uri, mut path) = if let Some(a) = archive {
885        if let Some(uri) = p.state.backend.with_local_archive(a, |a| {
886            a.map(|a| (a.uri().clone(), a.source_dir().join(relpath)))
887        }) {
888            uri
889        } else {
890            p.tokenizer.problem(
891                errpos,
892                format_args!("Unknown archive {a}"),
893                DiagnosticLevel::Error,
894            );
895            return None;
896        }
897    } else if let Some(a) = p.state.archive
898        && let Some(pth) = &p.state.in_path
899    {
900        (a.clone(), {
901            let mut np = &**pth;
902            while !np.ends_with("source") {
903                let Some(par) = np.parent() else {
904                    p.tokenizer
905                        .problem(errpos, "file not found", DiagnosticLevel::Error);
906                    return None;
907                };
908                np = par;
909            }
910            np.join(relpath)
911        })
912    } else {
913        p.tokenizer
914            .problem(errpos, "archive missing", DiagnosticLevel::Error);
915        return None;
916    };
917    path.add_extension("tex");
918    if let Ok(u) = DocumentUri::from_archive_relpath(archive_uri, &format!("{relpath}.tex")) {
919        Some((u, path.into()))
920    } else {
921        p.tokenizer.problem(
922            errpos,
923            format_args!("invalid document path {relpath}"),
924            DiagnosticLevel::Error,
925        );
926        None
927    }
928}
929
930optargtype! {parser =>
931  IncludeProblemArg {
932    {Pts = "pts" : f32}
933    {Min = "min": f32}
934    {Archive = "archive": str}
935  }
936}
937
938stex!(p => includeproblem[args:type IncludeProblemArg<Pos>]{filepath:name} => {
939    let args = args.unwrap_or_default();
940      let archive = args.iter().find_map(|p| if let IncludeProblemArg::Archive(a) = p {Some(a)} else {None})
941          .and_then(|pair|
942          parse_id(&pair.val,pair.key_range.start,&mut p.tokenizer).map(|a| (a,pair.val_range))
943          );
944      let rel_path: std::sync::Arc<str> = if filepath.0.ends_with(".tex") {
945        filepath.0.into()
946      } else {
947        format!("{}.tex",filepath.0).into()
948      };
949      {
950          if let Some(id) = archive.as_ref().map_or_else(||
951              p.state.archive.as_ref().map(|a| a.archive_id()),
952              |(a,_)| Some(a)
953          ) {
954              p.state.backend.with_local_archive(id,|a|
955                  if let Some(a) = a {
956                      let path = a.source_dir();
957                      let path = rel_path.as_ref().split('/').fold(path,|p,s| p.join(s));
958                      if !path.exists() {
959                          p.tokenizer.problem(filepath.1.start,format!("File {} not found",path.display()),DiagnosticLevel::Error);
960                      }
961                  }
962              );
963          }
964      }
965      let filepath = (rel_path,filepath.1);
966      MacroResult::Success(STeXToken::IncludeProblem {
967        filepath,full_range:includeproblem.range,archive,
968        token_range:includeproblem.token_range,args
969      })
970    }
971);
972
973optargtype! {parser =>
974  MHGraphicsArg {
975    {Width = "width" : str}
976    {Height = "height": str}
977    {Archive = "archive": str}
978    {Viewport = "viewport": str}
979    {Trim = "trim": str}
980    {Scale = "scale": f32}
981    {Angle = "angle": f32}
982    {Clip = "clip":()}
983    {KeepAspectRatio = "keepaspectratio":()}
984  }
985}
986
987stex!(p => mhgraphics[args:type MHGraphicsArg<Pos>]{filepath:name} => {
988    fn img_exists(path:&Path,rel_path:&mut String,warn:impl FnOnce(&str)) -> bool {
989        const IMG_EXTS: [&str;10] = ["png","PNG","jpg","JPG","jpeg","JPEG","bmp","BMP","pdf","PDF"];
990        if let Some(e) = path.extension().and_then(|s| s.to_str().and_then(|s| IMG_EXTS.iter().find(|e| **e == s))) {
991            if ["pdf","PDF"].contains(e) {
992                warn(".pdf extension not suitable for HTML\n\nrustex will substitute with a png instead.\nYou may want to directly use the .png here");
993            }
994            return path.exists();
995        }
996        for e in &IMG_EXTS {
997            if path.with_extension(e).exists() {
998                if ["pdf","PDF"].contains(e) {
999                    warn(".pdf extension not suitable for HTML\n\nrustex will substitute with a png instead.\nYou may want to directly use the .png here");
1000                }
1001                if let Some(ex) = path.extension().and_then(|s| s.to_str()) {
1002                    let len = rel_path.len() - ex.len();
1003                    rel_path.truncate(len);
1004                } else {
1005                    rel_path.push('.');
1006                }
1007                rel_path.push_str(*e);
1008                return true
1009            }
1010        }
1011        false
1012    }
1013    let args = args.unwrap_or_default();
1014    for a in &args {
1015        match a {
1016            MHGraphicsArg::Scale(x) => p.tokenizer.problem(x.key_range.start,"`scale` results in an image size relative to the original image file. Absolute values (`width` or `height`) are strongly encouraged",DiagnosticLevel::Warning),
1017            _ => ()
1018        }
1019    }
1020    if !args.iter().any(|e| matches!(e,MHGraphicsArg::Width(_)|MHGraphicsArg::Height(_))) {
1021        p.tokenizer.problem(mhgraphics.token_range.start,"No `width` or `height` attribute in image. It is strongly encouraged to provide one of them.",DiagnosticLevel::Warning);
1022    }
1023      let archive = args.iter().find_map(|p| if let MHGraphicsArg::Archive(a) = p {Some(a)} else {None})
1024          .and_then(|pair|
1025              parse_id(&pair.val,pair.key_range.start,&mut p.tokenizer).map(|a| (a,pair.val_range))
1026          );
1027      let mut rel_path = filepath.0.to_string();
1028      {
1029          if let Some(id) = archive.as_ref().map_or_else(||
1030              p.state.archive.as_ref().map(|a| a.archive_id()),
1031              |(a,_)| Some(a)
1032          ) {
1033              p.state.backend.with_local_archive(id,|a|
1034                  if let Some(a) = a {
1035                      let path = a.source_dir();
1036                      let path = rel_path.as_str().split('/').fold(path,|p,s| p.join(s));
1037                      if !img_exists(&path,&mut rel_path,|s| p.tokenizer.problem(filepath.1.start,s,DiagnosticLevel::Info)) {
1038                          p.tokenizer.problem(filepath.1.start,format!("Image file {} not found",path.display()),DiagnosticLevel::Error);
1039                      }
1040                  }
1041              );
1042          }
1043      }
1044      let filepath = (rel_path.into(),filepath.1);
1045      MacroResult::Success(STeXToken::MHGraphics {
1046        filepath,full_range:mhgraphics.range,archive,
1047        token_range:mhgraphics.token_range,args
1048      })
1049    }
1050);
1051
1052optargtype! {parser =>
1053  SymdeclArg<T> {
1054    {Name = "name" : str}
1055    {Tp = "type": T*}
1056    {Df = "def": T*}
1057    {Return = "return": T*}
1058    {Style = "style": ()}
1059    {Assoc = "assoc": ()}
1060    {Role = "role": ()}
1061    {Argtypes = "argtypes": T*}
1062    {Reorder = "reorder": ()}
1063    {Args = "args": Args}
1064  } @ SymdeclArgIter
1065}
1066
1067stex!(p => symdecl('*'?star){name:!name}[args:type SymdeclArg<Pos,STeXToken<Pos>>] => {
1068    let macroname = if star {None} else {Some(&name.0)};
1069    let args = args.unwrap_or_default();
1070    let main_name_range = name.1;
1071    let mut name:(&str,_) = (&name.0,name.1);
1072    let mut has_df = false;
1073    let mut has_tp = false;
1074    let mut argnum = 0;
1075    for e in &args { match e {
1076      SymdeclArg::Name(ParsedKeyValue { val_range, val,.. }) => {
1077        name = (val,*val_range);
1078      }
1079      SymdeclArg::Tp(_) | SymdeclArg::Return(_) => has_tp = true,
1080      SymdeclArg::Df(_) => has_df = true,
1081      SymdeclArg::Args(v) => argnum = v.val,
1082      _ => ()
1083    }}
1084
1085    let (state,mut groups) = p.split();
1086    let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1087      p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1088      return MacroResult::Simple(symdecl)
1089    };
1090    let mn = macroname.as_ref();
1091    if let Some(uri) = state.add_symbol(&mut groups,fname,
1092      mn.map(|s| (*s).to_string().into()),
1093      symdecl.range,has_tp,has_df,argnum
1094    ) {
1095      MacroResult::Success(STeXToken::Symdecl {
1096          starred:star,
1097          uri, main_name_range,
1098          full_range:symdecl.range,parsed_args:args,
1099          token_range:symdecl.token_range
1100      })
1101    } else {
1102      MacroResult::Simple(symdecl)
1103    }
1104  }
1105);
1106
1107optargtype! {parser =>
1108  TextSymdeclArg<T> {
1109    {Name = "name" : str}
1110    {Style = "style": ()}
1111    {Tp = "type": T*}
1112    {Df = "def": T*}
1113  } @ TextSymdeclArgIter
1114}
1115
1116stex!(p => textsymdecl{name:name}[args:type TextSymdeclArg<Pos,STeXToken<Pos>>] => {
1117  let macroname = Some(name.0);
1118  let main_name_range = name.1;
1119  let args = args.unwrap_or_default();
1120  let mut name:(&str,_) = (&name.0,name.1);
1121  //let mut has_df = false;
1122  //let mut has_tp = false;
1123  for e in &args { match e {
1124    TextSymdeclArg::Name(ParsedKeyValue { val_range, val,.. }) => {
1125      name = (val,*val_range);
1126    }
1127    //TextSymdeclArg::Tp(_) => has_tp = true,
1128    //TextSymdeclArg::Df(_) => has_df = true,
1129    _ => ()
1130  }}
1131
1132  let (state,mut groups) = p.split();
1133  let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1134    p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1135    return MacroResult::Simple(textsymdecl)
1136  };
1137  let mn = macroname.as_ref();
1138  if let Some(uri) = state.add_symbol(&mut groups,fname,
1139    mn.map(|s| (*s).to_string().into()),
1140    textsymdecl.range,false,false,0
1141  ) {
1142    MacroResult::Success(STeXToken::TextSymdecl {
1143      uri, main_name_range,
1144      full_range:textsymdecl.range,parsed_args:args,
1145      token_range:textsymdecl.token_range
1146    })
1147  } else {
1148    MacroResult::Simple(textsymdecl)
1149  }
1150}
1151);
1152
1153optargtype! {parser =>
1154  NotationArg<T> {
1155    {Prec = "prec": T*}
1156    {Op = "op": T*}
1157    _ = Id
1158  } @ NotationArgIter
1159}
1160
1161stex!(LSP: p => notation('*'?star){name:!name}[args:type NotationArg<LSPLineCol,STeXToken<LSPLineCol>>] => {
1162  let args = args.unwrap_or_default();
1163  let (state,mut groups) = p.split();
1164  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1165    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1166    return MacroResult::Simple(notation);
1167  };
1168  MacroResult::Success(STeXToken::Notation {
1169    uri:s,
1170    token_range:notation.token_range,
1171    name_range:name.1,
1172    notation_args:args,
1173    full_range:notation.range
1174  })
1175});
1176
1177optargtype! {parser =>
1178  SymdefArg<T> {
1179    {Name = "name" : str}
1180    {Tp = "type": T*}
1181    {Df = "def": T*}
1182    {Return = "return": T*}
1183    {Style = "style": ()}
1184    {Assoc = "assoc": ()}
1185    {Role = "role": ()}
1186    {Argtypes = "argtypes": T*}
1187    {Reorder = "reorder": ()}
1188    {Args = "args": Args}
1189    {Prec = "prec": T*}
1190    {Op = "op": T*}
1191    _ = Id
1192  } @ SymdefArgIter
1193}
1194
1195stex!(p => symdef{name:!name}[args:type SymdefArg<Pos,STeXToken<Pos>>] => {
1196  let macroname = Some(&name.0);
1197  let main_name_range = name.1;
1198  let args = args.unwrap_or_default();
1199  let mut name:(&str,_) = (&name.0,name.1);
1200  let mut has_df = false;
1201  let mut has_tp = false;
1202  let mut argnum = 0;
1203  for e in &args { match e {
1204    SymdefArg::Name(ParsedKeyValue { key_range, val_range, val }) => {
1205      name = (val,*val_range);
1206    }
1207    SymdefArg::Tp(_) | SymdefArg::Return(_) => has_tp = true,
1208    SymdefArg::Df(_) => has_df = true,
1209    SymdefArg::Args(v) => argnum = v.val,
1210    _ => ()
1211  }}
1212
1213  let (state,mut groups) = p.split();
1214  let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1215    p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1216    return MacroResult::Simple(symdef)
1217  };
1218  let mn = macroname.as_ref();
1219  if let Some(uri) = state.add_symbol(&mut groups,fname,
1220    mn.map(|s| (*s).to_string().into()),
1221    symdef.range,has_tp,has_df,argnum
1222  ) {
1223    MacroResult::Success(STeXToken::Symdef {
1224      uri, main_name_range,
1225      full_range:symdef.range,parsed_args:args,
1226      token_range:symdef.token_range
1227    })
1228  } else {
1229    MacroResult::Simple(symdef)
1230  }
1231}
1232);
1233
1234stex!(LSP: p => precondition{dim:!name}{symbol:!name} => {
1235  let Ok(cogdim) = dim.0.parse() else {
1236    p.tokenizer.problem(dim.1.start,format!("Invalid cognitive dimension {}",dim.0),DiagnosticLevel::Error);
1237    return MacroResult::Simple(precondition);
1238  };
1239  let (state,mut groups) = p.split();
1240  if !groups.groups.iter().rev().any(|g| matches!(g.kind,GroupKind::Problem)) {
1241    groups.tokenizer.problem(symbol.1.start, "\\precondition is only allowed in a problem",DiagnosticLevel::Error);
1242  }
1243  let Some(s) = state.get_symbol(symbol.1.start,&mut groups,&symbol.0) else {
1244    groups.tokenizer.problem(symbol.1.start, format!("Unknown symbol {}",symbol.0),DiagnosticLevel::Error);
1245    return MacroResult::Simple(precondition);
1246  };
1247  MacroResult::Success(STeXToken::Precondition {
1248    uri:s, full_range: precondition.range, token_range: precondition.token_range, dim_range:dim.1,
1249    symbol_range:symbol.1,dim:cogdim
1250  })
1251});
1252
1253stex!(LSP: p => objective{dim:!name}{symbol:!name} => {
1254  let Ok(cogdim) = dim.0.parse() else {
1255    p.tokenizer.problem(dim.1.start,format!("Invalid cognitive dimension {}",dim.0),DiagnosticLevel::Error);
1256    return MacroResult::Simple(objective);
1257  };
1258  let (state,mut groups) = p.split();
1259  if !groups.groups.iter().rev().any(|g| matches!(g.kind,GroupKind::Problem)) {
1260    groups.tokenizer.problem(symbol.1.start, "\\objective is only allowed in a problem",DiagnosticLevel::Error);
1261  }
1262  let Some(s) = state.get_symbol(symbol.1.start,&mut groups,&symbol.0) else {
1263    groups.tokenizer.problem(symbol.1.start, format!("Unknown symbol {}",symbol.0),DiagnosticLevel::Error);
1264    return MacroResult::Simple(objective);
1265  };
1266  MacroResult::Success(STeXToken::Objective {
1267    uri:s, full_range: objective.range, token_range: objective.token_range, dim_range:dim.1,
1268    symbol_range:symbol.1,dim:cogdim
1269  })
1270});
1271
1272stex!(LSP: p => symref[mut args:Map]{name:!name}{text:T} => {
1273  let (state,mut groups) = p.split();
1274  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1275    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1276    return MacroResult::Simple(symref);
1277  };
1278  args.inner.remove(&"root");
1279  for (k,v) in args.inner.iter() {
1280    p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1281  }
1282  MacroResult::Success(STeXToken::Symref {
1283    is_def:false,
1284    uri:s, full_range: symref.range, token_range: symref.token_range,
1285    name_range: name.1, text
1286  })
1287});
1288
1289stex!(LSP: p => definiendum[mut args:Map]{name:!name}{text:T!} => {
1290  let (state,mut groups) = p.split();
1291  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1292    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1293    return MacroResult::Simple(definiendum);
1294  };
1295  args.inner.remove(&"root");
1296  for (k,v) in args.inner.iter() {
1297    p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1298  }
1299
1300p.state.module_store.add_verbalization(
1301    text.2,
1302    &s.first().expect("should be unreachable").uri,
1303    p.state.language
1304);
1305  MacroResult::Success(STeXToken::Symref {
1306    is_def:true,
1307    uri:s, full_range: definiendum.range, token_range: definiendum.token_range,
1308    name_range: name.1, text:(text.0,text.1)
1309  })
1310});
1311
1312stex!(LSP: p => symname[mut args:Map]{name:!name} => {
1313  let (state,mut groups) = p.split();
1314  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1315    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1316    return MacroResult::Simple(symname);
1317  };
1318  let pre = if let Some(val) = args.inner.remove(&"pre") {
1319    Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1320  } else { None };
1321  let post = if let Some(val) = args.inner.remove(&"post") {
1322    Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1323  } else { None };
1324  for (k,v) in args.inner.iter() {
1325    p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1326  }
1327  MacroResult::Success(STeXToken::SymName {
1328    is_def:false,
1329    uri:s, full_range: symname.range, token_range: symname.token_range,
1330    name_range: name.1,
1331    mode: super::structs::SymnameMode::PrePost{ pre, post }
1332  })
1333});
1334
1335stex!(LSP: p => Symname[mut args:Map]{name:!name} => {
1336  let (state,mut groups) = p.split();
1337  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1338    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1339    return MacroResult::Simple(Symname);
1340  };
1341  let post = if let Some(val) = args.inner.remove(&"post") {
1342    Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1343  } else { None };
1344  for (k,v) in args.inner.iter() {
1345    p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1346  }
1347  MacroResult::Success(STeXToken::SymName {
1348    is_def:false,
1349    uri:s, full_range: Symname.range, token_range: Symname.token_range,
1350    name_range: name.1,
1351    mode: super::structs::SymnameMode::Cap{ post }
1352  })
1353});
1354
1355stex!(LSP: p => symnames[mut args:Map]{name:!name} => {
1356  let (state,mut groups) = p.split();
1357  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1358    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1359    return MacroResult::Simple(symnames);
1360  };
1361  let pre = if let Some(val) = args.inner.remove(&"pre") {
1362    Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1363  } else { None };
1364  for (k,v) in args.inner.iter() {
1365    p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1366  }
1367  MacroResult::Success(STeXToken::SymName {
1368    is_def:false,
1369    uri:s, full_range: symnames.range, token_range: symnames.token_range,
1370    name_range: name.1,
1371    mode: super::structs::SymnameMode::PostS{ pre }
1372  })
1373});
1374
1375stex!(LSP: p => Symnames{name:!name} => {
1376  let (state,mut groups) = p.split();
1377  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1378    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1379    return MacroResult::Simple(Symnames);
1380  };
1381  MacroResult::Success(STeXToken::SymName {
1382    is_def:false,
1383    uri:s, full_range: Symnames.range, token_range: Symnames.token_range,
1384    name_range: name.1,
1385    mode: super::structs::SymnameMode::CapAndPostS
1386  })
1387});
1388
1389stex!(LSP: p => definame[mut args:Map]{name:!name} => {
1390  let (state,mut groups) = p.split();
1391  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1392    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1393    return MacroResult::Simple(definame);
1394  };
1395  let pre = if let Some(val) = args.inner.remove(&"pre") {
1396    Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1397  } else { None };
1398  let post = if let Some(val) = args.inner.remove(&"post") {
1399    Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1400  } else { None };
1401  args.inner.remove(&"root");
1402  for (k,v) in args.inner.iter() {
1403    p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1404  }
1405  let mode =super::structs::SymnameMode::PrePost{ pre, post };
1406  /*p.state.module_store.add_verbalization(
1407      &name.0,
1408      &mode,
1409      &s.first().expect("should be unreachable").uri,
1410      p.state.language
1411  );*/
1412  MacroResult::Success(STeXToken::SymName {
1413    is_def:true,
1414    uri:s, full_range: definame.range, token_range: definame.token_range,
1415    name_range: name.1,
1416    mode
1417  })
1418});
1419
1420stex!(LSP: p => Definame[mut args:Map]{name:!name} => {
1421  let (state,mut groups) = p.split();
1422  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1423    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1424    return MacroResult::Simple(Definame);
1425  };
1426  let post = if let Some(val) = args.inner.remove(&"post") {
1427    Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1428  } else { None };
1429  for (k,v) in args.inner.iter() {
1430    p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1431  }
1432  let mode = super::structs::SymnameMode::Cap{ post };
1433  /*p.state.module_store.add_verbalization(
1434      &name.0,
1435      &mode,
1436      &s.first().expect("should be unreachable").uri,
1437      p.state.language
1438  );*/
1439  MacroResult::Success(STeXToken::SymName {
1440    is_def:true,
1441    uri:s, full_range: Definame.range, token_range: Definame.token_range,
1442    name_range: name.1,
1443    mode
1444  })
1445});
1446
1447stex!(LSP: p => definames[mut args:Map]{name:!name} => {
1448  let (state,mut groups) = p.split();
1449  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1450    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1451    return MacroResult::Simple(definames);
1452  };
1453  let pre = if let Some(val) = args.inner.remove(&"pre") {
1454    Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1455  } else { None };
1456  for (k,v) in args.inner.iter() {
1457    p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1458  }
1459  let mode = super::structs::SymnameMode::PostS{ pre };
1460  /*p.state.module_store.add_verbalization(
1461      &name.0,
1462      &mode,
1463      &s.first().expect("should be unreachable").uri,
1464      p.state.language
1465  );*/
1466  MacroResult::Success(STeXToken::SymName {
1467    is_def:true,
1468    uri:s, full_range: definames.range, token_range: definames.token_range,
1469    name_range: name.1,
1470    mode
1471  })
1472});
1473
1474stex!(LSP: p => Definames{name:!name} => {
1475  let (state,mut groups) = p.split();
1476  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1477    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1478    return MacroResult::Simple(Definames);
1479  };
1480  /*p.state.module_store.add_verbalization::<LSPLineCol>(
1481      &name.0,
1482      &super::structs::SymnameMode::CapAndPostS,
1483      &s.first().expect("should be unreachable").uri,
1484      p.state.language
1485  );*/
1486  MacroResult::Success(STeXToken::SymName {
1487    is_def:true,
1488    uri:s, full_range: Definames.range, token_range: Definames.token_range,
1489    name_range: name.1,
1490    mode: super::structs::SymnameMode::CapAndPostS
1491  })
1492});
1493
1494stex!(LSP: p => symuse{name:!name} => {
1495  let (state,mut groups) = p.split();
1496  let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1497    p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1498    return MacroResult::Simple(symuse);
1499  };
1500  MacroResult::Success(STeXToken::Symuse {
1501    uri:s, full_range: symuse.range, token_range: symuse.token_range,
1502    name_range: name.1
1503  })
1504});
1505
1506stex!(LSP: p => defnotation => {
1507  MacroResult::Success(STeXToken::Defnotation{full_range:defnotation.token_range})
1508});
1509
1510stex!(LSP: p => definiens[name_opt:!name] => {
1511  let (state,mut groups) = p.split();
1512  let (s,rng) = if let Some(name) = name_opt {
1513    if let Some((s,_)) = get_in_morphism(groups.groups, &name.0) {
1514      (smallvec::smallvec![s.uri.clone()],Some(name.1))
1515    } else {
1516      let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1517        p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1518        return MacroResult::Simple(definiens);
1519      };
1520      (s,Some(name.1))
1521    }
1522  } else {
1523    let Some(s) = groups.groups.iter().rev().find_map(|g|
1524      if let GroupKind::DefPara(defs) = &g.kind {
1525        defs.first().cloned()
1526      } else {None}
1527    ) else {
1528      p.tokenizer.problem(definiens.range.start, "No definition found".to_string(),DiagnosticLevel::Error);
1529      return MacroResult::Simple(definiens);
1530    };
1531    (smallvec::smallvec![s],None)
1532  };
1533  set_defined(s.first().unwrap_or_else(|| unreachable!()), definiens.range, groups.groups);
1534  MacroResult::Success(STeXToken::Definiens {
1535    uri:s, full_range: definiens.range, token_range: definiens.token_range,
1536    name_range: rng
1537  })
1538});
1539
1540stex!(LSP: p => defi_only => {
1541  p.tokenizer.problem(p.curr_pos(), "only allowed in definitions".to_string(),DiagnosticLevel::Error);
1542  MacroResult::Simple(defi_only)
1543});
1544
1545optargtype! {parser =>
1546  VardefArg<T> {
1547    {Name = "name" : str}
1548    {Args = "args": Args}
1549    {Tp = "type": T*}
1550    {Df = "def": T*}
1551    {Return = "return": T*}
1552    {Style = "style": ()}
1553    {Assoc = "assoc": ()}
1554    {Role = "role": ()}
1555    {Argtypes = "argtypes": T*}
1556    {Reorder = "reorder": ()}
1557    {Bind = "bind": !}
1558    {Prec = "prec": T*}
1559    {Op = "op": T*}
1560    _ = Id
1561  } @ VardefArgIter
1562}
1563
1564stex!(p => vardef{name:!name}[args:type VardefArg<Pos,STeXToken<Pos>>] => {
1565  let macroname = name.0.to_string();
1566  let args = args.unwrap_or_default();
1567  let main_name_range = name.1;
1568  let mut name: (&str,_) = (&name.0,name.1);
1569  let mut argnum = 0;
1570
1571  for e in &args { match e {
1572    VardefArg::Name(ParsedKeyValue { key_range, val_range, val }) => {
1573      name = (val,*val_range);
1574    }
1575    VardefArg::Args(v) => argnum = v.val,
1576    _ => ()
1577  }}
1578
1579  let (state,mut groups) = p.split();
1580  let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1581    p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1582    return MacroResult::Simple(vardef)
1583  };
1584  let rule = AnyMacro::Ext(DynMacro {
1585    ptr: variable_macro as _,
1586    arg:MacroArg::Variable(fname.clone(), vardef.range, false,argnum)
1587  });
1588  p.add_macro_rule(macroname.into(), Some(rule));
1589  MacroResult::Success(STeXToken::Vardef {
1590    name:fname, main_name_range,
1591    full_range:vardef.range,parsed_args:args,
1592    token_range:vardef.token_range
1593  })
1594});
1595
1596stex!(p => newvar{name:!name}[args:type VardefArg<Pos,STeXToken<Pos>>] => {
1597  let macroname = format!("v{}",name.0);
1598  let args = args.unwrap_or_default();
1599  let main_name_range = name.1;
1600  let mut name: (&str,_) = (&name.0,name.1);
1601  let mut argnum = 0;
1602
1603  for e in &args { match e {
1604    VardefArg::Name(ParsedKeyValue { key_range, val_range, val }) => {
1605      name = (val,*val_range);
1606    }
1607    VardefArg::Args(v) => argnum = v.val,
1608    _ => ()
1609  }}
1610
1611  let (state,mut groups) = p.split();
1612  let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1613    p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1614    return MacroResult::Simple(newvar)
1615  };
1616  let rule = AnyMacro::Ext(DynMacro {
1617    ptr: variable_macro as _,
1618    arg:MacroArg::Variable(fname.clone(), newvar.range, false,argnum)
1619  });
1620  p.add_macro_rule(macroname.into(), Some(rule));
1621  MacroResult::Success(STeXToken::Vardef {
1622    name:fname, main_name_range,
1623    full_range:newvar.range,parsed_args:args,
1624    token_range:newvar.token_range
1625  })
1626});
1627
1628stex!(p => varseq{name:!name}[args:type VardefArg<Pos,STeXToken<Pos>>] => {
1629  let macroname = name.0.to_string();
1630  let args = args.unwrap_or_default();
1631  let main_name_range = name.1;
1632  let mut name : (&str,_) = (&name.0,name.1);
1633  //let mut has_df = false;
1634  //let mut has_tp = false;
1635  let mut argnum = 0;
1636
1637  for e in &args { match e {
1638    VardefArg::Name(ParsedKeyValue { key_range, val_range, val }) => {
1639      name = (val,*val_range);
1640    }
1641    //VardefArg::Tp(_) | VardefArg::Return(_) => has_tp = true,
1642    //VardefArg::Df(_) => has_df = true,
1643    VardefArg::Args(v) => argnum = v.val,
1644    _ => ()
1645  }}
1646
1647  let (state,mut groups) = p.split();
1648  let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1649    p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1650    return MacroResult::Simple(varseq)
1651  };
1652  let rule = AnyMacro::Ext(DynMacro {
1653    ptr: variable_macro as _,
1654    arg:MacroArg::Variable(fname.clone(), varseq.range, true,argnum)
1655  });
1656  p.add_macro_rule(macroname.into(), Some(rule));
1657  MacroResult::Success(STeXToken::Varseq {
1658    name:fname, main_name_range,
1659    full_range:varseq.range,parsed_args:args,
1660    token_range:varseq.token_range
1661  })
1662});
1663
1664stex!(p => newseq{name:!name}[args:type VardefArg<Pos,STeXToken<Pos>>] => {
1665let macroname = format!("v{}",name.0);
1666  let args = args.unwrap_or_default();
1667  let main_name_range = name.1;
1668  let mut name : (&str,_) = (&name.0,name.1);
1669  //let mut has_df = false;
1670  //let mut has_tp = false;
1671  let mut argnum = 0;
1672
1673  for e in &args { match e {
1674    VardefArg::Name(ParsedKeyValue { key_range, val_range, val }) => {
1675      name = (val,*val_range);
1676    }
1677    //VardefArg::Tp(_) | VardefArg::Return(_) => has_tp = true,
1678    //VardefArg::Df(_) => has_df = true,
1679    VardefArg::Args(v) => argnum = v.val,
1680    _ => ()
1681  }}
1682
1683  let (state,mut groups) = p.split();
1684  let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1685    p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1686    return MacroResult::Simple(newseq)
1687  };
1688  let rule = AnyMacro::Ext(DynMacro {
1689    ptr: variable_macro as _,
1690    arg:MacroArg::Variable(fname.clone(), newseq.range, true,argnum)
1691  });
1692  p.add_macro_rule(macroname.into(), Some(rule));
1693  MacroResult::Success(STeXToken::Varseq {
1694    name:fname, main_name_range,
1695    full_range:newseq.range,parsed_args:args,
1696    token_range:newseq.token_range
1697  })
1698});
1699
1700stex!(p => svar[optname:!name]{arg:!name} => {
1701  let (name,name_range) = if let Some(optname) = optname {
1702    (optname.0,Some(optname.1))
1703  } else {
1704    (arg.0,None)
1705  };
1706  let Ok(name) = name.as_ref().parse::<UriName>() else {
1707    p.tokenizer.problem(name_range.unwrap_or_default().start, format!("Invalid uri segment {name}"),DiagnosticLevel::Error);
1708    return MacroResult::Simple(svar)
1709  };
1710  MacroResult::Success(STeXToken::Svar {
1711    name, full_range:svar.range,name_range,arg_range:arg.1,
1712    token_range:svar.token_range
1713  })
1714});
1715
1716static META_REL_PATH: std::sync::LazyLock<std::sync::Arc<str>> =
1717    std::sync::LazyLock::new(|| "Metatheory.en.tex".into());
1718static META_FULL_PATH: std::sync::LazyLock<Option<std::sync::Arc<Path>>> =
1719    std::sync::LazyLock::new(|| {
1720        GlobalBackend.with_local_archive(ftml_uris::metatheory::URI.archive_id(), |a| {
1721            a.map(|a| a.source_dir().join("Metatheory.en.tex").into())
1722        })
1723    });
1724
1725fn get_module<'a, 'b, Pos: StringPosition + 'a, MS: STeXModuleStore>(
1726    p: &'b mut LaTeXParser<'a, Pos, STeXToken<Pos>, STeXParseState<'a, Pos, MS>>,
1727) -> Option<(&'b ModuleUri, &'b mut Vec<ModuleRule<Pos>>)> {
1728    p.groups.iter_mut().rev().find_map(|g| match &mut g.kind {
1729        GroupKind::Module { uri, rules } | GroupKind::MathStructure { uri, rules } => {
1730            Some((&*uri, rules))
1731        }
1732        _ => None,
1733    })
1734}
1735
1736optargtype!(parser =>
1737  SModuleArg<T> {
1738    {Sig = "sig": Language}
1739    {Meta = "meta": str}
1740    //{Creators = "creators": ()}
1741    //{Contributors = "contributors": ()}
1742    {Title = "title": T*}
1743  } @ SModuleArgIter
1744);
1745
1746stex!(LSP: p => @begin{smodule}([opt:type SModuleArg<LSPLineCol,STeXToken<LSPLineCol>>]{name:name}){
1747      let opt = opt.unwrap_or_default();
1748      let mut sig = None;
1749      let mut has_meta_theory = Some(false);
1750      for e in &opt { match e {
1751        SModuleArg::Sig(s) => sig = Some(s.val),
1752        SModuleArg::Meta(s) => {
1753          if s.val.is_empty() || &*s.val == "{}" {
1754            has_meta_theory = None;
1755          } else {
1756            p.tokenizer.problem(smodule.begin.range.start,"TODO: metatheory",DiagnosticLevel::Error);
1757            has_meta_theory = Some(true);
1758          }
1759        }
1760        SModuleArg::Title(_) => ()
1761      }}
1762      let meta_theory = if has_meta_theory == Some(false) {
1763        Some(ModuleReference {
1764          uri:ftml_uris::metatheory::URI.clone(),
1765          in_doc:ftml_uris::metatheory::DOC_URI.clone(),
1766          rel_path:Some(META_REL_PATH.clone()),
1767          full_path:META_FULL_PATH.clone()
1768        })
1769      } else { None };
1770
1771      let uri = if let Some((m,_)) = get_module(p) {
1772        name.0.parse().map(|n| m.clone() / &n).map_err(Into::into)
1773      } else {
1774        p.state.doc_uri.module_uri_from(name.0)
1775      };
1776      let Ok(uri) = uri else {
1777        p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.1),DiagnosticLevel::Error);
1778        return ()
1779      };
1780      p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Module{
1781        uri:uri.clone(),rules:Vec::new()
1782      };
1783      if let Some(l) = sig {
1784        if let Some(path) = &p.state.in_path {
1785          let curr_lang = p.state.language;
1786          let Some(filename) = path.file_name().and_then(|s| s.to_str()) else {
1787            p.tokenizer.problem(smodule.begin.range.start, "file path error", DiagnosticLevel::Error);
1788            return
1789          };
1790          let filename = {
1791            let Some(filename) = filename.strip_suffix(".tex") else {
1792              p.tokenizer.problem(smodule.begin.range.start, "file path error", DiagnosticLevel::Error);
1793              return
1794            };
1795            let init = if filename.ends_with(<&'static str>::from(curr_lang)) {
1796              &filename[..filename.len()-3]
1797            } else {filename};
1798            format!("{init}.{l}.tex")
1799          };
1800          let full_path = path.with_file_name(&filename);
1801          let rel_path = p.state.archive.as_ref().and_then(|a| {
1802            p.state.backend.with_local_archive(a.archive_id(), |a|
1803              a.and_then(|a| path.strip_prefix(a.path()).ok().and_then(|p|
1804                p.strip_prefix("source").ok().map(|p| p.with_file_name(filename).display().to_string().into())
1805              ))
1806            )
1807          });
1808
1809          let uri = uri.clone();
1810          let in_doc = p.state.doc_uri.path_uri().clone() & (p.state.doc_uri.document_name().clone(),l);
1811          let mrf = ModuleReference {
1812            uri,in_doc,rel_path,full_path:Some(full_path.into())
1813          };
1814          let (state,groups) = p.split();
1815          state.add_import(&mrf, groups, smodule.begin.range);
1816        }
1817      }
1818      if let Some(rf) = meta_theory.as_ref() {
1819        let (state,groups) = p.split();
1820        //state.add_use(rf, groups, smodule.begin.range);
1821        state.add_import(rf, groups, smodule.begin.range);
1822      }
1823      smodule.children.push(STeXToken::Module{
1824        uri,full_range:smodule.begin.range,sig,meta_theory,
1825        children:Vec::new(),name_range:name.1,
1826        smodule_range:smodule.name_range,opts:opt,
1827        rules:ModuleRules::default()
1828      });
1829    }{
1830      let Some(g) = p.groups.last_mut() else {
1831        p.tokenizer.problem(smodule.begin.range.start,"Module ended unexpectedly",DiagnosticLevel::Error);
1832        return EnvironmentResult::Simple(smodule)
1833      };
1834      let GroupKind::Module { uri, rules } = std::mem::take(&mut g.kind) else {
1835        return EnvironmentResult::Simple(smodule);
1836      };
1837      let rules = ModuleRules{ rules:rules.into()};
1838      p.state.modules.push((uri,rules.clone()));
1839      match smodule.children.first() {
1840        Some(STeXToken::Module { .. }) => {
1841          let mut ch = smodule.children.drain(..);
1842          let Some(STeXToken::Module { uri,mut full_range,sig,meta_theory,mut children,name_range,smodule_range,opts,.. }) = ch.next() else {
1843            unreachable!()
1844          };
1845          children.extend(ch);
1846          if let Some(end) = smodule.end {
1847            full_range.end = end.range.end;
1848          }
1849          EnvironmentResult::Success(STeXToken::Module { uri,rules,full_range,sig,meta_theory,children,name_range,smodule_range,opts })
1850        }
1851        _ => EnvironmentResult::Simple(smodule)
1852      }
1853    }
1854);
1855
1856optargtype!(parser =>
1857  MathStructureArg<T> {
1858    {This = "this": T*}
1859    _ = Name
1860  } @ MathStructureArgIter
1861);
1862
1863stex!(LSP: p => @begin{mathstructure}({name:!name}[args:type MathStructureArg<LSPLineCol,STeXToken<LSPLineCol>>]){
1864  let args = args.unwrap_or_default();
1865  let name_range = name.1;
1866  let macroname = &name.0;
1867  let mut name : &str = &name.0;
1868  for a in &args{ match a {
1869    MathStructureArg::Name(_,n) => name = n,
1870    MathStructureArg::This(_) => ()
1871  }}
1872
1873  let Ok(fname) : Result<UriName,_> = name.parse() else {
1874    p.tokenizer.problem(name_range.start, format!("Invalid uri segment {name}"),DiagnosticLevel::Error);
1875    return
1876  };
1877  let (state,mut groups) = p.split();
1878  let Some(uri) = state.add_structure(
1879    &mut groups,fname,Some(macroname.to_string().into()),mathstructure.begin.range
1880  ) else {
1881    return
1882  };
1883
1884  groups.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::MathStructure{
1885    uri:uri.uri.clone().into_module(),rules:Vec::new()
1886  };
1887
1888  mathstructure.children.push(STeXToken::MathStructure {
1889    uri, name_range,
1890    opts:args,
1891    mathstructure_range: mathstructure.name_range,
1892    full_range: mathstructure.begin.range,
1893    extends: Vec::new(),
1894    children: Vec::new()
1895  })
1896}{
1897  match mathstructure.children.first() {
1898    Some(STeXToken::MathStructure { .. }) => {
1899      let mut ch = mathstructure.children.drain(..);
1900      let Some(STeXToken::MathStructure { uri, opts, extends, name_range, mut full_range, mut children, mathstructure_range }) = ch.next() else{
1901        unreachable!()
1902      };
1903      children.extend(ch);
1904      if let Some(end) = mathstructure.end.as_ref() {
1905        full_range.end = end.range.end;
1906      }
1907
1908      let Some(g) = p.groups.last_mut() else {
1909        p.tokenizer.problem(mathstructure.begin.range.start,"Mathstructure ended unexpectedly",DiagnosticLevel::Error);
1910        return EnvironmentResult::Simple(mathstructure)
1911      };
1912      let GroupKind::MathStructure { uri:_, rules } = std::mem::take(&mut g.kind) else {
1913        return EnvironmentResult::Simple(mathstructure);
1914      };
1915      let rules = ModuleRules{ rules:rules.into()};
1916      let (state,mut groups) = p.split();
1917      state.set_structure(&mut groups, rules, full_range);
1918
1919      EnvironmentResult::Success(STeXToken::MathStructure {
1920        uri,extends,name_range,full_range,opts,children,mathstructure_range
1921      })
1922    }
1923    _ => {
1924      EnvironmentResult::Simple(mathstructure)
1925    }
1926  }
1927});
1928
1929stex!(LSP: p => @begin{extstructure}({name:!name}[args:type MathStructureArg<LSPLineCol,STeXToken<LSPLineCol>>]{exts:!name+}){
1930  let args = args.unwrap_or_default();
1931  let name_range = name.1;
1932  let macroname = &name.0;
1933  let mut name: &str = &name.0;
1934  for a in &args{ match a {
1935    MathStructureArg::Name(_,n) => name = n,
1936    MathStructureArg::This(_) => ()
1937  }}
1938
1939  let Ok(fname) : Result<UriName,_> = name.parse() else {
1940    p.tokenizer.problem(name_range.start, format!("Invalid uri segment {name}"),DiagnosticLevel::Error);
1941    return
1942  };
1943  let (state,mut groups) = p.split();
1944  let mut extends = Vec::new();
1945  for (n,r) in exts {
1946    let Some(s) = state.get_structure(&groups,&n) else {
1947      groups.tokenizer.problem(r.start, format!("Unknown structure {n}"),DiagnosticLevel::Error);
1948      return
1949    };
1950    extends.push((s.0,s.1,r));
1951  }
1952  let Some(uri) = state.add_structure(
1953    &mut groups,fname,Some(macroname.clone().into()),extstructure.begin.range
1954  ) else { return };
1955
1956  groups.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::MathStructure{
1957    uri:uri.uri.clone().into_module(),rules:Vec::new()
1958  };
1959
1960  for (s,r,_) in &extends {
1961    state.import_structure(s,r,&mut groups,extstructure.begin.range);
1962  }
1963
1964  extstructure.children.push(STeXToken::MathStructure {
1965    uri, name_range,
1966    opts:args,
1967    mathstructure_range: extstructure.name_range,
1968    full_range: extstructure.begin.range,
1969    extends:extends.into_iter().map(|(a,_,b)| (a,b)).collect(),
1970    children: Vec::new()
1971  })
1972}{
1973  match extstructure.children.first() {
1974    Some(STeXToken::MathStructure { .. }) => {
1975      let mut ch = extstructure.children.drain(..);
1976      let Some(STeXToken::MathStructure { uri,opts , extends, name_range, mut full_range, mut children, mathstructure_range }) = ch.next() else{
1977        unreachable!()
1978      };
1979      children.extend(ch);
1980      if let Some(end) = extstructure.end.as_ref() {
1981        full_range.end = end.range.end;
1982      }
1983
1984      let Some(g) = p.groups.last_mut() else {
1985        p.tokenizer.problem(extstructure.begin.range.start,"extstructure ended unexpectedly",DiagnosticLevel::Error);
1986        return EnvironmentResult::Simple(extstructure)
1987      };
1988      let GroupKind::MathStructure { uri:_, rules } = std::mem::take(&mut g.kind) else {
1989        return EnvironmentResult::Simple(extstructure);
1990      };
1991      let rules = ModuleRules{ rules:rules.into()};
1992      let (state,mut groups) = p.split();
1993      state.set_structure(&mut groups, rules, full_range);
1994
1995      EnvironmentResult::Success(STeXToken::MathStructure {
1996        uri,extends,name_range,full_range,opts,children,mathstructure_range
1997      })
1998    }
1999    _ => {
2000      EnvironmentResult::Simple(extstructure)
2001    }
2002  }
2003});
2004
2005stex!(LSP: p => @begin{extstructure_ast}({exts:!name}){
2006  let (state,mut groups) = p.split();
2007  let Some((sym,rules)) = state.get_structure(&groups,&exts.0) else {
2008    groups.tokenizer.problem(exts.1.start, format!("Unknown structure {}",exts.0),DiagnosticLevel::Error);
2009    return
2010  };
2011  let Some(uri) = state.add_conservative_ext(&mut groups, &sym, extstructure_ast.begin.range) else {
2012    groups.tokenizer.problem(exts.1.start, "Not in a module".to_string(),DiagnosticLevel::Error);
2013    return
2014  };
2015  groups.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::ConservativeExt(uri,Vec::new());
2016  state.use_structure(&sym,&rules,&mut groups,extstructure_ast.begin.range);
2017
2018  extstructure_ast.children.push(STeXToken::ConservativeExt {
2019    uri:sym, ext_range:exts.1,
2020    extstructure_range: extstructure_ast.name_range,
2021    full_range: extstructure_ast.begin.range,
2022    children: Vec::new()
2023  });
2024}{
2025  match extstructure_ast.children.first() {
2026    Some(STeXToken::ConservativeExt { .. }) => {
2027      let mut ch = extstructure_ast.children.drain(..);
2028      let Some(STeXToken::ConservativeExt { uri,ext_range, extstructure_range, mut full_range, mut children }) = ch.next() else{
2029        unreachable!()
2030      };
2031      children.extend(ch);
2032      if let Some(end) = extstructure_ast.end.as_ref() {
2033        full_range.end = end.range.end;
2034      }
2035
2036      let Some(g) = p.groups.last_mut() else {
2037        p.tokenizer.problem(extstructure_ast.begin.range.start,"extstructure* ended unexpectedly",DiagnosticLevel::Error);
2038        return EnvironmentResult::Simple(extstructure_ast)
2039      };
2040      let GroupKind::ConservativeExt(_,rules) = std::mem::take(&mut g.kind) else {
2041        return EnvironmentResult::Simple(extstructure_ast);
2042      };
2043      let rules = ModuleRules{ rules:rules.into()};
2044      let (state,mut groups) = p.split();
2045      state.set_structure(&mut groups, rules, full_range);
2046
2047      EnvironmentResult::Success(STeXToken::ConservativeExt {
2048        uri,ext_range,extstructure_range,full_range,children
2049      })
2050    }
2051    _ => {
2052      EnvironmentResult::Simple(extstructure_ast)
2053    }
2054  }
2055});
2056
2057stex!(p => @begin{smodule_deps}([opt]{name:name}){
2058      let opt = opt.as_keyvals();
2059      let sig = opt.get(&"sig").and_then(|v| v.val.parse().ok());
2060      let uri = if let Some((m,_)) = get_module(p) {
2061        name.0.parse().map(|n| m.clone() / &n).map_err(Into::into)
2062      } else {
2063        p.state.doc_uri.module_uri_from(name.0)
2064      };
2065      let Ok(uri) = uri else {
2066        p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.1),DiagnosticLevel::Error);
2067        return ()
2068      };
2069      let meta_theory = match opt.get(&"meta").map(|v| v.val) {
2070        None => Some(ModuleReference{
2071          uri:ftml_uris::metatheory::URI.clone(),
2072          in_doc:ftml_uris::metatheory::DOC_URI.clone(),
2073          rel_path:Some(META_REL_PATH.clone()),
2074          full_path:META_FULL_PATH.clone()
2075        }),
2076        Some(""|"{}") => None,
2077        Some(o) => None// TODO
2078      };
2079      //p.state.push_module(uri.clone());
2080      smodule_deps.children.push(STeXToken::Module{
2081        uri,full_range:smodule_deps.begin.range,sig,meta_theory,
2082        children:Vec::new(),name_range:name.1,rules:ModuleRules::default(),
2083        smodule_range:smodule_deps.name_range,opts:Vec::new()
2084      });
2085    }{
2086      //p.state.pop_module();
2087      match smodule_deps.children.first() {
2088        Some(STeXToken::Module { .. }) => {
2089          let mut ch = smodule_deps.children.drain(..);
2090          let Some(STeXToken::Module { uri,mut full_range,sig,meta_theory,mut children,name_range,rules,smodule_range,opts }) = ch.next() else {
2091            unreachable!()
2092          };
2093          children.extend(ch);
2094          if let Some(end) = smodule_deps.end {
2095            full_range.end = end.range.end;
2096          }
2097          EnvironmentResult::Success(STeXToken::Module { uri,rules,full_range,sig,meta_theory,children,name_range,smodule_range,opts })
2098        }
2099        _ => EnvironmentResult::Simple(smodule_deps)
2100      }
2101    }
2102);
2103
2104optargtype! {LSP parser =>
2105  ParagraphArg<T> {
2106    {Id = "id": ()}
2107    {Name = "name": str}
2108    {MacroName = "macro": str}
2109    {Title = "title": T*}
2110    {Args = "args": Args}
2111    {Tp = "type": T*}
2112    {Df = "def": T*}
2113    {Return = "return": T*}
2114    {Style = "style": str}
2115    {Assoc = "assoc": ()}
2116    {Role = "role": ()}
2117    {From = "from": ()}
2118    {To = "to": ()}
2119    {Argtypes = "argtypes": T*}
2120    {Reorder = "reorder": ()}
2121    {Judgment = "judgment": ()}
2122    {Fors = "for": {Vec<(SmallVec<SymbolReference<Pos>,1>,StringRange<LSPLineCol>)> =>
2123      let strs = parser.read_value_strs_normalized();
2124      let (state,mut groups) = parser.parser.split();
2125      let ret = strs.into_iter().filter_map(|(name,range)|
2126        if let Some((symbol,_)) = get_in_morphism(&mut groups.groups, &name) {
2127          Some((smallvec::smallvec![symbol.uri.clone()],range))
2128        } else if let Some(symbol) = state.get_symbol(range.start,&mut groups, &name) {
2129          Some((symbol,range))
2130        } else {
2131          groups.tokenizer.problem(range.start,format!("Unknown symbol: {name}"),DiagnosticLevel::Error);
2132          None
2133        }
2134      ).collect();
2135      Some(Self::Fors(parser.to_key_value(ret)))
2136    }}
2137  } @ ParagraphArgIter
2138}
2139
2140fn do_def_macros<'a, MS: STeXModuleStore>(
2141    p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2142) {
2143    p.add_macro_rule(
2144        Cow::Borrowed("definame"),
2145        Some(AnyMacro::Ptr(definame as _)),
2146    );
2147    p.add_macro_rule(
2148        Cow::Borrowed("Definame"),
2149        Some(AnyMacro::Ptr(Definame as _)),
2150    );
2151    p.add_macro_rule(
2152        Cow::Borrowed("definames"),
2153        Some(AnyMacro::Ptr(definames as _)),
2154    );
2155    p.add_macro_rule(
2156        Cow::Borrowed("Definames"),
2157        Some(AnyMacro::Ptr(Definames as _)),
2158    );
2159    p.add_macro_rule(
2160        Cow::Borrowed("definiendum"),
2161        Some(AnyMacro::Ptr(definiendum as _)),
2162    );
2163    p.add_macro_rule(
2164        Cow::Borrowed("defnotation"),
2165        Some(AnyMacro::Ptr(defnotation as _)),
2166    );
2167}
2168
2169fn do_paragraph<'a, MS: STeXModuleStore>(
2170    kind: ParagraphKind,
2171    p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2172    range: StringRange<LSPLineCol>,
2173    open_group: bool,
2174) -> (
2175    Option<SymbolReference<LSPLineCol>>,
2176    Vec<ParagraphArg<LSPLineCol, STeXToken<LSPLineCol>>>,
2177) {
2178    let is_def_first = matches!(kind, ParagraphKind::Definition | ParagraphKind::Assertion);
2179    if open_group {
2180        p.open_group();
2181    }
2182    if is_def_first {
2183        p.add_macro_rule(
2184            Cow::Borrowed("definiens"),
2185            Some(AnyMacro::Ptr(definiens as _)),
2186        );
2187        if MS::FULL {
2188            do_def_macros(p);
2189        }
2190    }
2191
2192    let args =
2193        <Vec<ParagraphArg<_, _>> as crate::quickparse::latex::KeyValValues<_, _, _>>::parse_opt(p)
2194            .unwrap_or_default();
2195
2196    let mut name = None;
2197    let mut macroname = None;
2198    let mut argnum = 0;
2199    let mut has_tp = false;
2200    let mut has_def = false;
2201    let mut needs_name = false;
2202    let mut is_symdoc = false;
2203    let mut fors: &[_] = &[];
2204    for e in &args {
2205        match e {
2206            ParagraphArg::Name(n) => name = Some(&n.val),
2207            ParagraphArg::MacroName(n) => macroname = Some(&n.val),
2208            ParagraphArg::Args(n) => argnum = n.val,
2209            ParagraphArg::Tp(_) | ParagraphArg::Return(_) => has_tp = true,
2210            ParagraphArg::Df(_) => has_def = true,
2211            ParagraphArg::Argtypes(_)
2212            | ParagraphArg::Assoc(_)
2213            | ParagraphArg::Reorder(_)
2214            | ParagraphArg::Role(_) => needs_name = true,
2215            ParagraphArg::Style(s) if s.val.contains("symdoc") => is_symdoc = true,
2216            ParagraphArg::Fors(f) => fors = &f.val,
2217            _ => (),
2218        }
2219    }
2220
2221    let sym = if name.is_some() || macroname.is_some() {
2222        let fname = name.unwrap_or_else(|| macroname.unwrap_or_else(|| unreachable!()));
2223        let Ok(fname): Result<UriName, _> = fname.parse() else {
2224            p.tokenizer.problem(
2225                range.start,
2226                format!("Invalid uri segment {fname}"),
2227                DiagnosticLevel::Error,
2228            );
2229            return (None, args);
2230        };
2231        let (state, mut groups) = p.split();
2232        state.add_symbol(
2233            &mut groups,
2234            fname,
2235            macroname.map(|r| r.clone().into()),
2236            range,
2237            has_tp,
2238            has_def,
2239            argnum,
2240        )
2241    } else if argnum > 0 || has_tp || has_def || needs_name {
2242        p.tokenizer.problem(
2243            range.start,
2244            format!("Missing name or macroname"),
2245            DiagnosticLevel::Error,
2246        );
2247        None
2248    } else {
2249        None
2250    };
2251
2252    if !is_def_first && (sym.is_some() || matches!(kind,ParagraphKind::Paragraph if is_symdoc)) {
2253        p.add_macro_rule(
2254            Cow::Borrowed("definiens"),
2255            Some(AnyMacro::Ptr(definiens as _)),
2256        );
2257        if MS::FULL {
2258            do_def_macros(p);
2259        }
2260    }
2261
2262    let mut v: Vec<_> = fors
2263        .iter()
2264        .map(|(v, _)| v.first().unwrap_or_else(|| unreachable!()).clone())
2265        .collect();
2266    if let Some(s) = &sym {
2267        v.push(s.clone());
2268    }
2269    p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::DefPara(v);
2270    (sym, args)
2271}
2272
2273fn inline_paragraph<'a, MS: STeXModuleStore>(
2274    kind: ParagraphKind,
2275    p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2276    mut m: Macro<'a, LSPLineCol>,
2277    //body:(StringRange<LSPLineCol>,Vec<STeXToken<LSPLineCol>>)
2278) -> MacroResult<'a, LSPLineCol, STeXToken<LSPLineCol>> {
2279    let (sym, args) = do_paragraph(kind, p, m.range, true);
2280    let children = p.get_argument(&mut m);
2281    p.close_group();
2282    MacroResult::Success(STeXToken::InlineParagraph {
2283        kind,
2284        full_range: m.range,
2285        token_range: m.token_range,
2286        symbol: sym,
2287        parsed_args: args,
2288        children_range: children.0,
2289        children: children.1,
2290    })
2291}
2292
2293fn open_paragraph<'a, MS: STeXModuleStore>(
2294    kind: ParagraphKind,
2295    p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2296    env: &mut Environment<'a, LSPLineCol, STeXToken<LSPLineCol>>,
2297) {
2298    let (sym, args) = do_paragraph(kind, p, env.begin.range, false);
2299    env.children.push(STeXToken::Paragraph {
2300        kind,
2301        full_range: env.begin.range,
2302        name_range: env.name_range,
2303        symbol: sym,
2304        parsed_args: args,
2305        children: Vec::new(),
2306    });
2307}
2308
2309fn close_paragraph<'a, MS: STeXModuleStore>(
2310    p: &LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2311    mut env: Environment<'a, LSPLineCol, STeXToken<LSPLineCol>>,
2312) -> EnvironmentResult<'a, LSPLineCol, STeXToken<LSPLineCol>> {
2313    match env.children.first() {
2314        Some(STeXToken::Paragraph { .. }) => {
2315            let mut ch = env.children.drain(..);
2316            let Some(STeXToken::Paragraph {
2317                kind,
2318                mut full_range,
2319                name_range,
2320                symbol,
2321                parsed_args,
2322                mut children,
2323            }) = ch.next()
2324            else {
2325                impossible!()
2326            };
2327            children.extend(ch);
2328            if let Some(end) = env.end.as_ref() {
2329                full_range.end = end.range.end;
2330            }
2331            EnvironmentResult::Success(STeXToken::Paragraph {
2332                kind,
2333                full_range,
2334                name_range,
2335                symbol,
2336                parsed_args,
2337                children,
2338            })
2339        }
2340        _ => EnvironmentResult::Simple(env),
2341    }
2342}
2343
2344stex!(LSP: p => @begin{sassertion}(){
2345  open_paragraph(ParagraphKind::Assertion, p, sassertion);
2346}{
2347  close_paragraph(p, sassertion)
2348});
2349
2350stex!(LSP: p => @begin{sdefinition}(){
2351  open_paragraph(ParagraphKind::Definition, p, sdefinition);
2352}{
2353  close_paragraph(p, sdefinition)
2354});
2355
2356stex!(LSP: p => @begin{sparagraph}(){
2357  open_paragraph(ParagraphKind::Paragraph, p, sparagraph);
2358}{
2359  close_paragraph(p, sparagraph)
2360});
2361
2362stex!(LSP: p => @begin{sexample}(){
2363  open_paragraph(ParagraphKind::Example, p, sexample);
2364}{
2365  close_paragraph(p, sexample)
2366});
2367
2368stex!(LSP: p => inlinedef => {
2369  inline_paragraph(ParagraphKind::Definition, p, inlinedef)
2370});
2371
2372stex!(LSP: p => inlineass => {
2373  inline_paragraph(ParagraphKind::Assertion, p, inlineass)
2374});
2375
2376stex!(LSP: p => inlinepara => {
2377  inline_paragraph(ParagraphKind::Paragraph, p, inlinepara)
2378});
2379
2380stex!(LSP: p => inlineex => {
2381  inline_paragraph(ParagraphKind::Example, p, inlineex)
2382});
2383
2384optargtype! {LSP parser =>
2385  ProblemArg<T> {
2386    {Id = "id": ()}
2387    {Title = "title": T*}
2388    {Style = "style": str}
2389    {Pts = "pts": f32}
2390    {Min = "min": f32}
2391    //{Name = "name": str}
2392    {Autogradable = "autogradable": bool?}
2393
2394  } @ ProblemArgIter
2395}
2396
2397fn open_problem<'a, MS: STeXModuleStore>(
2398    sub: bool,
2399    p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2400    env: &mut Environment<'a, LSPLineCol, STeXToken<LSPLineCol>>,
2401) {
2402    let args =
2403        <Vec<ProblemArg<_, _>> as crate::quickparse::latex::KeyValValues<_, _, _>>::parse_opt(p)
2404            .unwrap_or_default();
2405    p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Problem;
2406    env.children.push(STeXToken::Problem {
2407        sub,
2408        full_range: env.begin.range,
2409        name_range: env.name_range,
2410        parsed_args: args,
2411        children: Vec::new(),
2412    });
2413}
2414fn close_problem<'a, MS: STeXModuleStore>(
2415    p: &LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2416    mut env: Environment<'a, LSPLineCol, STeXToken<LSPLineCol>>,
2417) -> EnvironmentResult<'a, LSPLineCol, STeXToken<LSPLineCol>> {
2418    if let Some(STeXToken::Problem { .. }) = env.children.first() {
2419        let mut ch = env.children.drain(..);
2420        let Some(STeXToken::Problem {
2421            sub,
2422            mut full_range,
2423            parsed_args,
2424            name_range,
2425            mut children,
2426        }) = ch.next()
2427        else {
2428            impossible!()
2429        };
2430        children.extend(ch);
2431        if let Some(end) = env.end.as_ref() {
2432            full_range.end = end.range.end;
2433        }
2434        EnvironmentResult::Success(STeXToken::Problem {
2435            sub,
2436            full_range,
2437            name_range,
2438            parsed_args,
2439            children,
2440        })
2441    } else {
2442        EnvironmentResult::Simple(env)
2443    }
2444}
2445
2446stex!(LSP: p => @begin{sproblem}(){
2447  open_problem(false,p,sproblem)
2448}{
2449  close_problem(p,sproblem)
2450});
2451stex!(LSP: p => @begin{subproblem}(){
2452  open_problem(true,p,subproblem)
2453}{
2454  close_problem(p,subproblem)
2455});
2456
2457fn get_in_morphism<'b, MS: STeXModuleStore>(
2458    groups: &'b mut Vec<STeXGroup<'_, MS, LSPLineCol>>,
2459    name: &str,
2460) -> Option<(
2461    &'b SymbolRule<LSPLineCol>,
2462    &'b mut VecMap<SymbolReference<LSPLineCol>, MorphismSpec<LSPLineCol>>,
2463)> {
2464    for g in groups.iter_mut().rev() {
2465        if let GroupKind::Morphism {
2466            domain,
2467            rules,
2468            specs,
2469        } = &mut g.kind
2470        {
2471            let mut name = name;
2472            for (s, r) in &specs.0 {
2473                if r.macroname.as_ref().is_some_and(|n| &**n == name)
2474                    || r.new_name.as_ref().is_some_and(|n| n.last() == name)
2475                {
2476                    name = s.uri.name().last();
2477                    break;
2478                }
2479            }
2480            for r in rules.iter().rev().flat_map(|r| r.rules.iter().rev()) {
2481                match r {
2482                    ModuleRule::Symbol(s) | ModuleRule::Structure { symbol: s, .. }
2483                        if s.macroname.as_ref().is_some_and(|n| &**n == name)
2484                            || s.uri.uri.name().as_ref() == name =>
2485                    {
2486                        return Some((s, specs));
2487                    }
2488                    _ => (),
2489                }
2490            }
2491            break;
2492        }
2493    }
2494    None
2495}
2496
2497fn set_defined<MS: STeXModuleStore>(
2498    symbol: &SymbolReference<LSPLineCol>,
2499    range: StringRange<LSPLineCol>,
2500    groups: &mut Vec<STeXGroup<'_, MS, LSPLineCol>>,
2501) {
2502    for g in groups.iter_mut().rev() {
2503        match &mut g.kind {
2504            GroupKind::Morphism {
2505                domain,
2506                rules,
2507                specs,
2508            } => {
2509                let v = specs.get_or_insert_mut(symbol.clone(), MorphismSpec::default);
2510                v.is_assigned_at = Some(range);
2511                return;
2512            }
2513            GroupKind::Module { rules, .. }
2514            | GroupKind::ConservativeExt(_, rules)
2515            | GroupKind::MathStructure { rules, .. } => {
2516                for r in rules.iter_mut().rev() {
2517                    match r {
2518                        ModuleRule::Symbol(s) if s.uri.uri == symbol.uri => {
2519                            s.has_df = true;
2520                            return;
2521                        }
2522                        _ => (),
2523                    }
2524                }
2525                return;
2526            }
2527            _ => (),
2528        }
2529    }
2530}
2531
2532stex!(LSP: p => renamedecl{orig:!name}[name:!name]{macroname:!name} => {
2533  let (_,mut groups) = p.split();
2534  let Some((symbol,specs)) = get_in_morphism(groups.groups, &orig.0) else {
2535    p.tokenizer.problem(renamedecl.range.start, format!("Could not find symbol {} in morphism",orig.0), DiagnosticLevel::Error);
2536    return MacroResult::Simple(renamedecl);
2537  };
2538  let uri = symbol.uri.clone();
2539  let spec = specs.get_or_insert_mut(uri.clone(), MorphismSpec::default);
2540  if spec.macroname.is_some() || spec.new_name.is_some() {
2541    p.tokenizer.problem(renamedecl.range.start, format!("Symbol {} already renamed in morphism",orig.0), DiagnosticLevel::Error);
2542    return MacroResult::Simple(renamedecl);
2543  }
2544  if let Some(name) = name.as_ref() {
2545    let Ok(name) = name.0.parse() else {
2546      p.tokenizer.problem(renamedecl.range.start, format!("Invalid name {}",name.0), DiagnosticLevel::Error);
2547      return MacroResult::Simple(renamedecl);
2548    };
2549    spec.new_name = Some(name);
2550  }
2551  spec.macroname = Some(macroname.0.to_string().into());
2552  if spec.decl_range == StringRange::default() {
2553    spec.decl_range = renamedecl.range;
2554  }
2555  MacroResult::Success(STeXToken::RenameDecl {
2556    uri, token_range: renamedecl.token_range, orig_range: orig.1,
2557    name_range: name.map(|(_,r)| r),
2558    macroname_range: macroname.1, full_range: renamedecl.range
2559  })
2560});
2561
2562stex!(LSP: p => assign{orig:!name} => {
2563  let (_,mut groups) = p.split();
2564  let Some((symbol,specs)) = get_in_morphism(groups.groups, &orig.0) else {
2565    p.tokenizer.problem(assign.range.start, format!("Could not find symbol {} in morphism",orig.0), DiagnosticLevel::Error);
2566    return MacroResult::Simple(assign);
2567  };
2568  let uri = symbol.uri.clone();
2569  let spec = specs.get_or_insert_mut(uri.clone(), MorphismSpec::default);
2570  if spec.is_assigned_at.is_some() {
2571    p.tokenizer.problem(assign.range.start, format!("Symbol {} already assigned in morphism",orig.0), DiagnosticLevel::Error);
2572    return MacroResult::Simple(assign);
2573  }
2574  if spec.decl_range == StringRange::default() {
2575    spec.decl_range = assign.range;
2576  }
2577  spec.is_assigned_at = Some(assign.range);
2578  MacroResult::Success(STeXToken::Assign {
2579    uri, token_range: assign.token_range, orig_range: orig.1,
2580    full_range: assign.range
2581  })
2582});
2583
2584fn define_assignment_macros<'a, MS: STeXModuleStore>(
2585    p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2586) {
2587    p.add_macro_rule(
2588        Cow::Borrowed("renamedecl"),
2589        Some(AnyMacro::Ptr(renamedecl as _)),
2590    );
2591    p.add_macro_rule(Cow::Borrowed("assign"), Some(AnyMacro::Ptr(assign as _)));
2592}
2593
2594fn setup_morphism<'a, MS: STeXModuleStore>(
2595    p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2596    name: &str,
2597    archive: &Option<(&'a str, StringRange<LSPLineCol>)>,
2598    domain: &str,
2599    pos: LSPLineCol,
2600) -> Option<(
2601    SymbolUri,
2602    ModuleOrStruct<LSPLineCol>,
2603    Vec<ModuleRules<LSPLineCol>>,
2604)> {
2605    let archive = archive.and_then(|(a, r)| parse_id(a, pos, &mut p.tokenizer));
2606    let (state, mut groups) = p.split();
2607
2608    let Ok(name) = name.parse::<UriName>() else {
2609        p.tokenizer.problem(
2610            pos,
2611            format!("Invalid module name: {name}"),
2612            DiagnosticLevel::Error,
2613        );
2614        return None;
2615    };
2616    let _ = state.add_symbol(
2617        &mut groups,
2618        name.clone(),
2619        None,
2620        StringRange {
2621            start: pos,
2622            end: pos,
2623        },
2624        false,
2625        true,
2626        0,
2627    );
2628    let Some((mors, rules)) = state.resolve_module_or_struct(&groups, domain, archive) else {
2629        groups.tokenizer.problem(
2630            pos,
2631            format!("No module or structure {domain} found"),
2632            DiagnosticLevel::Error,
2633        );
2634        return None;
2635    };
2636
2637    let Some((uri, _)) = get_module(p) else {
2638        p.tokenizer
2639            .problem(pos, "Not in a module", DiagnosticLevel::Error);
2640        return None;
2641    };
2642    Some((uri.clone() | name, mors, rules))
2643}
2644
2645fn elaborate_morphism<'a, MS: STeXModuleStore>(
2646    p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2647    do_macros: bool,
2648    check_defined: bool,
2649    range: StringRange<LSPLineCol>,
2650    name: &str,
2651    rules: Vec<ModuleRules<LSPLineCol>>,
2652    mut specs: VecMap<SymbolReference<LSPLineCol>, MorphismSpec<LSPLineCol>>,
2653) {
2654    let old_end = std::mem::replace(&mut p.tokenizer.reader.pos, range.end);
2655    let Some(name) = name.parse::<UriName>().ok() else {
2656        p.tokenizer.problem(
2657            range.start,
2658            format!("Invalid name: {name}"),
2659            DiagnosticLevel::Error,
2660        );
2661        p.tokenizer.reader.pos = old_end;
2662        return;
2663    };
2664    let Some((in_module, _)) = get_module(p) else {
2665        p.tokenizer.problem(
2666            range.start,
2667            "Morphism only allowed in module",
2668            DiagnosticLevel::Error,
2669        );
2670        p.tokenizer.reader.pos = old_end;
2671        return;
2672    };
2673    let mut dones = Vec::new();
2674    let (state, mut groups) = p.split();
2675    for rls in &rules {
2676        for r in rls.rules.iter() {
2677            if let ModuleRule::Symbol(s) = r
2678                && !dones.contains(&&s.uri)
2679            {
2680                dones.push(&s.uri);
2681                let (macroname, name, dfed, rng) = if let Some(spec) = specs.remove(&s.uri) {
2682                    let m = spec.macroname.map_or_else(
2683                        || if do_macros { s.macroname.clone() } else { None },
2684                        |m| Some(m.into()),
2685                    );
2686                    let n = spec.new_name.unwrap_or_else(|| &name / s.uri.uri.name());
2687                    let d = spec.is_assigned_at.is_some() || s.has_df;
2688                    (m, n, d, spec.decl_range)
2689                } else {
2690                    let m = if do_macros { s.macroname.clone() } else { None };
2691                    let n = &name / s.uri.uri.name();
2692                    let d = s.has_df;
2693                    (m, n, d, range)
2694                };
2695                if check_defined && !dfed {
2696                    groups.tokenizer.problem(
2697                        range.start,
2698                        format!("{} not defined in total morphism", s.uri.uri),
2699                        DiagnosticLevel::Error,
2700                    );
2701                }
2702                if state
2703                    .add_symbol(
2704                        &mut groups,
2705                        name,
2706                        macroname,
2707                        range,
2708                        s.has_tp,
2709                        dfed,
2710                        s.argnum,
2711                    )
2712                    .is_none()
2713                {
2714                    groups.tokenizer.problem(
2715                        range.start,
2716                        "Morphism only allowed in module",
2717                        DiagnosticLevel::Error,
2718                    );
2719                }
2720            }
2721        }
2722    }
2723    p.tokenizer.reader.pos = old_end;
2724}
2725
2726// TODO dependency!
2727stex!(LSP: p => @begin{copymodule}({name:!name}[archive:str]{domain:!name}){
2728  let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,copymodule.begin.range.start) else { return };
2729  p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors.clone(), rules, specs: VecMap::default() };
2730  define_assignment_macros(p);
2731  let dom_range_start = archive.map_or(domain.1.start,|(_,r)| r.start);
2732  let domain_range = StringRange{ start:dom_range_start, end:domain.1.end};
2733  copymodule.children.push(STeXToken::MorphismEnv {
2734    kind:MorphismKind::CopyModule,
2735    domain:mors,uri,
2736    star:false,
2737    full_range:copymodule.begin.range,
2738    env_range:copymodule.name_range,
2739    domain_range,
2740    name_range:name.1,
2741    children:Vec::new()
2742  });
2743}{
2744  match copymodule.children.first() {
2745    Some(STeXToken::MorphismEnv{..}) => {
2746      let mut ch = copymodule.children.drain(..);
2747      let Some(STeXToken::MorphismEnv { mut full_range, star,env_range, name_range, uri, domain, domain_range, kind, mut children }) = ch.next() else {
2748        unreachable!()
2749      };
2750      children.extend(ch);
2751      if let Some(end) =copymodule.end.as_ref() {
2752        full_range.end = end.range.end;
2753      }
2754      let Some(g) = p.groups.last_mut() else {
2755        p.tokenizer.problem(copymodule.begin.range.start,"copymodule ended unexpectedly",DiagnosticLevel::Error);
2756        return EnvironmentResult::Simple(copymodule)
2757      };
2758      let GroupKind::Morphism{domain,rules,specs} = std::mem::take(&mut g.kind) else {
2759        return EnvironmentResult::Simple(copymodule);
2760      };
2761      elaborate_morphism(p,star,false,copymodule.begin.range,uri.name().last(),rules,specs);
2762      EnvironmentResult::Success(STeXToken::MorphismEnv {
2763        kind, full_range, name_range, star,env_range,uri,domain,domain_range,children
2764      })
2765    }
2766    _ => EnvironmentResult::Simple(copymodule)
2767  }
2768});
2769
2770stex!(LSP: p => @begin{copymodule_ast}({name:!name}[archive:str]{domain:!name}){
2771  let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,copymodule_ast.begin.range.start) else { return };
2772  p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors.clone(), rules, specs: VecMap::default() };
2773  define_assignment_macros(p);
2774  let dom_range_start = archive.map_or(domain.1.start,|(_,r)| r.start);
2775  let domain_range = StringRange{ start:dom_range_start, end:domain.1.end};
2776  copymodule_ast.children.push(STeXToken::MorphismEnv {
2777    kind:MorphismKind::CopyModule,
2778    domain:mors,uri,
2779    star:true,
2780    full_range:copymodule_ast.begin.range,
2781    env_range:copymodule_ast.name_range,
2782    domain_range,
2783    name_range:name.1,
2784    children:Vec::new()
2785  });
2786}{
2787  match copymodule_ast.children.first() {
2788    Some(STeXToken::MorphismEnv{..}) => {
2789      let mut ch = copymodule_ast.children.drain(..);
2790      let Some(STeXToken::MorphismEnv { mut full_range, star,env_range, name_range, uri, domain, domain_range, kind, mut children }) = ch.next() else {
2791        unreachable!()
2792      };
2793      children.extend(ch);
2794      if let Some(end) =copymodule_ast.end.as_ref() {
2795        full_range.end = end.range.end;
2796      }
2797      let Some(g) = p.groups.last_mut() else {
2798        p.tokenizer.problem(copymodule_ast.begin.range.start,"copymodule* ended unexpectedly",DiagnosticLevel::Error);
2799        return EnvironmentResult::Simple(copymodule_ast)
2800      };
2801      let GroupKind::Morphism{domain,rules,specs} = std::mem::take(&mut g.kind) else {
2802        return EnvironmentResult::Simple(copymodule_ast);
2803      };
2804      elaborate_morphism(p,star,false,copymodule_ast.begin.range,uri.name().last(),rules,specs);
2805      EnvironmentResult::Success(STeXToken::MorphismEnv {
2806        kind, full_range, name_range, star,env_range,uri,domain,domain_range,children
2807      })
2808    }
2809    _ => EnvironmentResult::Simple(copymodule_ast)
2810  }
2811});
2812
2813#[allow(clippy::too_many_lines)]
2814fn parse_assignments<'a, MS: STeXModuleStore>(
2815    p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2816    m: &mut Macro<'a, LSPLineCol>,
2817) -> Option<(
2818    Vec<InlineMorphAssign<LSPLineCol, STeXToken<LSPLineCol>>>,
2819    VecMap<SymbolReference<LSPLineCol>, MorphismSpec<LSPLineCol>>,
2820)> {
2821    let mut specs = Vec::new();
2822    p.skip_comments();
2823    if !p.tokenizer.reader.starts_with('{') {
2824        p.tokenizer
2825            .problem(m.range.start, "Group expected", DiagnosticLevel::Error);
2826        return None;
2827    }
2828    p.tokenizer.reader.next_char();
2829    p.skip_comments();
2830    loop {
2831        if p.tokenizer.reader.starts_with('}') {
2832            p.tokenizer.reader.next_char();
2833            break;
2834        }
2835        let start = p.curr_pos();
2836        let symbol_name = p
2837            .tokenizer
2838            .reader
2839            .read_until(|c| c == '}' || c == ',' || c == '=' || c == '%' || c == '@')
2840            .trim();
2841        let symbol_range = StringRange {
2842            start,
2843            end: p.tokenizer.reader.curr_pos(),
2844        };
2845        let (state, groups) = p.split();
2846        let Some(symbol) = get_in_morphism(groups.groups, symbol_name).map(|(s, _)| s.uri.clone())
2847        else {
2848            groups.tokenizer.problem(
2849                symbol_range.start,
2850                format!("Symbol {symbol_name} not found in morphism"),
2851                DiagnosticLevel::Error,
2852            );
2853            return None;
2854        };
2855        p.skip_comments();
2856        let infix = p.curr_pos();
2857        macro_rules! def {
2858            () => {{
2859                p.skip_comments();
2860                let start = p.curr_pos();
2861                let txt = p
2862                    .tokenizer
2863                    .reader
2864                    .read_until_with_brackets('{', '}', |c| c == ',' || c == '@' || c == '}');
2865                let ret = p.reparse(txt, start);
2866                p.skip_comments();
2867                ret
2868            }};
2869        }
2870        macro_rules! rename {
2871            () => {{
2872                p.skip_comments();
2873                let real_name = if p.tokenizer.reader.starts_with('[') {
2874                    p.tokenizer.reader.next_char();
2875                    let start = p.curr_pos();
2876                    let namestr = p
2877                        .tokenizer
2878                        .reader
2879                        .read_until(|c| c == ']' || c == '=' || c == ',' || c == '}' || c == '%');
2880                    let range = StringRange {
2881                        start,
2882                        end: p.curr_pos(),
2883                    };
2884                    p.skip_comments();
2885                    match p.tokenizer.reader.next_char() {
2886                        Some(']') => (),
2887                        _ => {
2888                            p.tokenizer
2889                                .problem(start, "']' expected", DiagnosticLevel::Error);
2890                            return None;
2891                        }
2892                    }
2893                    let range = StringRange {
2894                        start,
2895                        end: p.curr_pos(),
2896                    };
2897                    let Ok(name) = namestr.parse::<UriName>() else {
2898                        p.tokenizer.problem(
2899                            start,
2900                            format!("Invalid name: {namestr}"),
2901                            DiagnosticLevel::Error,
2902                        );
2903                        return None;
2904                    };
2905                    Some((name, range))
2906                } else {
2907                    None
2908                };
2909                let start = p.curr_pos();
2910                let namestr = p
2911                    .tokenizer
2912                    .reader
2913                    .read_until(|c| c == '=' || c == ',' || c == '}' || c == '%');
2914                let range = StringRange {
2915                    start,
2916                    end: p.curr_pos(),
2917                };
2918                p.skip_comments();
2919                (real_name, namestr.to_string().into(), range)
2920            }};
2921        }
2922        match p.tokenizer.reader.next_char() {
2923            Some('=') => {
2924                let ret = def!();
2925                let infix2 = p.curr_pos();
2926                match p.tokenizer.reader.next_char() {
2927                    Some('}') => {
2928                        specs.push(InlineMorphAssign {
2929                            symbol,
2930                            symbol_range,
2931                            first: Some((infix, InlineMorphAssKind::Df(ret))),
2932                            second: None,
2933                        });
2934                        break;
2935                    }
2936                    Some(',') => {
2937                        specs.push(InlineMorphAssign {
2938                            symbol,
2939                            symbol_range,
2940                            first: Some((infix, InlineMorphAssKind::Df(ret))),
2941                            second: None,
2942                        });
2943                        p.skip_comments();
2944                    }
2945                    Some('@') => {
2946                        let (real_name, macroname, mrange) = rename!();
2947                        match p.tokenizer.reader.next_char() {
2948                            Some('}') => {
2949                                specs.push(InlineMorphAssign {
2950                                    symbol,
2951                                    symbol_range,
2952                                    first: Some((infix, InlineMorphAssKind::Df(ret))),
2953                                    second: Some((
2954                                        infix2,
2955                                        InlineMorphAssKind::Rename(real_name, macroname, mrange),
2956                                    )),
2957                                });
2958                                break;
2959                            }
2960                            Some(',') => {
2961                                specs.push(InlineMorphAssign {
2962                                    symbol,
2963                                    symbol_range,
2964                                    first: Some((infix, InlineMorphAssKind::Df(ret))),
2965                                    second: Some((
2966                                        infix2,
2967                                        InlineMorphAssKind::Rename(real_name, macroname, mrange),
2968                                    )),
2969                                });
2970                                p.skip_comments();
2971                            }
2972                            _ => {
2973                                p.tokenizer.problem(
2974                                    start,
2975                                    "'}' or ',' expected",
2976                                    DiagnosticLevel::Error,
2977                                );
2978                                return None;
2979                            }
2980                        }
2981                    }
2982                    _ => {
2983                        p.tokenizer.problem(
2984                            symbol_range.end,
2985                            "'}', ',' or '@' expected",
2986                            DiagnosticLevel::Error,
2987                        );
2988                        return None;
2989                    }
2990                }
2991            }
2992            Some('@') => {
2993                let (real_name, macroname, mrange) = rename!();
2994                let infix2 = p.curr_pos();
2995                match p.tokenizer.reader.next_char() {
2996                    Some('}') => {
2997                        specs.push(InlineMorphAssign {
2998                            symbol,
2999                            symbol_range,
3000                            first: Some((
3001                                infix,
3002                                InlineMorphAssKind::Rename(real_name, macroname, mrange),
3003                            )),
3004                            second: None,
3005                        });
3006                        break;
3007                    }
3008                    Some(',') => {
3009                        specs.push(InlineMorphAssign {
3010                            symbol,
3011                            symbol_range,
3012                            first: Some((
3013                                infix,
3014                                InlineMorphAssKind::Rename(real_name, macroname, mrange),
3015                            )),
3016                            second: None,
3017                        });
3018                        p.skip_comments();
3019                    }
3020                    Some('=') => {
3021                        let ret = def!();
3022                        match p.tokenizer.reader.next_char() {
3023                            Some('}') => {
3024                                specs.push(InlineMorphAssign {
3025                                    symbol,
3026                                    symbol_range,
3027                                    first: Some((
3028                                        infix,
3029                                        InlineMorphAssKind::Rename(real_name, macroname, mrange),
3030                                    )),
3031                                    second: Some((infix2, InlineMorphAssKind::Df(ret))),
3032                                });
3033                                break;
3034                            }
3035                            Some(',') => {
3036                                specs.push(InlineMorphAssign {
3037                                    symbol,
3038                                    symbol_range,
3039                                    first: Some((
3040                                        infix,
3041                                        InlineMorphAssKind::Rename(real_name, macroname, mrange),
3042                                    )),
3043                                    second: Some((infix2, InlineMorphAssKind::Df(ret))),
3044                                });
3045                                p.skip_comments();
3046                            }
3047                            _ => {
3048                                p.tokenizer.problem(
3049                                    start,
3050                                    "'}' or ',' expected",
3051                                    DiagnosticLevel::Error,
3052                                );
3053                                return None;
3054                            }
3055                        }
3056                    }
3057                    _ => {
3058                        p.tokenizer
3059                            .problem(start, "']' expected", DiagnosticLevel::Error);
3060                        return None;
3061                    }
3062                }
3063            }
3064            _ => {
3065                p.tokenizer.problem(
3066                    symbol_range.end,
3067                    "'@' or '=' expected",
3068                    DiagnosticLevel::Error,
3069                );
3070                return None;
3071            }
3072        }
3073    }
3074    m.range.end = p.tokenizer.reader.curr_pos();
3075
3076    let mut nspecs = VecMap::new();
3077    for InlineMorphAssign {
3078        symbol,
3079        first,
3080        second,
3081        ..
3082    } in &specs
3083    {
3084        let mut spec = MorphismSpec::default();
3085        if let Some((_, first)) = first {
3086            match first {
3087                InlineMorphAssKind::Df(_) => spec.is_assigned_at = Some(m.range),
3088                InlineMorphAssKind::Rename(rn, n, _) => {
3089                    spec.macroname = Some(n.clone());
3090                    if let Some((n, r)) = rn {
3091                        spec.new_name = Some(n.clone());
3092                    }
3093                }
3094            }
3095        }
3096        if let Some((_, second)) = second {
3097            match second {
3098                InlineMorphAssKind::Df(_) => spec.is_assigned_at = Some(m.range),
3099                InlineMorphAssKind::Rename(rn, n, _) => {
3100                    spec.macroname = Some(n.clone());
3101                    if let Some((n, r)) = rn {
3102                        spec.new_name = Some(n.clone());
3103                    }
3104                }
3105            }
3106        }
3107        nspecs.insert(symbol.clone(), spec);
3108    }
3109
3110    Some((specs, nspecs))
3111}
3112
3113stex!(LSP: p => copymod('*'?star){name:!name}[archive:str]{domain:!name} => {
3114  let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,copymod.range.start) else {
3115    return MacroResult::Simple(copymod)
3116  };
3117  p.open_group();
3118  p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors, rules, specs: VecMap::default() };
3119  let Some((v,specs)) = parse_assignments(p, &mut copymod) else {
3120    return MacroResult::Simple(copymod)
3121  };
3122  let GroupKind::Morphism { domain: mors, rules, .. } = std::mem::take(&mut p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind) else { unreachable!()};
3123  p.close_group();
3124  elaborate_morphism(p, star, false, copymod.range, &name.0, rules, specs);
3125
3126  MacroResult::Success(STeXToken::InlineMorphism {
3127    full_range: copymod.range, token_range: copymod.token_range,
3128    name_range: name.1, uri, star, domain: mors, domain_range: domain.1,
3129    kind: MorphismKind::CopyModule, assignments: v
3130  })
3131});
3132
3133stex!(LSP: p => interpretmod('*'?star){name:!name}[archive:str]{domain:!name} => {
3134  let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,interpretmod.range.start) else {
3135    return MacroResult::Simple(interpretmod)
3136  };
3137  p.open_group();
3138  p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors, rules, specs: VecMap::default() };
3139  let Some((v,specs)) = parse_assignments(p, &mut interpretmod) else {
3140    return MacroResult::Simple(interpretmod)
3141  };
3142  let GroupKind::Morphism { domain: mors, rules, .. } = std::mem::take(&mut p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind) else { unreachable!()};
3143  p.close_group();
3144  elaborate_morphism(p, star, true, interpretmod.range, &name.0, rules, specs);
3145
3146  MacroResult::Success(STeXToken::InlineMorphism {
3147    full_range: interpretmod.range, token_range: interpretmod.token_range,
3148    name_range: name.1, uri, star, domain: mors, domain_range: domain.1,
3149    kind: MorphismKind::CopyModule, assignments: v
3150  })
3151});
3152
3153// TODO dependency!
3154stex!(LSP: p => @begin{interpretmodule}({name:!name}[archive:str]{domain:!name}){
3155  let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,interpretmodule.begin.range.start) else { return };
3156  p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors.clone(), rules, specs: VecMap::default() };
3157  define_assignment_macros(p);
3158  let dom_range_start = archive.map_or(domain.1.start,|(_,r)| r.start);
3159  let domain_range = StringRange{ start:dom_range_start, end:domain.1.end};
3160  interpretmodule.children.push(STeXToken::MorphismEnv {
3161    kind:MorphismKind::InterpretModule,
3162    domain:mors,uri,
3163    star:false,
3164    full_range:interpretmodule.begin.range,
3165    env_range:interpretmodule.name_range,
3166    domain_range,
3167    name_range:name.1,
3168    children:Vec::new()
3169  });
3170}{
3171  match interpretmodule.children.first() {
3172    Some(STeXToken::MorphismEnv{..}) => {
3173      let mut ch = interpretmodule.children.drain(..);
3174      let Some(STeXToken::MorphismEnv { mut full_range, star,env_range, name_range, uri, domain, domain_range, kind, mut children }) = ch.next() else {
3175        unreachable!()
3176      };
3177      children.extend(ch);
3178      if let Some(end) = interpretmodule.end.as_ref() {
3179        full_range.end = end.range.end;
3180      }
3181      let Some(g) = p.groups.last_mut() else {
3182        p.tokenizer.problem(interpretmodule.begin.range.start,"interpretmodule ended unexpectedly",DiagnosticLevel::Error);
3183        return EnvironmentResult::Simple(interpretmodule)
3184      };
3185      let GroupKind::Morphism{domain,rules,specs} = std::mem::take(&mut g.kind) else {
3186        return EnvironmentResult::Simple(interpretmodule);
3187      };
3188      elaborate_morphism(p,star,true,interpretmodule.begin.range,uri.name().last(),rules,specs);
3189      EnvironmentResult::Success(STeXToken::MorphismEnv {
3190        kind, full_range, name_range, star,env_range,uri,domain,domain_range,children
3191      })
3192    }
3193    _ => EnvironmentResult::Simple(interpretmodule)
3194  }
3195});
3196
3197stex!(LSP: p => @begin{interpretmodule_ast}({name:!name}[archive:str]{domain:!name}){
3198  let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,interpretmodule_ast.begin.range.start) else { return };
3199  p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors.clone(), rules, specs: VecMap::default() };
3200  define_assignment_macros(p);
3201  let dom_range_start = archive.map_or(domain.1.start,|(_,r)| r.start);
3202  let domain_range = StringRange{ start:dom_range_start, end:domain.1.end};
3203  interpretmodule_ast.children.push(STeXToken::MorphismEnv {
3204    kind:MorphismKind::InterpretModule,
3205    domain:mors,uri,
3206    star:true,
3207    full_range:interpretmodule_ast.begin.range,
3208    env_range:interpretmodule_ast.name_range,
3209    domain_range,
3210    name_range:name.1,
3211    children:Vec::new()
3212  });
3213}{
3214  match interpretmodule_ast.children.first() {
3215    Some(STeXToken::MorphismEnv{..}) => {
3216      let mut ch = interpretmodule_ast.children.drain(..);
3217      let Some(STeXToken::MorphismEnv { mut full_range, star,env_range, name_range, uri, domain, domain_range, kind, mut children }) = ch.next() else {
3218        unreachable!()
3219      };
3220      children.extend(ch);
3221      if let Some(end) = interpretmodule_ast.end.as_ref() {
3222        full_range.end = end.range.end;
3223      }
3224      let Some(g) = p.groups.last_mut() else {
3225        p.tokenizer.problem(interpretmodule_ast.begin.range.start,"interpretmodule ended unexpectedly",DiagnosticLevel::Error);
3226        return EnvironmentResult::Simple(interpretmodule_ast)
3227      };
3228      let GroupKind::Morphism{domain,rules,specs} = std::mem::take(&mut g.kind) else {
3229        return EnvironmentResult::Simple(interpretmodule_ast);
3230      };
3231      elaborate_morphism(p,star,true,interpretmodule_ast.begin.range,uri.name().last(),rules,specs);
3232      EnvironmentResult::Success(STeXToken::MorphismEnv {
3233        kind, full_range, name_range, star,env_range,uri,domain,domain_range,children
3234      })
3235    }
3236    _ => EnvironmentResult::Simple(interpretmodule_ast)
3237  }
3238});
3239
3240#[allow(clippy::needless_pass_by_value)]
3241pub(super) fn semantic_macro<'a, MS: STeXModuleStore, Pos: StringPosition + 'a>(
3242    arg: &MacroArg<Pos>, //(uri,argnum):&(SymbolReference<Pos>,u8),
3243    m: Macro<'a, Pos>,
3244    _parser: &mut LaTeXParser<'a, Pos, STeXToken<Pos>, STeXParseState<'a, Pos, MS>>,
3245) -> MacroResult<'a, Pos, STeXToken<Pos>> {
3246    let MacroArg::Symbol(uri, argnum) = arg else {
3247        unreachable!()
3248    };
3249    MacroResult::Success(STeXToken::SemanticMacro {
3250        uri: uri.clone(),
3251        argnum: *argnum,
3252        full_range: m.range,
3253        token_range: m.token_range,
3254    })
3255}
3256
3257pub(super) fn variable_macro<'a, MS: STeXModuleStore, Pos: StringPosition + 'a>(
3258    arg: &MacroArg<Pos>, //(uri,argnum):&(SymbolReference<Pos>,u8),
3259    m: Macro<'a, Pos>,
3260    _parser: &mut LaTeXParser<'a, Pos, STeXToken<Pos>, STeXParseState<'a, Pos, MS>>,
3261) -> MacroResult<'a, Pos, STeXToken<Pos>> {
3262    let MacroArg::Variable(name, range, seq, argnum) = arg else {
3263        unreachable!()
3264    };
3265    MacroResult::Success(STeXToken::VariableMacro {
3266        name: name.clone(),
3267        full_range: m.range,
3268        token_range: m.token_range,
3269        sequence: *seq,
3270        orig: *range,
3271        argnum: *argnum,
3272    })
3273}