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