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