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