flams_stex/quickparse/stex/
rules.rs

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