Skip to main content

flams_stex/quickparse/stex/
rules.rs

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